API compatibility repair — evidence

Lane record for docs/audits/api-compatibility/2026-10-01/. Every line below is either a quote from an official page (URL + retrieval time), a measurement taken in this lane (command + result), or a pointer to a tracked file. Bulky page captures and wheels stayed in the session scratchpad; their digests are here so the measurement can be repeated.

1. Official provider notices (retrieved 2026-10-01, ~14:45–15:00Z)

Pages were fetched with curl -sS -L through the session proxy and reduced to text; quotes are verbatim from that text.

wheel sha256 _VALID_API_VERSIONS
25.1.0 (pinned by the GAQL cell) cbc4d174a7e8d66a76d9f0e22bbbb88052446bbf31945181a2982e49ff614948 ["v18", "v17", "v16"] (default v18)
32.0.0 83a3fe8be741a249afc261a97754e3c42d6181308121df652d0b37225053e867 ["v25", "v24", "v23", "v22", "v21"]
33.0.0 113a679e708779400e7318b202036f0aa0d02b665d78c9b940b58ade26504d63 ["v25", "v24", "v23"]
- google-ads 33.0.0, google/ads/googleads/v25/errors/types/change_status_error.py
(read 2026-10-01, for API-A10): `LIMIT_NOT_SPECIFIED (6): The change_status
search request must specify a LIMIT.INVALID_LIMIT_CLAUSE (7): The LIMIT
specified by change_status request should be less than or equal to 10K.`
`CHANGE_DATE_RANGE_INFINITE (4): The change_status search request must
specify a finite range filter on last_change_date_time.`
- https://developers.google.com/google-ads/api/fields/v25/metrics and the
segments and resource pages (retrieved 2026-10-01, for API-A13): the
"Selectable with" list of metrics.cost_per_conversion includes campaign
and segments.date but neither segments.conversion_action nor
segments.conversion_action_name; those of metrics.conversions,
metrics.conversions_value, metrics.all_conversions and
metrics.all_conversions_value include both. The registry check
(tests/fixtures/v25_field_compat.json) is these pages restricted to what
the GAQL registry uses.

Merchant API

Google Data Manager API

Meta Graph / Marketing API

Other providers (retrieved 2026-10-01, 15:54–16:06Z)

Pages fetched with curl -sS -L and reduced to text, as above; every quote below was re-checked against the saved bytes. The capture set (raw bytes, text, a fetch log with UTC time, HTTP code, final URL and sha256 per fetch) stayed in the session scratchpad.

2. Source measurements (baseline 3d5278b00)

See ISSUES.json source_evidence per issue. Commands used:

grep -rn -E "graph\.facebook\.com|GRAPH_API_VERSION|META_GRAPH|GRAPH_VERSION" services src connectors contracts
grep -n "version\|SUNSET" services/service-action-runner/execution_adapters/google_ads.py
python3 scripts/deps_lock.py --list | grep gaql

3. Workflow, build and runtime evidence

Every run in §3.1–§3.4 is local, on the branch named in RESUME.md, with the network namespace removed or the proxy variables unset (rule 01, "a network audit behind a loopback proxy sees only the proxy"), and every provider answer is a fake. §3.5 records the deploy runs that the owner's merges fired (#1299,

1302 and #1308), read through the GitHub API, and §3.6 to §3.8 the PR

checks. §3.9 records #1322's merge and two corrections to the closeout's manual-deploy steps. Nothing in this file is live-verified against a provider. (Until independent review pass 3, D8, this paragraph said nothing below was deployed, which §3.5 contradicted.)

3.1 Commits

Commit Scope
93a791b action runner: dated Google Ads refusal, no developer token
16ac0b3 GAQL cell: google-ads 33.0.0, bound v25, synthetic never live
ef8cc48 gateway: provider version policy, Merchant Reports v1, no developer token
fdd282c one policy in gateway/runner/Boss; Meta v26.0; CAPI v25.0; Boss direct writes off
236ca6a Data Manager: per-tenant tracking to final requestStatus
d1a50e3 Klaviyo 2026-07-15, gemini Meta worker, Graph v25.0, website schedule
d787e7e lifecycle inventory + deterministic CI check; WO-45 guard widened; docs
b4860c8 independent review pass 1 fixes (§4.2); one sunset policy; console Klaviyo route
925d005 inventory row reworded (it tripped the gateway env-source scanner, §4.2)
f44a7d8 this execution record and the skill delta
19e8a6c CodeQL: hostname comparisons in two test filters (§3.6)
faf28dc merge of origin/main 2ae5c87 (docs and memory only; no overlap)
0cf37f0 record: review pass 1 verbatim, dispositions, final sweep, release package. #1299 merged at this head (owner, 2026-10-01 20:14:51Z, merge cb7b7ff)
606fb8a follow-up PR #1302: independent review pass 2 fixes (N3, N4, N6, findings 10 and 20; §4.4). Authored as 8e961af on the pre-merge branch, rebased onto main 3f89cd0
e3bd49e follow-up PR #1302: Copilot's review of #1299 (§4.5): synthetic runs authorize nothing; failed extractions answer 502; one Data Manager status read per claim
db3c271 follow-up PR #1302: record (pass 2 verbatim and dispositions, Copilot dispositions, merge and deploy evidence, ledger corrections API-G12/API-G13); N2 guard test
22f711d follow-up PR #1302: independent review pass 3 fixes (D1–D4, D11–D13, the GAQL field lookup, the console email-route pin; §4.7)
5ff9bdb follow-up PR #1302: record (pass 3 verbatim and dispositions; ledger corrections API-A5, API-A7, API-G13; new issues API-A10, API-A11, API-A12)
fc2a3a3 follow-up PR #1302: conversion_segmentation_v1 no longer selects a metric Google refuses with its segments; every registered query checked in CI against Google's v25 field reference (API-A13)
9fd5982 follow-up PR #1302: record of fc2a3a3 (API-A13) and the pass-3 heal gate runs
b03f33e follow-up PR #1302: independent review pass 4 fixes (V5-1, V5-3 to V5-9, V5-11 to V5-13; §4.9)
9e433b7 follow-up PR #1302: the GAQL reference check's docstring says what Google's documentation shows (§4.9, V5-8)
b34358c follow-up PR #1302: record (pass 4 verbatim and dispositions; ledger corrections API-A3, API-A7, API-A11, API-A12, API-F3)
9d76b52 follow-up PR #1302: a test pins V5-12 (the executor holds no client; §4.9)
2ee03e0 follow-up PR #1302: record (how each pass-4 fix is verified; the V5-12 pin)
c7d8904 follow-up PR #1302: independent review pass 5 fixes (N1 to N5, and pass 5's notes on V5-1 and V5-8; §4.11)
701f67c follow-up PR #1302: record (pass 5 verbatim and dispositions; ledger corrections)
9d9cd01 follow-up PR #1302: independent review pass 6 fixes (D1, D3, D4, D5, D7; §4.13)
5971bcb merge of origin/main fa1cc19 (two docs files on main, the Shopify plan of record; no overlap)
85b7ecb follow-up PR #1302: the registry check encodes the metric half of the attributed-resource rule (pass 6, D5; §4.13)
d14dba0 follow-up PR #1302: record (pass 6 verbatim and dispositions; ledger corrections)
49f8d80 follow-up PR #1302: independent review pass 7 fixes (N1, N2, N3, N6; §4.15)
d7a5af2 follow-up PR #1302: record (pass 7 verbatim and dispositions; ledger corrections)
02b4c3c follow-up PR #1302: independent review pass 8 fixes (defects 1, 2, 3 and 5, and pass 7's N5; §4.17)
b9a35c6 follow-up PR #1302: record (pass 8 verbatim and dispositions; ledger corrections)
9736385 follow-up PR #1302: independent review pass 9 fixes (defects A to F; §4.19)
4e1fe7a follow-up PR #1302: record (pass 9 verbatim and dispositions; ledger corrections)
d1e1e7b follow-up PR #1302: independent review pass 10 fixes (defects 1 and 2, NITs 1 and 2; §4.21)
592fa5d follow-up PR #1302: the GAQL deploy pin's docstring names two more routes it does not check (docstring only)
1e78fad follow-up PR #1302: record (pass 10 verbatim and dispositions; NITs 3 and 4; ledger corrections)
8c4f986 follow-up PR #1302: independent review pass 11 fixes (defect 1; NITs 2, 5 and 7; §4.23)
c9df080 follow-up PR #1302: a seed for the deploy workflow's one-config rule (self-found; §4.23)
482b60b follow-up PR #1302: record (pass 11 verbatim and dispositions; NITs 1, 4 and 6; ledger corrections). #1302 merged at this head (owner, 2026-10-02 12:47:38Z, merge d98d213), before pass 12 reported
99381e8 follow-up record PR #1308: #1302's merge, its two deploys and the checks at its merge (§3.5, §3.7). #1308 merged at this head (owner, 2026-10-02 13:29:44Z, merge 990bccf)
5ae9bbc pass-12 record PR #1322: pass 12 verbatim and dispositions (§4.24, §4.25); the record corrections it called for (NITs 2, 3, 7 and 8); #1308's merge (§3.5, §3.8)
35a58e7 pass-12 record PR #1322: Copilot's review (the manual deploys are stated as not run by this lane, not as not run) and API-G7 deployed by homepage run #140. #1322 merged at this head (2026-10-03 14:46:04Z, merge d0992c1)
the commit that adds this row correction PR: the closeout's manual-deploy steps for API-G3, G9 and F5/F6, and #1322's merge (§3.9)

Published on work/mizoki-api-compatibility-3ae54n behind draft PR #1299. The owner marked it ready and merged it at 0cf37f0 (2026-10-01 20:14:51Z, merge commit cb7b7ff); GitHub then deleted the branch. The claim PR #1300 merged at 20:14:12Z. The work that followed (review pass 2 and Copilot's review of the merged head) went onto the same branch name restarted on main, behind draft PR #1302: the one unmerged commit was rebased (8e961af → 606fb8a) and pushed with --force-with-lease against 8e961af. The assigned claude/ branch was never pushed: a push there merges to main and fires the Deploy Router without the owner's typed MERGE gate.

The owner merged #1302 at 482b60b (2026-10-02 12:47:38Z, merge commit d98d213). GitHub kept the branch (read at 12:55Z). The record that followed went onto it as a fast-forward from d98d213, behind a new draft PR.

The owner merged that PR, #1308, at 99381e8 (2026-10-02 13:29:44Z, merge commit 990bccf). This time GitHub deleted the branch at the merge (pass 12 read it deleted at 13:29:49Z). Pass 12's record went onto the same branch name, restarted on main, behind a new PR, #1322. It was first made on main f44f961, then redone on main bf1ff32 when other sessions' memory commits made it conflict.

1322 merged at 35a58e7 (2026-10-03 14:46:04Z, merge commit d0992c1,

from the mediaintelligence account). GitHub kept the branch. The corrections in §3.9 went onto the same branch name, restarted on main 185f358, behind a new PR.

3.2 Test runs (fresh venvs; the install lines of the CI job named)

Suite Environment Result
tests/governance (whole) venv mirroring ci.yaml governance step (+ docs/whitepapers/requirements.txt), TMPDIR=/tmp/gv 4338 passed, 14 skipped, 0 failed
tests/remediation (whole) deploy-service-canonical-ingestion.yml test-gate deps 395 passed at fdd282c; 1 failed / 394 passed at d787e7e (independent review finding 1; the line here said "395 passed" until the review measured it); 396 passed at b4860c8 and at 19e8a6c
tests/connectors + services/service-marketing-connectors ci.yaml pins 972 passed
services/service-data-manager-connector/tests orphaned-suites deps, MIZOKI_STORE=memory 44 passed
services/measurement-rails orphaned-suites deps 497 passed
src/cells/google_ads_gaql/tests no SDK / venv from requirements.lock.txt (google-ads 33.0.0), unshare -rn at d787e7e: 70 passed + 3 skipped / 73 passed; at b4860c8: 73 + 3 / 76; at 8e961af: 74 + 3 / 77
services/gemini-kg-pipeline (unittest discover -s tests) deploy-gemini-kg-pipeline.yml gate deps 237 OK
tests/services, tests/claims_backing orphaned-suites deps 39 passed + 1 skipped; 196 passed
# MIZ OKI 3.5/tests (website) orphaned-suites deps 949 passed
services/net-yield, services/intent-pullers-extender, services/intent-leads-extender orphaned-suites deps 208; 24; 7 passed
tests/market_signal, src/cells/cell37/tests ci.yaml pins 292; 33 passed
.github/scripts/content_gates.sh orphaned-suites deps on PATH exit 0 (155 gate tests passed)

A first governance run in an older venv showed three failures: one real regression this lane introduced (the gateway's new import provider_versions failed when test_tenant_lane_vault loads connector_credentials.py by file path) — fixed in d787e7e with a sibling-file fallback — and two environment artifacts reproduced identically on pristine origin/main (reportlab absent from that venv; test_wo19_atomic_reservations failing on a long TMPDIR, AF_UNIX path too long, rule 01). The clean run above is the one that counts.

Final sweep (8e961af, the pass-2 commit before its rebase onto main as 606fb8a)

Every gate command again, on fresh venvs built from each job's install lines (build_p2.sh in the session scratchpad: ci.yaml lint-and-test, governance-gates, orphaned-suites, suite-wiring and measurement-rails; the canonical-ingestion gate; the gemini gate; the GAQL image's lock). The earlier venvs venv-ci and venv-cig were reinstalled by the pass-2 verifier while this lane's first sweep ran (its disclosure, §4.3), so no number below comes from them. Proxy variables unset, TMPDIR=/tmp/sw, one activity on the tree. The real-SDK GAQL step ran without unshare -rn in both sweeps. Its tests stub the SDK's credential factory (TestRealSdk), so no OAuth refresh is attempted; the other tests use fake clients or unconfigured settings. HEAD 8e961af5180cd4046ac0c389b102b781546beb1f dirty=0, started 2026-10-01T20:12:32Z; finished 2026-10-01T20:28:38Z dirty=0.

Step rc Result
cig_remediation 0 396 passed, 1 warning in 12.85s
cig_connectors 0 587 passed, 3 warnings in 28.67s
cig_kg_perimeter 0 68 passed in 7.54s
ci_governance 0 4347 passed, 7 skipped, 6 warnings, 6227 subtests passed in 441.86s (0:07:21)
ci_virtuoso_models 0 43 passed in 1.59s
ci_mem_commit_guard 0 16 passed in 2.32s
ci_memory_contract 0 7 passed, 10 subtests passed in 0.02s
ci_claim_check 0 51 passed in 0.54s
ci_pin_ratchet 0 13 passed, 20 subtests passed in 6.79s
ci_mcp_schema 0 3 passed in 0.41s
ci_registry_probe 0 8 passed in 0.27s
ci_connectors 0 587 passed, 2 warnings in 29.09s
ci_mc_service 0 388 passed, 1 warning in 13.74s
ci_exec_adapters 0 178 passed in 1.11s
ci_market_signal 0 294 passed, 2 warnings in 3.95s
ci_cell37 0 33 passed, 3 warnings in 0.52s
ci_secret_ignore 0 31 passed in 0.24s
ci_skills 0 252 passed, 12 subtests passed in 7.94s
ci_operator_preflight 0 No drift. Remaining ACTION items are credentialed operator steps: see docs/measurement-rails/RUNBOOK.md and docs/net-yield/RUNBOOK.md.
ci_legacy_model_ids 0 Model governance check passed.
ci_journey_smoke_dry 0 Revision ci-dry-run: PASS — every step passed.
rails_suite 0 497 passed, 2 warnings, 7 subtests passed in 1.90s
content_gates 0 155 passed in 10.59s
orphaned_suites 0 980 passed, 1 warning in 27.54s
suite_wiring_script 0 WHOLE miz-oki-command-center-ui/app/api/client-errors (1 files) <- frontend-guard.yml:🎭 Command Center e2e + a11y (Playwright), frontend-guard.y
wire___MIZ_OKI_3_5_tests_ 0 949 passed, 1 warning, 704 subtests passed in 144.33s (0:02:24)
wire_tests_cre_outreach_ 0 137 passed, 3 warnings in 2.23s
wire_tests_demo_ 0 130 passed, 2 skipped in 0.73s
wire_tests_entity_spine_ 0 62 passed in 0.74s
wire_tests_experiments_ 0 29 passed in 29.16s
wire_contracts_canonical_event 0 22 passed, 1 warning in 0.15s
wire_eval_graphrag_tests_ 0 28 passed, 1 warning in 0.35s
wire_eval_intent_tests_ 0 71 passed, 1 warning in 64.44s (0:01:04)
wire_libs_mizoki_lii_tests_ 0 221 passed, 1 warning in 3.48s
wire_miz_oki_adk_agents_boss_c 0 17 passed, 1 warning in 0.63s
wire_miz_oki_adk_agents_market 0 14 passed, 2 warnings in 0.45s
wire_services_llm_json_validat 0 35 passed, 1 warning in 0.12s
wire_services_marketing_contro 0 7 passed, 1 warning in 0.67s
wire_services_net_yield_ 0 208 passed, 2 warnings in 2.94s
wire_services_service_data_man 0 44 passed, 4 warnings in 0.67s
wire_src_cells_cell27_tests_ 0 8 passed, 1 skipped, 2 warnings in 3.06s
wire_services_relu_evaluation_ 0 4 passed, 1 warning in 0.04s
wire_services_virtuoso_models_ 0 87 passed, 1 skipped, 1 warning in 1.28s
wire_src_shared_virtuoso_model 0 87 passed, 1 skipped, 1 warning in 1.18s
wire_src_shared_creative_aesth 0 83 passed, 1 warning in 0.52s
wire_src_cells_cell38_tests_ 0 256 passed, 4 warnings in 1.08s
wire_src_cells_google_ads_gaql 0 74 passed, 3 skipped, 2 warnings in 1.66s
wire_src_cells_identity_attrib 0 25 passed, 1 warning in 0.81s
wire_services_intent_ga4_exten 0 14 passed, 2 warnings, 2 subtests passed in 1.00s
wire_services_intent_leads_ext 0 7 passed, 2 warnings in 0.37s
wire_services_intent_pullers_e 0 24 passed, 2 warnings, 5 subtests passed in 0.47s
wire_services_intent_shopify_e 0 50 passed, 2 warnings in 0.73s
wire_src_cells_cell21_tests_ 0 3 passed, 2 warnings in 0.59s
wire_tests_claims_backing_ 0 196 passed in 1.87s
wire_tests_services_ 0 41 passed, 1 skipped, 2 warnings, 5 subtests passed in 1.27s
wire_docs_audits_tests_ 1 1 failed, 7 passed, 1 warning in 1.07s
gaql_lock_sdk33 0 77 passed, 2 warnings in 6.04s
gemini_unittest 0 OK
console_email_vitest 0 Tests 2 passed (2)
content_qa_selftest 0 (no summary line)
content_qa 0 CONTENT QA OK — 69 scoped files clean (banned strings, preview framing, number labels, §-sequence, claims ledger backed, no homepage-dead-end links
canon_docs_selftest 0 Self-test OK — gate fires on seeded violations (1 finding(s)) and stays quiet on clean text.
canon_docs 0 CANON DOCS GATE OK — no new findings.
lifecycle_check 0 (no summary line)
memory_strict 0 (no summary line)
gate_leak 0 (no summary line)
ontology_skills_sync 0 Ontology-KG Virtuoso parity: OK (8 profiles; governance preserved; legacy skills intact)

Non-zero exits, each pre-existing and reproduced on base 3d5278b:

Follow-up head (e3bd49e, PR #1302, on main 3f89cd0)

The rebase changed no file of the pass-2 commit, so the full sweep above stands for it. These runs cover what changed after it, plus the gates that read the reworded inventory row (same fresh venvs):

Gate Result
src/cells/google_ads_gaql/tests: suite-wiring deps / image lock under unshare -rn 78 passed + 3 skipped / 81 passed
services/service-data-manager-connector/tests 46 passed
tests/connectors (canonical-ingestion gate deps) 615 passed (#1298 added tests on main)
services/service-marketing-connectors (ci.yaml deps, MIZOKI_STORE=memory) 399 passed
governance: lifecycle inventory, TTV stamps, Google Ads sunset guard 120 passed
content_gates.sh; lifecycle check; gate-leak; memory --strict exit 0 each
Deploy Router over origin/main..e3bd49e deploy-google-ads-gaql.yml (5 files), deploy-ui.yml (route comment), frontend-guard.yml

Pass-3 heal head (22f711d, fc2a3a3 and their record commits)

Same fresh venvs, proxy variables unset, TMPDIR=/tmp/f4 or /tmp/gv3; anything that can build a provider client under unshare -rn.

Gate Tree Result
src/cells/google_ads_gaql/tests, suite-wiring deps 22f711d / fc2a3a3 85 passed + 4 skipped / 87 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) 22f711d / fc2a3a3 89 passed / 91 passed
services/service-data-manager-connector/tests 22f711d 49 passed
tests/governance -c tests/governance/pytest.ini 5ff9bdb, clean tree 4350 passed, 7 skipped, 0 failed
content_gates.sh (governance-gates deps on PATH) 5ff9bdb 155 passed, exit 0
api_lifecycle_check.py; gate_leak_scan.py --check; check_canon_docs.py; memory check --strict 5ff9bdb exit 0 each
docs/audits/tests (suite-wiring deps) 5ff9bdb 7 passed, 1 failed: test_wo31_register.py, the shallow-clone case above (git cat-file reports commit 26bec9c6 absent here)
Deploy Router --base origin/main --head HEAD 5ff9bdb deploy-google-ads-gaql.yml, deploy-ui.yml, frontend-guard.yml

fc2a3a3 changes only the GAQL registry, its test and a test fixture, so the 5ff9bdb rows that read neither stand for it. The PR body records the gate run on the pushed head.

Pass-4 heal head (b03f33e and the record commit after it)

Same venvs, in a detached worktree at b03f33e (the main checkout was being edited for this record), proxy variables unset, TMPDIR=/tmp/t4; anything that can build a provider client under unshare -rn.

Gate Tree Result
src/cells/google_ads_gaql/tests, suite-wiring deps b03f33e 94 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) b03f33e 98 passed
services/service-data-manager-connector/tests b03f33e 51 passed
tests/remediation/test_gaql_governance_wiring.py b03f33e 5 passed
tests/governance/test_api_lifecycle_inventory.py b03f33e 23 passed

The record commit changes only docs/audits/api-compatibility/2026-10-01/. The gates that read it are the governance spine (the inventory's ledger-id guard), content_gates.sh, the lifecycle, gate-leak, canon-docs and memory checks, docs/audits/tests and the Deploy Router. They run on that commit, and the PR body records them, as it did for 9fd5982.

Pass-5 heal head (c7d8904 and the record commit after it)

Same venvs, proxy variables unset, TMPDIR=/tmp/n6; anything that can build a provider client under unshare -rn. Measured on the working tree that was then committed unchanged as c7d8904 (git status clean after the commit).

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 96 passed + 4 skipped
services/service-data-manager-connector/tests 53 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 23 passed

The image-lock GAQL suite and the final-tree gates run on the record commit; the PR body records them.

Pass-6 heal head (9d9cd01, 85b7ecb and the record commit after them)

Same venvs, proxy variables unset; anything that can build a provider client under unshare -rn. Measured on the working tree committed unchanged as 9d9cd01. 85b7ecb changes one test file: its registry tests pass (3), and the whole GAQL suite runs again in the final-tree gates.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 96 passed + 4 skipped
services/service-data-manager-connector/tests 54 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 23 passed

The image-lock GAQL suite and the final-tree gates run on the record commit; the PR body records them.

Pass-7 heal head (49f8d80 and the record commit after it)

Same venvs, proxy variables unset; anything that can build a provider client under unshare -rn. Measured on the working tree committed unchanged as 49f8d80.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 96 passed + 4 skipped
services/service-data-manager-connector/tests 55 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 23 passed

The image-lock GAQL suite and the final-tree gates run on the record commit; the PR body records them.

Pass-8 heal head (02b4c3c and the record commit after it)

Same venvs, proxy variables unset; anything that can build a provider client under unshare -rn. Measured on the working tree committed unchanged as 02b4c3c.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 97 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) 101 passed
services/service-data-manager-connector/tests 56 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 23 passed

The final-tree gates run on the record commit; the PR body records them.

Pass-9 heal head (9736385 and the record commit after it)

Same venvs, proxy variables unset; anything that can build a provider client under unshare -rn. Measured on the working tree committed unchanged as 9736385.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 97 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) 101 passed
services/service-data-manager-connector/tests 58 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 24 passed

The deploy pin's scan of the four roots takes about 13 s of the GAQL suite. The final-tree gates run on the record commit; the PR body records them.

Pass-10 heal head (d1e1e7b; 592fa5d changes a docstring only)

Same venvs, proxy variables unset; anything that can build a provider client ran under unshare -rn. Measured in a clean worktree at d1e1e7b. The fast gates (content gates 155 passed; lifecycle, gate-leak, canon docs, memory --strict and the router clean) and the same suites also passed on 592fa5d before it was pushed.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 97 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) 101 passed
services/service-data-manager-connector/tests 58 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 24 passed

The pin's test class took about 23 s here, measured while other runs shared the machine. The final-tree gates run on the record commit; the PR body records them.

Pass-11 heal head (8c4f986; c9df080 adds one seed)

These runs used the same venvs, with the proxy variables unset. Anything that can build a provider client ran under unshare -rn. Measured in a clean worktree at c9df080.

Before each commit was pushed, the fast gates passed on it: content gates (155 passed), and the lifecycle check, gate-leak, canon docs, memory --strict and the router, all clean. PR CI on 8c4f986 passed: 27 checks green, 1 skipped.

Gate Result
src/cells/google_ads_gaql/tests, suite-wiring deps 98 passed + 4 skipped
src/cells/google_ads_gaql/tests, image lock (google-ads 33.0.0) 102 passed
services/service-data-manager-connector/tests 58 passed
tests/remediation/test_gaql_governance_wiring.py 5 passed
tests/governance/test_api_lifecycle_inventory.py 24 passed

The pin's test class took about 23 s here (5 tests, test_the_tree_checks_read_both_ways among them). The final-tree gates run on the record commit; the PR body records them.

Earlier sweep (b4860c8, re-runs at 19e8a6c)

Every pytest command in .github/workflows/*.yml whose scope the branch touches, plus the ci.yaml jobs, each in a venv built from that job's install lines (proxy variables unset, TMPDIR=/tmp/sw). Commands and logs: session scratchpad sweep/ and rerun/.

Gate Result
canonical-ingestion gate: tests/remediation, tests/connectors, tests/test_kg_write_perimeter.py 396; 587; 68 passed
marketing-connectors gate: services/service-marketing-connectors 388 passed
ci.yaml governance: tests/governance -c tests/governance/pytest.ini 4340 passed, 14 skipped, 0 failed
ci.yaml other steps: virtuoso models, mem-commit guard, memory contract, claim check, pin ratchet, MCP schema, registry probe, market signal, cell37, secret ignore, skills (+ skills_sync --check), operator preflight, legacy model ids, journey smoke dry run 43; 16; 7; 51; 13; 3; 2 (+6 skipped); 294; 33; 31; 248 (+4 skipped); no drift; pass; PASS
measurement-rails job 497 passed
governance-gates job (content_gates.sh) 155 passed, exit 0
orphaned-suites job 980 passed
suite-wiring job: check_test_suite_wiring.py and all 31 per-directory lines all green except docs/audits/tests (below)
GAQL cell with google-ads 33.0.0 76 passed
gemini-kg-pipeline (unittest discover -s tests) OK
content-truth gate, canon docs gate, lifecycle check, memory check --strict, gate-leak scan, ontology skills sync all exit 0

docs/audits/tests/test_wo31_register.py fails here and fails identically on the base 3d5278b: it runs git show 26bec9c6…:docs/OPEN_ITEMS.md, a commit this shallow clone does not have (git rev-parse --is-shallow-repository → true). CI's suite-wiring job, which fetches full history, passed on #1299.

The first sweep run of tests/connectors and the gateway suite (2 failures each) overlapped an inventory edit made while it ran; it was discarded and re-run on the final tree (rule 01, "one tree, one activity").

3.3 Mutation probes (the new tests fail on a reverted fix)

3.4 Builds

3.5 Deploy, serving revision, runtime

This session made no merge, deploy, provider call, registration or credential change (no GCP credentials; merging is the owner's gate). The owner's merge of #1299 fired the Deploy Router's seven workflows on cb7b7ff. Each run and job below was read through the GitHub API on 2026-10-01 (~20:40Z); the job conclusions are success.

Service Run (job) What the run's own verify step reported
google-ads-gaql 36920171359 (110563954917) Ready=True latestReady=google-ads-gaql-cell-00015-4qn latestCreated=google-ads-gaql-cell-00015-4qn unauth=403
boss-agent-core 36920171187 (110563954595) revision boss-agent-adk-00423-lqd, runtime 6.49.4; SRPVDAL and agent-registry (118 entries) checks passed
service-action-runner 36920171312 (110563954483) rollout verified; serving /health: Google Ads adapters api_version v25, lifecycle supported, sunset 2027-08-01, sunset_scheduled {v22: 2026-10-07}; Meta ads v26.0 (supported_no_published_sunset); CAPI v25.0; EXECUTION_ADAPTERS_ENABLED false, every adapter flag false, allowlist 0: "adapters installed, execution fail-closed"
service-marketing-connectors 36920171263 (110564512882) live health, readiness and mounted routes verified; ready revision service-marketing-connectors-00079-ptp (the run's README record, e7348d5). The workflow checks out main, not the commit that triggered it: this job built e480aaa (git log -1 in its log at 20:16:47Z), which contains cb7b7ff (independent review pass 3, D10). Redeployed by run 36920255631 (#1298) as 00080-m5n (README record 3f89cd0)
gemini-kg-pipeline 36920171300 (110564520180) private service verified; image gemini-kg-pipeline:c4087d5a-9a02-43a5-9726-74455fcff4b4
gemini-meta-worker (job) 36920171356 (110563954663) job verified; "Wire Meta credentials" skipped (manual dispatch only)
console (deploy-ui) 36920171249 (110563954837) deploy and verify steps succeeded; the public URL answered 307

What this does and does not establish: - Deployed: the 32 issues whose code ships in these images are DEPLOYED in ISSUES.json. API-A5 was recorded DEPLOYED until pass 3 (D6): its fix is the reference manifest, which no deploy reads. API-A6, API-A7 and API-B7 are deployed in part (§4.4, #1302, net-yield). Manual or dispatch-only deploys did not run: the Data Manager connector, the Klaviyo puller, the leads extender, cell37, net-yield and the website. Corrected 2026-10-02 (Copilot review of #1322): - For the three manual deploys (the Data Manager connector, the Klaviyo puller and the leads extender), "did not run" was not measured. This lane did not run them, but a manual deploy leaves no trace on GitHub, and this session cannot read Cloud Run. - The dispatch-only ones are measured on GitHub. No deploy-net-yield.yml or deploy-cell37.yml run has started since #1299's merge; their latest runs are #15 (2026-08-27) and #24 (2026-09-25). - The website was deployed later, by another lane's homepage run #140 (below). - Not runtime-verified: no row is VERIFIED. The action runner's health block is the serving revision's own selection, not provider traffic. The provider-side checks (API-E4, API-D6, API-C5, API-F5) need an operator. - Not deployed by #1299: the follow-up commits (606fb8a, e3bd49e, 22f711d, fc2a3a3, b03f33e; until pass 4, V5-10, this list stopped at 22f711d; 9e433b7 changes a test docstring only), c7d8904 (9d76b52 is a test only), 9d9cd01, 49f8d80, 02b4c3c and 9736385. The one code change in each of the last four is the Data Manager connector's, a manual deploy; the rest of them, 85b7ecb, d1e1e7b and 592fa5d (pass 10), and 8c4f986 and c9df080 (pass 11), are tests. They merged with #1302 (below). Until then, the GAQL code deployed with #1299 answered /srpvdal/run with labelled synthetic totals while it was not live (the console Overview page showed them), and its live reads returned 200 with empty rows on a provider failure. - Not measured: whether the serving GAQL revision holds credentials. The deploy config (cloudbuild.yaml) sets none, but it passes no --set-secrets or --clear-secrets, so a secret mounted on an earlier revision would survive (rule 04), and the older reference manifest mounted four. API-E4 reads the serving revision's secret references. Until pass 3 (D5) this file said the cell has no credentials. The synthetic-to-ACT path stays unreachable either way: the deploy sets GAQL_ENABLE_LIVE_MUTATIONS=false and the operation builder raises.

Website source mirror failed on the merge commit (run 36920171366). It had already failed on its 19:30Z scheduled run at 2ae5c87, before the merge (run 36914807823). It is red on the base and not this change's.

#1302's merge. The owner merged #1302 at head 482b60b on 2026-10-02 at 12:47:38Z (merge commit d98d213, first parent f17e068), before review pass 12 reported. A merge through the pull request is a push to main, which fires each deploy-*.yml whose on.push.paths match the push. Two service deploys ran, the two the PR named (deploy_router.py --base f17e068 --head d98d213 lists the same two, plus the frontend-guard check). The Backup to GCS workflow (deploy-gcs.yml) ran too (run 37008851020, success): it has no paths: filter, so it runs on every push to main, and it uploads a snapshot of the repository to Cloud Storage; it deploys no service. This paragraph first said two deploy workflows ran (pass 12, NIT 8). Each run and job below was read through the GitHub API on 2026-10-02 (~13:12Z; the Backup run ~15:40Z).

Service Run (job) What the run's own verify step reported
google-ads-gaql 37008851021 (110843460918), success Ready=True latestReady=google-ads-gaql-cell-00016-cl4 latestCreated=google-ads-gaql-cell-00016-cl4 unauth=403
console (deploy-ui) 37008851067 (110845858893), success deploy and verify steps succeeded; the public URL answered 307

#1308's merge. The owner merged #1308, the record of #1302's merge, at head 99381e8 on 2026-10-02 at 13:29:44Z (merge commit 990bccf). Its diff is four files under docs/audits/. deploy_router.py --base d98d213 --head 99381e8 matches no deploy workflow, and no service deploy ran. The Backup to GCS workflow ran on the push (run 37013362669, success).

Homepage run #140, another lane's release. The owner dispatched deploy-homepage.yml at 7b2be4c for the /shopify Option B release (run 37033812102, job 110926990905, 2026-10-02 16:25–16:29Z). It ships the whole site from that commit, and 7b2be4c carries #1299's two site files unchanged: google_ads_gaql.py (blob 52b6eeb) and connections.py (blob 593fac5). Its log, read through the API: - it staged mizoki-website-00256-jam with no traffic; - it verified that revision and its focused routes; - it routed 100% to it. The previous revision was mizoki-website-00253-fah, run #139 of 2026-09-25, which predates #1299.

So API-G7 is DEPLOYED. This lane did not dispatch the run and has not probed the site's routes.

3.6 Pull request CI (#1299)

3.7 Pull request CI (#1302)

Read through the GitHub API at the merge and after it (2026-10-02). - At the merge (12:47:38Z), head 482b60b carried 28 check runs: 23 success, 1 skipped (Live Cell Endpoint Tests), and 4 still running: - Lint, Test, and Validate, one of the 13 required contexts (.github/required-status-checks.json); - the console typecheck (tsc --noEmit); - the console e2e + a11y job; - one CodeQL Analyze (python) job (run 37008407046). - Read at 13:12Z: - Lint, Test, and Validate ended success (its CI run 37008411903 completed at 12:58:58Z); - the console typecheck and e2e + a11y ended success (Frontend Guard run 37008411877, 12:48:32Z); - the CodeQL Analyze (python) job of the Code Quality run 37008407046 ended success at 13:11:41Z (job 110842038518; the run completed at 13:11:42Z). This line first said it was still running at that read (pass 12, NIT 7); re-read through the API. - The Copilot reviewer and Cursor Bugbot started after the merge (12:47:40Z and 12:47:41Z).

3.8 Pull request CI (#1308)

Read through the GitHub API after the merge (2026-10-02, ~15:40Z). - At the merge (13:29:44Z), 24 check runs on head 99381e8 had started: 22 success and 2 still running: - Lint, Test, and Validate, one of the 13 required contexts (CI run 37012761822); - one CodeQL Analyze (python) job (run 37012758776). - Both ended success: the first at 13:39:57Z, the second at 13:51:58Z. - Cursor Bugbot and the Copilot reviewer started after the merge (13:29:49Z and 13:29:54Z).

3.9 #1322's merge, and two corrections to the closeout's manual deploys

Read through the GitHub API on 2026-10-03, 14:47–15:17Z.

The merge. - #1322 merged at 2026-10-03 14:46:04Z from the mediaintelligence account: head 35a58e7, merge commit d0992c1. Its first parent is b303717, #1328's merge, so main had moved since the PR's base 51055b8. - The merge brought in the PR's patch unchanged: the same 13 files and the same hunks (git diff 51055b8 35a58e7 against git diff b303717 d0992c1, index lines aside). No other change touched those files between 51055b8 and b303717. - It deployed nothing. The Deploy Router over the merge (--base b303717 --head d0992c1) matches no deploy workflow, and no deploy workflow ran on d0992c1. These five runs did, all success:

Run Workflow Ended
37130796151 Claude Memory Governance 14:46:26Z
37130796139 Security - Verify No Secrets 14:46:31Z
37130796089 Backup to GCS 14:46:59Z
37130795730 CodeQL code scanning ("Push on main") 15:10:00Z
37130795489 Code Quality ("Code Quality: Push on main"); its Analyze (python) job ran 14:46:10Z–15:15:43Z 15:15:44Z

Correction 1: the extenders' manual builds need COMMIT_SHA (API-G3, API-G9). - The closeout gave API-G3 as gcloud builds submit --config services/intent-pullers-extender/cloudbuild.yaml. - That config tags its image gcr.io/$PROJECT_ID/intent-pullers-extender:$COMMIT_SHA (lines 6, 8, 15 and 26). The leads extender's config does the same (lines 7, 9, 16 and 26). - A manual build does not set $COMMIT_SHA. The repository records the result: - docs/lii/RUNBOOK.md:319–320: "A manual submit must pass it too, or the tag is an invalid :"; - the same runbook's troubleshooting row for "Build tag error / invalid image :" (line 988); - ops/remediation/cloudbuild.yaml:2–3.

gcloud 530.0.0's help lists COMMIT_SHA among the built-ins that --substitutions may set. - So the command as written would have stopped at the build's first step, before any deploy. This comes from the files, not from a run: the lane has no GCP access. - gcloud builds submit uploads the directory it is given, not a commit (rule 02). So the corrected commands build from a fresh export of origin/main and pass its SHA.

Correction 2: ops/remediation/deploy_all.sh is not a connector deploy (API-F5, API-F6). The closeout said "The operator deploys the connector (ops/remediation/deploy_all.sh)". That follows the service registry's deploy: field for service-data-manager-connector. The script does much more: - It deploys all ten governance services. The list is fixed (line 16), and there is no single-service option. - It builds from the operator's working tree at git rev-parse HEAD (lines 68 and 94–96). - Its deploy sets each service's env with --set-env-vars (line 110), which replaces the whole map, using four keys. A second pass puts back SELF_URL only (lines 118–123). Keys that CI deploys set on five of the ten would be gone: - service-action-runner: INVENTORY_SPEND_GATE and MIZOKI_TENANT_MAP (deploy-service-action-runner.yml:152); - service-canonical-ingestion: CANONICAL_EVENTS_BQ_TABLE, MIZOKI_TENANT_MAP and its second allowed caller (deploy-service-canonical-ingestion.yml:196); - service-policy-engine, service-decision-control-plane and service-audit-replay: MIZOKI_TENANT_MAP and per-service keys such as TENANT_LANE_VAULT, DECISION_METER and PASSPORT_SIGNING_KMS_KEY (deploy-governance-services.yml:223–278, applied at line 303). - It changes IAM and creates resources: - project roles and secret access for the runtime service account (lines 76 and 83); - the signing secret and the event topic, if they are missing (lines 82 and 88); - an invoker grant on each of the ten (line 134); - last, security/harden_auth.sh (line 139). It calls that script without PUBLIC_SERVICES, so only api-gateway is exempt (harden_auth.sh:39–52). Every other Cloud Run service in the region loses its allUsers and allAuthenticatedUsers invoker bindings (lines 57–75). That includes the intended public surfaces the script's own header lists (lines 18–24), and the leads extender, which is public by design. - Run today to ship one connector, the script would: - remove the tenant maps. Unset, MIZOKI_TENANT_MAP reads as unconfigured (contracts/mizoki_contracts/auth.py:43). - switch the action runner's inventory spend gate off. It defaults to off when unset (services/service-action-runner/execution_adapters/inventory_gate.py:47). - close public services.

The task says to preserve tenant isolation and allowlists. - The corrected step deploys the connector alone, as a new image only: - gcloud run deploy with --image and nothing else keeps the serving revision's env, service account and secrets, and leaves IAM alone. - It first runs deploy_all.sh's own gates (lines 43–66: the claims lint, the source-of-truth conformance check and tests/remediation) in the same export. - Before that, it reads the serving revision, so a missing service stops it, and that revision is the rollback target. The registry records service-data-manager-connector-00006-2c2, live-verified 2026-07-27.

How the corrected commands were checked. None of them reached GCP. Each ran in this sandbox from a clone, with a stub gcloud on PATH that logs its arguments. - Both extender blocks called gcloud builds submit once each. The source was a fresh export of origin/main (185f358), the config was the export's cloudbuild.yaml, and the substitution was COMMIT_SHA=185f35856851cb1a70c35be14ae1f7ac6c8a770f. The export holds .gcloudignore, and its config is identical to main's. - The connector block ran its real gates. It used a fresh venv built from deploy-service-canonical-ingestion.yml's pinned install lines, with mizoki_contracts not installed, so the export's copy was used through PYTHONPATH. - The claims lint was clean. - The conformance check was clean. - tests/remediation: 396 passed.

It then called builds submit with _SERVICE=service-data-manager-connector and the full SHA, and run deploy with the image only. - It stops early when it should. When the stub reported the service missing, the block stopped after its first call. When the interpreter had no pytest, it stopped at the test gate, before any build.

Not done. - None of the three deploys was run by this lane, and whether an operator has run any of them is still not measured. - The script and the registry row are unchanged. Making deploy_all.sh safe to run again (a service filter, and the public allowlist for its last step) is an owner decision.

4. Independent review

Blind passes by a separate verifier session. It received the commit range, the rules and the earlier passes' findings, never the builder's reasoning; it worked in its own detached worktrees and removed them. Each pass's fixes were written by the integrator, so they are not independent until the next pass checks them (rule 08): pass 2 checked b4860c8; pass 3 checks the follow-up PR, #1302 (606fb8a, e3bd49e and the record corrections, §4.6). Copilot also reviewed the merged head of #1299 (§4.5); that review is not blind, so each of its findings was verified before a fix.

4.1 Pass 1 — 3d5278b..d787e7e (report verbatim)

Review: 3d5278b..d787e7e (7 commits, branch claude/mizoki-api-compatibility-3ae54n), adversarial pass

I worked only in my own detached worktrees, plus a scratch repo that borrows objects from the main checkout through alternates. I have removed all of them. The main checkout is untouched: git status shows only the pre-existing untracked docs/audits/api-compatibility/. I did not touch the scratchpad/base worktree, which is someone else's. Test runs had the proxy variables unset and used a short TMPDIR.

Verdict: one blocker (a red test this change introduces), one major process risk, and several smaller defects. I found no new path that can change a customer's ads, audiences, conversions or spend, and no weakened gate or kill switch.


BLOCKER

1. The change leaves a red test in tests/remediation, and the evidence still says green. - Where: tests/remediation/test_wo24_google_ads_api_version.py:167 (test_wo24_sunset_list_agrees_with_the_repo_wide_sunset_guard) now fails. - Cause: commit d787e7e added v23, v24 and v25 rows to the WO-45 guard's SUNSET table (tests/governance/test_google_ads_api_version_sunset.py:45-47). The WO-24 test requires every guard version to be in the runner's SUNSET_API_VERSIONS | SUNSET_SCHEDULE. SUNSET_SCHEDULE holds only the day-precision rows (v22), so the test now fails. - Evidence: in a venv with the canonical-ingestion gate's pins (pydantic 2.13.4, fastapi 0.141.1, httpx 0.28.1), pytest tests/remediation -q gives 1 failed, 394 passed with AssertionError: {'v23', 'v24', 'v25'}. - The same file passes 40/40 at base 3d5278b and 40/40 at fdd282c. - Who runs it: deploy-service-canonical-ingestion.yml gates every deploy on pytest tests/remediation -q. Its triggers are contracts/**, the service itself, ops/remediation/* and src/shared/virtuoso_models/**. - So after merge, the next canonical-ingestion deploy fails at its gate. - PR CI stays green: ci.yaml runs only test_execution_adapters.py from that directory. This is the latent-red shape rules 07 and 08 describe. - Stale evidence: fdd282c's commit message says "tests/remediation 395 passed". That was measured before d787e7e, and EVIDENCE.md repeats it.

MAJOR

2. As named, this branch auto-merges and triggers six production deploys; no coordination claim is on record. - Auto-merge: the branch name matches claude/** in auto-merge-ai-branches.yml. None of the 65 paths matches protected_path_gate.sh (^\.github/|^deployment/terraform/|^deployment/cloudbuild|^CODEOWNERS$), so the protected-path gate would not stop it. - Deploys: deploy_router.py --base 3d5278b --head HEAD lists six workflows: - deploy-boss-agent-core - deploy-gemini-kg-pipeline - deploy-gemini-meta-worker - deploy-google-ads-gaql - deploy-service-action-runner - deploy-service-marketing-connectors - Drain risk: gemini-kg-pipeline falls under AGENTS 7.7 drain safety. - Rules: a large cross-cutting change belongs on a branch outside the auto-merge prefixes, behind a PR whose title gives the deploy count (rule 05 A.4, rule 02, rule 04), merged only after the owner's typed MERGE gate. - No claim: I found no claim for this lane in the branch's CLAUDE.md, the branch inbox, main's CLAUDE.md, or main's .claude/memory/inbox/2026-10.md (rule 05 A.2, rule 02). - Current state: not pushed yet (git ls-remote origin 'refs/heads/claude/mizoki-api-compatibility*' returns nothing). It merges cleanly with current main 67d6e41 (merge-tree exit 0).

MINOR

3. A Meta served-version warning from one tenant's call shows up in other tenants' results. - Where: services/service-action-runner/execution_adapters/meta_ads.py:243-248 stores the warning on self; :321-323 reads it back. - Adapters are built once per process (registry.build_adapters), and the warning is never cleared. - Effect: after any response carries X-Ad-Api-Version-Warning, every later update result, for any tenant, reports that warning. - Probe: one adapter, tenant acme gets a warning header, then tenant globex gets none. globex's provider_response still contains served_version_warning: 'call upgraded'. - So audited results are wrong, and state crosses tenants (the content itself is not sensitive).

4. Merchant v1 rows split one product into two knowledge-graph nodes. - Where: direct_connectors.py:338- sets no product_id on productPerformanceView rows. projector_kg.py:264 keys a Product by product_id or offer_id. - Probe output (catalog and performance rows for the same offer o1): - catalog row → product_gmc_online-en-US-o1 with {price: 1.99, currency: USD} - performance row → product_gmc_o1 with {currency: EUR} - The performance row's conversion-value currency lands in the Product node's currency field, which elsewhere means price currency. This misses requirement C ("canonical records keeping … product … currency").

5. Two sunset gates apply different policies to the same pins, on the wall clock. - The widened WO-45 guard (new FILE_PINS plus the v23–v25 rows) fails CI for any pin site. - The new inventory says credential_gated and dormant rows only warn. - Probe: - Guard _scan(2027-01-17) finds 0 problems; _scan(2027-01-18) finds 13, all v23 literals in Boss (cross_channel_cooldown_manager, mcp_connector_registry_v2, platform_rollback_integration, …). - API_LIFECYCLE_AS_OF=2027-01-18 scripts/api_lifecycle_check.py gives FAILURES (0) for the same rows, as a warning only. - CI never sets API_LIFECYCLE_AS_OF, so every PR in the repo goes red on 2027-01-18. That conflicts with the "deterministic CI checks" requirement and is the calendar time-bomb rule 01 describes.

6. In CI, the lifecycle unknowns are not visible. - test_api_lifecycle_inventory.py:106 prints the unknowns, and pytest swallows that output on a passing test. - pytest tests/governance/test_api_lifecycle_inventory.py -c tests/governance/pytest.ini (the CI invocation) gives "17 passed" with zero lines matching UNKNOWN or "no published retirement". Only the single dormant warning shows. The CLI lists 20 unknowns.

7. The coverage check skips the UI tree, which has a live Klaviyo call on a revision retiring in 14 days. - scripts/api_lifecycle_check.py:59 SOURCE_ROOTS leaves out miz-oki-command-center-ui. - app/api/action-hub/email/send/route.ts:72-76 POSTs to a.klaviyo.com/api/events/ with revision: '2024-10-15' (retires 2026-10-15 per the inventory's own table) when EMAIL_SERVICE=klaviyo. - The inventory has no row for it, and coverage_gaps reports nothing.

8. The Cloud-project remedy (API-D4) probably never fires on the real Google Ads pull. - provider_versions.google_ads_error_codes (:171-187) returns [] for a list body. - GoogleAdsAdapter.pull (direct_connectors.py:641) calls searchStream and already parses its success body as a JSON array. - google_ads_access_remedy([err]) returns None; the same error as an object returns the remedy. - The test (test_google_ads_pull_names_the_cloud_project_remedy) uses only an object-shaped error body. - That streaming errors arrive as [{"error":…}] is my inference from how REST streaming works; I did not measure it against Google.

9. The Page Insights path was recorded as compatible, but one default metric is not documented. - The default metrics at connectors/meta_signals/client.py:133-136 include page_engaged_users. - That metric is absent from the Page Insights reference for both v25.0 and v26.0. Both pages say "The API returns an invalid metric error when calling any of these metrics" about the deprecated ones. - The justification at :21-26 ("No v22.0-v26.0 changelog names … the four default Page metrics") is based on searching changelogs only — rule 01's narrow-search trap. The defect predates this change, but the change re-pins the path and records it as checked. One live call would settle it.

10. The GAQL "synthetic" label is not shown anywhere a user looks. - orchestrator.py:90 claims "so no surface can present it as one". - The cell's only live caller, the Command Center Google channel pages (app/channels/google/lib.ts gaqlGet and its components), never reads data_provenance. Grepping the UI for it finds nothing. - Those pages still render synthetic impressions, cost and ROAS as campaign metrics.

NIT

  • 11. Dangling references: 13 committed files cite the untracked docs/audits/api-compatibility/2026-10-01/{ISSUES.json,EVIDENCE.md}, including the inventory's ledger and sdk.evidence and the claims-ledger C38 note. No test checks that ledger exists.
  • 12. Inventory statuses:
  • enhanced_conversions_integration.py is imported by the deployed Boss and gated by ENABLE_ENHANCED_CONVERSIONS. That is "dark" by the inventory's own vocabulary, but it is filed under meta_marketing.dormant, so its retired v21.0 pin only warns.
  • google_ads.boss_integration_health is marked credential_gated, but credentials can be registered at runtime through an API.
  • 13. GAQL checks the version only once: client.py:103 runs it when the connector is built, so the /health as_of date is frozen. A long-lived instance would keep its live client past a sunset day. The runner, gateway and Boss check on every call.
  • 14. canonical_adapter.py:178 still falls back to "v23".
  • 15. Developer tokens still required in Boss:
  • platform_rollback_integration.py:240 sends the developer-token header.
  • :1160 reports the integration enabled only if a developer token exists.
  • mcp_connector_registry_v2 validate_credentials requires one (lines 1059 and 1493).
  • 16. Stale skill text: skills/adwords-virtuoso/SKILL.md:136 (and its .claude and Boss JSON copies) still say v23, pinned in connector_credentials.py. No docs/skills/SKILL_DELTA_* was logged (rule 03).
  • 17. Merchant provenance report_view is taken from req.resource's default even when req.query selects a different view.
  • 18. The Boss health probe ignores the GOOGLE_ADS_API_VERSION override that the Boss unified client honours.
  • 19. Regenerating the GAQL lock also pulled in about 15 unrelated transitive upgrades, including oauthlib 3.3.1→4.0.0 (a major version). Tests pass with the real SDK, but the PR should say so.
  • 20. /api/v1/upload-requests:reconcile is not tenant-scoped. The sweep is bounded and returns counts only.

Checked and found correct

  • Google Ads dates: I fetched the sunset page (last updated 2026-09-30): v22 "October 2026 (tentative)", v23 Feb 2027, v24 May 2027, v25 Aug 2027, "any time in that month", and "fail on or after the sunset date". The code matches. "Retired when days_left <= 0" is applied the same way in the runner, gateway, Boss, GAQL, website and offline rail, and boundary tests exist for each.
  • Meta tables: the Marketing and Graph version tables match the inventory. v26.0 is "Available until TBD". The Explore placement removal (v26.0 and later) and Messenger Stories removal (v26.0 and later, all versions on 2026-10-27) match REMOVED_PLACEMENTS. No Python Meta caller sends the 2026-10-27 legacy protocol fields or Delivery Estimate fields.
  • Merchant Reports v1: the URL and all field names exist in the reports_v1 reference. The Klaviyo 2026-07-15 Get Events change is as the change describes.
  • SDK: google-ads 33.0.0 ships _VALID_API_VERSIONS = ['v25','v24','v23'], and get_service uses the version set at construction. GAQL tests: 73 passed with the real SDK.
  • Safety:
  • flags.py is untouched, and the runner's deploy workflow asserts EXECUTION_ADAPTERS_ENABLED=false.
  • All Boss direct writes are refused before quota, token or network calls, with a source-literal pin on the default.
  • The GAQL live mutation path still raises NotImplementedError.
  • Data Manager: the consent gate runs first, then tenant resolution. Records are tenant-bound, the status route is tenant-scoped, records hold no personal data, and every transition is audited. A timeout becomes "unknown", and a blind resend gets 409.
  • Images: the four provider_versions.py copies are byte-identical and ship in every image. The gateway, runner, Boss and GAQL deploys use --set-env-vars, so no stale version env survives a redeploy.
  • Test results at HEAD:
  • connectors 972 · Data Manager 44 · measurement-rails 497 · net-yield 208
  • intent-leads-extender 7 · intent-pullers-extender 24 · website 949 · gemini-kg-pipeline 237 OK
  • tests/services 39 (+1 skipped) · claims_backing 196
  • Auto-merge gates: content_gates.sh exit 0 (155 gate tests passed); gate-leak scan clean; rule-03 V1–V3 greps clean on the changed files.
  • The governance suite fails on exactly one test at both base and HEAD (test_pilot_report::test_default_ledger_path_is_the_in_tree_ledger), caused by my venv's editable contracts install, not by the change.
  • Baseline moves in tests: each moved assertion keeps or strengthens its original intent. The one test that should have moved and didn't is finding 1.

4.2 Pass 1 dispositions (fix commit b4860c8)

Every code fix has a test that fails on d787e7e and passes on b4860c8 (measured by restoring the d787e7e file and re-running the test).

# Finding Disposition Issue Test
1 WO-24 agreement test red (canonical-ingestion deploy gate) fixed: compares with API_VERSION_SUNSETS, day and month rows; mutation-checked both ways API-E5 test_wo24_sunset_list_agrees_with_the_repo_wide_sunset_guard; pytest tests/remediation -q 396 passed
2 branch auto-merges, 6 deploys, no claim publication on a non-auto-merge branch behind a draft PR; coordination claim recorded with publication (RESUME.md) — —
3 Meta served-version warning crossed tenants fixed: read per response API-B9 test_apicompat_meta_served_version_warning_never_crosses_executions
4 Merchant performance rows: second Product node, conversion currency on it fixed: record type product_performance (unmapped), conversion_value_currency API-C6 test_merchant_catalog_and_performance_rows_name_one_product
5 two sunset gates, two policies fixed: deployed rows (live, dark, credential_gated) fail 14 days out in both; dormant/descriptive warn API-G15, API-G13 test_checker_fails_a_credential_gated_selection_like_a_dark_one
6 unknowns invisible in CI fixed: one warning in the pytest summary API-G15 governance run shows the 20 unknowns
7 console Klaviyo call on retiring revision, tree not covered fixed: revision 2026-07-15 + JSON:API Create Event body + empty-202 handling; tree covered; row klaviyo.console_email_send API-G14 route.test.ts (vitest)
8 Cloud-project remedy missed array-shaped errors fixed: both shapes read (4 copies) API-D7 test_google_ads_pull_names_the_cloud_project_remedy[stream-array]
9 Page Insights default metric not documented fixed: three defaults Meta retired for all versions replaced by its documented alternatives API-B10 tests/market_signal/test_meta_page_insights_metrics.py
10 synthetic GAQL rows rendered as campaign metrics fixed: channel routes 503 unless allow_synthetic=true API-A6 test_channel_routes_refuse_synthetic_rows_unless_asked
11 record untracked while 13 files cite it fixed: record committed; test requires the ledger and its four files API-G15 test_the_inventory_names_a_ledger_that_exists
12 enhanced conversions misfiled, expired v21.0 fixed: governed version; row moved API-G16 test_enhanced_conversions_emq_read_uses_the_governed_meta_version
13 GAQL version checked once fixed: per extraction and health read API-A7 TestVersionCheckedPerCall
14 GAQL envelope literal v23 fixed: configured version or unknown API-A8 test_api_version_fallback_is_configured_never_a_literal
15 Boss modules still require developer tokens not changed, on purpose: the requirement keeps Boss-direct write paths off for any setup without a legacy token; removing it would arm them API-G13, API-G12 —
16 skill text stale, no delta docs/skills/SKILL_DELTA_20261001_api_compatibility.md (applied by the Boss skill process) API-G17 —
17 Merchant report_view from the request fixed: read from the row API-C6 test_merchant_report_view_comes_from_the_row_not_the_request
18 Boss probe ignored the override fixed API-E6 test_google_probe_honours_the_operator_override_like_the_unified_client
19 15 transitive lock moves incl. oauthlib 4.0.0 disclosed (API-A1 evidence, PR body) API-A1 GAQL suite with google-ads 33.0.0
20 reconcile route not tenant-scoped kept global on purpose, documented in the route: counts only, due records only API-F3 —

One defect was introduced and caught while fixing these: the new inventory row first quoted the console's deploy-environment flag, and tests/connectors/test_ttv_onboarding_completion_gateway.py (and its twin in the gateway suite) reads every non-doc file that carries such a flag and names the service as an environment source, so it failed with cannot read. The copy was reworded (rule 01, "fix the copy, never the rule").

4.3 Pass 2 — d787e7e..b4860c8 (report verbatim)

Independent verification of d787e7e..b4860c8 (one commit, b4860c8)

Bottom line. b4860c8 closes most of the earlier findings, and every new test it adds fails on d787e7e's code and passes on b4860c8's (I ran b4860c8's tests against d787e7e). But b4860c8 on its own has four problems: - It is red on 3 CI steps (7 failing tests). One new inventory row breaks 6 tests, and the missing ledger breaks 1 governance test. - Finding 10 is only partly fixed. The console's Google Overview page still shows synthetic metrics. - The finding-13 fix creates a latent path from synthetic data to a live mutate client, with no Decision Control Plane in between. - Dispositions for findings 15 and 19 are not recorded, and the inventory cites ledger ids (API-G13, API-G14) that do not exist.

Two commits landed in the main checkout after b4860c8 while I was running: 925d005 and f44a7d8. On f44a7d8 the 7 failures pass (115, 49 and 76 passed in the three affected files). I did not otherwise verify those two commits.

Earlier findings

# Verdict Evidence
1 FIXED Ran pytest tests/remediation -q with the canonical-ingestion gate's install line. d787e7e: 1 failed (the WO-24 agreement test), 394 passed. b4860c8: 396 passed. The test is not weakened: it now checks every row of API_VERSION_SUNSETS against the guard, dates included. Mutation check: moving the v24 date to 2027-05-02 makes it fail.
3 FIXED Nothing is stored on the adapter any more: grep finds only the staticmethod and local variables, and no caller of the old _read_node is left. The new cross-tenant test fails on d787e7e and passes on b4860c8.
4 FIXED Performance rows now have record type product_performance and the projector skips them as unmapped; the conversion currency moved to conversion_value_currency. The new projector test fails on d787e7e. Side effect (NIT): the default Merchant pull (resource=product_performance) now puts nothing in the KG, not even the account_gmc_* PlatformAccount node. The commit does not mention this.
5 FIXED I swept every day from 2026-10-01 to 2027-08-15 through both gates. At b4860c8 both first fail the Boss v23 pins on 2027-01-18. At d787e7e, api_lifecycle_check.py --as-of 2027-01-18 gave 0 failures (a warning only).
6 FIXED Unknowns are now raised with warnings.warn. tests/governance/pytest.ini has no filterwarnings or -p no:warnings. A passing run printed UserWarning: provider API lifecycle: UNKNOWN …, 20 selection(s).
7 FIXED The console is now scanned (1172 tracked files) and the route is pinned to revision 2026-07-15. Removing the row in memory produces the coverage gap; restoring it gives none. vitest: the new test gets a 500 on the old route (empty 202 parsed as JSON) and passes on the new one (2/2). Klaviyo docs confirm revision 2026-07-15 is GA, 2024-10-15 is "supported until 2026-10-15", and the reference uses the {data:{type,attributes}} body. Governance note: see N4.
8 FIXED The gateway passes the raw parsed body (_json_body) on to the remedy lookup. The four copies are byte-identical (sha256 65d4dbd2…). On d787e7e the [stream-array] case returns 502; on b4860c8 it returns 503 with the remedy.
9 FIXED Checked against developers.facebook.com/docs/platforminsights/page/deprecated-metrics ("Updated: Mar 2, 2026"): page_engaged_users was deprecated 2024-03-14; page_fans (alternative page_follows) and page_impressions (alternative page_media_view) on 2025-11-15. page_views_total and page_post_engagements are still in the v26.0 reference. NIT: RETIRED_PAGE_METRICS (client.py:41) lists only those 3, so e.g. page_impressions_unique would still be sent. Nothing in production calls this method.
10 PARTIAL The eight /channels/google/* GET routes now return 503 unless allow_synthetic=true (checked in-process). But app/channels/google/page.tsx:32 posts to /srpvdal/run (main.py:120, not gated), which returns 200 with synthetic numbers: total_cost 1016890.83, total_conversions 30854.86, account_cpa 32.96. The page shows them as Total Cost / Conversions / Account CPA (page.tsx:112-114) without reading data_provenance. The deployed cell has no credentials, so this is what the production Overview page shows.
11 PARTIAL at b4860c8 The guard test is correct, but b4860c8's tree has 0 files under docs/audits/api-compatibility. So test_the_inventory_names_a_ledger_that_exists (test_api_lifecycle_inventory.py:118) fails at b4860c8. The ledger arrives in f44a7d8.
12 FIXED Probe: the Boss Meta client with api_version: None resolves to …/v26.0; v21.0 raises VersionRefused.
13 FIXED, but introduces N3 today=None is stored, so each refresh uses the real date. extract, /health and data_provenance all refresh.
14 FIXED The fallback is now the configured version, or "unknown". The WO-45 guard flagged canonical_adapter.py's v23 for 2027-01-18 at d787e7e and no longer does.
15 NOT FIXED; disposition unsound/incomplete No code change. The only record is ISSUES.json API-G12 in f44a7d8, and it is wrong in three ways (below). Leaving the token requirement in place arms nothing, but the plan in the next point should not be followed.
16 Disposition sound (outside range) The SKILL_DELTA in f44a7d8 is a DRAFT and not applied, which is what rule 03 requires. skills_sync --check and ontology_skills_sync --check both report OK.
17 FIXED report_view now comes from the row (merchant_record_type). The new test fails on d787e7e.
18 FIXED The probe now uses environment override, then class default, the same order as _api_base (config api_version is None by default). The new test fails on d787e7e. The Boss deploy sets no override.
19 NOT ADDRESSED / not recorded The lock file is unchanged in b4860c8, and git grep -i oauthlib f44a7d8 (excluding lock and requirements files) finds no disposition. My measurement says the risk is low (details below).
20 Disposition sound reconcile_due returns counts only (recovered/scanned/finalized/still_open/expired). It reads only records with next_check_at <= now; limit ≤ RECONCILE_BATCH; callers are verify_caller platform identities. Not in the docstring: recover_stale_sends changes state across tenants (in-flight to unknown). The background loop makes the same transition, and nothing is disclosed.

Finding 15, why API-G12 is not a sound disposition: - It calls platform_rollback_integration a "dormant path", but it is imported by the deployed Boss (boss_agent_core.py:2480), and the inventory classifies it credential_gated. - It never names mcp_connector_registry_v2, which requires developer_token (lines 1059 and 1493). - Its next action is "remove the header when a path is armed". PlatformRollbackManager makes direct Google and Meta mutations from Boss with no DCP or DIRECT_WRITES gate (grep finds none). The disposition should say this path must not be armed outside DCP → action-runner, not prepare it.

Finding 19, measured risk. google-ads 33.0.0's oauth2.py uses only google.oauth2 / google.auth. Nothing in the cell imports oauthlib. oauthlib 4.0.0 imports cleanly alongside requests-oauthlib 2.0.0 and google-auth-oauthlib 1.5.0. The cell suite passes on the lock (76 passed).

New defects

  • N1 BLOCKER (b4860c8 alone): 3 CI steps red.
  • Cause: production/provider-api-lifecycle.json:1385. The new console row's gate text quotes --set-env-vars, and the TTV scanners report production/provider-api-lifecycle.json:1385: cannot read.
  • Failing tests:
    • tests/governance/test_ttv_outcome_actual_stamps.py: 2 tests (governance spine step).
    • tests/connectors/test_ttv_onboarding_completion_gateway.py: 2 tests (ci.yaml connectors step and the canonical-ingestion deploy gate).
    • services/service-marketing-connectors/test_tenant_economics_ttv_stamp.py: 2 tests.
  • All of these pass at d787e7e.
  • Together with the ledger test in finding 11, governance is 3 failed / 4344 passed.
  • 925d005 rewords the text and f44a7d8 adds the ledger; all 7 pass at f44a7d8.
  • N3 MAJOR (latent): synthetic actions can reach a live mutate client without the DCP.
  • How it happens:
    • The ACT stage keeps its own reference to the Google Ads client, captured when the cell is built (orchestrator.py:54).
    • On the sunset day, refresh_version_status drops only the connector's reference (client.py:159).
    • The run then senses the synthetic stream, and synthetic runs skip the DCP (governed = None if synthetic, orchestrator.py:231).
    • The locally authorized actions then go to the executor (orchestrator.py:238), which still holds the live client.
  • Probe (fake SDK client; approval_required mode with the request's own human_approved=True; dry_run false; live mutations flag on):
    • Sunset day: 500 synthetic events and 58 authorized actions. The executor called get_service('AdGroupCriterionService', version=None) on the stale client.
    • It stopped only at act.py:98's NotImplementedError.
    • The control run one day earlier never reached ACT.
  • This state could not occur at d787e7e. It is not reachable today: the live-mutations flag is off by default, the cell has no credentials, and the operation builder is unimplemented.
  • Fix: drop or re-read executor._client on refresh, and refuse ACT whenever the data is synthetic.
  • N2 MINOR: inventory cites ledger ids that do not exist. It cites API-G13 (lines 621 and 626) and API-G14 (1384 and 1389). The ledger landed in f44a7d8 holds 45 ids, E1 through G12, with no G13 or G14.
  • N4 MINOR, governance: the Klaviyo fix makes a non-DCP write route work.
  • /api/action-hub/email/send is on the console's frozen list of routes with no in-handler caller check ("sends email through SendGrid/Klaviyo with the platform API key").
  • Klaviyo's reference says Create Event upserts the profile and triggers flows unless backfill is true. So after this fix, one environment variable (EMAIL_SERVICE=klaviyo plus a key) turns on a working provider write outside DCP → action-runner (law A.7).
  • It is not armed: EMAIL_SERVICE is not in the console's cloudbuild --set-env-vars, and the only mounted secret is the Supabase key.
  • The inventory row presents arming as a configuration step and does not mention the DCP rule.
  • N5 MINOR, package docs in f44a7d8 (outside the range) contradict b4860c8:
  • CLOSEOUT still says only live/dark rows fail and that the Boss v23 pins only warn (from 2026-11-03), and omits the 2027-01-18 CI-fail date.
  • It says "6 deploy workflows". The deploy router over d787e7e..b4860c8 and over 3d5278b..b4860c8 plans 7: boss-agent-core, gemini-kg-pipeline, gemini-meta-worker, google-ads-gaql, service-action-runner, service-marketing-connectors and ui, plus frontend-guard.
  • RESUME says "seven commits … d787e7e".
  • The CLOSEOUT "Independent review" section is a placeholder.
  • EVIDENCE's GAQL test counts are stale (70+3 / 73 written; now 73+3 / 76).
  • N6 NIT: refresh race. A health request on another thread can clear _client between _search_stream's None check and _service(). The resulting AttributeError is caught as an extraction error. It can only happen on the sunset transition.

Test runs

Fresh Python 3.11 venvs, install lines copied from the b4860c8 workflows; proxy variables unset; short TMPDIR. Results as b4860c8 → d787e7e:

Suite b4860c8 d787e7e
Canonical-ingestion gate: tests/remediation 396 passed 1 failed (finding 1), 394 passed
Canonical-ingestion gate: tests/connectors 2 failed (N1), 585 passed 584 passed
Canonical-ingestion gate: test_kg_write_perimeter.py 68 passed 68 passed
ci.yaml governance (-c tests/governance/pytest.ini) 3 failed (N1, finding 11), 4344 passed, 7 skipped 1 failed*, 4344 passed
ci.yaml services/service-marketing-connectors 2 failed (N1), 386 passed 388 passed
ci.yaml test_execution_adapters.py 178 passed 177 passed
ci.yaml tests/market_signal 294 passed 292 passed
ci.yaml cell37 33 passed 33 passed
GAQL, lock venv (google-ads 33.0.0) 76 passed 73 passed
GAQL, suite-wiring venv 73 passed, 3 skipped 70 passed, 3 skipped
Suite wiring: tests/services 41 passed, 1 skipped 39 passed, 1 skipped
Suite wiring: data-manager connector 44 passed 44 passed
Suite wiring: claims_backing 196 passed 196 passed
Suite wiring: "# MIZ OKI 3.5/tests" 949 passed 949 passed
Suite wiring: connector_gateway 17 passed 17 passed
Orphaned suites 980 passed 980 passed

*The d787e7e failure is test_pilot_report::test_default_ledger_path_is_the_in_tree_ledger. It is an artifact of my setup: the venv's editable contracts install pointed at the b4860c8 worktree, so the path comparison crossed trees. It passes in the matching tree, and I do not attribute it to either commit.

Also at b4860c8: - .github/scripts/content_gates.sh: rc 0 (155 passed). - Rule-03 V1–V3 greps on the diff: no hits. - Console: vitest route test 2/2; lib/auth, the no-public-backend-url ratchet and app/api/action-hub 192/192; tsc --noEmit clean; next lint clean on the two changed files.

Not checked, and disclosures

  • Constraint breach. While checking whether oauthlib is on the cell's runtime path, I called GoogleAdsClient.load_from_dict with dummy credentials ("x"/"y"/"z"). The library refreshes the token eagerly, so one request went to Google's OAuth token endpoint and came back invalid_client. No real credential was involved and no Google Ads API call was made, but this broke the no-provider-calls rule.
  • next lint ran without NEXT_TELEMETRY_DISABLED, so it may have sent a Next.js telemetry ping.
  • Shared venvs. My first venv build reused the names scratchpad/venv-ci and venv-cig, which belonged to another session (created 15:02 and 15:51). uv reinstalled into them and pointed their editable mizoki_contracts at my worktree. I pointed them back to /home/user/MIZOKICloudRun/contracts (finder MAPPING and direct_url.json), which is what that session's other venvs use. Their package versions may have changed. All my measurements came from fresh venvs under scratchpad/vfy.
  • Main checkout. One early git status there ran before I turned optional locks off. Everything else there was read-only.
  • Not checked:
  • What a real searchStream error body looks like (Google's docs do not show one).
  • Live behaviour at Klaviyo or Meta, and the deployed revisions (no GCP access).
  • The full console vitest suite and Playwright.
  • The CI runner's exact git and Python builds.

Cleanup. All five of my worktrees and /tmp/v2 are removed, along with my venvs. The base and memwt worktrees were not touched. Logs are in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy/ (ci-head.out, ci-prev.out, cig-*.out, wire-*.out, content-gates-head.out, cmp_gates.py).

4.4 Pass 2 dispositions (fixes in 606fb8a, authored as 8e961af; record in the commit that adds this section)

Each code fix has a test that fails on b4860c8's code and passes on 606fb8a (measured by restoring the old files in a throwaway worktree and re-running the test).

# Finding Disposition Issue Test
N1 3 CI steps red at b4860c8 alone already cleared before pass 2 reported: 925d005 reworded the inventory row, f44a7d8 committed the ledger; the verifier measured all 7 tests passing at f44a7d8 API-G15 the TTV env-source scanners; test_the_inventory_names_a_ledger_that_exists
N2 inventory cited API-G13 / API-G14 before the ledger held them the ids exist since 0cf37f0; a guard now fails on any id the inventory or this record cites that the ledger lacks API-G15 test_every_ledger_id_the_inventory_and_record_cite_exists
N3 synthetic actions could reach a live mutate client without the DCP fixed: the executor re-reads the connector's client before every ACT, and a synthetic run is always a dry run; e3bd49e makes it authorize nothing at all (Copilot, §4.5) API-A7 TestSyntheticRunsNeverMutate
N4 the Klaviyo fix makes a non-DCP write route work the route and its inventory row say it must stay unarmed (law A.7); it stays dark (EMAIL_SERVICE is not in the console's deploy env map); retiring it or routing it through DCP is the owner's decision API-G14 —
N5 package docs contradicted b4860c8 CLOSEOUT dates, the 7-deploy plan, the review section and RESUME were corrected in 0cf37f0; the GAQL counts in §3.2 now name their commit — —
N6 refresh race between the client check and _service() fixed: one snapshot of the client per extraction decides the label and the stream API-A7 no deterministic race test; the extraction tests exercise the snapshot path
10 the Overview page's /srpvdal/run still served synthetic totals fixed: /srpvdal/run, /srpvdal/sense, /srpvdal/run-mcc and GET /mcc/{id}/accounts answer 503 google_ads_not_live unless allow_synthetic is set API-A6 test_channel_routes_refuse_synthetic_rows_unless_asked (extended)
15 API-G12 disposition unsound corrected, and the pass-1 claim withdrawn: the developer-token references gate nothing (the rollback manager never checks it; the registry's validate_credentials has no caller). The rollback manager's direct Google and Meta writes are registered by default and dark only because Boss mounts no ad credentials. This lane leaves the module unchanged and records the owner decision API-G12, API-G13 —
19 the oauthlib major move was not recorded recorded with the verifier's measurement (no cell import; clean import; 76 passed on the lock) API-A1 —
20 the reconcile docstring omitted the one cross-tenant state change docstring now names recover_stale_sends API-F3 —
NIT (4) the default Merchant pull adds no KG account node recorded; before this lane the default pull failed outright, so no consumer lost a node API-C6 —
NIT (9) RETIRED_PAGE_METRICS lists three metrics kept narrow on purpose (the former defaults); acceptance reworded to say so API-B10 —

Verifier disclosures, recorded as given (§4.3): one OAuth token request to Google with dummy credentials while probing an import path (invalid_client; no real credential and no Google Ads call); a possible Next.js telemetry ping from next lint; and reinstalls into this lane's venv-ci / venv-cig, which it repointed. Responses: pass 3 runs any code that can build a provider client inside unshare -rn, with NEXT_TELEMETRY_DISABLED=1, in venvs of its own; the 8e961af sweep (§3.2) used fresh venvs only.

4.5 Copilot review of #1299 (head 0cf37f0, posted 20:20Z, after the merge)

Copilot's overview: "Synthetic data can still reach execution, provider failures can appear as valid empty reports, and reconciliation is race-prone." Its three inline comments, verbatim:

orchestrator.py 231–233 (high). When synthetic is true, skipping _govern leaves the locally authorized actions in authorized; lines 234–240 then pass them to the executor. With dry_run=false, human_approved=true, and live mutations enabled, synthetic metrics can therefore drive provider mutations without DCP authorization. Clear authorized for synthetic runs rather than merely bypassing _govern.

request_tracking.py 411–415 (medium). The due/rate-limit checks occur before the provider call and are not claimed transactionally. Two concurrent reconcilers (for example the background loop plus scheduler/manual refresh) can both fetch the same request status and consume two checks; a representative concurrent run produced two provider calls and incremented checks twice. Acquire a per-record transactional lease/check claim before fetch, then finalize that claimed attempt afterward.

main.py 253–256 (medium). This gate only proves that a client object was constructed. GoogleAdsConnector.extract() catches provider/auth failures and returns ExtractionResult.error, but cell.sense() discards that error; these channel routes then return HTTP 200 with empty rows. Propagate extraction failures to these routes (for example as a 502/503) so expired credentials or provider outages do not look like valid zero-data reports.

Finding Verified Disposition (e3bd49e) Issue Test
synthetic runs keep local authorizations yes, same path as pass 2's N3 a synthetic run authorizes nothing; gate reports kept; warning counts the withheld actions API-A7 TestSyntheticRunsNeverMutate (2 tests)
concurrent reconcilers read twice yes, reproduced deterministically (two reads, checks 2) checks and a claim in one transact_update; lease DM_STATUS_CHECK_LEASE_SECONDS (300 s); finalize clears it API-F6 test_concurrent_reconcilers_read_a_record_once, test_a_claim_left_by_a_dead_reconciler_lapses
failed extraction reads as empty yes, on every reading route and the run path 502 google_ads_extraction_failed naming each failed query; a live run stops after SENSE; a failed MCC listing runs no child API-A9 TestExtractionFailuresAreErrors (3 tests)

The replies on the three threads name these commits, and the threads are resolved; the fixes deploy when #1302 merges (the Data Manager one by operator deploy).

4.6 Pass 3 — follow-up PR #1302 (3f89cd0..db3c271, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-01 from 21:00Z to about 21:42Z. Its report, verbatim:

Independent verification, pass 3: 3f89cd0..db3c271 (draft PR #1302)

Bottom line. I found no blocker. The code does what the range says: - A synthetic run authorizes nothing, and the executor re-reads the connector's client before ACT. - While the connector is not live, every route that serves SENSE rows, totals or account listings answers 503 unless allow_synthetic is set. - A failed live extraction answers 502. - A Data Manager status read is claimed inside one transaction.

Every gate I ran is green, except two reds caused by my environment (the shallow clone, and the sandbox's commit signer). Each is explained below.

What is wrong: 1. MAJOR, latent. The new rule "a live run stops on any failed extraction" meets a registry query, change_status_v1, that carries no LIMIT unless the caller passes one. The installed v25 SDK documents that LIMIT as required. Once credentials land, /channels/google/decisions and every no-limit run will always answer 502 and plan nothing. 2. One of the two TestSyntheticRunsNeverMutate tests passes on the old code, although the record, the commit message, the PR body and the Copilot reply all say both fail there. 3. "Nothing persisted" is false for a partial failure: the raw rows of the queries that answered are saved during SENSE. 4. The Data Manager lease is stamped with the sweep's start time, so a slow sweep writes claims that have already expired. 5. Several record inaccuracies, the largest being API-A5 marked DEPLOYED and an unsupported "no credentials are mounted".

Basis for the old-code runs: git diff --stat shows the GAQL and Data Manager code identical at b4860c8, 0cf37f0 and 3f89cd0. I ran the new tests against 3f89cd0's code restored in my own worktree.

Pass-2 and Copilot items

Item Verdict Evidence I produced
N2 FIXED Catches the original case: the new guard, run on the f44a7d8 tree, fails with ['API-G13', 'API-G14'] in the inventory. Mutations at db3c271:
• an id the ledger lacks, added to RESUME.md → fails;
• API-G14 removed from ISSUES.json → fails in all four files;
• an id the ledger lacks, added to the inventory → fails;
• unmodified → passes.
Limits: D12.
N3 FIXED Code: orchestrator.py:254-261 empties authorized for a synthetic run, :271 re-reads the client, :272 forces a dry run. Single call site: git grep finds one executor call in the repo, orchestrator.py:274. It is reached only through run(), from /srpvdal/run, /srpvdal/run-mcc (per child) and /channels/google/decisions. Probe (never-live cell, approval_required + human_approved, live-mutations flag on): old code 28 locally authorized → 28 executions; new code 28 → 0 authorized, 0 executions. Residuals: D2, D13.
N4 FIXED (as a disposition) Recorded: the comment at route.ts:78-82, and the inventory gate text names law A.7. Dark today: EMAIL_SERVICE is absent from the console cloudbuild.yaml, which uses --set-env-vars and --set-secrets, both of which replace the whole map; the route defaults to 'mock' (route.ts:40). Still open: the route stays ungated (api-route-roles.ts:92-95). No test pins EMAIL_SERVICE's absence from the deploy env map.
N5 FIXED CLOSEOUT now has the 2027-01-18 fail date, "7 services" and a filled review section. RESUME's commit list and §3.2's GAQL counts name their commits. New inconsistencies: D8, D9.
N6 FIXED (the stream path) Fixed: client.py:243-245 snapshot, passed to _search_stream and _service (:272, :313). Remaining read: validation between the snapshot and the stream (:252-253 → _live_field_lookup :184-199) still reads self._client. It is benign: the lookup catches the error and _lookup falls back to the static catalog.
Finding 10 FIXED in #1302 (not deployed) Route table: I enumerated app.routes (23 method/route pairs). With the connector not live and no allow_synthetic: the 8 channel routes, the 3 /srpvdal POSTs and the MCC listing answer 503; /gaql/*, /health, /metrics and the docs pages answer 200 with no rows. Test: the extended route test fails on the old code. Residual: D11.
Finding 15 (disposition) ACCURATE, except one carried error Rollback manager (platform_rollback_integration.py):
• token sent but never checked: :186, :240
• OAuth from GOOGLE_ADS_CLIENT_ID/_SECRET/_REFRESH_TOKEN: :187-189, :207-227
• enabled appears only in get_status: :1160
• mutates with validateOnly false: :275, :285, :291, :362, :447
• Meta calls on graph.facebook.com: :570
Boss core: boss_agent_core.py:2480 (import), :2511 (default "true"), :27823 (MCP tools registered at startup).
Registry: validate_credentials requires developer_token at lines 1059 and 1493; it has no caller anywhere in the repo.
Boss deploy: cloudbuild.v5.yaml uses --set-env-vars and --set-secrets and names no Google Ads or Meta variable.
Error: D7.
Finding 19 (record) ACCURATE The GAQL lock moved 15 pins from 3d5278b to db3c271. The only major moves are google-ads 25.1.0 → 33.0.0 and oauthlib 3.3.1 → 4.0.0; the other 13 match the list.
Finding 20 (docstring) FIXED The docstring now names recover_stale_sends. reconcile_due calls it (request_tracking.py:496), and the background loop runs reconcile_due.
NIT (finding 4) ACCURATE direct_connectors.py:909 defaults to product_performance. merchant_record_type returns product_performance (:397-410), which projector_kg.py does not map (only product_report, :345). account_gmc_* is created only in _map_merchant_product (:265).
NIT (finding 9) ACCURATE RETIRED_PAGE_METRICS lists 3 metrics (connectors/meta_signals/client.py:41). get_page_insights has no caller beyond its own fake and the tests. The acceptance was reworded.
Copilot, high: synthetic runs keep authorizations FIXED Same evidence as N3. Only the sunset-day test is a real test (D2).
Copilot, medium: two reconcilers read one record twice FIXED when reconcilers share a clock; gap in long sweeps Both new tests fail on the old code (['req-1', 'req-1']); the suite has 46 passed. Gap: D4.
Copilot, medium: failed extraction reads as empty FIXED TestExtractionFailuresAreErrors (3 tests) fails on the old code. All 12 reading routes answer 502. Side effects: D1, D3.

New defects

D1 — MAJOR (latent): no live run without a limit can succeed, and the Decisions page will always error once Google Ads is live - Where: - gaql_registry.py:303 defines change_status_v1. - build() adds LIMIT only when limit is truthy (:41-42). - The query is in run()'s default set. - main.py:386 (decisions) and :339 (changes) pass no limit. - orchestrator.py:175-186 returns before REASON on any failed extraction. - Why it will fail: the installed SDK's v25 ChangeStatusErrorEnum documents LIMIT_NOT_SPECIFIED: "The change_status search request must specify a LIMIT." - Scenario: credentials are mounted, and the console Decisions page calls /channels/google/decisions. - change_status_v1 fails, the run stops after SENSE, and the route answers 502 every time. - The same happens on /channels/google/changes, and on any /srpvdal/run or /srpvdal/sense call without a limit. - In /srpvdal/run-mcc without a limit, every child counts as failed. - Before this range the failure was silent, and the other nine queries still produced decisions. The Overview page passes limit: 50, so this query does not break it. - Fix: - Give change_status a mandatory LIMIT of at most 10,000 in the registry. - Pin it with a test over every registered query built with limit=None. - Decide whether an auxiliary query's failure should block planning on the performance queries.

D2 — MINOR: one of the two new "synthetic never mutates" tests passes on the old code - Where: test_api_compat_binding.py:292-303, test_a_never_live_cell_authorizes_nothing_for_execution. - Why it is vacuous: it runs in autopilot mode, where the local gates authorize only low-risk action types, and on this synthetic data none is. - Probe on the old code: autopilot → 0 locally authorized; approval_required + human_approved → 28 authorized, 28 executions. - Measured: the test PASSES on the old code. The other 5 new GAQL tests fail there. - False claims: API-A7's evidence ("both tests fail on 0cf37f0's code"; "asserts some local gate authorized an action"), the e3bd49e commit message, the #1302 body and the Copilot reply. - Fix: use approval_required with human_approved=True, and assert that some gate authorized before asserting 0.

D3 — MINOR: "nothing persisted" is false for a partial failure - Where: SENSE saves raw rows (orchestrator.py:81-82) before run() checks the errors. The run's own warning (:184, returned in the API result) says "nothing persisted". - Probe: a live fake client where only change_status_v1 fails → 9 save_raw_rows calls, then that warning. - Repeated in: API-A9's acceptance, the #1302 body and the Copilot reply. - Why no test sees it: the new test uses a client where every read fails (:364). - Fix: buffer the raw rows until after the error check, or reword. Add a partial-failure test either way; that case is also where the old and new behaviour differ (old code planned 2 actions, new code stops).

D4 — MINOR: the Data Manager lease is anchored to the sweep's start - Where: request_tracking.py:431 stamps check_claimed_at with the caller's now, and reconcile_due passes one now, the sweep's start, to every record (:492-511, :504). - Probe: 12 due records, each read taking its 30 s timeout. The 12th claim is written 330 s into the sweep but stamped at its start. A concurrent reconciler at the real time sees it as lapsed and reads again: 2 reads, checks 2. - Scope: this is the case Copilot raised, during a slow provider period. The lease docstring's "a claim outlives its read" does not hold here. - Fix: stamp and compare the lease against the wall clock at claim time. Optionally, store a claim token so the finalizing write clears only its own claim.

D5 — MINOR: "no credentials are mounted" on the GAQL cell is unsupported present tense - Where: CLOSEOUT.md:49 and :94-95, EVIDENCE.md:513-515, API-A7's evidence. - Why it is unsupported: - The only basis is cloudbuild.yaml. It sets --set-env-vars but passes no --set-secrets or --clear-secrets, so a secret env var mounted on an earlier revision survives (rule 04). - The old manifest at 3d5278b mounted GOOGLE_ADS_CLIENT_ID, _CLIENT_SECRET, _REFRESH_TOKEN and _DEVELOPER_TOKEN from Secret Manager. - The deploy's verify step (job 110563954917) reads only the control plane and the unauthenticated 403, never /health. - Fix: say "the deploy config mounts none". Measure the serving revision's secret references, or an authenticated /health google_ads_live, under API-E4.

D6 — MINOR (record): API-A5 is marked DEPLOYED, but its fix ships nowhere - Its fix is cloud-run-google-ads-gaql.yaml, now headed "REFERENCE MANIFEST — not the deploy path"; the deploy uses gcloud run deploy flags. - Should be NOT_APPLICABLE, which makes the counts 32 DEPLOYED and 16 NOT_APPLICABLE. - The other 32 DEPLOYED issues map to files the Deploy Router matched for the seven workflows (cb7b7ff^1..cb7b7ff). The rails ship in the Boss image (Dockerfile.v5:60). Nothing is VERIFIED.

D7 — NIT (record, carried from 3f89cd0): API-G13 says "13 lines" and "the WO-45 guard's _scan(2027-01-18) reports the same 13 pins" - Measured: _scan reports 12 lines on both db3c271 and 3f89cd0, and git grep finds 12 v23 pins in the Boss tree. - The dated escalation itself is right. A day-by-day sweep from 2026-10-01 finds the first failure of both gates on 2027-01-18.

D8 — NIT (record): EVIDENCE.md:256 contradicts §3.5 - Line 256 still opens §3 with "Nothing below is deployed or live-verified", while §3.5 now lists the deploy runs and "Deployed: the 33 issues…". At 3f89cd0, §3.5 said "None."

D9 — NIT (record): miscounts - CLOSEOUT.md:19 and RESUME.md:27 say "53 implemented and tested". Measured: 53 IMPLEMENTED, 52 of them TESTED (API-G17's testing is NOT_APPLICABLE). - CLOSEOUT.md:165-166 says pass 2 "verified every pass-1 fix except three". Pass 2's table has four rows not FIXED or sound: 10, 11, 15 and 19. - API-A2 and API-A3 stay REVIEW_READY although 606fb8a edited _service() and extract()'s labelling. Their tests pass.

D10 — NIT (record): revision 00079-ptp was built from main (e480aaa), not from cb7b7ff - §3.5 and the deployed issues say "Deploy Marketing Connectors run 36920171263 at cb7b7ff … 00079-ptp". - That workflow checks out ref: main (deploy-service-marketing-connectors.yml:60-64 and :112-116). - e480aaa was on main by 20:15:35Z (run 36920255631 created), before this job's checkout at 20:16:21Z. Its README push shows e480aaa95..e7348d5c9. - e480aaa contains cb7b7ff, so the change is in the deployed code either way; only the attribution is imprecise.

D11 — NIT: a request straddling the sunset can still get synthetic data without allow_synthetic - _require_live (main.py:253-272) checks before SENSE, and the client is dropped inside extract's own refresh. - Probe: the check passes on 2027-07-31 and the extraction runs on 2027-08-01. /channels/google/campaigns answers 200 with 3 synthetic rows, and /srpvdal/run answers 200 with synthetic totals (30 sensed). They are labelled only in data_provenance, which the console does not read. - The window is the requests in flight at the sunset instant. - Fix: refuse from the extraction's own provenance.

D12 — NIT: limits of the N2 guard - It fires on any text of the shape "API", hyphen, uppercase letter, digits that is not a ledger id. I seeded a provider version written that way in EVIDENCE.md and the test failed. - It does not scan ISSUES.json's own references. A seeded dangling depends_on passes; none dangle today. - Because EVIDENCE.md quotes reviews verbatim, a review that names an id not yet in the ledger would fail CI unless the quote is edited. This report deliberately writes no such id.

D13 — NIT: test and design gaps - No partial-failure test (see D3). - By reading: the synthetic dry-run override (orchestrator.py:272) is not pinned on its own, because authorized is already empty for a synthetic run. - The executor's client is shared state written per run (:271) rather than passed to execute(). A thread interleave at the sunset instant could store a just-dropped client; this is by reading only, and needs live data and armed mutations.

Outside the range, recorded for the owner (not introduced here): - _live_field_lookup queries a segmenting field. The installed v25 GoogleAdsField has no such field (grep count 0), so in live mode every lookup fails and falls back to the static catalog, after one failing provider call per field per extract. - The GAQL image contains no mizoki_governance, so _govern always returns None in production. A live run's ACT then rests on the request's own human_approved. It is latent today: GAQL_ENABLE_LIVE_MUTATIONS=false and the operation builder raises.

Deploy and publication claims (GitHub API, read-only)

Run Head SHA Conclusion Job Log matches the record
36920171359 cb7b7ffc… success 110563954917 yes: Ready=True latestReady=google-ads-gaql-cell-00015-4qn latestCreated=… unauth=403
36920171187 cb7b7ffc… success 110563954595 yes: revision boss-agent-adk-00423-lqd, runtime 6.49.4, SRPVDAL passed, registry 118 entries
36920171312 cb7b7ffc… success 110563954483 yes: /health reports v25, sunset 2027-08-01, {v22: 2026-10-07}, Meta v26.0, CAPI v25.0, every flag false, allowlist 0
36920171263 cb7b7ffc… success 110564512882 yes (00079-ptp); but see D10 for which tree it built
36920171300 cb7b7ffc… success 110564520180 yes: image gemini-kg-pipeline:c4087d5a-…
36920171356 cb7b7ffc… success 110563954663 yes: "Wire Meta credentials" skipped; the job exists
36920171249 cb7b7ffc… success 110563954837 yes: HTTP Status: 307
36920255631 e480aaa success — the run exists and succeeded

Other publication checks: - The website mirror runs 36920171366 and 36914807823 both failed with the same cause, a missing WEBSITE_MIRROR_TOKEN. - #1299 merged at head 0cf37f0. The merge commit time is 20:14:51Z; the API's merged_at is 20:14:52Z. #1300 merged_at is 20:14:12Z. - #1302 is draft, head db3c271, base fa1cc19. main gained #1301 (two docs files) since 3f89cd0, and git merge-tree of the PR head onto fa1cc19 is clean. - Copilot's three threads on #1299 are resolved and their replies name the commits. Two replies repeat the D2 and D3 claims.

Ledger counts reconcile apart from D6 and D9: DEPLOYED 33, IN_PROGRESS 3, OPEN 10, NOT_APPLICABLE 15; runtime OPEN 46, BLOCKED_EXTERNAL 4 (E4, D6, C5, F5), NOT_APPLICABLE 11; 0 VERIFIED anywhere.

Test runs

All runs below were in fresh Python 3.11.15 venvs I built with uv from each job's install lines, inside unshare -rn (loopback only), with proxy variables unset and TMPDIR=/tmp/v3.

Command Environment Result
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" suite-wiring install line db3c271: 78 passed, 3 skipped. 3f89cd0: 73 passed, 3 skipped
same requirements.lock.txt + pytest (google-ads 33.0.0) 81 passed
the new GAQL tests, against the restored 3f89cd0 code wiring venv 5 failed, 1 passed (D2)
python -m pytest "services/service-data-manager-connector/tests" … wiring venv 46 passed. Old code: 2 failed (the new ones), 44 passed
pytest tests/governance -c tests/governance/pytest.ini ci.yaml lint-and-test line + -e contracts + docs/whitepapers/requirements.txt 4348 passed, 7 skipped, 0 failed, 6227 subtests (see Disclosures for the discarded first run)
MIZOKI_STORE=memory pytest tests/connectors -q; … services/service-marketing-connectors -q ci.yaml pins 615; 399 passed
pytest tests/remediation -q; pytest tests/connectors -q; pytest tests/test_kg_write_perimeter.py -q canonical-ingestion gate install lines 396; 615; 68 passed
python -m pytest "docs/audits/tests" … wiring venv 1 failed (test_wo31_register: git show 26bec9c6b… absent in this shallow clone), 7 passed. Identical on 3d5278b
bash .github/scripts/content_gates.sh governance-gates install line first on PATH rc 0, 155 passed
vitest run app/api/action-hub/email/send/route.test.ts npm ci --ignore-scripts, vitest 4.1.11, Node 22.22.0, NEXT_TELEMETRY_DISABLED=1, unshare -rn 2 passed
python3 scripts/api_lifecycle_check.py gates venv rc 0, FAILURES (0)
python3 scripts/gate_leak_scan.py --check gates venv rc 0: "0 new file(s); 0 grown; 0 stale baseline row(s)"
python3 scripts/claude_memory.py check --strict gates venv rc 0: "structurally valid"
the three governance files named in §3.2 ci venv 121 passed (db3c271), 120 (3f89cd0)
deploy_router.py --base 3f89cd0 --head db3c271 ci venv deploy-google-ads-gaql (5 files), deploy-ui (1), frontend-guard (1)

Not checked

  • Live provider behaviour. The change_status LIMIT requirement comes from the installed SDK's own documentation, not a live call. I did not check whether conversion_segmentation_v1's cost metric is compatible with segments.conversion_action.
  • The serving revisions' env and secret mounts (no GCP access).
  • The full console vitest suite, tsc, lint and Playwright.
  • The CI runner's exact git (2.55.0) and Python versions. The sandbox has git 2.43.0 and Python 3.11.15.
  • The ci.yaml jobs outside the range's scope (orphaned suites, the other suite-wiring lines, skills, measurement rails).
  • Gates on #1302's real merge result with fa1cc19. I only confirmed that merge-tree is clean.

Disclosures

  • First governance run discarded. It gave 185 failures caused by my environment. The sandbox's global commit.gpgsign=true calls a signing program that needs a local service, which the empty network namespace cannot reach. I re-ran with signing turned off for the test processes through GIT_CONFIG_COUNT environment variables only; no config file was changed.
  • One import outside the namespace. I checked where mizoki_contracts resolved by running python -c "import mizoki_contracts" in three venvs. Importing it builds a Firestore client, and in the canonical-ingestion venv google-auth looked for default credentials (this may include a metadata-server probe) and found none. No provider API call was made and no credential was used.
  • Install differences from CI. I installed with uv instead of pip; unpinned packages resolved to pytest 9.1.1, plus jsonschema 4.26.0 and pydantic 2.13.5 where those were unpinned. I ran npm ci with --ignore-scripts; CI runs the scripts.
  • Main checkout. I added and removed worktrees with git worktree add/remove, which writes only worktree metadata. The checkout is otherwise untouched: same branch, HEAD db3c271, status clean.
  • My own worktrees. In them I restored old files with git checkout 3f89cd0 -- <paths> and made the guard mutations, reverting each after the run. I copied db3c271's test file into the f44a7d8 worktree.
  • Removed: all six of my worktrees, all venvs and /tmp/v3. I did not touch base, fix4 or memwt2.
  • No writes outside my scratchpad. GitHub was read only; I made no pushes, comments, memory records, deploys or dispatches.
  • Kept: logs and probe scripts in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy3/ (logs/, probe_*.py, sweep_dates.py).

4.7 Pass 3 dispositions (fixes in 22f711d; record in the commit that adds this section)

Each code fix has a test that fails on db3c271's code and passes on 22f711d (§3.3). The heals are this session's own and therefore non-independent; pass 4 re-checks them before the merge gate.

# Finding Disposition Issue Test
D1 change_status_v1 has no LIMIT unless the caller passes one; with failed extractions now errors, every live read without a limit would answer 502 fixed: the query always carries a LIMIT capped at 10,000 (the provider's ceiling), newest changes first. Failing closed on any failed extraction stays deliberate: planning on a partial SENSE set is the misleading-zero report in another form (a missing conversions query reads as no conversions) API-A10 (new) TestChangeStatusLimit
D2 the never-live "authorizes nothing" test passed on the old code fixed: it runs approval_required with human approval and asserts some gate authorized before asserting 0. The claims that both tests failed on the old code (API-A7, the e3bd49e message, the #1302 body, a reply on #1299) are corrected here, in the ledger, in the PR body and on the thread API-A7 TestSyntheticRunsNeverMutate
D3 "nothing persisted" was false for a partial failure fixed in code, not reworded: raw rows are saved only when every extraction in the pass succeeded API-A9 the partial-failure test
D4 a slow sweep wrote Data Manager claims that had already lapsed fixed: each claim carries the time it is made (both service sweeps pass clock=utc_now), and a read releases only its own claim API-F6 three tests (§3.3)
D5 "no credentials are mounted" on the GAQL cell was unsupported reworded to what is measured (§3.5); reading the serving revision's secret references joins API-E4 API-E4 —
D6 API-A5 marked DEPLOYED, though its fix ships nowhere corrected to NOT_APPLICABLE (deployment and runtime) API-A5 —
D7 API-G13 said 13 pins corrected to the 12 the WO-45 guard lists on 2027-01-18 (0 on 2027-01-17) API-G13 —
D8 §3's opening line contradicted §3.5 reworded — —
D9 miscounts; API-A2/A3 kept REVIEW_READY after 606fb8a touched them CLOSEOUT and RESUME count 55 implemented, 54 tested (56 and 55 once fc2a3a3 added API-A13; this row went stale then, pass 4, V5-10); pass 2 left four pass-1 rows open (findings 10, 11, 15 and 19); API-A2 and API-A3 record that pass 3 re-checked the 606fb8a edits (N6 FIXED) — —
D10 00079-ptp was built from main (e480aaa), not from cb7b7ff corrected in §3.5 from the job's own git log -1 line — —
D11 a request in flight at a sunset could be served the synthetic stream fixed: every SENSE-reading route re-checks liveness after the read API-A6 TestReadsThatCrossTheSunset
D12 the ledger-id guard's limits tightened (workstream letters A–G, a word boundary), extended to ISSUES.json's own references, seeded in both directions. A verbatim review that cites an id the ledger lacks still fails: a cited id must exist API-G15 test_the_ledger_id_guard_in_both_directions
D13 the dry-run override is not pinned on its own; the executor's client is shared per-run state ACT re-reads the lifecycle and passes the client per call; the override and the call are pinned by AST API-A7 TestActGuards
N4 residual no test pinned EMAIL_SERVICE's absence pinned API-G14 test_the_console_email_route_stays_unarmed_on_deploy
outside the range the live field lookup selected segmenting fixed: it selects category and reads a segment from it. Pass 4 (V5-1): not fixed in effect. The query still named FROM google_ads_field, which Google refuses for this service, and the test's fake accepted it. Fixed in b03f33e (§4.9) API-A11 (new) TestLiveFieldLookup, TestRealSdk
outside the range the GAQL image has no DCP client, so _govern is a no-op in production recorded for the owner, not changed: running without a DCP is the cell's documented deployment decision, and the path is latent (live mutations off; the operation builder raises). Pass 4 (V5-4): that latency rested on unpinned defaults, and the request also chooses the autonomy mode. Pinned in b03f33e (§4.9) API-A12 (new) —
"Not checked" whether conversion_segmentation_v1's cost metric works with segments.conversion_action it does not (Google's v25 field reference, §1), so the query always failed and, with API-A9, would stop every live default run. Fixed in fc2a3a3; every registered query was then checked against the reference and nothing else failed, and the check is a CI test. Found by this session, so non-independent API-A13 (new) TestRegistryAgainstTheV25FieldReference

Verifier disclosures, recorded as given (§4.6): its first governance run was discarded (the sandbox's commit signing needs a service the empty network namespace cannot reach; it re-ran with signing off through environment variables only); one mizoki_contracts import outside the namespace let google-auth look for default credentials (none found; no provider call); it installed with uv and ran npm ci --ignore-scripts. It changed no file in the main checkout and removed its worktrees and venvs.

4.8 Pass 4 — follow-up PR #1302 (db3c271..9fd5982, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. A first launch at about 22:10Z was lost to a container restart; its worktrees and venvs were removed before the relaunch, which ran 2026-10-01 from about 22:40Z to 23:15Z. Its report, verbatim:

Independent verification, pass 4 (blind): db3c271..9fd5982 (draft PR #1302)

Bottom line. I found no blocker. - Every pass-3 code item is fixed except one: the outside-range field-lookup item. The segmenting field is gone, but the lookup still sends a FROM google_ads_field clause. Google documents that clause as one that "must be omitted when querying GoogleAdsFieldService". So in live mode every lookup is still expected to fail and fall back to the static catalog. The new test pins that wrong grammar: removing FROM makes TestLiveFieldLookup fail. - The registry fixture matches Google's published v25 field reference exactly: 58 fields, 10 attributed-resource lists, 0 mismatches. With API-A13 applied, no registered query is invalid under the extra rules I checked. - Record problems: - D5 is only partly corrected: API-A7 still says "the cell has no credentials". - API-A11's "fixed" and "the validator reads live metadata" are unsupported. - API-F3 moved to REVIEW_READY although 22f711d changed its reconcile code. - The EVIDENCE §4.7 D9 row says "55 implemented, 54 tested"; the documents now say 56 and 55. - Every gate I ran is green, except docs/audits/tests. That red is environmental: it fails identically on 3d5278b because the shallow clone lacks commit 26bec9c6.

Pass-3 items

Item Verdict Evidence I produced
D1 FIXED Build: build() with limit None, 0, 1, 50, 10000, 10001 and 50000 always ends in a LIMIT between 1 and 10,000. A negative limit is unreachable: every request model has ge=1. Only the registry builds a change_status query (git grep).
Docs: Google's change-status guide says the query "must filter on a date within the past 90 days ... and must include a LIMIT clause set to at most 10,000". Google's own example is DURING LAST_14_DAYS ORDER BY ... LIMIT 10000.
Reference: the v25 reference marks last_change_date_time filterable and sortable. Every DURING literal (docs/query/date-ranges) is under 90 days.
Old code: 22f711d's tests on db3c271 answer 502 LIMIT_NOT_SPECIFIED on the Decisions route.
D2 FIXED Head's TestSyntheticRunsNeverMutate on 3f89cd0's code: 2 failed, each 28 != 0. The tests pass on db3c271. The corrected test asserts that some gate authorized before it asserts 0.
D3 FIXED (code) The partial-failure test on db3c271 fails with 9 save_raw_rows calls. run() is the only caller that persists raw rows: every main.py caller passes persist_raw=False. Residual: V5-6.
D4 FIXED Probe (12 records × 30 s reads; a second reconciler tries the 12th at the real time): at head 0 extra reads and checks 1; at db3c271 1 extra read and checks 2.
Production callers: both pass clock=rt.utc_now (main.py:452, :459); the manual refresh passes utc_now().
Same-stamp claims: impossible, because _int_env floors the lease at 1 s.
Firestore: the stamp is stored and read back as a string, and transact_update returns the dict it wrote.
Residual: V5-3.
D5 (record) PARTIAL CLOSEOUT and EVIDENCE §3.5 are reworded. API-A7's evidence, one of the places pass 3 named, still says "the cell has no credentials". API-A3's source_evidence still says "mounts no Google Ads credentials, so production serves synthetic rows".
D6 (record) ACCURATE API-A5 now reads NOT_APPLICABLE for both deployment and runtime. git grep cloud-run-google-ads-gaql outside docs/audits finds nothing; the deploy submits cloudbuild.yaml.
D7 (record) ACCURATE The WO-45 guard's _scan reports 0 pins on 2027-01-17 and 12 on 2027-01-18: 8 files, the lines API-G13 lists. api_lifecycle_check.py --as-of exits 0 on 2027-01-17 and 1 on 2027-01-18 (FAILURES (1)).
D8 (record) ACCURATE §3 no longer says nothing below is deployed, and it matches §3.5.
D9 (record) ACCURATE, one stale row CLOSEOUT and RESUME counts equal ISSUES.json (below). API-A2 and API-A3 record pass 3's N6 re-check. The §4.7 D9 row still says 55 implemented and 54 tested.
D10 (record) ACCURATE The log of job 110564512882 shows git log -1 → e480aaa952938f… at 20:16:47Z. The image is tagged :cb7b7ffc…, and the README push is e480aaa95..e7348d5c9.
D11 FIXED Routes: app.routes has 23 method/route pairs. With the connector never live and no allow_synthetic, the 8 channel routes, the MCC listing and the 3 /srpvdal POSTs answer 503. The other routes answer 200 and serve no rows.
Straddle: TestReadsThatCrossTheSunset fails on db3c271 (200 != 503). No route serves synthetic rows without allow_synthetic, and the console never passes it (git grep).
Residual: V5-5.
D12 FIXED The 22 inventory tests pass.
Caught on the real files: a dangling id in RESUME.md, and one in an ISSUES.json entry's acceptance.
Not flagged: the look-alikes API-V25, API-E2E and XAPI-A1.
D13 FIXED Both TestActGuards tests fail on db3c271. The old code requested mutate services on the retired client, and _build_operation raised. git grep finds no execute or _execute_one caller other than orchestrator.py:284, so no caller breaks. Residual: V5-12.
N4 residual FIXED (pinned) Seeding EMAIL_SERVICE=klaviyo into --set-env-vars, or into --set-secrets, fails the test. Gaps: V5-7.
Field lookup segmenting PARTIAL (in effect, not fixed) See V5-1.
GAQL image without a DCP client Record mostly ACCURATE. Disposition sound as an owner item, but its latency rests on unpinned defaults and the exposure is understated (V5-4) The lock has no mizoki_governance, and the Dockerfile copies gaql_cell/ only. cloudbuild.yaml sets GAQL_ENABLE_LIVE_MUTATIONS=false,GAQL_DRY_RUN_DEFAULT=true,GAQL_AUTONOMY_MODE=advisory.
"Not checked" → API-A13 FIXED, and the record is ACCURATE Reference: I parsed Google's v25 reference pages (metrics, segments, and the 11 resource pages). metrics.cost_per_conversion's "Selectable with" lacks both segments.conversion_action and segments.conversion_action_name; conversions, conversions_value, all_conversions and all_conversions_value include both.
Test: it fails on 5ff9bdb's registry.
Stricter rules: I also checked that each metric and segment is available with its resource in the FROM clause, that segments are compatible with each other, and that attributed resources are compatible with the selected segments. No other query fails.

Ledger at 9fd5982. 65 issues; nothing VERIFIED.

Track Counts
Implementation 56 IMPLEMENTED, 7 NOT_APPLICABLE, 2 OPEN (API-A12, API-G13)
Testing 55 TESTED, 10 NOT_APPLICABLE
Review 48 REVIEW_READY, 11 IN_PROGRESS, 2 OPEN, 4 NOT_APPLICABLE
Deployment 32 DEPLOYED, 3 IN_PROGRESS (A6, A7, B7), 13 OPEN, 17 NOT_APPLICABLE
Runtime 48 OPEN, 4 BLOCKED_EXTERNAL (E4, D6, C5, F5), 13 NOT_APPLICABLE

CLOSEOUT, RESUME and the PR body match these counts. No new or changed entry claims DEPLOYED or VERIFIED from a test.

The other changed entries are accurate against the tree: - API-A6, A9, A10, A13, F6, G13, G14 and G15. G14's wording is accurate; its pin has the gaps in V5-7. - The five moved to REVIEW_READY: A1, C6, B10, G12 match pass 3's verdicts. F3 is the exception (V5-10).

New defects

V5-1: MINOR (latent). The live field lookup is still invalid, and its test pins the invalid grammar. - Where: src/cells/google_ads_gaql/gaql_cell/connector/client.py:194-197, SELECT name, category, selectable, filterable, sortable FROM google_ads_field WHERE name = '…'. - Google's documentation: - docs/query/grammar: "FromClause … must be omitted when querying GoogleAdsFieldService". - docs/query/structure: "the FROM clause should not be specified when using GoogleAdsFieldService". - docs/query/overview: "Note that there's no FROM clause in this query". - samples/search-for-google-ads-fields: all five languages omit FROM. - google-ads 33.0.0's v25 QueryError has UNEXPECTED_FROM_CLAUSE (47): FROM clause cannot be specified in this query. - Scenario: once credentials land, every lookup is expected to fail. Each extract then makes about 14–28 failing GoogleAdsFieldService calls (twice per extract: cached and uncached validation) before falling back to the static catalog. That is exactly the state pass 3 reported. - Test: TestLiveFieldLookup's fake parses SELECT … FROM …. When I removed FROM in my own worktree, the test failed with None != {...}. TestRealSdk checks only the selected names, and it is skipped in CI because the suite-wiring job installs no SDK. - Record: API-A11 ("fixed"; "effect once live: the validator reads live metadata"), EVIDENCE §4.7, CLOSEOUT ("fixed, API-A11") and RESUME ("API-A11 fixed") are unsupported. - Impact: no regression. The static catalog matches the reference for every field the registry uses; the one difference is value_settings.default_value filterable, which no WHERE clause uses. - Fix: drop the FROM clause. Make the fake refuse a FROM clause, and assert the built query has none. Alternatively, retire the live lookup and keep the CI reference check.

V5-2: MINOR (record). The D5 correction is incomplete. - Where: ISSUES.json API-A7 verification_evidence ("the cell has no credentials"); API-A3 source_evidence ("mounts no Google Ads credentials, so production serves synthetic rows"). - Failure: a reader takes an unmeasured present-tense claim as fact. API-A7 is the exact place pass 3 named. - Fix: reword to "the deploy config sets none; the serving revision's secret references are unmeasured (API-E4)".

V5-3: MINOR (pre-existing, in the scope D4 claims). A stale overtaken Data Manager read can regress a terminal record. - Where: services/service-data-manager-connector/request_tracking.py:457-474. - Probe: a read outlives the lease. A second reconciler claims the record, reads SUCCESS and finishes. The first read then finishes with an older PROCESSING answer. The record ends as: - status processing, with needs_reconcile False, so the sweep never picks it up again; - applied True and confirmed_events 1 kept from the success; - last_checked_at moved backwards (12:06:01 → 12:01:00), next_check_at in the past, checks 2. - db3c271 behaves identically. The range releases only the claim, while its own docstring now describes the overtaken case. - Fix: when the claim was overtaken (the current claim is not this read's stamp), the record is already terminal, or last_checked_at is newer than this read's time, record the late read in history only. Never move status or last_checked_at backwards.

V5-4: MINOR. API-A12's "latent" rests on unpinned defaults, and its exposure is understated. - Unpinned: no test pins GAQL_ENABLE_LIVE_MUTATIONS=false in cloudbuild.yaml, the _flag(..., False) default (config.py:209), or _build_operation raising. git grep over the tests finds none (rule 01: fail-if-flipped). - Understated: A12 says authorization "rests on the request's own human_approved". The request also chooses autonomy_mode, and autopilot authorizes ADD_NEGATIVE_KEYWORD and ADJUST_BID with no approval at all (gates.py:122-124). - Fix: add a pin like the EMAIL_SERVICE one, and reword A12.

V5-5: NIT. The post-read check refuses all-live results after the run has persisted. - Where: main.py:153 (_require_still_live after cell.run). - Probe: all rows live, persist=True (the request default), midnight passes after the run. Result: 16 store writes (events, raw rows, decisions, snapshots, query audit, BigQuery), then 503 google_ads_not_live. The 503 hides a run that persisted and could have executed. - Fix: decide from the extractions' own provenance, or return the run_id in the 503.

V5-6: NIT. A SENSE pass that crosses the sunset persists raw rows while the run says it persisted nothing. - Probe: 3 live extractions, then the client drops. Result: 3 save_raw_rows calls, and the warning "...were not persisted, enveloped or governed". - Fix: persist raw rows in run() after the provenance check, or word the warning accurately.

V5-7: NIT. Gaps in the EMAIL_SERVICE pin. - Where: tests/governance/test_api_lifecycle_inventory.py, test_the_console_email_route_stays_unarmed_on_deploy. - Seeds:

Seed Result
gcloud ^@^ custom delimiter not caught
--env-vars-file not caught
a second --set-env-vars flag not caught
removing the unrelated --set-secrets test fails (ValueError from args.index)
  • The docstring's "absence here is absence on the revision" holds only for revisions this cloudbuild creates through those two flags.
  • Fix: parse every env/secret flag form, treat a missing flag as no keys, and handle the delimiter syntax.

V5-8: NIT. Gaps in the registry-reference test. - Seeds that pass but should fail: - a WHERE field missing from the fixture behind NOT IN, because the regex reads no NOT IN, BETWEEN or IS NULL; - campaign_budget.amount_micros with segments.device FROM campaign, which the reference disallows (attributed resource × segment is not encoded). - Minor behaviours: - if problems: continue tests the cumulative list, so after one problem the later queries skip their compatibility checks. The test still fails, but it under-reports. - Only the first ORDER BY field is checked. - A new resource or segment reports as "not selectable" rather than "regenerate the fixture". - Caught as intended: a non-selectable segment, a field missing from the fixture, an unsortable ORDER BY.

V5-9: NIT (stale references introduced by the range). - Where: - production/service-registry.yaml:1132,1137-1138 (act.py:75-80, act.py:61, act.py:92-101); - tests/remediation/test_gaql_governance_wiring.py:4; - docs/INTEGRATION_PLAN.md:371. - These were exact at db3c271. act.py now shifts them by 10 lines. - Fix: update the references in the same PR (rule 01).

V5-10: NIT (record). - API-F3 moved to REVIEW_READY although 22f711d changed its reconcile path (reconcile_record, reconcile_due). That contradicts the ledger's own review_track_note. - The EVIDENCE §4.7 D9 row is stale. - §3.5's "Not yet deployed" list omits fc2a3a3.

V5-11: NIT. Some tests build a real Google Ads client. - With google-ads installed (the image lock), 5 tests build a real GoogleAdsClient, whose construction attempts an OAuth refresh to accounts.google.com with fake credentials. Two of them are new in this range: the partial-failure test and the sunset-before-ACT test. - unshare -rn blocked the calls (NameResolutionError). - Fix: inject client_factory=_FakeClient before GAQLIntelligenceCell() builds its connector.

V5-12: NIT. The executor keeps its start-up client. - MutationExecutor._client keeps the start-up client forever, because nothing clears it now. - execute() without client= uses that client, even after the connector dropped it. No caller does this today. - Fix: make client a required keyword.

V5-13: NIT. Every Changes or Decisions page load now asks Google for up to 10,000 change_status rows. - The routes display at most 2000 changes or 100 decisions. - Fix: pass the route's limit through.

Test runs

All runs used fresh Python 3.11.15 venvs I built with uv from each job's install lines, inside unshare -rn, with proxy variables unset, TMPDIR=/tmp/v5 (governance: /tmp/v5g), and signing off through GIT_CONFIG_* environment variables.

Command Environment Result
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" suite-wiring line, MIZOKI_STORE=memory 87 passed, 4 skipped
same requirements.lock.txt + pytest (google-ads 33.0.0) 91 passed
22f711d's GAQL and DM tests on db3c271's code wiring venv GAQL 7 failed, 19 passed, 4 skipped; DM 3 failed, 46 passed
head's TestSyntheticRunsNeverMutate on 3f89cd0 wiring venv 2 failed (28 != 0)
TestRegistryAgainstTheV25FieldReference on 5ff9bdb wiring venv 1 failed, 1 passed
python -m pytest "services/service-data-manager-connector/tests" … wiring venv 49 passed
python -m pytest "docs/audits/tests" … wiring venv 1 failed (test_wo31_register: commit 26bec9c6 absent), 7 passed; identical on 3d5278b
pytest tests/governance -c tests/governance/pytest.ini -p no:cacheprovider ci.yaml lint-and-test line + -e contracts + docs/whitepapers/requirements.txt 4350 passed, 7 skipped, 0 failed, 6227 subtests
bash .github/scripts/content_gates.sh governance-gates install line first on PATH rc 0, 155 passed
tests/governance/test_api_lifecycle_inventory.py ci venv 22 passed, plus the seeds above
tests/remediation/test_gaql_governance_wiring.py wiring venv 5 passed
python3 scripts/api_lifecycle_check.py gates venv rc 0, FAILURES (0), WARNINGS (1)
python3 scripts/gate_leak_scan.py --check gates venv rc 0: 0 new, 0 grown, 0 stale
python3 scripts/claude_memory.py check --strict gates venv rc 0
python3 .github/scripts/deploy_router.py --base 3f89cd0 --head 9fd5982 gates venv 18 files → deploy-google-ads-gaql.yml (8), deploy-ui.yml (1), frontend-guard.yml (1)
PR #1302 check-runs on 9fd5982 (gh api, read-only) GitHub all success (one skipped); mergeable_state clean against fa1cc19

Not checked

  • Live provider behaviour. V5-1 rests on Google's documentation and the SDK's error enum, not a live call.
  • The serving revisions' env and secret mounts (no GCP access).
  • The console vitest, tsc, lint and Playwright suites. GitHub reports them green.
  • The other ci.yaml jobs.
  • CI's exact git and Python versions.
  • Gates on the real merge result with fa1cc19. I ran no local merge-tree, to avoid writing objects into the main repository.
  • Whether Next.js would load an EMAIL_SERVICE placed in .env.production.

Disclosures

  • Main checkout: untouched. Branch work/mizoki-api-compatibility-3ae54n, HEAD 9fd5982, status clean. git worktree add/remove wrote only worktree metadata.
  • Cleanup: I removed all 7 of my worktrees, all 4 venvs, /tmp/v5 and /tmp/v5g. I did not touch base, fix5 or memwt2. I did not read the builder's scratchpad files.
  • Network:
  • Google documentation pages fetched read-only with curl, plus one WebSearch.
  • GitHub reads only: PR metadata, comments, job logs, check-runs.
  • No provider call left the host: the 5 OAuth refresh attempts in the lock run were blocked by the namespace.
  • No pushes, comments, records, deploys or dispatches.
  • Deviations from CI: uv instead of pip (pytest resolved to 9.1.1), and -p no:cacheprovider on the governance run.
  • Mutations: my seeds and old-code copies were made only in my own worktrees and reverted.
  • Kept:
  • logs, probes, the parsed reference, and REPORT.partial.md in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy5/;
  • the fetched pages and parsers in docs/ there, with docs/compare.py doing the fixture-vs-reference comparison.

4.9 Pass 4 dispositions (fixes in b03f33e; record in the commit that adds this section)

How each fix is verified (§3.3): - A test that fails on 9fd5982's code: V5-1, V5-3 (two tests), V5-5, V5-6, V5-12 (its pin, added in 9d76b52) and V5-13. - Pins that fail when flipped: V5-4. - Self-seeded tests: V5-7 and V5-8 check other checks, so their tests seed both directions. Pass 4 measured the old checks missing those seeds. - Read, not tested: V5-9's new line references. - Measured by a DNS-lookup audit: V5-11. - Record items: V5-2 and V5-10.

This list's first wording, in b34358c, said every code fix had a test that fails on 9fd5982's code. V5-9, V5-11 and V5-12 had none then.

The heals are this session's own and therefore non-independent; pass 5 re-checks them before the merge gate.

Pass 4's verdicts on the pass-3 items stand as reported (§4.8). The two it did not close are D5, corrected further under V5-2, and the field lookup, fixed under V5-1.

# Finding Disposition Issue Test
V5-1 the live field lookup still sent FROM google_ads_field, and its test pinned that grammar fixed: the query has no FROM, the fake refuses one, and the test asserts that none is sent. API-A11's "fixed" and "the validator reads live metadata" are marked superseded. Whether the validator reads live metadata once live is now expected, not verified (no live account) API-A11 TestLiveFieldLookup
V5-2 the D5 correction missed API-A7 and API-A3 ("no credentials") corrected: each line is kept, marked superseded, and followed by the measured wording (the deploy config sets none; the serving revision's secret references are unmeasured, API-E4). Pass 5: content accurate, but the markers said "next line" where the correction is further down; the markers now name the line they mean (§4.11) API-A3, API-A7 —
V5-3 a stale read whose claim was overtaken regressed a record that a newer read had settled fixed: a read whose record is already terminal, or was read later than this read's time, is counted and noted in history. It is never applied and not audited twice. No status, last_checked_at or schedule moves backwards. Pass 5 (N1): partial. A read that straddled a re-send was still applied, to the new attempt. Fixed in c7d8904 (§4.11) API-F6 the two late-read tests
V5-4 API-A12's "latent" rested on unpinned defaults; the request also chooses autonomy_mode, and autopilot authorizes two action types with no approval pinned: the deploy's GAQL_ENABLE_LIVE_MUTATIONS=false, GAQL_DRY_RUN_DEFAULT=true and GAQL_AUTONOMY_MODE=advisory (a merging env flag fails too), the code defaults, and the operation builder's refusal. A12's title and evidence say autonomy mode and approval. The owner decision stands API-A12 TestLiveMutationsStayOff (3)
V5-5 the post-read check refused a run whose rows were all live, after it had persisted fixed: the run routes decide from the run's own provenance, taken right after its reads, and a 503 names the run. An MCC run takes its provenance after the listing; a synthetic child marks the result. The routes without a run keep the post-read check: they persist nothing API-A6 test_a_sunset_after_the_reads_does_not_refuse_a_live_run
V5-6 a SENSE pass that crossed the sunset saved the raw rows of its live extractions fixed: run() saves raw rows only after it knows the pass was live and complete API-A9 test_a_sense_pass_that_crosses_the_sunset_persists_nothing
V5-7 the EMAIL_SERVICE pin missed the delimiter syntax, --env-vars-file, a repeated flag, and broke on a missing --set-secrets fixed: every env and secret flag is read (repeated, --flag=value, ^DELIM^); a merging flag or an env file fails closed; a missing flag sets nothing API-G14 test_the_email_route_pin_in_both_directions
V5-8 gaps in the registry-reference test fixed: every WHERE operator (including NOT IN, BETWEEN, IS NULL) and every ORDER BY field; each query checked on its own; a resource missing from the fixture is named. Not encoded: segments against an attributed resource's fields, because the reference does not settle it. Neither segments.date's list nor the ad_group_criterion page names the other. Yet Google's Query Cookbook keyword query selects ad_group_criterion fields and five metrics FROM keyword_view with segments.date in its WHERE clause. And v25's PROHIBITED_SEGMENT_IN_SELECT_OR_WHERE_CLAUSE (51) describes a segment incompatible with "the main resource or other selected segmenting resources", naming no attributed resource. Read strictly, the rule fails one registered query, keyword_performance_v1, which selects segments.date with ad_group_criterion fields. Pass 4 reports that no other query fails its stricter checks, yet its kept script (eval_registry.py, re-run here) flags that query on this reading, for segments.date and for every metric. The metric half is contradicted by the Cookbook query above. The disagreement is left for pass 5, not settled here. Whether Google accepts the query is unverified until the first authorized live read (CLOSEOUT, API-D6). b03f33e's test docstring said Google's example selects the date; 9e433b7 corrects it. Pass 5 (N3): partial. The each-query property was unpinned, and pass 4's seed 2 was uncaught. Fixed in c7d8904, which also encodes the rule for attributed resources whose lists the fixture holds (§4.11) API-A13 test_the_check_catches_what_it_encodes
V5-9 stale act.py line references moved with the code (80-85, 66, 97-106) API-A7 tests/remediation/test_gaql_governance_wiring.py
V5-10 API-F3 moved to REVIEW_READY although 22f711d changed its path; the §4.7 D9 row; §3.5's list API-F3 back to IN_PROGRESS until pass 5 (b03f33e changes reconcile_record again); the D9 row and §3.5 annotated API-F3 —
V5-11 five tests built a real GoogleAdsClient with fake credentials fixed: the test cells are built before credentials are set. Measured with a DNS-lookup audit of the image-lock suite (unshare -rn, proxy variables unset): 5 accounts.google.com lookups on 9fd5982's tree, none on b03f33e's. Both trees also probe the metadata server (120 and 126 lookups): the BigQuery and Firestore stores looking for default credentials, as before this PR API-A7 —
V5-12 the executor kept its start-up client, used when no client was passed fixed: the executor holds no client; without one passed for the call, every action is simulated. Pinned in 9d76b52: no constructor, client defaults to None, and execute() with live mutations on and dry_run=False but no client only simulates. Until 9d76b52 this row named TestActGuards, which passes on both trees API-A7 test_the_executor_holds_no_client_of_its_own
V5-13 every Changes or Decisions load asked Google for up to 10,000 change_status rows Changes passes its own limit. Decisions keeps the cap: its limit counts decisions, and a run's row limit applies to every query the plan reads, so passing it would change the plan. That is one bounded search per run API-A10 test_the_changes_route_sends_its_own_limit

Verifier disclosures, recorded as given (§4.8): it installed with uv (pytest 9.1.1) and ran the governance suite with -p no:cacheprovider; it turned commit signing off for its test processes through environment variables only; five OAuth refresh attempts in its image-lock run were blocked by the empty network namespace (V5-11); it fetched Google's documentation pages read-only and made GitHub reads only. It changed no file in the main checkout and removed its worktrees and venvs.

4.10 Pass 5 — follow-up PR #1302 (9fd5982..2ee03e0, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 00:01Z to 00:43Z. Its report, verbatim:

Independent verification, pass 5 (blind): 9fd5982..2ee03e0 (draft PR #1302)

Bottom line. I found no blocker. - Code items. 11 of the 13 V5 code items, the field lookup and D5 hold. V5-3 and V5-8 are PARTIAL. - The new defects. One MINOR, N1: a Data Manager status read can finish after the upload was re-sent, and it is then applied to the new attempt. Pass 4 recommended three conditions for treating a read as late, and the fix encodes two of them. The rest are NITs. - Builder's claims I re-measured: each one reproduced. - 7 tests fail on 9fd5982's code. - Each of the 10 seeded flips fails exactly one test. - The DNS audit finds 5 accounts.google.com lookups on the old tree and 0 on the new one. - Gates: all green except docs/audits/tests. That suite fails identically on 3d5278b, because this shallow clone lacks commit 26bec9c6. - The disagreement: by Google's published documentation, keyword_performance_v1 is expected to be valid, but that cannot be verified offline. The builder's statement of the evidence is accurate, with two omissions.

Pass-4 items

Item Verdict Evidence I produced
V5-1 FIXED Query: client.py:193-194 builds SELECT name, category, selectable, filterable, sortable WHERE name = '…'.
Grammar: Google's grammar page is Query -> SelectClause FromClause? WhereClause? … and says "FromClause … must be omitted when querying GoogleAdsFieldService". The five-language sample omits FROM and uses WHERE name LIKE.
SDK: google-ads 33.0.0 accepts search_google_ads_fields(request=None, *, query=None, …), and its category enum has SEGMENT.
Old code: head's test on 9fd5982's code fails with None != {...}.
Fake fidelity (NIT): the fake checks only FROM and the SELECT list. With AND not_a_field = 1 appended to the query, TestLiveFieldLookup still passes.
V5-2 (record) Content ACCURATE, pointers INACCURATE Content: the corrections match cloudbuild.yaml, which passes no --set-secrets or --clear-secrets.
Pointers: API-A3 source_evidence[0] and API-A7 verification_evidence[5] say "SUPERSEDED … next line", but the corrections are [2] and [9]. So §4.9's "followed by the measured wording" is not literally true.
V5-3 PARTIAL Fixed: the reported interleaving.
- Probe A at head: success, checks 2, last_checked_at 12:06:01, needs_reconcile False, one success audit.
- On 9fd5982 the same probe ends in processing.
- Both new tests fail on 9fd5982.
Missing: pass 4's first condition ("the current claim is not this read's stamp"). See N1.
V5-4 FIXED Pins: the three TestLiveMutationsStayOff tests each fail on their own flips; see the runs table.
A12: the title now names autonomy_mode. gates.py:39 sets _LOW_RISK_ACTIONS = {ADD_NEGATIVE_KEYWORD, ADJUST_BID}, and _authorize authorizes them on AUTOPILOT.
gcloud: --set-env-vars uses UpdateAction, which raises on a duplicate key, and it is mutually exclusive with --update-env-vars and --env-vars-file. So a second flag in the same call cannot flip a pinned key.
V5-5 FIXED Routes: the app has 27 method/route pairs; 12 of them read SENSE.
- All live: every route 200.
- Sunset inside the first read: all 12 answer 503 with 0 writes.
- Sunset after the first read: the multi-read routes (run, run-mcc, sense, decisions) answer 503 with 0 writes; single-read routes answer 200, because their one read was live.
Old code: head's test fails on it (503 != 200).
When provenance is taken: in run(), right after the last SENSE read (orchestrator.py:180), before any write (:207, :311). In MCC, after the listing (:509), and re-marked after each child's run. Residual: N5.
V5-6 FIXED Old code: saves raw rows 3 times (['save_raw_rows']*3 != []).
Head: raw rows are saved only at orchestrator.py:207-209, after both the error check and the provenance check.
Callers: no caller passes persist_raw=True, and the routes persist nothing.
V5-7 FIXED (as scoped) Forms read: repeated flags, --flag=value, ^DELIM^; a missing flag sets nothing.
Fails closed on: --update-* and --env-vars-file.
Checks: the seeded test passes; the real console cloudbuild.yaml gives no false positive; seeding EMAIL_SERVICE=klaviyo fails exactly that one test.
New gaps: N4.
V5-8 PARTIAL Pinned: every WHERE operator and every ORDER BY field (the old regex, or reading only the first field, fails the assertions). A resource missing from the fixture is named.
Not pinned: "each query is checked on its own". The pre-V5-8 cumulative check leaves all 3 tests green (N3).
Uncaught: pass 4's seed 2 (campaign_budget with segments.device) still returns [].
V5-9 FIXED Lines: act.py:80-85, :66 and :97-106 hold the same statements as db3c271's 75-80, 61 and 92-101.
Observation: # MIZ OKI 3.5/site_docs_internal/INTEGRATION_PLAN.html:607 still says 75-80. deploy-homepage.yml rebuilds that mirror at deploy.
V5-10 (record) ACCURATE API-F3's review was REVIEW_READY at 5ff9bdb and is IN_PROGRESS at b34358c. 22f711d changed request_tracking.py. The D9 row and the §3.5 list are annotated.
V5-11 FIXED DNS audit (lock venv, unshare -rn):
- 9fd5982: 91 passed; 5 accounts.google.com and 120 169.254.169.254 lookups.
- 2ee03e0: 99 passed; 0 and 126.
Record wording: N7.
V5-12 FIXED Executor: no __init__; client defaults to None.
Caller: the only caller (orchestrator.py:298-299) passes the client right after refresh_version_status(). A dropped client is None, so the action is simulated (act.py:66).
Old code: the pin fails ('__init__' unexpectedly found). Its behavioural half alone passes on the old code too.
V5-13 FIXED Changes route: passes its own limit (le=2000); the registry caps any LIMIT at 10,000 (gaql_registry.py:44-47). On 9fd5982 the route sent LIMIT 10000.
Decisions route: keeps the cap. The builder's reason is sound: the route's limit slices decisions after the run, while run(limit=) would change every query's LIMIT.
D5 (record) ACCURATE (with the V5-2 pointer defect) Every GAQL "no credentials" line is now marked superseded and corrected. The remaining "mounts no ad credentials" lines are Boss's, measured separately.
Field lookup FIXED As V5-1.

The disagreement (keyword_performance_v1)

Verdict: expected valid, not verifiable offline. The CLOSEOUT's planned first live call to /srpvdal/sense is the right first measurement. The docs I fetched were last updated 2026-09-30.

What Google publishes in favour of the query: - keyword_view's v25 page marks segments.date "Yes, it is", meaning usable when keyword_view is in the FROM clause. - That page lists ad_group_criterion as an attributed resource: "Fields from the above resources may be selected along with this resource in your SELECT and WHERE clauses. These fields will not segment metrics". - The criteria-metrics guide tells clients to select ad_group_criterion fields with the *_view resources.

The text that supports the strict reading, and why it cannot be evaluated: - The field-service concept page says: "If you select fields from a resource that is not in the FROM clause, that resource's selectableWith list must include all other segments and resources present in your SELECT clause." - ad_group_criterion's resource-level selectableWith is not published. Its v25 page has only an Attributed-resources table: no Segments or Metrics tables and no "Selectable with" row. So that rule cannot be checked offline.

Why the omission from the published lists is not evidence of incompatibility: - segments.date's 545-entry list omits ad_group_criterion, campaign_criterion and accessible_bidding_strategy. - metrics.clicks and metrics.impressions omit ad_group_criterion and accessible_bidding_strategy the same way. They name campaign, campaign_budget, ad_group, customer and bidding_strategy. - Google's Cookbook query selects 5 metrics with ad_group_criterion fields FROM keyword_view, and the metric lists omit ad_group_criterion too.

The SDK carries no field catalog. The QueryError 51 text the builder quotes is exact. Codes 48 and 65 also exist; 65 is "A metric may not be selected with one of the selected resource fields…".

The builder's statement is accurate. I copied pass 4's kept eval_registry.py into my own folder and ran it on 2ee03e0 and on 9fd5982. It flags exactly segments.date and the 5 metrics of keyword_performance_v1, and every other query is OK. Two omissions: - the concept page's rule above; - pass 4's own kept notes (vfy5/REPORT.partial.md, line 10) dismissed that flag as "a parser artefact: that page has no segment/metric tables". So pass 4's "no other query fails" was a judgement, not an oversight.

New defects

N1 — MINOR. A late status read that straddles a re-send is applied to the new attempt. - Where: services/service-data-manager-connector/request_tracking.py:458-491; the guard is at :467. - Scenario (probe E): 1. R1 claims the record for req-1 at 12:01:00, and its read stalls past the 300 s lease. 2. R2 claims at 12:06:01, reads FAILED, and the record becomes a failure. 3. The caller re-sends: begin_submission allows a FAILED record to be re-sent, and the record is accepted again as req-2 (attempt 2). 4. R1 then finishes with req-1's FAILED answer. - Result at head: - status failure, request_id req-2, attempt 2; - needs_reconcile False; - last_checked_at 12:01:00, earlier than attempt 2's submission at 12:06:06; - a second conversions.request.failure audit. - Consequence: req-2 is never read, and a third re-send is allowed. The same happens on 9fd5982. It is pre-existing, but inside V5-3's scope. - Record: it contradicts API-F6 ("not applied"), §4.9 V5-3 ("no status … moves backwards") and the CLOSEOUT Data Manager row ("a late read never undoes a newer one"). - Fix: treat current.get("check_claimed_at") != stamp, or a changed request_id/attempt, as a late read (note it, never apply it). Add a re-send test.

N2 — NIT. A late read that carries the final answer is dropped. - Where: request_tracking.py:467-479. - Scenario (probe C3): the overtaking read answers PROCESSING and spends the last check, so the record becomes unknown/status_expired with needs_reconcile False. The late read carried SUCCESS; it is discarded, and the history note records the current status, not the late answer. - Effect: the sweep never reads the record again; only a manual refresh recovers it. 9fd5982 applied the SUCCESS. With checks left (probe C2), the next sweep heals it. - Fix: put the late read's mapped status in the history note. Optionally, let a late terminal answer settle an unknown/status_expired record.

N3 — NIT. Gaps in the registry-reference test. - Where: src/cells/google_ads_gaql/tests/test_api_compat_binding.py:524-560 and :589-618. - Gaps: - The "each query is checked on its own" property is unpinned (the cumulative-check seed stays green). - Pass 4's campaign_budget × segments.device seed is uncaught. The fixture already distinguishes it: segments.device's list omits campaign_budget and segments.date's includes it. ad_group_criterion is outside the fixture's resource universe, so this rule fails nothing registered. - Segment-to-segment compatibility is neither encoded nor listed as "not encoded". - Fix: - Place a compatibility seed after a missing-name seed, and assert both are reported. - Encode the attributed-resource rule for attributed resources that are themselves FROM resources in the fixture.

N4 — NIT. Forms the EMAIL_SERVICE pin does not read. - Where: tests/governance/test_api_lifecycle_inventory.py:188-239. - Seeds that pass the test: - the _LIFT_ENGINE_URL default in the file's own substitutions: block set to "…run.app,EMAIL_SERVICE=klaviyo". Cloud Build expands it inside the --set-env-vars value, and gcloud splits on the comma. - --flags-file=… added to the deploy args. - By reading: only the deploy-to-cloud-run step is read. The GAQL pin's --set-env-vars=(\S+) regex also misses the space form in a separate gcloud step. So the docstring's "Arming the route means editing this test" overstates. - Fix: expand ${_X} from the file's own substitutions (fail closed if a value contains , or =), refuse --flags-file, and scan every step.

N5 — NIT. An MCC run with a synthetic child hides a persisted live child. - Where: orchestrator.py:536-537 and main.py:174-175. - Probe: child 1 live, then a sunset before child 2's SENSE. Child 1 makes 17 store writes, then the route answers 503. - Gap: the 503 detail has only the MCC run_id, which is never persisted, and no child run ids. - Fix: put per_account (run ids, ok flags) in the 503 detail.

N6 — NIT (record). The PR body is stale. - PR #1302 at 2ee03e0: - the title still says "review passes 2–3"; - the commit list stops at 9fd5982; - it says the merge gate waits for pass 4; - its gate table is for 9fd5982; - its field-lookup row says only "It now reads category". - Elsewhere: - EVIDENCE §3.2 says the record-commit gates are recorded in the PR body; at 2ee03e0 they are not. - CLOSEOUT's release-package row says "pass 5 reports no open blocker" in the present tense, before pass 5 reported.

N7 — NIT (record). Five ledger lines and the review note. - API-A7 [10]: "no test builds a real GoogleAdsClient" is false. TestRealSdk builds real ones with a stubbed credential factory. What was measured is that no test looks up accounts.google.com. - API-A12: says the flips were seeded "on 9fd5982's tree", while EVIDENCE §3.3 says b03f33e. The pin tests do not exist on 9fd5982. - API-A13: says the check is "seeded in both directions", which includes the unpinned each-query property (N3). - API-A11 [2]: "unsupported until b03f33e" implies the claim is supported after it. - review_track_note: its IN_PROGRESS definition covers G13 and G15, which b34358c changed but which are REVIEW_READY. Their new lines do match pass 4's report.

Ledger at 2ee03e0

65 issues; nothing is VERIFIED.

Track Counts
Implementation 56 IMPLEMENTED (55 TESTED; API-G17 is the only untested one), 7 NOT_APPLICABLE, 2 OPEN (API-G13, API-A12)
Review 48 REVIEW_READY, 11 IN_PROGRESS (A3, A6, A7, A9, A10, A11, A12, A13, F3, F6, G14), 2 OPEN, 4 NOT_APPLICABLE
Deployment 32 DEPLOYED, 3 IN_PROGRESS (A6, A7, B7), 13 OPEN, 17 NOT_APPLICABLE
Runtime 48 OPEN, 4 BLOCKED_EXTERNAL, 13 NOT_APPLICABLE

CLOSEOUT and RESUME match these counts. No changed entry claims DEPLOYED or VERIFIED from a test.

Data Manager interleavings (probes on head)

Columns: status, checks, last_checked_at, needs_reconcile, audit. The claim is released only by its own read in every case.

Interleaving Result
Two reconcilers: a late PROCESSING after a newer SUCCESS success, 2, 12:06:01, False, one success audit
Manual refresh inside the lease refused; the sweep's claim is kept
Manual refresh after the lease same as two reconcilers
Late newer answer, checks left (C2) processing, then the next sweep settles success
Late newer answer after the overtaking read spent the last check (C3) status_expired, SUCCESS lost (N2)
Firestore-style retry (attempt 1 stale, attempt 2 late) applied cleared; nothing applied; no audit
Re-send between the claim and the late read (E) N1

Nothing reconciles forever: late reads add to checks, and the next applied read checks the expiry. The comparison orders reads by claim time, never equal ones (the lease is at least 1 s). A late read that carries a newer answer is therefore treated as older (C2, C3).

Test runs

Common environment: fresh pip venvs on CPython 3.11.15 (pytest 9.1.1) built from the CI install lines, run under unshare -rn, proxy variables unset, short TMPDIR.

Command Environment Result
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" @2ee03e0 suite-wiring venv, MIZOKI_STORE=memory 95 passed, 4 skipped
same image-lock venv (google-ads 33.0.0) 99 passed
GAQL suite with a getaddrinfo audit lock venv, @9fd5982 / @2ee03e0 91 passed, 5 accounts.google.com lookups / 99 passed, 0
services/service-data-manager-connector/tests wiring venv 51 passed
Head's two test files on 9fd5982's code wiring venv GAQL file 5 failed / 31 passed / 4 skipped; Data Manager suite 2 failed / 49 passed
tests/remediation/test_gaql_governance_wiring.py wiring venv 5 passed
docs/audits/tests @2ee03e0 and @3d5278b wiring venv 1 failed (test_wo31_register, commit 26bec9c6 absent), 7 passed, identical on both
pytest tests/governance -c tests/governance/pytest.ini -p no:cacheprovider ci venv (+ -e contracts, whitepapers), signing off through GIT_CONFIG_* 4351 passed, 7 skipped, 6227 subtests, 0 failed
bash .github/scripts/content_gates.sh governance-gates venv first on PATH rc 0, 155 passed
api_lifecycle_check.py / gate_leak_scan.py --check / claude_memory.py check --strict gates venv rc 0 each (FAILURES 0, WARNINGS 1 / 0 new, 0 grown, 0 stale / valid)
deploy_router.py --base 3f89cd0 --head 2ee03e0 gates venv 21 files → deploy-google-ads-gaql.yml (8), deploy-ui.yml (1), frontend-guard.yml (1)
10 seeded flips: the GAQL suite plus the inventory test file flip worktree @2ee03e0 each flip fails exactly 1 test
Seeds the checks miss: cumulative check, bogus WHERE, substitution default, --flags-file as above all pass, so each check misses its seed
PR #1302 check-runs (gh api, read-only) GitHub 28: 26 success, 1 skipped, 1 in progress (CodeQL)

The 10 flips were each of the deploy's three values, an added --update-env-vars, each of the three code defaults, an operation builder that returns, cost_per_conversion back in conversion_segmentation_v1, and EMAIL_SERVICE in the console's env map.

Not checked

  • Live provider behaviour.
  • Whether Cloud Run accepts a secret-sourced env var with the same name as a literal one.
  • The serving revisions' env and secret mounts.
  • The console vitest, tsc, lint and Playwright suites, and the other ci.yaml jobs.
  • Gates on the merge result with fa1cc19.
  • Whether §4.8 quotes pass 4 verbatim: I had only pass 4's partial notes, not its original report.
  • CI's git version.

Disclosures

  • Main checkout: I only read it, with GIT_OPTIONAL_LOCKS=0, and ran worktree add/remove there. During my run another session moved its branch from b34358c to 2ee03e0, and c3wt disappeared from the worktree list; neither was me. Its status was clean at the end.
  • Cleanup: I removed all 6 of my worktrees, all 4 venvs and /tmp/v6*. I did not touch base, memwt2 or c3wt. Outside vfy6/ I read only pass 4's vfy5/ files.
  • Kept, in vfy6/: REPORT.partial.md, logs/, probes/, the fetched docs, and p4docs/ (copies of pass 4's scripts and its parsed reference).
  • Network:
  • Google documentation pages fetched read-only with curl.
  • PyPI installs.
  • GitHub REST reads only. One gh pr view hit the GraphQL 403 (a read).
  • No provider call: the DNS audit refused every non-loopback lookup.
  • Deviations from CI: pip in plain python3.11 -m venv venvs, not setup-python; -p no:cacheprovider on the governance run; commit signing turned off through GIT_CONFIG_* environment variables only.
  • No writes: no pushes, comments, records, deploys or dispatches.

4.11 Pass 5 dispositions (fixes in c7d8904; record in the commit that adds this section)

How each fix is verified (§3.3): - A test that fails on 2ee03e0's code: N1, N2, N5. - Seeds that fail when the rule is removed: N3. For N4, seeds on the real deploy files fail. - Record items: N6, N7 and the V5-2 markers.

The heals are this session's own and therefore non-independent; pass 6 re-checks them before the merge gate. Pass 5's verdicts on the pass-4 items stand as reported (§4.10); its two PARTIALs are N1 (V5-3) and N3 (V5-8).

# Finding Disposition Issue Test
N1 (MINOR) a late read that straddled a re-send was applied to the new attempt fixed: a read is late, noted but never applied, if its claim was taken over, if the record tracks another request or attempt, or if a newer read settled or advanced the record (pass 4 named all three conditions; b03f33e encoded two). A read of another attempt does not spend the new attempt's checks API-F6 test_a_late_read_is_never_applied_to_a_re_sent_record
N2 a late read that carried the final answer left no trace the late read's note records its own answer. It is still not applied: a manual refresh re-reads the record. Letting a late final answer settle an expired record was considered and not done, so that "a late read is never applied" stays one rule API-F6 test_a_late_read_notes_what_it_answered
N3 registry-check gaps fixed. Segment-to-segment compatibility is checked. A selected segment is checked against an attributed resource's fields where the fixture holds that resource's lists (a FROM resource of the registry); that is the rule Google's field-service guide states, which pass 5 quoted. The seed order pins that each query is checked on its own, and pass 4's seed 2 is caught. Still not encoded: an attributed resource whose lists Google does not publish (ad_group_criterion). Pass 6 (D5): that list was incomplete, and the metric half of the rule was not encoded either. 85b7ecb encodes the metric half; the docstring lists what stays unencoded (§4.13) API-A13 test_the_check_catches_what_it_encodes
N4 forms the deploy pins did not read fixed. The console pin fails closed on: EMAIL_SERVICE named anywhere in the file (as a whole name, so EMAIL_SERVICE_URL stays legal); --flags-file; a substitution default that could carry env pairs; and a submit-time substitution other than the image tag. It scans every step. The GAQL pin wants one env flag in any form and each pinned name once in the whole file, and refuses --flags-file. Out of reach: a Cloud Run setting changed by hand, which the next deploy replaces. The docstring says so. Pass 6 (N4 partial, D1, D7): "a submit-time substitution other than the image tag" was false for a pair written after ${{ github.sha }}. The console pin read neither deploy-all.yml, which submits the same build, nor the console's Dockerfile, and the GAQL pin did not read its workflow. Fixed in 9d9cd01 (§4.13) API-G14, API-A12 test_the_email_route_pin_in_both_directions, test_the_console_email_route_stays_unarmed_on_deploy, test_the_deploy_keeps_live_mutations_off
N5 an MCC run refused for a synthetic child hid a live child that may have persisted fixed: the 503 names every child run (customer, ok, run id, synthetic); per_account entries gain an additive synthetic flag. Pass 6 (D6): only the children that ran carry it; a skipped or raised child shows null (§4.13) API-A6 test_an_mcc_run_refused_for_a_synthetic_child_names_its_child_runs
N6 (record) the PR body was stale; §3.2's pointer; CLOSEOUT's tense the PR body was updated at 2ee03e0's push, after pass 5 read it. The CLOSEOUT release-package row no longer speaks for a pass before it reports. Pass 6 (D2): it still did; corrected (§4.13) — —
N7 (record) five ledger lines and the review note corrected: API-A7 now records what was measured (no accounts.google.com lookup; TestRealSdk builds real clients with a stubbed credential factory); API-A12 records that the flips were seeded on b03f33e; API-A13 records the seeds; API-A11's marker no longer implies the claim became supported; the review note says that recording a blind pass's verdict is not a change API-A7, API-A11, API-A12, API-A13 —
V5-1 (pass 5's note) the field-lookup fake checked only FROM and the SELECT list the fake refuses any WHERE but the name filter; a seeded bogus WHERE term fails the test API-A11 TestLiveFieldLookup
V5-9 (pass 5's observation) the internal site mirror INTEGRATION_PLAN.html:607 still says 75-80 not changed: it is a generated mirror in the owner-dispatched website tree, rebuilt at deploy by deploy-homepage.yml — —
the disagreement keyword_performance_v1 pass 5: expected valid, not verifiable offline, and the builder's statement accurate with two omissions. Both are now recorded here: the field-service guide's rule (above, N3), and pass 4's own note setting its flag aside as a parser artefact. The first authorized live read settles it (CLOSEOUT, API-D6) API-A13 —

Verifier disclosures, recorded as given (§4.10): - Environment: it built plain python3.11 -m venv venvs with pip, ran the governance suite with -p no:cacheprovider, and turned commit signing off through GIT_CONFIG_* environment variables only. - Network: it fetched Google's documentation pages read-only and made GitHub reads only (one gh pr view hit the GraphQL 403). - Observed during its run: the branch moving from b34358c to 2ee03e0, and the c3wt worktree disappearing. Both were this session's: the fast-forward and its scratch worktree. - Footprint: it changed no file in the main checkout and removed its worktrees and venvs.

4.12 Pass 6 — follow-up PR #1302 (2ee03e0..701f67c, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 01:13Z to 01:52Z. Its report, verbatim:

Independent verification, pass 6 (blind): 2ee03e0..701f67c (draft PR #1302)

Bottom line. I found no blocker and no MAJOR.

  • Code fixes: N1, N2, N3 and N5 are FIXED.
  • On 2ee03e0's code with c7d8904's three test files, exactly 3 tests fail, the 3 the builder named. Reproduced.
  • Each N3 seed fails when its rule is removed. The V5-1 seed (a bogus WHERE term) fails TestLiveFieldLookup. The four seeded deploy files each fail exactly the pin that guards them.
  • N4 is PARTIAL. The forms pass 5 named are now caught. Two problems remain:
  • The record claims the console pin refuses "a submit-time substitution in deploy-ui.yml other than _IMAGE_TAG". That is false for a pair written after ${{ github.sha }}.
  • The pin still misses several in-repo ways to arm the route, so the docstring and API-G14 overstate it.
  • N6 is PARTIAL. The PR body is now current. But CLOSEOUT.md:273 still says pass 6 "reports no open blocker", while §4.11 says that row no longer speaks for a pass before it reports.
  • The rest of the record is ACCURATE: the V5-2 markers, N7, the counts, and API-A9/A10 moving to REVIEW_READY. No changed line calls anything deployed or verified beyond the evidence.
  • New defects: 7, all NIT. One is in code: a late Data Manager read can now raise on a malformed status body.
  • Gates: all green in fresh venvs, except docs/audits/tests::test_wo31_register. It fails identically on 3d5278b, because commit 26bec9c6 is not in this clone.

Pass-5 items

Item Verdict Evidence I produced
N1 FIXED Old code: the new re-send test fails there (status failure != submitted).
Probe P6: R2 fails the record, it is re-sent as req-2, and R3 claims attempt 2; then R1 returns. Head keeps R3's claim, checks stay 0, and the note says "re-sent as attempt 2". 2ee03e0 applied the failure to attempt 2.
A read that should apply still applies: a sweep read, a manual refresh, a lapsed claim nobody took over, and a legacy record without attempt, check_claimed_at or checks.
Firestore-style retry, stale snapshot first then the real one: applied once, one audit. Reverse order: not applied, no audit.
History: stays at 20 entries; the note is at most about 311 characters; history is not in public_view.
N2 FIXED; disposition SOUND Old code: the new test fails there (no "answered success" in the note).
Probe with MAX_CHECKS=1: the late SUCCESS is dropped and the record ends unknown/status_expired. The sweep scans 0 records. The note says "answered success". A manual refresh then sets success with applied true.
N3 FIXED Seeds: removing the segment-to-segment rule, removing the attributed rule, or restoring the cumulative skip each fails test_the_check_catches_what_it_encodes, and nothing else.
Pass 4's seed 2 is caught.
Against Google's pages: I fetched the v25 pages for all 10 registry FROM resources. Each page's list matches the fixture's segment and metric lists: 0 mismatches. campaign_budget's page does not list segments.device. So the rule as coded agrees with the field-service guide's rule for these resources.
N4 PARTIAL Caught: a substitution default carrying EMAIL_SERVICE; --flags-file in a step; a plain shell step that names it; in the GAQL deploy, a second space-form flag and --flags-file.
Not caught: see D1.
N5 FIXED Old code: the test fails there (KeyError: 'per_account').
Probe with 5 child states:
- live: run id, synthetic: false;
- skipped: run_id null, synthetic null;
- run raised: run_id null, synthetic null, and the exception text is not in the 503;
- failed extraction: run id, synthetic: false;
- after the sunset: ok: true, synthetic: true.
The additive flag: no reader of per_account exists outside tests, and the schema is List[Dict].
N6 (record) PARTIAL ACCURATE: the PR body now has the title "passes 2–5", commits through 701f67c, and a gate table whose numbers match mine. The timeline shows the 00:17:48Z rename came after pass 5's read at 00:16:53Z. The §3.2 pointer is now true.
INACCURATE: CLOSEOUT.md:273; see D2.
N7 (record) ACCURATE API-A7 [10] → [11]; API-A12 [3] → [4] (on b03f33e); API-A13 [5]'s marker; API-A11 [2]'s wording; the review note's "a verdict line is not a change".
V5-2 markers ACCURATE API-A3 [0] points to [2] and API-A7 [5] points to [9]. Both targets start "corrected after independent review pass 4".
V5-1 fidelity note FIXED Bogus WHERE seed: TestLiveFieldLookup fails.
Real lookups: all 58 registry field names match the fake's name regex, so it refuses nothing the real lookup sends.
Remaining gaps (pre-existing): the fake is stricter than Google on WHERE forms, and it returns a row for a well-formed name that does not exist.
V5-9 observation Disposition SOUND deploy-homepage.yml:216 runs build_site_docs.py, whose --out-internal default is site_docs_internal. The committed copy (INTEGRATION_PLAN.html:607) still says 75-80.
keyword_performance_v1 Disposition SOUND Both omissions are now recorded (§4.11). The new rule skips ad_group_criterion, and that skip is asserted legal. Its v25 page publishes 0 segments and 0 metrics; customer's publishes 93 and 209.

New defects

D1 — NIT (record and test scope). The console email-route pin misses several arming routes, and the record overstates it. - Where: - tests/governance/test_api_lifecycle_inventory.py:267: the substitution regex --substitutions[= ]+(\S+). - :249-256: the docstring. - ISSUES.json:1757 (API-G14), EVIDENCE.md:1732 (§4.11 N4) and the PR body. - Seeds that leave both email tests passing: 1. A second pair in deploy-ui.yml:58. --substitutions=_IMAGE_TAG=${{ github.sha }},_REQUIRE_AUTH=false passes, because \S+ stops at the space inside ${{ github.sha }}. So does a quoted pair that puts a shell command into _REQUIRE_AUTH, because the auth-guard step pastes '${_REQUIRE_AUTH}' into bash. I did not run that in Cloud Build. 2. deploy-all.yml:123-126, which submits the same Cloud Build file. With '--substitutions=^:^_LIFT_ENGINE_URL=https://x.run.app,EMAIL_SERVICE=klaviyo:_IMAGE_TAG=…' the pin passes; it reads only deploy-ui.yml. 3. ENV EMAIL_SERVICE=klaviyo in the console Dockerfile's runtime stage (after line 41). 4. deploy-ui.yml given --flags-file=…, or --config= another file that names the variable. 5. An obfuscated shell step, such as N=EMAIL; … --update-env-vars "$${N}_SERVICE=klaviyo". The merging-flag check reads only arguments that start with the flag. - Fix: - Correct the API-G14, §4.11 and PR wording. - Pin the exact submit line, and do it in every workflow that submits this config. - Refuse --flags-file and a different --config in those workflows. - Scan the Dockerfile and next.config.mjs for the name. - Extend the "out of reach" list beyond "a Cloud Run setting changed by hand".

D2 — NIT (record). CLOSEOUT.md:273 reads "pass 6, which re-checks the pass-5 heals, reports no open blocker". That is the same construction pass 5 flagged (2ee03e0's row 255), yet §4.11 N6 says the row was fixed. - Fix: "pass 6 must report no open blocker", or fill the row in after pass 6 reports.

D3 — NIT (code). The late-read path can now raise on a malformed status body. - Where: request_tracking.py:480-481 calls apply_status on the late answer. apply_status raises AttributeError when errorInfo or warningInfo is not a mapping (:336, :339). - Scenario (probe P8): a late read gets HTTP 200 with "errorInfo": "boom". - Head raises out of reconcile_record; 2ee03e0 noted the read. - reconcile_due (:547) has no per-record isolation, so the sweep's batch stops there. The loop logs and retries; a manual refresh answers 500. - The same body on the applied path raises on both trees (pre-existing). - Fix: catch the error and note "answered an unparseable body", or make apply_status check types.

D4 — NIT (code wording). request_tracking.py:482-483: when a read's claim was taken over but the newer read has not landed yet (probe P5), the note still says "a newer read had already updated this record". In that probe nothing had updated the record: status submitted, last_checked_at null. - Fix: add a third reason, "its claim was taken over".

D5 — NIT (docstring and record). The registry check skips more than it says. - Where: test_api_compat_binding.py:537-542 and :574-576, API-A13 [6], and the PR body. - What is wrong: - "Not encoded" names only ad_group_criterion. In fact the attributed rule skips every attributed resource that is not a registry FROM resource: customer, bidding_strategy, accessible_bidding_strategy, campaign_group, and change_status's asset, asset_set, combined_audience and shared_set. Google does publish lists for some of these (customer: 93 segments). - The metric half of the same guide sentence (an attributed resource must also be compatible with each selected metric) is neither encoded nor listed. - Impact today: none. I checked every registered query's metrics against its attributed registry resources, and none fails. - Fix: list both gaps under "Not encoded".

D6 — NIT (record). API-A6 [9] (ISSUES.json:1547) says "per_account entries gain a synthetic flag", and the PR body says "on each MCC child entry". Skipped and raised children get no flag (orchestrator.py:521-525, :563-565), and the 503 shows them as null. A child whose run raised also has no run id, so the 503 cannot name a run that may have partly persisted (pre-existing). - Fix: say "each child that ran".

D7 — NIT (test scope). The GAQL deploy pin (test_api_compat_binding.py:955-958) has one gap and one false positive. - Not caught: a step running gcloud run services replace src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml, with that manifest flipped to GAQL_ENABLE_LIVE_MUTATIONS "true". The GAQL file still passes, 37 tests. By reading, a different --config in deploy-google-ads-gaql.yml is not read either. - False positive: a YAML comment naming a pinned key fails the pin (count 2). That fails closed, but unlike the console test, its comment does not say comments count. - Fix: pin the workflow's --config, and state these limits in the test.

Test runs

All runs: fresh python3.11 -m venv venvs (CPython 3.11.15, pytest 9.1.1) built from the CI install lines, under unshare -rn, with the proxy variables unset, TMPDIR=/tmp/v7/<run>, and commit signing turned off through GIT_CONFIG_* environment variables.

Command Environment Result
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" @701f67c suite-wiring venv, MIZOKI_STORE=memory 96 passed, 4 skipped
same image-lock venv (google-ads 33.0.0) 100 passed
same, under my own getaddrinfo audit (a direct lookup of accounts.google.com was recorded) lock venv 100 passed; 126 metadata-server lookups, 0 accounts.google.com
services/service-data-manager-connector/tests wiring venv 53 passed
tests/remediation/test_gaql_governance_wiring.py wiring venv 5 passed
docs/audits/tests @701f67c and @3d5278b wiring venv 1 failed (test_wo31_register, git show 26bec9c6… exit 128), 7 passed, identical on both; the object is absent from this clone
pytest tests/governance -c tests/governance/pytest.ini -p no:cacheprovider ci venv (+ -e contracts, whitepaper requirements) 4351 passed, 7 skipped, 6227 subtests, rc 0
bash .github/scripts/content_gates.sh governance-gates venv first on PATH rc 0, 155 passed
api_lifecycle_check.py / gate_leak_scan.py --check / claude_memory.py check --strict gates venv rc 0 each (FAILURES 0, WARNINGS 1 / 0 new, 0 grown, 0 stale / valid)
deploy_router.py --base 3f89cd0 --head 701f67c gates venv 21 files → deploy-google-ads-gaql.yml (8), deploy-ui.yml (1), frontend-guard.yml (1); with --base fa1cc19, 23 files and the same three
git merge-tree 3f89cd0 fa1cc19 701f67c (stdout-only form) — 0 conflicts
c7d8904's three test files on 2ee03e0's code wiring / lock / ci venvs GAQL suite 1 failed, 95 passed, 4 skipped (lock: 1 failed, 99 passed); GAQL file alone 1 failed, 36 passed, 4 skipped; Data Manager 2 failed, 51 passed; inventory file 23 passed
18 seeded mutations @701f67c GAQL file + inventory file as reported above
PR #1302 check-runs @701f67c gh api, read-only 28: 27 success, 1 skipped (Live Cell Endpoint Tests)

Not checked

  • Live provider behaviour.
  • Whether Cloud Build would actually run any seeded file. The claims that an image ENV survives --set-env-vars and that gcloud splits pairs on the comma come from documented behaviour; I did not measure them.
  • The serving revisions.
  • Gates on the merge result with fa1cc19. I only checked it for conflicts.
  • The console vitest, tsc and Playwright suites myself (CI reports them green).
  • Whether §4.10 quotes pass 5 verbatim. I had only pass 5's kept notes in vfy6/; they do not contradict it.
  • The PR body's edit history between 00:17Z and 01:14Z.
  • CI's git version.

Disclosures

  • Main checkout: I only read it, with GIT_OPTIONAL_LOCKS=0, and ran worktree add/remove there. It was clean at the start and the end; HEAD stayed 701f67c. I did not touch base or memwt2.
  • My worktrees: I created and removed 6. In them, I restored mutated files with git show HEAD:<path>; I used no stash.
  • Cleanup: I removed all 4 venvs and /tmp/v7.
  • Kept, in vfy7/: REPORT.partial.md, logs/, probes/, gdocs/, dnshook/, pr_body.md and ledger_diff.txt.
  • Read outside vfy7/: only vfy6/REPORT.partial.md, vfy6/pr1302.json, and directory listings of vfy5/ and vfy6/.
  • Network:
  • Google's field-service page and the v25 field-reference pages, fetched read-only.
  • PyPI installs.
  • GitHub REST reads only (the PR, its check-runs, its timeline).
  • No provider call.
  • Deviations from CI: plain venvs rather than setup-python; -p no:cacheprovider on the governance run; -rf added to some runs; pytest installed after the lock.
  • No writes: no pushes, comments, records, deploys or dispatches.

4.13 Pass 6 dispositions (fixes in 9d9cd01 and 85b7ecb; record in the commit that adds this section)

How each fix is verified (§3.3): - A test that fails on 701f67c's code: D3, D4. - Seeds on the real files: D1 and D7. Of the 15 arming routes seeded, the pins as pass 6 read them catch 1, and the new pins catch all 15. A legal look-alike passes both. - A seed that fails when the rule is removed: D5's metric half. - Record and docstrings: D2, D5, D6.

The heals are this session's own and therefore non-independent; pass 7 re-checks them before the merge gate. Pass 6's verdicts on the pass-5 items stand as reported (§4.12); its two PARTIALs are N4 (D1) and N6 (D2).

# Finding Disposition Issue Test
D1 the console email-route pin missed several in-repo arming routes, and the record overstated it fixed. The pin now reads: each workflow that submits the console's Cloud Build file (deploy-ui.yml and deploy-all.yml; a third submitter fails the test), where each submit command's substitutions must be exactly the image tag, with no flags file; deploy-ui.yml's --config values, in either form; every file under .github, ops, scripts and deployment, for the variable's name; and the console's Dockerfiles, next.config.mjs and the .env files Next.js loads. A merging flag inside a shell string fails too. Out of reach, as the docstring now says: a Cloud Run setting changed by hand (the next deploy replaces it), a name assembled at run time inside a shell step (pass 6's seed 5), and a deploy from outside the repository. API-G14 [8] and §4.11's N4 row are marked. Pass 7 (N2): partial. Nine more in-repo routes passed, and three sentences here overstated the pin's reach: it read files of six suffixes, one spelling of the config path, and only the lines that start with --substitutions. Fixed in 49f8d80 (§4.15) API-G14 test_the_console_email_route_stays_unarmed_on_deploy
D2 (record) CLOSEOUT's pre-merge row spoke for pass 6 before it reported the row now says what must be true before the merge: pass 7 reports no open blocker — —
D3 (code) a late read could raise on a malformed status body, and the sweep's batch stopped at that record fixed: apply_status reads a provider field of the wrong shape (the row list, errorInfo, warningInfo, their count lists, eventsIngestionStatus) as absent, on the applied path (which raised on both trees) and on the late-read path. A body with no readable rows reads unknown. Not changed: reconcile_due still has no per-record isolation, so an exception from the store stops the batch, as before. Pass 7 (N3): a count of Infinity still raised (OverflowError), and this sentence understated it: any exception in one record stops the sweep. Fixed in 49f8d80 (§4.15) API-F6, API-F3 test_a_malformed_status_body_is_read_not_raised
D4 a read whose claim was taken over, with nothing landed yet, was noted "a newer read had already updated this record" fixed: the note gives one of three reasons: the record was re-sent; a newer read had already updated it (it is terminal, or was read later); or its claim was taken over by another read API-F6 the note assertion in test_a_read_that_outlived_its_lease_releases_only_its_own_claim
D5 the registry check skipped more than it said the metric half of the rule is now encoded (85b7ecb): no registered query fails it, and its seed fails when it is removed. The docstring lists what stays unencoded: an attributed resource that is not a FROM resource of the registry (today a query selects only ad_group_criterion; customer and the others pass 6 named would be skipped the same way), and two attributed resources against each other (the fixture holds no resource-level lists) API-A13 test_the_check_catches_what_it_encodes
D6 (record) API-A6 [9] and the PR body said every per_account entry gains a synthetic flag corrected: only the children that ran carry it. A skipped or raised child shows null in the 503, and a raised child has no run id, so the 503 cannot name a run that may have partly persisted (pre-existing, not changed) API-A6 —
D7 the GAQL deploy pin missed a workflow step that deploys the reference manifest, and a different --config; a comment naming a pinned key fails it, and the test did not say so fixed: exactly one workflow submits the cell's Cloud Build file, with that file as its only --config (either form) and no flags file, and nothing under .github, ops, scripts or deployment names the reference manifest. The test says a comment counts. Pass 7 (N1): partial. Pass 6's own seed, a step in the cell's Cloud Build file, still passed; the seed §3.3 called pass 6's was a different one. Fixed in 49f8d80 (§4.15) API-A12 test_the_deploy_keeps_live_mutations_off

Pass 6's other observations, recorded as given (§4.12): - What it did not check: - live provider behaviour, the serving revisions, and whether Cloud Build would run any seeded file; - the gates on the merge result with fa1cc19 (it checked only for conflicts). 5971bcb merges fa1cc19, and the final-tree gates run on the merge result; - the console's vitest, tsc and Playwright suites; - whether §4.10 quotes pass 5 verbatim; - the PR body's edit history between 00:17Z and 01:14Z; - CI's git version. - Its DNS audit of the image-lock GAQL suite recorded 126 metadata-server lookups and no accounts.google.com lookup. It did not raise the metadata lookups as a finding. - Footprint: it only read the main checkout, removed its worktrees and venvs, and kept its notes in vfy7/.

4.14 Pass 7 — follow-up PR #1302 (701f67c..d14dba0, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 02:35Z to 03:17Z. Its report, verbatim (taken from its hand-back; the copy it kept at vfy8/FINAL.md differs in the last line only):

Independent verification, pass 7 (blind): 701f67c..d14dba0 (draft PR #1302)

Bottom line. I found no blocker and no MAJOR. I found one MINOR and five NITs.

  • Code fixes D3, D4 and D5 are FIXED.
  • On 701f67c's code with 9d9cd01's test files, exactly 2 tests fail, the 2 the builder named. Reproduced.
  • With the metric half removed, exactly test_the_check_catches_what_it_encodes fails.
  • D1 is PARTIAL. All five of pass 6's seeds now fail the pin, seed 5 included. But nine new in-repo routes I seeded pass both email tests, and three sentences of the record are false (N2).
  • D7 is PARTIAL (MINOR). I replayed pass 6's own D7 seed from its kept mutate.py. It still passes, 37 passed and 4 skipped. That seed is a step in the cell's own Cloud Build file. The record says D7 is fixed, and it labels a different seed "pass 6's D7": one in the workflow (N1).
  • D2 and D6 are ACCURATE. N6 is fixed. But CLOSEOUT and RESUME credit the record fixes to 9d9cd01 and 85b7ecb; the PR body correctly says d14dba0 (N4).
  • Data Manager.
  • A body of the wrong shape is now read, not raised, on both paths.
  • A documented-shape body gives identical output on both trees.
  • The late-read note gives the right reason in all 9 cases I probed.
  • A pre-existing case still raises: an unquoted Infinity in any recordCount. It stops the sweep. The PR body and CLOSEOUT overstate this (N3).
  • The rest of the record is ACCURATE: the counts and states, API-A3, A7 and A11 moving to REVIEW_READY, the index markers, and API-A6, A13, F3 and F6.
  • Gates: all green in fresh venvs. The one exception is docs/audits/tests::test_wo31_register, which fails identically on 3d5278b and fa1cc19: commit 26bec9c6 is absent from this clone. PR CI on d14dba0: 28 check runs, 27 success, 1 skipped.

Pass-6 items

Item Verdict Evidence I produced
D1 (test scope + record) PARTIAL Pass 6's own seeds, replayed from its kept mutate.py and mutate2.py on d14dba0, each fail exactly test_the_console_email_route_stays_unarmed_on_deploy:
- seed 1 (ui_wf_second_subst);
- seed 2 (deploy_all_subst);
- seed 3 (dockerfile_env);
- seed 4 (ui_wf_flags_file, ui_wf_other_config);
- seed 5 (ui_shell_obfuscated). Seed 5 is now caught by the substring merging-flag check, though §3.3 calls it out of reach.
The builder's 11 console seeds each fail exactly that test. With 701f67c's test file, only B02 fails.
Not caught: nine in-repo routes (V01–V09, under N2).
D2 (record) FIXED / ACCURATE CLOSEOUT.md:294 now reads "pass 7, which re-checks the pass-6 heals, must report no open blocker".
D3 (code) FIXED as scoped; residual NIT (N3) Old code + new test: AttributeError at request_tracking.py:336.
Head reads these without raising, on both paths: errorInfo a string, warningInfo an int, the row list 5, a dict or a string, and a non-mapping body. The old code raised on the first three.
A documented-shape body with 2 destinations gives identical output on head and old code.
Still raises (pre-existing): a recordCount of Infinity or -Infinity raises OverflowError on both paths.
D4 (code wording) FIXED 9 late cases probed (probes/dm_reasons.py):
- re-sent and accepted, or re-sent and still in flight: "re-sent as attempt 2";
- a later read settled the record, advanced it, or failed; or R2 was overtaken by R3, which applied: "a newer read had already updated this record";
- the claim was taken over by a sweep or a manual refresh and is still in flight; or R2 was noted while R3 is in flight: "its claim was taken over by another read".
The old code said "newer read" in the last three.
D5 (docstring + test) FIXED Google's field-service guide (fetched; last updated 2026-09-30): a non-FROM resource "must be compatible with all other fields, segments, and metrics that are selected". Each v25 resource page lists "all metrics and segments that can be put in the same SELECT clause as the fields of" the resource.
Proxy vs the documented list: for the 3 attributed owners the registry uses (campaign_budget, campaign, ad_group), against all 14 fixture segments and metrics: 42 comparisons, 0 mismatches.
Not vacuous: 6 queries exercise it, and its seed fails when it is removed.
The "Not encoded" list is accurate:
- the 9 non-FROM attributed names in the fixture are exactly the docstring's;
- ad_group_criterion is the only one any query selects;
- its v25 page has no segment or metric tables;
- the Cookbook keyword query is as described;
- the fixture has no resource-level lists.
D6 (record) ACCURATE By reading orchestrator.py:519-567 and main.py:178-180: a skipped child and a raised child carry no run_id or synthetic key, so they project to null. A child that ran (ok, or with extraction errors) carries both.
D7 (test scope + record) PARTIAL (N1) Caught: the builder's 4 GAQL seeds each fail exactly test_the_deploy_keeps_live_mutations_off. 701f67c's pin catches 0 of them.
Not caught:
- pass 6's own seed, gaql_services_replace: 37 passed, 4 skipped;
- V10 to V12.
N4 (pass 6 PARTIAL) still PARTIAL Through the D1 and D7 residuals.
N6 (pass 6 PARTIAL) FIXED (D2) A new disagreement between the documents is N4 below.

Record items.

Item Verdict
API-A3, API-A7 and API-A11 → REVIEW_READY Sound. No pass-6 finding maps to them, and 9d9cd01 and 85b7ecb touch none of their code or tests. These are the only state changes against 701f67c.
Counts ACCURATE.
- 65 issues.
- Implementation: 56 IMPLEMENTED, 7 not applicable, 2 OPEN.
- Testing: 55 TESTED, 10 not applicable.
- Review: 53 REVIEW_READY, 6 IN_PROGRESS (A6, A12, A13, F3, F6, G14), 2 OPEN, 4 not applicable.
- Deployment: 32 DEPLOYED, 3 in progress, 13 OPEN, 17 not applicable.
- Runtime: 48 OPEN, 4 BLOCKED_EXTERNAL (E4, D6, C5, F5), 13 not applicable.
- Nothing is VERIFIED. CLOSEOUT and RESUME match.
Index markers ACCURATE.
- API-G14: [8] is marked SUPERSEDED.
- API-A6: [9] is marked, and [10] corrects it.
- API-A3: source_evidence [0] points to [2].
- API-A7: [5] points to [9].
API-A6 [10], API-A13 [7], API-F3, API-F6 and the new lines on A3, A7 and A11 ACCURATE.
API-G14 [9], §4.13 D1, docstring, PR body INACCURATE (N2).
API-A12 (new line), §4.13 D7, §3.3 row "pass 6's D7", the test comment "nothing deploys the reference manifest" INACCURATE (N1).
§3.3, "Pass 6's seed 5 … out of the pin's reach" INACCURATE, in the harmless direction: the seed as pass 6 gave it is caught.
§3.1, §3.2 (its numbers equal mine on d14dba0), §3.5, §4.11's marked rows ACCURATE.
§4.12 Consistent with pass 6's kept files. Every number, seed and probe in it matches vfy7/REPORT.partial.md, logs/mutations.txt (18 seeds) and probes/. Pass 6's final report text is not kept in vfy7, so I cannot prove the quote verbatim; I can only say nothing in those files contradicts it.
Deployed, verified or safe claims None beyond the evidence. "Not merged or deployed" holds. "Merging deploys 2 services" holds: the router dispatches deploy-google-ads-gaql and deploy-ui, plus the frontend-guard check. "PR CI green on the head" holds: 27 success, 1 skipped.

New defects

N1 — MINOR (test scope + record): pass 6's own D7 seed still passes, and the record says D7 is fixed. - Where: - src/cells/google_ads_gaql/tests/test_api_compat_binding.py:974-990. The scan reads .github, ops, scripts and deployment, and only .yml, .yaml, .sh and .py files there. The cell's own cloudbuild.yaml is read only for the env flag and the pinned keys. - The test comment at :974-976 ("nothing deploys the reference manifest"). - EVIDENCE.md:660 (§3.3) and :1970 (§4.13 D7). - ISSUES.json:1987 (API-A12). - The PR body's "GAQL cell: ACT" row. - Scenario: pass 6's vfy7/probes/mutate.py gaql_services_replace, applied verbatim to d14dba0, gives 37 passed and 4 skipped. It does two things: - appends to src/cells/google_ads_gaql/cloudbuild.yaml a step gcloud run services replace src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml; - sets the manifest's GAQL_ENABLE_LIVE_MUTATIONS to "true".

On merge, that Cloud Build file deploys the cell, and the replace step would then leave live mutations on. The operation builder still raises (pinned), so no mutation runs today. The builder seeded a different variant, a step in deploy-google-ads-gaql.yml, and §3.3 attributes it to pass 6. - Same gap, also passing: - V10: a step in deploy-google-ads-gaql.yml running gcloud run services update google-ads-gaql-cell --update-env-vars=GAQL_ENABLE_LIVE_MUTATIONS=true,.... - V11: a copy of the manifest under deployment/gaql/live.yaml, deployed by a services replace step. - V12: scripts/arm_gaql.js, which names the manifest.

The class docstring (:951) still says that flipping any of the pinned settings is "a visible change to this test". - Fix: - Pin the cell's Cloud Build steps exactly (their ids, or no services replace, and the manifest's name absent). - Scan workflows for the three key names, as the console pin does for its variable. - Drop the suffix filter, or state it. - Correct §3.3, §4.13, API-A12 and the PR body.

N2 — NIT (test scope + record, the same class as pass 6's D1): the console pin's reach is overstated again. - Where: - tests/governance/test_api_lifecycle_inventory.py: :254-255 (_CONSOLE_ENV_SOURCES), :285-292 (the docstring), :305, :310 and :316-318. - ISSUES.json:1762 (API-G14 [9]), EVIDENCE.md:1964 (§4.13 D1) and the PR body's "Console Klaviyo route + inventory" row. - False sentences: - "every file under .github, ops, scripts and deployment". Only .yml, .yaml, .sh, .py, .json and .env suffixes are read. Those roots hold 77 .tf files, 8 extensionless files (including ops/Makefile), and .js, .ts and .hcl files. - "a third submitter fails it". This holds only when the path is spelled exactly. - "each submit command's substitutions must be exactly the image tag". Only lines that start with the flag are read. - The "out of reach" list is not the remainder. - Seeds that pass both email tests and 701f67c's pin (each restored clean afterwards): - V01: EMAIL_SERVICE: klaviyo in the committed miz-oki-command-center-ui/env.production.yaml. The documented scripts/ops/deploy_frontend_cloudrun_prod.sh turns that file into --set-env-vars. - V02: a deploy-ui.yml step running services update --env-vars-file= on that file. - V03: scripts/arm_email.mjs, run by a step. - V04: an extensionless .github/scripts/arm-email. - V05: Dockerfile.prod with ENV EMAIL_SERVICE, and the console cloudbuild.yaml's -f pointed at it. No workflow edit is needed, and deploy-ui fires on merge. - V06: next.config.js with env.EMAIL_SERVICE. Next 15.5.24 resolves .js before .mjs; I read that, I did not build it. - V07: a new workflow with --config=miz-oki-command-center-ui/./cloudbuild.yaml and extra substitutions. - V08: a second --substitutions in the middle of a line in deploy-ui.yml. - V09: EMAIL_SERVICE in cloudbuild.otel.yaml's Knative env (it deploys miz-oki-command-center-ui), and a new workflow that submits it. - Mitigation: the route also needs EMAIL_API_KEY, SENDGRID_API_KEY or KLAVIYO_PRIVATE_API_KEY, and none is in the console's deploy env. That barrier is not pinned. - Fix: - Reword every copy to the measured scope. - Add the out-of-reach classes above. - Read the Cloud Build file's -f target, every next.config.*, and the console directory's YAML env files. - Scan without the suffix filter.

N3 — NIT (code, pre-existing; the record overstatement is new): a non-finite count still raises out of reconcile_record. - Where: - request_tracking.py:309-313: _count catches TypeError and ValueError, not OverflowError. - main.py:412: httpx r.json() uses json.loads, which accepts Infinity. - The sweep loop :557 has no per-record isolation. - Scenario (probe): a 200 response with "recordCount": Infinity raises OverflowError on the applied path and on the late path. reconcile_due raises at that record, and the other 2 due records stay submitted. The old code behaves identically. - Record overstatements of the same thing: - CLOSEOUT.md:60: "a malformed status body is read rather than raised". - The PR body: "instead of raising and stopping the sweep's batch". - §4.13 D3: "an exception from the store stops the batch". - By reading, not run: reason and destination.reference are stored as given. Firestore's documented limits would refuse a nested array, depth beyond 20, or more than 1 MiB on the applied-path write. - Fix: except (TypeError, ValueError, OverflowError) plus a finiteness check; a try/except per record in reconcile_due; and correct the wording.

N4 — NIT (record): the documents disagree on where the pass-6 fixes are. - Where: - CLOSEOUT.md:278: "All are fixed in 9d9cd01 and 85b7ecb". - RESUME.md:84-85: "Its two partials … and its seven nits are fixed in 9d9cd01 and 85b7ecb". - Measured: 9d9cd01 changes 4 files: request_tracking.py and 3 tests. D2 (the CLOSEOUT row), D6 (API-A6) and D1's record wording were changed in d14dba0. The PR body says so correctly. - Fix: say "the code findings in 9d9cd01 and 85b7ecb; the record findings in d14dba0".

N5 — NIT (label): an unreadable body is recorded as the provider's own "unknown". - Where: request_tracking.py:373. - Scenario: with the row list 5, a string or a dict, or a non-mapping body, the record becomes unknown/provider_reported_unknown with the history note "status read". That is the same record a genuine REQUEST_STATUS_UNKNOWN leaves. The record keeps being polled until its budget runs out, which is sensible; only the label is wrong. Pre-existing for an empty body; the row list 5 is a new path to it. - Fix: a distinct reason, or the note "unreadable status body".

N6 — NIT (observation, pre-existing, no impact today): the registry check against Google's own published queries. - The segment half of the attributed rule, as documented and encoded, would refuse Google's Query Cookbook "Search terms" query. That query selects segments.keyword.info.match_type with campaign.name FROM search_term_view, and campaign's v25 list (152 segments) omits that segment. The metric half refuses none of the Cookbook's 15 owner/query pairs. - Google's segmentation guide says "When a segment is in the WHERE clause, it must also be in the SELECT clause", except the core date segments. The check does not encode this, and the docstring does not list it: replace(campaign_performance_v1, where="segments.device = 'MOBILE'") gives []. No registered query has a segment only in WHERE (measured).

Test runs

All runs: fresh python3.11 -m venv venvs (CPython 3.11.15, pytest 9.1.1) built from the install lines below, under unshare -rn, with the proxy variables unset (both cases), TMPDIR=/tmp/v8/<run>, and commit signing off through GIT_CONFIG_COUNT/KEY/VALUE environment variables only. Every run is on d14dba0 unless stated.

The venvs: - ci: ci.yaml's Install Dependencies line, the consolidated-tests line, -e contracts, and the whitepaper requirements. - wire: the suite-wiring line. - gates: the governance-gates line. - lock: src/cells/google_ads_gaql/requirements.lock.txt, then pytest (google-ads 33.0.0, fastapi 0.109.1, pydantic 2.5.0). - cing: the install line of the deploy-service-canonical-ingestion.yml gate.

Command Environment Result
python -m pytest "services/service-data-manager-connector/tests" -q -p no:cacheprovider -o addopts="" wire, MIZOKI_STORE=memory 54 passed
python -m pytest "src/cells/google_ads_gaql/tests" … (same flags) wire 96 passed, 4 skipped
same lock 100 passed
pytest tests/remediation/test_gaql_governance_wiring.py wire / cing (the only workflow that runs it is deploy-service-canonical-ingestion.yml, as pytest tests/remediation) 5 passed / 5 passed
python -m pytest "docs/audits/tests" … @d14dba0, @fa1cc19, @3d5278b (my own worktree) wire 1 failed (test_wo31_register: "not in '26bec9c6…'"), 7 passed, identical on all three; the object is absent from this clone
pytest tests/governance -c tests/governance/pytest.ini -p no:cacheprovider ci 4351 passed, 7 skipped, 6227 subtests, rc 0 (444 s)
bash .github/scripts/content_gates.sh gates venv first on PATH rc 0, 155 passed
python3 scripts/api_lifecycle_check.py gates rc 0 (FAILURES 0, WARNINGS 1, UNKNOWNS 20)
python3 scripts/gate_leak_scan.py --check gates rc 0 (0 new, 0 grown, 0 stale)
python3 scripts/claude_memory.py check --strict gates rc 0 (valid)
python3 .github/scripts/deploy_router.py --base fa1cc19 --head d14dba0 gates 21 files → deploy-google-ads-gaql.yml (8), deploy-ui.yml (1), frontend-guard.yml (1); with --base 3f89cd0, 23 files and the same three
git merge-tree --write-tree 9d9cd01 fa1cc19 — tree d5e3561 = 5971bcb^{tree}: a clean merge with no hand edits. It brought only 8924d1c's two Shopify docs; there is no overlap with the PR's 21 files and no interaction
701f67c's code with 9d9cd01's 3 test files wire / lock / ci Data Manager: 2 failed (exactly the 2 named), 52 passed. GAQL suite: 96 passed + 4 skipped (wire), 100 passed (lock). GAQL file alone: 37 passed + 4 skipped. Inventory: 23 passed
15 builder seeds + look-alike + clean (probes/seeds.py), with head's pins and with 701f67c's pins ci + wire each fails exactly the named pin; 701f67c's pins catch 1 (B02); the look-alike and the clean tree pass both
12 own seeds V01–V12 ci + wire all pass, under both the new and the old pins
pass 6's 17 seeds, replayed ci + wire 16 caught as expected (seed 5 included); gaql_services_replace not caught
metric half removed (f.startswith("segments.")) wire 1 failed (exactly test_the_check_catches_what_it_encodes), 36 passed, 4 skipped
Data Manager probes (probes/dm_probe.py, dm_reasons.py) on head and 701f67c wire, memory store as reported under D3, D4 and N3
PR #1302 check runs on d14dba0 gh api, read-only 28: 27 success, 1 skipped (Live Cell Endpoint Tests)

What I did not check

  • Live provider behaviour and the serving revisions.
  • Whether Cloud Build, gcloud or Next.js would act on any seed. Three behaviours come from documentation or reading, not measurement: an image ENV surviving --set-env-vars, how gcloud treats a repeated --substitutions, and whether Next.js prefers next.config.js and inlines its env.
  • Firestore behaviour. It is from its documented limits; I ran nothing against it.
  • Whether Google's API accepts the Cookbook query that conflicts with the documented rule.
  • The console's vitest, tsc and Playwright suites myself. CI's Frontend Guard is success.
  • A DNS audit of the image-lock suite. Every suite ran under unshare -rn.
  • That §4.12 is verbatim, beyond being consistent with vfy7.
  • CI's git version.
  • The PR body's edit history.

Disclosures

  • Main checkout: I read it only, with GIT_OPTIONAL_LOCKS=0. I also ran git worktree add and remove there, and one git worktree prune; base and memwt2 are still listed and I did not touch them. At the start and the end, status was clean, HEAD was d14dba0 and there were 0 stashes.
  • My worktrees: I created and removed 6 under vfy8 (head, p701, main, w3d, mut, mut2). In them, I restored seeded files with git checkout -- . and git clean; I used no stash.
  • Cleanup: I removed all 5 venvs and /tmp/v8.
  • Read outside vfy8:
  • vfy7/REPORT.partial.md, vfy7/probes/mutate.py, vfy7/probes/mutate2.py, vfy7/logs/mutations.txt;
  • directory listings of vfy5, vfy6 and vfy7;
  • one listing of the scratchpad root, file names only. I read none of those files.
  • Network:
  • read-only fetches of Google documentation: the field-service guide; the v25 pages for campaign, campaign_budget, ad_group, ad_group_criterion and metrics; the Query Cookbook; the segmentation guide (one 404 first); and two Firestore pages;
  • PyPI installs;
  • GitHub REST reads of PR #1302 and its check runs.

I made no provider call. - Deviations from CI: - plain venvs rather than setup-python; - -p no:cacheprovider and -rf/-rfE added on some runs; - content gates and the gate scripts ran in a clean worktree at the same commit. - No writes: no pushes, comments, records, deploys or dispatches. - Kept, in vfy8/: REPORT.partial.md (which also holds this report), logs/, probes/ and gdocs/.

4.15 Pass 7 dispositions (fixes in 49f8d80; record in the commit that adds this section)

How each fix is verified (§3.3): - A test that fails on d14dba0's code: N3. - The verifiers' own seeds, replayed on the real files: N1 and N2. Of 28 arming routes from pass 7's driver and pass 6's D7 seed, 49f8d80's pins catch 28 and d14dba0's catch 15. The clean tree and a look-alike name pass both. - Docstrings and record: N2's wording, N4, N6. - Recorded, not changed: N5, N3's per-record isolation, and N6's Cookbook observation.

The heals are this session's own and therefore non-independent; pass 8 re-checks them before the merge gate. Pass 7's verdicts on the pass-6 items stand as reported (§4.14): D2 to D6 FIXED or ACCURATE, and D1 and D7 PARTIAL (N2, N1).

# Finding Disposition Issue Test
N1 (MINOR) pass 6's own D7 seed, a step in the cell's Cloud Build file, still passed the GAQL deploy pin; so did V10 to V12; and the record called a different seed pass 6's fixed. The Cloud Build file's steps are pinned: the image build, the push and one gcloud run deploy of the cell, with no services replace or services update and no mention of the manifest. Under .github, ops, scripts and deployment, no file of any suffix may name the manifest or a pinned key, and none that names the cell's service may change it with those verbs. The submitter is matched under any spelling of the config path. The class docstring says what stays out of reach: a by-hand change, a deploy from outside the repository, a name or path assembled at run time. §3.3's row and API-A12's pass-6 line are marked. Pass 8 (defect 1): partial. Six literal in-repo routes (G1–G6) passed the pin, one of them a fourth step in the Cloud Build file, so "the steps are pinned" and the out-of-reach list were false. Fixed in 02b4c3c (§4.17). Pass 9 (defects A and B): that fix was partial too: eight more literal routes inside its stated reach passed, three of them regressions. Fixed in 9736385 (§4.19) API-A12 test_the_deploy_keeps_live_mutations_off
N2 the console pin's reach was overstated again: nine in-repo routes passed fixed. The pin reads files of any suffix under the four roots, every top-level file of the console's directory, and each Dockerfile its Cloud Build file builds. It looks there for EMAIL_SERVICE and the route's three API-key variables (arming needs both, and neither is pinned elsewhere). It matches the submitters under any spelling of the config path, and wants one --substitutions per submit command. The docstring, API-G14 and the PR body now state that reach, and the remainder: a by-hand change, a name assembled at run time, a deploy from outside the repository, and a file elsewhere that names nothing pinned (a nested console directory, a new top-level directory). Pass 8: fixed for the nine routes. But the shared key names made two new false positives (defect 2), and "any spelling of the config path" was overstated (defect 4). Both fixed in 02b4c3c (§4.17) API-G14 test_the_console_email_route_stays_unarmed_on_deploy
N3 a non-finite count still raised out of reconcile_record, and the record overstated what was fixed fixed. A count that is not a finite 64-bit integer reads as absent, and provider labels (status, reason, reference) are kept only as bounded strings: pass 7 named, by reading, the Firestore limits they could exceed. Measured before the fix: such a record was never retired (§3.3). Not changed: reconcile_due has no per-record isolation, so an exception from the store in one record stops the sweep, as it did before (write paths fail loudly). With every provider answer now read, that is the remaining way for a record to stop a sweep. Pass 8 (defect 3): that sentence was false. The totals and the number of rows were still unbounded, so a provider answer could still make the store refuse the write (measured with Firestore's encoder). Fixed in 02b4c3c (§4.17). Pass 9 (defect D): not yet for a label carrying a lone surrogate. Fixed in 9736385 (§4.19) API-F6, API-F3 test_a_status_body_out_of_range_is_read_not_raised
N4 (record) CLOSEOUT and RESUME credited the pass-6 record fixes to the code commits corrected: the code findings are fixed in 9d9cd01 and 85b7ecb, the record findings in d14dba0 — —
N5 an unreadable body is recorded as the provider's own unknown recorded for the owner, not changed. The state and the retry are right; only the label is shared with a genuine REQUEST_STATUS_UNKNOWN, and a distinct reason would widen the unknown_reason vocabulary callers read. Pass 8: that reason covered one of the two fixes; the other, a history note, widens nothing. Added in 02b4c3c (§4.17) API-F6 —
N6 (observation) the registry check against Google's own published queries recorded. The docstring lists the rule pass 7 found unencoded: a segment in the WHERE clause must also be selected, except the core date segments. No registered query has a segment only in its WHERE clause; this session measured that too. It also records that the documented segment rule would refuse Google's Cookbook "Search terms" query. No registered query is affected API-A13 —

Pass 7's other observations, recorded as given (§4.14): - What it did not check: - live provider behaviour and the serving revisions; - whether Cloud Build, gcloud or Next.js would act on any seed: an image ENV surviving --set-env-vars, a repeated --substitutions, and the next.config.js precedence are from documentation or reading; - Firestore behaviour (documented limits only); - whether Google accepts the Cookbook query; - the console's vitest, tsc and Playwright suites (CI's Frontend Guard is green); - a DNS audit (every suite ran under unshare -rn); - that §4.12 is verbatim: pass 6 kept no copy of its final text, so pass 7 could check §4.12 only against pass 6's kept files, which nothing in it contradicts; - CI's git version, and the PR body's edit history. - Footprint: it read the main checkout only, and ran git worktree add/remove and one git worktree prune there. It removed its worktrees and venvs, and kept its notes in vfy8/.

4.16 Pass 8 — follow-up PR #1302 (d14dba0..d7a5af2, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 03:50Z to 04:28Z. Its report, verbatim (taken from its hand-back):

Independent verification, pass 8 (blind): d14dba0..d7a5af2 (draft PR #1302)

Bottom line. I found no blocker and no MAJOR. I found one MINOR and four NITs.

  • The pass-7 heals hold for every seed they were built against.
  • I replayed pass 7's seed driver (vfy8/probes/seeds.py, paths changed only) and pass 6's D7 seed (vfy7/probes/mutate.py, gaql_services_replace, verbatim). That is 28 arming routes.
  • With 49f8d80's test files, all 28 are caught, and each fails exactly the test named. With d14dba0's test files, 15 are caught.
  • The clean tree and the look-alike name pass both.
  • N3's new test fails on d14dba0's code: 1 failed (OverflowError), 54 passed. Each half of the N3 fix makes that test fail when I remove it.
  • MINOR: N1 is only PARTIAL, so D7 stays PARTIAL. Six in-repo, literal routes I seeded (G1–G6) pass both the new and the old GAQL pins. One of them is a fourth step in the cell's own Cloud Build file. So these statements are false:
  • "the Cloud Build file's steps are pinned";
  • the docstring's "out of reach" list.

The operation builder still raises NotImplementedError (its test passes), so no mutation can run today. - NITs: - Both pins now fail on plausible changes to other services (false positives). - N3 bounds each count, but not their sums or the number of status rows. On head, with Firestore's own encoder in the store path, one provider answer raised 960 times in 80 hours, and its record was never retired. - Several record sentences overstate the fixes (defect 4). - One pre-existing accept-path gap of the same kind as N3 (defect 5). - Gates: all green in fresh venvs. The one exception is test_wo31_register, which fails identically on 3d5278b because this shallow clone lacks commit 26bec9c6. - PR CI on d7a5af2: 28 check runs, 27 success, 1 skipped. - RESUME's own rule ("a blocker, major or minor in the pass-7 heals is fixed and re-checked again") applies to the MINOR.

Pass-7 items

Item Verdict Evidence I produced
N1 (MINOR: GAQL pin and record) PARTIAL Pass 6's D7 seed, verbatim: the new pins fail exactly test_the_deploy_keeps_live_mutations_off; d14dba0's pins pass it. V10, V11 and V12 are now caught (the old pins catch none of them). G1–G6 (defect 1) pass both the whole new GAQL test file (0 failures) and the old pin.
N2 (NIT: console pin and record) FIXED for the nine routes; NIT residuals V01–V09 each fail exactly test_the_console_email_route_stays_unarmed_on_deploy; the old pin catches none. Console total: 20 of 20 (old pin: 11). Residuals: C3/C3b and C4 pass (defect 4); C1 and C2 are new false positives (defect 2).
N3, code FIXED as scoped Old code with the new tests: 1 failed (the named test), 54 passed.
Head with the 64-bit range check removed, or with _label returning the raw value: exactly that test fails.
10 documented-shape bodies (int64 min/max strings, numbers instead of strings, a missing count, an empty body, 1–2 destinations): apply_status output identical on head and on d14dba0.
N3, record: "never retired" ACCURATE (now measured) Old code, 80 hours of 1-minute sweeps: 960 raises, one every 300 s. The record stayed submitted with 0 checks, past the 72-hour TTL.
Head: finalized on the first sweep.
Label mismatch: §3.3 says "by reading"; §4.15 and API-F6 say "measured".
N3, record: "With every provider answer now read, [a store exception] is the remaining way for a record to stop a sweep" INACCURATE Defect 3
N3's per-record isolation (recorded, not changed) Deferral defensible; premise false Rule 01 ("write paths fail loudly") supports not swallowing store errors. But a provider answer can still produce a store error, with the same never-retired outcome (defect 3), so the residual is larger than recorded.
N4 (record) ACCURATE CLOSEOUT and RESUME now credit the code findings to 9d9cd01/85b7ecb and the record findings to d14dba0.
N5 (recorded) Sound as a deferral; its reason is incomplete Head and old both label a row list of 5, a string, or a non-mapping body as unknown/provider_reported_unknown. The stated reason (it would widen the unknown_reason vocabulary) covers one of pass 7's two fixes. The other, the history note "unreadable status body", widens nothing.
N6 (observation, docstring) ACCURATE Segmentation guide (fetched; last updated 2026-10-01): its wording matches the docstring.
Registry: 11 queries; 7 have a segment in WHERE, all segments.date, and each also selects it. So no query has a WHERE-only segment.
Cookbook (last updated 2026-09-30): the "Search terms" query selects segments.keyword.info.match_type with campaign.name FROM search_term_view. Campaign's v25 resource-level segment list (152 entries) has no keyword.* segment.
Registry test: passes.
Pass 7's PARTIAL on D1 Now FIXED for every measured route NIT residuals as for N2
Pass 7's PARTIAL on D7 Still PARTIAL G1 and G5 are exactly D7's class: a deploy of a manifest copy, and a different Cloud Build config from another workflow.

Record items

Item Verdict
§4.14 verbatim ACCURATE. The 194 quoted lines equal vfy8/FINAL.md except the last line, as stated. vfy8/REPORT.partial.md holds the same text. Pass 7's hand-back itself was not available to me.
Counts and states (ISSUES.json) ACCURATE:
- 65 issues.
- Implementation: 56 IMPLEMENTED, 7 not applicable, 2 OPEN (G13, A12).
- Testing: 55 TESTED, 10 not applicable.
- Review: 54 REVIEW_READY, 5 IN_PROGRESS (F3, G14, A12, A13, F6), 2 OPEN, 4 not applicable.
- Deployment: 32 DEPLOYED, 3 in progress, 13 OPEN, 17 not applicable.
- Runtime: 48 OPEN, 4 BLOCKED_EXTERNAL (E4, D6, C5, F5), 13 not applicable.
- Nothing is VERIFIED. CLOSEOUT and RESUME match.
API-A6 → REVIEW_READY Sound. It is the only state change. 49f8d80 does not touch A6's code or its tests (test_api_compat_binding.py:704–830). Its new line only records pass 7's verdict.
API-A12, pass-7 line Numbers ACCURATE (8 of 8; 4 with the old pin). "Out of reach…" INACCURATE (G1–G6).
API-A13, F3, F6 lines ACCURATE. F6 says nothing about sums or rows.
API-G14 Numbers ACCURATE (20 of 20; 11 with the old pin). "Any spelling of the config path" is overstated (C3).
EVIDENCE §3.1, §3.2 (pass-7 heal head), §3.3 (pass-7 block and the two marked pass-6 lines), §3.5 ACCURATE. My numbers equal the record's. Pass 6's kept seed did put the step in the Cloud Build file, and its seed 5 does carry --update-env-vars.
§4.13 marked rows ACCURATE. NIT: D7's and A12's markers do not say that the old GAQL scan read only four suffixes.
§4.15 N1's disposition and its "out of reach" list: INACCURATE. N2: mostly accurate. N3's last sentence: INACCURATE. N4, N5, N6: ACCURATE.
CLOSEOUT ACCURATE, except the Data Manager row (:60): "counts or labels the store cannot hold, is read rather than raised" is overstated.
RESUME ACCURATE.
PR body The gate table and the numbers are ACCURATE (reproduced). INACCURATE:
- the GAQL row: "that file's steps…", "changes the cell's service with those verbs", and "Out of reach";
- the corrections bullet "both read six file suffixes only": d14dba0's GAQL scan read four (.yml .yaml .sh .py, :988);
- the Data Manager row: overstated, as in CLOSEOUT;
- the console row's "any spelling" (C3).
Deployed, verified or safe claims None beyond the evidence. PR #1302 is open, a draft, and not merged (REST read). The router dispatches 2 deploys (GAQL cell, console) plus the frontend-guard check, as stated.

New defects

1. MINOR: the GAQL deploy pin is bypassable by literal in-repo changes, and the record says otherwise. - Where: - src/cells/google_ads_gaql/tests/test_api_compat_binding.py: :955–959 (the constants), :968–977 (the docstring), :1002–1008 (the step pin, done with line regexes), and :1025–1034. In :1025–1034 the verb check runs only when a file names the service, and the cell's directory is not scanned beyond cloudbuild.yaml. - The record: §4.15 N1, API-A12's pass-7 line, and the PR body's GAQL row. - Seeds: each passes the whole new GAQL test file and d14dba0's pin, and each was restored clean. - G1: a new push-to-main workflow runs gcloud run services replace src/cells/google_ads_gaql/live.yaml. live.yaml is the reference manifest with GAQL_ENABLE_LIVE_MUTATIONS: "true", kept in the cell's directory. The workflow never names the service, so the verb check never runs. - G2: a fourth step in the cell's own cloudbuild.yaml, written - id: arm-live / name: gcr.io/cloud-builders/gcloud / args: [run, services, replace, src/cells/google_ads_gaql/live.yaml, --region=us-central1]. - PyYAML parses 4 steps; the ^\s*- name: regex sees 3. - The step has no entrypoint, and the verb regex misses services, replace. - .gitignore re-includes /src/ (I read this; I did not run a build). - G3 and G4: a deploy-google-ads-gaql.yml step running gcloud run services \, then update google-ads-gaql-cell … --env-vars-file=src/cells/google_ads_gaql/live-env.yaml on the next line. G4 is the same with the verb quoted ("update"). - G5: src/cells/google_ads_gaql/cloudbuild.live.yaml, a copy of the pinned file with =true, submitted by a new workflow. - G6: a deploy-google-ads-gaql.yml step running gcloud run deploy google-ads-gaql-cell --image=… --env-vars-file=src/cells/google_ads_gaql/live-env.yaml. It needs no trick: run deploy is not a pinned verb.

None of these is a by-hand change, a deploy from outside the repository, or a name assembled at run time. - Fix: - Parse the Cloud Build file with yaml.safe_load and assert the exact step list (name, entrypoint, args). - Before matching verbs, tokenize the arguments: join list items, and strip quotes and line continuations. - Treat run deploy, services update/replace, --env-vars-file, and --set-env-vars/--update-env-vars on the service as changes. - Scan the cell's directory (excluding tests) for any other Cloud Build file or Knative YAML that names google-ads-gaql-cell. - Add "a file outside the scanned places that a literal deploy step reads" to the docstring, API-A12, §4.15 and the PR body, as the console pin already does.

2. NIT: both pins now fail on legitimate changes to other services (false positives). - Where: tests/governance/test_api_lifecycle_inventory.py:257–259 with :345–354; test_api_compat_binding.py:959 with :1033–1034. - Seeds: each fails the new pin; the old pin passes. - C1: deploy-homepage.yml:409's --update-secrets gains SENDGRID_API_KEY=…. That is the site's own pilot-email key (# MIZ OKI 3.5/mizoki_runtime/pilot_requests.py:34). The console test fails. - C2: ops/rails/arm_klaviyo_feed.sh sets measurement-rails' KLAVIYO_PRIVATE_API_KEY (named in docs/measurement-rails/RUNBOOK.md:189 and klaviyo_feed.py:47). The console test fails. - GFP: verify-cloudrun-state.yml, whose fleet list names google-ads-gaql-cell, prints gcloud run services update {svc} --min-instances=1. The GAQL test fails. - Why it matters: arming either documented dark rail through a scanned deploy file would turn the governance suite red for a service it does not touch. That invites narrowing the rule, which rule 01 forbids. - Fix: fail only when the same command targets the console or GAQL service. At minimum, document the coupling.

3. NIT: Data Manager. N3 bounds each count, but not the values derived from them or the number of status rows (pre-existing; the record overstates the fix). - Where: services/service-data-manager-connector/request_tracking.py:353 (the rows are unbounded) and :392–400 (failed, sent, confirmed_events and failed_events are unbounded). In the record: CLOSEOUT.md:60, §4.15 N3, and the PR body's Data Manager row. - Measured (head and d14dba0 behave identically): - Two destinations, each answering recordCount "9223372036854775807", give confirmed_events 2^64−2. - A partial success with two such error counts gives failed_events 2^64−2. - An error count of −2^63 gives confirmed_events 2^63+5. - google-cloud-firestore 2.34.0 and 2.11.1 _helpers.encode_dict refuse all three, offline: ValueError: Value out of range. - End to end on head: I ran 80 hours of 1-minute sweeps with a store whose transact_update runs that encoder (as transaction.set does). There were 960 raises. The record stayed submitted with 0 checks and its claim held, and it was never retired; the other two records succeeded. - Rows: a 1-destination record answered with 90 SUCCESS rows reads as success and stores a 1,067,314-byte provider_status. 20,000 minimal rows give 2,220,004 bytes. Firestore's 1 MiB document limit comes from its documentation; I did not run Firestore. - The memory store accepts all of these, so the test suite cannot see them. - Fix: - Clamp the sums, or treat a total outside int64 as unknown (confirmed_events None), and reject negative counts. - Cap the rows at the record's number of destinations. - Add a seed whose sums overflow. - Correct CLOSEOUT :60, §4.15 N3 and the PR body.

4. NIT: record wording. - PR body: "both read six file suffixes only" is wrong for the GAQL scan, which read four. - §4.13 D7 and API-A12's pass-6 marker: they do not say the old scan read four suffixes (pass 7's V12), unlike G14's marker. - "Never retired": §4.15 and API-F6 say measured; §3.3 says "by reading". The fact is true. - "Under any spelling of its path" (console): C3 and C3b pass all 23 inventory tests. C3b is a workflow with working-directory: miz-oki-command-center-ui running gcloud builds submit .. --config=cloudbuild.yaml --substitutions=…,_REQUIRE_AUTH=false. This does not arm the email route by itself. - C4: YAML-escaped names ("EMAIL\x5FSERVICE") in deployment/ui/runtime-env.yaml, applied by a deploy-ui step with --env-vars-file, pass. This is arguably "assembled at run time", and is worth naming.

5. NIT (pre-existing, outside the range's claims; by reading only): field_warnings() (request_tracking.py:163–174) keeps the reason and field of an events:ingest response unbounded and of any type. It is the accept-path twin of N3's labels.

Test runs

Environment for every run: - Fresh python3.11 -m venv venvs (CPython 3.11.15, pytest 9.1.1), built from the install lines below. - Everything ran under unshare -rn. - Proxy variables unset, and also GH, GCP and AWS credential variables. - TMPDIR=/tmp/v9/<run>. - Commit signing off via GIT_CONFIG_* environment variables only.

The venvs: - ci: ci.yaml's Install Dependencies line, the consolidated-tests line, -e contracts, and the whitepaper requirements. - wire: the suite-wiring line. - gates: the governance-gates line. - lock: the GAQL lock file, then pytest (google-ads 33.0.0, fastapi 0.109.1, pydantic 2.5.0). - cing: the gate line of deploy-service-canonical-ingestion.yml (google-cloud-firestore 2.34.0).

Command Env Result
pytest tests/governance -c tests/governance/pytest.ini @d7a5af2 ci 4351 passed, 7 skipped, 6227 subtests passed, rc 0 (441 s)
python -m pytest "services/service-data-manager-connector/tests" -q -p no:cacheprovider -o addopts="" (MIZOKI_STORE=memory) wire 55 passed
same flags, "src/cells/google_ads_gaql/tests" wire / lock 96 passed + 4 skipped / 100 passed
pytest tests/remediation/test_gaql_governance_wiring.py; pytest tests/remediation -q wire / cing 5 passed; 396 passed
"docs/audits/tests" @d7a5af2 and @3d5278b (my own worktree) wire 1 failed (test_wo31_register, git show 26bec9c6b… exit 128), 7 passed; identical on both
tests/governance/test_api_lifecycle_inventory.py ci 23 passed
bash .github/scripts/content_gates.sh gates venv first on PATH rc 0, 155 passed
api_lifecycle_check.py / gate_leak_scan.py --check / claude_memory.py check --strict gates rc 0 each: FAILURES 0, WARNINGS 1, UNKNOWNS 20 / 0 new, 0 grown, 0 stale / valid
deploy_router.py --base fa1cc19 --head d7a5af2 gates 21 files → deploy-google-ads-gaql (8), deploy-ui (1), frontend-guard (1)
d14dba0's code with 49f8d80's Data Manager tests wire 1 failed (the named test, OverflowError), 54 passed
28 replayed arming seeds, plus the clean tree and the look-alike, against the new and the old pins ci + wire new pins 28 of 28, each failing exactly the named test; old pins 15 of 28
13 own seeds (G0–G6, GFP, C1–C4, C3b) ci + wire G1–G6, C3, C3b and C4 pass both pins; G0 (control) passes both; C1, C2 and GFP fail the new pin only
Data Manager and Firestore-encoder probes wire / cing / lock As in defect 3 and the N3 rows
PR #1302 check runs on d7a5af2 gh api, read-only 28: 27 success, 1 skipped (Live Cell Endpoint Tests)

What I did not check

  • Live provider behaviour and the serving revisions.
  • Firestore itself. I used only its client's offline encoder; the 1 MiB limit is from its documentation.
  • Whether Cloud Build or gcloud would execute G1–G6. That they would is from reading.
  • The console's vitest, tsc and Playwright suites (CI's Frontend Guard is green).
  • A DNS audit.
  • Pass 7's hand-back text.
  • The PR body's edit history, and CI's git version.

Disclosures

  • Main checkout: I read it only, with GIT_OPTIONAL_LOCKS=0, and ran git worktree add/remove there. Status was clean, HEAD was d7a5af2 and there were 0 stashes, at the start and at the end. I did not touch base or memwt2.
  • My worktrees: I created and removed 7 under vfy9 (head, head2, old, mut, mut2, mutold, w3d). I seeded files in my own worktrees and restored them with git checkout/git clean and file copies; I used no stash.
  • Cleanup: I removed all venvs and /tmp/v9. No /tmp/wo26-* or /tmp/v417-* entries were left.
  • Read outside vfy9:
  • vfy8/FINAL.md, vfy8/REPORT.partial.md, vfy8/probes/seeds.py and its run and build scripts;
  • vfy7/probes/mutate.py;
  • directory listings, and one listing of the scratchpad root (file names only). I opened none of the builder's files.
  • Network:
  • PyPI installs;
  • read-only fetches of Google's segmentation guide (three 404s while finding its URL), the Query Cookbook and the v25 campaign fields page;
  • GitHub REST reads of PR #1302 and its check runs. One GraphQL attempt was refused (403) before any data was read.

I made no provider call. - Deviations from CI: - plain venvs rather than setup-python; - -p no:cacheprovider and -rf/-rfE added on some runs; - an early governance run had a doubled -q, which hid its summary line; I re-ran it exactly as CI does; - some probe scripts unset only the HTTP(S) proxy variables, but all of them ran under unshare -rn. - No writes: no pushes, comments, records, deploys or dispatches. - Kept in vfy9/: REPORT.partial.md (which also holds this report), logs/, probes/ and gdocs/.

Note (after pass 9, defect F): the quote above is byte for byte pass 8's hand-back (19,536 characters, compared with the SubagentHandback message in pass 8's transcript). Its line ".gitignore re-includes /src/" should read .gcloudignore: the tree has !/src/ at .gcloudignore:4 and none in .gitignore, and pass 8's own notes (vfy9/REPORT.partial.md) say .gcloudignore. The quote keeps pass 8's word.

4.17 Pass 8 dispositions (fixes in 02b4c3c; record in the commit that adds this section)

How each fix is verified (§3.3): - A test that fails on d7a5af2's code: defect 3, and with it defect 5 and pass 7's N5. Each of its five parts fails when its part of the fix is removed. - A two-way seed test of the new command reader: defect 1 (8 routes it must catch, 6 it must not, among them pass 8's fleet-wide false positive). - The verifiers' own seeds, replayed on the real files: defects 1 and 2. - Record: defect 4, and the sentences pass 8 found false.

The heals are this session's own and therefore non-independent; pass 9 re-checks them before the merge gate. Pass 8's verdicts on the pass-7 items stand as reported (§4.16): N2, N3 (code), N4 and N6 hold; N1, and with it D7, stay PARTIAL (defect 1).

# Finding Disposition Issue Test
Defect 1 (MINOR) the GAQL deploy pin was bypassable by six literal in-repo routes (G1–G6), and the record said otherwise fixed. The cell's Cloud Build file is parsed: exactly the image build, the push and one gcloud run deploy of the cell. Every command under the four roots is read as written: line continuations joined, quotes and YAML list syntax dropped, block lists joined. Such a command may not change a Cloud Run service while naming the cell's service or a pinned key, or while reading a repository file that does. The cell's own configuration files are pinned: no new one names its service or a key. The docstring, API-A12 and the PR body state that reach and the remainder: a by-hand change; a deploy from outside the repository; a name, path or command assembled at run time; a command in a file outside the places read; and a path relative to a step's working directory. Pass 9 (defects A and B): partial. The six routes are caught, but eight more inside the stated reach passed, three of them caught before this fix (X5, X6, X8: regressions): a repeated steps: key that PyYAML reads last and gcloud first, a .txt manifest, a folded YAML scalar, a comment in a block list, a multi-line Python or flow list, YAML escapes, and quotes inside a word. The reach and remainder above were therefore false. Fixed in 9736385 (§4.19) API-A12 test_the_deploy_keeps_live_mutations_off, test_the_deploy_scan_reads_commands_as_written
Defect 2 both pins failed on plausible changes to other services fixed. The GAQL check is per command, not per file. The route's API-key names, which other services share, are looked for only in the console's own files; EMAIL_SERVICE is still looked for everywhere. Pass 8's three false-positive seeds pass. Pass 9: console fixed; GAQL partial: two new false positives, another service's command or env file carrying the cell's URL (defect C). Fixed in 9736385 (§4.19) API-A12, API-G14 the two pins
Defect 3 the totals and the number of status rows were unbounded; with Firestore's encoder, one answer left its record unretirable fixed. The totals stay within 64 bits, a negative count reads as absent, and rows beyond the request's destinations read as absent. With counts, totals, labels and rows bounded, this session knows of no provider answer that produces a value the store refuses. A store failure in one record still stops a sweep, as before. Pass 9 (defect D): that sentence was false. A label carrying a lone surrogate (JSON "\ud800") was kept, Firestore's encoder refuses it, and the record was never retired (measured: 960 raises in 80 h of sweeps); and a label was bounded in characters, not bytes. Fixed in 9736385 (§4.19); the remaining size bound is recorded there API-F6, API-F3 test_status_totals_and_rows_stay_in_what_the_store_holds
Defect 4 (record) wording corrected. Before 49f8d80 the GAQL scan read four suffixes, and the PR body said six for both. "Any spelling" is now "any spelling from the repository root". The escaped-name and working-directory routes are named out of reach. "Never retired" is labelled measured where pass 8 measured it. Pass 9 (defect F): "any spelling from the repository root" was still not literal (a quote inside the path), and the escaped-name route was named out of reach only in the console's docstring. Fixed in 9736385 (§4.19) — —
Defect 5 field warnings kept their reason and field unbounded and of any type fixed: bounded strings, like the status labels API-F6 the same test
N5 (pass 7, re-judged) the deferral's reason covered one of the two fixes an answer with no readable status row is now noted "status read: no readable status rows" in the record's history. The reason vocabulary is unchanged API-F6 the same test

Pass 8's other observations, recorded as given (§4.16): - What it did not check: - live provider behaviour and the serving revisions; - Firestore itself (only its client's offline encoder; the 1 MiB limit is documented); - whether Cloud Build or gcloud would run G1–G6; - the console's suites (CI's Frontend Guard is green); - a DNS audit; - pass 7's hand-back text; - the PR body's edit history, and CI's git version. - Footprint: it read the main checkout only and ran git worktree add/remove there. It removed its worktrees and venvs, and kept its notes in vfy9/.

4.18 Pass 9 — follow-up PR #1302 (d7a5af2..b9a35c6, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 05:12Z to 05:51Z. Its report, verbatim (taken from its hand-back):

Independent verification, pass 9 (blind): d7a5af2..b9a35c6 (draft PR #1302)

Bottom line. I found no blocker and no MAJOR. I found one MINOR (pass 8's defect 1 persists, with three regressions) and five NITs.

  • The range's own claims reproduce.
  • The new Data Manager test fails on d7a5af2's code (1 failed, 55 passed). Each of its five parts fails when I remove it (10 mutations, 1 failed / 55 passed each).
  • Pass 8's kept seeds, paths changed only: the new GAQL pin catches G1–G6 (d7a5af2's pin: 0).
  • All 28 earlier arming routes are caught by both pin versions, and pass 8's three false positives pass.
  • Every gate is green in fresh venvs, except test_wo31_register, which fails identically on 3d5278b (shallow clone).
  • The ledger counts and the API-A13 move are right.
  • MINOR: the GAQL deploy pin is still bypassable by literal in-repo changes.
  • X8, in the cell's own Cloud Build file: a duplicate steps: block passes the new pin. The test's PyYAML keeps the last block; gcloud's own loader (measured offline) keeps the first. So the existing deploy workflow would run services replace on a flipped manifest. d7a5af2's pin caught this.
  • Seven more routes inside the stated reach pass the new pin (X1–X7: a .txt manifest, a folded YAML scalar, a comment in a block list, multi-line flow and Python lists, YAML escapes, quotes inside a word). X5 and X6 were caught by d7a5af2's pin.
  • So the reach and remainder statements in the docstring, API-A12, §4.17 and the PR body are inaccurate.
  • No live mutation can run today: the operation builder still raises NotImplementedError, and its test passes.
  • NITs:
  • two new GAQL false positives;
  • a lone-surrogate label still leaves a Data Manager record never retired (measured: 960 raises in 80 h, with the production lock's Firestore client), so "labels … the store cannot hold … read as absent" is overstated;
  • the row cap reads an extra FAILED row as absent (fail-open, out-of-spec bodies only);
  • "any spelling from the repository root" is not literal;
  • one word in §4.16 is false per the tree, and §4.16 cannot be checked byte for byte because pass 8's hand-back is not on disk.
  • RESUME's own rule ("a blocker, major or minor in the pass-8 heals is fixed and re-checked again") applies to the MINOR.

Pass-8 items

Item Verdict Evidence I produced
Defect 1 (MINOR: GAQL pin bypassable; record) PARTIAL Fixed for the six seeds: G1–G6, replayed from vfy9/probes/seeds9_extra.py and seeds9_extra2.py (paths changed only), each fail exactly test_the_deploy_keeps_live_mutations_off (whole GAQL file). d7a5af2's pin catches 0 of 6.
Not fixed as a class: X1–X8 (defects A and B) pass the new pin. X5, X6 and X8 failed d7a5af2's pin.
Defect 2 (NIT: false positives) Console FIXED; GAQL PARTIAL Fixed: C1 and C2 pass the new inventory pin and fail d7a5af2's. GFP passes the new GAQL pin and fails d7a5af2's.
New: XFP1 and XFP2 fail the new GAQL pin and pass d7a5af2's (defect C).
Defect 3 (NIT: DM totals and rows), code FIXED as scoped Old code, new tests: d7a5af2's code with 02b4c3c's test gives 1 failed (confirmed_events 18446744073709551614), 55 passed.
Each part removed in turn, each making exactly that test fail (1 failed, 55 passed): both clamps, the failed clamp alone, the sent clamp alone, the negative refusal, the row cap, the cap +1, both warning labels, reason alone, field alone, and the note.
Valid bodies: 15 documented-shape status bodies give identical output on both trees. They cover zero counts, a zero error count, rows reversed, rows without destination, three mixed rows, counts as numbers, the int64 max, and fewer rows than destinations. 3 valid ingest warning bodies are also identical.
Defect 3, record INACCURATE in part Labels: a lone-surrogate label still produces the never-retired outcome (defect D).
Rows: "rows the store cannot hold" still occurs at 13 destinations with cap-length 4-byte labels (computed).
Defect 4 (record wording) Mostly ACCURATE Correct now:
- "Six for both" is corrected: d14dba0's GAQL scan read .yml .yaml .sh .py (:988), the console's six (:318).
- "Never retired" is labelled measured.
- The console remainder names working-directory and escaped forms.
Residue:
- "Any spelling … from the repository root" is not literal (Y1, Y2; defect F).
- §4.17 says the escaped-name routes are named out of reach, but the GAQL remainder does not name them (X5).
Defect 5 (NIT: field-warning labels) FIXED reason and field are bounded strings, and each is mutation-pinned. Valid ingest warnings are unchanged. Surrogate residue: defect D.
Pass 8's PARTIAL on N1 Still PARTIAL Defects A and B.
Pass 8's PARTIAL on D7 Still PARTIAL X8 is D7's own class: a step in the cell's Cloud Build file. X1 is G1's class with another suffix.
N5 (pass 7, re-judged) FIXED as worded The note: "status read: no readable status rows" is asserted by the test and pinned by mutation 5.
Its limit: public_view (request_tracking.py:599) returns no history, so callers still see one provider_reported_unknown. The record claims only a history note.

Record items

Item Verdict
API-A12 (pass-8 line, ISSUES.json:1994) Numbers ACCURATE: 6 of 6, and 0 with d7a5af2's pin.
INACCURATE: "read as written: continuations joined, quotes and YAML list syntax dropped, block lists joined", and the out-of-reach list (X1–X8).
API-A13 → REVIEW_READY SOUND. It is the only state change in the range. Its test class (:603) is untouched: 02b4c3c's hunks are at :952–:1144.
API-F3 (:980), API-F6 (:2066) ACCURATE.
API-G14 (:1767) ACCURATE, except "any spelling … from the repository root" (Y1).
EVIDENCE §3.1, §3.5 ACCURATE. Each of 9d9cd01, 49f8d80 and 02b4c3c changes one code file (request_tracking.py); the rest of each, and all of 85b7ecb, are tests.
§3.2 pass-8 block ACCURATE. Reproduced on b9a35c6, which has the same code as 02b4c3c: 97 + 4, 101, 56, 5, 23.
§3.3 pass-8 block, and the marked pass-7 sentence ACCURATE. Every row reproduced: 1 failed / 55 passed; the five parts; 28 of 28 on both versions; G1–G6 6 / 0; GFP; C1–C4; control; B00; B16. The pass-7 sentence matches pass 8's notes.
§4.15 marked rows They record pass 8's findings accurately.
N1's and N3's "Fixed in 02b4c3c" overstate (defects A, B and D).
§4.16 verbatim Not verifiable byte for byte. vfy9/REPORT.partial.md holds pass 8's notes and says "FINAL report = the hand-back"; no copy of the hand-back is on disk.
Agrees: every number, and every line reference I checked at d7a5af2 (deploy-homepage.yml:409, pilot_requests.py:34, RUNBOOK.md:189, klaviyo_feed.py:47, the test and module line ranges, CLOSEOUT:60, :988).
One word differs: EVIDENCE.md:2442 says ".gitignore re-includes /src/"; the notes say .gcloudignore. The tree has !/src/ at .gcloudignore:4 and none in .gitignore.
§4.17 Overstated: the defect-1 and defect-3 dispositions (above).
True as worded: "defect 2 fixed" holds for the three seeds named.
ACCURATE: 4, 5 and N5.
"Knows of no provider answer that produces a value the store refuses" is now superseded by defect D.
Counts and states ACCURATE:
- 65 issues.
- Implementation: 56 / 7 / 2.
- Testing: 55 / 10.
- Review: 55 REVIEW_READY; 4 IN_PROGRESS (A12, F3, F6, G14); 2 OPEN (G10, G11); 4 N/A.
- Deployment: 32 / 3 / 13 / 17.
- Runtime: 48 OPEN, 4 BLOCKED_EXTERNAL, 13 N/A, 0 VERIFIED.
- CLOSEOUT and RESUME match.
CLOSEOUT Counts ACCURATE.
Overstated:
- the Data Manager row (:61) (defect D);
- the pass-8 bullet (:322–:327): "All are fixed in 02b4c3c" and "The record now states each pin's reach and its remainder".
RESUME ACCURATE.
PR body ACCURATE:
- the gate table (every row reproduced);
- the deploy count: the router gives deploy-google-ads-gaql (8), deploy-ui (1) and frontend-guard (1), and the console change against main is 5 comment lines;
- the corrections list.
INACCURATE:
- the GAQL row: "that file, parsed, holds exactly …" (X8), "no command, read as written (continued, quoted, or as a YAML list) …" (X1–X7), and its out-of-reach list;
- the Data Manager row: "labels or rows the store cannot hold … read … as absent" (defect D);
- the console row: "from the repository root" (NIT).
Deployed, verified or safe claims None beyond the evidence. PR #1302 is open, a draft, and not merged (REST read). The ledger has no runtime VERIFIED. The four documents and the PR body agree with each other, including on the overstatements.

New defects

A. MINOR: the Cloud Build pin parses YAML differently from gcloud, so the cell's own Cloud Build file can arm the cell (a regression). - Where: src/cells/google_ads_gaql/tests/test_api_compat_binding.py:1064 (yaml.safe_load) and the docstring :1021–1022. In the record: §4.17 defect 1, API-A12 (ISSUES.json:1994), and the PR body's GAQL row. - Scenario (X8, seeded, restored): - The seed prepends a steps: block to src/cells/google_ads_gaql/cloudbuild.yaml: docker build, docker push, then gcloud run services replace src/cells/google_ads_gaql/gaql_cell/live.yaml. The pinned file follows unchanged. gaql_cell/live.yaml is the reference manifest with GAQL_ENABLE_LIVE_MUTATIONS "true". - Test results: the whole new GAQL test file passes (0 failures). d7a5af2's pin fails test_the_deploy_keeps_live_mutations_off. - gcloud's view: I ran gcloud SDK 530.0.0's own loader on that file, offline under unshare -rn. config.LoadCloudbuildConfigFromPath is the --config path of gcloud builds submit (submit_util.py:300). It returns 3 steps: build, push, run services replace. images are kept, no step carries an env flag, and the only warning is a DuplicateKeyFutureWarning. PyYAML returns the pinned three steps. - deploy-google-ads-gaql.yml submits this file on every push touching src/cells/google_ads_gaql/**. So the merge would replace the service with live mutations on, and the pinned deploy step would never run. - By reading the two loaders' policies (not seeded): a duplicate key inside a step, such as two args:, splits the parsers the same way. - Fix: - Load the file with a loader that refuses duplicate keys anywhere (a SafeLoader whose construct_mapping raises on a repeated key). - Seed X8 in the test. - Or require PyYAML's parse and a first-wins parse to agree.

B. MINOR: the command reader's stated reach is wider than what it parses (defect 1 persists, with two regressions). - Where: test_api_compat_binding.py: - :963: _READ_PATH knows only .yaml .yml .env .json. - :966–986: _commands. A command is one physical line, except contiguous block-list items and backslash continuations. :975 replaces quotes with spaces, while the docstring says they are "dropped". - :993–1006: the per-command check. - :1025–1036: the docstring. - The record is as in A. - Seeds (each restored; results are the whole new GAQL file / d7a5af2's pin): - X1, pass / pass: gaql_cell/live.txt (a flipped manifest copy), plus a new workflow running gcloud run services replace src/cells/google_ads_gaql/gaql_cell/live.txt. gcloud reads FILE through arg_parsers.YAMLFileContents → yaml.load_all_path, with no suffix check (read). - X2, pass / pass: a workflow step run: >- folding gcloud run services replace / src/cells/google_ads_gaql/gaql_cell/live.yaml / --region=… into one command (PyYAML output shown). - X3, pass / pass: deployment/gaql/arm.yaml, a Cloud Build args: block list with a comment line between - run and - services, submitted by a new workflow. The cell's own cloudbuild.yaml has comments between args items. - X4, pass / pass: scripts/arm_gaql.py, a subprocess.run([...]) list over four lines, black style, run by a new workflow. - X7, pass / pass: args: [run, services, replace, / <path>, --region=…] in a Cloud Build file under deployment/. - X5, pass / FAIL: a deploy-google-ads-gaql.yml step run: "gcloud run services update google-ads-gaql\x2Dcell --region=us-central1 --update-env-vars=GAQL_ENABLE_LIVE_MUTATION\x53=true". PyYAML decodes it to the real name and key. - X6, pass / FAIL: the same file with google-ads-gaql-ce''ll … --update-env-vars=GAQL_ENABLE_LIVE_MUTATION''S=true. bash and shlex give the real words. - None of these is a by-hand change, a deploy from outside the repository, something assembled at run time, a command in a file outside the places read, or a path relative to a working directory. So the remainder lists are not the remainder. - Fix: - Parse YAML (duplicate-refusing, as in A) and walk every string and list, joining a list's items. - Split shell strings with shlex, and read Python list literals with ast. - Treat any token that names an existing repository file, of any suffix, as a read. - Or keep the reader, state its parse limits, and seed X1–X8 as known misses in test_the_deploy_scan_reads_commands_as_written. - After three rounds of this class, the owner's decision on API-A12 (a DCP client, or retiring the mutate path) may be cheaper than a fourth round of hardening.

C. NIT: two new GAQL false positives. - Where: :993–1006. Any mention of the cell's name, a URL included, in a command for another service, or in a file such a command reads, counts as a change of the cell. - Seeds: - XFP1: deploy-service-action-runner.yml's --set-env-vars="^|^…" gains |GAQL_CELL_URL=https://google-ads-gaql-cell-698171499447.us-central1.run.app|. Boss already hardcodes that URL (boss_agent_core.py:31553). The new GAQL pin fails; d7a5af2's passes. - XFP2: deployment/ui/runtime-env.yaml with NEXT_PUBLIC_GAQL_CELL_URL: https://google-ads-gaql-cell-… (as env.production.example:25 documents), applied by a deploy-ui step with --env-vars-file. The new GAQL pin fails; d7a5af2's passes. - The real tree: the pin's own reader (extracted with ast) finds 343 service-changing commands under the four roots. It flags 0, and 0 of them read an existing repository file. - Fix: - Take the target from the command: the SERVICE after deploy/update/replace, or metadata.name of a manifest it reads. - For an env file, look only at its keys.

D. NIT (pre-existing; the record overstates the fix): a Data Manager label the store cannot hold still leaves a record unretirable. - Where: - request_tracking.py:328–331 (_label keeps any str) and :163–174 (warnings; description at :173). - The record: CLOSEOUT.md:61, the PR body's Data Manager row, the §4.15 N3 marker, and §4.17 defect 3. - Measured: - What is kept: a JSON "\ud800" in requestStatus, a reference, an error or warning reason, or a field-warning reason, field or description is kept verbatim on both trees. - The encoder: the production lock (google-cloud-firestore 2.19.0, protobuf 5.29.6, Python 3.12.3, as ops/remediation/requirements.lock.txt and Dockerfile.template use). Its _helpers.pbs_for_set_no_merge raises UnicodeEncodeError: surrogates not allowed. - End to end: 80 h of 1-minute sweeps, with that encoder in a memory store's transact_update, gave 960 raises, one every 300 s. The record stayed submitted with 0 checks and its claim held, past the 72 h TTL, so it was never retired. The other two records succeeded. d7a5af2 behaves identically. - Size: MAX_LABEL counts characters, not bytes, and the service does not cap destinations. 13 destinations × (50 + 50 counts) × 200 four-byte characters = 1,091,341 bytes by Firestore's documented size formula (computed, not run). Documented reason enums alone stay under 1 MiB up to 250 destinations. - Fix: - Keep a label only if it encodes as UTF-8, and bound labels in bytes. - Or retire a record after N consecutive store failures. - Correct the CLOSEOUT and PR body wording.

E. NIT: the row cap fails open on an over-long answer. - Where: request_tracking.py:354–359. - Measured: - 1 destination answered [SUCCESS, FAILED]: d7a5af2 reads partial, failed 5; head reads success, applied true, failed 0. - 2 destinations answered [A, A duplicate, B FAILED]: partial on d7a5af2, success on head. - Both are outside the documented shape: no valid body changed (15 checked). - Fix: store at most expected rows, but read an answer with more rows than destinations as unknown (or note it).

F. NIT (record): wording. - "Under any spelling of its path from the repository root" (inventory docstring :318, GAQL docstring :1023, API-G14, API-A12, PR body): _configs and _normalized_configs (:268, :1012) strip only the outer quotes. - Y1: a new workflow with --config="miz-oki-command-center-ui"/cloudbuild.yaml --substitutions=_IMAGE_TAG=…,_REQUIRE_AUTH=false passes both inventory pins. - Y2: --config="src/cells/google_ads_gaql"/cloudbuild.yaml passes both GAQL pins. - Neither arms anything by itself. - §4.16 (EVIDENCE.md:2442): ".gitignore", where the tree has .gcloudignore:4. A bracketed note would keep the quote verbatim and true. - §4.17 defect 4: "the escaped-name … routes are named out of reach" is true only of the console docstring.

Observation (pre-existing, outside the range, by reading): on the accept and reject paths, request_id (main.py:257) and last_error (request_tracking.py:285–286, from up to five 4xx reasons) are still stored unbounded and of any type.

Test runs

Environment for every run: - Fresh python3.11 -m venv (CPython 3.11.15, pytest 9.1.1). The rem venv was Python 3.12.3. - env -i with a whitelist: no proxy, GH, GCP or AWS variables. - TMPDIR=/tmp/v10/<run>. - Commit signing off through GIT_CONFIG_* environment variables only. - Everything ran under unshare -rn.

The venvs: - ci: ci.yaml's Install Dependencies line, the consolidated-tests line, -e contracts, and the whitepaper requirements. - wire: the suite-wiring line. - gates: the governance-gates line. - lock: src/cells/google_ads_gaql/requirements.lock.txt, then pytest (google-ads 33.0.0, fastapi 0.109.1, pydantic 2.5.0). - cing: the deploy-service-canonical-ingestion.yml gate line (google-cloud-firestore 2.34.0). - rem: ops/remediation/requirements.lock.txt, plus contracts with --no-deps.

Command Env Result
pytest tests/governance -c tests/governance/pytest.ini @b9a35c6 ci 4351 passed, 7 skipped, 6227 subtests passed, rc 0 (418.8 s)
python -m pytest "services/service-data-manager-connector/tests" -q -p no:cacheprovider -o addopts="" (MIZOKI_STORE=memory) wire 56 passed
same flags, "src/cells/google_ads_gaql/tests" wire / lock 97 passed + 4 skipped / 101 passed
tests/remediation/test_gaql_governance_wiring.py; pytest tests/remediation -q wire / cing 5 passed; 396 passed
"docs/audits/tests" @b9a35c6 and @3d5278b (my own worktree) wire 1 failed (test_wo31_register, git show 26bec9c6b… rc 128; the object is absent), 7 passed; identical on both
tests/governance/test_api_lifecycle_inventory.py -c tests/governance/pytest.ini ci 23 passed
bash .github/scripts/content_gates.sh gates venv first on PATH rc 0, 155 passed
api_lifecycle_check.py / gate_leak_scan.py --check / claude_memory.py check --strict / check_canon_docs.py --self-test and plain gates rc 0 each: FAILURES 0, WARNINGS 1, UNKNOWNS 20 / 74 invalidated, 0 new, 0 grown, 0 stale / valid / 48 files, 8 held, 0 new
deploy_router.py --base fa1cc19 --head b9a35c6 gates 21 files → deploy-google-ads-gaql (8), deploy-ui (1), frontend-guard (1)
d7a5af2's code with 02b4c3c's DM test file wire 1 failed (the named test), 55 passed
10 mutations of the DM fix on b9a35c6 wire each: exactly the named test fails (1 failed, 55 passed); restored clean
Pass 8's seeds (seeds9*.py, paths only), groups p, n, m, b, v ci + wire 28 of 28 caught on both pin versions, each failing exactly its pin; G1–G6 new 6 / old 0; GFP, C1 and C2 pass new (fail old); C3, C4, G0, B00 and B16 pass both
Own seeds X0–X8, XFP1–2, Y1–2 (same driver) ci + wire as in defects A, B, C and F; X0 passes all
DM probes (dm_probe10.py, dm_surrogate_sweep.py, dm_size.py) wire / rem as in defects D and E
gcloud SDK 530.0.0 LoadCloudbuildConfigFromPath on X8 bundled python, unshare -rn, throwaway CLOUDSDK_CONFIG 3 steps: build, push, run services replace
PR #1302 check runs on b9a35c6 gh api REST, read-only 28: 27 success, 1 skipped (Live Cell Endpoint Tests)

What I did not check

  • Live provider behaviour and the serving revisions.
  • Firestore itself: I used only its client's offline encoder, and computed the 1 MiB limit with the documented size formula.
  • Whether GitHub Actions and Cloud Build would execute X1–X8 end to end:
  • Measured: gcloud's config loader for X8, and the PyYAML, bash, shlex and ast decodings.
  • Read only: GitHub's YAML escapes, and gcloud's suffix-free FILE reading for X1.
  • The console's vitest, tsc and Playwright suites (CI's Frontend Guard is green on b9a35c6).
  • A DNS audit.
  • Pass 8's hand-back text, which is not on disk.
  • The PR body's edit history, and CI's git version.

Disclosures

  • Main checkout:
  • I read it only, with GIT_OPTIONAL_LOCKS=0, and ran git worktree add/remove there.
  • At the end: status clean, HEAD b9a35c6, 0 stashes. I did not touch base or memwt2.
  • My worktrees: I created and removed 8 under vfy10 (head, prev, mut, mut2, mut3, dmold, dmmut, w3d).
  • I seeded only mut, mut2, mut3, dmold and dmmut.
  • I restored them with git checkout/git clean and file copies; I used no stash.
  • Cleanup: I removed all venvs and /tmp/v10. No /tmp/wo26-* or /tmp/v417-* entries were left.
  • Read outside vfy10: vfy9/REPORT.partial.md and vfy9/probes/*, plus directory listings. I opened none of the builder's other files.
  • Network:
  • PyPI installs;
  • 5 read-only fetches of Google Data Manager reference pages (4 × 200, 1 × 404);
  • GitHub REST reads of PR #1302 and its check runs. One gh pr view went to GraphQL and was refused (403) before any data was read.

I made no provider call. - Deviations from CI: - plain venvs rather than setup-python; - -rf/-rfs added on some runs; - env -i with a whitelist; - the seed driver keeps the shell's non-proxy variables (it is pass 8's, unchanged), but every pytest in it ran under unshare -rn. - No writes: no pushes, comments, reviews, records, deploys or dispatches. - Kept in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy10/: REPORT.partial.md (it also holds this report), FINAL.md (this report), logs/ and probes/ (seed drivers and own seeds), and gdocs/.

4.19 Pass 9 dispositions (fixes in 9736385; record in the commit that adds this section)

How each fix is verified (§3.3): - Tests that fail on b9a35c6's code (with 9736385's Data Manager tests: 3 failed, 55 passed): defect D, from a store that refuses what Firestore's encoder refuses (UnicodeEncodeError: surrogates not allowed), and defect E, twice (success where unknown is due; one of the two is pass 8's own test, whose baseline moved). Each of the five parts of the Data Manager fix fails its test when it is removed. - Two-way seeds of the deploy pins: test_the_deploy_scan_reads_commands_as_written now holds: - 16 commands it must catch and 9 it must not (XFP1 and XFP2 among them); - 7 files it must flag once decoded (X2 to X5, X7, a repeated key, and a key a shell reads through quotes in a Python constant) and 3 it must not; - names of the cell (4 that count, 3 that do not, URLs among them); - deploy-workflow commands through a variable (3 caught, 2 legal); - config spellings (3 that are the cell's file, 1 that is not); - the strict reader's 5 refusals and 1 acceptance.

Each of the pin's 14 rules, removed in turn, makes this test fail (§3.3). test_config_spellings_and_the_strict_reader does the same for the console pin (Y1's spelling). - The verifiers' own seeds, replayed on the real files (pass 9's seeds10_own.py, seeds10_y.py and seeds10_z.py, pass 8's seeds9.py, seeds9_extra.py and seeds9_extra2.py, paths changed only), against 9736385's pins and the pins pass 9 reviewed: §3.3. - Record: defect F, and the sentences pass 9 found false.

The heals are this session's own and therefore non-independent; pass 10 re-checks them before the merge gate. Pass 9's verdicts on the pass-8 items stand as reported (§4.18): defect 2 (console), defect 3 (as scoped), defect 5 and N5 hold, and defect 4 holds but for the wording in defect F; defect 1, and with it N1 and D7, stay PARTIAL (defects A and B). The three routes the pin had caught before pass 8's rewrite and stopped catching (X5, X6, X8) are regressions of 02b4c3c, this session's own.

# Finding Disposition Issue Test
A (MINOR) the cell's Cloud Build file was read by PyYAML, which keeps the last of two repeated keys while gcloud keeps the first: a steps: block placed first armed the cell (X8, a regression) fixed. Both Cloud Build pins (the GAQL cell's and the console's) read their file with a reader that refuses a repeated key, an anchor, an alias or a merge key, and more than one document, so the steps they check are the steps any YAML reader reads. The GAQL pin also checks the decoded arguments: only the deploy's one env map names a pinned key or sets env, and none merges env or reads an env or flags file. Pass 10 (defect 2): not any YAML reader. gcloud's own loader does not end a plain scalar at U+2028, U+2029 or U+0085, and PyYAML does (Z6, Z6b). Fixed in d1e1e7b (§4.21) API-A12, API-G14 test_the_deploy_keeps_live_mutations_off, test_the_console_email_route_stays_unarmed_on_deploy, both seed tests
B (MINOR) the command reader's stated reach was wider than what it parsed: X1 to X7 passed (X5 and X6 regressions) fixed. Every file under the four roots is read as written and decoded: the scalars of any file that parses as YAML (JSON too; escapes, folded and literal blocks, flow lists over several lines, comments in block lists, and a repeated key read in both places) and a Python file's string constants, each list of either joined into one string. Words are split as a POSIX shell splits them, so quote marks inside a word are removed (ce''ll is cell). A command reads any repository file it names, of any suffix, decoded the same way, and a pipeline stays one command. The cell's own files other than its Python code and Markdown are read the same way, under its code directory too. Only three listed files under the four roots may name the cell's service as a word (its deploy workflow, the fleet state check's default list, the console's invoker-grant targets), so a new one, a Terraform resource say, fails until it is reviewed; and the deploy workflow runs no command that changes a Cloud Run service, whatever it targets (self-found, below). The class docstring, API-A12 and the PR body state this reach, and the remainder: a by-hand change; a deploy from outside the repository; anything assembled at run time (a variable set outside the file, an expression, a concatenation, a glob, stdin) or encoded in a form not decoded here (a Python bytes literal, ANSI-C shell quoting); a service-changing command in a listed file other than the deploy workflow that targets the cell through a variable (the fleet state check's loop); a command in a file outside the places read (a new top-level directory, the cell's Python code, the documentation); and a path relative to a step's working directory. Pass 9's remark that the owner's API-A12 decision may now be cheaper than another round of hardening is carried to CLOSEOUT. Pass 10 (defect 1): partial again. Eight more routes inside this reach passed (Z1 to Z5, Z8 to Z10), and Z4, Z5 and Z9 were regressions. "As a POSIX shell splits them" was not literal. Fixed in d1e1e7b, where the docstring states only what the pin checks (§4.21). Pass 11 (defect 1): not so. The docstring said no scanned file names the reference manifest, and the cell's own files were not checked for it. Its config checks joined no backslash-newline, and it had dropped stdin and a listed file's variable target from what it does not check. Fixed in 8c4f986 (§4.23) API-A12 the same tests
C two new GAQL false positives: another service's command or env file carrying the cell's URL fixed. A command targets the cell only through its service as a word of its own (not inside a URL or a flag's value), a pinned key, or a file it reads that names one or is a manifest for the cell (metadata.name); an env file counts only through a pinned key. XFP1 and XFP2 are seeded legal API-A12 test_the_deploy_scan_reads_commands_as_written
D a label the store cannot encode (a lone surrogate) left its record never retired, and labels were bounded in characters; the record overstated the fix fixed. A label is kept only if it is valid Unicode, cut to 200 bytes of UTF-8 at a character boundary; a field warning's description likewise (300 bytes). The size half is recorded, not changed: with labels bounded in bytes, a status row is at most about 23 KB by Firestore's documented size formula, so a request with 45 or more destinations whose answer carried maximal labels could still exceed the 1 MiB document limit, and that record would not be retired (computed, not run: 1,030,366 bytes at 44 destinations, 1,077,012 at 46; §3.3). CLOSEOUT and the PR body say so. Pass 10 (NIT 3): the ingest answer's own field warnings count too. With 50 maximal ones, 44 destinations suffice: 1,068,957 bytes, re-measured in §3.3. The bound now reads "44 or more (45 without field warnings)". Pass 11 (NIT 4): the record's bounded history counts too. With 20 failed status reads recorded, 43 destinations suffice: 1,051,932 bytes, re-measured in §3.3. The bound now reads "43 or more once the history is full (45 without field warnings)" API-F6 test_a_label_the_store_cannot_encode_reads_as_absent
E the row cap read an extra FAILED row as absent, so an over-long answer read as success fixed. An answer with more rows than the request had destinations reads as unknown, one row per destination is kept, and the history notes "status read: more status rows than the request's destinations" API-F6 test_an_answer_with_more_rows_than_destinations_is_unknown
F (record) "any spelling of its path from the repository root" was not literal; §4.16's .gitignore; §4.17's line on the escaped-name route fixed. Quote marks inside a --config path are removed in both pins (Y1 and Y2 are now caught), and the docstrings say "any spelling this test normalizes". §4.16's quote is byte for byte pass 8's hand-back, so it keeps the word, and a note after it gives .gcloudignore. §4.17's defect-4 row is annotated API-G14, API-A12 test_config_spellings_and_the_strict_reader, the GAQL seed test
Observation request_id and last_error on the accept and reject paths are stored unbounded and of any type recorded for the owner, not changed (outside the range). A write that fails there leaves the record submission_in_flight; recover_stale_sends turns it into submission_outcome_unknown after DM_SEND_GRACE_SECONDS, and it is never re-sent automatically API-F6 —

Self-found, not verifier findings; non-independent, and pass 10 reads them: - The deploy workflow's own variable. Re-reading these heals: the cell's deploy workflow sets SERVICE_NAME: google-ads-gaql-cell, so a step there running gcloud run services update ${{ env.SERVICE_NAME }} (with --image, say) passed the first version of this fix, and b9a35c6's pin too; d7a5af2's file-wide rule caught it. The deploy workflow now runs no command that changes a Cloud Run service, and only the three files in _NAMES_THE_CELL may name the cell's service as a word under the four roots. Both are seeded in test_the_deploy_scan_reads_commands_as_written. Pass 10 (defect 1): "runs no command that changes a Cloud Run service" was false. A gcloud run --quiet services update, a curl to the Run Admin API and the deploy-cloudrun action passed (Z5, Z8, Z10). Fixed in d1e1e7b: the workflow is now pinned byte for byte as well (§4.21). - The ledger's next actions. While preparing the closeout: 14 next_action lines in ISSUES.json still named the work they had been opened for (11) or a RESUME section that does not exist (3: API-E4, API-C5, API-F5). Each now names its actual next action, as CLOSEOUT's blockers table does.

Pass 9's other observations, recorded as given (§4.18): - What it did not check: - live provider behaviour and the serving revisions; - Firestore itself (only its client's offline encoder; the 1 MiB limit by the documented size formula); - whether GitHub Actions and Cloud Build would run X1 to X8 end to end (gcloud's own config loader was run on X8); - the console's suites (CI's Frontend Guard is green on b9a35c6); - a DNS audit; - pass 8's hand-back text (§4.16's note answers it); - the PR body's edit history, and CI's git version. - Footprint: it read the main checkout only and ran git worktree add/remove there. It removed its worktrees and venvs, and kept its notes in vfy10/.

4.20 Pass 10 — follow-up PR #1302 (b9a35c6..4e1fe7a, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 07:43Z to 08:37Z. Its report, verbatim (taken from its hand-back):

Independent verification, pass 10 (blind): b9a35c6..4e1fe7a (draft PR #1302)

Bottom line. I found no blocker and no MAJOR. I found two MINORs in the GAQL deploy pin and four NITs.

  • What the range claims reproduces.
  • On b9a35c6's code with 9736385's Data Manager tests, 3 tests fail and 55 pass. Each of the five parts of the Data Manager fix fails its own test when I remove it.
  • Each of the 14 listed GAQL pin rules, removed in turn, gives 1 failed and 3 passed.
  • I replayed all 55 kept seeds and got exactly §3.3's table.
  • Every gate is green in fresh venvs, except test_wo31_register, which fails the same way on 3d5278b (shallow clone).
  • §4.18 is pass 9's hand-back byte for byte (23,535 characters). §4.16 is pass 8's byte for byte (19,536).
  • The ledger counts are right, and no state changed in the range.
  • MINOR 1: the GAQL deploy pin is still bypassable by literal in-repo changes.
  • Eight new seeds inside the stated reach pass the whole new GAQL test file (Z1–Z5, Z8–Z10).
  • Z9 is a regression of 9736385: both b9a35c6's pin and d7a5af2's pin catch it.
  • Z4 and Z5 are 02b4c3c regressions that 9736385 set out to close. d7a5af2's pin catches both.
  • So the stated reach and remainder are untrue again. This covers the docstring, API-A12, §4.19 (B and the self-found item), CLOSEOUT and the PR body. Specifically, "the deploy workflow runs no command that changes a Cloud Run service" is false.
  • MINOR 2: the strict reader does not make "every YAML reader" agree.
  • gcloud 530.0.0's own loader (ruamel 0.15.93) does not end a plain scalar at U+2028, U+2029 or U+0085. PyYAML does.
  • A seeded cell Cloud Build file passes the whole pin, yet gcloud deploys GAQL_DRY_RUN_DEFAULT as true
- --no-allow-unauthenticated. The cell reads that as False. This was measured with gcloud's own loader and its own env-var parser.
  • A second variant drops the env map from gcloud's view entirely.
  • No live mutation can run today. The operation builder raises NotImplementedError both at the head and on the deployed cb7b7ff, and its test passes.
  • NITs:
  • a step-level env hook in the Cloud Build file is unpinned;
  • the env-flag alternatives of _CHANGES_A_SERVICE are pinned by no seed;
  • the Data Manager size bound "45 or more" ignores the ingest answer's field warnings: 44 destinations suffice;
  • the new API-F5 next_action names a validate-only request, which creates no record to read.
  • RESUME's rule ("a blocker, major or minor in the pass-9 heals is fixed and re-checked again") applies to both MINORs.
  • This is the fifth round in which the pin's stated reach was wider than what it parses. Pass 9 suggested the owner's API-A12 decision might be the cheaper exit; that applies with more force now.

Pass-9 items

Item My verdict Evidence I produced
A (MINOR: repeated steps: key) PARTIAL Closed: the duplicate-key class (X8) is caught (replayed). The strict reader refuses all five of its seeded texts (repeated key ×2, alias, merge key, second document); removing any one of those refusals fails the seed test.
Still open: the docstring sentence "so that every YAML reader reads it the same way" (test_api_compat_binding.py:1237–1238) is false for gcloud's own loader.
How I found it: a 4,000-insertion differential fuzz of the real file plus targeted cases, comparing PyYAML 6.0.3 with gcloud 530.0.0's LoadCloudbuildConfigFromPath offline under unshare -rn. A U+2028, U+2029 or U+0085 inside a plain scalar joins the next list item in gcloud's view only.
Seeds Z6 and Z6b: below, new defect 2.
B (MINOR: reach wider than parsed) PARTIAL Closed: X1–X7 are caught; the replay matches §3.3.
Still open: routes inside the restated reach pass the whole new GAQL file:
- Z1/Z2: a backslash-newline inside a word.
- Z3/Z4/Z5: a gcloud global flag between run and the verb.
- Z8/Z10: a service change made without the gcloud CLI.
- Z9: a nested shell in a listed file.
Details are in new defect 1.
C (false positives) FIXED XFP1 and XFP2 pass the new pin and fail b9a35c6's (replayed). The legal seeds are load-bearing against the broadenings I tried: dropping targeting fails 7 of them, a substring cell name fails legal07, treating describe/submit as changes fails 5, and any manifest name fails legal04.
D (lone-surrogate label) FIXED (encoding)
Size half: recorded, bound slightly off
Encoding: the label test fails on b9a35c6's code with UnicodeEncodeError … surrogates not allowed. Removing the Unicode check, the byte bound or the description bound each fails it (1F/57P).
Size: see NIT 3.
E (over-long answer read as success) FIXED Tests: the rows test and pass 8's test fail on old code. Removing the rule gives 2F/56P; removing the note gives 1F/57P.
Valid bodies: 15 documented-shape status bodies give identical output on both trees.
F (record wording) FIXED Y1 fails the new console pin and Y2 the new GAQL pin; neither failed b9a35c6's pins.
Stripping only outer quotes, or removing any strict-reader rule, fails test_config_spellings_and_the_strict_reader (4 mutations).
The note after §4.16 is accurate: .gcloudignore:4 is !/src/, and .gitignore has no !/src/.
Observation (request_id, last_error) Disposition SOUND By reading: a refused accept or reject write leaves the record submission_in_flight (main.py:312–364). recover_stale_sends later writes submission_outcome_unknown without the bad field, and begin_submission refuses a re-send unless resubmit_of names it.
Not stated: a provider-rejected request then ends unknown, not failure. This is the conservative direction.
Pass 8 defect 1 / pass 7 N1 / pass 6 D7 PARTIAL Defect 1 and N1: new defect 1.
D7's class (a step in the cell's own Cloud Build file) is still open via Z6/Z6b (new defect 2) and Z7 (NIT 1).
Pass 8 defect 2 FIXED C1, C2 and GFP pass; XFP1 and XFP2 pass.
Pass 8 defect 3 FIXED as scoped Pass 8's test passes at the head. Pass 9's fail-open (E) is now closed.
Pass 8 defect 4 ACCURATE The wording is now "any spelling … this test normalizes". The escaped forms are named in both remainders.
Pass 8 defect 5 FIXED Reason, field and description are byte-bounded strings, each mutation-pinned.
Pass 7 N5 FIXED as worded The "no readable status rows" note is unchanged. The new "more status rows…" note is mutation-pinned. public_view still returns no history (pass 9's limit stands).

Record items

Item Verdict
API-A12 pass-9 line (ISSUES.json:1997) Replay numbers ACCURATE: 8/0, Y2, the 34 earlier routes, and the 14 rules.
INACCURATE: the reach ("words split as a POSIX shell splits them") and the "Out of reach" list. New defects 1 and 2.
API-A13 line ACCURATE. 9736385's hunks in the GAQL test file start at line 959; the registry-check class at :603 is untouched.
API-F3 line ACCURATE.
API-F6 line (:2071) ACCURATE: 3/55, the five parts, and 58.
Not reproduced byte for byte: the size figures (NIT 3).
API-G14 line ACCURATE: Y1 is caught, and B01–B11 and V01–V09 are still caught.
review_track_note, publication ACCURATE. PR #1302 is open, a draft and not merged (REST read).
14 next_action lines 13 ACCURATE, checked as follows:
- RESUME@b9a35c6 has no read-only-checks section, and CLOSEOUT has the rows they now point to.
- B8: the router's own build_plan(['connectors/meta_signals/client.py']) returns [], cell37 is dispatch-only, and only cell37's Dockerfile copies connectors/.
- F1–F4, G3, G9: no workflow deploys them and the router returns [].
- G1: checked_at 2026-10-01, fail at 365 days, warn at 120, present at cb7b7ff.
- G2, G7, G8: checked.
API-F5 half-INACCURATE (NIT 4).
EVIDENCE §3.1, §3.2 (pass-9), §3.5 ACCURATE. I reproduced 97+4, 101, 58, 5 and 24. Each of 9d9cd01, 49f8d80, 02b4c3c and 9736385 changes one code file, request_tracking.py.
"About 13 s" measured 19.6 s here; that is machine-dependent, not a defect.
§3.3 pass-9 block ACCURATE: the DM rows, the 14 rules and the seed table.
Not reproduced: the size bytes (23,253 per row; 1,030,366 at 44).
§4.15 N1, N3; §4.17 defects 1–4 ("Pass 9" annotations) Accurate as records of pass 9.
Overstated: "Fixed in 9736385" on N1 and defect 1 (new defects 1 and 2).
§4.18 Verbatim. Stripping > gives 23,535 characters, identical to the SubagentHandback input.message (transcript line 571).
Note after §4.16 ACCURATE. It is 19,536 characters, identical to pass 8's hand-back (transcript line 516).
§4.19 C–F, the Observation and the seed-test counts: ACCURATE. The counts are 16/9, 7/3, 4/3, 3/2, 3/1 and 5/1.
INACCURATE:
- A: "so the steps they check are the steps any YAML reader reads" (EVIDENCE.md:2932).
- B's reach and remainder (:2933).
- The self-found "The deploy workflow now runs no command that changes a Cloud Run service" (:2946).
D's bound: NIT 3.
CLOSEOUT, RESUME Counts ACCURATE. I recomputed 65; 56/7/2; 55/10; 55 REVIEW_READY, 4 IN_PROGRESS (A12, F3, F6, G14), 2 OPEN, 4 N/A; 32/3/13/17; 48/4/13 and 0 VERIFIED.
INACCURATE: CLOSEOUT.md:352 ("That workflow may now run no command that changes a service").
NIT 3: the "45 or more" at CLOSEOUT.md:61 and RESUME.md:147.
PR body ACCURATE:
- the gate table, every row reproduced;
- the deploy count (21 files → deploy-google-ads-gaql 8, deploy-ui 1, frontend-guard 1; the console change is 5 comment lines);
- the tests paragraph;
- #1303 is memory-only (5 files), a draft.
INACCURATE: the GAQL row's reach and remainder.
NIT 3: the Data Manager row.
Deployed, verified or safe claims None beyond the evidence. Check runs on 4e1fe7a: 28 (27 success, 1 skipped). The four documents and the PR body agree with each other, including on the overstatements.

New defects

1. MINOR: the deploy pin's command reader and service-change recognizer still fall short of the stated reach.

Where: - src/cells/google_ads_gaql/tests/test_api_compat_binding.py: - :1092: a continuation is joined with a space; - :960–961: _CHANGES_A_SERVICE needs run adjacent to the verb and recognizes gcloud text only; - :1204: the cell is targeted only as a separate word; - :1144: _service_changes; - :1236–1274: the docstring. - The record: ISSUES.json:1997, EVIDENCE.md:2933 and :2946, CLOSEOUT.md:352, and the PR body's GAQL row.

Seeds. I used pass 8's driver with paths changed. Every seed below passes the whole new GAQL file and b9a35c6's pin unless I note otherwise. - Z1: a step in the deploy workflow: gcloud run services upd\ ate ${{ env.SERVICE_NAME }} --region=… --update-env-v\ ars=GAQL_ENABLE_LIVE_MUTATI\ ONS=true bash --noprofile --norc -eo pipefail (GitHub's default) runs gcloud run services update google-ads-gaql-cell … --update-env-vars=GAQL_ENABLE_LIVE_MUTATIONS=true (measured with a stub gcloud). POSIX removes a backslash-newline; the pin replaces it with a space. - Z2: a new workflow with the cell's name and the key split the same way. The naming rule does not see the name. - Z3: a new workflow running gcloud run --quiet services replace src/cells/google_ads_gaql/LIVE.md, where LIVE.md is a flipped manifest copy. - gcloud 530.0.0, offline, parses this as gcloud.run.services.replace and loads the .md FILE. - The pin never treats the command as a change, so it never reads the file. - Z4: Z3's command in the deploy workflow (d7a5af2's pin catches it). - Z5: gcloud run --quiet services update ${{ env.SERVICE_NAME }} --image=…/google-ads-gaql-cell:other in the deploy workflow. This deploys the cell another way. I measured the parse of gcloud run --quiet services update …. d7a5af2's pin catches it. - Z8: in the deploy workflow, curl -X PATCH …run.googleapis.com/v2/…/services/${{ env.SERVICE_NAME }}… --data-binary @src/cells/google_ads_gaql/ARM.md, with a body that sets the key. The pin passes; the API behaviour is by reading only. - Z10: a deploy-workflow step uses: google-github-actions/deploy-cloudrun@v2 with metadata: docs/gaql-live-manifest.yaml. The pin passes; the action's behaviour is by reading only. - Z9 (regression of 9736385): in the listed verify-cloudrun-state.yml, a step bash -c "gcloud run services update google-ads-gaql-cell --region=us-central1 --env-vars-file=docs/gaql-live-env.yaml". - _GAQL_SERVICE in words cannot see a name inside the quoted string. - _reads cannot see the file either, because split("=", 1) takes the region. - b9a35c6's and d7a5af2's pins both fail it. - Z11 (control): replace /dev/stdin <LIVE.md also passes, but "stdin" is in the stated remainder.

Fix: - Remove backslash-newline before splitting, with no replacement. - Recognize gcloud commands by tokens (gcloud [track] [flags] run [flags] deploy|services [flags] replace|update). - Count deploy-cloudrun steps and run.googleapis.com calls as service changes. Better, pin the deploy workflow's step list exactly. - Re-split bash -c, sh -c and eval strings, or pin the listed files' contents. - Or state the parser's actual limits in the docstring and the record instead of "as a POSIX shell".

2. MINOR: _strict_yaml accepts Cloud Build texts that gcloud reads differently.

Where: - the GAQL test, :964–985, :1237–1238 and :1303–1314; - the governance test, :273–294 and :348–350; - EVIDENCE.md:2932 and the PR body.

Z6. I reordered the env map so GAQL_DRY_RUN_DEFAULT comes last, then put U+2028 and - --no-allow-unauthenticated on the same physical line. - The whole new GAQL file passes, and so do b9a35c6's and d7a5af2's pins (pre-existing). - gcloud's loader gives one argument: --set-env-vars=…,GAQL_DRY_RUN_DEFAULT=true
- --no-allow-unauthenticated. - gcloud's ArgDict(EnvVarKeyType, EnvVarValueType) yields the value true
- --no-allow-unauthenticated. U+2029 behaves the same; U+0085 gives true - --no-allow-unauthenticated. - The cell's _flag logic then reads dry_run_default False. - gcloud run deploy <those args> parses offline (it stops at auth). - --no-allow-unauthenticated is no longer a separate argument.

Z6b. - --description=GAQL cell + U+2028 before the env map. - gcloud's arguments then carry no --set-env-vars at all, and they parse. - So the deploy no longer resets env, and the remainder's premise "the next deploy replaces it" fails.

The console pin. Its reader accepts the console file with - --timeout=300 U+2028 - --description=console; gcloud reads that as one argument. I found no arming consequence, because EMAIL_SERVICE must still be named somewhere.

Fix: - Refuse U+0085, U+2028 and U+2029, or simply any non-ASCII, in both Cloud Build files. - Or also parse with gcloud's ruamel pinned at 0.15.93 and require the two readers to agree.

NITs

NIT 1: other fields of the Cloud Build steps are not pinned. - Where: :1303–1314, which reads only each step's name, entrypoint and args. - Scenario: Z7 adds env: [CLOUDSDK_PYTHON=/bin/sh, CLOUDSDK_PYTHON_ARGS=/workspace/src/cells/google_ads_gaql/HOOK.md] to the deploy step. The whole pin passes. The gcloud wrapper (bin/gcloud:199, 530.0.0) runs exec "$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS …/gcloud.py "$@", so the "one gcloud run deploy" becomes any script in the build context. - Fix: pin each step's key set and the top-level key set.

NIT 2: part of _CHANGES_A_SERVICE is seeded by nothing. - Where: :1370–1484. - Measured: removing --env-vars-file|--(set|update)-env-vars from _CHANGES_A_SERVICE (either part, or both) leaves all 57 seed checks green, in my per-seed matrix of 30 removals and 4 broadenings. - Why it matters: those alternatives are what catch an env change written with an interposed flag (gcloud run --quiet services update X --update-env-vars=…). - Fix: add such a seed.

NIT 3: the recorded Data Manager size bound ignores field warnings. - Where: ISSUES.json:2071, §4.19 D, CLOSEOUT.md:61, RESUME.md:147, the PR body. - Measured: I computed with the head's begin_submission → record_accepted → reconcile_record and Firestore's documented formula. - A row with every label at 200 bytes is 23,376 bytes (23,183 with a SUCCESS status; the record says 23,253). - With no field warnings: 44 destinations give 1,032,557 bytes (under the limit) and 45 give 1,055,999 (over). So "45" holds for that composition. - The ingest answer's own 50 maximal field warnings add 36,400 bytes. With them, 44 destinations give 1,068,957, over the limit. - Docs: events.ingest (read-only fetch) states no maximum number of destinations. - Fix: say "44 or more (45 without field warnings)", or bound the record's total size.

NIT 4: the new API-F5 next_action names a validate-only request. - Where: ISSUES.json:1034; the unchanged CLOSEOUT.md:146 row has the same wording. - Problem: it says to run the check "on a request made by a sanctioned validate-only or test flow". But a validate-only upload creates no tracking record (main.py:312–318: record = None unless the upload is not validate-only). So GET /api/v1/upload-requests/{record_id}?refresh=true cannot run on one. - Fix: name a test flow only.

Design note (not a defect). Any new file under the four roots that names the cell as a word fails until it is listed; a read-only fleet script is an example. Once a file is listed, only _gaql_changes guards it, which is weaker (see Z9).

Test runs

Environment for every run: - Fresh python3.11 -m venv (CPython 3.11.15, pytest 9.1.1, PyYAML 6.0.3). - env -i with a whitelist: no proxy or credential variables. - TMPDIR=/tmp/v11/<run>. - Commit signing off through GIT_CONFIG_* only. - Everything ran under unshare -rn.

The venvs: - ci: ci.yaml's Install Dependencies, the consolidated extras, -e contracts and the whitepaper requirements. - wire: the suite-wiring line, with MIZOKI_STORE=memory. - gates: the governance-gates line. - lock: the GAQL requirements.lock.txt, then pytest.

Command (at 4e1fe7a unless noted) Env Result
pytest tests/governance -c tests/governance/pytest.ini ci 4352 passed, 7 skipped, 6227 subtests, rc 0 (485 s)
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" wire / lock 97 passed + 4 skipped / 101 passed, rc 0
same, "services/service-data-manager-connector/tests" wire 58 passed
same, tests/remediation/test_gaql_governance_wiring.py wire 5 passed
same, "docs/audits/tests", at head and on my own 3d5278b worktree wire 1 failed (test_wo31_register: object 26bec9c6b… absent), 7 passed, identical on both
tests/governance/test_api_lifecycle_inventory.py ci 24 passed, rc 0
bash .github/scripts/content_gates.sh gates on PATH 155 passed, rc 0
api_lifecycle_check.py / gate_leak_scan.py --check / claude_memory.py check --strict / check_canon_docs.py (--self-test and plain) gates rc 0 each:
- FAILURES 0, WARNINGS 1, UNKNOWNS 20;
- 74 invalidated, 0 new, 0 grown, 0 stale;
- valid;
- 48 files, 8 held, 0 new
deploy_router.py --base fa1cc19 --head 4e1fe7a gates 21 files → deploy-google-ads-gaql 8, deploy-ui 1, frontend-guard 1
b9a35c6's code with 9736385's DM tests wire 3 failed (the three named), 55 passed
5 DM fix-part removals wire 1F/57P ×4; the rows rule 2F/56P; restored clean
14 GAQL rule removals, class run wire 1 failed (seed test), 3 passed, each
4 console rule removals ci only test_config_spellings_and_the_strict_reader fails, each
55 kept seeds + 13 own (seeds*.py; new pins vs b9a35c6's) ci + wire §3.3 reproduced in full.
Own seeds: Z1–Z8, Z6b, Z10, Z11 pass both versions; Z9 passes the new pin and fails the old.
Own seeds vs d7a5af2's pin class wire Caught: Z4, Z5, Z9. Passed: the rest.
gcloud 530.0.0 LoadCloudbuildConfigFromPath, ArgDict and run deploy/run --quiet services … parse bundled python and gcloud, unshare -rn, empty CLOUDSDK_CONFIG as in defects 1 and 2
PR #1302 check runs on 4e1fe7a gh api REST, read-only 28: 27 success, 1 skipped

What I did not check

  • Live provider behaviour, serving revisions, and Cloud Run's acceptance of an env value containing U+2028.
  • Firestore itself: I computed sizes with the documented formula and did not re-run its encoder.
  • GitHub Actions' own YAML parser on workflow files.
  • End-to-end runs of the seeds on GitHub or Cloud Build.
  • Measured: bash's behaviour for Z1; gcloud's parse and load for Z3–Z6b.
  • Read only: Z8, Z10 and Z7's runtime effect.
  • The console's vitest, tsc and Playwright suites.
  • A DNS audit.
  • The full tests/remediation suite.

Disclosures

  • Main checkout:
  • I read it only, with GIT_OPTIONAL_LOCKS=0, and ran git worktree add/remove there.
  • At the end: status clean, HEAD 4e1fe7a, 0 stashes. I did not touch base or memwt2.
  • My worktrees: I created 11 under vfy11: head, prev, mut, mut2–mut6, dmold, dmmut and w3d.
  • I seeded only mut*, dmold (a test file swapped in) and dmmut.
  • I restored them with git checkout/git clean and file rewrites; I made no commits and used no stash.
  • All are removed, along with the 4 venvs, vfy11/gcfg and /tmp/v11. No /tmp/wo26-* or /tmp/v417-* entries were left.
  • The head gate runs shared one tree, sequentially. 33 .pyc files from the governance run were present under the four roots during the GAQL gate; none contains a service-change line.
  • Read outside vfy11: vfy10/probes/seeds/* (replayed with paths changed), the two transcripts (by script), and directory listings.
  • Network:
  • PyPI installs;
  • one read-only fetch of Google's events.ingest reference;
  • GitHub REST reads of PR #1302, its check runs, and #1303.

I made no provider call. Every gcloud run was offline and had no credentials. - Deviations from CI: - plain venvs rather than setup-python; - -rf added on some runs; - env -i; - the kept seed driver's inherited env had its credential and proxy variables stripped (not otherwise changed), and its pytest runs are under unshare -rn. - No writes: no pushes, comments, reviews, records, deploys or dispatches. - Kept in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy11/: REPORT.partial.md (it also holds this report), FINAL.md, logs/ (gate, seed and rule-removal logs) and probes/ (seed drivers, own seeds seeds11_*.py, the gcloud loader worker, the fuzz and size scripts).

4.21 Pass 10 dispositions (fixes in d1e1e7b, docstring 592fa5d; record in the commit that adds this section)

Pass 10 found no blocker and no MAJOR. Each of the pass-9 heals' measured claims reproduced: - 3 tests failed and 55 passed on b9a35c6's code; - the five Data Manager parts and the 14 GAQL rules each failed their test when removed; - the 55-seed replay matched §3.3; - the gates passed; - §4.18 and §4.16 matched the hand-backs byte for byte.

It found two MINORs in the GAQL deploy pin and four NITs. The stop rule (RESUME) applies to both MINORs: they are fixed here, and pass 11 re-checks the fixes. The NITs are cheap, so they are fixed too.

How each fix is verified (§3.3, pass-10 block): - Two-way seeds. test_the_deploy_scan_reads_commands_as_written now holds: - 30 commands it must catch and 14 it must leave (pass 10's routes and their legal look-alikes among them); - 10 files it must flag once decoded and 4 it must leave; - 5 names of the cell that count and 3 that do not; - 9 service changes through a variable and 4 non-changes; - 13 texts the strict reader refuses and 1 it reads; - the Cloud Build pin's 28 seeded texts, and the sample it accepts.

test_config_spellings_and_the_strict_reader gains the same reader refusals for the console pin. - Rule removals: 38 tried. 37 each make exactly one test fail: the command reader's 15 rules, the strict reader's three new refusals, and 16 of the Cloud Build pin's 17 rules fail the seed test, and the console reader's three new refusals fail test_config_spellings_and_the_strict_reader. The 38th, "every deploy argument is a string", fails nothing when removed, because the flag allow-list refuses the same case. It is recorded as subsumed, not as pinned. Pass 11 (NIT 1): not so. With the rule removed, the seed test fails: the allow-list crashes on a non-string (§4.23). - The verifiers' seeds, replayed on the real files: pass 10's seeds11_own.py and seeds11_more.py (13 seeds), with the 55 of §3.3's pass-9 block, paths changed only. They ran against d1e1e7b's pins and 4e1fe7a's. Pass 10's 12 arming routes (Z1 to Z11 and Z6b) are caught by the new pins; 4e1fe7a's catch none. The 44 earlier arming routes are still caught, each failing exactly one test. The 11 controls and legal seeds pass, GFP among them. - gcloud's own loader: both Cloud Build files were mutated: 5,501 texts for the cell's and 37,901 for the console's. Of the texts the new pins accept (1,104 and 11,994), gcloud 530.0.0's loader, run offline, read every one it loads the same way PyYAML does. It refused 413 of the console's, and so did the PyYAML side. This is a measurement, not a proof.

# Finding Disposition Issue Test
1 (MINOR) the command reader and the service-change recognizer fell short of the stated reach. Z1 to Z5 and Z8 to Z10 passed: a continuation inside a word, a flag between run and its verb, a curl to the Run Admin API, the deploy-cloudrun action, and a nested bash -c. Z4, Z5 and Z9 were regressions fixed, and the reach restated as what the pin checks.
(a) The deploy workflow. It is pinned byte for byte (_DEPLOY_WORKFLOW_SHA256). Z1, Z4, Z5, Z8, Z10, and any other change to it, fail until a reviewer re-pins it. It also holds no service-changing command, whatever it targets.
(b) The command reader:
  • removes a backslash-newline with no replacement (Z1, Z2);
  • reads a quoted word holding whitespace again as commands, to three levels (bash -c, sh -c, eval; Z9);
  • recognizes a gcloud change by its words: run, then later deploy, replace or update (Z3 to Z5);
  • counts a call to run.googleapis.com (Z8) as a change, and the deploy-cloudrun action too, read as its uses with its with inputs (Z10);
  • reads a repository file named after =, @ or < (Z8's body, Z11's redirect).
A command targets the cell by its name as a word, after the last = of a word, or after /services/ in a URL.
(c) The docstring states exactly what is checked. Its out-of-reach list names the rest (pass 11, defect 1: not so. The docstring itself says "among others", and the cell's own files were not checked for the manifest's name. Fixed in 8c4f986, §4.23):
  • a tool the recognizer does not know (592fa5d adds a reusable workflow called with the cell's name);
  • a traffic change (592fa5d);
  • a target assembled or read at run time;
  • a command split over lines other than by a backslash-newline;
  • what the image does when it starts.
API-A12 test_the_deploy_keeps_live_mutations_off, test_the_deploy_scan_reads_commands_as_written
2 (MINOR) _strict_yaml accepted texts gcloud 530.0.0's own loader reads another way. Z6: GAQL_DRY_RUN_DEFAULT was deployed as true - --no-allow-unauthenticated. Z6b: the env map was dropped fixed.
Both strict readers (the cell's and the console's) now also refuse:
  • every control character but the newline;
  • U+2028, U+2029, a byte-order mark and the noncharacters;
  • a directive and an explicit tag.
The cell's Cloud Build file is then pinned whole (NIT 1).
The docstrings say "known to read differently", and cite the fuzz below as a measurement, not a proof
API-A12, API-G14 both strict-reader seed tests
NIT 1 a step-level env hook (Z7), and the other step fields, were unpinned fixed, and widened by the builder. _cloudbuild_problems pins:
  • exactly the top-level keys steps, images and options;
  • options: exactly CLOUD_LOGGING_ONLY logging;
  • the two images;
  • the build and push steps exactly;
  • a deploy step with exactly the keys name, entrypoint and args.
The deploy step's flags come from an allow-list, each given once, so it has no --command, --args, --set-secrets or --update-env-vars. --image must be the image the build tagged. The env map has exactly six names, three pinned to their values, so it has no PYTHONPATH
API-A12 test_the_deploy_scan_reads_commands_as_written (its _CB_SAMPLE seeds)
NIT 2 the env-flag alternatives were seeded by nothing fixed: one seed per alternative, each through a tool the verb rule does not recognize API-A12 the same
NIT 3 the size bound "45 or more" ignored the ingest answer's field warnings corrected to "44 or more destinations (45 without field warnings)" in ISSUES.json, the §4.19 D annotation, CLOSEOUT, RESUME and the PR body. Re-measured (§3.3):
  • a status row with every label at its bound is 23,376 bytes (23,183 with SUCCESS);
  • 50 maximal field warnings add 36,400 bytes;
  • with them, 44 destinations give 1,068,957 bytes.
Pass 11 (NIT 4): the record's history counts too; 43 destinations suffice once it is full (§4.23)
API-F6 —
NIT 4 API-F5's next action named a validate-only request, which creates no tracking record corrected in ISSUES.json and CLOSEOUT: a sanctioned test flow only API-F5 —
Design note a new file that names the cell fails until it is listed; once it is listed, only _gaql_changes guards it recorded. The one listed file that deploys, the deploy workflow, is now also pinned byte for byte API-A12 —

Self-found while healing; non-independent, and pass 11 reads them: - A false positive the first version of this fix brought back. The first version also required that no listed file hold a service-changing command, whatever it targets. The replay of pass 8's GFP failed it at once: the fleet state check prints a WARMUP_CMD for each service, and pass 8 had required that seed to stay legal (defect 2). The rule now covers the deploy workflow only. The fleet loop's variable target is stated out of reach: the pin cannot tell a command a listed file runs from one it prints. The fix commit was amended before it was pushed. - Three more routes in the cell's Cloud Build file, found while pinning NIT 1: a start command on the deploy (--command, --args), another image, and an env name such as PYTHONPATH. The allow-lists close them. - The image's start command can still set the process env: its Dockerfile's CMD, or a file that a step copies into the image. It is in the out-of-reach list, not pinned. What holds there is the operation builder's refusal.

Pass 10's verdicts on the pass-9 items stand as reported (§4.20): - C, E and F: FIXED. - D: FIXED for the encoding; its size bound is re-worded (NIT 3). - The observation on request_id and last_error: disposition SOUND. - A and B: PARTIAL. They are defects 2 and 1 above.

Pass 10 found these sentences overstated. Each is annotated or superseded in this commit: - §4.19, rows A, B and D, and the self-found bullet on the deploy workflow; - CLOSEOUT's pass-9 paragraph; - API-A12's and API-F6's pass-9 lines; - the PR body's GAQL and Data Manager rows.

Pass 10's other observations, recorded as given (§4.20): - What it did not check: - live provider behaviour and the serving revisions; - whether Cloud Run accepts an env value containing U+2028; - Firestore itself (sizes were computed with the documented formula); - GitHub Actions' own YAML parser; - the seeds end to end (it measured bash for Z1 and gcloud's parse for Z3 to Z6b; Z7, Z8 and Z10 it read); - the console's suites, a DNS audit, and the full tests/remediation suite. - Footprint: it read the main checkout only, ran git worktree add and remove there, removed its worktrees and venvs, and kept its notes in vfy11/. - API-A12: "This is the fifth round in which the pin's stated reach was wider than what it parses. Pass 9 suggested the owner's API-A12 decision might be the cheaper exit; that applies with more force now." Carried to CLOSEOUT and RESUME.

4.22 Pass 11 — follow-up PR #1302 (4e1fe7a..1e78fad, report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. It ran 2026-10-02 from about 09:59Z to 11:17Z. Its report, verbatim (taken from its hand-back):

Independent verification, pass 11 (blind): 4e1fe7a..1e78fad (draft PR #1302)

Bottom line. I found no blocker and no MAJOR. I found one MINOR and seven NITs.

  • What the range claims reproduces.
  • The 68 kept seeds replay exactly as §3.3 records:
    • pass 10's 12 routes each fail one new test, and 4e1fe7a's pins catch none of them;
    • the 44 earlier routes each fail one new test and one old test;
    • the 12 controls (Z0 included) pass both.
  • The Data Manager size table reproduces byte for byte.
  • Every gate is green in fresh venvs. The exception is test_wo31_register, which fails the same way on 3d5278b (shallow clone).
  • §4.20 is pass 10's hand-back verbatim: 23,340 characters, identical.
  • The ledger counts are right: 56 REVIEW_READY, 3 IN_PROGRESS (A12, F6, G14), 2 OPEN, 4 N/A.
  • No live mutation can run. The operation builder still raises NotImplementedError, and no gaql_cell code changed in the range.
  • MINOR: the stated reach is again wider than what the code checks (sixth round).
  • GAQL pin. d1e1e7b's docstring says no file in scope, the cell's own files included, names the reference manifest. The code never checks the cell's own files for the manifest's name. It also dropped two exclusions that 4e1fe7a's docstring had: "stdin", and a listed file that targets the cell through a variable. It also narrowed variables to "set outside the file".
  • Console pin. A new sentence says a gcloud hook "still has to name the switch somewhere above to arm it". That is false.
  • What passes. Literal in-repo routes pass the whole GAQL test file and arm the cell (S1arm, S2, S4, S4b), or deploy another image (S3, S5). A console seed (CH1) passes the console pin. These routes predate the range: 4e1fe7a's pin passes them too. The claims that cover them are new.
  • NITs:
  • C10 does fail a test when removed; the record says it fails nothing.
  • Eight rule removals fail no test, the deploy-workflow digest among them.
  • Two new false positives, introduced by d1e1e7b.
  • The Data Manager bound is off by one again (43 destinations suffice).
  • Strict-reader wording.
  • An unscoped CLOSEOUT sentence.
  • One exclusion wider than it needs to be.
  • The owner's API-A12 / API-G14 decisions remain the cheaper exit.

Pass-10 items

Item My verdict Evidence I produced
Defect 1 (MINOR: reader short of the stated reach) PARTIAL Fixed: Z1–Z5, Z8–Z11 are caught. In the replay each fails exactly one new test, and 4e1fe7a's pins pass all of them. Each of the builder's 15 command-reader rules fails the seed test when removed (pytest, and an in-process per-seed matrix).
Still open: the restated reach is again wider than the code. See new defect 1.
Defect 2 (MINOR: strict reader vs gcloud's loader) FIXED (as measured) Mechanism re-measured with gcloud 530's LoadCloudbuildConfigFromPath:
- U+2028 gives ["--x=1,B=true
- --no-allow","c"];
- NEL gives ["--x=1,B=true - --no-allow","c"];
- PyYAML gives 3 args for each.
Refusals are pinned: Z6 and Z6b are caught, and the odd-character, tag and directive refusals each fail their seed test when removed (both readers).
My structural fuzz: 12,000 random renderings. Of them, 3,389 are accepted by the full pin, and gcloud reads every one of them identically.
Residual NIT (NIT 5): the flow-context x: divergence.
NIT 1 (step env hook) FIXED for GAQL The deploy step's keys are exact. Removing that rule (C08) flips Z7 and "step key". The console twin is open (new defect 1(b)).
NIT 2 (env-flag marks unseeded) FIXED Removing --env-vars-file, --set-env-vars or --update-env-vars each flips exactly its own seed and fails the seed test.
NIT 3 (DM size bound) PARTIAL Reproduced exactly:
- rows: 23,183 / 23,376;
- 50 maximal field warnings: 36,400;
- the totals: 1,024,004 / 1,060,404 / 1,032,557 / 1,068,957 / 1,047,253 / 1,055,999 / 1,070,502.
The new bound is wrong: "44 or more" ignores MAX_HISTORY=20. See NIT 4.
NIT 4 (F5 validate-only) FIXED / ACCURATE main.py:312-313: record = None / if not req.validate_only:.
Design note Disposition SOUND as recorded Pinned: the deploy workflow's digest is the only thing that stops S7, a sed of the Cloud Build file in that workflow. With the digest assertion removed, the class passes.
Still realized: a listed workflow can still deploy the cell another way (S3, S5).
Pass 10 on pass-9 A / B Agree (PARTIAL then) Z6 / Z6b mechanism above; the Z routes pass 4e1fe7a's pins.
Pass 10 on C Agree (FIXED) XFP1 and XFP2 pass at the head and at 4e1fe7a (replay).
Pass 10 on D Agree; the re-worded bound is off again NIT 4.
Pass 10 on E Agree (not re-measured) The range changes no connector code. The DM suite has 58 passed.
Pass 10 on F Agree (FIXED) Y1 and Y2 are caught in the replay. Removing the quote or normpath rule (R36, R37) fails the seed test.
Pass 10 on the observation Agree (SOUND) Unchanged by the range.

Record items

Item Verdict
API-A12 pass-10 line (ISSUES.json:2002) ACCURATE: the replay and seed numbers.
INACCURATE:
- "The docstring states what the pin checks" (S1b).
- "the 38th (every deploy argument a string) is subsumed by the flag allow-list": removing C10 makes the seed test fail with AttributeError: 'int' object has no attribute 'split' at test_api_compat_binding.py:1374. The allow-list crashes on a non-string; it does not refuse it.
API-F3 ACCURATE. The move to REVIEW_READY is SOUND: no connector change in the range, and only a verdict line was added.
API-F5 ACCURATE (NIT 4).
API-F6 pass-10 line (:2078) ACCURATE: the numbers.
INACCURATE: the bound "44 or more destinations" (NIT 4).
API-G14 pass-10 line Accurate as a record of pass 10. The console docstring sentence d1e1e7b added is false (new defect 1(b)).
API-A13 ACCURATE. The GAQL test's hunks are at :14 (import) and from :955 on. The registry class at :604 is untouched.
review_track_note, publication ACCURATE:
- passes 1–10;
- 27 commits, which match git log fa1cc19..1e78fad;
- PR open, draft, not merged, mergeable_state clean.
EVIDENCE §3.1 ACCURATE. d1e1e7b changes 2 test files, 592fa5d the docstring only (4+/1−), and 1e78fad the 4 record files.
EVIDENCE §3.2 (pass-10 block) ACCURATE. I reproduced 97+4, 101, 58, 5 and 24. The class took 22.5 s here.
EVIDENCE §3.3 (pass-10 block) ACCURATE: the replay table and its counts; the DM table, byte-exact; the seed-test counts (30/14, 10/4, 5/3, 9/4, 13/1, 28).
INACCURATE:
- the C10 sentence (EVIDENCE.md:920-924);
- "each new rule, removed in turn" omits new rules that fail nothing when removed (NIT 2).
Not reproducible from the record: the builder's fuzz scripts are not in the record. Its arithmetic is consistent (52 and 376 line segments × 50 × 2 + 300 + 1), and my independent fuzz agrees.
EVIDENCE §3.5 ACCURATE.
§4.19 "Pass 10" annotations Accurate as records of pass 10.
INACCURATE:
- B's "the docstring states only what the pin checks";
- D's new bound.
§4.20 Verbatim. It is identical to the SubagentHandback input.message at transcript line 703 (23,340 characters; split on \n).
§4.21 Seed counts, NIT 4 and the self-found items are ACCURATE.
INACCURATE:
- (c) "states exactly what is checked. Its out-of-reach list names the rest" (the docstring itself says "among others"; S1b, S3, S5);
- "The 38th … fails nothing when removed";
- the NIT 3 bound.
CLOSEOUT, RESUME Counts ACCURATE: 65; 56/3/2/4; 32/3/13/17; 0 VERIFIED.
INACCURATE:
- CLOSEOUT.md:391 ("states what the pin checks, and nothing more");
- :395 (the 37-of-38 reading);
- :62 and RESUME.md:164 ("44 or more").
Unscoped: CLOSEOUT.md:396 (NIT 6).
PR body ACCURATE:
- the gate table (every row reproduced);
- the deploy count;
- the seed counts;
- the fuzz totals as arithmetic.
INACCURATE:
- "None may name the reference manifest" (for the cell's own files);
- "The 38th … is subsumed";
- "44 or more".
Deployed, verified or safe claims None beyond the evidence. The one exception is the CLOSEOUT fuzz sentence (NIT 6). Check runs on 1e78fad: 28 (27 success, 1 skipped).

New defects

1. MINOR: both deploy pins' restated reach is again wider than what their code checks. Literal in-repo routes pass the whole test files.

The routes predate the range: 4e1fe7a's GAQL pin passes every one of them. The claims that cover or dismiss them are new in d1e1e7b and 1e78fad.

(a) GAQL pin (src/cells/google_ads_gaql/tests/test_api_compat_binding.py)

Where: - :1446-1447: the claim "No such file names the reference manifest" covers the cell's own files. - :1533-1538: the own-file checks name only the service and the pinned keys. - :1465-1470: variables are "set outside the file or read from a file". - :1471: implies a backslash-newline split is handled. - :1496-1508 and :1308-1312: item 2's config checks never join continuations.

Seeds. Each passes the whole GAQL file: 38 passed, 4 skipped. - S1arm (arms). Three edits: - flip GAQL_ENABLE_LIVE_MUTATIONS to "true" in the reference manifest; its values are pinned by nothing, and it may name keys; - add src/cells/google_ads_gaql/deploy_ref.sh, not valid YAML, with M=src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml and gcloud run services replace "$M" --region=us-central1; - add a new workflow sh src/cells/google_ads_gaql/deploy_ref.sh.

Measured: bash with a stub gcloud gets argv [run][services][replace][src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml]. gcloud 530, offline, parses and loads the file and stops at auth; a malformed manifest fails earlier at "argument FILE". - S1b. An own file NOTES.txt naming cloud-run-google-ads-gaql.yaml. - S2 (arms). docs/gaql/live.yaml (a flipped manifest), plus a new workflow M=docs/gaql/live.yaml / gcloud run services replace "$M". - S3 (another image). The listed verify-cloudrun-state.yml gains gcloud run services replace - <<'EOF' with an inline manifest for the cell. Pass 9's remainder listed "stdin"; it was dropped. - S5 (another image). The same listed file gains env: {SVC: google-ads-gaql-cell} and gcloud run services update "$SVC" --image=…/other:latest. 4e1fe7a's docstring listed this exact class; it was dropped. - S4 (arms). A new workflow: sed -i 's/S=false,/S=true,/' src/cells/google_ads_gaql/cloudbuild\ .yaml gcloud builds submit --config=src/cells/google_ads_gaql/cloudbuild\ .yaml … Measured: - bash with a stub gets --config=src/cells/google_ads_gaql/cloudbuild.yaml; - gcloud's own loader plus ArgDict read GAQL_ENABLE_LIVE_MUTATIONS='true'; - the cell's _flag reads True. - S4b (arms). The same through cp "src/cells/google_ads_gaql/"cloudbuild.yaml /tmp/c.yaml, with the same measured result.

(b) Console pin (tests/governance/test_api_lifecycle_inventory.py:371-373)

Claim: "what a step's own environment runs (a gcloud hook), which still has to name the switch somewhere above to arm it". It is new in d1e1e7b.

Seed CH1. - The console's deploy step gains env: ["CLOUDSDK_PYTHON=/bin/sh", "CLOUDSDK_PYTHON_SITEPACKAGES=1", "CLOUDSDK_PYTHON_ARGS=/workspace/src/hooks/console.sh"]. - src/hooks/console.sh runs the deploy, then gcloud run services update miz-oki-command-center-ui --update-env-vars=EMAIL_SERVICE=klaviyo. - The root .gcloudignore re-includes /src/, so the script is uploaded, and no test scans that directory. - Result: the inventory suite has 24 passed. - The hook mechanism is read, not run: bin/gcloud:199 does exec "$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS …/gcloud.py "$@".

Fix: - Check the manifest's name in the cell's own files (none name it today). - Apply _joined and _words before item 2's substring and --config checks. - State plainly that the pin resolves no variable, heredoc or stdin in any file. Or pin verify-cloudrun-state.yml by digest as well. - Pin the console's gcloud steps' keys as _cloudbuild_problems does, or replace the sentence with the route. - Better: take the owner's API-A12 / API-G14 decision.

NIT 1: C10's removal is reported as failing nothing; it fails the seed test. - Where: EVIDENCE.md:920-924, ISSUES.json:2002, CLOSEOUT.md:395, the PR body. - Measured: - pytest: 1 failed, with AttributeError at :1374; - in-process: the "not a string" seed crashes _cloudbuild_problems. - Fix: record it as pinned (by crash), or seed a non-string explicitly.

NIT 2: new or load-bearing checks seeded by nothing. Removing any of these fails no test (pytest: 4 passed each). - The deploy-workflow digest (:1490-1492). It is the sole defense for S7. - _targets_cell's atom pass (:1219). It is new and catches a JSON body {"name":"google-ads-gaql-cell"}. - _reads's atom pass (:1254). It is new and catches $(cat file). - "One env map" (:1380). It is subsumed by unique flags plus the text count. - _words' bracket and comma replacement and its punctuation_chars. These matter only in the false-positive direction. - The two other real-tree assertions: the deploy workflow holding no service change (redundant with the digest) and the _NAMES_THE_CELL equality. Neither has an in-file seed.

Fix: seed each (for the digest, factor it into a helper and seed a one-byte change), or delete what is redundant.

NIT 3: two new false positives (fail closed) in a listed file. Both pass 4e1fe7a's pin and fail the new one. - FP1. gcloud run services describe google-ads-gaql-cell --region=us-central1 --format='value(status.url)' # re-checked after each deploy. "deploy" in the comment counts as a verb after run. - FP2. A GET curl -s -H "Authorization: Bearer …" https://run.googleapis.com/v2/…/services/google-ads-gaql-cell. - Fix: stop a command at a # that starts a word, and count run.googleapis.com as a change only with a write method or a body.

NIT 4: the DM bound "44 or more" ignores the record's bounded history. - Measured: 43 destinations, 50 maximal field warnings and maximal labels, then 20 failed status reads (TimeoutError text cut to 200; history 20/20), gives 1,051,932 bytes: over 1 MiB. Without the reads it is 1,045,515. - What still holds: "45 without field warnings" (44/none/max with full history: 1,038,974). - Fix: "43 or more (with a full history)", or bound the record's total size.

NIT 5: the strict reader's docstring overstates what it refuses. - A divergence it accepts. It reads args: [x, y:]: PyYAML gives ['x', {'y': None}], gcloud ['x', 'y:']. Likewise [--image=gcr.io/p/x:, --region=r]. - No consequence found. The GAQL pin refuses PyYAML's dict. The console check applies str() to its args and needs EMAIL_SERVICE in bytes. - "The noncharacters" covers only U+FFFE and U+FFFF. U+FDD0 and U+1FFFE are accepted and read the same. - It over-refuses a tab in a comment and a leading BOM. gcloud reads both like PyYAML.

NIT 6: CLOSEOUT.md:396 is unscoped. "gcloud's own loader read every accepted Cloud Build text it loads as PyYAML does" has no corpus and no "measurement, not a proof".

NIT 7: an exclusion is wider than it needs to be. - Measured: _gaql_changes over the cell's own .md files flags 0 commands, and over its .py files only tests/test_api_compat_binding.py. - What it admits: S6, a RUN.md arming script run by sh from a new workflow, passes as "Markdown". - Separately, by reading: the premise "a setting changed by hand (the next deploy replaces it)" fails for a pinned traffic split. gcloud's own --no-traffic help says later deployments then get no traffic, and the deploy workflow's verify step checks ready==created, not traffic.

Test runs

Environment for every run: - Fresh python3.11 -m venv (CPython 3.11.15, pytest 9.1.1, PyYAML 6.0.3), built from each job's install lines. - env -i with PATH/HOME/LANG only: no proxy or credential variables. - TMPDIR=/tmp/v12v/<run>. - Commit signing off through GIT_CONFIG_* env only. - Everything under unshare -rn.

Command (at 1e78fad unless noted) Env Result
pytest tests/governance -c tests/governance/pytest.ini (venv pytest) ci 4352 passed, 7 skipped, 6227 subtests, rc 0 (522 s)
pytest tests/governance/test_api_lifecycle_inventory.py -c … ci 24 passed
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" wire (MIZOKI_STORE=memory) / lock 97 passed + 4 skipped / 101 passed
same, services/service-data-manager-connector/tests wire 58 passed
same, tests/remediation/test_gaql_governance_wiring.py wire 5 passed
same, docs/audits/tests, at the head and on my 3d5278b worktree wire 1 failed (test_wo31_register: 26bec9c6b absent), 7 passed, identical on both
bash .github/scripts/content_gates.sh (GITHUB_EVENT_NAME=pull_request) gates 155 passed, rc 0
api_lifecycle_check.py, gate_leak_scan.py --check, claude_memory.py check --strict, check_canon_docs.py (--self-test and plain) gates rc 0 each:
- FAILURES 0, WARNINGS 1, UNKNOWNS 20;
- 74 invalidated, 0 new;
- valid;
- 48 files, 8 held
deploy_router.py --base fa1cc19 --head 1e78fad gates 21 files → deploy-google-ads-gaql 8, deploy-ui 1, frontend-guard 1
68 kept seeds (vfy10 and vfy11 drivers, paths changed only) vs 4e1fe7a's pins ci + wire as §3.3
67 rule removals (pytest) wire / ci 59 fail exactly one test, 8 fail nothing
Per-seed matrix (152 assertions × 64 mutations) wire NIT 2
My seeds: S1arm–S7, FP1, FP2, CH1, and each against 4e1fe7a's pin wire / ci defect 1, NIT 3
Structural fuzz, 12,000 texts wire + gcloud bundled python 3,389 accepted, all read identically
PR #1302 check runs on 1e78fad GitHub MCP, read-only 28: 27 success, 1 skipped

What I did not check

  • Live provider, Cloud Run or Cloud Build behaviour. Measured offline: gcloud's parse and file load, and bash with a stub gcloud. Read only: the hook runtime and the traffic semantics.
  • GitHub Actions' own YAML parser.
  • Firestore itself: sizes are computed with the documented formula.
  • The builder's fuzz scripts, which I did not read.
  • A full console-file structural fuzz.
  • The console's vitest, tsc and Playwright suites.
  • A DNS audit.
  • The full tests/remediation suite.

Disclosures

  • Main checkout:
  • I read it only, with GIT_OPTIONAL_LOCKS=0, and ran git worktree add/remove there.
  • At the end: status clean, HEAD 1e78fad, 0 stashes. I did not touch base or memwt2.
  • My worktrees, under vfy12: head, prev, g2, g3, w3d, mut1, rpA–rpD and rr.
  • I seeded only mut1, rr and rpA–rpD (the kept replay drivers seed and restore those), and restored them with git checkout/git clean.
  • Artifacts in my own worktrees:
    • -e contracts (ci and wire venvs) created contracts/mizoki_contracts.egg-info in head;
    • importing the test module created __pycache__ in head and g3;
    • S4's stub run applied its sed to mut1's Cloud Build file, then I reset it.
  • All worktrees and venvs are removed, along with /tmp/v12v. No /tmp/wo26-* or /tmp/v417-* entries are left.
  • A discarded run. A first governance run started with python -m pytest. I killed it after about a minute, cleaned its pycache and re-ran it with the venv's pytest (CI's form).
  • Read outside vfy12: vfy10 and vfy11 kept seeds and probes (drivers copied and path-rewritten), and the pass-10 transcript.
  • Network:
  • PyPI installs;
  • GitHub reads of PR #1302 and its check runs.

I made no provider call. Every gcloud run was offline, with no credentials, under unshare -rn. - No writes: no pushes, comments, records, deploys or dispatches. - Kept in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy12/: REPORT.partial.md (it also holds this report), FINAL.md, logs/ (gate, replay, rule-removal and matrix logs) and probes/ (my seeds seeds12/seeds.py, mutations12.py, seed_matrix12.py, the fuzz fuzz/, dm_size12.py, the copied replay drivers).

4.23 Pass 11 dispositions (fixes in 8c4f986 and c9df080; record in the commit that adds this section)

Pass 11 found no blocker and no MAJOR. What it reproduced: - the 68-seed replay of §3.3; - the Data Manager size table, byte for byte; - every gate, in fresh venvs. test_wo31_register fails the same way on 3d5278b (shallow clone); - §4.20 against the hand-back (23,340 characters); - the ledger counts.

It found one MINOR and seven NITs. The stop rule (RESUME) applies to the MINOR: it is fixed here, and pass 12 re-checks the fix. NITs 1, 2 and 4 to 7 are cheap, so they are fixed too. NIT 3 is recorded for the owner and not changed.

How each fix is verified (§3.3, pass-11 block): - Seeds, both ways. test_the_tree_checks_read_both_ways builds a tree and seeds the pin's tree rules on it: the deploy workflow, the four roots, _names_config and the cell's own files. - Rule removals: 66 at 8c4f986, and five again at c9df080. 63 each fail at least one test. One of them, the deploy workflow's single --config, needed the seed c9df080 adds. Three fail nothing: _names_config's shortcut, which is not a rule; "one env map", which is subsumed; and _words' bracket replacement, which is not seeded. - The verifiers' seeds, replayed on 8c4f986 against its pins and 1e78fad's: - Pass 11's six arming routes inside the pin's checks (S1, S1arm, S1b, S4, S4b, S6): 8c4f986's pins catch all six, and 1e78fad's catch none. - S7 is caught by both. - S2, S3, S5 and CH1 pass both, as the docstrings now say. - FP1 and FP2 fail both (NIT 3). - The 68 earlier seeds give the same answer with both pins.

# Finding Disposition Issue Test
1 (MINOR) both pins' stated reach was again wider than their code. GAQL: the cell's own files were not checked for the reference manifest's name (S1b; S1arm arms the cell through it), the config checks joined no backslash-newline (S4) and read no quoted path (S4b), and the docstring had dropped stdin and a listed file's variable target from what it does not check (S3, S5). Console: a gcloud hook need not name the switch where the test reads (CH1) fixed, by code where the claim was cheap to make true, and by wording elsewhere.
(a) The GAQL pin's tree checks are now helpers that return their problems: _root_problems and _own_file_problems. Each rule is seeded both ways on a built tree.
  • None of the cell's own files may name the reference manifest (S1arm, S1b).
  • Only the deploy workflow may name the Cloud Build file, anywhere under the four roots. A name counts as written once backslash-newlines are removed, and as a path a command holds, read the way _reads reads one (_names_config; S4, S4b).
(b) The docstring states the four things the pin checks, and nothing else. It says how a command is read, and that no variable, heredoc or stdin is resolved. Its list of what is not checked is marked as examples, not a complete list. S2, S3 and S5 are on it, along with the root Makefile's target, which submits the pinned Cloud Build file.
(c) The console docstring drops the false sentence. It lists, among what is not checked, any file in a place the test does not read that a deploy reads or runs. A step's own environment can make gcloud run such a file, and the test reads no step's environment (CH1)
API-A12, API-G14 test_the_deploy_keeps_live_mutations_off, test_the_tree_checks_read_both_ways
NIT 1 C10's removal was recorded as failing nothing. It fails the seed test corrected in §3.3, §4.21, ISSUES.json, CLOSEOUT and the PR body. The pass-10 run coerced the arguments to strings instead of removing the rule. Removed, the rule makes the seed test fail with AttributeError: 'int' object has no attribute 'split', a crash in the flag allow-list. Re-measured at c9df080 API-A12 test_the_deploy_scan_reads_commands_as_written
NIT 2 eight rule removals failed no test, among them the deploy workflow's digest fixed for six:
  • the digest;
  • _targets_cell's atom pass;
  • _reads' atom pass;
  • _words' punctuation;
  • the two real-tree assertions: the deploy workflow holds no service change, and exactly the listed files name the cell. Both moved into _root_problems.
Each is now seeded. Recorded for two: "one env map" is subsumed, and the bracket and comma replacement changes no verdict found
API-A12 the two seed tests
NIT 3 two new false positives in a listed file. A read with a trailing comment that says "deploy" (FP1), and a GET of the Run Admin API (FP2), fail closed recorded, not changed. Narrowing the recognizer to admit them (cutting a command at a #, or counting the Run Admin API only with a write method) would release real routes: a write written another way, say. Rule 01 says never narrow a rule to admit a false positive. A reviewer who meets one rewords the line or extends the pin under review API-A12 —
NIT 4 the Data Manager bound "44 or more" ignored the record's bounded history corrected to "43 or more once the history is full (45 without field warnings)" in ISSUES.json, the §4.19 D annotation, CLOSEOUT, RESUME and the PR body. Re-measured (§3.3): 43 destinations with a full history of failed reads give 1,051,932 bytes. A late read's longer note moves neither count API-F6 —
NIT 5 the strict readers' docstrings overstated what they refuse fixed in wording, in both readers:
  • they name the noncharacters they refuse (U+FFFE and U+FFFF);
  • they say a text the two readers read differently can pass (an entry ending in a colon inside a flow list), and where each pin then fails closed;
  • they note that some texts both read alike are refused.
Seeds: that entry passes both readers, and the Cloud Build pin refuses it in a step
API-A12, API-G14 both seed tests
NIT 6 CLOSEOUT's fuzz sentence named no corpus corrected: 13,098 mutated texts the pins accept, single insertions into the real files, a measurement and not a proof API-A12 —
NIT 7 the own-file exclusion of Python code and Markdown was wider than needed (S6), and "the next deploy replaces it" is false for a pinned traffic split fixed. The cell's own files are now read whole, this test file and compiled Python aside: the manifest-name check and the command scan cover Python code and Markdown. The naming checks for the service and the keys still skip them, since the code and the README name both. Both docstrings drop "the next deploy replaces it" API-A12, API-G14 test_the_tree_checks_read_both_ways

Self-found while healing (non-independent; pass 12 reads them): - An unseeded rule among the new ones. "The deploy workflow passes exactly one --config as written" failed nothing when removed: every seed that broke it also broke the set check over the workflow's YAML strings. c9df080 adds a seed that only it catches. - A wrong legal seed, dropped before the commit. It was an absolute path ending in the Cloud Build file's path. _names_config's substring check flags it, and so did the check it replaces. That fails closed, so the seed was wrong, not the rule. - The replay harness and the new own-file check. The new check reads the copy of the old pin that the harness puts in the cell's directory, so the harness moves that copy out while the new pins run.

Pass 11's verdicts on the pass-10 items stand as reported (§4.22): - defect 1: PARTIAL (defect 1 above); - defect 2: FIXED as measured; - NITs 1, 2 and 4: FIXED; - NIT 3: PARTIAL (NIT 4 above); - the design note's disposition: SOUND.

Its record verdicts are corrected where it found them inaccurate: - §3.3's C10 sentence and its rule-removal list; - §4.19's B and D annotations; - §4.21's (c), its 38th removal and its NIT 3 row; - the API-A12 and API-F6 pass-10 lines; - CLOSEOUT's pass-10 bullet; - the PR body.

Pass 11's other observations, recorded as given (§4.22): - What it did not check: - live provider, Cloud Run or Cloud Build behaviour (it ran gcloud's parse and file load offline, and bash with a stub gcloud); - GitHub Actions' own YAML parser; - Firestore itself; - the builder's fuzz scripts; - a full fuzz of the console file's structure; - the console's vitest, tsc and Playwright suites; - a DNS audit; - the full tests/remediation suite. - Footprint: it read the main checkout only, ran git worktree add and remove there, removed its worktrees and venvs, and kept its notes in vfy12/. - API-A12 and API-G14: "The owner's API-A12 / API-G14 decisions remain the cheaper exit." Carried to CLOSEOUT and RESUME. This is the sixth round in which a pin's stated reach was wider than its code. Each round's fix narrows a claim or closes routes; none makes the cell safe to arm.

4.24 Pass 12 — 1e78fad..482b60b (#1302, merged as d98d213; report verbatim)

The verifier received the range, the earlier reviews (in this file) and the rules; never the builder's reasoning. #1302 had merged before it started, so it also checked d98d213 and the record of that merge, 99381e8 (merged through #1308), reading GitHub for each claim about a run or a merge. - Its first attempt ran from 12:50:49Z to 13:09:39Z. A user interrupt in the parent session ended it, and it returned no report. Its partial notes stay in the session scratchpad (vfy13/). The second attempt was told not to read them, and its disclosures list no read of them. - The second attempt ran from 14:21:09Z to 15:29:01Z, in a fresh directory (vfy14/).

Its report, verbatim (taken from its hand-back, 29,985 characters). It quotes two noncharacters, U+FFFE and U+FFFF, as written:

Independent verification, pass 12 (blind): 1e78fad..482b60b (PR #1302, merged as d98d213)

Bottom line. I found no blocker, no MAJOR and no MINOR. I found eight NITs, four of them in the record (two of those four in 99381e8).

  • Pass 11's MINOR (defect 1) is fixed as stated.
  • I checked each sentence of the GAQL class docstring against the code it describes. Each is true, with two wording NITs in the safe direction (NIT 5).
  • The replays match the record:
    • Pass 11's six arming routes inside the pin's checks (S1, S1arm, S1b, S4, S4b, S6) fail 482b60b's pin, and 1e78fad's pin catches none of them.
    • S7 fails both pins. FP1 and FP2 fail both. S2, S3, S5 and CH1 pass both.
    • Of the 68 earlier kept seeds, 56 are caught by both pins, each failing the same single test, and 12 pass both.
  • The console docstring's false sentence is gone.
  • Pass 11's NITs. NITs 1, 2 and 4 to 7 are fixed. NIT 3's "recorded, not changed" disposition is sound. Two checks I reproduced independently:
  • Data Manager sizes. All six size rows of §3.3 reproduce byte for byte with my own implementation of Firestore's documented formula, and the bound "43 or more once the history is full (45 without field warnings)" holds.
  • Strict-reader wording. The new sentences match what gcloud 530.0.0's own loader does, run offline.
  • What I found (all NIT):
  • S4 one directory over. S4/S4b relocated into the cell's own directory pass the whole GAQL test file and arm the cell. Own files are not held to item 3's rule that only the deploy workflow names the Cloud Build file. No sentence claims they are, and the "not checked" examples do not name it (NIT 1).
  • Two rules the range added are seeded by nothing, beyond the three the record names (NIT 2):

    • the own-file decoding;
    • the U+FFFE/U+FFFF refusal, which both readers already apply.

    The API-G14 ledger line says "a seed for each". - "Compiled Python: the clean tree holds none" is wrong for a normal run (NIT 3). - New fail-closed false positives from the all-roots Cloud Build name rule, with no reviewed allowlist (NIT 4). - Two docstring wording points: "no … stdin is read", and "every file … under" (NIT 5). - Stale seed counts in the PR body (NIT 6). - In 99381e8: - "still running" for a CodeQL job that finished at 13:11:41Z (NIT 7); - "Two deploy workflows ran" leaves out deploy-gcs.yml, which also ran on the push (NIT 8). - Gates. Every gate is green in fresh venvs at 482b60b and at d98d213. The one exception is test_wo31_register, which fails identically on 3d5278b (shallow clone). The results on d98d213 are identical to 482b60b's. - No live mutation can run. gaql_cell code is untouched by the range, and the operation builder still raises NotImplementedError (test_the_operation_builder_refuses passes on both trees). The owner's API-A12 / API-G14 decisions remain the cheaper exit.

Pass-11 items

Item My verdict Evidence I produced
Defect 1(a), GAQL pin's stated reach FIXED as stated Sub-items:
- Own files are checked for the manifest's name, prose and code included. Removing the check (O03) or its prose_too (O04) fails test_the_tree_checks_read_both_ways.
- _names_config joins continuations and reads quoted paths. Seven mutations of it (N01, N02, N04–N08) each fail the tree test.
- The docstring lists stdin, heredoc and a listed file's variable target as not checked.
- S6 is now caught.
Replay: S1, S1arm, S1b, S4, S4b and S6 fail the new pin's test_the_deploy_keeps_live_mutations_off, and the old pin passes them. S2, S3 and S5 pass both, as stated.
Residue: NIT 1 (S4 route class still open via the cell's own dir) and NIT 5 (wording).
Defect 1(b), console sentence FIXED The sentence is gone. "any file in a place not listed above … that a deploy reads or runs" and "this test reads no step's environment" are true of the code.
CH1 passes the inventory suite with both pins, as now stated.
NIT 1, C10 record FIXED; corrections ACCURATE With C10 removed, the seed test fails with AttributeError: 'int' object has no attribute 'split' at test_api_compat_binding.py:1383.
NIT 2, unseeded rules FIXED for the eight it named The six now seeded fail when removed:
- the digest (P01), the deploy workflow's service changes (P05) and _NAMES_THE_CELL (P07) fail the tree test;
- the _targets_cell atoms (R18), _reads atoms (R21) and _words punctuation (R25) fail the seed test.
The two recorded fail nothing, as recorded: "one env map" (C15) and the brackets (R24).
New residue: NIT 2.
NIT 3, FP1/FP2 Disposition SOUND Measured:
- FP1 and FP2 fail both pins (replay).
- Two writes are caught today, and the proposed narrowings would release them:
- a list-form subprocess.run(["gcloud","run","deploy","--args","#x","google-ads-gaql-cell","--image=…/other"]): cutting at a word that starts with # drops the target;
- requests.patch("https://run.googleapis.com/…/services/google-ads-gaql-cell", json=…): the string has no method word or body.
Rule 01 applies.
NIT 4, DM bound FIXED; figures ACCURATE My own formula code, the real lifecycle at 482b60b, pass 11's inputs (each row is destinations / field warnings / history):
- 42/50/20 reads: 1,028,490, not over;
- 43/50/3 entries: 1,045,515, not over;
- 43/50/20: 1,051,932, over;
- 44/none/20: 1,038,974, not over;
- 45/none/3: 1,055,999, over;
- 45/none/20: 1,062,416, over.
Notes: a failed read's note is 234 B; a late read's is 342 B (+108; ×20 = 2,160).
Thresholds:
- 43 with warnings and a full history (failed or late reads);
- 44 with warnings and no extra reads;
- 45 without warnings.
The thresholds still hold with a 128-character tenant, a 200-character caller and 20-digit action ids.
NIT 5, strict-reader wording FIXED gcloud 530.0.0's loader, offline, unshare -rn:
- a: [x, y:] gives ['x','y:'], where PyYAML gives ['x',{'y':None}];
- the Cloud Build file with [push, --all-tags:, gives push args ['push','--all-tags:',…] (a dict to PyYAML), and _cloudbuild_problems fails closed (seeded);
- U+FDD0 and U+1FFFE are read alike;
- a tab in a comment and a leading BOM are read alike by both, and refused by the strict reader.
Residue: the noncharacter refusal has no seed (NIT 2).
NIT 6, CLOSEOUT fuzz sentence FIXED "13,098 … the pins accept" = 1,104 + 11,994 from §3.3's table. "Every one it loads" correctly excludes the 413 that gcloud refuses.
NIT 7, exclusion and "next deploy replaces it" FIXED S6 is caught (replay). O04 fails the tree test. The phrase is gone from both docstrings.
Pass 11 on pass-10 defect 1 (PARTIAL) Agree; closed by 8c4f986 Z1–Z5 and Z8–Z11 are caught by both pins (replay). R01–R37, with R19/R20 re-anchored, each fail the seed test, except R24 (the bracket replacement, recorded as unseeded).
Pass 11 on pass-10 defect 2 (FIXED as measured) Agree Z6 and Z6b are caught by both pins. Y01–Y06 and GY1–GY3 each fail their seed test when removed.
Pass 11 on pass-10 NITs 1, 2, 4 (FIXED) and NIT 3 (PARTIAL) Agree NIT 1: C08 fails the seed test, and Z7 is caught. NIT 2: R08–R10 fail. NIT 4: main.py:312-313 read record = None / if not req.validate_only:. NIT 3: closed by the NIT 4 correction above.
Pass 11 on the design note (SOUND) Agree S7 is caught by both pins. The digest is now seeded (P01).
Pass 11 on pass-10's C, F and the observation Agree XFP1 and XFP2 pass both pins. Y1 and Y2 are caught by both. The range changes no connector code.
Pass 11's record verdicts (its INACCURATE items) Corrections ACCURATE Annotations present and true:
- §3.3 (C10; "these are the rules this run removed");
- §4.19 B and D;
- §4.21 (c), its 38th removal and its NIT 3 row;
- the API-A12 and API-F6 pass-10 lines marked SUPERSEDED in part;
- the CLOSEOUT pass-10 bullet.
Rewritten: the CLOSEOUT and RESUME "44 or more" and the fuzz sentence. PR body: "Corrections" list.

Record items changed by the range

Item Verdict
§4.22 VERBATIM. It is identical to the SubagentHandback input.message in pass 11's transcript (JSON line index 770, split on \n): 20,842 characters on each side.
The transcript runs from 09:59:52Z, and the hand-back is at 11:19:05Z. The intro says "about … 11:17Z", which is immaterial.
§4.23 ACCURATE except as in NITs 2 and 3. Every claim I could measure reproduced:
- 6/1/4/2 for the replayed seeds;
- the 68 earlier seeds the same;
- P02 fails nothing without c9df080's seed and fails with it;
- the removed wrong legal seed is consistent with the old substring rule.
§3.1 ACCURATE. The rows for 1e78fad, 8c4f986, c9df080 and the record commit are correct.
§3.2 (pass-11 block) ACCURATE:
- 98+4, 102, 58, 5, 24;
- the class takes ~23 s (I measured 23.2 s);
- PR CI on 8c4f986: 28 runs, 27 success, 1 skipped (c9df080 the same).
§3.3 (pass-11 block) ACCURATE: the seed descriptions, the replays, the DM table and the self-found items.
INACCURATE: EVIDENCE.md:1104-1105 ("The exception is compiled Python: the clean tree holds none"; NIT 3).
Incomplete: "Three fail nothing" holds for the builder's removal set only (NIT 2).
§3.5 (8c4f986/c9df080 are tests) ACCURATE. Both touch only the two test files.
§3.3 / §4.19 / §4.21 "Pass 11" annotations ACCURATE.
API-A12 pass-11 line ACCURATE: the replay statements and the counts for the builder's set.
Incomplete: "the three that fail none" (NIT 2). Its description of the docstring ("no variable, heredoc or stdin is resolved") is faithful, but the docstring understates the code (NIT 5).
API-F3, API-F5, API-A13 pass-11 lines ACCURATE.
- 8c4f986 touches no connector code.
- The F5 line matches main.py:312-313.
- The A13 class (:604-680) is untouched: the hunks start at :967, and c9df080 adds 2 lines in the tree test.
API-F6 pass-11 line ACCURATE. All figures reproduce.
API-G14 pass-11 line ACCURATE except "with a seed for each" (NIT 2).
review_track_note, publication ACCURATE when written. follow_up.commits (29 SHAs + placeholder) equals git log fa1cc19..482b60b (30 commits). Counts: 65 issues; review 56 RR / 3 IP (A12, F6, G14) / 2 OPEN / 4 N/A; deployment 32/3/13/17; 0 VERIFIED.
CLOSEOUT, RESUME (range) ACCURATE when written. The counts match ISSUES.json, and the four documents agree with each other and with the PR body.
PR body ACCURATE: the gate table (every row reproduced, canon docs included), the replay statements and the deploy count.
Stale: the seed-test counts (NIT 6).
Inherited: the stdin wording (NIT 5).
Deployed / verified / safe claims (range) None beyond the evidence. "Pin what keeps ACT inert" refers to the Cloud Build file's pinned settings, the code defaults and the refusing builder, all pinned.

99381e8 (merged via #1308 as 990bccf): claims checked against GitHub (REST, read-only)

Claim Verdict
#1302 merged at head 482b60b, 2026-10-02 12:47:38Z, merge d98d213, first parent f17e068 ACCURATE. pulls/1302: merged_at 12:47:38Z, merged by mediaintelligence, merge_commit_sha d98d213…, 30 commits, 21 files.
GAQL run 37008851021 (job 110843460918), success; its verify step printed Ready=True latestReady=…00016-cl4 latestCreated=…00016-cl4 unauth=403 ACCURATE. The run was a push on d98d213. The job log has Building google-ads-gaql-cell @ d98d213 and exactly that verify line.
Console run 37008851067 (job 110845858893), success; the public URL answered 307; it built d98d213, which also carries #1306; #1306's own deploy, run 37008560190, succeeded first ACCURATE:
- the log shows a fetch of +d98d213…, _IMAGE_TAG=d98d213… and HTTP Status: 307;
- #1306 merged as 80bcb6e at 12:44:51Z;
- run 37008560190 completed at 12:54:55Z, before job 110845858893 started (12:54:57Z).
The console Cloud Build file at d98d213 names EMAIL_SERVICE 0 times; #1302's console change is one comment ACCURATE. grep finds 0. The route.ts diff is 5 comment lines.
"fires each deploy-*.yml whose on.push.paths match the push. Two deploy workflows ran" INACCURATE in part (NIT 8). Nine runs exist on d98d213. Besides the two service deploys, deploy-gcs.yml ("Backup to GCS", run 37008851020) ran: it has no paths: filter, so it runs on every push to main. Frontend Guard and Verify No Secrets also ran, plus two CodeQL runs and two Journey Smoke runs.
deploy_router.py --base f17e068 --head d98d213 lists the same two plus frontend-guard ACCURATE. I ran it: 21 files, giving deploy-google-ads-gaql 8, deploy-ui 1, frontend-guard 1.
Deployed GAQL code = 606fb8a e3bd49e 22f711d fc2a3a3 b03f33e c7d8904; DM code commits = 606fb8a e3bd49e 22f711d b03f33e c7d8904 9d9cd01 49f8d80 02b4c3c 9736385 ACCURATE, by git log fa1cc19..482b60b, excluding tests.
§3.7: 28 check runs at the merge (23 success, 1 skipped, 4 running: Lint/Test/Validate, tsc, e2e+a11y, one Analyze (python) in run 37008407046); Copilot and Bugbot started 12:47:40Z/12:47:41Z ACCURATE. Of 30 check runs, the 28 that started by 12:47:38Z split exactly so. "Lint, Test, and Validate" is in .github/required-status-checks.json.
"Read at 13:12Z: … CI run 37008411903 completed at 12:58:58Z; … Frontend Guard run 37008411877, 12:48:32Z; the CodeQL Analyze (python) job … was still running" First two ACCURATE. The third is not true at 13:12Z (NIT 7): job 110842038518 completed success at 13:11:41Z, and run 37008407046 at 13:11:42Z.
#1303 merged 12:46:58Z; the record went onto the branch as a fast-forward from d98d213, behind a new draft PR; GitHub kept the branch (read at 12:55Z) ACCURATE when written.
- 99381e8's parent is d98d213.
- #1308 was opened at 13:24:15Z as a draft (ready_for_review at 13:29:35Z).
- The branch existed then, and it was deleted at 13:29:49Z.
ISSUES.json: A6, A7, A9, A10, A11, A13 → DEPLOYED with run evidence; counts 38 DEPLOYED / 1 in part / 9 not deployed / 17 N/A ACCURATE. Recounted from 99381e8's ISSUES.json: 38/1 IP/9 OPEN/17 N/A. The six state changes are exactly those, and B7 is the one "in part". Nothing is VERIFIED, and "Its routes were not probed (IAM-locked)" is stated.
"Data Manager changes … manual deploy, which has not run" Not verifiable by me. There is no GitHub trace of a manual deploy.

Statements made stale by the merges (true when written; not counted as defects): - 482b60b, by #1302's merge: - ISSUES.json publication.follow_up.state "draft, not merged", and A6/A7 "IN_PROGRESS (remainder #1302)" and A9–A11/A13 "OPEN"; - CLOSEOUT: - "The follow-up is open … They are not merged or deployed"; - the #1302 row "draft; merging deploys 2 services"; - "#1302 merge | owner gate, after pass 12"; - "Pre-merge checks (#1302) | … pass 12 … must report no open blocker"; - "Pending: PR #1302 head"; - "#1302 is not [deployed]"; - the 32/3/13/17 deployment counts; - RESUME: - "Open: draft PR #1302"; - "Merging #1302 deploys …"; - Pending items 1–3 ("waits on the owner's merge decision"; "#1302 CI … the owner's merge gate after that"; #1303 "If main moves before it merges"); - "the Data Manager connector after #1302 merges"; - EVIDENCE §3.5 "Until #1302 merges …"; - PR body "Pass 12 … The merge gate waits for it." - Note: the merge also happened with 4 check runs still running, one of them the required "Lint, Test, and Validate". It later passed. - 99381e8, by #1308's merge (13:29:44Z, also with "Lint, Test, and Validate" and one Analyze (python) still running; both later success): - CLOSEOUT: - :52 "the follow-up record PR | … | draft"; - :20/:150 "What it finds goes to a new PR" / "fixed in the follow-up PR"; - :471 "Pending: the follow-up record PR"; - RESUME :52 "Open: the follow-up record PR" and :161; - ISSUES.json publication.follow_up_2.state "draft PR, not merged"; - EVIDENCE §3.1 "GitHub kept the branch" (deleted at 13:29:49Z).

New defects

NIT 1: the S4/S4b route class is still open through the cell's own directory. - Where: - src/cells/google_ads_gaql/tests/test_api_compat_binding.py:1501-1522: _own_file_problems has no _names_config check. - :1489-1497: the rule runs over the four roots only. - Docstring :1549-1558. - Scenario (measured, whole GAQL file: 39 passed, 4 skipped each): - N1: src/cells/google_ads_gaql/tools/redeploy.sh with sed -i 's/S=false,/S=true,/' src/cells/google_ads_gaql/cloudbuild.yaml and gcloud builds submit --config=src/cells/google_ads_gaql/cloudbuild.yaml …, plus a new workflow sh src/cells/google_ads_gaql/tools/redeploy.sh. The sed turns the real file's GAQL_ENABLE_LIVE_MUTATIONS=false, into =true,. - The same passes as REDEPLOY.md (N1b), as a subprocess list in gaql_cell/redeploy.py (N1c), and in S4b's form, cp "src/cells/google_ads_gaql/"cloudbuild.yaml /tmp/c.yaml; sed …; submit (N1d). - Context: - Not a regression: 1e78fad's pin passes N1 too. - No sentence claims own files are held to the rule, and item 4's rules are enumerated with "nothing else". So, like pass 11's S6, this is an exclusion wider than it needs to be. - The same edit-and-submit route from an unread place (docs/) is already listed as unchecked. - Fix: - Apply _names_config to own files other than cloudbuild.yaml. It flags 0 own files on the real tree today (measured; the reference manifest says only "cloudbuild.yaml"). Seed one. - Or name the route in the "not checked" examples.

NIT 2: rules seeded by nothing, beyond the three the record names, and a ledger line that says otherwise. - Where: - test_api_compat_binding.py:1506 (own-file _decoded); - :975 and tests/governance/test_api_lifecycle_inventory.py:280 (￾￿); - ISSUES.json:1776 (API-G14 pass-11 line, "with a seed for each"). - Measured: - (a) Own-file decoding. Reading own files as written only (O10) fails no test (5 passed). Yet it is load-bearing: in a copy of the cell, an own extra.yaml with svc: "google-ads-gaql\x2Dcell" is caught with decoding and missed without it. - (b) The noncharacters. Removing U+FFFE/U+FFFF from both _ODD_CHARACTER classes fails nothing (pin class 5 passed; inventory 24 passed). No seed exists, and none could pin it: PyYAML and gcloud 530 both refuse them already (ReaderError / YAMLParseError "unacceptable character"). - (c) A subsumed half. "Only the deploy workflow names it" also requires the deploy workflow itself to name it (P09). That is subsumed by the one---config rule, like "one env map". - Fix: - Seed (a) in test_the_tree_checks_read_both_ways. - Call (b) redundant and drop "with a seed for each" from the G14 line. - Record (c) as subsumed.

NIT 3: record. "The exception is compiled Python: the clean tree holds none" (EVIDENCE.md:1104-1105 at 482b60b). - Measured: - In a normal run, gaql_cell and the test module are compiled to __pycache__ before the test body runs. With the .pyc exclusion removed (O02), test_the_deploy_keeps_live_mutations_off fails with 20 problems, the first "tests/__pycache__/test_api_compat_binding.cpython-311-pytest-9.1.1.pyc names the reference manifest". So all four exclusions fail the real-tree test. - It passes only with PYTHONDONTWRITEBYTECODE=1 and __pycache__ removed. - Fix: say "all four fail it in a normal run (bytecode written)".

NIT 4: new fail-closed false positives with no reviewed allowlist. - Where: test_api_compat_binding.py:1491-1497 (config_names != [_DEPLOY_WORKFLOW]). - Measured. Each fails test_the_deploy_keeps_live_mutations_off, and each passes 1e78fad's pin: - N3: a CODEOWNERS line /src/cells/google_ads_gaql/cloudbuild.yaml @MIZOKI-3-5/owners, a plausible hardening of exactly this file. - N6: a scripts/ lint list naming the path. - Context: failing closed is the design, but unlike _NAMES_THE_CELL a reviewed non-submitting mention can be admitted only by editing the rule. - Fix: add a reviewed list for non-submitting mentions, or record the trade-off with FP1/FP2.

NIT 5: two docstring wording points (safe direction). - (a) Stdin. The GAQL class says "no heredoc or stdin is read" (:1563-1564) and lists "a manifest … reached through … stdin" as not checked (:1574). But the code reads a manifest fed through a redirect or a pipeline from a named repository file: - the seed test's own entries at :1637 (pipeline) and :1652 (redirect); - my N7, a new workflow gcloud run services replace - <docs/gaql/live.txt with a cell manifest in docs/, which is caught.

The PR body repeats the sentence. - (b) Symlinked directories. "Every file of any suffix under .github, ops, scripts and deployment" (:1539): rglob (:1483; also the console's :413) does not descend into a symlinked directory on Python 3.11. - N8, a symlinked scripts/gaqlx -> ../docs/gaqlx holding an arming script run by a new workflow, passes. A symlinked file (N9) is caught. - This adds no route beyond the listed "file outside the places read (the documentation)" exclusion. - Fix: "no heredoc, and no stdin other than a redirect or pipeline from a named repository file"; "every file … under (a symlinked directory is not followed)".

NIT 6: PR body seed counts are stale. - Where: the "Pass 10's fixes" bullet reads "The seed test now holds: 30 … 14 …; 10 … 4; 13 … and 1 accepted text; … 28". - Measured: 482b60b holds caught 32 / legal 15, decoded 10/4, 13 refusals, 2 accepted-text asserts and 29 Cloud Build seeds. - Fix: say "after pass 10", or update the counts.

NIT 7: 99381e8. "Read at 13:12Z … the CodeQL Analyze (python) job … was still running." - Where: EVIDENCE.md:1299-1305, CLOSEOUT.md:476 and ISSUES.json:2161 (at 99381e8). - Measured: job 110842038518 completed success at 13:11:41Z; run 37008407046 completed at 13:11:42Z. - Fix: "ended success at 13:11:41Z", or give the read time to the second.

NIT 8: 99381e8. "Two deploy workflows ran" (EVIDENCE.md:1245-1246 at 99381e8). - The sentence's own rule ("each deploy-*.yml whose on.push.paths match the push") also covers deploy-gcs.yml (Backup to GCS, no paths:), which ran on d98d213 (run 37008851020). - Fix: "two service deploys ran (and the Backup to GCS workflow, which runs on every push to main)".

Test runs

Environment for every run: - Venvs. Fresh python3.11 -m venv (CPython 3.11.15, pytest 9.1.1, PyYAML 6.0.3), built from each job's install lines: - ci: ci.yaml's Install Dependencies line, plus -e contracts and docs/whitepapers/requirements.txt; - wire: the suite-wiring line; - gates: the governance-gates line; - lock: requirements.lock.txt plus pytest.

cim and wirem are the same, built for d98d213. Each editable contracts points at the tree under test. - Isolation: - env -i with PATH/HOME/LANG only: no proxy or credential variables; - TMPDIR=/tmp/v14v/<run>; - commit signing off through GIT_CONFIG_* env only; - everything under unshare -rn.

Command Tree Env Result
pytest tests/governance -c tests/governance/pytest.ini 482b60b ci 4352 passed, 7 skipped, 6227 subtests, rc 0 (479 s)
same d98d213 cim 4352 passed, 7 skipped, 6227 subtests, rc 0 (718 s, loaded host)
python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts="" (MIZOKI_STORE=memory) both wire / wirem 98 passed, 4 skipped, rc 0
same both lock (google-ads 33.0.0) 102 passed, rc 0
same, services/service-data-manager-connector/tests both wire / wirem 58 passed
same, tests/remediation/test_gaql_governance_wiring.py both wire / wirem 5 passed
same, docs/audits/tests 482b60b, d98d213, 3d5278b wire / wirem 1 failed (test_wo31_register: git show 26bec9c6b… exit 128, object absent from this shallow clone), 7 passed; identical on all three
pytest tests/governance/test_api_lifecycle_inventory.py -c … both wire / wirem 24 passed
bash .github/scripts/content_gates.sh (GITHUB_EVENT_NAME=pull_request) both gates 155 passed, rc 0
python3 scripts/api_lifecycle_check.py both gates rc 0: FAILURES 0, WARNINGS 1, UNKNOWNS 20
python3 scripts/gate_leak_scan.py --check both gates rc 0: 74 invalidated, 0 new, 0 grown, 0 stale
python3 scripts/claude_memory.py check --strict both gates rc 0, "structurally valid"
python3 scripts/check_canon_docs.py (--self-test and plain) 482b60b gates rc 0 each; 48 files, 8 held
deploy_router.py --base fa1cc19 --head 482b60b 482b60b gates 21 files: deploy-google-ads-gaql 8, deploy-ui 1, frontend-guard 1
deploy_router.py --base f17e068 --head d98d213 d98d213 gates same: 21 files, 8 / 1 / 1
GAQL test file after content gates in the same tree (11 .pyc under the roots) 482b60b wire 39 passed, 4 skipped
Rule removals: 94 (probes/mutations14.py), plus U+FFFE/U+FFFF in both readers, plus each of the 4 roots; pin class or inventory per removal 482b60b wire / ci Fail nothing (7 of the 94):
- C15, N03 and R24, as recorded;
- O10 and P09 (NIT 2);
- T04/T05, which remove the real-tree calls and are not rules.
The noncharacter removal also fails nothing. Every other removal fails ≥1 test (87 of the 94, and each root).
68 kept seeds (vfy10/vfy11 drivers, paths only, plus a wrapper that parks the old pin copy while the new GAQL pin runs) 482b60b vs 1e78fad pins ci + wire 56 caught by both, each failing the same single test; 12 pass both (B00, B16, C1–C4, G0, GFP, X0, XFP1, XFP2, Z0)
Pass 11's 13 seeds (vfy12/probes/seeds12/seeds.py unchanged; 1e78fad's test files swapped in place for "old") 482b60b vs 1e78fad ci + wire as the §4.23 bullets say (see pass-11 table)
My seeds N1–N9 (whole GAQL file), and N1/N3/N4/N6/N7 against 1e78fad's pin 482b60b wire NITs 1, 4 and 5; N4 (README naming the manifest) fails closed by design; N5 (README naming the Cloud Build file) passes
DM size, own formula code, real lifecycle 482b60b wire NIT-4 row above
gcloud 530.0.0 loader (/opt/google-cloud-sdk, bundled python, empty CLOUDSDK_CONFIG) — offline NIT-5 row above; U+FFFE/U+FFFF refused
GitHub REST (gh api, read-only): PR #1302/#1303/#1308, check runs on 482b60b/8c4f986/c9df080/99381e8, runs on d98d213, jobs, two job logs — network as above

What I did not check

  • Live behaviour:
  • live provider, Cloud Run or Cloud Build behaviour;
  • the serving revision's env and secrets;
  • the GAQL routes (IAM-locked);
  • whether the Data Manager connector's manual deploy has run.
  • Not reproduced:
  • S4/N1's arming end to end through gcloud (pass 11 measured S4's; N1 uses the same sed and submit);
  • the builder's own harness and fuzz scripts (mut13.py, run_in13.py, dm_size13.py, fuzz12.py), which are outside the paths I may read;
  • a structural fuzz.
  • Not covered:
  • GitHub Actions' YAML parser;
  • the console's vitest, tsc and Playwright suites;
  • the full tests/remediation;
  • a DNS audit.
  • The A6/A7 commit attributions in 99381e8: checked at file level only.

Disclosures

  • Main checkout:
  • Read only, with GIT_OPTIONAL_LOCKS=0. I ran git worktree add/remove, git show and git archive there.
  • At the end: status clean, HEAD 482b60b, 0 stashes.
  • base, fu12, memwt2 and memwt3 untouched.
  • My worktrees, under vfy14: wt482, wtmerge, wt1e7, src482, srcm, g482b, gmergeb, mutA–C, mut, mut2, mut3, mut6, mutb, probe, probe2 and b3d. Seeds went only into the mut and probe trees, each restored with git checkout/git clean. All of them are removed, along with the venvs and /tmp/v14v. No /tmp/wo26-* or /tmp/v417-* entries.
  • One discarded run. My first spine run at 482b60b used a venv whose editable contracts pointed at another worktree. test_pilot_report::test_default_ledger_path_is_the_in_tree_ledger failed on the ledger path. That was my setup, not the range. I re-pointed every editable install to the tree under test and re-ran: 4352 passed.
  • Copies I ran from:
  • a throwaway git archive copy of the cell plus a scratch venv, for the O10 demonstration (both removed);
  • pass 11's seeds and the vfy10/11 drivers, copied into vfy14/probes (paths changed only).
  • Read outside vfy14: vfy10–vfy12 kept files and pass 11's transcript.
  • Network:
  • PyPI installs through the proxy;
  • GitHub REST reads.

I made no provider call. Every gcloud run was offline, with no credentials, under unshare -rn. - No writes: no pushes, comments, records, deploys or dispatches. - Kept in /tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy14/: REPORT.partial.md (it also holds this report), FINAL.md, logs/ (gates, mutations, replays, own seeds) and probes/ (mutations14.py, run_mutations14.py, replay/replay14.py, seeds12/replay12_14.py, own14/, dm_size14.py, gc/).

4.25 Pass 12 dispositions (record corrections in the commit that adds this section; no code change)

Pass 12 found no blocker, no MAJOR and no MINOR. What it reproduced: - pass 11's six arming routes inside the pin's checks fail 482b60b's pin, and 1e78fad's catches none of them. S7, FP1 and FP2 fail both; S2, S3, S5 and CH1 pass both; - of the 68 earlier kept seeds, 56 are caught by both pins, each failing the same single test, and 12 pass both; - 87 of its 94 rule removals fail at least one test; - the Data Manager size table, byte for byte, with its own formula code; - §4.22 against pass 11's hand-back (20,842 characters); - every gate, in fresh venvs, at 482b60b and at d98d213, with the same results. test_wo31_register fails the same way on 3d5278b (shallow clone); - the claims about GitHub in 99381e8, except NITs 7 and 8. The Data Manager connector's manual deploy leaves no trace on GitHub, so "it has not run" was not checkable.

The stop rule (RESUME) applies: a blocker, MAJOR or MINOR would be fixed and re-checked; NITs are recorded for the owner as residual, and the lane then waits on the owner's merge decision. So no code changes here. A code change under src/cells/google_ads_gaql/ would also deploy the GAQL cell on merge and would need another blind pass. The record errors among the NITs are corrected (they are this session's own, so non-independent), and nothing else is.

# Finding Disposition Issue
NIT 1 the S4/S4b route class stays open through the cell's own directory. Own files are not held to the rule that only the deploy workflow names the Cloud Build file, so a script there that edits and submits it (N1 to N1d) passes the whole GAQL test file and arms the cell. Not a regression: 1e78fad's pin passes N1 too recorded for the owner, not changed. The pin is a tripwire in front of ACT; what keeps ACT inert is its code (the operation builder raises, and the defaults are off), pinned by tests. The verifier's fix, _names_config applied to the own files other than cloudbuild.yaml (0 flagged on the real tree) plus a seed, or a "not checked" example naming the route, is a test change that would need another pass. It belongs with the API-A12 decision API-A12
NIT 2 rules seeded by nothing beyond the three §3.3 named: (a) the own-file decoding, which is load-bearing; (b) the U+FFFE/U+FFFF refusal in both strict readers; (c) "only the deploy workflow names it" also requiring the deploy workflow to name it. The API-G14 ledger line said "with a seed for each" (a) recorded for the owner, not changed (a seed is a test change). (b) recorded as redundant: both readers end in PyYAML's safe_load, which refuses both characters, as gcloud 530.0.0's loader does, so no seed could pin it. (c) recorded as subsumed by the one---config rule. Corrected: §3.3 (annotation under "Three fail nothing"), the API-G14 pass-11 line (superseded in part) and the API-A12 pass-11 line API-A12, API-G14
NIT 3 §3.3: "The exception is compiled Python: the clean tree holds none" is wrong for a normal run corrected in §3.3 by annotation: Python writes bytecode before the test body runs, so all four exclusions fail the real-tree test in a normal run API-A12
NIT 4 the all-roots Cloud Build name rule fails closed on plausible mentions that submit nothing (N3, a CODEOWNERS line; N6, a scripts/ lint list), with no reviewed allowlist recorded for the owner, with pass 11's NIT 3 (FP1, FP2). Failing closed is the design, and narrowing the rule to admit them would release routes (rule 01). A reviewer who meets one changes the rule under review. A reviewed list of mentions that submit nothing is the verifier's suggested fix; it is a test change API-A12
NIT 5 docstring wording, in the safe direction: (a) "no heredoc or stdin is read", but the code reads a manifest fed through a redirect or a pipeline from a named repository file (N7 is caught); (b) "every file … under" the four roots, but rglob does not descend into a symlinked directory (N8 passes; a symlinked file, N9, is caught). #1302's PR body repeats (a) recorded, not changed. The GAQL docstring sits in the cell's test file under src/cells/google_ads_gaql/, so changing it deploys the GAQL cell on merge, and the change would need another pass. The console pin's scan has the same rglob. The accurate wording is the verifier's: "no heredoc, and no stdin other than a redirect or pipeline from a named repository file"; "every file … under (a symlinked directory is not followed)". (b) adds no route beyond the listed exclusion of files outside the places read API-A12, API-G14
NIT 6 #1302's PR body gives stale seed counts recorded. The body gave the counts after pass 10's fixes. At 482b60b the seed tests hold 32 commands to catch and 15 to leave, 10 decoded files to flag and 4 to leave, 13 strict-reader refusals and 2 accepted texts, and 29 Cloud Build seeds (pass 12's count). #1302 is merged, and its body is left as it was at the merge; this row is the correction API-A12
NIT 7 99381e8: the CodeQL Analyze (python) job recorded as still running at the 13:12Z read had ended success at 13:11:41Z corrected in §3.7, CLOSEOUT's release package and ISSUES.json (publication.follow_up.checks_at_merge), re-read through the API: job 110842038518 ended success at 13:11:41Z, and run 37008407046 at 13:11:42Z —
NIT 8 99381e8: "Two deploy workflows ran" leaves out deploy-gcs.yml (Backup to GCS), which has no paths: filter and runs on every push to main corrected in §3.5, re-read through the API: two service deploys ran, and the Backup to GCS workflow (run 37008851020, success), which uploads a repository snapshot and deploys no service. §3.5 names its run on #1308's merge too (37013362669) —

Statements pass 12 lists as made stale by the merges (true when written): - By #1302's merge, in 482b60b: corrected in 99381e8, which pass 12 checked. The one left is #1302's PR body ("The merge gate waits for it"), left as it was at the merge. - By #1308's merge, in 99381e8: corrected in this commit (CLOSEOUT's publication table, top bullet, blocker row and Source row; RESUME's "Open" line and Pending items; ISSUES.json publication.follow_up_2). §3.1's "GitHub kept the branch" was true of #1302's merge and stays, with #1308's deletion added below it.

Pass 12's verdicts on the pass-11 items stand as reported (§4.24): - defect 1(a): FIXED as stated; - defect 1(b): FIXED; - NITs 1, 2 and 4 to 7: FIXED; - NIT 3's disposition: SOUND; - its agreement with pass 11's verdicts on the pass-10 items.

Pass 12's other observations, recorded as given (§4.24): - What it did not check: - live provider, Cloud Run or Cloud Build behaviour, the serving revision's env and secrets, and the GAQL routes (IAM-locked); - whether the Data Manager connector's manual deploy has run; - S4/N1's arming end to end through gcloud; - the builder's own harness and fuzz scripts; - a structural fuzz, GitHub Actions' YAML parser, the console's vitest, tsc and Playwright suites, the full tests/remediation and a DNS audit; - the A6/A7 commit attributions in 99381e8, which it checked at file level only. - Footprint: it read the main checkout only, ran git worktree add, remove, show and archive there, removed its worktrees and venvs, and kept its notes in vfy14/. One of its spine runs was discarded for a venv whose editable contracts pointed at another worktree: the artifact that earlier passes met, and that #1308's PR body recorded. - API-A12 and API-G14: "The owner's API-A12 / API-G14 decisions remain the cheaper exit." Carried to CLOSEOUT and RESUME. With pass 12, the lane's review loop ends: no further pass is planned, and the NITs above are the owner's.

← All docsView source on GitHub →