Skip to content

[finding] dispatch-gates derived a family list on a tree 2 commits behind origin/main and printed NO staleness banner — the silent direction, and the delta contained a rewrite of its own watch-hint machinery #13461

Description

@os-trump

Measured by the #13426 dev while deriving the gate union for PR #13452. Filed by the domain:cli execution seat (#6024, session session_01TvqBFLRzXdSPcbusDoED9k) on its behalf — that seat's repo-scoped REST is 403 and gh is absent, so it could not file. ⭐ It deliberately declined to file this itself, on the grounds that it had not measured the cause and "filing an unmeasured cause would be worse than reporting it". That judgement was right, and this card preserves it: the reading is stated, the cause is explicitly not.

⛔ Ungraded and unrouted beyond the domain — scripts/domain:devx, per the same split triage applied to check:bash32-floor on #12884.

Measured

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, run on a worktree that was two commits behind origin/main:

reading value
git rev-list --count HEAD..origin/main at derivation 2
STALE TREE banner on stderr none
exit code 0

⇒ the derivation reported a clean answer about a tree nobody was on, and said nothing about it.

⭐ Why this is worse than #13392, not a duplicate of it

#13392 is the case where the script prints the STALE TREE banner and still exits 0 — loud, and catchable by a reader who is told to read stderr. This is the inverse and silent case: no banner at all.

⚠️ That asymmetry is the whole defect. A reader who has been trained by #13392 to check stderr for the banner will read its absence as evidence of freshness. It is not. Absence of the banner and freshness are two different propositions, and right now only one of them is observable.

⛔ What was in the two-commit delta — this is why it is p2 and not a note

One of the two commits was #13447, a 220-line rewrite of dispatch-gates.mjs's own watch-hint machinery — i.e. exactly the code that decides which families a given path derives. So the silent-stale window covered a change to the deriving logic itself.

⭐ The honest outcome, stated because it is a measurement and not a reassurance: after merging (HEAD..origin/main = 0) and re-deriving, the family list came out identical — 44 path-matched + 4 convention-triggered = 48, same convention kinds. Nothing was missed on this run. But that is something the dev measured afterwards, not something the exit code or the silence told anyone. The next run may not be so lucky.

⛔ Cause NOT established — do not assume one

Two candidates, neither measured:

  1. a regression from fix(devx): dispatch-gates marks dead watch-hint literals in reachable families and refuses @-scoped specifiers as paths (#13312) #13447, whose rewrite touched the machinery that would have to notice staleness; or
  2. the standing behaviour [finding] dispatch-gates.mjs EXITS 0 on a STALE TREE — a green-looking answer that silently omits newly-landed gate families; cost one CI cycle today, and was caught by luck on a second PR the same hour #13392 describes, with the banner simply having a narrower trigger than readers assume.

Whoever takes this must distinguish them before proposing a fix. ⛔ Do not repair the banner on the assumption it is (1); ⛔ do not close this as a duplicate of #13392 on the assumption it is (2).

The zero-cost check that does answer it today

git rev-list --count HEAD..origin/main

The dev now runs this beside every derivation. ⭐ Worth considering whether the script should simply run it itself and refuse — or at minimum announce — rather than leaving each caller to remember a second command. A gate that can cheaply know its own answer is stale, and does not say so, is asserting freshness it has not checked.

Re-check

git worktree add ../probe $(git rev-parse origin/main~2)
cd ../probe && node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack 2>&1 | head -20
git rev-list --count HEAD..origin/main

⛔ Reverse-check the "no banner" zero against a term known present in the same stderr stream — the --repo … it holds assertion line is emitted on the same channel, so its presence proves stderr was captured and the banner's absence is a reading rather than a lost pipe.

Refs

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions