manifest.json

[
 {
  "id": "WO-00",
  "pkg": "A",
  "sev": "P0",
  "lane": "ENG",
  "title": "Pin audit commit and diff to current main",
  "body": "**Finding:** Audit pinned `fc8b03f9`; local main is already at `15a6ba29b`. Every finding must be re-anchored before work is assigned.\n**Files:** repo root; `OPEN_ITEMS.md`; `docs/BUILD_DEBT.md`.\n**Fix:** `git diff fc8b03f9..main --stat` over the files named in WO-01..33; mark each finding *unchanged / moved / already fixed*. Reconcile against `OPEN_ITEMS.md` so no duplicate remediation tickets exist (report §Findings 4).\n**Acceptance:** a table in `docs/audits/AUDIT_2026-09-06_RECONCILIATION.md` with one row per R-reference: path at fc8b03f9, path at main, status, ticket. All 33 rows filled.\n**Depends on:** none.",
  "deps": []
 },
 {
  "id": "WO-31",
  "pkg": "A",
  "sev": "P2",
  "lane": "OWNER",
  "title": "Reconcile open register with audit",
  "body": "**Finding:** `OPEN_ITEMS.md` already lists pilot, MMM and activation gaps [R31]; some older defect lists are obsolete (#804 closed via #809/#810).\n**Files:** `OPEN_ITEMS.md`, `docs/BUILD_DEBT.md`.\n**Fix:** merge WO-01..33 into the existing register; close items superseded by Sep 2 state; do not create a competing status doc.\n**Acceptance:** one register, every WO linked, no duplicate of an already-closed item.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-30",
  "pkg": "A",
  "sev": "P2",
  "lane": "ENG",
  "title": "Verify onboarding lane-readiness evidence join",
  "body": "**Finding:** Lane readiness is derived from an evidence join whose inputs were not verified [R30].\n**Files:** `miz-oki-command-center-ui/app/api/bff/lanes/status/route.ts` (+ `.test.ts`); onboarding page.\n**Fix:** trace each readiness flag to its evidence source; readiness must not report *ready* from a default or missing record.\n**Acceptance:** test: tenant with no economics record → lane status `not_ready`, never `ready`.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-01",
  "pkg": "B",
  "sev": "P0",
  "lane": "ENG",
  "title": "Make hard-gate failures terminal in policy eligibility",
  "body": "**Finding:** Six-check validator with a failed incremental-profit check still returned ELIGIBLE at DEL 91.7 because eligibility uses an aggregate pass-rate floor [R1][R2].\n**Files:** `services/service-policy-engine/main.py` (pass_rate / DEL); `services/service-validation-orchestrator/main.py` (incremental_profit check); `services/service-decision-control-plane/main.py`.\n**Fix:** partition checks into *hard* (economic, integrity, consent, policy) and *rank*. Any hard failure → `INELIGIBLE` before DEL is computed. Exploratory experiments get their own bounded eligibility class, never a hidden exception.\n**Acceptance:** negative tests: each hard check failing alone, with all others passing at 100%, → INELIGIBLE. Property test: no combination of rank scores can flip a hard failure.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-02",
  "pkg": "B",
  "sev": "P0",
  "lane": "ENG",
  "title": "Reject unbounded exploration",
  "body": "**Finding:** Companion to WO-01: exploration must be explicit and capped, not a side effect of averaging [R1].\n**Files:** `services/service-policy-engine/main.py`.\n**Fix:** `eligibility_class ∈ {standard, exploration}`; exploration requires an approved envelope ID, cap, and logged assignment probability.\n**Acceptance:** exploration candidate without envelope → refused; with envelope over cap → refused.\n**Depends on:** WO-01.",
  "deps": [
   "WO-01"
  ]
 },
 {
  "id": "WO-03",
  "pkg": "B",
  "sev": "P0",
  "lane": "SEC",
  "title": "Bind evidence passports to the decision",
  "body": "**Finding:** DCP consumed a fetched passport's aggregate scores without checking tenant/domain/path binding or seal; a foreign, invalidly sealed passport yielded a signed Stage-4 authorization [R3].\n**Files:** `services/service-decision-control-plane/main.py`, `decision_meter.py`.\n**Fix:** resolve passports as immutable records; verify seal; bind tenant, action fingerprint, model version, horizon, validity window into the signed authorization payload.\n**Acceptance:** tests: foreign-tenant passport, stale passport, altered-body passport, wrong-action passport → each refused with a distinct reason code. Authorization signature covers the binding fields.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-04",
  "pkg": "B",
  "sev": "P0",
  "lane": "MEAS",
  "title": "Prove holdout registration, not a boolean",
  "body": "**Finding:** Experiment sufficiency depends on a proposer boolean; a nonblank holdout ID at the adapter does not prove pre-exposure registration [R4].\n**Files:** `services/service-action-runner/execution_adapters/base.py`, `meta_ads.py` (holdout checks); DCP.\n**Fix:** adapter resolves holdout ID against the experiment registry; requires `registered_at < first_exposure_at` and a matching tenant.\n**Acceptance:** unregistered ID, post-exposure registration, other-tenant registration → refused.\n**Depends on:** WO-03.",
  "deps": [
   "WO-03"
  ]
 },
 {
  "id": "WO-05",
  "pkg": "B",
  "sev": "P0",
  "lane": "SEC",
  "title": "Derive approver identity from authentication",
  "body": "**Finding:** Approval service compares a request-body actor string with the requesting service; the same service passes by inventing a human name [R5].\n**Files:** `services/service-approval-routing/main.py`; principal auth module.\n**Fix:** approver identity and role come only from the verified principal; body-supplied actor fields are ignored or must match the principal. Service allowlisting ≠ human approval.\n**Acceptance:** HTTP test with a service principal and a body actor of a different human → 403. Test with a verified human principal lacking the role → 403.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-06",
  "pkg": "B",
  "sev": "P0",
  "lane": "SEC",
  "title": "Verify rollback proof before promotion",
  "body": "**Finding:** Actuator registration can assert `rollback_demonstrated=True`; promotion trusts it without a drill [R6].\n**Files:** `services/service-action-runner/main.py`; `tests/governance/test_action_runner.py`, `test_decision_control_plane.py`; `ops/remediation/live_proof.py`.\n**Fix:** promotion requires a stored proof artifact (drill ID, tenant, account, action class, timestamp, outcome) per tenant/account/action; registration flags are advisory only.\n**Acceptance:** promotion with flag=True and no artifact → refused; with artifact for a different action class → refused.\n**Depends on:** WO-05.",
  "deps": [
   "WO-05"
  ]
 },
 {
  "id": "WO-07",
  "pkg": "B",
  "sev": "P0",
  "lane": "ENG",
  "title": "Single-use approval under concurrency",
  "body": "**Finding:** Concurrent redemption of one approval issued two distinct authorization IDs [R7].\n**Files:** `services/service-decision-control-plane/main.py` (approval redemption); Firestore/DB layer.\n**Fix:** atomic claim on the decision/approval; deterministic authorization ID derived from (approval_id, decision_fingerprint); retries return the same stored result.\n**Acceptance:** 50-way concurrent redemption test → exactly one authorization ID; crash-after-write retry → same ID; contention at every write boundary covered.\n**Depends on:** WO-03.",
  "deps": [
   "WO-03"
  ]
 },
 {
  "id": "WO-15",
  "pkg": "C",
  "sev": "P0",
  "lane": "SEC",
  "title": "Role-check the onboarding mutation handlers",
  "body": "**Finding:** Onboarding page requires admin, but economics / cost / connector-credential save handlers check tenant identity only; viewer identity returned 200 and invoked all three saves [R15][R16].\n**Files:** `miz-oki-command-center-ui/app/api/bff/tenant-economics/save/route.ts`; connector credential save route under `app/api/bff/connectors/`; reference pattern in `app/api/bff/actions/authorize/route.ts`.\n**Fix:** apply the canonical role + actor check from the authorize route to all three mutations; backend economics/cost routes verify end-user role, not just service + tenant.\n**Acceptance:** Vitest: viewer → 403 on all three, no adapter call; admin → 200. Backend route test with valid service token but viewer role → 403.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-16",
  "pkg": "C",
  "sev": "P0",
  "lane": "SEC",
  "title": "Inventory the end-user role model",
  "body": "**Finding:** Companion to WO-15: role checks exist only on some routes.\n**Files:** `miz-oki-command-center-ui/app/api/**/route.ts`.\n**Fix:** generate a route → required-role table; every mutating route must have a non-null entry.\n**Acceptance:** CI test fails if a mutating route has no role annotation.\n**Depends on:** WO-15.",
  "deps": [
   "WO-15"
  ]
 },
 {
  "id": "WO-17",
  "pkg": "C",
  "sev": "P0",
  "lane": "ENG",
  "title": "Fail closed on empty tenant registry",
  "body": "**Finding:** Shared tenant resolver permits arbitrary tenant input when its registry is empty; a registry read failure produces that state [R17].\n**Files:** tenant resolver (DCP `decision_meter.py`; policy engine `main.py`; shared resolver in `src/`/`common/` — locate in WO-00).\n**Fix:** strict mode refuses unknown tenants; distinguish `unavailable` from `intentionally_empty`; last-good cache only with TTL and documented policy. Enforce stored-tenant ownership on DCP reads and runner execute/rollback/outcome writes.\n**Acceptance:** registry read raises → resolution refused; empty registry in strict mode → refused; cross-tenant read of a stored decision → 404/403.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-18",
  "pkg": "C",
  "sev": "P0",
  "lane": "ENG",
  "title": "One versioned constraint state from Decide to settlement",
  "body": "**Finding:** Policy reads treasury from tenant vaults; DCP/Act loads an optional global file at startup, so a per-proposal treasury pass does not establish an aggregate reservation [R18].\n**Files:** `services/service-decision-control-plane/main.py`, `decision_meter.py`; `services/service-action-runner/main.py`; `services/service-policy-engine/main.py`, `pacing_veto.py`.\n**Fix:** single per-tenant versioned constraint resolver used at admission, reservation, execution, settlement; currency, horizon, freshness bound to the action.\n**Acceptance:** test: policy-level treasury pass with no DCP reservation → execution refused; stale constraint version → refused.\n**Depends on:** WO-17.",
  "deps": [
   "WO-17"
  ]
 },
 {
  "id": "WO-19",
  "pkg": "C",
  "sev": "P0",
  "lane": "ENG",
  "title": "Persist atomic exposure reservations and freezes",
  "body": "**Finding:** Portfolio exposure and reconciliation freezes are process-local dicts; two $70 checks against a $100 cap both passed → $140 exposure [R19].\n**Files:** `services/service-action-runner/execution_adapters/portfolio.py`, `base.py`.\n**Fix:** move reservations/freezes to a transactional store (Firestore transaction or equivalent); check-and-reserve is one atomic op keyed by tenant/account.\n**Acceptance:** two workers, two processes, $70+$70 vs $100 cap → exactly one passes; restart mid-reservation → reservation survives.\n**Depends on:** WO-18.",
  "deps": [
   "WO-18"
  ]
 },
 {
  "id": "WO-20",
  "pkg": "C",
  "sev": "P0",
  "lane": "ENG",
  "title": "Cover the whole mutation-and-verification interval",
  "body": "**Finding:** An ambiguous exception inside `adapter.execute` is raised before the freeze handler's try-block [R20].\n**Files:** `services/service-action-runner/execution_adapters/base.py`, `main.py`.\n**Fix:** wrap dispatch → provider call → read-back in one guarded span; unknown outcome → freeze + reconcile before any retry; state machine proposed→validated→authorized→dispatched→confirmed/uncertain/failed→compensated/closed.\n**Acceptance:** fault-injection tests: provider success + client timeout, crash after provider success, duplicate delivery → no duplicate spend effect, freeze recorded.\n**Depends on:** WO-19.",
  "deps": [
   "WO-19"
  ]
 },
 {
  "id": "WO-21",
  "pkg": "C",
  "sev": "P0",
  "lane": "SEC",
  "title": "Authenticate the Boss service perimeter",
  "body": "**Finding:** Production entry re-exports the Boss app; chat and direct-action handlers have no auth dependency and the deploy config requests public access [R21].\n**Files:** `miz-oki-adk-agents/boss/app.py`, `miz-oki-adk-agents/app/main.py`; deploy workflows carrying `allow-unauthenticated`/`allUsers` (see `.github/workflows/deploy-governance-services.yml` and others found in WO-00).\n**Fix:** explicit public/private route inventory; auth dependency on chat and direct-action; deploy config no longer requests public invoker unless the route inventory says so.\n**Acceptance:** anonymous request to direct-action → 401 in test client; route inventory committed; IAM invoker policy verified by OPS (read-only check).\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-08",
  "pkg": "D",
  "sev": "P1",
  "lane": "ENG",
  "title": "Tenant-key every net-yield aggregation",
  "body": "**Finding:** Return-rate SQL groups by SKU without tenant_id; order-rate stage joins by order_id alone; final tenant MERGE cannot undo pooled inputs [R8]. Finding is from generated-SQL inspection, not BigQuery execution.\n**Files:** `services/net-yield/compute.py`, `bq.py`, `test_compute.py`.\n**Fix:** carry tenant_id through every CTE, join, group-by, and maturity window.\n**Acceptance:** two-tenant invariance test against a real BigQuery test dataset: replacing tenant B's rows changes nothing in tenant A's output. Generated SQL snapshot test asserts tenant_id in every GROUP BY / JOIN ON.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-09",
  "pkg": "D",
  "sev": "P1",
  "lane": "ENG",
  "title": "Replay-safe refunds, fees and changed orders",
  "body": "**Finding:** $40 refund doubled to $80 under concurrency/retry; refund before order lost; two flat fees overwrote each other; changed orders kept stale COGS [R9].\n**Files:** `services/net-yield/returns_adjustment.py`, `bq.py`, `cost_config.py`; tests `test_order_economics.py`, `test_bq.py`.\n**Fix:** durable unique event ledger keyed by provider event ID; atomic transitions or deterministic materialization; unmatched refunds retained and re-matched; versioned recompute on order change; fees keyed by (tenant, fee_type).\n**Acceptance:** against a real test DB: duplicate refund delivery → one entry; refund-before-order → matched later; crash-and-retry → idempotent; two fee types → both kept; order change → COGS recomputed.\n**Depends on:** WO-08.",
  "deps": [
   "WO-08"
  ]
 },
 {
  "id": "WO-10",
  "pkg": "E",
  "sev": "P1",
  "lane": "MEAS",
  "title": "Replace individual caused/anticipated labels with experiment-level estimands",
  "body": "**Finding:** Causal credit labels first-N conversions anticipated, rest caused; swapping two timestamps moved summed caused value $1,000 → $10 [R10].\n**Files:** `services/measurement-rails/causal_credit.py`, `main.py`, `test_causal_credit.py`.\n**Fix:** compute incremental revenue/profit at the assignment-unit level with intervals; any per-purchase allocation is labeled `convention`, never `causal`.\n**Acceptance:** permutation test: reordering purchase timestamps within a cell does not change the estimand; output schema carries `estimand`, `ci_low`, `ci_high`, `n_units`.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-11",
  "pkg": "E",
  "sev": "P1",
  "lane": "MEAS",
  "title": "Stop feeding the point sum into Meridian calibration",
  "body": "**Finding:** MMM export consumes the caused-value sum as a calibration point estimate [R11].\n**Files:** `services/service-media-incrementality/main.py`; `services/service-validation-orchestrator/main.py` (meridian export).\n**Fix:** export experiment-level effect + interval from WO-10; refuse export when the estimand is a convention.\n**Acceptance:** export test: convention-labeled input → export refused; experiment input → prior with SD populated.\n**Depends on:** WO-10.",
  "deps": [
   "WO-10"
  ]
 },
 {
  "id": "WO-12",
  "pkg": "E",
  "sev": "P1",
  "lane": "MEAS",
  "title": "Cell 26: honest evaluation split and interval",
  "body": "**Finding:** Policy evaluated on data including its training rows; interval from dispersion of predicted individual effects omits fitting uncertainty [R12].\n**Files:** cell 26 module (resolve via `config/actual_urls.py` in WO-00); reuse seeded-bootstrap / grouped cross-fitting from `services/lift-engine`.\n**Fix:** grouped cross-fit evaluation; bootstrap over refits; report exposure counts.\n**Acceptance:** leakage test: evaluation rows disjoint from training rows; interval widens when n shrinks.\n**Depends on:** WO-10.",
  "deps": [
   "WO-10"
  ]
 },
 {
  "id": "WO-13",
  "pkg": "E",
  "sev": "P1",
  "lane": "MEAS",
  "title": "Cell 27: refresh intervals on posterior update",
  "body": "**Finding:** Posterior parameters update but promotion still reads the original stored intervals, so no winner is ever selected [R13].\n**Files:** cell 27 module (resolve in WO-00).\n**Fix:** recompute and persist intervals on every update; promotion reads the current version.\n**Acceptance:** lifecycle test: after N updates with a clear winner, promotion selects it.\n**Depends on:** WO-12.",
  "deps": [
   "WO-12"
  ]
 },
 {
  "id": "WO-14",
  "pkg": "E",
  "sev": "P2",
  "lane": "MEAS",
  "title": "Provenance on F2 retention multipliers",
  "body": "**Finding:** Multipliers are useful scenario inputs but lack assumption-vs-effect provenance [R14].\n**Files:** `src/shared/growth_control/f2_ltv/dtr.py`; `tests/governance/test_f2_ltv.py`; `services/net-yield/test_returns_adjusted_f2_bridge.py`.\n**Fix:** each multiplier carries `provenance ∈ {assumption, baseline, measured_effect}`; proposals and bid values may consume only `measured_effect`.\n**Acceptance:** test: assumption-tagged multiplier in a bid-value path → refused.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-29",
  "pkg": "E",
  "sev": "P3",
  "lane": "MEAS",
  "title": "Dosage estimator: held-out real-data test",
  "body": "**Finding:** Synthetic smoke recovered 3.0274 vs known 3.0 and refused constant dose; that is algorithmic, not marketing, evidence [R29].\n**Files:** `services/lift-engine/continuous_dosage.py`, `src/core/continuous_dosage.py`, `tests/test_continuous_dosage.py`.\n**Fix:** add nonlinear synthetic cases (saturation, carryover); then a bounded prospective real-data test under WO-41.\n**Acceptance:** saturation fixture recovered within tolerance; support-range refusal test.\n**Depends on:** WO-41.",
  "deps": [
   "WO-41"
  ]
 },
 {
  "id": "WO-22",
  "pkg": "F",
  "sev": "P2",
  "lane": "ENG",
  "title": "Quarantine the legacy omnichannel allocator",
  "body": "**Finding:** Routable allocation API returns hardcoded defaults on missing data/exception: $68,000 budget, $281,835.51 projected revenue from zero input; channel budgets summed to $53,828.12; 267,000% conversion rate [R22][R23].\n**Files:** `miz-oki-command-center-ui/app/api/omnichannel/allocation/route.ts`.\n**Fix:** return `unavailable` on missing live evidence; simulations explicitly labeled; assert allocated + unallocated = budget; guard zero denominators.\n**Acceptance:** zero-input → 422 `evidence_unavailable`; sum invariant test; missing clicks → rate `null`, not a number.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-23",
  "pkg": "F",
  "sev": "P2",
  "lane": "ENG",
  "title": "Assert no path from legacy allocator into DCP execution",
  "body": "**Finding:** No connection to canonical DCP execution was demonstrated, but not disproven [R23].\n**Files:** as WO-22; DCP intake.\n**Fix:** grep-based CI guard that the legacy route's output type is never accepted by DCP proposal intake.\n**Acceptance:** CI test present and green.\n**Depends on:** WO-22.",
  "deps": [
   "WO-22"
  ]
 },
 {
  "id": "WO-24",
  "pkg": "F",
  "sev": "P2",
  "lane": "ENG",
  "title": "Google Ads adapter: upgrade off sunset v21",
  "body": "**Finding (re-confirmed on local main 15a6ba29b):** `google_ads.py:55` defaults `GOOGLE_ADS_API_VERSION` to `v21`; v21 sunset 5 Aug 2026; no version override in the runner workflow; adapters checked disabled. Dormant activation blocker [R24][W16][W17].\n**Files:** `services/service-action-runner/execution_adapters/google_ads.py`; runner deploy workflow env.\n**Fix:** default to a currently supported version (release notes list v25.1, 19 Aug 2026 — confirm latest supported at implementation time); test every mutation and read-back contract against the new version.\n**Acceptance:** validate-only mutation + read-back succeeds in a test account; CI asserts default version is not in Google's sunset list.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-25",
  "pkg": "F",
  "sev": "P2",
  "lane": "ENG",
  "title": "Data Manager connector: fix request contract",
  "body": "**Finding:** Existing connector omits `productDestinationId`, never consumes `conversion_action`, sends `conversionValue` as an object instead of number + sibling currency, and omits encoding for hashed `userData`. Independently confirmed against REST schema [R25][W18][W19]. Do not build a second connector.\n**Files:** `services/service-data-manager-connector/main.py`; `miz-oki-adk-agents/kg-canonical-ingest/mappers/google_ads.py`.\n**Fix:** conform to Event / IngestEvents / Destination schema; multi-action destination routing; validate-only reporting surfaced.\n**Acceptance:** schema-validation unit tests; validate-only ingest accepted in a test account; final ingestion diagnostics captured.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-33",
  "pkg": "F",
  "sev": "P3",
  "lane": "CUST",
  "title": "Wire the site pilot request callback",
  "body": "**Finding:** Site pilot request construction exists with an unwired callback [R33].\n**Files:** website pilot intake (locate in WO-00 — not found under repo root; may live in the website repos).\n**Fix:** wire callback to the pilot intake route; confirm delivery.\n**Acceptance:** submit test request → record appears in intake store.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-26",
  "pkg": "H",
  "sev": "P2",
  "lane": "ENG",
  "title": "Protect the exact commit that ships",
  "body": "**Finding:** main unprotected (rulesets API 403, plan-related); auto-merge reruns gates on merge result but the push-retry path can rebase after the check [R0][R26]. Several MCP/spec/origin suites absent from CI wiring.\n**Files:** `.github/workflows/auto-merge-ai-branches.yml`, `auto-merge-grothendieck.yml`, `auto-merge-mcclintock.yml`, `auto-sync-main.yml`, `ci.yaml`.\n**Fix:** retry path re-runs gates on the rebased SHA or fails; required checks at repo level (branch protection if rulesets unavailable on plan); map every required suite to a CI job.\n**Acceptance:** simulated rebase-after-check → merge blocked; required-checks list committed and enforced.\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-27",
  "pkg": "H",
  "sev": "P2",
  "lane": "ENG",
  "title": "Extend dependency locking by service",
  "body": "**Finding:** 419 unbounded declarations in 52 of 135 requirements manifests; pin ratchet covers only Firestore and google-api-core [R27]. Not a vulnerability scan.\n**Files:** `tests/test_client_library_pin_ratchet.py`; per-service `requirements*.txt`.\n**Fix:** lockfiles per deployed service; ratchet extended to all deployed services; advisory scan added as a separate job.\n**Acceptance:** ratchet test covers every service in the deploy allowlist (`tests/governance/test_deploy_allowlist_completeness.py` pattern).\n**Depends on:** WO-00.",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-28",
  "pkg": "H",
  "sev": "P3",
  "lane": "OPS",
  "title": "Authenticated customer-journey smoke at each deploy",
  "body": "**Finding:** GitHub records green Boss/UI deploys at the pinned commit; no fresh authenticated journey exercised [R28].\n**Files:** `.github/workflows/ci.yaml`, deploy workflows.\n**Fix:** post-deploy job runs an authenticated tenant journey against the named revision.\n**Acceptance:** job reports revision name + journey pass/fail; not just build success.\n**Depends on:** WO-21.",
  "deps": [
   "WO-21"
  ]
 },
 {
  "id": "WO-32",
  "pkg": "H",
  "sev": "P2",
  "lane": "SEC",
  "title": "Certification evaluator enforcement scope",
  "body": "**Finding:** Certification evaluator exists; its enforcement scope is narrower than the promotion path [R32].\n**Files:** `services/service-action-runner/execution_adapters/portfolio.py`; `services/service-decision-control-plane/decision_meter.py`.\n**Fix:** promotion calls the evaluator per tenant/account/action; no bypass path.\n**Acceptance:** promotion without a certification record → refused.\n**Depends on:** WO-06.",
  "deps": [
   "WO-06"
  ]
 },
 {
  "id": "WO-40",
  "pkg": "G",
  "sev": "P1",
  "lane": "CUST",
  "title": "Select one external design partner",
  "body": "**Current disposition (reproduced 2026-09-17):** `BLOCKED-ON-OWNER` on OPEN_ITEMS L6-1. The engineering dependencies are closed (#983 / WO-15, #985 / WO-17, #972 / WO-04, and #978 / WO-10), the authenticated `/onboarding` surface and tenant vault exist, and the target registry still contains no named organization. An agent must not invent or select a counterparty.\n\n**Owner action:** name one organization in a dated ruling and fill one organization-only slot in `docs/gtm/DESIGN_PARTNER_TARGETS.yaml`. Do not put a person, e-mail address, phone number, credential, economics input, or other tenant-owned value in git or chat.\n\n**Then:** the selected partner completes authenticated `/onboarding`; only after the resulting tenant has real economics and at least one live read-only connector may this work order close. WO-41 starts after that tenant exists; WO-42 and WO-43 remain chained behind WO-41.\n\n**Acceptance:** tenant record with real economics and at least one live read-only connector.\n**Depends on:** owner decision L6-1. Engineering dependencies WO-15 and WO-17 are closed.",
  "deps": [
   "WO-15",
   "WO-17"
  ]
 },
 {
  "id": "WO-41",
  "pkg": "G",
  "sev": "P1",
  "lane": "MEAS",
  "title": "Preregister one powered experiment",
  "body": "**Fix:** declare tenant, unit, treatment, comparator, primary outcome, horizon, return maturity, MDE, power, alpha, exposure limits, stopping rule before exposure; register salt/holdout in the registry (WO-04).\n**Acceptance:** registration record timestamped before first exposure; independent MEAS sign-off.\n**Depends on:** WO-04, WO-10, WO-40.",
  "deps": [
   "WO-04",
   "WO-10",
   "WO-40"
  ]
 },
 {
  "id": "WO-42",
  "pkg": "G",
  "sev": "P1",
  "lane": "ENG",
  "title": "One complete decision-to-outcome trace",
  "body": "**Fix:** produce the compact decision record (§7): tenant/account/action, evidence versions, baseline, distributions, approved spend/horizon, constraint snapshot, registration, approver, authorization + reservation IDs, provider pre/post state, rollback state, mature outcome.\n**Acceptance:** one real decision with every field populated from system records, no manual fill.\n**Depends on:** all P0 in B and C; WO-41.",
  "deps": [
   "WO-41"
  ]
 },
 {
  "id": "WO-43",
  "pkg": "G",
  "sev": "P1",
  "lane": "OWNER",
  "title": "Readout and promotion decision",
  "body": "**Fix:** report incremental contribution after acquisition with uncertainty, iCAC, payback, reconciled coverage, duplicate/unknown-action counts; decide next investment by conservative benefit / total cost ≥ 10 hurdle.\n**Acceptance:** readout may say \"insufficient evidence\"; no public claim without evidence-class enforcement.\n**Depends on:** WO-42.",
  "deps": [
   "WO-42"
  ]
 },
 {
  "id": "WO-44",
  "pkg": "H",
  "sev": "P0",
  "lane": "OWNER",
  "title": "Org transfer: rule A/B and restore the homepage deploy lane",
  "body": "**Finding (measured 2026-09-04, PR #948 body; `docs/runbooks/ORG_MIGRATION_HOMEPAGE_LANE_REPAIR_2026-09-04.md`):** `MIZOKICloudRun` moved from the `mediaintelligence` account into org `MIZOKI-3-5` on 2026-09-04. `deploy-homepage.yml` has failed since 2026-09-03T00:44Z and nobody noticed (dispatch-only). Five guards fail: (1) repo-identity literal — fixed by #948; (2) `ACTOR_ID != OWNER_ID` structurally unsatisfiable in an org; (3) WIF pool `attributeCondition` and (4) `homepage-prod-deployer@` `principalSet` are GCP-side; (5) `ref_protected` is FALSE and CANNOT be set — rulesets/branch protection on a private repo in a Free org return 403. The same plan limit blocks WO-26 (protect the exact commit that ships / V4-17) and environment `required_reviewers`.\n**Files:** `.github/workflows/deploy-homepage.yml`, `.github/workflows/fix-homepage-deploy.yml`; `tests/governance/test_homepage_deploy_guard.py`; GCP WIF pool + SA binding (owner `gcloud`, runbook §5, new binding before old).\n**Fix:** Owner ruling A — recommended A1: explicit actor-id allowlist `{163805125}` (already pinned by #963/`037233b05`); A2 environment `required_reviewers` added once the plan allows. Owner ruling B — recommended B1: upgrade org to GitHub Team (restores rulesets, `ref_protected`, unblocks WO-26/V4-17, enables A2). B2 (make repo public) is irreversible — not recommended. B3 (drop guard 5) asserts a protection the platform no longer enforces — refuse. Then run the two GCP commands and dispatch one homepage deploy.\n**Acceptance:** rulings A and B recorded in `OPEN_ITEMS.md`; `gh api repos/MIZOKI-3-5/MIZOKICloudRun/branches/main -q .protected` returns `true`; one owner-dispatched `deploy-homepage.yml` run passes all five guards and live-verifies on mizoki3.com. Until then homepage production deploys are honestly BLOCKED — never patched green.\n**Depends on:** none. **Blocks:** WO-26.\n**Owning prompt:** owner (rulings, billing, gcloud); CX-4 for any workflow edit.",
  "deps": []
 },
 {
  "id": "WO-45",
  "pkg": "F",
  "sev": "P1",
  "lane": "ENG",
  "title": "Retire the v22 uploadClickConversions rail; Data Manager rail is the pilot path",
  "body": "**Finding (confirmed on main 635318712):** `services/measurement-rails/offline_conversions.py:30` pins `GOOGLE_ADS_API_VERSION = \"v22\"` and builds `customers/{id}:uploadClickConversions` payloads (line 124). Two clocks run against it: since 2026-06-15 the Ads API refuses NEW adopters of offline conversion imports (official post 2026-05-15; `CUSTOMER_NOT_ALLOWLISTED_FOR_THIS_FEATURE`; only developer tokens with Dec 2025–May 2026 import history keep access) — a first design partner has no such history under our token; and v22 sunsets ~2026-10-07 (secondary source; confirm on the official sunset page). This is a SECOND sunset-pinned Google site beside WO-24's `google_ads.py` v21. `services/service-data-manager-connector` already speaks `datamanager.googleapis.com/v1/events:ingest` (WO-25 fixes its contract).\n**Files:** `services/measurement-rails/offline_conversions.py`, `services/measurement-rails/test_rails_offline.py`, `services/measurement-rails/flags.py`; connector-health panel adapter in `miz-oki-command-center-ui/lib/bff/adapters/`.\n**Fix:** keep the provider-neutral front half (gclid→gbraid→wbraid precedence, 90-day window, before-click rejection — unit-tested) and route the send through the Data Manager connector; the legacy `uploadClickConversions` builder becomes compatibility-only behind an explicit `LEGACY_ADS_API_OFFLINE=true` flag that refuses when the pinned version is past its recorded sunset date or the tenant has no recorded pre-2026-06-15 import. Add Data Manager developer-token/allowlist eligibility to connector health.\n**Acceptance:** test: default path never emits an `uploadClickConversions` payload; test: legacy path refuses past sunset and without allowlist evidence; validate-only `events:ingest` accepted in a test account (shared with WO-25); CI asserts no `GOOGLE_ADS_API_VERSION` literal in the tree is on Google's sunset list (extend WO-24's check to all sites).\n**Depends on:** WO-00, WO-25.\n**Owning prompt:** CC-4 (`services/measurement-rails/**`); the sunset-list CI assertion lands with CX-3/WO-24.",
  "deps": [
   "WO-00",
   "WO-25"
  ]
 },
 {
  "id": "WO-46",
  "pkg": "A",
  "sev": "P0",
  "lane": "OPS",
  "title": "Re-authorize the GitHub App for org MIZOKI-3-5 and repoint every stale repo reference",
  "body": "**Finding:** The 2026-08-18 account-level GitHub App grant was made on `mediaintelligence`; an org installation is a separate authorization. Cloud/fleet Claude sessions, the Sep 4 review and the create_issues batch all fail on the repo (404 / token refuses). Memory ledger `4b3208ff0` notes the token lacks `admin:org`. #953 fixed in-repo URLs, but prompt-board files on Drive, scheduled triggers and any connector config that name `mediaintelligence/MIZOKICloudRun` are still stale.\n**Files:** GitHub org settings (install github.com/apps/claude on `MIZOKI-3-5`, grant the repo); Drive prompt-board folder `1942_8C4Dsj6hmARrBogNsy7lVZP-sKkx`; scheduled-task prompts; `docs/audits/wo/create_issues.sh` (`REPO` default already correct).\n**Fix:** install/authorize the App on the org; start a NEW cloud session afterwards (credentials are scoped at session start); grep the board and triggers for `mediaintelligence/MIZOKICloudRun` and repoint; then run `create_issues.sh --dry-run` from a credentialed shell.\n**Acceptance:** a fresh cloud session can `git ls-remote` the org repo; `create_issues.sh --dry-run` lists all WO-nn; zero stale references on the board.\n**Depends on:** none. **Blocks:** every CC/CX prompt that runs in the cloud, and the issue batch.\n**Owning prompt:** owner/operator (WO-40..43 class); CX-1 records the result in the reconciliation table.",
  "deps": []
 },
 {
  "id": "WO-47",
  "pkg": "B",
  "sev": "P0",
  "lane": "SEC",
  "title": "Tenant-check DCP GET /api/v1/decision/{id}",
  "body": "**Finding (confirmed on main 635318712; OPEN_ITEMS S3-4):** `services/service-decision-control-plane/main.py:504-508` `get_decision` returns any DecisionProof by id to any allow-listed caller — `STORE.get(\"decision_proofs\", decision_id)` with no `resolve_tenant` call, while the sibling `list_decisions` (line 526) and `decisions_summary` (549) do resolve tenant against the caller. `mcp-server` checks the stored `tenant_id` itself, but the upstream route must too; passport assembly (S3-3) reads through this route.\n**Files:** `services/service-decision-control-plane/main.py`; its tests.\n**Fix:** resolve the caller's tenant and refuse (404, never 403 that confirms existence) when `doc[\"tenant_id\"]` does not match; same rule on `/decision/{id}/chain` and the passport GET. Pairs with WO-03 (passport binding) and WO-05 (approver identity).\n**Acceptance:** negative test over HTTP: tenant B caller requesting tenant A's decision id gets 404 and no body fields; positive test unchanged; the same test against `/chain` and `/passport/{id}`.\n**Depends on:** WO-00.\n**Owning prompt:** CC-1 (`services/service-decision-control-plane/**`).",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-48",
  "pkg": "H",
  "sev": "P1",
  "lane": "ENG",
  "title": "Run the orphaned test suites in CI",
  "body": "**Finding (OPEN_ITEMS W3-CI-1, measured):** no workflow runs `tests/mcp`, `tests/spec`, `tests/gtm`, `packages/truthgate/tests`, `tests/shared/test_origin_{schema,strata,classifier}.py`, `tests/shared/test_agent_share_threshold.py`, `tests/test_origin_shadow_ddl.py` on PR or merge (`ci.yaml:140` names one file, not the directory). Their tenant-isolation, read-only-manifest, consent and flag-pin gates are enforced only when someone runs them locally. Separately, `scripts/mizoki_canon.py` has no CLI — `--check` is silently ignored (library only); the canon gate is `scripts/skill_sync.py --audit`.\n**Files:** `.github/workflows/ci.yaml` (protected path → review PR); `tests/governance/` (new pin test).\n**Fix:** one step beside the governance-gates job: `pytest tests/mcp tests/spec tests/gtm packages/truthgate/tests tests/shared tests/test_origin_shadow_ddl.py -q -p no:cacheprovider -o addopts=\"\"`; plus a governance test asserting no workflow/Makefile/doc invokes `mizoki_canon.py --check` and that `skill_sync.py --audit` is the named canon gate.\n**Acceptance:** the step is green on a PR; a seeded failure in `tests/mcp` reddens CI; the canon-invocation pin passes.\n**Depends on:** WO-00. Same review PR as WO-26/27 where practical.\n**Owning prompt:** CX-4 (`.github/workflows/**`).",
  "deps": [
   "WO-00"
  ]
 },
 {
  "id": "WO-49",
  "pkg": "A",
  "sev": "P0",
  "lane": "OWNER",
  "title": "Execute the PII history purge across ALL copies, not the repo alone",
  "body": "**Finding (OPEN_ITEMS V4-4 + memory ledger `a1ec34ccc`, `9454163f4`, 2026-09-05):** `docs/misc/mycocoons_customers.csv` (real PII, Option A decided 2026-09-02) — serving exposure closed and live-verified 2026-09-02T19:48Z, but the history purge is NOT executed; scope is five repository paths across three renames. The 5 Sep audit adds: the purged CSV is still tracked in the MIZ clone, and the export exists in at least three places, one in a local folder that looks like Google Drive but is not.\n**Files:** repo history (five paths in `docs/reports/WS0_PII_SCANNER_REPORT_2026-09-01.md` §5a); the MIZ clone; the local pseudo-Drive folder; any Drive mirror.\n**Fix:** owner-run maintenance window after the audit lanes land (history rewrite invalidates every open `audit/*` branch — sequence it); force-push under ruling; every clone re-cloned; delete the non-repo copies; record closure evidence (`git log --all -- <path>` empty; file hashes absent from the three locations) without copying any customer row into a report.\n**Acceptance:** closure evidence in `OPEN_ITEMS.md` V4-4 for all copies; scanner report re-run clean.\n**Depends on:** none (but sequence AFTER the `audit/*` merges). **Owning prompt:** owner (WO-40..43 class).",
  "deps": []
 }
]
← All docsView source on GitHub →