# Two-Resource Translation Dispatch and Controller

Audience: AI coding agents first.

- **ID:** IPZ-TWO-RESOURCE-DISPATCH-CONTROLLER-2026-08-15
- **Status:** DONE
- **Tasks:** SC-DISPATCH-01, SC-CONTROLLER-01, POST-HANDLER-01
- **Source request:** Continue every unfinished multilingual Site Content and multilingual-source slice through session end. Owner requires current coordinator to implement and review this PHP transport/controller lane directly, with every gate remote-only on registry-selected `debian1`/`debian2`/`debian3`. Owner later authorized exactly one disjoint admin-side Codex worker after a complete written plan/spec; coordinator MUST continue this lane after dispatch and later review/fix/integrate that worker output.
- **Execution owner:** Current main coordinator only for every path in this plan. The separate admin exception is governed by `2026-08-15-site-content-admin-ux.md` and grants no delegation here.

## Outcome

Recover post adaptation, exact post-versus-`site_content` dispatch, and a dormant Site Content REST controller as one coordinated compatibility slice. Preserve the existing post dispatcher/finalizer as authoritative. Connect the published Site Content resource handler to the same durable local-job, backend-identity, callback, polling, retry, and terminal-state seams without hidden state, latest-job lookup, arbitrary metadata, or duplicate finalization. Do not register, construct, schedule, hook, or expose the new runtime behavior.

## Acceptance

- Preserve `TranslationJobDispatcher::dispatch_content()` request, authorization, immutable source snapshot, mutation lock, local-job creation, backend submission, uncertain-submission reconciliation, and post behavior exactly.
- Add one exact resource boundary. Unknown content types fail closed. `site_content` routes only to `SiteContentTranslationResourceHandler`; current post jobs route only through `TranslationFinalizer` or a thin post adapter that delegates to it with explicit typed inputs.
- Persist immutable, versioned resource context in the existing local job row before backend submission. Site Content context MUST include exact prepared request, source revision, attempt authority, target language, actor, and contract version. Never infer a latest job or rebuild from mutable source on retry.
- Submit Site Content through backend contract version 1 with exact camel-case resource/version/revision/token/segments fields plus existing callback identity, exception, and client-job identity seams.
- Validate backend job identity plus exact `resourceType=site_content`, `contractVersion=1`, source revision, target language, and callback-only attempt token before Site Content mutation. Polling uses locally persisted attempt authority and MUST reject any remote attempt token.
- Finalize each completion exactly once. Preserve duplicate delivery, terminal replay, backend-job mismatch, uncertain-submission reconciliation, and retry-count semantics. Site Content failure consumes only the matching persisted attempt and stores bounded local failure text.
- Retry Site Content from the exact persisted prepared request and unchanged attempt authority. Do not call `prepare()` again. Re-arm only a matching persisted failed attempt through repository compare-and-swap; repository transition MAY advance `translation_revision`, but MUST NOT alter source revision, attempt token, or backend request identity.
- Authorize Site Content queue/read/review/delete/job access with `edit_theme_options`, translation entitlement, and exact catalog-object policy. Never use `edit_post` against a Site Content translation-row identifier.
- Recover only controller behavior compatible with current catalog/repository/codec contracts. Reject preserved direct SQL queueing and `wp_schedule_single_event()` design; dispatch through the coordinated durable dispatcher.
- Controller request bounds MUST not exceed backend/handler contract: 1 MiB encoded body, 1,000 segments, and effective backend advertised character bound. Do not hardcode stale 500-segment/200,000-character limits or trust an unversioned boolean capability.
- Add focused regression coverage for handler selection, post parity, Site Content request/context persistence, backend acceptance/reconciliation, callback, polling, retry, failure, stale attempt, backend mismatch, duplicate/terminal replay, authorization, and complete dormancy.
- Collection responses MUST omit internal catalog exclusions; authorization-filtered identifiers and exclusion reasons MUST NOT be exposed.
- Queueing after a live source change MUST atomically reconcile the persisted row from its exact old source and translation revision to the current source revision before dispatch. Preserve only exact unchanged segment translations, mark changed rows `needs_update`, reject concurrent/stale reconciliation, then prepare the new attempt from the current revision.
- Add no bootstrap construction, runtime handler registry, dispatcher switch from an active caller, route registration, schedule, write-path activation, or UI consumer.
- Run every dependency install, test, lint, typecheck, build, static analysis, security check, diagnostic, browser run, smoke, screenshot, and related gate only through canonical remote infrastructure on registry-selected `debian1`/`debian2`/`debian3`. NEVER run local gates, direct SSH, hardcoded normal-run hosts, workstation fallback, dev1 tests, or dev3 tests.

## Preserved WIP / ref / path

