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.
- Audit lead examined:
1603d538a1411cd0d12a3aafc7ffbb669dfaa471(historical lead only). - Baseline measured here:
origin/main=3d5278b00a19b47ae369f248953eb9d961ac3ad5(2026-10-01 10:41 -0400, merge of #1290). The checkout is shallow (git rev-parse --is-shallow-repository→true). - Session capabilities (measured 2026-10-01T14:5xZ):
gcloud auth list→ "No credentialed accounts";gh auth status→ token invalid. No Cloud Run, Secret Manager, Cloud Console metrics or provider account access exists in this lane. Every runtime row below that needs them isBLOCKED_EXTERNAL.
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.
Google Ads API
- https://developers.google.com/google-ads/api/docs/sunset-dates — "Last
updated 2026-09-30 UTC." Released versions table:
v22 October 15, 2025 → October 2026 (tentative),v23 January 28, 2026 → February 2027,v23.1/v23.2 → February 2027,v24 April 22, 2026 → May 2027,v24.1 → May 2027,v24.2 June 24, 2026 → June 2027,v25 July 22, 2026 → August 2027,v25.1 August 19, 2026 → August 2027,v25.2 September 23, 2026 → August 2027. Upcoming:v26 October 2026 → November 2027,v26.1* November 2026. "Requests sent to this version will fail on or after the sunset date." Python client minimums: "v25 Min: 31.2.0", "v24 Min: 30.1.0", "v23 Min: 29.2.0". - https://ads-developers.googleblog.com/ — post "Google Ads API v22 sunset reminder", Wednesday, September 2, 2026: "Google Ads API v22 will sunset on October 7, 2026. Starting on this date, all v22 API requests will begin to fail." (The sunset page's "October 2026 (tentative)" is the month; the blog post fixes the day.)
- https://developers.google.com/google-ads/api/docs/api-policy/developer-token — "Developer tokens were sunset on September 9, 2026." "You can continue sending developer tokens in your API call headers, but this is optional and ignored by the API servers." "Your API access levels are determined by the Google Cloud project you used to generate your OAuth credentials. If your app uses the user authentication workflow, then this is the project that owns your OAuth client ID and secret. If you use the service account workflow, then this is the project that owns your service account." "Version v25 of the Google Ads API will throw a AuthorizationError.CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION error if you try to use a Google Cloud project with Test access to make calls to a production account. Older API versions will throw an AuthorizationError.ACTION_NOT_PERMITTED error instead." "We encourage you to update your app to stop sending a developer token as part of your API calls." "We will start rejecting developer tokens in API calls in a future major version of the Google Ads API."
- https://developers.google.com/google-ads/api/docs/api-policy/access-levels — four access levels on the Cloud project: Test (test accounts only), Explorer (2,880 production operations/day; planning, billing, user management restricted), Basic (15,000/day), Standard (unlimited).
- https://github.com/googleads/google-ads-python/blob/main/ChangeLog (raw):
33.0.0 — Google Ads API v25_2 release. Remove Google Ads API v22. Remove Google Ads API v21.32.0.0 — Remove validation checking if developer token is present in configuration. - PyPI
google-ads(JSON API, 2026-10-01): latest33.0.0uploaded 2026-09-23T21:18Z,requires_python <3.15,>=3.9. Wheels downloaded and digest-checked against PyPI;google/ads/googleads/client.pyread from each:
| 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
- https://developers.google.com/merchant/api/guides/versioning — sub-API table: "Reports v1 v1beta Active Discontinued on Feb 28, 2026" (every sub-API's v1beta: "Discontinued on Feb 28, 2026"). Stable versions get "a 12-month deprecation window ... starting from the official deprecation announcement".
- https://developers.google.com/merchant/api/guides/compatibility/migrate-v1beta-v1 — "You will need to call the registerGcp method (only once for each Google Cloud project used for authentication) ... You won't be able to use any v1 or v1alpha API until this step is completed."
- https://developers.google.com/merchant/api/reference/rest/reports_v1/accounts.reports/search
—
POST https://merchantapi.googleapis.com/reports/v1/{parent=accounts/*}/reports:search; body{query, pageSize, pageToken}; "pageSize ... Defaults to 1000. Values above 100,000 are coerced to 100,000."; response{results[], nextPageToken}; scopehttps://www.googleapis.com/auth/content. Same page banner: "Content API for Shopping was sunset on August 18, 2026 ... Starting September 1, 2026, Content API for Shopping requests will experience progressive errors." - https://developers.google.com/merchant/api/reference/rest/reports_v1/accounts.reports
—
ReportRow: "Only the message corresponding to the queried table is populated".ProductPerformanceViewfields:date(Date; "Condition on date is required in the WHERE clause"),week,conversionValue(Price; "Available only for the FREE traffic source"),marketingMethod,customerCountryCode,storeType,offerId,title,brand,categoryL1..5,productTypeL1..5,customLabel0..4,clicks(int64 string),impressions(int64 string),clickThroughRate,conversions(FREE only),conversionRate(FREE only). "Segment fields cannot be selected in queries without also selecting at least one metric field." - https://developers.google.com/merchant/api/guides/reports/overview — "This API is only available for standalone and individual sub-accounts. You can't retrieve reports for advanced accounts." "You can query only one view per request."
Google Data Manager API
- https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest
—
POST https://datamanager.googleapis.com/v1/events:ingest; "At most 2000 Event resources can be sent in a single request";validateOnly: "If true, the request is validated but not executed. Only errors are returned, not results."; response{"requestId": string, "fieldWarnings": [FieldWarning]}— "fieldWarnings[] Detailed row-level warnings with field paths." - https://developers.google.com/data-manager/api/reference/rest/v1/FieldWarning
—
{reason (WarningReason), description, field}; reasons includeWARNING_REASON_CUSTOM_VARIABLE_NOT_ENABLED,WARNING_REASON_GENERIC,WARNING_REASON_INVALID_MERCHANT_ID, ... - https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve
—
GET https://datamanager.googleapis.com/v1/requestStatus:retrieve?requestId=; responserequestStatusPerDestination[]withdestination,requestStatus(REQUEST_STATUS_UNKNOWN,SUCCESS"Processing succeeded for all records without any errors. However, there may be warnings",PROCESSING,FAILED"Processing failed for all records",PARTIAL_SUCCESS),errorInfo("Only populated if the requestStatus is FAILED or PARTIAL_SUCCESS. This field isn't populated while the request has requestStatus of PROCESSING"),warningInfo, andeventsIngestionStatus.recordCount— "The total count of events sent in the upload request. Includes all events in the request, regardless of whether they were successfully ingested or not." "The order of the statuses matches the order of the destinations in the original request."
Meta Graph / Marketing API
- https://developers.facebook.com/docs/graph-api/changelog/versions/ — Graph
API:
v26.0 July 29, 2026 TBD,v25.0 February 18, 2026 → July 29, 2028,v24.0 → February 18, 2028,v23.0 → October 8, 2027,v22.0 → May 20, 2027,v21.0 October 2, 2024 → January 21, 2027,v20.0 → September 24, 2026. Marketing API: "Marketing API version auto-upgrade will release on July 29, 2026."v25.0 February 18, 2026 → TBD,v24.0 → October 6, 2026,v23.0 → June 9, 2026,v22.0 → February 19, 2026,v21.0 → September 9, 2025. - https://developers.facebook.com/docs/graph-api/changelog/version26.0/ —
"Marketing API Released July 29, 2026 | Available until TBD". Changes this
lane maps in ISSUES.json API-B6: Delivery Estimate
daily_outcomes_curve,budget_guardrail,estimate_dauremoved ("Applies to all remaining supported versions on October 27, 2026"); "Instagram Explore Feed placement is no longer available ... requests that explicitly specify Explore return an error" (v26.0+); Messenger Stories: "The story value in messenger_positions is silently removed" ("Applies to all Marketing API versions, including unversioned calls, on October 27, 2026"); HEC-Ftargeting_automation.advantage_audienceexplicit on ad set creation (v26.0+); poll ads and web-only destination for Web+App campaigns (all versions 2026-10-27); legacy Graph protocol features (pretty,debug,date_format,GET /?ids=,If-None-Match; all remaining versions from October 27, 2026); Shops ads default destinationWEBSITE_AND_SHOP(v26.0+). - https://developers.facebook.com/docs/marketing-api/overview/versioning/ — "Once a version is unavailable, any calls made to that version number may fail or be upgraded to the next available version." "the auto-upgrade is not applied to endpoints affected by next available version". "If an API call targets a version that has been deprecated and has been automatically upgraded, an API response header is included ... X-Ad-Api-Version-Warning". "Unversioned calls are invalid and will fail when made against Marketing API endpoints."
- Conversions API pages read (Using the API, Marketing API versioning, Graph
versioning) do not state which expiry table governs
/{pixel_id}/events; recorded as unresolved in API-B7.
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.
- Shopify — https://shopify.dev/docs/api/usage/versioning: "| 2026-07 | July 1, 2026 | July 16, 2027 15:00 UTC | Latest stable" (column "Accessible until"); "If your app targets an inaccessible version, Shopify falls forward and responds using the oldest accessible stable version."
- Klaviyo — https://developers.klaviyo.com/en/docs/changelog_: "Revision
2024-10-15 (GA) Revision supported until: 2026-10-15". No per-revision date
for 2026-07-15; the policy page
(https://developers.klaviyo.com/en/docs/api_versioning_and_deprecation_policy)
says "Each revision is supported for 2 years after its release" (so
2028-07-15 is DERIVED, not published) and "Klaviyo falls forward and responds
to your request with the same behavior as the next oldest revision"; removed
endpoints answer 410. Breaking changes between 2024-10-15 and 2026-07-15
(changelog sections): Bulk Subscribe/Unsubscribe require
subscriptions(2025-01-15); plural profile conversations (2026-07-15); Get Events returns events whose metric cannot be resolved by default (2026-07-15). - LinkedIn —
https://learn.microsoft.com/en-us/linkedin/marketing/integrations/migrations?view=li-lms-2026-09:
"...version 202601 (January 2026)... | January 15, 2027 | Active",
"...version 202604 (April 2026)... | April 15, 2027 | Active";
https://learn.microsoft.com/en-us/linkedin/marketing/error-responses?view=li-lms-2026-09:
a deprecated version header answers 426
NONEXISTENT_VERSION("Requested version yyyymmdd is not active"). - Amazon SP-API — https://developer-docs.amazon/sp-api/docs/catalog-items-api.md: "Current version: v2022-04-01"; product-type-definitions-api.md: "Current version: v2020-09-01"; sp-api-deprecations.md (updatedAt 2026-09-09): no entry for either; "Removed indicates that calls to the resources fail as of the removal date."
- Amazon Ads reporting — deprecations release note (content host
d3a0d0y2hgofx6.cloudfront.net/en-us/release-notes/deprecations.md, named by the page's own server config): "All v3 reporting endpoints and associated report types are also deprecated ... available throughPOST /reporting/reports"; "Hard shutoff date: ... v3 reporting ... will stop delivering data on June 30, 2027"; Reporting API v1 "now generally available" (2026-09-30). - Google Analytics — https://developers.google.com/analytics/devguides/reporting/data/v1: "Beta : No breaking changes are expected in this channel." Measurement Protocol (https://developers.google.com/analytics/devguides/collection/protocol/ga4): "will remain operational with no plans for deprecation".
- Merchant API Accounts — versioning guide: "| Accounts | v1 v1alpha v1beta | Active Active Discontinued on Feb 28, 2026"; "We commit to a 12-month deprecation window for stable major versions".
- The Trade Desk — partner portal and
api.thetradedesk.com/v3/docare login-gated (401); the public OpenTTD page https://open.thetradedesk.com/rest/openttd/advertiser/content/docs/Foundations/resources/doc/ApiChanges: "We don't employ a formal versioning policy"; "communicate at least 3 months before planned changes that require integration changes take effect". - Data Manager — GA announcement 2025-12-09 (https://ads-developers.googleblog.com/2025/12/the-data-manager-api-is-now-generally.html); v1 is the only version in the reference; no versioning or sunset policy page was found (release-notes / changelog / versioning URLs answered 404).
- Meta Graph — versions page, Graph table: "| v21.0 | October 2, 2024 | January 21, 2027", "| v25.0 | February 18, 2026 | July 29,2028"; Graph versioning guide: "once a version is no longer usable, any calls made to it will be defaulted to the next oldest, usable version." Marketing API v24.0 changelog: "Daily budget flexibility is increasing from 25% to 75%" and "Your weekly spend will not change, and will not be greater than 7 times your daily budget". v26.0 changelog: Explore Feed placement "requests that explicitly specify Explore return an error"; Messenger Stories "The story value in messenger_positions is silently removed" (v26.0+; all versions 2026-10-27). No Graph or Marketing changelog from v22.0 to v26.0 lists a Conversions API change (grep over the five pages: only the v26 Business SDK note).
- Data Manager requestStatus —
https://developers.google.com/data-manager/api/reference/rest/v1/requestStatus/retrieve
(retrieved 15:56Z):
ErrorInfo {errorCounts[{recordCount, reason}]}("May not be populated in all cases"),WarningInfo {warningCounts[...]},IngestEventsStatus {recordCount}("Includes all events in the request, regardless of whether they were successfully ingested or not").
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:
wire_docs_audits_tests_:docs/audits/tests/test_wo31_register.pyrunsgit show 26bec9c6…:docs/OPEN_ITEMS.md, a commit this shallow clone lacks; it fails identically on base3d5278b, and CI's suite-wiring job (full history) passes it.
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)
- gateway (
tests/connectors/test_api_compat_2026_10.py): 8/8 mutants caught. - Data Manager (
test_api_compat_final_status.py): 8/8 caught — applied on acceptance, duplicate refusal removed, sweep unbounded, warnings dropped, tenant scoping removed, success aggregated withany, expiry disabled, live upload without tenant. - WO-45 guard widening: on
origin/mainit reportsad_integration_health.py:393 v22andunified_platform_integration.py:72 v18, the two pins the first-line rule never saw. - Pass-3 heals (
22f711d), each new test run against the old code in a throwaway worktree: - On
db3c271's code, 10 fail: 7 GAQL (TestChangeStatusLimit×2,TestReadsThatCrossTheSunset,TestActGuards×2,TestLiveFieldLookup, the partial-failure test) and 3 Data Manager (the claim-stamp and own-claim tests); 65 pass. On the Decisions route the old code answers502 LIMIT_NOT_SPECIFIED; in the sunset-before-ACT test it reaches the retired version's client and attempts the mutations, which the placeholder operation builder refuses. - The corrected D2 test passes on
db3c271(its fix,e3bd49e, is there) and fails on3f89cd0's code:28 != 0, the 28 locally authorized actions reach ACT. Its sibling fails there too. test_the_console_email_route_stays_unarmed_on_deployfails whenEMAIL_SERVICE=klaviyois seeded into the console deploy's env map.fc2a3a3:TestRegistryAgainstTheV25FieldReferencefails on5ff9bdb's registry (conversion_segmentation_v1,metrics.cost_per_conversion, not selectable with the conversion-action segments) and passes now.- Pass-4 heals (
b03f33e), each new test run against9fd5982's code in a throwaway worktree: -
7 fail there. 5 are GAQL tests:
test_the_changes_route_sends_its_own_limit;- both
TestRunsDecideFromTheirOwnReadstests; TestLiveFieldLookup, whose fake now refuses the FROM clause the old query sent;test_the_executor_holds_no_client_of_its_own(V5-12, added in9d76b52; this count uses9d76b52's test files).
The other 2 are the Data Manager late-read tests. The rest of those two files pass there: 31 GAQL tests (4 skipped) and 34 Data Manager tests. - The pins pass on both trees, as pins of unchanged values do. On
b03f33e, each of ten seeded flips fails exactly one test:Seeded flip Test that fails each of the deploy's three values; an added --update-env-varstest_the_deploy_keeps_live_mutations_offeach of the three code defaults test_the_code_defaults_keep_live_mutations_offan operation builder that returns test_the_operation_builder_refusesmetrics.cost_per_conversionback inconversion_segmentation_v1TestRegistryAgainstTheV25FieldReferenceEMAIL_SERVICE=klaviyoin the console's env maptest_the_console_email_route_stays_unarmed_on_deployThe worktree was clean after each restore. - Pass-5 heals (
c7d8904), in throwaway worktrees: - On2ee03e0's code withc7d8904's test files, 3 fail: -test_an_mcc_run_refused_for_a_synthetic_child_names_its_child_runs(N5); -test_a_late_read_is_never_applied_to_a_re_sent_record(N1); -test_a_late_read_notes_what_it_answered(N2).Everything else passes there: the GAQL file 36 passed + 4 skipped, the Data Manager suite 51, the inventory tests 23. - The registry check's seeds fail (
test_the_check_catches_what_it_encodes) when the attributed-resource rule or the segment-to-segment rule is removed, or when the cumulative skip pass 5 described is restored. - Seeded real deploy files each fail exactly the pin that guards them: - a console substitution default carryingEMAIL_SERVICE; ---flags-filein the console deploy; - a second, space-form--set-env-varsstep in the GAQL deploy; ---flags-filein the GAQL deploy.The clean files pass. -
TestLiveFieldLookupfails when the lookup's query gains a bogus WHERE term. - Pass-6 heals (9d9cd01,85b7ecb), in throwaway worktrees: - On701f67c's code with9d9cd01's test files, 2 fail: -test_a_malformed_status_body_is_read_not_raised(D3:AttributeError: 'str' object has no attribute 'get', raised atrequest_tracking.py:336); -test_a_read_that_outlived_its_lease_releases_only_its_own_claim(D4: the note's reason).Everything else passes there: the Data Manager suite 52, the GAQL file 37 passed + 4 skipped, the inventory tests 23. The pins pass on both trees, as pins of unchanged files do. - Seeds on the real files. With
9d9cd01's test files, each fails exactly the test named. The last column is the result with701f67c's test files.Seed Test that fails With 701f67c's testsa step in deploy-ui.ymlrunninggcloud run services update … --update-env-vars EMAIL_SERVICE=…test_the_console_email_route_stays_unarmed_on_deploypasses a second, space-form submit of the console build in deploy-ui.yml, with another substitutionsame fails the name added to scripts/ops/deploy_frontend_cloudrun_prod.sh's env mapsame passes --update-env-vars EMAIL_SERVICE=…onpatch-react-rsc-gcp.yml's console deploysame passes a second pair after ${{ github.sha }}indeploy-ui.yml(pass 6's seed 1)same passes a quoted pair there that puts a shell command into _REQUIRE_AUTH(seed 1)same passes pass 6's seed 2 in deploy-all.yml, as it gave it ('--substitutions=^:^…,EMAIL_SERVICE=…:_IMAGE_TAG=…')same passes a plain second pair in deploy-all.ymlsame passes ENV EMAIL_SERVICE=…in the console's Dockerfile (seed 3)same passes --flags-fileondeploy-ui.yml's submit (seed 4)same passes another --configindeploy-ui.yml(seed 4)same passes another --configindeploy-google-ads-gaql.ymltest_the_deploy_keeps_live_mutations_offpasses a second, space-form --configtheresame passes a step there running gcloud run services replaceon the reference manifest, with itsGAQL_ENABLE_LIVE_MUTATIONSset to "true" (pass 6's D7). Pass 7 (N1): not pass 6's seed, which put the step in the cell's Cloud Build file; that one passed these pinssame passes a script under deployment/naming the reference manifestsame passes A look-alike name (
EMAIL_SERVICE_URL) in a deploy script passes both. The clean files pass both, and the worktree was clean after each restore. Pass 6's seed 5, a name assembled at run time in a shell step, was not seeded: it is out of the pin's reach, and its docstring says so. Pass 7: inaccurate in the harmless direction. The seed as pass 6 wrote it carries--update-env-varsin a shell string, which the substring merging-flag check catches. -85b7ecb: with the metric half removed again, exactlytest_the_check_catches_what_it_encodesfails. Its new seed dropscampaignfrommetrics.clicks' list. - Pass-7 heals (49f8d80), in throwaway worktrees: - Ond14dba0's code with49f8d80's Data Manager tests, 1 fails:test_a_status_body_out_of_range_is_read_not_raised(OverflowError: cannot convert float infinity to integer). The other 54 pass there. - Before the fix, ond14dba0's code, a probe swept three due records, the first answering with anInfinitycount. The first sweep raised at it and read nothing else. Sweeps inside the lease skipped it and finalized the other two. After the lease it raised again, and its checks stayed 0. By reading, the budget and TTL checks run inside the update that raised, so nothing could retire it. With the fix one sweep finalizes all three. Pass 8 measured it: 80 hours of 1-minute sweeps ond14dba0's code gave 960 raises, one every 300 s, and the record stayedsubmittedwith 0 checks, past the 72-hour TTL. - The verifiers' own seeds, replayed on the real files rather than rewritten from their reports: - pass 7's seed driver (vfy8/probes/seeds.py), unchanged except for its paths: its 15 replays of this record's seeds, its look-alike, its clean tree and its 12 own seeds V01–V12; - pass 6's D7 seed, as pass 6 wrote it.Each seed ran against
49f8d80's pins and againstd14dba0's. Of the 28 arming routes,49f8d80's pins catch 28, each failing exactly the test named;d14dba0's catch 15. By family: the console route 20 of 20 (d14dba0: 11), the GAQL deploy 8 of 8 (d14dba0: 4). The clean tree and the look-alike name (EMAIL_SERVICE_URL) pass both, and the worktree was clean after each restore.Seed With 49f8d80's pins, the test that failsWith d14dba0's pinspass 6's own D7 seed ( vfy7/probes/mutate.py,gaql_services_replace): a step in the cell's Cloud Build file replacing the service from the reference manifest, itsGAQL_ENABLE_LIVE_MUTATIONSset to "true"test_the_deploy_keeps_live_mutations_offpasses a deploy-ui.ymlstep runninggcloud run services update … --update-env-vars EMAIL_SERVICE=…test_the_console_email_route_stays_unarmed_on_deployfails a second, space-form submit of the console build in deploy-ui.yml, with another substitutiontest_the_console_email_route_stays_unarmed_on_deployfails the name added to scripts/ops/deploy_frontend_cloudrun_prod.sh's env maptest_the_console_email_route_stays_unarmed_on_deployfails --update-env-vars EMAIL_SERVICE=…onpatch-react-rsc-gcp.yml's console deploytest_the_console_email_route_stays_unarmed_on_deployfails a second pair after ${{ github.sha }}indeploy-ui.yml(pass 6's seed 1)test_the_console_email_route_stays_unarmed_on_deployfails a quoted pair there that puts a shell command into _REQUIRE_AUTH(seed 1)test_the_console_email_route_stays_unarmed_on_deployfails pass 6's seed 2 in deploy-all.yml, in its^:^formtest_the_console_email_route_stays_unarmed_on_deployfails a plain second pair in deploy-all.ymltest_the_console_email_route_stays_unarmed_on_deployfails ENV EMAIL_SERVICE=…in the console's Dockerfile (seed 3)test_the_console_email_route_stays_unarmed_on_deployfails --flags-fileondeploy-ui.yml's submit (seed 4)test_the_console_email_route_stays_unarmed_on_deployfails another --configindeploy-ui.yml(seed 4)test_the_console_email_route_stays_unarmed_on_deployfails another --configindeploy-google-ads-gaql.ymltest_the_deploy_keeps_live_mutations_offfails a second, space-form --configtheretest_the_deploy_keeps_live_mutations_offfails a step there running gcloud run services replaceon the reference manifest, flipped to "true"test_the_deploy_keeps_live_mutations_offfails a script under deployment/naming the reference manifesttest_the_deploy_keeps_live_mutations_offfails V01: EMAIL_SERVICEin the console'senv.production.yamltest_the_console_email_route_stays_unarmed_on_deploypasses V02: a deploy-ui.ymlstep runningservices update --env-vars-file=on that file (which names it)test_the_console_email_route_stays_unarmed_on_deploypasses V03: scripts/arm_email.mjs, run by a steptest_the_console_email_route_stays_unarmed_on_deploypasses V04: an extensionless .github/scripts/arm-email, run by a steptest_the_console_email_route_stays_unarmed_on_deploypasses V05: Dockerfile.prodwithENV EMAIL_SERVICE, and the console Cloud Build file's-fpointed at ittest_the_console_email_route_stays_unarmed_on_deploypasses V06: next.config.jswithenv.EMAIL_SERVICEtest_the_console_email_route_stays_unarmed_on_deploypasses V07: a new workflow submitting miz-oki-command-center-ui/./cloudbuild.yamlwith extra substitutionstest_the_console_email_route_stays_unarmed_on_deploypasses V08: a second --substitutionsin the middle of a line ofdeploy-ui.yml's submittest_the_console_email_route_stays_unarmed_on_deploypasses V09: EMAIL_SERVICEincloudbuild.otel.yaml's Knative env, and a new workflow submitting ittest_the_console_email_route_stays_unarmed_on_deploypasses V10: a deploy-google-ads-gaql.ymlstep runningservices update … --update-env-vars=GAQL_ENABLE_LIVE_MUTATIONS=true,…test_the_deploy_keeps_live_mutations_offpasses V11: a copy of the manifest, flipped, at deployment/gaql/live.yaml, replaced by a deploy steptest_the_deploy_keeps_live_mutations_offpasses V12: scripts/arm_gaql.js, which names the manifesttest_the_deploy_keeps_live_mutations_offpasses -
Pass-8 heals (
02b4c3c), in throwaway worktrees: - On
d7a5af2's code with02b4c3c's Data Manager tests, 1 fails:test_status_totals_and_rows_stay_in_what_the_store_holds(two widest counts giveconfirmed_events2**64 − 2). The other 55 pass there. - With the fix in place, removing each of its five parts in turn makes that test fail: the clamped totals, the refusal of negative counts, the row cap, the bounded warning labels and the history note. Restored, it passes.
-
The verifiers' seeds, replayed from the files pass 8 kept (
vfy9/probes/seeds9.py,seeds9_extra.py,seeds9_extra2.py), paths changed only, on02b4c3cwith its pins and withd7a5af2's:- pass 7's driver and pass 6's D7 seed, as pass 8 replayed them: of the
28 arming routes,
02b4c3c's pins catch 28 andd7a5af2's 28, each failing exactly its pin; the clean tree and the look-alike pass both; - pass 8's own seeds, below:
02b4c3c's GAQL pin catches 6 of the 6 GAQL routes (d7a5af2's: 0), each failing exactlytest_the_deploy_keeps_live_mutations_off; its three false positives and the control pass; the two routes now stated out of reach (C3, C4) pass both.
Seed With 02b4c3c's pinsWith d7a5af2's pinsG1: a new workflow running services replaceon a flipped manifest copy kept in the cell's directory (the service named only in the copy)test_the_deploy_keeps_live_mutations_offpasses G2: a fourth step in the cell's Cloud Build file ( idfirst, noentrypoint, flow-list args) replacing from that copytest_the_deploy_keeps_live_mutations_offpasses G3: a deploy-workflow step whose services updateis split by a line continuation, with an env file in the cell's directorytest_the_deploy_keeps_live_mutations_offpasses G4: the same with the verb quoted test_the_deploy_keeps_live_mutations_offpasses G5: a second Cloud Build file in the cell's directory (live settings), submitted by a new workflow test_the_deploy_keeps_live_mutations_offpasses control: a harmless new workflow and a new note in the cell's directory passes passes C1: the homepage deploy mounting SENDGRID_API_KEY, the site's own pilot-email key (a false positive ofd7a5af2's pin)passes test_the_console_email_route_stays_unarmed_on_deployC2: an ops script arming measurement-rails' KLAVIYO_PRIVATE_API_KEY(a false positive ofd7a5af2's pin)passes test_the_console_email_route_stays_unarmed_on_deployC3: a third submitter through working-directory, with the config spelled relative to the console's directorypasses passes C4: YAML-escaped names in an env file under deployment/, applied by adeploy-uisteppasses passes G6: a deploy-workflow step gcloud run deploy google-ads-gaql-cell --env-vars-file=…test_the_deploy_keeps_live_mutations_offpasses GFP: the fleet verify workflow printing a services update {svc} --min-instances=1for each service (a false positive ofd7a5af2's pin)passes test_the_deploy_keeps_live_mutations_off - pass 7's driver and pass 6's D7 seed, as pass 8 replayed them: of the
28 arming routes,
-
Pass-9 heals (
9736385), in throwaway worktrees: - On
b9a35c6's code with9736385's Data Manager tests, 3 fail; the other 55 pass there:test_a_label_the_store_cannot_encode_reads_as_absent:UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' … surrogates not allowed, raised by the test's store, which refuses what Firestore's encoder refuses;test_an_answer_with_more_rows_than_destinations_is_unknown:successwhereunknownis due;test_status_totals_and_rows_stay_in_what_the_store_holds: the same, in pass 8's own test, whose baseline moved.
- With the fix in place, removing each of its five parts in turn makes its test fail (1 failed, 57 passed; the row rule 2 failed, 56 passed): the Unicode check, bytes rather than characters, the description's bound, more rows read as unknown, and the history note. Restored, it passes.
- Each of the GAQL pin's 14 rules, removed in turn, makes
test_the_deploy_scan_reads_commands_as_writtenfail (1 failed, 3 passed each): the repeated-key and alias refusals, YAML decoding, Python decoding, shell words, joined block lists, cuts at&∧, reads of any suffix, the manifest rule, the service-word rule, the bounds of the cell's name, the deploy-workflow rule, quote marks in a config path, and the shell reading of names. - Size, computed with Firestore's documented formula on
apply_status's own output (not run against Firestore): a status row with maximal labels is 23,253 bytes, and the record is 1,030,366 bytes at 44 destinations and 1,077,012 at 46. -
The verifiers' seeds, replayed from the files passes 8 and 9 kept (
vfy10/probes/seeds/:seeds9.py,seeds9_extra.py,seeds9_extra2.py,seeds10_own.py,seeds10_y.py,seeds10_z.py), paths changed only, on9736385with its pins and withb9a35c6's: 55 seeds.- Pass 9's 8 arming routes (X1 to X8):
9736385's pins catch 8,b9a35c6's 0. - Its two spellings (Y1, Y2): caught 2, against 0.
- Its two false positives (XFP1, XFP2) pass.
- The 34 earlier arming routes (pass 7's driver and pass 6's D7 seed, 28; pass 8's G1 to G6, 6) are caught by both.
- The controls and legal seeds pass both: B00, B16, G0, X0, C1 to C4 and GFP.
- Every caught seed fails exactly one test, the pin that guards it.
Seed With 9736385's pinsWith b9a35c6's pinsX1: a flipped manifest copy with a .txtsuffix in the cell's code directory,services replaced by a new workflowtest_the_deploy_keeps_live_mutations_offpasses X2: a YAML folded scalar ( run: >-) splittingservices replacefrom its manifesttest_the_deploy_keeps_live_mutations_offpasses X3: a Cloud Build file under deployment/whose blockargslist has a comment line, submitted by a new workflowtest_the_deploy_keeps_live_mutations_offpasses X4: a Python script under scripts/with a multi-linesubprocesslist, run by a new workflowtest_the_deploy_keeps_live_mutations_offpasses X5: YAML double-quoted escapes for the service name and the key in a deploy-workflow step test_the_deploy_keeps_live_mutations_offpasses X6: shell quotes inside the service name and the key in a deploy-workflow step test_the_deploy_keeps_live_mutations_offpasses X7: a Cloud Build file under deployment/with a flowargslist over two lines, submitted by a new workflowtest_the_deploy_keeps_live_mutations_offpasses X8: the cell's own Cloud Build file gains a first steps:block (build, push,services replaceof a flipped copy); the pinned block follows unchangedtest_the_deploy_keeps_live_mutations_offpasses XFP1: the action runner's deploy env gains the cell's URL (another service) passes test_the_deploy_keeps_live_mutations_offXFP2: a console env file under deployment/carryingNEXT_PUBLIC_GAQL_CELL_URL, applied by adeploy-uisteppasses test_the_deploy_keeps_live_mutations_offX0: the clean tree passes passes Y1: a third console submitter, the path with a quoted segment, an extra substitution test_the_console_email_route_stays_unarmed_on_deploypasses Y2: a second submitter of the cell's Cloud Build file, the path with a quoted segment test_the_deploy_keeps_live_mutations_offpasses - Pass-10 heals ( d1e1e7b;592fa5dchanges the docstring only), in throwawayworktrees: - Each new rule, removed in turn: 38 removals in a clean worktree at d1e1e7b(mut12.py). With nothing removed, the GAQL pin's classpasses (4 passed) and so does the inventory suite. - The command reader's 15 rules and the strict reader's 3 new refusals each make test_the_deploy_scan_reads_commands_as_writtenfail alone(1 failed, 3 passed): - continuation removal; - a quoted word read again; - a verb anywhere after run;- each of the five change marks ( --env-vars-file,--set-env-vars,--update-env-vars,run.googleapis.com,deploy-cloudrun);- a step's usesread with its inputs;- a target after =, and after/services/;- reads after =,@and<;- words cut at brackets and quotes; - odd characters, explicit tags and directives. - Of _cloudbuild_problems' 17 rules, 16 each make the same test failalone. The 17th, "every deploy argument is a string" (C10), fails nothing when removed, because the flag allow-list also refuses a non-string argument. All C10 adds is a named problem in place of a crash. It is recorded as subsumed, not pinned. Pass 11 (NIT 1): not so. That run coerced the arguments to strings instead of removing the rule. With the rule removed, the seed test fails: the flag allow-list crashes on a non-string ( AttributeError) instead of refusing it. Re-measured in thepass-11 block below. - The console reader's three new refusals each make test_config_spellings_and_the_strict_readerfail alone.- Pass 11 (NIT 2): these are the rules this run removed, not every rule the pin holds. Eight more failed no test when removed, the deploy workflow's digest among them. The pass-11 block below seeds them, or says why not. - gcloud's own loader (Cloud SDK 530.0.0), run offline under unshare -rnwith no credentials ( fuzz12.py,classify12.py).- Candidates. Each mutates one of the real Cloud Build files: 300 random insertions of one to three characters from a pool of 50, plus every pool character at the start and at the end of every line. The pool: - ASCII punctuation, space, newline, tab and CR; - NEL, U+2028, U+2029, a byte-order mark, U+FFFE and DEL; - NUL, VT, FF and ESC; - non-breaking space, U+200B, U+3000, an em dash, é,§,·, anemoji, a soft hyphen and U+200F; - a few letters, digits and symbols. - Comparison. gcloud's LoadCloudbuildConfigFromPathloaded each textthe new pins accept. Its Build message was compared with PyYAML's reading put through gcloud's own message conversion ( _YamlToMessageandFinalizeCloudbuildConfig, compared asMessageToPyValue).File (the pin that accepts it) Candidates Accepted Read the same Refused by both Read differently the cell's ( _cloudbuild_problemsis empty)5,501 1,104 1,104 0 0 the console's ( _strict_yamlreads it)37,901 11,994 11,581 413 0 - The 413 refused texts. gcloud itself refuses them, so a deploy of them fails. In 10 of them the two sides' error texts differ. Of the 11 read in full, 8 have an unknown key, 2 a malformed substitution key, and 1 a null key.
- No text gcloud loads is read differently. Pass 10's Z6 and Z6b are refused by the reader, as seeded.
- What this establishes. It is a measurement of single insertions into the real files, not a proof for every text.
- Size (NIT 3), re-measured by this session with Firestore's documented
formula (computed, not run against Firestore). The record goes through
the real lifecycle (
begin_submission,record_accepted,reconcile_record), with every label at its bound:
Destinations Field warnings Status label Bytes Over 1 MiB 44 none SUCCESS1,024,004 no 44 50 maximal SUCCESS1,060,404 yes 44 none maximal (reads as unknown) 1,032,557 no 44 50 maximal maximal 1,068,957 yes 45 none SUCCESS1,047,253 no 45 none maximal 1,055,999 yes 46 none SUCCESS1,070,502 yes - A status row is 23,183 bytes with
SUCCESS, and 23,376 with a maximal status label. - 50 maximal field warnings are 36,400 bytes.
- Pass 9's figures came from a synthetic record that skipped the lifecycle and the field warnings: 23,253 bytes per row, and 1,030,366 at 44 destinations. These replace them, and match pass 10's.
- The verifiers' seeds, replayed from the files passes 8 to 10 kept, with
paths changed only. They ran on
d1e1e7bwith its pins and with4e1fe7a's: 68 seeds, pass 10's 13 (seeds11_own.py,seeds11_more.py) and the 55 of the pass-9 block. - Pass 10's 12 arming routes (Z1 to Z11 and Z6b):
d1e1e7b's pins catch 12,4e1fe7a's catch 0. Its clean tree (Z0) passes both. - The 44 earlier arming routes are caught by both, each failing exactly one test: the 34 of the pass-8 block, and pass 9's X1 to X8, Y1 and Y2.
- The 11 controls and legal seeds pass both: B00, B16, G0, X0, C1 to C4, GFP, XFP1 and XFP2. GFP failed the first version of this fix, which was amended before it was pushed (§4.21).
- One kept driver,
seeds9_extra.py, names its worktree in its own code. A symlink pointed that name at the worktree it ran in; nothing else changed.
Seed With d1e1e7b's pinsWith 4e1fe7a's pinsZ1 GAQL: deploy-workflow step, mid-word shell continuations (upd\ ate, --update-env-v\ ars, the key split), target ${{ env.SERVICE_NAME }} test_the_deploy_keeps_live_mutations_offpasses Z2 GAQL: new workflow, mid-word shell continuations in the cell's name, the env flag and the key test_the_deploy_keeps_live_mutations_offpasses Z3 GAQL: new workflow gcloud run --quiet services replaceof a flipped manifest copy kept as LIVE.md in the cell's dirtest_the_deploy_keeps_live_mutations_offpasses Z4 GAQL: deploy-workflow step gcloud run --quiet services replaceof LIVE.md (flipped copy, cell's dir)test_the_deploy_keeps_live_mutations_offpasses Z5 GAQL: deploy-workflow step gcloud run --quiet services update ${{ env.SERVICE_NAME }} --image=...(deploys the cell another way)test_the_deploy_keeps_live_mutations_offpasses Z6 GAQL: the cell's Cloud Build file, env map reordered and followed by U+2028 + the next item (gcloud's reader joins them) test_the_deploy_keeps_live_mutations_offpasses Z7 GAQL: the cell's Cloud Build deploy step gains env CLOUDSDK_PYTHON=/bin/sh + CLOUDSDK_PYTHON_ARGS= test_the_deploy_keeps_live_mutations_offpasses Z8 GAQL: deploy-workflow step curl -X PATCHthe Run Admin API for ${{ env.SERVICE_NAME }} with a body kept as ARM.md in the cell's dirtest_the_deploy_keeps_live_mutations_offpasses Z9 GAQL: listed verify workflow step bash -c "gcloud run services update google-ads-gaql-cell --region=... --env-vars-file=docs/..."test_the_deploy_keeps_live_mutations_offpasses Z0 CLEAN tree (mut6) passes passes Z6b GAQL: the cell's Cloud Build file gains - --description=GAQL cell+ U+2028 before the env map (gcloud's reader merges the env map into the description)test_the_deploy_keeps_live_mutations_offpasses Z10 GAQL: deploy-workflow step uses: google-github-actions/deploy-cloudrun@v2withmetadata:a flipped manifest copy under docs/test_the_deploy_keeps_live_mutations_offpasses Z11 GAQL: new workflow gcloud run services replace /dev/stdin <src/cells/google_ads_gaql/LIVE.md(redirect; stated out of reach as stdin)test_the_deploy_keeps_live_mutations_offpasses - Pass-11 heals ( 8c4f986;c9df080adds one seed), in throwawayworktrees: - The tree checks, seeded both ways. test_the_tree_checks_read_both_waysbuilds a tree and checks it: - the deploy workflow (item 2): one byte added, and five added steps, each caught under its own digest: a second config, the same config twice, a config that only a YAML reader joins to its flag, a flags file, and a service change; - the four roots (item 3): five files caught, each naming the Cloud Build file or the cell's service, or arming the cell (S4 and S4b among them). A listed file that stops naming the cell is caught too, and two legal look-alikes pass; - _names_config: 7 spellings that name the Cloud Build file, and 3that do not; - the cell's own files (item 4): seven files caught: - S1b; - S1arm's script; - a Markdown file naming the manifest; - S6's Markdown command; - a Python command; - a new file naming the service; - a new file naming a key. A tree passes in which prose and code name the service and a key and this test file and compiled Python are present. This test file is caught when it is not skipped.
test_the_deploy_scan_reads_commands_as_writtengains: - two commands it catches: the cell named in a JSON body, and a file read through$(realpath ...); - one it leaves: a;with no space around it; - the flow-list entry_strict_yamlpasses; - one Cloud Build text: a colon ending a flow-list entry. - Each rule, removed in turn. 66 removals ran in a clean worktree at8c4f986(mut13.py), and five again atc9df080(mut13b.py). With nothing removed, the pin's class passes (5 passed), and so does the inventory suite. - 63 removals each make at least one test fail: - The GAQL reader's 15 rules and its strict reader's three refusals each failtest_the_deploy_scan_reads_commands_as_written. So does each of_cloudbuild_problems' 17. - Continuation removal, the verb rule and the atom cut also failtest_the_tree_checks_read_both_ways, which uses them. - C10 fails withAttributeError: 'int' object has no attribute 'split': the flag allow-list crashes rather than refusing (pass 11, NIT 1). - The reads after=,@and<were removed atc9df080. At8c4f986their patterns also matched_names_config. - The console reader's three refusals each failtest_config_spellings_and_the_strict_reader. - The new rules each failtest_the_tree_checks_read_both_ways:_names_config's five,_root_problems' eight and_own_file_problems' five. One of them, "the deploy workflow passes exactly one--configas written", failed nothing at8c4f986.c9df080adds a seed that only it catches (the same config submitted twice), and there it fails. - NIT 2's three each fail the seed test:_targets_cell's atom pass,_reads' atom pass and_words' punctuation. - The four exclusions each fail the tree test: this test file, compiled Python, the Cloud Build file's own deploy, and prose and code in the naming checks. Three of them fail the real-tree test too. The exception is compiled Python: the clean tree holds none. Pass 12 (NIT 3): not in a normal run. Python writes bytecode before the test body runs, so with the.pycexclusion removed the real-tree test fails with 20 problems, the first a compiled copy of this test file. All four fail it in a normal run. The.pycexclusion's removal passes it only withPYTHONDONTWRITEBYTECODE=1and no__pycache__. - Three fail nothing: -_names_config's shortcut. It is not a rule: it skips texts no decoding could match, and the results are the same without it. - "One env map" in_cloudbuild_problems. A second map breaks the each-flag-once rule and the count of--set-env-vars, and a missing one breaks the count. The rule stays as a guard against an index error. -_words' bracket and comma replacement._atomscuts the same marks wherever a verdict depends on them, and no input was found on which it changes a verdict. It is not seeded. - Pass 12 (NIT 2): these are the three this run's removals found. Pass 12 made 94 removals, plus the noncharacter refusal in both readers and each of the four roots. Besides these three, and two that remove the real-tree calls and are not rules, three more fail nothing: - the decoding of the cell's own files, which is load-bearing (a decoded name in an own file is missed without it) and seeded by nothing; - "only the deploy workflow names the Cloud Build file" also requiring the deploy workflow to name it, which the one---configrule subsumes; - the U+FFFE/U+FFFF refusal in both strict readers, which is redundant: they end in PyYAML'ssafe_load, which refuses both, as gcloud 530.0.0's loader does.Recorded for the owner (§4.25). - The verifiers' seeds, replayed with paths changed only. They ran on
8c4f986with its pins and with1e78fad's. - Pass 11's 13 (vfy12/probes/seeds12/seeds.py, unchanged). Its S7 variant without the digest edits the old test file, so it is not replayed.Seed With 8c4f986's pinsWith 1e78fad's pinsS1: a script in the cell's directory names the reference manifest through a variable; a new workflow runs it test_the_deploy_keeps_live_mutations_offpasses S1arm: S1, with the reference manifest's live-mutations value flipped test_the_deploy_keeps_live_mutations_offpasses S1b: a file in the cell's directory names the reference manifest test_the_deploy_keeps_live_mutations_offpasses S2: a flipped manifest under docs/, applied through a variable a new workflow setspasses (not checked: a variable) passes S3: a listed workflow applies an inline manifest from a heredoc passes (not checked: a heredoc) passes S4: a second submitter; the Cloud Build file's path split by backslash-newlines, edited by sedfirsttest_the_deploy_keeps_live_mutations_offpasses S4b: a copy of the Cloud Build file made through a quoted path, edited and submitted test_the_deploy_keeps_live_mutations_offpasses S5: a listed workflow updates the cell through a variable set in its step's envpasses (not checked: a variable) passes S6: an arming command in a Markdown file in the cell's directory, run by a new workflow test_the_deploy_keeps_live_mutations_offpasses S7: the deploy workflow edits the Cloud Build file before submitting it test_the_deploy_keeps_live_mutations_offtest_the_deploy_keeps_live_mutations_offFP1: a read with a trailing comment that says "deploy", in a listed file test_the_deploy_keeps_live_mutations_off(fails closed; NIT 3)test_the_deploy_keeps_live_mutations_offFP2: a read of the Run Admin API in a listed file test_the_deploy_keeps_live_mutations_off(fails closed; NIT 3)test_the_deploy_keeps_live_mutations_offCH1: the console's deploy step gains a gcloud hook that runs a script under src/passes (not checked: a step's environment) passes - The 68 of the earlier blocks: both pins agree on every seed. The 56 arming routes are caught by both, each failing the same one test. The 12 controls and legal seeds pass both.
- One harness change. The new own-file check reads every file under
the cell's directory, including the copy of
1e78fad's GAQL pin (test_api_compat_binding_oldd14.py). That copy was moved out of the directory while the new pins ran (run_in13.py). - Size (NIT 4), re-measured by this session with Firestore's documented
formula (
dm_size13.py; computed, not run against Firestore). The record goes through the real lifecycle with every label at its bound, then through 20 manual status reads that each fail with an error cut to 200 characters. That fills the history (MAX_HISTORY= 20):
Destinations Field warnings History Bytes Over 1 MiB 42 50 maximal 20 failed reads 1,028,490 no 43 50 maximal 3 entries 1,045,515 no 43 50 maximal 20 failed reads 1,051,932 yes 44 none 20 failed reads 1,038,974 no 45 none 3 entries 1,055,999 yes 45 none 20 failed reads 1,062,416 yes - Notes. A failed read's note is 234 bytes. With a 36-character request id, a late read's note is at most 342 bytes. That is 2,160 bytes more over a full history, which moves neither count.
- Agreement with pass 11. Pass 11 measured 43 destinations at 1,051,932 bytes, 1,045,515 without the reads, and 44 without field warnings at 1,038,974. These agree.
- Pass 9's 8 arming routes (X1 to X8):
3.4 Builds
- GAQL cell image built locally from the branch with a sandbox-only harness
Dockerfile (proxy CA added; not committed), digest
sha256:3341bd88d2791d3d11ef688a670012e4667d25f11d2415b4ff69f06ce10d292b. Offline smoke: v23/v25 →supported, not live (google_ads_credentials_not_configured),data_source: synthetic; v22 →api_version_sdk_unsupported:v22. This is a build check, not a release artifact. python3 scripts/deps_lock.py --check→ 0 findings (18 allowlisted images).- The image above was built before
b4860c8, which changed the GAQL cell (per-call version check, 503 on synthetic channel reads, envelope fallback). It is not evidence for the final head; the deploy builds its own. - Console:
npx tsc --noEmitexit 0 andapp/api/action-hub/email/send/route.test.ts2 passed (vitest 4.1.11, afternpm ci).next lint/next buildwere not run locally; frontend-guard runs them on the PR.
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 |
- Deployed: the GAQL cell's code from #1302, that is the code changes in
606fb8a,e3bd49e,22f711d,fc2a3a3,b03f33eandc7d8904. The rest of #1302's GAQL changes are tests. API-A6, A7, A9, A10, A11 and A13 are DEPLOYED in ISSUES.json. The new revision's routes were not probed: the service is IAM-locked (unauth=403) and this session holds no invoker. - The console run is not this change's alone. It built
mainatd98d213, which also carries #1306's console change (merge commit80bcb6e, minutes before #1302; its own console deploy, run 37008560190, succeeded first). #1302's console change is one comment in the Klaviyo route (API-G14). The console'scloudbuild.yamlatd98d213namesEMAIL_SERVICE0 times. - Not deployed: #1302's Data Manager connector changes (in
606fb8a,e3bd49e,22f711d,b03f33e,c7d8904,9d9cd01,49f8d80,02b4c3cand9736385). They ship only with the connector's manual deploy (ops/remediation/deploy_all.sh), which this lane has not run (API-F1 to F4, API-F6). Whether an operator has run it is not measured: a manual deploy leaves no trace on GitHub, and reading the serving revision needs GCP access (API-E4). This line first said "which has not run" (Copilot review of #1322). - Not runtime-verified: as for #1299, no row is VERIFIED.
#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)
- Head
f44a7d8: CodeQL reported 2 high alerts (py/incomplete-url-substring-sanitization, alerts 291 and 292) in two test filters that selected Google Ads calls with a substring test on the URL.19e8a6ccompares the parsed hostname instead. Every other check that had finished onf44a7d8was green (governance gates, orphaned suites, suite wiring, measurement rails, LII cells, frontend guard, console typecheck, manifest validation, secrets scan, truth gate). - Head
0cf37f0(merged): all 30 check runs green when read (20:10Z) except one CodeQLAnalyze (python)job still running; the CodeQL check itself reported success and both alert threads were resolved as outdated. The claim PR #1300 (f5475c6) read the same: 25 green, oneAnalyze (python)running. - Later heads: see the PR's checks; this file records what was read when it was written.
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 |
- The connectors deploy that ran at the same time belongs to #1328. Run #94
(37130753359) was created at 14:45:23Z for
b303717, before #1322 merged, and its README record commit185f358landed at 14:48:21Z. - The memory on
d0992c1is valid:claude_memory.py check --strictpasses,reindexchanges nothing, no claim is open, andCLAUDE.mdis 16,206 bytes.
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, branchclaude/mizoki-api-compatibility-3ae54n), adversarial passI 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 statusshows only the pre-existing untrackeddocs/audits/api-compatibility/. I did not touch thescratchpad/baseworktree, which is someone else's. Test runs had the proxy variables unset and used a shortTMPDIR.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'sSUNSETtable (tests/governance/test_google_ads_api_version_sunset.py:45-47). The WO-24 test requires every guard version to be in the runner'sSUNSET_API_VERSIONS | SUNSET_SCHEDULE.SUNSET_SCHEDULEholds 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 -qgives1 failed, 394 passedwithAssertionError: {'v23', 'v24', 'v25'}. - The same file passes 40/40 at base 3d5278b and 40/40 at fdd282c. - Who runs it:deploy-service-canonical-ingestion.ymlgates every deploy onpytest tests/remediation -q. Its triggers arecontracts/**, the service itself,ops/remediation/*andsrc/shared/virtuoso_models/**. - So after merge, the next canonical-ingestion deploy fails at its gate. - PR CI stays green:ci.yamlruns onlytest_execution_adapters.pyfrom 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/**inauto-merge-ai-branches.yml. None of the 65 paths matchesprotected_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 HEADlists 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'sCLAUDE.md, the branch inbox, main'sCLAUDE.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-treeexit 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-248stores the warning onself;:321-323reads it back. - Adapters are built once per process (registry.build_adapters), and the warning is never cleared. - Effect: after any response carriesX-Ad-Api-Version-Warning, every later update result, for any tenant, reports that warning. - Probe: one adapter, tenantacmegets a warning header, then tenantglobexgets none.globex'sprovider_responsestill containsserved_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 noproduct_idonproductPerformanceViewrows.projector_kg.py:264keys a Product byproduct_id or offer_id. - Probe output (catalog and performance rows for the same offero1): - catalog row →product_gmc_online-en-US-o1with{price: 1.99, currency: USD}- performance row →product_gmc_o1with{currency: EUR}- The performance row's conversion-value currency lands in the Product node'scurrencyfield, 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_PINSplus the v23–v25 rows) fails CI for any pin site. - The new inventory sayscredential_gatedanddormantrows 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.pygivesFAILURES (0)for the same rows, as a warning only. - CI never setsAPI_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:106pytest 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:59SOURCE_ROOTSleaves outmiz-oki-command-center-ui. -app/api/action-hub/email/send/route.ts:72-76POSTs toa.klaviyo.com/api/events/withrevision: '2024-10-15'(retires 2026-10-15 per the inventory's own table) whenEMAIL_SERVICE=klaviyo. - The inventory has no row for it, andcoverage_gapsreports 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) callssearchStreamand already parses its success body as a JSON array. -google_ads_access_remedy([err])returnsNone; 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-136includepage_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:90claims "so no surface can present it as one". - The cell's only live caller, the Command Center Google channel pages (app/channels/google/lib.tsgaqlGetand its components), never readsdata_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'sledgerandsdk.evidenceand the claims-ledger C38 note. No test checks thatledgerexists.- 12. Inventory statuses:
enhanced_conversions_integration.pyis imported by the deployed Boss and gated byENABLE_ENHANCED_CONVERSIONS. That is "dark" by the inventory's own vocabulary, but it is filed undermeta_marketing.dormant, so its retired v21.0 pin only warns.google_ads.boss_integration_healthis markedcredential_gated, but credentials can be registered at runtime through an API.- 13. GAQL checks the version only once:
client.py:103runs it when the connector is built, so the/healthas_ofdate 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:178still falls back to"v23".- 15. Developer tokens still required in Boss:
platform_rollback_integration.py:240sends the developer-token header.:1160reports the integration enabled only if a developer token exists.mcp_connector_registry_v2validate_credentialsrequires one (lines 1059 and 1493).- 16. Stale skill text:
skills/adwords-virtuoso/SKILL.md:136(and its.claudeand Boss JSON copies) still say v23, pinned inconnector_credentials.py. Nodocs/skills/SKILL_DELTA_*was logged (rule 03).- 17. Merchant provenance
report_viewis taken fromreq.resource's default even whenreq.queryselects a different view.- 18. The Boss health probe ignores the
GOOGLE_ADS_API_VERSIONoverride 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:reconcileis 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'], andget_serviceuses the version set at construction. GAQL tests: 73 passed with the real SDK.- Safety:
flags.pyis untouched, and the runner's deploy workflow assertsEXECUTION_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.pycopies 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.shexit 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 editablecontractsinstall, 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 -qwith 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 ofAPI_VERSION_SUNSETSagainst the guard, dates included. Mutation check: moving the v24 date to2027-05-02makes 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_nodeis left. The new cross-tenant test fails on d787e7e and passes on b4860c8.4 FIXED Performance rows now have record type product_performanceand the projector skips them asunmapped; the conversion currency moved toconversion_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 theaccount_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-18gave 0 failures (a warning only).6 FIXED Unknowns are now raised with warnings.warn.tests/governance/pytest.inihas nofilterwarningsor-p no:warnings. A passing run printedUserWarning: 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 (sha25665d4dbd2…). 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_userswas deprecated 2024-03-14;page_fans(alternativepage_follows) andpage_impressions(alternativepage_media_view) on 2025-11-15.page_views_totalandpage_post_engagementsare still in the v26.0 reference. NIT:RETIRED_PAGE_METRICS(client.py:41) lists only those 3, so e.g.page_impressions_uniquewould still be sent. Nothing in production calls this method.10 PARTIAL The eight /channels/google/*GET routes now return 503 unlessallow_synthetic=true(checked in-process). Butapp/channels/google/page.tsx:32posts 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 readingdata_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. Sotest_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: Noneresolves to…/v26.0;v21.0raises VersionRefused.13 FIXED, but introduces N3 today=Noneis stored, so each refresh uses the real date.extract,/healthanddata_provenanceall 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 --checkandontology_skills_sync --checkboth report OK.17 FIXED report_viewnow 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(configapi_versionis 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_duereturns counts only (recovered/scanned/finalized/still_open/expired). It reads only records withnext_check_at <= now;limit ≤ RECONCILE_BATCH; callers areverify_callerplatform identities. Not in the docstring:recover_stale_sendschanges 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_integrationa "dormant path", but it is imported by the deployed Boss (boss_agent_core.py:2480), and the inventory classifies itcredential_gated. - It never namesmcp_connector_registry_v2, which requiresdeveloper_token(lines 1059 and 1493). - Its next action is "remove the header when a path is armed".PlatformRollbackManagermakes direct Google and Meta mutations from Boss with no DCP orDIRECT_WRITESgate (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.pyuses onlygoogle.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
gatetext quotes--set-env-vars, and the TTV scanners reportproduction/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_statusdrops 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._clienton 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) andAPI-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/sendis 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
backfillis true. So after this fix, one environment variable (EMAIL_SERVICE=klaviyoplus a key) turns on a working provider write outside DCP → action-runner (law A.7).- It is not armed:
EMAIL_SERVICEis 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
_clientbetween_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/remediation396 passed 1 failed (finding 1), 394 passed Canonical-ingestion gate: tests/connectors2 failed (N1), 585 passed 584 passed Canonical-ingestion gate: test_kg_write_perimeter.py68 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-connectors2 failed (N1), 386 passed 388 passed ci.yaml test_execution_adapters.py178 passed 177 passed ci.yaml tests/market_signal294 passed 292 passed ci.yaml cell3733 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/services41 passed, 1 skipped 39 passed, 1 skipped Suite wiring: data-manager connector 44 passed 44 passed Suite wiring: claims_backing196 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 andapp/api/action-hub192/192;tsc --noEmitclean;next lintclean 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_dictwith dummy credentials ("x"/"y"/"z"). The library refreshes the token eagerly, so one request went to Google's OAuth token endpoint and came backinvalid_client. No real credential was involved and no Google Ads API call was made, but this broke the no-provider-calls rule.next lintran withoutNEXT_TELEMETRY_DISABLED, so it may have sent a Next.js telemetry ping.- Shared venvs. My first venv build reused the names
scratchpad/venv-ciandvenv-cig, which belonged to another session (created 15:02 and 15:51). uv reinstalled into them and pointed their editablemizoki_contractsat 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 underscratchpad/vfy.- Main checkout. One early
git statusthere 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/v2are removed, along with my venvs. Thebaseandmemwtworktrees 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
syntheticis true, skipping_governleaves the locally authorized actions inauthorized; lines 234–240 then pass them to the executor. Withdry_run=false,human_approved=true, and live mutations enabled, synthetic metrics can therefore drive provider mutations without DCP authorization. Clearauthorizedfor 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
checkstwice. Acquire a per-record transactional lease/check claim beforefetch, 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 returnsExtractionResult.error, butcell.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_syntheticis 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/decisionsand every no-limit run will always answer 502 and plan nothing. 2. One of the twoTestSyntheticRunsNeverMutatetests 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 --statshows the GAQL and Data Manager code identical atb4860c8,0cf37f0and3f89cd0. I ran the new tests against3f89cd0'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 f44a7d8tree, fails with['API-G13', 'API-G14']in the inventory. Mutations atdb3c271:
• 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-261emptiesauthorizedfor a synthetic run,:271re-reads the client,:272forces a dry run. Single call site:git grepfinds one executor call in the repo,orchestrator.py:274. It is reached only throughrun(), 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_SERVICEis absent from the consolecloudbuild.yaml, which uses--set-env-varsand--set-secrets, both of which replace the whole map; the route defaults to'mock'(route.ts:40). Still open: the route staysungated(api-route-roles.ts:92-95). No test pinsEMAIL_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-245snapshot, passed to_search_streamand_service(:272,:313). Remaining read: validation between the snapshot and the stream (:252-253→_live_field_lookup:184-199) still readsself._client. It is benign: the lookup catches the error and_lookupfalls 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 noallow_synthetic: the 8 channel routes, the 3/srpvdalPOSTs and the MCC listing answer 503;/gaql/*,/health,/metricsand 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 fromGOOGLE_ADS_CLIENT_ID/_SECRET/_REFRESH_TOKEN::187-189,:207-227
•enabledappears only inget_status::1160
• mutates withvalidateOnlyfalse::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_credentialsrequiresdeveloper_tokenat lines 1059 and 1493; it has no caller anywhere in the repo.
Boss deploy:cloudbuild.v5.yamluses--set-env-varsand--set-secretsand names no Google Ads or Meta variable.
Error: D7.Finding 19 (record) ACCURATE The GAQL lock moved 15 pins from 3d5278btodb3c271. 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_duecalls it (request_tracking.py:496), and the background loop runsreconcile_due.NIT (finding 4) ACCURATE direct_connectors.py:909defaults toproduct_performance.merchant_record_typereturnsproduct_performance(:397-410), whichprojector_kg.pydoes not map (onlyproduct_report,:345).account_gmc_*is created only in_map_merchant_product(:265).NIT (finding 9) ACCURATE RETIRED_PAGE_METRICSlists 3 metrics (connectors/meta_signals/client.py:41).get_page_insightshas 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
limitcan succeed, and the Decisions page will always error once Google Ads is live - Where: -gaql_registry.py:303defineschange_status_v1. -build()addsLIMITonly whenlimitis truthy (:41-42). - The query is inrun()'s default set. -main.py:386(decisions) and:339(changes) pass no limit. -orchestrator.py:175-186returns before REASON on any failed extraction. - Why it will fail: the installed SDK's v25ChangeStatusErrorEnumdocumentsLIMIT_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_v1fails, the run stops after SENSE, and the route answers 502 every time. - The same happens on/channels/google/changes, and on any/srpvdal/runor/srpvdal/sensecall without a limit. - In/srpvdal/run-mccwithout 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 passeslimit: 50, so this query does not break it. - Fix: - Givechange_statusa mandatory LIMIT of at most 10,000 in the registry. - Pin it with a test over every registered query built withlimit=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"), thee3bd49ecommit message, the #1302 body and the Copilot reply. - Fix: use approval_required withhuman_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) beforerun()checks the errors. The run's own warning (:184, returned in the API result) says "nothing persisted". - Probe: a live fake client where onlychange_status_v1fails → 9save_raw_rowscalls, 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:431stampscheck_claimed_atwith the caller'snow, andreconcile_duepasses onenow, 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,checks2. - 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:49and:94-95,EVIDENCE.md:513-515, API-A7's evidence. - Why it is unsupported: - The only basis iscloudbuild.yaml. It sets--set-env-varsbut passes no--set-secretsor--clear-secrets, so a secret env var mounted on an earlier revision survives (rule 04). - The old manifest at3d5278bmountedGOOGLE_ADS_CLIENT_ID,_CLIENT_SECRET,_REFRESH_TOKENand_DEVELOPER_TOKENfrom 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/healthgoogle_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 usesgcloud run deployflags. - 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:_scanreports 12 lines on bothdb3c271and3f89cd0, andgit grepfinds 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:256contradicts §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…". At3f89cd0, §3.5 said "None."D9 — NIT (record): miscounts -
CLOSEOUT.md:19andRESUME.md:27say "53 implemented and tested". Measured: 53 IMPLEMENTED, 52 of them TESTED (API-G17's testing is NOT_APPLICABLE). -CLOSEOUT.md:165-166says 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 although606fb8aedited_service()andextract()'s labelling. Their tests pass.D10 — NIT (record): revision 00079-ptp was built from
main(e480aaa), not fromcb7b7ff- §3.5 and the deployed issues say "Deploy Marketing Connectors run 36920171263 at cb7b7ff … 00079-ptp". - That workflow checks outref: main(deploy-service-marketing-connectors.yml:60-64and:112-116). -e480aaawas onmainby 20:15:35Z (run 36920255631 created), before this job's checkout at 20:16:21Z. Its README push showse480aaa95..e7348d5c9. -e480aaacontainscb7b7ff, 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 insideextract's own refresh. - Probe: the check passes on 2027-07-31 and the extraction runs on 2027-08-01./channels/google/campaignsanswers 200 with 3 synthetic rows, and/srpvdal/runanswers 200 with synthetic totals (30 sensed). They are labelled only indata_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_onpasses; 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, becauseauthorizedis already empty for a synthetic run. - The executor's client is shared state written per run (:271) rather than passed toexecute(). 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_lookupqueries asegmentingfield. The installed v25GoogleAdsFieldhas 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 perextract. - The GAQL image contains nomizoki_governance, so_governalways returns None in production. A live run's ACT then rests on the request's ownhuman_approved. It is latent today:GAQL_ENABLE_LIVE_MUTATIONS=falseand 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=40336920171187 cb7b7ffc…success 110563954595 yes: revision boss-agent-adk-00423-lqd, runtime 6.49.4, SRPVDAL passed, registry 118 entries36920171312 cb7b7ffc…success 110563954483 yes: /healthreports v25, sunset 2027-08-01,{v22: 2026-10-07}, Meta v26.0, CAPI v25.0, every flag false, allowlist 036920171263 cb7b7ffc…success 110564512882 yes ( 00079-ptp); but see D10 for which tree it built36920171300 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: 30736920255631 e480aaasuccess — 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 head0cf37f0. The merge commit time is 20:14:51Z; the API'smerged_atis 20:14:52Z. #1300merged_atis 20:14:12Z. - #1302 is draft, headdb3c271, basefa1cc19.maingained #1301 (two docs files) since3f89cd0, andgit merge-treeof the PR head ontofa1cc19is 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
uvfrom each job's install lines, insideunshare -rn(loopback only), with proxy variables unset andTMPDIR=/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 skippedsame requirements.lock.txt+ pytest (google-ads 33.0.0)81 passed the new GAQL tests, against the restored 3f89cd0codewiring 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.inici.yaml lint-and-test line + -e contracts+docs/whitepapers/requirements.txt4348 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 -qci.yaml pins 615; 399 passed pytest tests/remediation -q;pytest tests/connectors -q;pytest tests/test_kg_write_perimeter.py -qcanonical-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 on3d5278bbash .github/scripts/content_gates.shgovernance-gates install line first on PATH rc 0, 155 passed vitest run app/api/action-hub/email/send/route.test.tsnpm ci --ignore-scripts, vitest 4.1.11, Node 22.22.0,NEXT_TELEMETRY_DISABLED=1,unshare -rn2 passed python3 scripts/api_lifecycle_check.pygates venv rc 0, FAILURES (0) python3 scripts/gate_leak_scan.py --checkgates venv rc 0: "0 new file(s); 0 grown; 0 stale baseline row(s)" python3 scripts/claude_memory.py check --strictgates 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 db3c271ci venv deploy-google-ads-gaql(5 files),deploy-ui(1),frontend-guard(1)Not checked
- Live provider behaviour. The
change_statusLIMIT requirement comes from the installed SDK's own documentation, not a live call. I did not check whetherconversion_segmentation_v1's cost metric is compatible withsegments.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 thatmerge-treeis clean.Disclosures
- First governance run discarded. It gave 185 failures caused by my environment. The sandbox's global
commit.gpgsign=truecalls 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 throughGIT_CONFIG_COUNTenvironment variables only; no config file was changed.- One import outside the namespace. I checked where
mizoki_contractsresolved by runningpython -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
uvinstead 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 rannpm ciwith--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, HEADdb3c271, 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 copieddb3c271's test file into thef44a7d8worktree.- Removed: all six of my worktrees, all venvs and
/tmp/v3. I did not touchbase,fix4ormemwt2.- 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
segmentingfield is gone, but the lookup still sends aFROM google_ads_fieldclause. 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: removingFROMmakesTestLiveFieldLookupfail. - 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 although22f711dchanged 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, exceptdocs/audits/tests. That red is environmental: it fails identically on3d5278bbecause the shallow clone lacks commit26bec9c6.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 hasge=1. Only the registry builds achange_statusquery (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 isDURING LAST_14_DAYS ORDER BY ... LIMIT 10000.
Reference: the v25 reference markslast_change_date_timefilterable and sortable. Every DURING literal (docs/query/date-ranges) is under 90 days.
Old code:22f711d's tests ondb3c271answer502 LIMIT_NOT_SPECIFIEDon the Decisions route.D2 FIXED Head's TestSyntheticRunsNeverMutateon3f89cd0's code: 2 failed, each28 != 0. The tests pass ondb3c271. The corrected test asserts that some gate authorized before it asserts 0.D3 FIXED (code) The partial-failure test on db3c271fails with 9save_raw_rowscalls.run()is the only caller that persists raw rows: every main.py caller passespersist_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 checks1; atdb3c2711 extra read andchecks2.
Production callers: both passclock=rt.utc_now(main.py:452,:459); the manual refresh passesutc_now().
Same-stamp claims: impossible, because_int_envfloors the lease at 1 s.
Firestore: the stamp is stored and read back as a string, andtransact_updatereturns 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-gaqloutside docs/audits finds nothing; the deploy submitscloudbuild.yaml.D7 (record) ACCURATE The WO-45 guard's _scanreports 0 pins on 2027-01-17 and 12 on 2027-01-18: 8 files, the lines API-G13 lists.api_lifecycle_check.py --as-ofexits 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 ise480aaa95..e7348d5c9.D11 FIXED Routes: app.routeshas 23 method/route pairs. With the connector never live and noallow_synthetic, the 8 channel routes, the MCC listing and the 3/srpvdalPOSTs answer 503. The other routes answer 200 and serve no rows.
Straddle:TestReadsThatCrossTheSunsetfails ondb3c271(200 != 503). No route serves synthetic rows withoutallow_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-alikesAPI-V25,API-E2EandXAPI-A1.D13 FIXED Both TestActGuardstests fail ondb3c271. The old code requested mutate services on the retired client, and_build_operationraised.git grepfinds noexecuteor_execute_onecaller other thanorchestrator.py:284, so no caller breaks. Residual: V5-12.N4 residual FIXED (pinned) Seeding EMAIL_SERVICE=klaviyointo--set-env-vars, or into--set-secrets, fails the test. Gaps: V5-7.Field lookup segmentingPARTIAL (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 copiesgaql_cell/only.cloudbuild.yamlsetsGAQL_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 bothsegments.conversion_actionandsegments.conversion_action_name;conversions,conversions_value,all_conversionsandall_conversions_valueinclude both.
Test: it fails on5ff9bdb'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 hasUNEXPECTED_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 parsesSELECT … FROM …. When I removedFROMin my own worktree, the test failed withNone != {...}.TestRealSdkchecks 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 isvalue_settings.default_valuefilterable, 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-A3source_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: -statusprocessing, withneeds_reconcileFalse, so the sweep never picks it up again; -appliedTrue andconfirmed_events1 kept from the success; -last_checked_atmoved backwards (12:06:01 → 12:01:00),next_check_atin the past,checks2. -db3c271behaves 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, orlast_checked_atis newer than this read's time, record the late read in history only. Never move status orlast_checked_atbackwards.V5-4: MINOR. API-A12's "latent" rests on unpinned defaults, and its exposure is understated. - Unpinned: no test pins
GAQL_ENABLE_LIVE_MUTATIONS=falseincloudbuild.yaml, the_flag(..., False)default (config.py:209), or_build_operationraising.git grepover the tests finds none (rule 01: fail-if-flipped). - Understated: A12 says authorization "rests on the request's own human_approved". The request also choosesautonomy_mode, andautopilotauthorizes 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_liveaftercell.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), then503 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_rowscalls, and the warning "...were not persisted, enveloped or governed". - Fix: persist raw rows inrun()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 delimiternot caught --env-vars-filenot caught a second --set-env-varsflagnot caught removing the unrelated --set-secretstest 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_microswithsegments.deviceFROM campaign, which the reference disallows (attributed resource × segment is not encoded). - Minor behaviours: -if problems: continuetests 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 atdb3c271.act.pynow 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
22f711dchanged its reconcile path (reconcile_record,reconcile_due). That contradicts the ledger's ownreview_track_note. - The EVIDENCE §4.7 D9 row is stale. - §3.5's "Not yet deployed" list omitsfc2a3a3.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 -rnblocked the calls (NameResolutionError). - Fix: injectclient_factory=_FakeClientbeforeGAQLIntelligenceCell()builds its connector.V5-12: NIT. The executor keeps its start-up client. -
MutationExecutor._clientkeeps the start-up client forever, because nothing clears it now. -execute()withoutclient=uses that client, even after the connector dropped it. No caller does this today. - Fix: makeclienta required keyword.V5-13: NIT. Every Changes or Decisions page load now asks Google for up to 10,000
change_statusrows. - 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
uvfrom each job's install lines, insideunshare -rn, with proxy variables unset,TMPDIR=/tmp/v5(governance:/tmp/v5g), and signing off throughGIT_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=memory87 passed, 4 skipped same requirements.lock.txt+ pytest (google-ads 33.0.0)91 passed 22f711d's GAQL and DM tests ondb3c271's codewiring venv GAQL 7 failed, 19 passed, 4 skipped; DM 3 failed, 46 passed head's TestSyntheticRunsNeverMutateon3f89cd0wiring venv 2 failed (28 != 0) TestRegistryAgainstTheV25FieldReferenceon5ff9bdbwiring 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: commit26bec9c6absent), 7 passed; identical on3d5278bpytest tests/governance -c tests/governance/pytest.ini -p no:cacheproviderci.yaml lint-and-test line + -e contracts+docs/whitepapers/requirements.txt4350 passed, 7 skipped, 0 failed, 6227 subtests bash .github/scripts/content_gates.shgovernance-gates install line first on PATH rc 0, 155 passed tests/governance/test_api_lifecycle_inventory.pyci venv 22 passed, plus the seeds above tests/remediation/test_gaql_governance_wiring.pywiring venv 5 passed python3 scripts/api_lifecycle_check.pygates venv rc 0, FAILURES (0), WARNINGS (1) python3 scripts/gate_leak_scan.py --checkgates venv rc 0: 0 new, 0 grown, 0 stale python3 scripts/claude_memory.py check --strictgates venv rc 0 python3 .github/scripts/deploy_router.py --base 3f89cd0 --head 9fd5982gates 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_stateclean againstfa1cc19Not 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 localmerge-tree, to avoid writing objects into the main repository.- Whether Next.js would load an
EMAIL_SERVICEplaced in.env.production.Disclosures
- Main checkout: untouched. Branch
work/mizoki-api-compatibility-3ae54n, HEAD9fd5982, status clean.git worktree add/removewrote only worktree metadata.- Cleanup: I removed all 7 of my worktrees, all 4 venvs,
/tmp/v5and/tmp/v5g. I did not touchbase,fix5ormemwt2. 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:
uvinstead of pip (pytest resolved to 9.1.1), and-p no:cacheprovideron 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.mdin/tmp/claude-0/-home-user-MIZOKICloudRun/3197261c-38e1-556d-ba3d-19d3526cd8c2/scratchpad/vfy5/;- the fetched pages and parsers in
docs/there, withdocs/compare.pydoing 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 5accounts.google.comlookups on the old tree and 0 on the new one. - Gates: all green exceptdocs/audits/tests. That suite fails identically on3d5278b, because this shallow clone lacks commit26bec9c6. - The disagreement: by Google's published documentation,keyword_performance_v1is 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-194buildsSELECT name, category, selectable, filterable, sortable WHERE name = '…'.
Grammar: Google's grammar page isQuery -> SelectClause FromClause? WhereClause? …and says "FromClause … must be omitted when querying GoogleAdsFieldService". The five-language sample omits FROM and usesWHERE name LIKE.
SDK: google-ads 33.0.0 acceptssearch_google_ads_fields(request=None, *, query=None, …), and its category enum hasSEGMENT.
Old code: head's test on9fd5982's code fails withNone != {...}.
Fake fidelity (NIT): the fake checks only FROM and the SELECT list. WithAND not_a_field = 1appended to the query,TestLiveFieldLookupstill passes.V5-2 (record) Content ACCURATE, pointers INACCURATE Content: the corrections match cloudbuild.yaml, which passes no--set-secretsor--clear-secrets.
Pointers: API-A3source_evidence[0]and API-A7verification_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_at12:06:01, needs_reconcile False, one success audit.
- On9fd5982the same probe ends in processing.
- Both new tests fail on9fd5982.
Missing: pass 4's first condition ("the current claim is not this read's stamp"). See N1.V5-4 FIXED Pins: the three TestLiveMutationsStayOfftests each fail on their own flips; see the runs table.
A12: the title now namesautonomy_mode.gates.py:39sets_LOW_RISK_ACTIONS = {ADD_NEGATIVE_KEYWORD, ADJUST_BID}, and_authorizeauthorizes them on AUTOPILOT.
gcloud:--set-env-varsusesUpdateAction, which raises on a duplicate key, and it is mutually exclusive with--update-env-varsand--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: inrun(), 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 atorchestrator.py:207-209, after both the error check and the provenance check.
Callers: no caller passespersist_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 consolecloudbuild.yamlgives no false positive; seedingEMAIL_SERVICE=klaviyofails 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_budgetwithsegments.device) still returns[].V5-9 FIXED Lines: act.py:80-85,:66and:97-106hold the same statements asdb3c271's75-80,61and92-101.
Observation:# MIZ OKI 3.5/site_docs_internal/INTEGRATION_PLAN.html:607still says 75-80.deploy-homepage.ymlrebuilds that mirror at deploy.V5-10 (record) ACCURATE API-F3's review was REVIEW_READY at 5ff9bdband is IN_PROGRESS atb34358c.22f711dchangedrequest_tracking.py. The D9 row and the §3.5 list are annotated.V5-11 FIXED DNS audit (lock venv, unshare -rn):
-9fd5982: 91 passed; 5accounts.google.comand 120169.254.169.254lookups.
-2ee03e0: 99 passed; 0 and 126.
Record wording: N7.V5-12 FIXED Executor: no __init__;clientdefaults to None.
Caller: the only caller (orchestrator.py:298-299) passes the client right afterrefresh_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). On9fd5982the route sentLIMIT 10000.
Decisions route: keeps the cap. The builder's reason is sound: the route'slimitslices decisions after the run, whilerun(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/senseis 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 listsad_group_criterionas 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 selectad_group_criterionfields with the*_viewresources.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 omitsad_group_criterion,campaign_criterionandaccessible_bidding_strategy. -metrics.clicksandmetrics.impressionsomitad_group_criterionandaccessible_bidding_strategythe same way. They name campaign, campaign_budget, ad_group, customer and bidding_strategy. - Google's Cookbook query selects 5 metrics withad_group_criterionfields FROM keyword_view, and the metric lists omitad_group_criteriontoo.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.pyinto my own folder and ran it on2ee03e0and on9fd5982. It flags exactlysegments.dateand the 5 metrics ofkeyword_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 forreq-1at 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_submissionallows a FAILED record to be re-sent, and the record is accepted again asreq-2(attempt 2). 4. R1 then finishes withreq-1's FAILED answer. - Result at head: - status failure,request_idreq-2, attempt 2; - needs_reconcile False; -last_checked_at12:01:00, earlier than attempt 2's submission at 12:06:06; - a secondconversions.request.failureaudit. - Consequence:req-2is never read, and a third re-send is allowed. The same happens on9fd5982. 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: treatcurrent.get("check_claimed_at") != stamp, or a changedrequest_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.9fd5982applied 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-560and:589-618. - Gaps: - The "each query is checked on its own" property is unpinned (the cumulative-check seed stays green). - Pass 4'scampaign_budget×segments.deviceseed is uncaught. The fixture already distinguishes it:segments.device's list omitscampaign_budgetandsegments.date's includes it.ad_group_criterionis 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_SERVICEpin does not read. - Where:tests/governance/test_api_lifecycle_inventory.py:188-239. - Seeds that pass the test: - the_LIFT_ENGINE_URLdefault in the file's ownsubstitutions:block set to"…run.app,EMAIL_SERVICE=klaviyo". Cloud Build expands it inside the--set-env-varsvalue, and gcloud splits on the comma. ---flags-file=…added to the deploy args. - By reading: only thedeploy-to-cloud-runstep 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-537andmain.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 MCCrun_id, which is never persisted, and no child run ids. - Fix: putper_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 at9fd5982; - it says the merge gate waits for pass 4; - its gate table is for9fd5982; - its field-lookup row says only "It now readscategory". - Elsewhere: - EVIDENCE §3.2 says the record-commit gates are recorded in the PR body; at2ee03e0they 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.TestRealSdkbuilds real ones with a stubbed credential factory. What was measured is that no test looks upaccounts.google.com. - API-A12: says the flips were seeded "on 9fd5982's tree", while EVIDENCE §3.3 saysb03f33e. The pin tests do not exist on9fd5982. - 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, whichb34358cchanged but which are REVIEW_READY. Their new lines do match pass 4's report.Ledger at
2ee03e065 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) appliedcleared; nothing applied; no auditRe-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, shortTMPDIR.
Command Environment Result python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts=""@2ee03e0suite-wiring venv, MIZOKI_STORE=memory95 passed, 4 skipped same image-lock venv (google-ads 33.0.0) 99 passed GAQL suite with a getaddrinfoauditlock venv, @9fd5982 / @2ee03e0 91 passed, 5 accounts.google.comlookups / 99 passed, 0services/service-data-manager-connector/testswiring venv 51 passed Head's two test files on 9fd5982's codewiring venv GAQL file 5 failed / 31 passed / 4 skipped; Data Manager suite 2 failed / 49 passed tests/remediation/test_gaql_governance_wiring.pywiring venv 5 passed docs/audits/tests@2ee03e0 and @3d5278bwiring venv 1 failed ( test_wo31_register, commit26bec9c6absent), 7 passed, identical on bothpytest tests/governance -c tests/governance/pytest.ini -p no:cacheproviderci venv (+ -e contracts, whitepapers), signing off throughGIT_CONFIG_*4351 passed, 7 skipped, 6227 subtests, 0 failed bash .github/scripts/content_gates.shgovernance-gates venv first on PATHrc 0, 155 passed api_lifecycle_check.py/gate_leak_scan.py --check/claude_memory.py check --strictgates venv rc 0 each (FAILURES 0, WARNINGS 1 / 0 new, 0 grown, 0 stale / valid) deploy_router.py --base 3f89cd0 --head 2ee03e0gates 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-fileas 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_conversionback inconversion_segmentation_v1, andEMAIL_SERVICEin 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.yamljobs.- 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 fromb34358cto2ee03e0, andc3wtdisappeared 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 touchbase,memwt2orc3wt. Outsidevfy6/I read only pass 4'svfy5/files.- Kept, in
vfy6/:REPORT.partial.md,logs/,probes/, the fetched docs, andp4docs/(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 viewhit 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 venvvenvs, notsetup-python;-p no:cacheprovideron the governance run; commit signing turned off throughGIT_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 withc7d8904'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:273still 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 on3d5278b, because commit26bec9c6is 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 asreq-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".2ee03e0applied 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 withoutattempt,check_claimed_atorchecks.
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 inpublic_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 endsunknown/status_expired. The sweep scans 0 records. The note says "answered success". A manual refresh then sets success withappliedtrue.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 listsegments.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-filein 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_idnull,syntheticnull;
- run raised:run_idnull,syntheticnull, 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 ofper_accountexists outside tests, and the schema isList[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: TestLiveFieldLookupfails.
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:216runsbuild_site_docs.py, whose--out-internaldefault issite_docs_internal. The committed copy (INTEGRATION_PLAN.html:607) still says 75-80.keyword_performance_v1Disposition 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 indeploy-ui.yml:58.--substitutions=_IMAGE_TAG=${{ github.sha }},_REQUIRE_AUTH=falsepasses, 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 onlydeploy-ui.yml. 3.ENV EMAIL_SERVICE=klaviyoin the console Dockerfile's runtime stage (after line 41). 4.deploy-ui.ymlgiven--flags-file=…, or--config=another file that names the variable. 5. An obfuscated shell step, such asN=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-fileand a different--configin those workflows. - Scan the Dockerfile andnext.config.mjsfor the name. - Extend the "out of reach" list beyond "a Cloud Run setting changed by hand".D2 — NIT (record).
CLOSEOUT.md:273reads "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-481callsapply_statuson the late answer.apply_statusraises AttributeError whenerrorInfoorwarningInfois not a mapping (:336,:339). - Scenario (probe P8): a late read gets HTTP 200 with"errorInfo": "boom". - Head raises out ofreconcile_record;2ee03e0noted 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 makeapply_statuscheck 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: statussubmitted,last_checked_atnull. - 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-542and:574-576, API-A13 [6], and the PR body. - What is wrong: - "Not encoded" names onlyad_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, andchange_status'sasset,asset_set,combined_audienceandshared_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 runninggcloud run services replace src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml, with that manifest flipped toGAQL_ENABLE_LIVE_MUTATIONS "true". The GAQL file still passes, 37 tests. By reading, a different--configindeploy-google-ads-gaql.ymlis 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 venvvenvs (CPython 3.11.15, pytest 9.1.1) built from the CI install lines, underunshare -rn, with the proxy variables unset,TMPDIR=/tmp/v7/<run>, and commit signing turned off throughGIT_CONFIG_*environment variables.
Command Environment Result python -m pytest "src/cells/google_ads_gaql/tests" -q -p no:cacheprovider -o addopts=""@701f67csuite-wiring venv, MIZOKI_STORE=memory96 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.comwas recorded)lock venv 100 passed; 126 metadata-server lookups, 0 accounts.google.comservices/service-data-manager-connector/testswiring venv 53 passed tests/remediation/test_gaql_governance_wiring.pywiring venv 5 passed docs/audits/tests@701f67c and @3d5278bwiring venv 1 failed ( test_wo31_register,git show 26bec9c6…exit 128), 7 passed, identical on both; the object is absent from this clonepytest tests/governance -c tests/governance/pytest.ini -p no:cacheproviderci venv (+ -e contracts, whitepaper requirements)4351 passed, 7 skipped, 6227 subtests, rc 0 bash .github/scripts/content_gates.shgovernance-gates venv first on PATHrc 0, 155 passed api_lifecycle_check.py/gate_leak_scan.py --check/claude_memory.py check --strictgates venv rc 0 each (FAILURES 0, WARNINGS 1 / 0 new, 0 grown, 0 stale / valid) deploy_router.py --base 3f89cd0 --head 701f67cgates 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 threegit merge-tree 3f89cd0 fa1cc19 701f67c(stdout-only form)— 0 conflicts c7d8904's three test files on2ee03e0's codewiring / 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-only28: 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-varsand 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 stayed701f67c. I did not touchbaseormemwt2.- 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.mdandledger_diff.txt.- Read outside
vfy7/: onlyvfy6/REPORT.partial.md,vfy6/pr1302.json, and directory listings ofvfy5/andvfy6/.- 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:cacheprovideron the governance run;-rfadded 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 with9d9cd01'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_encodesfails.- 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
9d9cd01and85b7ecb; the PR body correctly saysd14dba0(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
Infinityin anyrecordCount. 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 on3d5278bandfa1cc19: commit26bec9c6is absent from this clone. PR CI ond14dba0: 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.pyandmutate2.pyond14dba0, each fail exactlytest_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. With701f67c's test file, only B02 fails.
Not caught: nine in-repo routes (V01–V09, under N2).D2 (record) FIXED / ACCURATE CLOSEOUT.md:294now 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: AttributeErroratrequest_tracking.py:336.
Head reads these without raising, on both paths:errorInfoa string,warningInfoan int, the row list5, 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): arecordCountofInfinityor-InfinityraisesOverflowErroron 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_criterionis 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-567andmain.py:178-180: a skipped child and a raised child carry norun_idorsynthetickey, 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 9d9cd01and85b7ecbtouch none of their code or tests. These are the only state changes against701f67c.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 rowsACCURATE. §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) andprobes/. Pass 6's final report text is not kept invfy7, 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-gaqlanddeploy-ui, plus thefrontend-guardcheck. "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,scriptsanddeployment, and only.yml,.yaml,.shand.pyfiles there. The cell's owncloudbuild.yamlis 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'svfy7/probes/mutate.pygaql_services_replace, applied verbatim tod14dba0, gives 37 passed and 4 skipped. It does two things: - appends tosrc/cells/google_ads_gaql/cloudbuild.yamla stepgcloud run services replace src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yaml; - sets the manifest'sGAQL_ENABLE_LIVE_MUTATIONSto"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 indeploy-google-ads-gaql.ymlrunninggcloud run services update google-ads-gaql-cell --update-env-vars=GAQL_ENABLE_LIVE_MUTATIONS=true,.... - V11: a copy of the manifest underdeployment/gaql/live.yaml, deployed by aservices replacestep. - 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 noservices 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,:310and: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,scriptsanddeployment". Only.yml,.yaml,.sh,.py,.jsonand.envsuffixes are read. Those roots hold 77.tffiles, 8 extensionless files (includingops/Makefile), and.js,.tsand.hclfiles. - "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 and701f67c's pin (each restored clean afterwards): - V01:EMAIL_SERVICE: klaviyoin the committedmiz-oki-command-center-ui/env.production.yaml. The documentedscripts/ops/deploy_frontend_cloudrun_prod.shturns that file into--set-env-vars. - V02: adeploy-ui.ymlstep runningservices 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.prodwithENV EMAIL_SERVICE, and the consolecloudbuild.yaml's-fpointed at it. No workflow edit is needed, anddeploy-uifires on merge. - V06:next.config.jswithenv.EMAIL_SERVICE. Next 15.5.24 resolves.jsbefore.mjs; I read that, I did not build it. - V07: a new workflow with--config=miz-oki-command-center-ui/./cloudbuild.yamland extra substitutions. - V08: a second--substitutionsin the middle of a line indeploy-ui.yml. - V09:EMAIL_SERVICEincloudbuild.otel.yaml's Knative env (it deploysmiz-oki-command-center-ui), and a new workflow that submits it. - Mitigation: the route also needsEMAIL_API_KEY,SENDGRID_API_KEYorKLAVIYO_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-ftarget, everynext.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:_countcatchesTypeErrorandValueError, notOverflowError. -main.py:412: httpxr.json()usesjson.loads, which acceptsInfinity. - The sweep loop:557has no per-record isolation. - Scenario (probe): a 200 response with"recordCount": InfinityraisesOverflowErroron the applied path and on the late path.reconcile_dueraises at that record, and the other 2 due records staysubmitted. 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:reasonanddestination.referenceare 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 inreconcile_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 in9d9cd01and85b7ecb". -RESUME.md:84-85: "Its two partials … and its seven nits are fixed in9d9cd01and85b7ecb". - Measured:9d9cd01changes 4 files:request_tracking.pyand 3 tests. D2 (the CLOSEOUT row), D6 (API-A6) and D1's record wording were changed ind14dba0. The PR body says so correctly. - Fix: say "the code findings in9d9cd01and85b7ecb; the record findings ind14dba0".N5 — NIT (label): an unreadable body is recorded as the provider's own "unknown". - Where:
request_tracking.py:373. - Scenario: with the row list5, a string or a dict, or a non-mapping body, the record becomesunknown/provider_reported_unknownwith the history note "status read". That is the same record a genuineREQUEST_STATUS_UNKNOWNleaves. 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 list5is 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_typewithcampaign.nameFROMsearch_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 venvvenvs (CPython 3.11.15, pytest 9.1.1) built from the install lines below, underunshare -rn, with the proxy variables unset (both cases),TMPDIR=/tmp/v8/<run>, and commit signing off throughGIT_CONFIG_COUNT/KEY/VALUEenvironment variables only. Every run is ond14dba0unless 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 thedeploy-service-canonical-ingestion.ymlgate.
Command Environment Result python -m pytest "services/service-data-manager-connector/tests" -q -p no:cacheprovider -o addopts=""wire, MIZOKI_STORE=memory54 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.pywire / cing (the only workflow that runs it is deploy-service-canonical-ingestion.yml, aspytest 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 clonepytest tests/governance -c tests/governance/pytest.ini -p no:cacheproviderci 4351 passed, 7 skipped, 6227 subtests, rc 0 (444 s) bash .github/scripts/content_gates.shgates venv first on PATHrc 0, 155 passed python3 scripts/api_lifecycle_check.pygates rc 0 (FAILURES 0, WARNINGS 1, UNKNOWNS 20) python3 scripts/gate_leak_scan.py --checkgates rc 0 (0 new, 0 grown, 0 stale) python3 scripts/claude_memory.py check --strictgates rc 0 (valid) python3 .github/scripts/deploy_router.py --base fa1cc19 --head d14dba0gates 21 files → deploy-google-ads-gaql.yml(8),deploy-ui.yml(1),frontend-guard.yml(1); with--base 3f89cd0, 23 files and the same threegit merge-tree --write-tree 9d9cd01 fa1cc19— tree d5e3561=5971bcb^{tree}: a clean merge with no hand edits. It brought only8924d1c's two Shopify docs; there is no overlap with the PR's 21 files and no interaction701f67c's code with9d9cd01's 3 test fileswire / 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 with701f67c's pinsci + wire each fails exactly the named pin; 701f67c's pins catch 1 (B02); the look-alike and the clean tree pass both12 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_replacenot caughtmetric half removed ( f.startswith("segments."))wire 1 failed (exactly test_the_check_catches_what_it_encodes), 36 passed, 4 skippedData Manager probes ( probes/dm_probe.py,dm_reasons.py) on head and701f67cwire, memory store as reported under D3, D4 and N3 PR #1302 check runs on d14dba0gh api, read-only28: 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 prefersnext.config.jsand inlines itsenv.- 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 rangit worktree addandremovethere, and onegit worktree prune;baseandmemwt2are still listed and I did not touch them. At the start and the end, status was clean, HEAD wasd14dba0and 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 withgit checkout -- .andgit 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,vfy6andvfy7;- 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:cacheproviderand-rf/-rfEadded 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, invfy8/:REPORT.partial.md(which also holds this report),logs/,probes/andgdocs/.
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. Withd14dba0'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 istest_wo31_register, which fails identically on3d5278bbecause this shallow clone lacks commit26bec9c6. - PR CI ond7a5af2: 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_labelreturning 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_statusoutput identical on head and ond14dba0.N3, record: "never retired" ACCURATE (now measured) Old code, 80 hours of 1-minute sweeps: 960 raises, one every 300 s. The record stayed submittedwith 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/85b7ecband the record findings tod14dba0.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 asunknown/provider_reported_unknown. The stated reason (it would widen theunknown_reasonvocabulary) 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, allsegments.date, and each also selects it. So no query has a WHERE-only segment.
Cookbook (last updated 2026-09-30): the "Search terms" query selectssegments.keyword.info.match_typewithcampaign.nameFROMsearch_term_view. Campaign's v25 resource-level segment list (152 entries) has nokeyword.*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.mdexcept the last line, as stated.vfy8/REPORT.partial.mdholds 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. 49f8d80does 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-guardcheck, 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–1034the verb check runs only when a file names the service, and the cell's directory is not scanned beyondcloudbuild.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 andd14dba0's pin, and each was restored clean. - G1: a new push-to-main workflow runsgcloud run services replace src/cells/google_ads_gaql/live.yaml.live.yamlis the reference manifest withGAQL_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 owncloudbuild.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 noentrypoint, and the verb regex missesservices, replace. -.gitignorere-includes/src/(I read this; I did not run a build). - G3 and G4: adeploy-google-ads-gaql.ymlstep runninggcloud run services \, thenupdate google-ads-gaql-cell … --env-vars-file=src/cells/google_ads_gaql/live-env.yamlon 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: adeploy-google-ads-gaql.ymlstep runninggcloud run deploy google-ads-gaql-cell --image=… --env-vars-file=src/cells/google_ads_gaql/live-env.yaml. It needs no trick:run deployis 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_loadand assert the exact step list (name, entrypoint, args). - Before matching verbs, tokenize the arguments: join list items, and strip quotes and line continuations. - Treatrun deploy,services update/replace,--env-vars-file, and--set-env-vars/--update-env-varson the service as changes. - Scan the cell's directory (excludingtests) for any other Cloud Build file or Knative YAML that namesgoogle-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–259with:345–354;test_api_compat_binding.py:959with:1033–1034. - Seeds: each fails the new pin; the old pin passes. - C1:deploy-homepage.yml:409's--update-secretsgainsSENDGRID_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.shsets measurement-rails'KLAVIYO_PRIVATE_API_KEY(named indocs/measurement-rails/RUNBOOK.md:189andklaviyo_feed.py:47). The console test fails. - GFP:verify-cloudrun-state.yml, whose fleet list namesgoogle-ads-gaql-cell, printsgcloud 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_eventsandfailed_eventsare unbounded). In the record:CLOSEOUT.md:60, §4.15 N3, and the PR body's Data Manager row. - Measured (head andd14dba0behave identically): - Two destinations, each answeringrecordCount"9223372036854775807", giveconfirmed_events2^64−2. - A partial success with two such error counts givesfailed_events2^64−2. - An error count of −2^63 givesconfirmed_events2^63+5. -google-cloud-firestore2.34.0 and 2.11.1_helpers.encode_dictrefuse all three, offline:ValueError: Value out of range. - End to end on head: I ran 80 hours of 1-minute sweeps with a store whosetransact_updateruns that encoder (astransaction.setdoes). There were 960 raises. The record stayedsubmittedwith 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-byteprovider_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_eventsNone), 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-uirunninggcloud builds submit .. --config=cloudbuild.yaml --substitutions=…,_REQUIRE_AUTH=false. This does not arm the email route by itself. - C4: YAML-escaped names ("EMAIL\x5FSERVICE") indeployment/ui/runtime-env.yaml, applied by adeploy-uistep 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 thereasonandfieldof anevents:ingestresponse 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 venvvenvs (CPython 3.11.15, pytest 9.1.1), built from the install lines below. - Everything ran underunshare -rn. - Proxy variables unset, and also GH, GCP and AWS credential variables. -TMPDIR=/tmp/v9/<run>. - Commit signing off viaGIT_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 ofdeploy-service-canonical-ingestion.yml(google-cloud-firestore 2.34.0).
Command Env Result pytest tests/governance -c tests/governance/pytest.ini@d7a5af2ci 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 -qwire / cing 5 passed; 396 passed "docs/audits/tests"@d7a5af2and @3d5278b(my own worktree)wire 1 failed ( test_wo31_register,git show 26bec9c6b…exit 128), 7 passed; identical on bothtests/governance/test_api_lifecycle_inventory.pyci 23 passed bash .github/scripts/content_gates.shgates venv first on PATHrc 0, 155 passed api_lifecycle_check.py/gate_leak_scan.py --check/claude_memory.py check --strictgates rc 0 each: FAILURES 0, WARNINGS 1, UNKNOWNS 20 / 0 new, 0 grown, 0 stale / valid deploy_router.py --base fa1cc19 --head d7a5af2gates 21 files → deploy-google-ads-gaql(8),deploy-ui(1),frontend-guard(1)d14dba0's code with49f8d80's Data Manager testswire 1 failed (the named test, OverflowError), 54 passed28 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 d7a5af2gh api, read-only28: 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 rangit worktree add/removethere. Status was clean, HEAD wasd7a5af2and there were 0 stashes, at the start and at the end. I did not touchbaseormemwt2.- 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 withgit checkout/git cleanand 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.pyand 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:cacheproviderand-rf/-rfEadded 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 underunshare -rn. - No writes: no pushes, comments, records, deploys or dispatches. - Kept invfy9/:REPORT.partial.md(which also holds this report),logs/,probes/andgdocs/.
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 on3d5278b(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 runservices replaceon a flipped manifest.d7a5af2's pin caught this.- Seven more routes inside the stated reach pass the new pin (X1–X7: a
.txtmanifest, 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 byd7a5af2'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.pyandseeds9_extra2.py(paths changed only), each fail exactlytest_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 failedd7a5af2'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 failsd7a5af2's.
New: XFP1 and XFP2 fail the new GAQL pin and passd7a5af2's (defect C).Defect 3 (NIT: DM totals and rows), code FIXED as scoped Old code, new tests: d7a5af2's code with02b4c3c's test gives 1 failed (confirmed_events18446744073709551614), 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 withoutdestination, 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 reasonandfieldare 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 oneprovider_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,49f8d80and02b4c3cchanges one code file (request_tracking.py); the rest of each, and all of85b7ecb, are tests.§3.2 pass-8 block ACCURATE. Reproduced on b9a35c6, which has the same code as02b4c3c: 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 in02b4c3c" overstate (defects A, B and D).§4.16 verbatim Not verifiable byte for byte. vfy9/REPORT.partial.mdholds 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 atd7a5af2(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:2442says ".gitignorere-includes/src/"; the notes say.gcloudignore. The tree has!/src/at.gcloudignore:4and 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 in02b4c3c" 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 givesdeploy-google-ads-gaql(8),deploy-ui(1) andfrontend-guard(1), and the console change againstmainis 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 asteps:block tosrc/cells/google_ads_gaql/cloudbuild.yaml: docker build, docker push, thengcloud run services replace src/cells/google_ads_gaql/gaql_cell/live.yaml. The pinned file follows unchanged.gaql_cell/live.yamlis the reference manifest withGAQL_ENABLE_LIVE_MUTATIONS "true". - Test results: the whole new GAQL test file passes (0 failures).d7a5af2's pin failstest_the_deploy_keeps_live_mutations_off. - gcloud's view: I ran gcloud SDK 530.0.0's own loader on that file, offline underunshare -rn.config.LoadCloudbuildConfigFromPathis the--configpath ofgcloud builds submit(submit_util.py:300). It returns 3 steps: build, push,run services replace.imagesare kept, no step carries an env flag, and the only warning is aDuplicateKeyFutureWarning. PyYAML returns the pinned three steps. -deploy-google-ads-gaql.ymlsubmits this file on every push touchingsrc/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 twoargs:, splits the parsers the same way. - Fix: - Load the file with a loader that refuses duplicate keys anywhere (aSafeLoaderwhoseconstruct_mappingraises 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_PATHknows only.yaml .yml .env .json. -:966–986:_commands. A command is one physical line, except contiguous block-list items and backslash continuations.:975replaces 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 runninggcloud run services replace src/cells/google_ads_gaql/gaql_cell/live.txt. gcloud reads FILE througharg_parsers.YAMLFileContents→yaml.load_all_path, with no suffix check (read). - X2, pass / pass: a workflow steprun: >-foldinggcloud 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 Buildargs:block list with a comment line between- runand- services, submitted by a new workflow. The cell's owncloudbuild.yamlhas comments betweenargsitems. - X4, pass / pass:scripts/arm_gaql.py, asubprocess.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 underdeployment/. - X5, pass / FAIL: adeploy-google-ads-gaql.ymlsteprun: "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 withgoogle-ads-gaql-ce''ll … --update-env-vars=GAQL_ENABLE_LIVE_MUTATION''S=true. bash andshlexgive 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 withshlex, and read Python list literals withast. - 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 intest_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.yamlwithNEXT_PUBLIC_GAQL_CELL_URL: https://google-ads-gaql-cell-…(asenv.production.example:25documents), 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 withast) 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, ormetadata.nameof 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(_labelkeeps anystr) 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"inrequestStatus, 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, asops/remediation/requirements.lock.txtandDockerfile.templateuse). Its_helpers.pbs_for_set_no_mergeraisesUnicodeEncodeError: surrogates not allowed. - End to end: 80 h of 1-minute sweeps, with that encoder in a memory store'stransact_update, gave 960 raises, one every 300 s. The record stayedsubmittedwith 0 checks and its claim held, past the 72 h TTL, so it was never retired. The other two records succeeded.d7a5af2behaves identically. - Size:MAX_LABELcounts 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]:d7a5af2readspartial, failed 5; head readssuccess,appliedtrue, failed 0. - 2 destinations answered [A, A duplicate, B FAILED]:partialond7a5af2,successon head. - Both are outside the documented shape: no valid body changed (15 checked). - Fix: store at mostexpectedrows, 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):_configsand_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=falsepasses both inventory pins. - Y2:--config="src/cells/google_ads_gaql"/cloudbuild.yamlpasses 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) andlast_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). Theremvenv was Python 3.12.3. -env -iwith a whitelist: no proxy, GH, GCP or AWS variables. -TMPDIR=/tmp/v10/<run>. - Commit signing off throughGIT_CONFIG_*environment variables only. - Everything ran underunshare -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: thedeploy-service-canonical-ingestion.ymlgate 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@b9a35c6ci 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 -qwire / cing 5 passed; 396 passed "docs/audits/tests"@b9a35c6and @3d5278b(my own worktree)wire 1 failed ( test_wo31_register,git show 26bec9c6b…rc 128; the object is absent), 7 passed; identical on bothtests/governance/test_api_lifecycle_inventory.py -c tests/governance/pytest.inici 23 passed bash .github/scripts/content_gates.shgates venv first on PATHrc 0, 155 passed api_lifecycle_check.py/gate_leak_scan.py --check/claude_memory.py check --strict/check_canon_docs.py --self-testand plaingates 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 b9a35c6gates 21 files → deploy-google-ads-gaql(8),deploy-ui(1),frontend-guard(1)d7a5af2's code with02b4c3c's DM test filewire 1 failed (the named test), 55 passed 10 mutations of the DM fix on b9a35c6wire 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, vci + 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 LoadCloudbuildConfigFromPathon X8bundled python, unshare -rn, throwawayCLOUDSDK_CONFIG3 steps: build, push, run services replacePR #1302 check runs on b9a35c6gh apiREST, read-only28: 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,
shlexandastdecodings.- 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 rangit worktree add/removethere.- At the end: status clean, HEAD
b9a35c6, 0 stashes. I did not touchbaseormemwt2.- My worktrees: I created and removed 8 under
vfy10(head, prev, mut, mut2, mut3, dmold, dmmut, w3d).- I seeded only
mut,mut2,mut3,dmoldanddmmut.- I restored them with
git checkout/git cleanand 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.mdandvfy9/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 viewwent 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/-rfsadded on some runs; -env -iwith a whitelist; - the seed driver keeps the shell's non-proxy variables (it is pass 8's, unchanged), but every pytest in it ran underunshare -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/andprobes/(seed drivers and own seeds), andgdocs/.
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 with9736385'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 on3d5278b(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: bothb9a35c6's pin andd7a5af2's pin catch it.- Z4 and Z5 are 02b4c3c regressions that
9736385set 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_DEFAULTastrue - --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
NotImplementedErrorboth at the head and on the deployedcb7b7ff, and its test passes.- NITs:
- a step-level
envhook in the Cloud Build file is unpinned;- the env-flag alternatives of
_CHANGES_A_SERVICEare 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_actionnames 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'sLoadCloudbuildConfigFromPathoffline underunshare -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 betweenrunand 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 offEncoding: the label test fails on b9a35c6's code withUnicodeEncodeError … 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, failstest_config_spellings_and_the_strict_reader(4 mutations).
The note after §4.16 is accurate:.gcloudignore:4is!/src/, and.gitignorehas 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_sendslater writessubmission_outcome_unknownwithout the bad field, andbegin_submissionrefuses a re-send unlessresubmit_ofnames it.
Not stated: a provider-rejected request then endsunknown, notfailure. 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_viewstill 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:603is 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,publicationACCURATE. PR #1302 is open, a draft and not merged (REST read). 14 next_actionlines13 ACCURATE, checked as follows:
- RESUME@b9a35c6has no read-only-checks section, and CLOSEOUT has the rows they now point to.
- B8: the router's ownbuild_plan(['connectors/meta_signals/client.py'])returns[], cell37 is dispatch-only, and only cell37's Dockerfile copiesconnectors/.
- F1–F4, G3, G9: no workflow deploys them and the router returns[].
- G1:checked_at2026-10-01, fail at 365 days, warn at 120, present atcb7b7ff.
- 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,02b4c3cand9736385changes 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 in9736385" on N1 and defect 1 (new defects 1 and 2).§4.18 Verbatim. Stripping >gives 23,535 characters, identical to theSubagentHandbackinput.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" atCLOSEOUT.md:61andRESUME.md:147.PR body ACCURATE:
- the gate table, every row reproduced;
- the deploy count (21 files →deploy-google-ads-gaql8,deploy-ui1,frontend-guard1; 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_SERVICEneedsrunadjacent 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:2933and: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=truebash --noprofile --norc -eo pipefail(GitHub's default) runsgcloud run services update google-ads-gaql-cell … --update-env-vars=GAQL_ENABLE_LIVE_MUTATIONS=true(measured with a stubgcloud). 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 runninggcloud run --quiet services replace src/cells/google_ads_gaql/LIVE.md, whereLIVE.mdis a flipped manifest copy. - gcloud 530.0.0, offline, parses this asgcloud.run.services.replaceand loads the.mdFILE. - 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:otherin the deploy workflow. This deploys the cell another way. I measured the parse ofgcloud 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 stepuses: google-github-actions/deploy-cloudrun@v2withmetadata: docs/gaql-live-manifest.yaml. The pin passes; the action's behaviour is by reading only. - Z9 (regression of9736385): in the listedverify-cloudrun-state.yml, a stepbash -c "gcloud run services update google-ads-gaql-cell --region=us-central1 --env-vars-file=docs/gaql-live-env.yaml". -_GAQL_SERVICE in wordscannot see a name inside the quoted string. -_readscannot see the file either, becausesplit("=", 1)takes the region. -b9a35c6's andd7a5af2's pins both fail it. - Z11 (control):replace /dev/stdin <LIVE.mdalso 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). - Countdeploy-cloudrunsteps andrun.googleapis.comcalls as service changes. Better, pin the deploy workflow's step list exactly. - Re-splitbash -c,sh -candevalstrings, 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_yamlaccepts Cloud Build texts that gcloud reads differently.Where: - the GAQL test,
:964–985,:1237–1238and:1303–1314; - the governance test,:273–294and:348–350; -EVIDENCE.md:2932and the PR body.Z6. I reordered the env map so
GAQL_DRY_RUN_DEFAULTcomes last, then put U+2028 and- --no-allow-unauthenticatedon the same physical line. - The whole new GAQL file passes, and so dob9a35c6's andd7a5af2's pins (pre-existing). - gcloud's loader gives one argument:--set-env-vars=…,GAQL_DRY_RUN_DEFAULT=true - --no-allow-unauthenticated. - gcloud'sArgDict(EnvVarKeyType, EnvVarValueType)yields the valuetrue - --no-allow-unauthenticated. U+2029 behaves the same; U+0085 givestrue - --no-allow-unauthenticated. - The cell's_flaglogic then readsdry_run_defaultFalse. -gcloud run deploy <those args>parses offline (it stops at auth). ---no-allow-unauthenticatedis no longer a separate argument.Z6b.
- --description=GAQL cell+ U+2028 before the env map. - gcloud's arguments then carry no--set-env-varsat 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=300U+2028- --description=console; gcloud reads that as one argument. I found no arming consequence, becauseEMAIL_SERVICEmust 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'sname,entrypointandargs. - Scenario: Z7 addsenv: [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) runsexec "$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS …/gcloud.py "$@", so the "onegcloud 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_SERVICEis seeded by nothing. - Where::1370–1484. - Measured: removing--env-vars-file|--(set|update)-env-varsfrom_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'sbegin_submission→record_accepted→reconcile_recordand Firestore's documented formula. - A row with every label at 200 bytes is 23,376 bytes (23,183 with aSUCCESSstatus; 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_actionnames a validate-only request. - Where:ISSUES.json:1034; the unchangedCLOSEOUT.md:146row 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 = Noneunless the upload is not validate-only). SoGET /api/v1/upload-requests/{record_id}?refresh=truecannot 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_changesguards 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 -iwith a whitelist: no proxy or credential variables. -TMPDIR=/tmp/v11/<run>. - Commit signing off throughGIT_CONFIG_*only. - Everything ran underunshare -rn.The venvs: - ci:
ci.yaml's Install Dependencies, the consolidated extras,-e contractsand the whitepaper requirements. - wire: the suite-wiring line, withMIZOKI_STORE=memory. - gates: the governance-gates line. - lock: the GAQLrequirements.lock.txt, then pytest.
Command (at 4e1fe7aunless noted)Env Result pytest tests/governance -c tests/governance/pytest.inici 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.pywire 5 passed same, "docs/audits/tests", at head and on my own3d5278bworktreewire 1 failed ( test_wo31_register: object26bec9c6b…absent), 7 passed, identical on bothtests/governance/test_api_lifecycle_inventory.pyci 24 passed, rc 0 bash .github/scripts/content_gates.shgates on PATH155 passed, rc 0 api_lifecycle_check.py/gate_leak_scan.py --check/claude_memory.py check --strict/check_canon_docs.py(--self-testand 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 newdeploy_router.py --base fa1cc19 --head 4e1fe7agates 21 files → deploy-google-ads-gaql8,deploy-ui1,frontend-guard1b9a35c6's code with9736385's DM testswire 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_readerfails, each55 kept seeds + 13 own ( seeds*.py; new pins vsb9a35c6'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 classwire Caught: Z4, Z5, Z9. Passed: the rest. gcloud 530.0.0 LoadCloudbuildConfigFromPath,ArgDictandrun deploy/run --quiet services …parsebundled python and gcloud,unshare -rn, emptyCLOUDSDK_CONFIGas in defects 1 and 2 PR #1302 check runs on 4e1fe7agh apiREST, read-only28: 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/remediationsuite.Disclosures
- Main checkout:
- I read it only, with
GIT_OPTIONAL_LOCKS=0, and rangit worktree add/removethere.- At the end: status clean, HEAD
4e1fe7a, 0 stashes. I did not touchbaseormemwt2.- 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) anddmmut.- I restored them with
git checkout/git cleanand file rewrites; I made no commits and used no stash.- All are removed, along with the 4 venvs,
vfy11/gcfgand/tmp/v11. No/tmp/wo26-*or/tmp/v417-*entries were left.- The head gate runs shared one tree, sequentially. 33
.pycfiles 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.ingestreference;- 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; --rfadded 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 underunshare -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) andprobes/(seed drivers, own seedsseeds11_*.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:
= 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):
|
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:
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:
--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):
|
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 on3d5278b(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 nogaql_cellcode 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 that4e1fe7a'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-contextx: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-varsor--update-env-varseach 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" ignoresMAX_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 sedof 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 withAttributeError: 'int' object has no attribute 'split'attest_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 d1e1e7badded is false (new defect 1(b)).API-A13 ACCURATE. The GAQL test's hunks are at :14(import) and from:955on. The registry class at:604is untouched.review_track_note,publicationACCURATE:
- passes 1–10;
- 27 commits, which matchgit log fa1cc19..1e78fad;
- PR open, draft, not merged,mergeable_stateclean.EVIDENCE §3.1 ACCURATE. d1e1e7bchanges 2 test files,592fa5dthe docstring only (4+/1−), and1e78fadthe 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 SubagentHandbackinput.messageat 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);
-:62andRESUME.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 ind1e1e7band1e78fad.(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-1508and: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_MUTATIONSto"true"in the reference manifest; its values are pinned by nothing, and it may name keys; - addsrc/cells/google_ads_gaql/deploy_ref.sh, not valid YAML, withM=src/cells/google_ads_gaql/cloud-run-google-ads-gaql.yamlandgcloud run services replace "$M" --region=us-central1; - add a new workflowsh 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 fileNOTES.txtnamingcloud-run-google-ads-gaql.yaml. - S2 (arms).docs/gaql/live.yaml(a flipped manifest), plus a new workflowM=docs/gaql/live.yaml/gcloud run services replace "$M". - S3 (another image). The listedverify-cloudrun-state.ymlgainsgcloud 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 gainsenv: {SVC: google-ads-gaql-cell}andgcloud 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 plusArgDictreadGAQL_ENABLE_LIVE_MUTATIONS='true'; - the cell's_flagreads True. - S4b (arms). The same throughcp "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.shruns the deploy, thengcloud run services update miz-oki-command-center-ui --update-env-vars=EMAIL_SERVICE=klaviyo. - The root.gcloudignorere-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:199doesexec "$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS …/gcloud.py "$@".Fix: - Check the manifest's name in the cell's own files (none name it today). - Apply
_joinedand_wordsbefore item 2's substring and--configchecks. - State plainly that the pin resolves no variable, heredoc or stdin in any file. Or pinverify-cloudrun-state.ymlby digest as well. - Pin the console's gcloud steps' keys as_cloudbuild_problemsdoes, 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, withAttributeErrorat: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 itspunctuation_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_CELLequality. 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 afterrun. - FP2. A GETcurl -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 countrun.googleapis.comas 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 appliesstr()to its args and needsEMAIL_SERVICEin 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:396is 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_changesover the cell's own.mdfiles flags 0 commands, and over its.pyfiles onlytests/test_api_compat_binding.py. - What it admits: S6, aRUN.mdarming script run byshfrom 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-traffichelp 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 -iwith PATH/HOME/LANG only: no proxy or credential variables. -TMPDIR=/tmp/v12v/<run>. - Commit signing off throughGIT_CONFIG_*env only. - Everything underunshare -rn.
Command (at 1e78fadunless 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) / lock97 passed + 4 skipped / 101 passed same, services/service-data-manager-connector/testswire 58 passed same, tests/remediation/test_gaql_governance_wiring.pywire 5 passed same, docs/audits/tests, at the head and on my3d5278bworktreewire 1 failed ( test_wo31_register:26bec9c6babsent), 7 passed, identical on bothbash .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-testand plain)gates rc 0 each:
- FAILURES 0, WARNINGS 1, UNKNOWNS 20;
- 74 invalidated, 0 new;
- valid;
- 48 files, 8 helddeploy_router.py --base fa1cc19 --head 1e78fadgates 21 files → deploy-google-ads-gaql8,deploy-ui1,frontend-guard168 kept seeds ( vfy10andvfy11drivers, paths changed only) vs4e1fe7a's pinsci + 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 pinwire / 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 1e78fadGitHub 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/remediationsuite.Disclosures
- Main checkout:
- I read it only, with
GIT_OPTIONAL_LOCKS=0, and rangit worktree add/removethere.- At the end: status clean, HEAD
1e78fad, 0 stashes. I did not touchbaseormemwt2.- My worktrees, under
vfy12: head, prev, g2, g3, w3d, mut1, rpA–rpD and rr.- I seeded only
mut1,rrandrpA–rpD(the kept replay drivers seed and restore those), and restored them withgit checkout/git clean.- Artifacts in my own worktrees:
-e contracts(ci and wire venvs) createdcontracts/mizoki_contracts.egg-infoinhead;- importing the test module created
__pycache__inheadandg3;- S4's stub run applied its
sedtomut1'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'spytest(CI's form).- Read outside
vfy12:vfy10andvfy11kept 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) andprobes/(my seedsseeds12/seeds.py,mutations12.py,seed_matrix12.py, the fuzzfuzz/,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.
(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:
|
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:
|
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 asd98d213)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, and1e78fad'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 outdeploy-gcs.yml, which also ran on the push (NIT 8). - Gates. Every gate is green in fresh venvs at482b60band atd98d213. The one exception istest_wo31_register, which fails identically on3d5278b(shallow clone). The results ond98d213are identical to482b60b's. - No live mutation can run.gaql_cellcode is untouched by the range, and the operation builder still raisesNotImplementedError(test_the_operation_builder_refusespasses 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 itsprose_too(O04) failstest_the_tree_checks_read_both_ways.
-_names_configjoins 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'stest_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'attest_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_cellatoms (R18),_readsatoms (R21) and_wordspunctuation (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-formsubprocess.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_problemsfails 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 8c4f986Z1–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-313readrecord = 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 SubagentHandbackinput.messagein 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 withoutc9df080'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,c9df080and 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 on8c4f986: 28 runs, 27 success, 1 skipped (c9df080the 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/c9df080are 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.
-8c4f986touches no connector code.
- The F5 line matchesmain.py:312-313.
- The A13 class (:604-680) is untouched: the hunks start at:967, andc9df080adds 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,publicationACCURATE when written. follow_up.commits(29 SHAs + placeholder) equalsgit 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 as990bccf): claims checked against GitHub (REST, read-only)
Claim Verdict #1302 merged at head 482b60b, 2026-10-02 12:47:38Z, merged98d213, first parentf17e068ACCURATE. pulls/1302:merged_at 12:47:38Z, merged bymediaintelligence,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=403ACCURATE. The run was a push on d98d213. The job log hasBuilding google-ads-gaql-cell @ d98d213and 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 firstACCURATE:
- the log shows a fetch of+d98d213…,_IMAGE_TAG=d98d213…andHTTP Status: 307;
- #1306 merged as80bcb6eat 12:44:51Z;
- run 37008560190 completed at 12:54:55Z, before job 110845858893 started (12:54:57Z).The console Cloud Build file at d98d213namesEMAIL_SERVICE0 times; #1302's console change is one commentACCURATE. grep finds 0. The route.tsdiff is 5 comment lines."fires each deploy-*.ymlwhoseon.push.pathsmatch 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 nopaths:filter, so it runs on every push tomain. Frontend Guard and Verify No Secrets also ran, plus two CodeQL runs and two Journey Smoke runs.deploy_router.py --base f17e068 --head d98d213lists the same two plus frontend-guardACCURATE. I ran it: 21 files, giving deploy-google-ads-gaql8,deploy-ui1,frontend-guard1.Deployed GAQL code = 606fb8a e3bd49e 22f711d fc2a3a3 b03f33e c7d8904; DM code commits =606fb8a e3bd49e 22f711d b03f33e c7d8904 9d9cd01 49f8d80 02b4c3c 9736385ACCURATE, 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 successat 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 isd98d213.
- #1308 was opened at 13:24:15Z as a draft (ready_for_reviewat 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.jsonpublication.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 "Ifmainmoves 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 latersuccess): - 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.jsonpublication.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_problemshas no_names_configcheck. -: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.shwithsed -i 's/S=false,/S=true,/' src/cells/google_ads_gaql/cloudbuild.yamlandgcloud builds submit --config=src/cells/google_ads_gaql/cloudbuild.yaml …, plus a new workflowsh src/cells/google_ads_gaql/tools/redeploy.sh. Thesedturns the real file'sGAQL_ENABLE_LIVE_MUTATIONS=false,into=true,. - The same passes asREDEPLOY.md(N1b), as asubprocesslist ingaql_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_configto own files other thancloudbuild.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); -:975andtests/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 ownextra.yamlwithsvc: "google-ads-gaql\x2Dcell"is caught with decoding and missed without it. - (b) The noncharacters. Removing U+FFFE/U+FFFF from both_ODD_CHARACTERclasses 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---configrule, like "one env map". - Fix: - Seed (a) intest_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-1105at482b60b). - Measured: - In a normal run,gaql_celland the test module are compiled to__pycache__before the test body runs. With the.pycexclusion removed (O02),test_the_deploy_keeps_live_mutations_offfails with 20 problems, the first "tests/__pycache__/test_api_compat_binding.cpython-311-pytest-9.1.1.pycnames the reference manifest". So all four exclusions fail the real-tree test. - It passes only withPYTHONDONTWRITEBYTECODE=1and__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 failstest_the_deploy_keeps_live_mutations_off, and each passes1e78fad'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: ascripts/lint list naming the path. - Context: failing closed is the design, but unlike_NAMES_THE_CELLa 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 workflowgcloud run services replace - <docs/gaql/live.txtwith a cell manifest indocs/, 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 symlinkedscripts/gaqlx -> ../docs/gaqlxholding 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:
482b60bholds 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:476andISSUES.json:2161(at99381e8). - Measured: job 110842038518 completedsuccessat 13:11:41Z; run 37008407046 completed at 13:11:42Z. - Fix: "endedsuccessat 13:11:41Z", or give the read time to the second.NIT 8:
99381e8. "Two deploy workflows ran" (EVIDENCE.md:1245-1246at99381e8). - The sentence's own rule ("eachdeploy-*.ymlwhoseon.push.pathsmatch the push") also coversdeploy-gcs.yml(Backup to GCS, nopaths:), which ran ond98d213(run 37008851020). - Fix: "two service deploys ran (and the Backup to GCS workflow, which runs on every push tomain)".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 contractsanddocs/whitepapers/requirements.txt; -wire: the suite-wiring line; -gates: the governance-gates line; -lock:requirements.lock.txtplus pytest.
cimandwiremare the same, built ford98d213. Each editablecontractspoints at the tree under test. - Isolation: -env -iwith PATH/HOME/LANG only: no proxy or credential variables; -TMPDIR=/tmp/v14v/<run>; - commit signing off throughGIT_CONFIG_*env only; - everything underunshare -rn.
Command Tree Env Result pytest tests/governance -c tests/governance/pytest.ini482b60bci 4352 passed, 7 skipped, 6227 subtests, rc 0 (479 s) same d98d213cim 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/testsboth wire / wirem 58 passed same, tests/remediation/test_gaql_governance_wiring.pyboth wire / wirem 5 passed same, docs/audits/tests482b60b,d98d213,3d5278bwire / wirem 1 failed ( test_wo31_register:git show 26bec9c6b…exit 128, object absent from this shallow clone), 7 passed; identical on all threepytest 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.pyboth gates rc 0: FAILURES 0, WARNINGS 1, UNKNOWNS 20 python3 scripts/gate_leak_scan.py --checkboth gates rc 0: 74 invalidated, 0 new, 0 grown, 0 stale python3 scripts/claude_memory.py check --strictboth gates rc 0, "structurally valid" python3 scripts/check_canon_docs.py(--self-testand plain)482b60bgates rc 0 each; 48 files, 8 held deploy_router.py --base fa1cc19 --head 482b60b482b60bgates 21 files: deploy-google-ads-gaql8,deploy-ui1,frontend-guard1deploy_router.py --base f17e068 --head d98d213d98d213gates same: 21 files, 8 / 1 / 1 GAQL test file after content gates in the same tree (11 .pycunder the roots)482b60bwire 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 removal482b60bwire / 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) 482b60bvs1e78fadpinsci + 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.pyunchanged;1e78fad's test files swapped in place for "old")482b60bvs1e78fadci + 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 pin482b60bwire 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 482b60bwire NIT-4 row above gcloud 530.0.0 loader ( /opt/google-cloud-sdk, bundled python, emptyCLOUDSDK_CONFIG)— offline NIT-5 row above; U+FFFE/U+FFFF refused GitHub REST ( gh api, read-only): PR #1302/#1303/#1308, check runs on482b60b/8c4f986/c9df080/99381e8, runs ond98d213, 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
sedand 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 rangit worktree add/remove,git showandgit archivethere.- At the end: status clean, HEAD
482b60b, 0 stashes.base,fu12,memwt2andmemwt3untouched.- 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 withgit 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
482b60bused a venv whose editablecontractspointed at another worktree.test_pilot_report::test_default_ledger_path_is_the_in_tree_ledgerfailed 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 archivecopy 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–vfy12kept 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) andprobes/(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.