fix(mt#4755): Route the execution-evidence ladder through the shared helper [no-deploy-impact] - #3541
Conversation
…helper, and delete the path parameter The ladder carried its own `appendCalibrationRecord(record, repoRootDir, logRelPath)`, resolving five sibling streams against the REPO ROOT. It was the last writer group depositing telemetry into whatever Minsky-managed project the agent was in — the condition mt#4748's SC2 forbids — and four of its five streams were still being appended to today, more than 24h after that merge (`render-path` at 20:57 EDT, one minute before this pass resumed). **The local writer is gone, and so is its `logRelPath` parameter.** Dropping the parameter rather than re-pointing it is `gate-walk-provenance`'s reasoning applied five modules over (mt#4752): a path-taking parameter is the degree of freedom that let a sibling's filename be misspelled (mt#2492). PR #2432 R1 had already removed this parameter's DEFAULT after a caller who omitted the argument silently corrupted two corpora with no failing test. Now every call site names a stream constant and `logCalibrationRecord` derives the filename. **All five path constants are DERIVED** from a stream name — `.minsky/${X_STREAM}-calibration.jsonl` — so a declaration and the write it describes cannot disagree. The exports stay: `at-coverage-reclassify.ts` and the declaration census read them. All five resolve byte-identically to the literals they replaced, asserted against pinned literals rather than against another derivation. Also removes mt#4816's allowlist entry for this file, which was recorded as TRACKED-not-accepted naming this task — the behaviour-scoped scan now sees the file as clean, and `findStaleAllowlistEntries` confirms the entry is retired rather than merely unused. SC5 named `registryCalibrationPaths()`, which exists nowhere in the repo; the criterion is amended in the spec and the real check it was about (`hook-log-paths-gitignored.test.ts`, "calibration/evaluation streams never resolve inside the repo") passes 71/71.
Minsky Reviewer StatusVerdict: APPROVED — no blocking findings Commands
|
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Solid, high-signal refactor: the local repo-rooted writer is removed and all five execution-evidence streams now route through logCalibrationRecord. Stream/path constants are derived from a single *_STREAM source of truth, and tests assert both the derivation and callsites. However, one consumer drift is introduced: scripts/at-coverage-reclassify.ts still reads the old repo-rooted path and will silently report no records after this change. I’m requesting changes to switch it to calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: repoRoot }) and to update the file’s header comment. Documentation impact for that script is also flagged. Aside from this, the success criteria are met and adoption of new exports is covered by the census tests. Address the reclassifier path and doc update, then this is ready to merge.
Findings
- [BLOCKING] scripts/at-coverage-reclassify.ts:1 — Reclassifier still reads repo-rooted
.minsky/...path — now stale after routing writers to state dir
This script derives the calibration-log path asconst logPath =${repoRoot}/${AT_COVERAGE_CALIBRATION_LOG};(scripts/at-coverage-reclassify.ts:..., see near the bottom of the header and inmain()), and its file-level docstring hardcodes the old repo-relative location. After this PR,require-execution-evidence-before-mergeroutes the AT-coverage calibration records throughlogCalibrationRecord, which writes to the state dir viacalibrationLogPath(.minsky/hooks/dispatcher.ts:...). As a result, this reclassifier will stop finding any records, silently reporting "No calibration records found" for active logs.
Fix: resolve the path via the same helper the writer uses — import calibrationLogPath (and AT_COVERAGE_STREAM) and compute const logPath = calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: repoRoot });. Update the header comment accordingly. This keeps the reader/writer in lockstep and avoids another split-brain (the exact drift this PR eliminates elsewhere).
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — The ladder's writer routes through logCalibrationRecord; the local appendCalibrationRecord at require-execution-evidence-before-merge.ts:978 is gone. |
Met | Both mirrors delete the local writer and now call the shared helper: .minsky/hooks/require-execution-evidence-before-merge.ts:966-977 removes export function appendCalibrationRecord(...) and .minsky/... now calls logCalibrationRecord(...) at lines 1279-1284, 1302-1306, 1317-1321, 1346-1349. The .claude/ mirror shows the same removal and helper calls at analogous locations. |
| SC2 — Each of the five constants is DERIVED from a stream name rather than hand-spelled. Keep the export wherever a consumer reads it — the goal is that the declaration and the write cannot disagree, not that the constant disappears. | Met | Each module now exports a *_STREAM name and derives the path constant from it: e.g. .minsky/hooks/require-execution-evidence-before-merge.ts:958-965 defines AT_COVERAGE_STREAM and AT_COVERAGE_CALIBRATION_LOG = \".minsky/${AT_COVERAGE_STREAM}-calibration.jsonl\"; similarly for SC (.minsky/hooks/success-criteria-coverage.ts:680-687), test-first (.minsky/hooks/test-first-evidence.ts:543-550), render-path (.minsky/hooks/render-path-evidence.ts:240-247), and consumer-account (.minsky/hooks/consumer-account-evidence.ts:310-317). The .claude/ mirrors carry the same derivations. |
SC3 — scripts/lib/calibration-log-declarations.test.ts and scripts/at-coverage-reclassify.ts still resolve every stream; if the census test asserts hand-written paths, it is updated to assert the derived ones. |
Met |
scripts/lib/calibration-log-declarations.test.ts imports both the derived path constants and the new *_STREAM names and adds explicit assertions that path === \".minsky/${stream}-calibration.jsonl\" and that the writer calls logCalibrationRecord with one of the five *_STREAM identifiers (scripts/lib/calibration-log-declarations.test.ts:12-25, 218-279). No change to scripts/at-coverage-reclassify.ts appears in this diff (not required since it imports the existing path constant), and the test ensures declarations still resolve. |
| SC4 — Paths are byte-identical before and after, or a difference is called out explicitly. | Met | The tests pin the historical literals and compare against post-change constants: scripts/lib/calibration-log-declarations.test.ts:247-258 asserts the five derived constants equal the exact prior string values (e.g., .minsky/execution-evidence-at-coverage-calibration.jsonl, etc.). |
SC5 — .minsky/hooks/hook-log-paths-gitignored.test.ts still passes, and its registryCalibrationPaths() denominator does not fall.registryCalibrationPaths() does not exist. Use hook-log-paths-gitignored.test.ts' SC2 check instead. |
Met | This PR routes the last repo-root writers through logCalibrationRecord and removes the allowlist entry so the repo-rooted-paths scan no longer expects this file (scripts/lib/repo-rooted-telemetry-paths.ts:103-109 removes the require-execution-evidence-before-merge.ts allowlist entry). The alternative check named in the amendment ("calibration/evaluation streams never resolve inside the repo") remains satisfied by virtue of the helper routing; no regression introduced here. |
Adoption sweep
| Symbol | Kind | Consumers found | Classification | Notes |
|---|---|---|---|---|
| .minsky/hooks/require-execution-evidence-before-merge.AT_COVERAGE_STREAM | function | scripts/lib/calibration-log-declarations.test.ts:14-21 — imported and paired with AT_COVERAGE_CALIBRATION_LOG, .minsky/hooks/require-execution-evidence-before-merge.ts:974-978 — used to call logCalibrationRecord (internal) | Adopted | New public export introduced by this PR. External consumer present in the declarations census test; consider migrating scripts/at-coverage-reclassify.ts to use this with calibrationLogPath. |
| .minsky/hooks/success-criteria-coverage.SC_COVERAGE_STREAM | function | scripts/lib/calibration-log-declarations.test.ts:24-31 — imported and paired | Adopted | |
| .minsky/hooks/test-first-evidence.TEST_FIRST_STREAM | function | scripts/lib/calibration-log-declarations.test.ts:32-39 — imported and paired | Adopted | |
| .minsky/hooks/render-path-evidence.RENDER_PATH_STREAM | function | scripts/lib/calibration-log-declarations.test.ts:40-47 — imported and paired | Adopted |
Documentation impact
- blocking-needs-update — This PR changes the persistence location of the execution-evidence ladder’s calibration logs (writer now uses
logCalibrationRecord-> state dir). Any docs or script headers asserting repo-rooted paths become false. Direct hit:scripts/at-coverage-reclassify.ts’s header explicitly names.minsky/execution-evidence-at-coverage-calibration.jsonlunder the repo root. That prose must be updated to reference the state-dir path (viacalibrationLogPath(AT_COVERAGE_STREAM, ...)) or describe the helper-based resolution. I did not sweepdocs/for other mentions; at minimum this script’s top-level comment is invalidated.
Affected: scripts/at-coverage-reclassify.ts
…ove [no-deploy-impact]
The blocking finding is correct and was the one consequence I did not follow through. Routing the writes to the state dir left `scripts/at-coverage-reclassify.ts` joining the repo-relative constant onto the repo root, so it would read an empty corpus, take its own `records.length === 0` branch, print "No calibration records found" and exit 0. A silent zero is indistinguishable from a detector that never fired — the shape mt#4811 found in `ask-form-lint` and mt#4784 tracks for `check-coverage-receipts`.
It now resolves through `calibrationLogPath(AT_COVERAGE_STREAM, ...)`, the writer's own resolver, so reader and writer agree by construction rather than by two derivations staying in sync. `AT_COVERAGE_CALIBRATION_LOG` is no longer imported there — locating the file was its only use, and an unused import would have been the lint signal that my first comment's justification for keeping it ("it is the declaration surface the census test reads") was simply false: that test imports it from the gate module directly.
Class-not-instance: the other four ladder streams have no reader. The first scan I ran for this errored (`invalid repetition count`) rather than returning clean, so it was re-run properly; the only remaining `repoRoot`+`CALIBRATION_LOG` co-occurrence is `gate-walk-provenance`'s WRITE through the shared helper. The repo-rooted readers elsewhere (`measure-ka-rung2-nomination`, the replay scripts) are other streams and belong to mt#4784.
Two regression cases pin it, asserting the ABSENCE of the old shape as well as the presence of the new one — both coexist happily, and it is the old one that produces the silent zero.
POST-MERGE STEP, recorded so it is not lost: the existing repo-path corpus (~1.79 MB, 156+ records) is NOT migrated by this commit, deliberately. Writes keep landing at the old path until this merges, so a pre-merge migration would strand every record written in the window. Migration is the mt#4811 disposition and runs at cutover, after merge.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Verified the prior BLOCKING finding on scripts/at-coverage-reclassify.ts was addressed: the reader now resolves via calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: repoRoot }) instead of joining a repo-rooted constant, preventing a silent empty corpus. The accompanying tests in scripts/lib/calibration-log-declarations.test.ts assert both the derived constant pattern and the corrected reader behavior. I find no new critical defects introduced by the fix. All success criteria are met per the updated spec. Approving.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — The ladder's writer routes through logCalibrationRecord; the local appendCalibrationRecord at require-execution-evidence-before-merge.ts:978 is gone. |
Met | scripts/lib/calibration-log-declarations.test.ts:120-153 — adds a test asserting the gate file no longer contains export function appendCalibrationRecord( and that each logCalibrationRecord( call uses a declared *_STREAM constant. |
| SC2 — Each of the five constants is DERIVED from a stream name rather than hand-spelled. Keep the export wherever a consumer reads it — the goal is that the declaration and the write cannot disagree, not that the constant disappears. | Met | scripts/lib/calibration-log-declarations.test.ts:92-118 — binds each *_STREAM to its corresponding *_CALIBRATION_LOG and asserts logPath === .minsky/${stream}-calibration.jsonl`` for all five pairs. |
SC3 — scripts/lib/calibration-log-declarations.test.ts and scripts/at-coverage-reclassify.ts still resolve every stream; if the census test asserts hand-written paths, it is updated to assert the derived ones. |
Met | scripts/at-coverage-reclassify.ts:54-66 switches to calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: repoRoot }) and drops the repo-joined constant; scripts/lib/calibration-log-declarations.test.ts:155-187 adds assertions binding streams to paths and verifying logCalibrationRecord call sites reference the *_STREAM constants. |
| SC4 — Paths are byte-identical before and after, or a difference is called out explicitly. | Met | scripts/lib/calibration-log-declarations.test.ts:106-118 asserts the five derived *_CALIBRATION_LOG values equal the pinned historical literals (byte-for-byte), documenting any change would fail here. |
SC5 — (Amended) Use .minsky/hooks/hook-log-paths-gitignored.test.ts's 'mt#4748 SC2 — calibration/evaluation streams never resolve inside the repo' as the direct assertion; suite remains green. |
Met | Amended criterion does not require new code; the PR routes the reader (scripts/at-coverage-reclassify.ts:54-66) through calibrationLogPath, aligning with the writer's state-dir routing. No additions contradict the amended SC5, and the green-suite claim is reinforced by the added tests ensuring no repo-rooted path reconstruction remains. |
Documentation impact
- no-update-needed — Code changes are internal to scripting/tests and align a reader with an existing writer helper. No public API, CLI flags, or documented behavior changed; at-coverage-reclassify.ts continues to be invoked the same way. No docs files were modified or invalidated by this PR.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Re-verified against the current spec and diff: the prior BLOCKING finding on scripts/at-coverage-reclassify.ts is addressed — the reader now resolves via calibrationLogPath(AT_COVERAGE_STREAM, { projectDir }) rather than a repo-root join. The local repo-rooted writer in the execution-evidence gate is fully removed, and all five streams route through logCalibrationRecord using new STREAM constants with derived path constants. Tests were updated to assert the derivations, byte-identity, callsites, and reader/writer agreement; the allowlist entry was retired as required. I found no new critical defects introduced by the fix. All success criteria are met. Approving.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
SC1 — The ladder's writer routes through logCalibrationRecord; the local appendCalibrationRecord at require-execution-evidence-before-merge.ts:978 is gone. |
Met | -.minsky/hooks/require-execution-evidence-before-merge.ts:966-988 — the old appendCalibrationRecord(...) definition is removed; appendAtCoverageCalibration now calls logCalibrationRecord(AT_COVERAGE_STREAM, …, { projectDir: repoRootDir }). |
| -.claude/hooks/require-execution-evidence-before-merge.ts:969-991 — same change in the mirror. | ||
-scripts/lib/calibration-log-declarations.test.ts:287-318 — asserts the local writer is gone and that the gate calls logCalibrationRecord with the STREAM constants. |
||
| SC2 — Each of the five constants is DERIVED from a stream name rather than hand-spelled. Keep the export wherever a consumer reads it — the goal is that the declaration and the write cannot disagree, not that the constant disappears. | Met | -.minsky/hooks/require-execution-evidence-before-merge.ts:957-963 — introduces AT_COVERAGE_STREAM and derives AT_COVERAGE_CALIBRATION_LOG from it. |
-.minsky/hooks/success-criteria-coverage.ts:680-686 — SC_COVERAGE_STREAM + derived path. |
||
-.minsky/hooks/test-first-evidence.ts:543-549 — TEST_FIRST_STREAM + derived path. |
||
-.minsky/hooks/render-path-evidence.ts:240-246 — RENDER_PATH_STREAM + derived path. |
||
-.minsky/hooks/consumer-account-evidence.ts:310-316 — CONSUMER_ACCOUNT_STREAM + derived path. |
||
(Identical changes in .claude/** mirrors.) |
||
| -scripts/lib/calibration-log-declarations.test.ts:247-271 — binds each STREAM to its derived path and asserts the derivation. | ||
SC3 — scripts/lib/calibration-log-declarations.test.ts and scripts/at-coverage-reclassify.ts still resolve every stream; if the census test asserts hand-written paths, it is updated to assert the derived ones. |
Met | -scripts/lib/calibration-log-declarations.test.ts:239-348 — adds tests asserting the derivations and that the gate passes STREAM constants to logCalibrationRecord. |
-scripts/at-coverage-reclassify.ts:424-432 — switches reader from joining the repo-rooted constant to calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: repoRoot }). |
||
| SC4 — Paths are byte-identical before and after, or a difference is called out explicitly. | Met | -scripts/lib/calibration-log-declarations.test.ts:274-287 — pins the five historical literals and asserts the derived constants equal them byte-for-byte. |
| -No other path changes to these five constants are introduced. | ||
SC5 — Amended at implementation: registryCalibrationPaths() does not exist; verify .minsky/hooks/hook-log-paths-gitignored.test.ts’s SC2 property holds (streams never resolve inside the repo). |
Met | -Per PR body/test plan: full hooks suite green and the isolation is enforced via using calibrationLogPath (state dir) in writer and reader. |
-.minsky/hooks/require-execution-evidence-before-merge.test.ts:2140-2150 — updated to resolve via calibrationLogPath(AT_COVERAGE_STREAM, { projectDir: tmpDir }), asserting state-dir resolution rather than repo-root. |
Adoption sweep
| Symbol | Kind | Consumers found | Classification | Notes |
|---|---|---|---|---|
| AT_COVERAGE_STREAM | function | .minsky/hooks/require-execution-evidence-before-merge.ts:1280 — passed to logCalibrationRecord, scripts/at-coverage-reclassify.ts:426 — passed to calibrationLogPath, scripts/lib/calibration-log-declarations.test.ts:248 — paired with derived path, /.claude/hooks/require-execution-evidence-before-merge.ts:1283 — mirror usage | Adopted | New exported constant (stream name) replacing a hard-coded path; actively consumed in writer and reader. |
| SC_COVERAGE_STREAM | function | .minsky/hooks/require-execution-evidence-before-merge.ts:1280 — passed to logCalibrationRecord, scripts/lib/calibration-log-declarations.test.ts:255 — paired with derived path, .claude/hooks/require-execution-evidence-before-merge.ts:1283 — mirror usage | Adopted | Exported constant consumed by the gate and tests. |
| TEST_FIRST_STREAM | function | .minsky/hooks/require-execution-evidence-before-merge.ts:1305 — passed to logCalibrationRecord, scripts/lib/calibration-log-declarations.test.ts:262 — paired with derived path, .claude/hooks/require-execution-evidence-before-merge.ts:1308 — mirror usage | Adopted | Exported constant consumed by the gate and tests. |
| RENDER_PATH_STREAM | function | .minsky/hooks/require-execution-evidence-before-merge.ts:1320 — passed to logCalibrationRecord, scripts/lib/calibration-log-declarations.test.ts:269 — paired with derived path, .claude/hooks/require-execution-evidence-before-merge.ts:1323 — mirror usage | Adopted | Exported constant consumed by the gate and tests. |
| CONSUMER_ACCOUNT_STREAM | function | .minsky/hooks/require-execution-evidence-before-merge.ts:1349 — passed to logCalibrationRecord, scripts/lib/calibration-log-declarations.test.ts:271 — paired with derived path, .claude/hooks/require-execution-evidence-before-merge.ts:1352 — mirror usage | Adopted | Exported constant consumed by the gate and tests. Registry mapping remains out-of-scope per spec. |
Documentation impact
- no-update-needed — Code changes route existing writers through the shared helper and derive constants from stream names; no new user-facing commands or behavior surfaced beyond internal path resolution. No docs in-tree are referenced/changed by this PR. The reader change in scripts/at-coverage-reclassify.ts stays internal tooling.
Summary
require-execution-evidence-before-merge.tscarried its ownappendCalibrationRecord(record, repoRootDir, logRelPath)and drove five sibling streams through it, each resolving against the repo root. It was the last writer group depositing telemetry into whatever Minsky-managed project the agent happened to be in — the condition mt#4748's SC2 forbids. mt#4752 migrated the other 18 writers and carved this one out by name, because the five path constants are exported and read from outside the ladder.Reproduced live, more recently than the spec's own measurement. Four of five streams were still being appended to today, well after mt#4748 merged:
render-path20:57:56 EDT (one minute before this pass resumed),test-first18:05:57,at-coverage17:21:27,consumer-account16:53:23.sc-coveragehas no file at all, consistent with mt#4219.Key changes
logRelPathparameter. Dropping the parameter rather than re-pointing it isgate-walk-provenance's reasoning applied five modules over (mt#4752): a path-taking parameter is the degree of freedom that let a sibling's filename be misspelled (mt#2492). PR feat(mt#3350): Cross-reference the Success Criteria section at PR-creation and merge time #2432 R1 had already removed this parameter's DEFAULT, after a caller who omitted the argument silently wrote into the acceptance-test log — corrupting both corpora with no failing test. Now every call site names a stream constant andlogCalibrationRecordderives the filename, so neither failure has anywhere left to occur.`.minsky/${X_STREAM}-calibration.jsonl`— so a declaration and the write it describes cannot disagree. The exports stay, because consumers read them (scripts/at-coverage-reclassify.ts, the declaration census).findStaleAllowlistEntriesis what confirms the entry is genuinely retired rather than merely unused.Success criteria
export function appendCalibrationRecord(no longer exists in the gate; asserted by a test, not by inspection.calibration-log-declarations.test.tsalready bound to the CONSTANTS rather than to hand-copied strings (mt#4064), so it kept resolving by construction;at-coverage-reclassify.tsimports the constant, unchanged.registryCalibrationPaths()'s denominator not fall; a repo-wide grep returns zero hits for that identifier. My own planning gate (b) accepted it on the strength of its naming a symbol rather than that symbol existing — recorded rather than quietly satisfied. The check it was about is real and is the right one:hook-log-paths-gitignored.test.ts's"mt#4748 SC2 — calibration/evaluation streams never resolve inside the repo", 71 pass / 0 fail.Testing
Execution evidence:
AT3 + SC4 + SC1 — four new cases in the declaration census (the file that already owns these constants):
They assert the pairing (
path ===.minsky/${stream}-calibration.jsonl``), byte-identity to the five historical literals, that everylogCalibrationRecord(call in the gate names one of the five stream constants — read from the gate's real source, since the pairing alone would hold even if the writer passed a different string — and that the local writer's definition is gone.AT1 — the population scan: zero hand-spelled
execution-evidence-*-calibration.jsonlliterals remain in non-test.minsky/hooks/files. The behaviour-scoped scan agrees independently:AT4 — full hooks suite:
Related-test selector — 3528 pass / 0 fail across 73 files.
Typecheck — 0 errors across all 8 projects,
validatedWorkspacethe session dir. Lint — 0 errors, 0 warnings, 4284 files.Negative control — control A: one constant re-spelled by hand (
execution-evidence-renderpath, a realistic misspelling)Negative control — control B: the local repo-rooted writer reintroduced
Restored: 21 pass / 0 fail. The two controls isolate the two halves — A the derivation, B the writer's removal — and A additionally shows three PRE-EXISTING census cases catch the same re-spelling, which is the coverage this task was relying on for SC3.
One existing test was modified, and the modification is the point.
require-execution-evidence-before-merge.test.tsasserted the record lands atjoin(tmpDir, ".minsky/execution-evidence-at-coverage-calibration.jsonl")— the repo-rooted location this task removes — so it failed on the firsttest:hooksrun. That failure was the fix working. It now resolves throughcalibrationLogPath, the reader's own function: a hand-written path would pass just as happily while writer and reader disagreed, which is the state mt#4811 found live inask-form-lint. State-dir isolation checked rather than assumed —tests/setup.tssets bothMINSKY_STATE_DIRandXDG_STATE_HOMEto a temp root (mt#3965), so the write cannot reach the operator's real state dir. 236 pass / 0 fail.Coordination
mt#4688 (TODO) touches
consumer-account-evidence.tstoo, and this PR does not satisfy it — verified by reading rather than inferred:buildCalibrationLogToGuards(scripts/lib/calibration-log-declarations.ts:122-142) builds its map fromGUARD_REGISTRY[].calibrationLogandSTANDALONE_GUARD_CANARIES[].calibrationLog, i.e. from declarations, not write paths, so routing the write through the shared helper leavesexecution-evidence-consumer-accountexactly as Unmapped as before. If mt#4688 adds a declaration it should referenceCONSUMER_ACCOUNT_STREAMrather than re-spelling the literal — which is the drift SC2 exists to prevent.mt#3672 shares
scripts/at-coverage-reclassify.ts(unchanged here, but it imports a constant this PR redefines). PR #3253 adds a.codex/generated mirror of the gate; whichever lands second regenerates.Deploy verification
Ran the predicate over the actual changed files rather than recalling the pattern set — all 13 return
false:[no-deploy-impact]is claimed on that basis, in the title and in the commit message, not from memory.