# Asynchronous Translation Manifest Implementation Plan

**Design:** `docs/specs/2026-08-24-async-translation-manifest-design.md`  
**Repository root:** `/home/user/Projects/Press.zone/wordpress/wp-content/.claude/worktrees/async-translation-manifest`  
**Delivery:** all paths below are relative to that root

## Delivery rules

- Implement the design contract without weakening durability, authorization, fencing, liveness, or proof requirements.
- Workflow implementers use `gpt-5.6-luna/max`; code reviewers use `gpt-5.6-sol/low`; security/auth review uses `gpt-5.6-sol/medium`.
- Same-wave tasks own disjoint files. Agents edit only their Files list, never commit, never build/test/profile on the workstation, and report exact diffs plus unresolved dependencies.
- The parent reviews and commits task file groups serially.
- Static inspection and `git diff --check -- <owned files>` are allowed on the workstation; executable gates are not.
- All executable PHP/JS/TS/Prisma/unit/integration/browser/build gates run on registry-selected debian1/2/3 or the canonical k3s/e2e-remote lane.
- Never read or print secret values, authorization headers, `.env`, `.secrets`, token-bearing config, npmrc contents, or Kubernetes Secret data.
- Never use local Podman WordPress. Never test or smoke dev1.
- Do not enable a feature-specific flag. Admission/UI stay behind `ipz_unreleased` until external-runner health and every non-dev1 gate pass. Worker, callback, reconciliation, and cleanup hooks continue for admitted work even when admission is disabled.
- Land only with `.claude/scripts/ship.sh land <branch> <worktree>`. A green delivery includes the landed `origin/master` SHA.
- Build the distribution remotely. Deploy dev1 only after landing and all non-dev1 proof is green; do not test dev1 afterward.

## Wave 1 — independent durable foundations

### Task 1A — WordPress manifest schema and migration

**Goal:** add the four InnoDB tables and an idempotent migration with verified readiness.

**Files:**

- `plugins/international-press-zone/includes/Core/Database.php`
- `plugins/international-press-zone/includes/Migrations/Migration20260824AsyncTranslationManifests.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestSchemaStandaloneTest.php` (new)

**Contract:**

- Advance `Database::DB_VERSION` from `1.3.2`; keep final DDL in `create_tables()` and migration idempotent.
- Create manifests, intents, submissions, and attempts exactly as specified; explicitly request InnoDB and verify required columns/indexes before recording the version.
- Use a named migration lock and bounded timeout. Because MySQL DDL implicitly commits, implement resumable information-schema-driven forward repair; never promise rollback and never run an unbounded request-time migration.
- Prove rerun safety, partial-schema repair, version-update ordering, and `503 ipz_manifest_schema_unavailable` readiness behavior.

**Agent acceptance:** focused diff check plus a DDL/design parity table.

### Task 1B — WordPress manifest repository

**Goal:** implement transactions, idempotent admission, lazy expansion, exact aggregate recomputation, leases/fencing, immutable submissions, retry generations, attempt history, cleanup, and stale recovery against the pinned schema contract.

**Files:**

- `plugins/international-press-zone/includes/Translation/TranslationManifestRepository.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestRepositoryStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/integration/TranslationManifestRepositoryConcurrencyTest.php` (new)

**Read-only dependency:** Task 1A schema is pinned verbatim by the design; do not edit its files.

**Contract:**

- Use explicit `READ COMMITTED` transactions, rollback on any error, and at most three deadlock retries.
- Canonicalize admission before hashing; unique `(user_id,request_key)` returns existing only for identical fingerprint.
- Every claimed-intent mutation checks manifest lease, intent claim, generation, and expected state. Submission mutation checks its lease.
- `persist_submission()` atomically links the exact claimed set, inserts existing local parent/items, and persists immutable canonical secret-free body bytes before I/O. Repository insertion is the only SQL owner for this boundary.
- Recompute seven public counters in the transition transaction, synthesizing unexpanded work from manifest total.
- Explicit retry increments generation, resets only generation attempts, writes history, and preserves lifetime attempts.
- Cleanup uses a durable cursor and requires terminal/reconciled state.
- Public errors are allowlisted and messages bounded to 500 bytes.

**Agent acceptance:** focused diff check and a report mapping every repository seam in the design to a method/test.

### Task 2 — Action Scheduler, external runner, and health seam

**Goal:** bundle Action Scheduler and implement scheduling plus the externally-driven WP-CLI drain seam without depending solely on WP-Cron.

**Files:**

- `plugins/international-press-zone/composer.json`
- `plugins/international-press-zone/international-press-zone.php`
- `plugins/international-press-zone/includes/Translation/TranslationManifestScheduler.php` (new)
- `plugins/international-press-zone/includes/CLI/TranslationManifestCommand.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestSchedulerStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestCommandStandaloneTest.php` (new)

**Contract:**

- Require `woocommerce/action-scheduler:^3.9`; remote dependency resolution owns lock regeneration and packaging verification.
- Bootstrap the library before `plugins_loaded` without fataling when dependency packaging is incomplete; admission readiness must then fail closed.
- Register group `international-press-zone-manifests`, immediate unique action `ipz_process_translation_manifest`, and recovery action `ipz_recover_translation_manifests`.
- Treat uniqueness as optimization only; repository leases remain concurrency authority.
- Implement `wp ipz translation-manifests run --time-budget=50 --max-manifests=20` and guarded health option `ipz_manifest_worker_health`.
- External scans recover the commit-before-enqueue crash gap and due/expired rows. WP-Cron/loopback are secondary wakeups.
- No command output contains source content, API credentials, or callback secrets.

**Agent acceptance:** focused diff check and proof that no local dependency install/build was run.

### Task 3 — Backend database idempotency and outbox scheduling schema

**Goal:** expand Prisma schema for create-or-return-existing bulk submissions and durable callback retry timing.

**Files:**

- `press-zone-backend/api/prisma/schema.prisma`
- `press-zone-backend/api/prisma/migrations/20260824000000_async_manifest_delivery/migration.sql` (new)
- `press-zone-backend/api/src/__tests__/unit/asyncManifestSchemaContract.test.ts` (new)

**Contract:**

- Add globally unique `TranslationJob.submission_id` and immutable `submission_fingerprint`.
- Add `WebhookOutbox.next_attempt_at`, `first_attempt_at`, `last_attempt_at`, `dead_at`, and `response_status` with due/stale indexes.
- Preserve existing queue payload, queue lease, processing lease, callback fields, and multiple outbox row support.
- Migration is deploy-safe for populated tables: nullable expansion/backfill-compatible columns and concurrent-safe indexes supported by the migration lane.

**Agent acceptance:** focused diff check plus a field/index/migration parity table.

### Task 4 — Generate All manifest client and UI

**Goal:** replace browser chunk workers with one idempotent manifest admission, durable polling, reload restoration, complete counters, and retry UI.

**Files:**

- `plugins/international-press-zone/admin/src/pages/content-translate.js`
- `plugins/international-press-zone/admin/src/pages/content-translate.test.js` (new)

**Read-only dependencies:** `admin/src/utils/api.js`, `admin/src/utils/DataStore.js`, existing modal/component classes.

**Contract:**

- Remove 20-pair request chunking and concurrent browser dispatch workers.
- Canonicalize the pair list once, generate one stable UUID request ID, and submit one request.
- On ambiguous admission failure, retry the identical body/request ID.
- Store at most 20 active manifest identities in site/user/version-namespaced guarded localStorage; never persist authoritative progress.
- Restore multiple active manifests, deduplicate pollers, pause hidden-document polling, and expose “View Generate All progress.”
- Render preparing, queued, processing, completed, failed, protected, and skipped counts; never classify a polling failure as translation failure.
- Render paginated failure details and retry all/selected eligible failures.
- Preserve accessibility and existing style architecture; no inline CSS.

**Agent acceptance:** focused diff check and a test inventory covering single request, ambiguous retry, reload/navigation, concurrent tabs, partial failure, selective retry, and stale 404 cleanup.

## Wave 2 — contracts consuming Wave 1

### Task 5 — Dispatcher preparation and immutable submission seams

