{"type": "meta", "slug": "ipz-advanced-settings", "base_branch": "fix/content-generate-all", "gate0_mode": "strict", "preset": "codex", "land_mode": "none"}
{"type": "goal", "text": "Port translate-press-zone's full advanced settings surface into international-press-zone: translation tone, auto-publish, debug mode/detailed logging, and exact/contains exceptions with bulk import — wired end to end (model, REST, admin UI, backend sync)."}
{"type": "methodology", "text": "Maximally parallel waves of small subagent tasks with strictly disjoint file ownership; no two tasks may touch the same file. Code review on every task. Fine-grained decomposition so a small coder model can complete each task without cross-file reasoning."}
{"type": "intent", "text": "translate-press-zone is superseded by international-press-zone; every setting that still lives only in the old plugin must exist in the new one so the old tree can be retired."}
{"type": "direction", "verbatim": "i want this plan to be paralelized as much as possible to get fast results, run with paralel luna subagents for non conflicting tasks in a way they wont touch each others work"}
{"type": "direction", "verbatim": "I want all the advanced settings to be on international-press-zone, since translate plugin is supreseded by it."}
{"type": "direction", "verbatim": "for luna, a small model, you must break down the tasks to smaller sub tasks that luna can handle easily"}
{"type": "direction", "verbatim": "check translate-press-zone for full functionality, see how it works."}
{"type": "direction", "verbatim": "never modify the abandoned translate-press-zone or multilingual-press-zone trees — read-only reference only"}
{"type": "session_memory", "note": "Backend rejects a regex match_type: api/src/routes/exceptions.ts pins z.enum(['exact','contains']). TPZ's UI offered regex; IPZ must not."}
{"type": "session_memory", "note": "api/src/routes/translate.ts has NO exceptions field in translateSchema/bulkTranslateSchema — inline exceptions are stripped by zod. Enforcement is server-side from Prisma rows keyed by userId, so backend sync is mandatory for the feature to work at all."}
{"type": "session_memory", "note": "Backend exceptions are keyed per user account, not per site: all sites on one license share one exception list."}
{"type": "session_memory", "note": "Canonical debug option is presszone_international_debug_mode (read by Translation/Logger.php:41). ipz_debug_mode is a dead duplicate written by API/SettingsController and is migrated away. ipz_log_queries is a separate concern and stays."}
{"type": "session_memory", "note": "Settings wire shape is FLAT in both directions; the nested branch in admin/src/pages/settings.js:494-508 is dead legacy handling. Do not introduce nesting."}
{"type": "session_memory", "note": "No luna preset exists in the harness engine and v2 dropped runconfig overrides (v2/seats.js loads presets from the read-only engine dir only). Run uses preset codex: coder gpt-5.6-terra-medium, reviewer gpt-5.6-sol-low."}
{"type": "session_memory", "note": "REST controllers are registered in includes/Core/Plugin.php around line 650; that file is owned exclusively by the ExceptionsController task."}
{"type": "session_memory", "note": "E2E must run via ~/.claude/bin/e2e-remote — local headless launches exit 97 by design."}
{"type": "anchor", "path": "plugins/international-press-zone/docs/specs/2026-08-04-ipz-advanced-settings-design.md", "what": "spec"}
{"type": "anchor", "path": "docs/plans/2026-08-04-ipz-advanced-settings.md", "what": "plan"}
{"type": "task", "id": "t1", "wave": 1, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 1 (Settings model — exceptions sync state) for the full contract. Add get/set/clear_exceptions_synced_at() to Translation\\Settings and clear the timestamp on every local exceptions mutation. Acceptance: podman exec devzone-wordpress php -r 'require \"/var/www/html/wp-load.php\"; $s = \\InternationalPressZone\\Translation\\Settings::instance(); $s->set_exceptions([]); $s->set_exceptions_synced_at(); echo (is_string($s->get_exceptions_synced_at()) ? \"SET_OK \" : \"SET_FAIL \"); $s->add_exception(\"Acme Corp\",\"exact\"); echo (($s->get_exceptions_synced_at() === null) ? \"DIRTY_OK\" : \"DIRTY_FAIL\"), PHP_EOL;' → SET_OK DIRTY_OK. Commit only: plugins/international-press-zone/includes/Translation/Settings.php.", "requires_decision": null}
{"type": "task", "id": "t2", "wave": 1, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 2 (Debug-mode consolidation migration) for the full contract. New AbstractMigration that copies ipz_debug_mode into presszone_international_debug_mode and deletes the legacy option. Acceptance: podman exec devzone-wordpress php -r 'require \"/var/www/html/wp-load.php\"; delete_option(\"presszone_international_debug_mode\"); update_option(\"ipz_debug_mode\", true); (new \\InternationalPressZone\\Migrations\\Migration20260804MigrateDebugMode())->up(); echo ((get_option(\"presszone_international_debug_mode\") == true && get_option(\"ipz_debug_mode\") === false) ? \"PASS\" : \"FAIL\"), PHP_EOL;' → PASS. Commit only: plugins/international-press-zone/includes/Migrations/Migration20260804MigrateDebugMode.php.", "requires_decision": null}
{"type": "task", "id": "t3", "wave": 1, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 3 (ExceptionSync transport + dead request key removal) for the full contract. New Translation\\ExceptionSync with push()/pull() against /v1/exceptions, plus removal of the dead $body['exceptions'] key in BulkActions. Acceptance: podman exec devzone-wordpress php -r 'require \"/var/www/html/wp-load.php\"; $r = (new \\InternationalPressZone\\Translation\\ExceptionSync())->push(); echo (is_array($r) && array_key_exists(\"success\",$r) && array_key_exists(\"count\",$r) && array_key_exists(\"message\",$r) ? \"SHAPE_OK\" : \"SHAPE_FAIL\"), PHP_EOL;' && ! grep -q \"body\\['exceptions'\\]\" plugins/international-press-zone/includes/Translation/BulkActions.php && echo DEADKEY_GONE. Commit only: plugins/international-press-zone/includes/Translation/ExceptionSync.php, plugins/international-press-zone/includes/Translation/BulkActions.php.", "requires_decision": null}
{"type": "task", "id": "t4", "wave": 1, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 4 (Exceptions tab styles) for the full contract. New _exceptions.scss with the pinned ipz-exceptions BEM classes plus one @use line in main.scss. Acceptance: cd plugins/international-press-zone/admin && npm run build 2>&1 | tail -20 && grep -c \"ipz-exceptions\" dist/css/main.css → clean build, count > 0. Commit only: plugins/international-press-zone/admin/src/styles/pages/_exceptions.scss, plugins/international-press-zone/admin/src/styles/main.scss.", "requires_decision": null}
{"type": "task", "id": "t5", "wave": 2, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 5 (Exceptions REST controller) for the full contract. New API\\ExceptionsController with six routes under presszone-international/v1/exceptions, registered in Plugin.php. Acceptance: podman exec devzone-wordpress php -r 'require \"/var/www/html/wp-load.php\"; do_action(\"rest_api_init\"); $routes = rest_get_server()->get_routes(); foreach ([\"/presszone-international/v1/exceptions\",\"/presszone-international/v1/exceptions/import\",\"/presszone-international/v1/exceptions/sync\",\"/presszone-international/v1/exceptions/pull\"] as $r) { echo $r, isset($routes[$r]) ? \" OK\" : \" MISSING\", PHP_EOL; }' → four OK lines. Commit only: plugins/international-press-zone/includes/API/ExceptionsController.php, plugins/international-press-zone/includes/Core/Plugin.php.", "requires_decision": null}
{"type": "task", "id": "t6", "wave": 2, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 6 (Settings REST delegation) for the full contract. Delegate tone, auto_publish and debug_mode to Translation\\Settings in getSettings/updateSettings/resetSettings; PUT response shape unchanged. Acceptance: podman exec devzone-wordpress php -r 'require \"/var/www/html/wp-load.php\"; \\InternationalPressZone\\Translation\\Settings::instance()->set_tone(\"casual\"); do_action(\"rest_api_init\"); $d = rest_do_request(new WP_REST_Request(\"GET\",\"/presszone-international/v1/settings\"))->get_data()[\"data\"]; echo ((($d[\"tone\"] ?? \"\") === \"casual\" && array_key_exists(\"auto_publish\",$d) && array_key_exists(\"debug_mode\",$d)) ? \"PASS\" : \"FAIL\"), PHP_EOL;' → PASS. Commit only: plugins/international-press-zone/includes/API/SettingsController.php.", "requires_decision": null}
{"type": "task", "id": "t7", "wave": 2, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 7 (Auto-publish wiring) for the full contract. One rule in authorizedTargetStatus(): with no explicit caller status, auto-publish on means publish. Literal code is in the plan — apply inline. Acceptance: podman exec devzone-wordpress php -l /var/www/html/wp-content/plugins/international-press-zone/includes/Translation/TranslationFinalizer.php → No syntax errors detected. Commit only: plugins/international-press-zone/includes/Translation/TranslationFinalizer.php.", "requires_decision": null}
{"type": "task", "id": "t8", "wave": 3, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 8 (Exceptions tab component) for the full contract. New vanilla-JS ExceptionsTab.js consuming the six exceptions routes; add form, table, bulk import, sync row. Acceptance: cd plugins/international-press-zone/admin && npx eslint src/components/ExceptionsTab.js → exit 0, no warnings. Commit only: plugins/international-press-zone/admin/src/components/ExceptionsTab.js.", "requires_decision": null}
{"type": "task", "id": "t9", "wave": 3, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 9 (Settings page controls) for the full contract. Tone Select and auto-publish Toggle in renderGeneralSettings(), extended save payload, Exceptions tab registered. Acceptance: cd plugins/international-press-zone/admin && npx eslint src/pages/settings.js && grep -c \"auto_publish\" src/pages/settings.js → clean lint, count >= 2. Commit only: plugins/international-press-zone/admin/src/pages/settings.js.", "requires_decision": null}
{"type": "task", "id": "t10", "wave": 4, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 10 (Admin build) for the full contract. Rebuild the admin bundle so wave-5 journeys run against the new UI; every warning addressed, none suppressed. Acceptance: cd plugins/international-press-zone/admin && npm run build 2>&1 | tee /tmp/ipz-build.log; grep -Ei \"warn|error\" /tmp/ipz-build.log → build succeeds, no warning or error lines. Commit only: plugins/international-press-zone/admin/dist.", "requires_decision": null}
{"type": "task", "id": "t15", "wave": 4, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 15 (Auto-publish status integration check) for the full contract. PHP integration test asserting post_status across four auto-publish cases with a stubbed payload — no live backend call. Acceptance: podman exec devzone-wordpress php /var/www/html/wp-content/plugins/international-press-zone/tests/integration/AutoPublishStatusTest.php; echo \"exit=$?\" → four PASS lines and exit=0. Commit only: plugins/international-press-zone/tests/integration/AutoPublishStatusTest.php.", "requires_decision": null}
{"type": "task", "id": "t16", "wave": 4, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 16 (E2E journey runner) for the full contract. Fail-closed wrapper encoding the SSH reverse tunnel + e2e-remote invocation; verified mechanics are literal in the plan. Acceptance: from plugins/international-press-zone/tests/e2e/: ./run-journey.sh journeys/UJ-006-save-settings.spec.js → PASS; ./run-journey.sh with no argument exits non-zero with a usage line. Commit only: plugins/international-press-zone/tests/e2e/run-journey.sh.", "requires_decision": null}
{"type": "task", "id": "t11", "wave": 5, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 11 (Journey UJ-022 — tone and auto-publish persist) for the full contract. Playwright journey asserting tone persists across reload and auto_publish round-trips through GET /settings. Acceptance: from plugins/international-press-zone/tests/e2e/: ./run-journey.sh journeys/UJ-022-set-translation-tone.spec.js → all branches PASS. Commit only: plugins/international-press-zone/tests/e2e/journeys/UJ-022-set-translation-tone.spec.js, plugins/international-press-zone/tests/e2e/journeys/UJ-022-set-translation-tone.spec.manifest.json.", "requires_decision": null}
{"type": "task", "id": "t12", "wave": 5, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 12 (Journey UJ-023 — debug round-trip and reset) for the full contract. Asserts debug_mode reads back from the canonical option and that reset restores tone/auto_publish/debug defaults. Acceptance: from plugins/international-press-zone/tests/e2e/: ./run-journey.sh journeys/UJ-023-debug-mode-round-trip.spec.js → all branches PASS. Commit only: plugins/international-press-zone/tests/e2e/journeys/UJ-023-debug-mode-round-trip.spec.js, plugins/international-press-zone/tests/e2e/journeys/UJ-023-debug-mode-round-trip.spec.manifest.json.", "requires_decision": null}
{"type": "task", "id": "t13", "wave": 5, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 13 (Journey UJ-024 — add and delete an exception) for the full contract. Covers add, duplicate 409, delete, and a slash-containing exception text. Acceptance: from plugins/international-press-zone/tests/e2e/: ./run-journey.sh journeys/UJ-024-manage-exceptions.spec.js → all branches PASS. Commit only: plugins/international-press-zone/tests/e2e/journeys/UJ-024-manage-exceptions.spec.js, plugins/international-press-zone/tests/e2e/journeys/UJ-024-manage-exceptions.spec.manifest.json.", "requires_decision": null}
{"type": "task", "id": "t14", "wave": 5, "seat": "coder", "tier": "medium", "desc": "Read docs/plans/2026-08-04-ipz-advanced-settings.md Task 14 (Journey UJ-025 — bulk import counts) for the full contract. Covers added/skipped counts for fresh lines, duplicates plus blanks, and an over-500-character line. Acceptance: from plugins/international-press-zone/tests/e2e/: ./run-journey.sh journeys/UJ-025-bulk-import-exceptions.spec.js → all branches PASS. Commit only: plugins/international-press-zone/tests/e2e/journeys/UJ-025-bulk-import-exceptions.spec.js, plugins/international-press-zone/tests/e2e/journeys/UJ-025-bulk-import-exceptions.spec.manifest.json.", "requires_decision": null}
