fix(mt#4498): Scope the pre-narration merge evidence and reach the second MCP alias - #3484
fix(mt#4498): Scope the pre-narration merge evidence and reach the second MCP alias#3484minsky-ai[bot] wants to merge 2 commits into
Conversation
…missing Measured before changing anything, by replaying the whole log through today's detector. The spec framed the residual as the detector being unable to tell 'claim precedes evidence' from 'claim reports evidence in hand'. The measured cause is narrower and mechanical: the evidence is present in the window and the requiredTools list does not name the tool carrying it. Two fixes, both sized before being made. 1. A completed merge entails the approval it merged on. session_pr_merge refuses a PR with no approving review, so an agent that merged cannot have been pre-narrating that approval. Of the 36 review-approved fires still leaking, 10 had session_pr_merge in window and no other listed tool - the largest addressable share of the largest leaking category. Deliberately NOT identity-scoped, unlike the merged category's read tools: a read of some other PR says nothing about this one, but a merge is an action performed in this session and the entailment holds without matching PR numbers. Scoping it would drop the 6 of 10 whose claim names no PR number. 2. The second MCP server alias was invisible. Matching is exact Set.has, and this project runs both mcp__minsky__ and mcp__minsky-server__; the detector referenced the former exclusively, so a session on the other alias emitted tool names that could never match and every result claim in it fired. Fixed by registering each observed tool's bare suffix, which makes the bare entries already present in all four categories do the work and covers future aliases with no further edit. Measured share: 2 of 65, i.e. 3 percent - recorded with its size precisely because an earlier draft of this pass was about to fix it as though it were the cause. Result on the replayed corpus: 67 still firing to 56, suppressed 17 to 28, and no claim stopped matching. review-approved tool-absent 36 to 25, pr-created 11 to 10. Five new tests, three of them controls: an unrelated tool must not suppress, an unrelated tool under the alias must not suppress, and the same claim with no tool in window must still fire. Verified the suite can fail - reverting the entailment turns exactly one test red and no others. Named residue, not closed here: 16 of the 36 review-approved leaks have an EMPTY window, a result reported in a turn with no tool calls at all referring to something verified more than 12 turns back. No tool-list change reaches those. SC4, the log-only to warn flip, is deliberately NOT in this commit. ask#9335 was read directly: the principal selected the option labelled 'Leave quiet, tune first'. The clause about it coming back on once the tune lands sits in that option's description, which is agent-authored. The tune is authorized; the posture flip is one confirmation away.
Minsky Reviewer StatusReview in progress... |
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Request changes. The PR improves the suppressor but introduces two new risks and misses a required flip. 1) Over-broad suppression: adding unscoped session_pr_merge as evidence for review-approved will suppress claims about PR B if any PR A was merged in-window; merge-entailment should be identity-scoped when a claim names a PR. 2) Alias handling is not applied to identity-scoped evidence; buildIdentityEvidence still does exact-name matches, so minsky-server alias reads don’t contribute PR numbers. Also, Success Criterion 4 (flip back to warn) is not met — INJECTION_ENABLED remains false — and docs weren’t updated for the new semantics. Please scope merge evidence to the claimed PR (when numbered), extend alias handling to identity-scoped PR-number extraction, either perform the posture flip or adjust the task spec, and update docs accordingly. Overall test additions are solid, but these correctness and compliance gaps must be addressed before merge.
Findings
-
[BLOCKING] .minsky/hooks/pre-narration-detector.ts:322 — Over-broad suppression: unscoped
session_pr_mergetreats any merge as evidence for anyreview-approvedclaim
You added merge tools toreview-approved.requiredToolsand explicitly chose NOT to identity-scope them (see the new comment and entries at.minsky/hooks/pre-narration-detector.ts:314-333). As a result,detectPreNarrationWithSuppression()will suppress areview-approvedclaim whenever ANY merge occurred in-window (sameTurn/inWindowchecks), even when the claim names a specific PR number that was not merged. This can mask genuine pre‑narration on PR B simply because PR A was merged earlier in the same session. -
Evidence of the unscoped addition:
.minsky/hooks/pre-narration-detector.ts:314-333— merge tools added underrequiredToolswith a comment “NOT identity-scoped”. -
Suppression path:
.minsky/hooks/pre-narration-detector.ts:611-630— suppression triggers onsameTurn || inWindowoverrequiredToolswith no PR-number check.
Requested fix: Bound the merge‑entailment to the claimed PR when the claim names one. Concretely: for review-approved, treat session_pr_merge/merge_pull_request as evidence only when (a) the claim names a PR number and (b) a merge tool in the window targeted that PR (similar to how merged.identityScopedTools works). When the claim names no PR number, you can keep the current unscoped entailment. Add unit tests for the numbered-PR case to prevent regressions.
- [BLOCKING] .minsky/hooks/pre-narration-detector.ts:534 — Alias fix not applied to identity-scoped evidence: PR-number correlation misses
minsky-serveralias tools
buildIdentityEvidence()derives PR numbers viaextractPrNumbersForTools(slice, scoped)wherescopedcomes directly fromcategory.identityScopedTools(see.minsky/hooks/pre-narration-detector.ts:518-544).extractPrNumbersForToolsusesfindToolUseInputs(lines, toolName)which requires an exact-name match.
You added withBareToolAliases and applied it to the presence sets (same-turn and window) via extractWindowToolUseNames() and in-turn toolNames (see .minsky/hooks/pre-narration-detector.ts:499-516 and :606-614), but you did NOT apply any aliasing when resolving identity-scoped tool INPUTS. Therefore, a session that emits mcp__minsky-server__session_pr_get or mcp__minsky-server__pull_request_read will not be recognized by identity correlation, because identityScopedTools lists only mcp__minsky__… and the bare names. This silently drops legitimate identity-scoped evidence under the alternate alias — the very invisibility this PR set out to address.
Requested fix: Expand identity-scoped tool-name matching the same way you did for presence sets. Options include: (a) have extractPrNumbersForTools accept a Set from withBareToolAliases(identityScopedTools) and treat observed names by suffix; or (b) pass an expanded name set into buildIdentityEvidence. Add tests proving that mcp__minsky-server__session_pr_get contributes PR numbers to identity evidence.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
| The tune distinguishes report-a-result-in-hand from claim-a-result-not-yet-had, and the discriminator is stated explicitly in the implementation rather than left implicit in a regex. | Met | .minsky/hooks/pre-narration-detector.ts:481-517 introduces withBareToolAliases and uses explicit tool-presence/evidence semantics; .minsky/hooks/pre-narration-detector.ts:304-333 explicitly encodes merge-entailment as evidence for approvals. The discriminator is tools-in-window (and identity-scoped reads), not regex-only. |
| Re-run against the captured window: the 10 injected fires drop, and the count of correctly suppressed matches does not fall. A tune that quiets the class by widening suppression until the detector fires on nothing is the failure mode to avoid. | Unverifiable | This requires rerunning scripts/diagnose-pre-narration-window.ts and comparing counts. The diff does not contain the output artifacts; the PR description reports numbers, but those are out-of-repo execution results. Per the constitution, this cannot be verified from the diff alone. |
| A negative control is recorded: a genuine pre-narration sentence — a result asserted with no preceding tool return — still fires after the tune. Without this the tune is indistinguishable from disabling the detector. | Met | .minsky/hooks/pre-narration-detector.test.ts:1049-1067 adds a negative-control test under mt#4498 — a merge entails the approval it merged on ensuring the same claim with NO tool in window still fires. Additional controls for unrelated tools and alias behavior are present at :1069-1117 and :1119-1154. |
| mt#4286's restore condition is discharged: once this lands, the detector returns from log-only to warn, and the flip is recorded where mt#4286 records the quieting. | Not Met | INJECTION_ENABLED remains false in .minsky/hooks/pre-narration-detector.ts:69-104. No change to the posture flag or registry wiring is present in the diff. The PR body explicitly defers the flip. This contradicts the Success Criteria’s requirement to restore from log-only to warn upon landing. Either update the task spec to reflect this deferral or add the flip here. |
Documentation impact
- blocking-needs-update — This PR changes suppression semantics (approvals now considered backed by merges; alias handling widened). If any docs describe the pre-narration detector’s evidence sources or suppression logic, they are now stale. I could not find docs updated in this diff;
.minsky/hooks/pre-narration-detector.tscomments changed but nodocs/file was touched. At minimum, the architecture doc that explains detector categories and evidence (“hooks/pre-narration-detector” or a shared guard overview) should note merge-entailment and alias handling. Additionally, the task spec’s Success Criteria demanded flipping posture back to warn; since the code leavesINJECTION_ENABLED=false, any doc claiming the detector is live would be wrong and should be aligned with actual behavior or the code should be changed.
…lias on both paths Both findings were correct. The first is the more interesting one. BLOCKING 1 - over-broad suppression. I had put the merge tools in requiredTools UNSCOPED, arguing a merge is an action the agent performed rather than a read, so the entailment holds without matching PR numbers. That argument is true and does not license the scope: unscoped, a merge of PR #100 suppresses a false 'PR #200 APPROVED' claim in the same window. It also contradicted this file's own stated principle one list below - for a suppressor the safe degrade direction is MORE fires, never fewer. Moved to identityScopedTools. BLOCKING 2 - the alias fix was one-sided. I normalized the two tool-NAME sets and not extractPrNumbersForTools, which matches names exactly too, so PR-number correlation stayed blind to mcp__minsky-server__. Fixed at that function, with a test asserting identity evidence sees the alias. Scoping surfaced a real constraint, and it costs most of the gain. Honest numbers on the replayed corpus: baseline 67 firing / 17 suppressed unscoped (R0) 56 firing / 28 suppressed <- unsound, withdrawn scoped (R1) 65 firing / 19 suppressed <- this commit Only 2 of 65 eliminated, not 11. The cause is structural: extractClaimedPrNumber reads the matched PHRASE, and review-approved's dominant pattern is the bare token APPROVED, so the phrase carries no PR number and can never be identity-backed. Added a PR-carrying pattern ordered before the bare one so a claim that DOES name its PR becomes scopeable - that is what the 2 are - but most of the corpus does not name one, and 16 of the 36 leaks have no tool calls in window at all. So this commit is now mostly a correctness change, not the FP reduction the task set out to make. Saying so plainly rather than reporting the withdrawn 56. Three new negative controls, one of them encoding R1 directly: a merge of a DIFFERENT PR must not suppress. Also reconciled an existing test that asserted review-approved has no identity evidence - true only while merged was the sole category declaring scoped tools. Its intent was category keying, so it now asserts a READ backs merged and does not leak into review-approved, which tests that intent directly.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
The fix commit addresses the prior blocking issues: merge evidence is now correctly identity-scoped (preventing cross-PR suppression), and alias handling is applied to both window and identity-evidence paths. New tests cover positive cases and multiple negative controls. However, the task spec’s SC4 requires restoring the detector from log-only to warn; the code still sets INJECTION_ENABLED = false, and no registry posture update is present. That leaves SC4 Not Met and is a merge blocker. Please flip the posture per the spec (or amend the spec to defer it with a follow-up), then this should be ready to approve.
Findings
- [BLOCKING] .minsky/hooks/pre-narration-detector.ts:86 — Spec-required posture flip not implemented — detector remains log-only
The task spec’s Success Criteria require restoring the pre-narration detector from log-only back to warn once the tune lands. In the current codeexport const INJECTION_ENABLED = false;remains unchanged (see.minsky/hooks/pre-narration-detector.ts:86and its Enforcement posture section), and there is no complementary registry or wiring change flipping the posture. The PR description explicitly defers this flip, but the spec is canonical and SC4/ATs require it in this task. Please flipINJECTION_ENABLEDback totrueand update any registry canary/expectations as needed — or amend the spec to defer SC4 and land it in a follow-up, with tests adjusted accordingly.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
| The tune distinguishes report-a-result-in-hand from claim-a-result-not-yet-had, and the discriminator is stated explicitly in the implementation rather than left implicit in a regex. | Met | The implementation explicitly adds identity-scoped evidence for approvals via merges and documents the entailment and scope: .minsky/hooks/pre-narration-detector.ts:285-307 adds identityScopedTools for review-approved with a rationale block explaining why merges entail prior approvals and why identity scoping is required. It also adds an ordered pattern /\bPR\s+#?\d+\b[^.!?\n]{0,80}?\bAPPROVED\b/ first so the matched phrase carries the PR number for correlation (:271-285). Alias handling is made explicit via bareToolName/withBareToolAliases and comments (:472-514, :561-637). |
| Re-run against the captured window: the 10 injected fires drop, and the count of correctly suppressed matches does not fall. A tune that quiets the class by widening suppression until the detector fires on nothing is the failure mode to avoid. | Unverifiable | This criterion requires executing the replay over .minsky/pre-narration-calibration.jsonl and comparing counts. The diff ships code and tests but not the replay outputs. While scripts/diagnose-pre-narration-window.ts is referenced in the PR description, the verification evidence (before/after counts) is not a repo artifact in this diff, so from code alone I cannot re-run or confirm the numeric result. |
| A negative control is recorded: a genuine pre-narration sentence — a result asserted with no preceding tool return — still fires after the tune. Without this the tune is indistinguishable from disabling the detector. | Met | .minsky/hooks/pre-narration-detector.test.ts adds multiple negative controls. Examples: the test "NEGATIVE CONTROL: a merge of a DIFFERENT PR does not suppress" ensures false backing does not silence (:1064-1081), and "NEGATIVE CONTROL: no evidence at all still fires" asserts a claim still fires when no evidence is present (:1083-1092). Additional alias negative control ensures unrelated tools under the alias do not suppress (:1126-1141). |
| mt#4286's restore condition is discharged: once this lands, the detector returns from log-only to warn, and the flip is recorded where mt#4286 records the quieting. | Not Met | export const INJECTION_ENABLED = false; remains in .minsky/hooks/pre-narration-detector.ts (near the top, Enforcement posture section). No change flips it back to warn, and no accompanying registry/doc flag change is present in this diff. The spec requires returning from log-only to warn in this task; the PR body explicitly defers this flip, so this criterion is unmet. |
Adoption sweep
| Symbol | Kind | Consumers found | Classification | Notes |
|---|---|---|---|---|
| .minsky/hooks/pre-narration-detector.ts#bareToolName | function | .minsky/hooks/pre-narration-detector.test.ts:1049 — assertions on alias handling, Used internally by extractPrNumbersForTools (:238-257) and withBareToolAliases (:496-514) | Adopted | New helper exported and consumed by tests; also used internally in this module. |
Documentation impact
- no-update-needed — Internal tuning to the pre-narration detector (identity-scoped merge entailment and alias handling) and added tests. No user-facing CLI, API, or documented behavior changed. The enforcement posture flip back to warn was deferred (and is called out as unmet in spec verification), so no posture-doc updates are included or needed in this PR.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
Verification pass: the R1 blocking issue remains — the spec-required posture flip back to warn is still not implemented. The code continues to export INJECTION_ENABLED = false, leaving the detector log-only, which leaves Success Criterion 4 Not Met. The rest of the changes look sound: merge evidence is correctly identity-scoped for review-approved, alias handling is applied consistently (including identity evidence), and tests add both positive cases and negative controls. Please implement the posture flip per the current task spec (or amend the spec to defer it with a follow-up), then this should be ready to approve.
Findings
- [BLOCKING] .minsky/hooks/pre-narration-detector.ts:86 — Spec-required posture flip not implemented — detector remains log-only
The task spec’s Success Criteria require restoring the pre-narration detector from log-only back to warn once this tune lands. In the current codeexport const INJECTION_ENABLED = false;remains unchanged in.minsky/hooks/pre-narration-detector.ts(Enforcement posture section near the top), and there is no complementary registry/wiring change to flip posture. The PR description explicitly defers this, but the current spec is canonical and SC4/ATs require it in this pass. Please flip posture to warn (setINJECTION_ENABLED = true) and adjust any registry canary/expectations as needed, or amend the spec to defer SC4 with a follow-up task and matching test updates.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
| The tune distinguishes report-a-result-in-hand from claim-a-result-not-yet-had, and the discriminator is stated explicitly in the implementation rather than left implicit in a regex. | Met | .minsky/hooks/pre-narration-detector.ts:286-309 adds identityScopedTools for review-approved with explanatory comments that a merge of PR #N entails prior approval of PR #N, and scopes it by PR identity. A new ordered pattern /\bPR\s+#?\d+\b[^.!?\n]{0,80}?\bAPPROVED\b/ is inserted before the bare APPROVED token so the matched phrase carries the PR number for correlation. Alias handling is factored explicitly via bareToolName/withBareToolAliases and applied to both window names and identity evidence (:514-552, :637-645). |
| Re-run against the captured window: the 10 injected fires drop, and the count of correctly suppressed matches does not fall. A tune that quiets the class by widening suppression until the detector fires on nothing is the failure mode to avoid. | Unverifiable | The criterion requires executing a replay over .minsky/pre-narration-calibration.jsonl and comparing before/after counts. The diff updates code and tests but does not include replay outputs or CI artifacts of the run; from repository content alone this numeric verification cannot be observed. |
| A negative control is recorded: a genuine pre-narration sentence — a result asserted with no preceding tool return — still fires after the tune. Without this the tune is indistinguishable from disabling the detector. | Met | New tests in .minsky/hooks/pre-narration-detector.test.ts cover multiple negative controls: "NEGATIVE CONTROL: a merge of a DIFFERENT PR does not suppress" (:1064-1081), and "NEGATIVE CONTROL: no evidence at all still fires" (:1083-1092). An alias negative control ensures unrelated tools under the alias do not suppress (:1126-1141). |
| mt#4286's restore condition is discharged: once this lands, the detector returns from log-only to warn, and the flip is recorded where mt#4286 records the quieting. | Not Met | .minsky/hooks/pre-narration-detector.ts still exports INJECTION_ENABLED = false (see the Enforcement posture section near the top). No complementary registry/wiring change flips posture. The PR description explicitly defers this flip, but the current task spec requires restoring warn posture in this pass; it remains undone and must be completed or the spec amended with a follow-up task. |
Documentation impact
- no-update-needed — Internal detector tuning (identity-scoped merge entailment for
review-approvedand alias handling) and added tests. No user-facing CLI or API changed. Posture remains log-only in code (flip deferred), so no posture-doc updates accompany this PR.
There was a problem hiding this comment.
Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2
R4 verification: the prior BLOCKING finding (SC4 posture flip) remains unresolved — INJECTION_ENABLED is still false and no registry/wiring change restores warn posture, while the current task spec still requires flipping back to warn. The other changes (identity-scoped merge entailment and alias handling) look correct and are well covered by tests with appropriate negative controls. Please either implement the posture flip per the spec or amend the spec to record the principal’s decision and defer SC4; once aligned, this should be ready to approve.
Findings
- [BLOCKING] .minsky/hooks/pre-narration-detector.ts:103 — Spec-required posture flip not implemented — detector remains log-only
Success Criterion 4 in the current task spec requires restoring the pre-narration detector from log-only back to warn once this tune lands. In the current code, the enforcement flag remainsexport const INJECTION_ENABLED = false;(see.minsky/hooks/pre-narration-detector.ts:56-101for the posture docs and:103for the flag). No complementary registry/wiring change flips posture. While the PR description cites a principal decision to remain quiet, the spec provided for this review is canonical and still requires the flip. Please either (a) setINJECTION_ENABLED = trueand adjust any related canaries/wiring, or (b) amend the task spec to defer SC4 (recording the principal decision) and update tests accordingly.
Spec verification
| Criterion | Status | Evidence |
|---|---|---|
| The tune distinguishes report-a-result-in-hand from claim-a-result-not-yet-had, and the discriminator is stated explicitly in the implementation rather than left implicit in a regex. | Met | .minsky/hooks/pre-narration-detector.ts:286-315 adds identity-scoped evidence for review-approved via merge entailment and documents why identity scoping is required. An ordered PR-number-carrying pattern is inserted before the bare APPROVED token so the matched phrase can be PR-scoped (see :292-305). Alias handling is made explicit via bareToolName/withBareToolAliases and applied on both window and identity-evidence paths (:508-552, :566-574). |
| Re-run against the captured window: the 10 injected fires drop, and the count of correctly suppressed matches does not fall. A tune that quiets the class by widening suppression until the detector fires on nothing is the failure mode to avoid. | Unverifiable | This requires executing a replay over .minsky/pre-narration-calibration.jsonl and comparing numeric before/after counts. The diff ships code and tests but no replay outputs; from repository content alone this numerical result cannot be observed. |
| A negative control is recorded: a genuine pre-narration sentence — a result asserted with no preceding tool return — still fires after the tune. Without this the tune is indistinguishable from disabling the detector. | Met | .minsky/hooks/pre-narration-detector.test.ts:1091-1109 asserts that a merge of a different PR does not suppress an APPROVED claim; :1111-1119 asserts that with no evidence present the claim still fires. Additional alias negative control at :1162-1177 confirms unrelated tools under the alias do not suppress. |
| mt#4286's restore condition is discharged: once this lands, the detector returns from log-only to warn, and the flip is recorded where mt#4286 records the quieting. | Not Met | .minsky/hooks/pre-narration-detector.ts:56-101 documents the quieted posture and :103 still exports INJECTION_ENABLED = false. No complementary registry/wiring change flips posture. The current task spec requires restoring warn posture; this remains undone in this diff. |
Adoption sweep
| Symbol | Kind | Consumers found | Classification | Notes |
|---|---|---|---|---|
| .minsky/hooks/pre-narration-detector.ts#bareToolName | function | .minsky/hooks/pre-narration-detector.test.ts:121-139 — alias helper tests, Used internally by extractPrNumbersForTools (:138-156), Used by withBareToolAliases (:530-552) | Adopted | Helper is exported from the module and exercised by tests; also used internally to normalize tool names for alias handling. |
Documentation impact
- no-update-needed — Internal detector tuning and alias handling; no user-facing CLI or API changed. Posture remains log-only in code (INJECTION_ENABLED = false), and the spec-required flip back to warn is currently unmet — but no existing docs are updated or invalidated by this PR. I checked only this hook’s code and tests; no docs files in
docs/reference this specific posture toggle.
Summary
The pre-narration detector warns when an agent claims an outcome before verifying it. Two calibration
windows measured its injected residual at 10 of 10 false — every one an agent reporting a result
already in hand.
I measured the cause before changing anything, and it is not what the spec assumed. Replaying the
whole log: the evidence is in the window and
requiredToolsdoes not name the tool carrying it.What this delivers — read this first
A correctness change, not the false-positive reduction the task set out to make.
2 of 65 eliminated, not 11.
Why scoping costs almost all of it — the structural finding
extractClaimedPrNumberreads the matched phrase.review-approved's dominant pattern is thebare token
/\bAPPROVED\b/, so the phrase is literally"APPROVED"and carries no PR number — thecategory cannot be identity-backed as written, and identity-scoping is the only sound form of the
merge evidence. A PR-carrying pattern ordered before the bare one makes a claim that does name its
PR scopeable; that is the 2. Most of the corpus does not, and 16 of the 36 leaks have no tool calls
in window at all.
This ceiling is now its own task: mt#4810.
The two fixes
1. A merge of PR #N entails the approval of PR #N.
session_pr_mergerefuses a PR with noapproving review, so the merge proves the approval happened.
R1 corrected this. I first put the merge tools in
requiredToolsunscoped, arguing a merge isan action performed rather than a read. True, and it does not license the scope: unscoped, a merge
of PR #100 suppresses a false "PR #200 APPROVED" claim. It also contradicted this file's own stated
principle one list below — "the safe degrade direction is MORE fires, never fewer." Now
identity-scoped.
2. The second MCP server alias was invisible. Matching is exact
Set.has; this project runs bothmcp__minsky__andmcp__minsky-server__, and the detector referenced the former exclusively(
grep -c→ 0). Every result claim in a session on the other alias could never be suppressed.R1 also corrected this. My first fix normalized the two tool-name sets and missed
extractPrNumbersForTools, leaving PR-number correlation one-sided. Both paths now usebareToolName.Testing
Execution evidence:
test:hooksis explicit —ROOTSexcludes.minsky/hooks, so the gated pre-push runner cannotreach this tree.
Negative controls — three, because the failure mode is a tune that silently disables the
category: a merge of a different PR must not suppress (encodes R1 directly); no evidence must
still fire; an unrelated tool under the alias must not suppress. Each differs from its positive by
one thing.
Verified the suite can fail: reverting the entailment turned exactly one test red and no others.
Reconciled an existing test rather than deleting it — it asserted
review-approvedhas noidentity evidence, true only while
mergedwas the sole category with scoped tools. Its intent wascategory keying, so it now asserts a READ backs
mergedand does not leak intoreview-approved.Typecheck: 0 errors, 8 projects. Lint: 0 errors, 0 warnings, 4179 files.
SC4 — resolved by the principal, not deferred
This is the PR's one BLOCKING finding, and it is now answered. The reviewer was right that SC4
(flip log-only → warn) had no disposition at review time.
ask#11118, answered 2026-08-31: "Keep it quiet, I file a task for the real fix." A selected
option label — principal provenance. The detector stays log-only until a tune actually moves the
count; the ask stated the real rate (65 of 167) so the call was made against the honest number, not
the withdrawn one. The follow-up it names is filed as mt#4810.
So SC4 is satisfied by not flipping. Nothing further is owed here.
Not closed here
16 of 36
review-approvedleaks have an empty tool window — a result reported in a turn with notool calls, referring to something verified more than
TRAILING_WINDOW_TURNS = 12turns back. Notool-list change reaches them. Owned by mt#4810.
Deploy impact
[no-deploy-impact]—isDeploySurfaceFilefalse for all three changed files, run over the diff.