- Active worktree: `/home/user/Projects/Press.zone/wordpress/wp-content/.worktrees/site-content-dispatch-controller`
- Branch: `wt/site-content-dispatch-controller`
- Exact base: `a6febe270f37bb5572dc1deb0f9cb9b7be38a80a`
- Published dormant Site Content handler: `097a5f64b078078896f88de326278d2101263094`, published merge `aa56fce307a2c02aa34f36c37b5ef006755ea34f`.
- Published segmented backend: implementation `b56f15f269e3e74a2216074785d26a240a191476`, typecheck seam `923ed493b3955b10fb5836d62736e4f7d6a7dd4a`, published merge `a6febe270f37bb5572dc1deb0f9cb9b7be38a80a`.
- Preserved controller/post candidates: `e9a2c64f6169d85d76b3606d502c1312b912f919` and `09d3de3ac2c9805f63820433c8b1378fd163ee80`. Behavioral evidence only. NEVER transplant wholesale.
- Read-only extracted evidence: `/tmp/ipz-preserved-site-content-controller.php`, `/tmp/ipz-preserved-post-handler.php`.

## Allowed paths

- `includes/Translation/TranslationJobDispatcher.php`
- `includes/Translation/TranslationResourceHandler.php`
- `includes/Translation/TranslationPayload.php`
- `includes/Translation/TranslationResult.php`
- `includes/Translation/SiteContentTranslationResourceHandler.php` only for exact backend-contract compatibility defects proven by tests
- `includes/SiteContent/class-sitecontentrepository.php` only for a strict optimistic manual-review compare-and-swap required by the review route
- `includes/SiteContent/class-sitecontentcatalog.php` only to apply the exact object-authorization predicate before pagination so restricted resources and counts cannot leak through collection reads
- New exact translation boundary value/service files under `includes/Translation/` only when current signatures cannot carry required job identity without metadata bags
- `includes/API/TranslateJobsController.php`
- New dormant `includes/API/SiteContentController.php`
- `includes/Core/Database.php` and one focused migration only if the existing `translation_context` cannot safely persist exact versioned resource context; prefer existing storage and prove any schema need first
- Focused tests and fixtures under `tests/Unit/Translation/`, `tests/Unit/API/`, `tests/unit/API/`, and `tests/Fixtures/`
- This plan, `docs/plans/INDEX.md`, `2026-08-15-post-translation-resource-handler.md`, `2026-08-15-segmented-site-content-backend.md`, and `2026-08-09-multilingual-site-entry-and-layout.md`

## Constraints

- Current master code is authoritative. Existing post dispatcher and finalizer behavior MUST remain structurally intact.
- Keep domain authority separated: dispatcher owns durable transport; post finalizer owns post mutation; Site Content handler owns Site Content prepare/finalize and attempt compare-and-swap; controller owns REST validation/authorization only.
- Prefer exact method parameters or exact immutable value objects over generic arrays. NEVER add `metadata`, `raw_data`, `job`, or extensible bags to `TranslationResult`.
- NEVER duplicate `TranslationFinalizer` into a post handler. A post adapter, if needed, MUST delegate to the existing finalizer.
- NEVER route Site Content through legacy `JobSender`, post-only `TranslationFinalizer`, `edit_post`, or mutable retry reconstruction.
- No nested delegation, subagents, workflows, or external models.
- Backend production deployment remains externally blocked because only forbidden direct SSH is available. WordPress runtime activation remains forbidden until backend deployment, this slice, and admin Site Content UX are complete.

## Execution

1. Map preserved evidence against current dispatcher, finalizer, jobs controller, repository/catalog/codec, jobs schema, registration, and tests. Reject stale architecture explicitly.
2. Pin exact resource context, transport, completion, and retry boundaries in focused failure-first tests.
3. Implement smallest coordinated post/Site Content dispatch and completion path while leaving every new entry point dormant.
4. Recover current-compatible Site Content list/get/queue/review/delete controller behavior using dispatcher rather than direct SQL/scheduling. Do not register routes.
5. Run focused and applicable broad gates remotely only. Inspect output, not exit code alone. Address every warning, notice, and hint.
6. Directly review authorization, callback authentication, object identity, attempt authority, stale/replay behavior, idempotency, retry determinism, size bounds, error disclosure, and dormancy. Fix findings and rerun affected remote gates.
7. Commit normally through installed remote enforcement. Publish through serialized repository publisher. Fetch exact `origin/master`; prove source ancestry and exact tree receipt.
8. Do not deploy or activate. Record backend deployment blocker and continue admin Site Content UX only after this dormant slice is published.

## Current receipt

Fresh worktree is based on exact published segmented-backend master. Mapping confirms existing `TranslationJobDispatcher::dispatch_content()` is the authoritative post submission path; `TranslationFinalizer::finalize()` is the authoritative post mutation/terminal path; `TranslateJobsController` owns callback, polling, retry, local/backend identity, and terminal replay; `SiteContentTranslationResourceHandler` owns Site Content attempt authority and compare-and-swap mutation. Existing `translation_context` is a bounded `LONGTEXT` seam already persisted before post submission and can carry a strict versioned resource context without a schema change.