**Depends on:** Tasks 1 and 3 contract shapes.

**Files:**

- `plugins/international-press-zone/includes/Translation/TranslationJobDispatcher.php`
- `plugins/international-press-zone/includes/Translation/Settings.php`
- `plugins/international-press-zone/tests/unit/Translation/TranslationJobDispatcherManifestStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/SettingsTest.php`

**Contract:**

- Extract `prepare_content_intent()` without duplicating current canonical-source, group authorization, target protection, source revision, advisory lock, local-job identity, and structured-context logic.
- Return explicit prepared/protected/skipped/existing/error outcomes. Existing links its local job and current state; it is not silently skipped.
- Produce versioned canonical structured envelopes with checksum and source fingerprint; local job idempotency/ref is `ipz-manifest:{intent_public_id}:g{generation}`. Never reuse a terminal prior-generation job after explicit retry.
- Extract a pure submission-draft builder with no SQL/I/O and a network sender that accepts only a persisted submission UUID plus exact canonical secret-free body; it must not accept/re-serialize prepared objects. The sender reads the stable callback secret at send time and sends it only as `X-IPZ-Callback-Secret`; rotation is blocked while work is nonterminal.
- Repository `persist_submission()` remains the single atomic owner of submission plus local parent/item rows.
- Keep the site callback secret stable and block rotation while local jobs/manifests are nonterminal; add regression coverage.
- Remove the extra-field singleton restriction. Preserve arbitrary core/ACF/SEO keys and local protection metadata.
- Keep `dispatch_content_batch()` as a compatibility wrapper; the REST route will stop calling it.

**Agent acceptance:** focused diff check and seam/outcome mapping against the design.

### Task 6 — Manifest admission/status/retry REST surface

**Depends on:** Task 1 repository and Task 2 scheduler.

**Files:**

- `plugins/international-press-zone/includes/API/TranslateController.php`
- `plugins/international-press-zone/includes/API/TranslationManifestController.php` (new)
- `plugins/international-press-zone/tests/unit/API/TranslationManifestControllerStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/API/TranslateAsyncBatchAdmissionStandaloneTest.php` (new)

**Contract:**

- Existing `translate-async-batch` route performs only canonicalization, one batched post load/cache prime, one `edit_post` check per unique post, repository create, and scheduler enqueue.
- Enforce UUID request ID, 1 MiB body, 2,000 canonical-intent cap, supported language/post type, and 202/409/413/503 contracts.
- Add owner-or-site-local-`manage_options` status route with indistinguishable 404 behavior and per-failure-row `edit_post` filtering.
- Add owner-only selective retry with current `edit_post` checks and `409 ipz_nothing_to_retry`.
- Include bounded failure pagination and worker health fields; admission fails `503 ipz_manifest_worker_unavailable` unless Action Scheduler is loaded and external-run health is at most 150 seconds old. Expose no numeric internals/content/secrets.
- Stay behind `ipz_unreleased` for admission/UI only.

**Agent acceptance:** focused diff check and route/permission/response matrix.

### Task 7 — Backend arbitrary structured bulk submission

**Depends on:** Task 3 schema.

**Files:**

- `press-zone-backend/api/src/routes/jobs.ts`
- `press-zone-backend/api/src/types/index.ts`
- `press-zone-backend/api/src/worker.ts`
- `press-zone-backend/api/src/__tests__/unit/routes/jobsBulkContent.test.ts`
- `press-zone-backend/api/src/__tests__/unit/workerBulkContent.test.ts`
- `press-zone-backend/api/src/__tests__/unit/workerBulkContentConcurrency.test.ts`

**Read-only dependencies:** `utils/structuredFields.ts`, `services/translationService.ts`, `services/geminiClient.ts`, queue dispatcher.

**Contract:**

