Skip to content

fix(devx): dispatch-gates drift banner scopes its quiet line to the visible range and refuses the unqualified all-clear - #13418

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13392-stale-tree-honest-refusal
Aug 30, 2026
Merged

fix(devx): dispatch-gates drift banner scopes its quiet line to the visible range and refuses the unqualified all-clear#13418
os-project-manager merged 1 commit into
mainfrom
claude/issue-13392-stale-tree-honest-refusal

Conversation

@claude

@claude claude Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #13392

Per the dispatch ruling, this lands the corrected card's option D — fix the determination itself — and deliberately does NOT layer a non-zero exit or a stdout incompleteness marker on top of it (the exit-code question once the determination is trustworthy is a follow-up card). The loud STALE TREE branch, the three-dot diff direction, and the silence at zero are untouched; no existing refusal is weakened. Everything below strictly adds refusals.

What changed

1. The quiet line no longer asserts what it did not measure. The old spelling — At least N commit(s) behind origin/main, but nothing this answer derives from changed across that range — was a claim about a range the instrument cannot see the end of: the diff runs against the LOCAL origin/main snapshot, which only a fetch moves, while a reader takes "that range" to reach upstream. The new spelling states exactly the reading taken and refuses the rest, in two lines: ...and none of the commit(s) this tree can SEE touched what this answer derives from... followed by Whether UNSEEN upstream work did, this run cannot tell: the range above ends at origin/main, a LOCAL snapshot only a fetch moves — not at upstream, plus the fetch remedy. A true "I cannot tell" replaces a sometimes-false "nothing changed".

2. A second unearned-reassurance door is closed. When the three-dot diff READ failed, the old producer collapsed it into an empty changed-set (names ? split : []), and the render printed the same reassurance from no reading at all. changed is now null when unread and an array only when read; unmeasuredDrift gains a third door that refuses in the register the other two already use (STALENESS NOT MEASURED ... The changed set is UNKNOWN. Not empty: no reading was taken.), naming the step that failed and the diff command as its remedy. This state is one command away in production, not hypothetical: a depth-1 clone — which is how this fleet's containers arrive — plus one shallow fetch counts a distance fine (rev-list --count answered 1, exit 0) while the three-dot diff dies with no merge base (exit 128). Measured in a sandbox and re-measured by the new self-test fixture.

The measured mechanism (Zone 2 verification)

The PM's hypothesis was "the #13369 worktree had an unfetched base". Measured, the mechanism is sharper and worse:

  • PR Rule 3 root extension: a ledgered cross-package prose-id leg on check-doc-authoring, sized by its own AST census #13355 (the check:doc-authoring cross-package prose-id leg) touched exactly 4 files, all under scripts/ — inside DERIVATION_SURFACE. Alternatives (a) surface-misses-the-path and (b) family-derives-off-surface are dead: after merging main, re-derivation on test(qa): census the authz-conformance probe table's reach across all 11 probe files #13369 gained exactly that family, so the surface and the matcher see it whenever it is on disk.
  • Alternative (c), the behind ? read : empty short-circuit, was not the emitter: the quoted first-run line says At least 1 commit(s) behind, which requires a truthy behind, so the diff ran — and the visible diff genuinely was empty. (The adjacent failed-read door is real anyway and is closed by change 2.)
  • Timeline, from REST commit/PR readings: the test(qa): census the authz-conformance probe table's reach across all 11 probe files #13369 branch was cut from 3ec8646f (landed 06:08:09Z). Its final pre-fix commit is 06:41:04Z; the PR opened 07:07:13Z with the union results already in its body, and the union includes an 85-second repo lint plus 24 families — so the derivation ran in the window 06:41 to roughly 07:00. The reading it printed — behind 1, changed empty — is exactly what a snapshot at 56c5b1db (PR 13316, landed 06:32:24Z, plugin-email only, off-surface) yields. That snapshot was AT MOST ~13 minutes old at derivation, possibly minutes. The falsifying landings came after the snapshot and mostly after the derivation: 54cc1555 (scripts, 06:45:04Z), then four more, then Rule 3 root extension: a ledgered cross-package prose-id leg on check-doc-authoring, sized by its own AST census #13355 itself at 07:05:43Z — about 20 minutes after the derivation and 11 minutes before the CI run (07:16:21Z) that consumed the answer and reddened on the missing family.
  • So the falsified half of the hypothesis matters: the base was not an old unfetched ref; it was nearly fresh. A freshness gate on the snapshot — the optional Zone 3 shape — would have called this base fresh and printed the reassurance anyway, because fresh-at-derivation is not true-at-consumption against a merge queue that landed six times in the gap. The confirmed half is the lower-bound property: the changed-set, like the count, can only understate. That is why the fix is the ruling's own preferred sentence (a stated inability) rather than a freshness-gated reassurance: at this repo's landing cadence no local instrument can earn the unqualified claim, ever.