Preserved controller is evidence for route shapes, `edit_theme_options` plus entitlement authorization, catalog identity resolution, optimistic review/delete, and idempotency intent. Reject its stale unversioned capability boolean, 500-segment/200,000-character bounds, direct SQL local-job creation, transaction split from remote dispatch, and `wp_schedule_single_event()` activation. Preserved post handler is rejected as source: it duplicates the current 1,182-line finalizer, wraps post content into legacy HTML, treats every non-Site-Content type as supported, and depends on forbidden arbitrary `TranslationResult::metadata` bags.

Dormant WIP now includes strict versioned Site Content job context, actor-bound handler factory, durable dispatch, callback/poll/failure routing, exact persisted-request retry, resource-aware absent-backend reconciliation, the catalog/read/queue/review/delete REST controller, and the strict repository manual-review compare-and-swap. Collection object authorization runs before pagination and count calculation. Queue idempotency serializes expired-claim replacement and removes a newly created but unstarted claim when advisory-lock release fails. Concurrent translation-row creation recovers the canonical unique-key winner. No new route, dispatch branch from an active caller, hook, schedule registration, or UI is active.

Direct review fixed three transport correctness defects. Site Content dispatch no longer returns or continues from inside the advisory-lock scope before exact release disposition. Ambiguous local commit acknowledgment is queried before any backend submission; a visible committed row becomes non-dispatchable reconciliation state, while an absent row returns the bounded persistence failure. Every uncertain backend outcome now reports or schedules `reconciling` only after the exact `processing` to `reconciling` write succeeds. Post-commit Site Content cache rotation is best-effort and can no longer convert committed domain/local completion or failure into a false mutation error.

Focused standalone regressions cover Site Content dispatch, immutable request identity, duplicate suppression, malformed targets, uncertain and rejected submissions, unlock and commit ambiguity, failed reconciliation persistence, identity persistence, exact retry, REST route/authorization/idempotency/catalog/review/delete behavior, callback metadata, polling authority, retry/cancel routing, post-commit cache failure, and the Site Content timeout boundary. Remote broad PHPUnit passed with 120 tests and 666 assertions. The remote standalone sweep discovered 61 files (18 PHPUnit and 43 procedural); every file passed, including the repaired callback backend-identity contract, with the four repository-declared known-failing baseline entries still recognized as baseline entries. Simulated error output came only from explicit failure-path fixtures. No gate ran locally.

Direct review fixed the collection leak, changed-source dead end, and public response drift. Public collection responses now omit internal exclusion records and apply exact object authorization before pagination and counts; visibility lookup fails closed. Queueing after a live source change reconciles the exact old source and translation revisions, preserves only segment translations whose IDs and source hashes are unchanged, advances to the current revision with review required, and rejects stale or active-attempt races. The list and detail serializers expose the exact planned public catalog fields and exact translation-state fields without internal identity, exclusion, or redundant source-revision data. Focused controller, repository, and jobs regressions pass remotely.

Direct jobs-controller review found that the generic one-hour pending/processing timeout also selected `site_content`, which could fail the local job without consuming the matching Site Content attempt. The timeout now explicitly excludes Site Content. Final review also found collection synchronization ran before object visibility, allowing an object-denied caller to trigger backend polling and domain mutation for a hidden Site Content job. Collection visibility is now computed first and constrains the synchronization query; trusted direct `syncJob()` remains unchanged. Focused regressions prove both boundaries and pass remotely.

Callback, polling, retry, cancellation, terminal replay, backend identity, persisted attempt authority, idempotency, transaction boundaries, and object authorization were reviewed against the coordinated handler boundary. Final remote receipts are clean: focused jobs regression, 120 PHPUnit tests with 666 assertions, affected PHPStan, baseline-aware PHPCS, and diff whitespace. A mistakenly broad Composer PHPStan invocation ignored requested file arguments and exposed only repository baseline diagnostics; the corrected direct focused invocation reports no errors. No gate ran locally.

Owner-authorized parallel admin work is fully specified in `2026-08-15-site-content-admin-ux.md`. It owns no PHP path. The isolated worker output was rejected; the coordinator replaced and verified it directly.

Source commit `dd2bd00f9462a20cbaa893a98e9f2eab70568e74` passed installed remote pre-commit enforcement and the serialized lander's candidate typecheck plus remote test gate. It is published as the second parent of merge `a5e2f9de600a7385e8c83bf7d1d49b3c7fb97780` on `origin/master`. Exact ancestry is proven. Published merge tree `2b252fe8ec9bbc46ef158354a0b9e5cef4bd5f78` equals the fetched `origin/master` tree. The remote toolchain warning about `@ast-grep/cli` postinstall approval is benign: npm intentionally blocked the optional script, then the installed `ast-grep 0.45.1` binary executed and the complete remote PHP gate passed.

## Next executable action

None for this dormant slice. Keep all new Site Content entry points inactive until the separately tracked segmented-backend production deployment blocker is resolved; activation requires its own registered plan and verification.