- Require `submissionId` and authenticated `X-IPZ-Callback-Secret`; implement create-or-return-existing under unique submission UUID/fingerprint. Exclude the secret header from fingerprint/log/queue payload, store it only on first job creation, and never replace it on replay. Create/replay and job-status responses return `submissionId`; terminal callbacks return `submission_id`, `event_sequence`, job/client identities, and refs.
- Return original job identity on exact replay in any state; 409 mismatch; 404 cross-principal.
- Carry `fields: Record<string,string>` through route validation, types, durable `queue_payload`, Bull data, worker results, stored translation, and webhook results.
- Reuse existing canonical merge/count/exception/Gemini structured pipeline. Result keys must exactly equal input keys.
- Preserve queue payload creation and durable post-transaction queue sweep.
- Prove multi-item jobs with differing ACF/SEO keys and no field-driven singleton fallback.

**Agent acceptance:** focused diff check and end-to-end field mapping table.

### Task 8 — Deterministic k3s harness and browser proof definition

**Depends on:** Tasks 2, 4, and route contracts from Task 6.

**Files:**

- `plugins/international-press-zone/tests/e2e/remote-stack.sh`
- `plugins/international-press-zone/tests/e2e/live-batch-proof.spec.js`
- `plugins/international-press-zone/tests/e2e/journeys/UJ-021-generate-all-content.spec.js`
- `plugins/international-press-zone/tests/e2e/manifest-fault-injection.php` (new test bootstrap fixture)

**Contract:**

- Add test-only controllable worker ticks, frozen/advanced clock, deterministic UUID/jitter, backend request capture, named crash boundaries, callback duplicate/reorder controls, and DB assertions.
- Never expose production REST fault switches or secrets.
- Replace old HTTP 200/direct-batch assertions with one 202 admission, exact request body, stable ambiguous retry, 1,000-intent latency, bounded drain, one submission/backend job per crash scenario, real multi-item fields, callback completion, exact counters, reload/navigation, and retry proof.
- Run Chromium and Firefox; control workers explicitly to avoid races.
- External runner proof must drain while Action Scheduler loopback is disabled.

**Agent acceptance:** focused diff check and traceability from all 11 design evidence items to assertions.

## Wave 3 — orchestration and callback durability

### Task 9 — Bounded manifest processor and reconciler integration

**Depends on:** Tasks 1, 2, 5, and 7 contracts.

**Files:**

- `plugins/international-press-zone/includes/Translation/TranslationManifestProcessor.php` (new)
- `plugins/international-press-zone/includes/Translation/BulkContentReconciler.php`
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestProcessorStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestCrashRecoveryStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/BulkContentManifestReconciliationStandaloneTest.php` (new)

**Contract:**

- One invocation: max 100 expansions, 8 preparations, 4 submissions, and no new preparation after 25 seconds.
- Renew/check manifest lease between phases; pass intent/submission fencing tokens on every write.
- Recheck initiating actor and canonical group authorization before reading content.
- Revalidate source fingerprint before submission.
- Build a pure submission draft, atomically persist it plus local parent/items through the repository before network I/O, reload it, and send only the same stored submission UUID/body plus the nonpersisted callback-secret header after ambiguous failure. Atomically record remote ID/accepted state and purge the body only then; retain body whenever remote identity is unknown.
- Group by the exact compatibility key; use genuine multi-item chunks when two compatible prepared intents exist; final singleton remains supported.
- Integrate bounded 20-row/20-second reconciliation, stable cursor, 60-second age, 30-day horizon, create-or-return recovery when remote ID is missing, and manifest synchronization after local transitions.
- Classify retries and backoff exactly; one intent never blocks unrelated work.

**Agent acceptance:** focused diff check and crash-boundary/state-transition table.

### Task 10 — WordPress callback-to-manifest synchronization

**Depends on:** Task 1 repository and Task 9 synchronization contract.

**Files:**

- `plugins/international-press-zone/includes/API/TranslateJobsController.php`
- `plugins/international-press-zone/tests/unit/Translation/TranslateJobsManifestCompletionStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/Translation/TranslateJobsManifestOrderingStandaloneTest.php` (new)

**Contract:**

- Preserve current HMAC/timestamp/IP/delivery/client/backend/ref/content-type validation.
- Accept backend `event_sequence` and submission identity.
- Require callback `submission_id` and `event_sequence`; after local finalization, synchronize the exact current-generation intent and aggregate in the same success path.
- Duplicate delivery is an idempotent success; old generation is an audited stale no-op; identity mismatch rejects.
- Terminal state never regresses. Per-ref bulk failures and whole-job failure update only matching current nonterminal intents.
- Webhook delivery is recorded only after finalization plus manifest synchronization commit.

**Agent acceptance:** focused diff check and adversarial callback ordering matrix.

### Task 11 — Backend transactional failure outbox and durable delivery

**Depends on:** Tasks 3 and 7; this task owns the second, later edit of `worker.ts`.

**Files:**

- `press-zone-backend/api/src/worker.ts`
- `press-zone-backend/api/src/services/webhookService.ts`
- `press-zone-backend/api/src/routes/admin/translationWebhookOutbox.ts` (new)
- `press-zone-backend/api/src/server.ts`
- `press-zone-backend/api/src/__tests__/unit/workerLifecycle.test.ts`
- `press-zone-backend/api/src/__tests__/unit/services/webhookServiceBulk.test.ts`
- `press-zone-backend/api/src/__tests__/unit/translationWebhookOutbox.test.ts` (new)
- `press-zone-backend/api/src/__tests__/unit/routes/adminTranslationWebhookOutbox.test.ts` (new)

**Contract:**

- Every winning terminal transition, including all whole-job failure branches, writes exactly one outbox row in the same transaction; rollback proves neither commit.
- Emit monotonic per-job `event_sequence` and stable delivery ID; regenerate timestamp/signature per attempt.
- Claim only due rows, recover stale delivery leases, persist each result/status and capped exponential next due time, and include completion plus failure events.
- Exhaustion marks `dead`; authenticated admin list/redrive APIs omit secrets/source payload and audit action.
- Preserve HMAC over `timestamp.body`, constant-time verification compatibility, queue leases, processing heartbeat, billing transaction, and completion behavior.

**Agent acceptance:** focused diff check and terminal-path/outbox coverage table.

## Wave 4 — bootstrap, system integration, and property proof

### Task 12 — Plugin dependency wiring and lifecycle

**Depends on:** Tasks 1, 2, 6, 9, and 10.

**Files:**

- `plugins/international-press-zone/includes/Core/Plugin.php`
- `plugins/international-press-zone/tests/unit/Translation/TranslationManifestPluginWiringStandaloneTest.php` (new)
- `plugins/international-press-zone/tests/unit/ActivationBootstrapStandaloneTest.php`

**Contract:**

- Construct one repository, scheduler, processor, and manifest controller; inject the same repository into callback/reconciler seams.
- Register routes only after schema readiness. Schema failure yields safe 503 admission, not fatal/partial work.
- Register Action Scheduler, WP-CLI, external recovery, reconciliation, and cleanup hooks regardless of admission feature state when admitted work exists.
- Activation schedules recovery/cleanup and validates dependency readiness without performing translation work.
- Do not duplicate service instances or add direct SQL outside repository.

**Agent acceptance:** focused diff check and service/hook lifecycle map.

### Task 13 — Deterministic interleaving/property integration tests

**Depends on:** all implementation tasks.

**Files:**

- `plugins/international-press-zone/tests/integration/TranslationManifestEndToEndTest.php` (new)
- `plugins/international-press-zone/tests/integration/TranslationManifestInterleavingTest.php` (new)
- `press-zone-backend/api/src/__tests__/integration/asyncManifestDelivery.test.ts` (new)

**Contract:**

- Deterministically interleave claims, lease expiry, source mutation, backend accepted/lost response, enqueue sweep, callback failure/backoff, duplicate/reordered/old-generation events, reconciliation, and selective retry.
- Assert one manifest, unique intent ordinals/pairs, one immutable submission/backend job per UUID, one current-generation local job/ref, exact seven-counter sum, durable history, and eventual terminal state.
- Exercise both backend completion and whole-job failure transactions.
- No sleeps: use injected clock and explicit worker/drainer ticks.

**Agent acceptance:** focused diff check and invariant matrix.

## Wave review gates

After each wave, run one Sol reviewer per completed task in parallel. Reviewers:

- inspect only the task's Files list and the design/plan;
- report only, never edit or commit;
- verify no files outside ownership changed because of that task;
- flag correctness, authorization/IDOR, transaction, fencing, idempotency, privacy, and compatibility defects;
- do not claim executable tests passed; those are parent-owned remote gates.

Any blocking finding returns to a Luna/max fixer owning the same file list, followed by a fresh Sol review. Auth/callback tasks 6, 10, and 11 receive an additional Sol/medium security review.

## Parent serial commit sequence

After each reviewed wave, the parent inspects the aggregate diff, then commits disjoint groups serially in task order. No agent commits. Before every commit, verify the staged paths exactly equal that task's Files list. Do not include unrelated pre-existing changes.

Suggested commit subjects:

1. `Add translation manifest schema`
2. `Add durable translation manifest storage`
3. `Add durable manifest worker scheduling`
3. `Add backend manifest delivery schema`
4. `Move Generate All to manifest polling`
5. `Extract manifest-safe translation dispatch seams`
6. `Add translation manifest REST endpoints`
7. `Batch arbitrary structured translation fields`
8. `Add deterministic manifest browser proof`
9. `Process translation manifests in bounded actions`
10. `Synchronize callbacks with translation manifests`
11. `Make failed translation callbacks durable`
12. `Wire translation manifest lifecycle`
13. `Prove manifest crash and retry invariants`

Every commit message ends with `Co-Authored-By: Claude <noreply@anthropic.com>`.

## Remote verification sequence

No command in this section runs on the workstation. Use the registry-selected debian1/2/3 execution path and canonical k3s wrappers.

1. Regenerate `plugins/international-press-zone/composer.lock`, install dependencies, and verify Action Scheduler files are present in the distribution remotely; this parent-owned generated lockfile is committed serially after Task 2.
2. Run focused plugin standalone/unit/integration tests for repository, scheduler, dispatcher, controllers, processor, callback ordering, wiring, and interleavings.
3. Run backend Prisma generate/migration validation, typecheck, focused Jest suites, and build remotely.
4. Run remote PHP syntax/PHPCS/PHPStan and admin lint/Vitest/build through the applicable IPZ gate lane.
5. Run focused k3s browser proof from plugin root in Chromium and Firefox:

```text
~/.claude/bin/e2e-remote --server "tests/e2e/remote-stack.sh" --wait-port 8080 --env WP_BASE_URL=http://127.0.0.1:8080 -- /home/user/.local/share/mise/installs/pnpm/11.5.2/pnpm --dir tests/e2e exec playwright test --config=playwright.config.js live-batch-proof.spec.js journeys/UJ-021-generate-all-content.spec.js --project=chromium --project=firefox
```

6. Capture literal evidence: 202 latency under 3 seconds for 1,000 intents, zero request-time preparation/backend calls, bounded tick metrics, multi-item structured payload, immutable replay IDs, DB uniqueness/counters, callback outbox attempts, reconciliation repair, reload/navigation, and selective retry.
7. Run the full remote release gate via `plugins/international-press-zone/tests/e2e/gate-and-land.sh`; its land tail must produce a receipt with `landed_master_sha`.
8. If the lander reports candidate conflict, merge current `origin/master` into the worktree, resolve, rerun the complete remote gate-and-land transaction, and use the sanctioned lander only.
9. Confirm `origin/master` at the receipt SHA, then perform the production distribution build remotely.
10. Provision the external once-per-minute manifest runner, invoke the CLI once, verify `TranslationManifestScheduler::is_ready()` and a fresh health timestamp in the non-dev1 lane, and keep admission fail-closed on stale health before enabling the shared flag.
11. Deploy the remotely built plugin to dev1 only after all prior non-dev1 gates and landing succeed. Do not open, curl, smoke, or test dev1 afterward.

## Completion criteria

This work is complete only when:

- every design contract and deterministic evidence item passes remotely;
- all review blockers are fixed;
- the release distribution contains Action Scheduler and compiled UI assets;
- external runner health is provisioned for the enabled environment;
- the branch is landed on `origin/master` through the sanctioned lander;
- the final receipt names the landed master SHA;
- the remotely built release is deployed to dev1 without post-deploy testing.