Self-tests (ruling obligation 4)

New cases pin both doors from literals and from a real depth-1 fixture, with the required red demonstrated by ablation:

  • Quiet branch: scopes to the visible range (can SEE), states the unseen half as untellable (cannot tell), hands over the fetch, and a departure pin with a length-and-content conjunct asserts the retired spelling is gone — it cannot pass vacuously against an empty render.
  • Third door: literal drift with a read distance and an unread changed-set refuses (Not empty), names the base and the count so the reader can tell WHICH step failed, and its remedy is the diff, not the fetch or the count; the three unmeasured doors render distinctly.
  • Real-repo fixture: depth-1 clone, positive control (fresh shallow clone counts 0), upstream surface commit beyond the shallow boundary, one shallow fetch — distance reads, changed-set is null, render refuses, and no line reassures while a surface commit sits in the unreadable range.
  • Vacuous-pass audit: no new success condition equals its total-failure condition — each absence assertion carries a positive-content conjunct, and the fixture holds a live upstream surface commit while asserting no reassurance prints.

Ablation, both legs predicted before running, mutations and restores proven on disk (anchored grep counts, then blob hash against the HEAD blob; restores byte-identical, git diff HEAD empty; the subject runs from source, so no build sits between the edit and the run):

  • Leg A — old reassurance sentence reinstated: predicted 5 named cases red, measured exactly those 5 of 919 red, exit 1; the shallow-fixture refusals stayed green as predicted (door 3 intact).
  • Leg B — old failed-read collapse reinstated: predicted 5 named cases red, measured exactly those 5 of 919 red, exit 1; the door-3 literals stayed green as predicted (hand-built null bypasses the producer).

Verification

Union derived on the final head — the derivation's own stderr names objectstack-ai/objectstack at commit a1d5df1d, change set 1 path vs merge base 090f2302e — 14 matched families, all run at that head:

  • GREEN, verdict lines quoted from the gates, exits captured before any pipe: check:pm-dispatch-gates ("919 cases pass"), check:self-test-wired ("every one of the 151 script(s) ... has that self-test run by CI"), check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check:watch-hint-literal, check:cross-package-test-inputs ("OK: 24 package(s) read outside themselves, all declared"), check-ci-filter-parity ("OK: all 123 declared cross-package glob(s)"), check-cross-package-test-inputs, check-shard-attestation ("2 aggregate gate(s) count 3 declared leg(s)").
  • NOT MEASURED, by the gate's own declaration: check-test-completeness exits 3 with "PREREQUISITE NOT MET — this gate grades a saved turbo run test log ... the local reading for this gate is NOT MEASURED. It is not a red."
  • Card-named extras: node scripts/pm/bare-root-worklist.mjs --self-test OK ("51 live row(s) ... none stale, none missing, none contradicted"); check:nul-bytes OK (7433 files, no raw control bytes).
  • Lint, narrowed with the three-part proof: population is eslint's own flat config; the diff's git-derived change set is exactly 1 path (scripts/pm/dispatch-gates.mjs, from the derivation stderr); --format json counted 1 file linted, 0 errors 0 warnings, exit 0; and the config is not type-aware (no project service for these files — stated at eslint.config.mjs line 328), so this diff cannot move any untouched file's verdict.
  • The changed banner ran live on this very derivation: the checkout sat 2 commits behind the snapshot, both off-surface, and the new two-line form printed — re-derived immediately after a fresh fetch, family list byte-identical.

No changeset: the diff publishes nothing — it is entirely scripts/pm/ (PM tooling), which is the skip-changeset class; the label is applied with this PR's opening.

The report with the full measurement record is on the card as an os-dev-report comment.

Generated by Claude Code


Generated by Claude Code

… range and refuses the unqualified all-clear

The quiet branch printed 'nothing this answer derives from changed across
that range' from a reading whose range ends at the last-fetched snapshot
of the base ref. Measured on a production incident: the snapshot was at
most ~13 minutes old, the visible reading exact, and upstream landed four
derivation-surface commits between derivation and the CI run that consumed
the answer — one carrying the very family whose absence turned CI red. The
sentence is not earnable by any local instrument, so it now states what it
measured (the VISIBLE commits are surface-clear), states the unseen half
as untellable, and hands over the fetch.

A second unearned-reassurance door closed with it: a failed three-dot diff
read collapsed into changed: [] and rendered the same quiet clear sentence
from no reading at all. A shallow clone plus one shallow fetch reaches it
(measured: the count reads 1, the diff dies with no merge base). changed
is now null when unread, unmeasuredDrift gains the third door, and the
self-test pins both doors from literals and from a real depth-1 fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 30, 2026 11:21
@os-project-manager
os-project-manager added this pull request to the merge queue Aug 30, 2026
Merged via the queue into main with commit 5f0a9c4 Aug 30, 2026
34 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13392-stale-tree-honest-refusal branch August 30, 2026 11:54
This was referenced Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant