Merge-queue triage: name the exception — the discriminator is what the assertion measures - #13966
Merged
Merged
Conversation
…hat the assertion MEASURES The posted triage comment tells readers that a timeout is load/timing and an `AssertionError` points at a real behaviour change. That rule is right about the common case and demonstrably prevented a wrong flake call the same morning this exception was measured — but "assertion ⇒ real change" has a counterexample class, and it is the expensive direction. A validity-precondition assertion (the run must fit inside a time budget for the following distinctness assertion to mean anything) measures nothing about the product. It reads with the timeouts: load-sensitive, and one re-queue is a legitimate discriminator. The tell is mechanical — the assertion's message or its compared values name a duration, a timestamp, or a count of elapsed units. Purely additive (46 lines, 0 deletions): one paragraph in the posted comment and the provenance section in the file header. The existing heuristic is untouched, and so is the re-queue allowance, which is governed elsewhere. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
This was referenced Aug 31, 2026
os-sam
marked this pull request as ready for review
August 31, 2026 20:19
os-sam
enabled auto-merge
August 31, 2026 20:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13830
The merge-queue triage comment tells its reader that a timeout is load/timing and an
AssertionErrorpoints at a real behaviour change. That rule is right about the common case and is doing real work — the same morning the counterexample below was measured, a seat used it to refuse a flake reading on anAssertionError(#13683), correctly, and that refusal is why that card exists.But "assertion ⇒ real behaviour change" has a counterexample class, and it is the expensive direction. #13691 ejected the queue with an
AssertionErrorthat measures nothing about the product:That is the test's own validity precondition — the run has to fit inside one second so that a truncated second-precision stamp could not have distinguished the two updates, which is what gives the distinctness assertion below it any meaning. The invariant actually under test (monotonicity, asserted a line above) held. The experiment was invalidated; the product was not falsified — and it was confirmed load-dependent by evidence rather than taste: same head, same test, re-queued once with no change, success.
Under the rule as written, the instructed outcome there is to send an author to debug a product that is not broken, on a red they cannot reproduce.
What this changes
The discriminator is not
AssertionErrorvs timeout. It is what the assertion MEASURES.The tell is cheap and mechanical: the assertion's message or its compared values name a duration, a timestamp, or a count of elapsed units.
46 insertions(+), 0 deletions(-)— purely additive, and the two existing guidance lines are byte-identical toorigin/main.Carrier grep — the result is one carrier, not two
The card and the claim both asked for the 超时/断言 pair to be located by grep before editing, so the copies cannot diverge. Grepped against
origin/main, the pair resolves to exactly one carrier:.github/workflows/merge-queue-triage.yml— the twobodyarray lines that compose the posted triage comment.Checked and not carriers (no copy of the pair, so nothing to keep in sync):
.claude/skills/pm-dispatch/references/landing-operations.md.claude/skills/pm-dispatch/references/dispatch-runbook.md— the file HELD by pending PR #13948.claude/skills/pm-dispatch/SKILL.mdscripts/check-merge-queue-triage-outcome.mjs,scripts/fixtures/merge-queue-triage/**AssertionErroras parser input and fixture bytes, not as guidance proseCopy count 1, so neither of the claim's stop conditions (count above two ·
SKILL.mda carrier) fires.Why the numbered pair is in the header and not in the posted body
The card asks for the counterexample and its same-morning control to be cited, because the pair is what makes the distinction legible. They are cited, in full, in the file-header section — which is this file's existing idiom for provenance (#4859, #10112, #10120, #10115, #10128 all live there and none of them is in the posted body).
Keeping the two numbers out of the posted body is deliberate and mechanical, not a softening: that body is auto-posted onto a PR on every red queue build, and a bare issue reference in it would mint a fresh cross-reference event on both cards every single time. The body therefore carries the two cases descriptively — and it carries them as measured bytes, which is the operative half anyway: the precondition assertion verbatim from the counterexample, against this file's own already-quoted product-behaviour assertion (
SecurityPlugin.init() ran: expected false to be true). No id-lint gate is in force here —check:pm-skill-id-lintscopes itself to.claude/skills/pm-dispatch— so this is a judgment about comment noise, and it is reversible in one line if the seat prefers the numbers inline.Verification
All on the final head
0183098e, gate union derived on that same head withnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(the script's own change-set derivation, no hand-built path list).19 derived families + the pin suite's
--self-testleg +check:nul-bytes= 21 invocations, 21 green, 0 red. Exit codes captured before any pipe (redirect, then read the file), and the verdicts below are the lines the gates themselves printed:The pin suite is the load-bearing one for a workflow edit, and it ran on both legs the way
lint.ymlinvokes it. Its plain run reports the char count of the script it extracted from the edited YAML, so the edit is parse-clean and the comment body still composes; its--self-testdrove 17 mutations of that shipped script to red, so the battery is not decoration.ESLint: a declared narrowing, and a measured one
pnpm lintis a repo-wide scan CI owns. It was narrowed to the diff's paths, and the narrowing excluded nothing — three readings, none of them a guess:files:glob ineslint.config.mjsis**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}or a narrowerts/tsx/mts/ctssubset. No glob names.yml.--format json: runningeslint --no-inline-config --format jsonover this diff's one path returns exactly one result entry whose only message isFile ignored because no matching configuration was supplied.—errorCount: 0, and zero rules applied. This diff contributes zero linted files.parserOptions.project, noprojectService, everyparserOptionsin the file is a bare{ ecmaVersion, sourceType }, and the config states this at line 328. With no cross-file type program, a.ymledit cannot move the verdict on any file it did not touch. The diff also edits no eslint config.Changeset
None, deliberately — the diff is one
.github/workflows/**file and publishes nothing from any package.skip-changesetapplied at PR-open time..claude/**file is touched), so it follows the normal code path, but the dispatch holds it as a draft either way.Generated by Claude Code