Skip to content

ci(devx): delete the stale cost note on the dispatch-gates self-test step - #12982

Merged
os-elon merged 1 commit into
mainfrom
claude/issue-12831-dispatch-gates-cost-note
Aug 28, 2026
Merged

ci(devx): delete the stale cost note on the dispatch-gates self-test step#12982
os-elon merged 1 commit into
mainfrom
claude/issue-12831-dispatch-gates-cost-note

Conversation

@os-elon

Copy link
Copy Markdown
Collaborator

Fixes#12831

The PM dispatch-gates self-test step in .github/workflows/lint.yml closed its
justification with a cost note: "Reads two files and walks packages/; ~0.3s."
That note is deleted, not refreshed. Comment-only change: 26 changed lines, 0 of
them outside a # comment.

Why deletion rather than a new number

The sentence's defect is standing, not accuracy. It was the load-bearing half
of a paragraph, and a cost nobody re-measures ends up endorsing a decision it has
no standing to endorse. Supplying a corrected figure would require a reading from a
real CI run of that step; a reading taken in this agent container is a reading
of a contended box, not of a runner (#12528). Taking that reading is separate work.

The description was false in the same way as the estimate, so it went with it. Its
replacement is qualitative and carries no counts at all — counts rot exactly the
way ~0.3s did, and one quoted here would become the next generation of this same
defect. The retired line is kept in the comment as a quotation, explicitly past
tense, which is this file's existing convention for a claim it has withdrawn.

What the argument for unconditional execution now rests on

Solely on the first paragraph of that comment, which is untouched and never
depended on cost:

Same family as the Changeset-family gate self-tests step above, and like that one
this step is deliberately UNCONDITIONAL: no if:, no label read, no paths filter.
An exemption is what a self-test must not have, or the gap moves.

⛔ Nothing here argues the step should become conditional, and the rewrite says so in
the file: losing the estimate is not an argument for an if:, a label read or a
paths filter. Weakening this gate is a maintainer call. Whoever now reads the honest
description of what the self-test does and concludes the step is expensive is holding
a question for the maintainer, not a licence.

The content claims, re-verified on this tree

The correction rests on what the self-test does, which needs no stopwatch. Measured
on 7349a760a6 by instrumenting fs.readFileSync/fs.openSync/child_process around
node scripts/pm/dispatch-gates.mjs --self-test, with a null control in the same run
(node -e 0 through the same instrument reported 0 for every counter):

readingself-testnull control
self-test cases834 passn/a
workflow files opened280
distinct scripts/** sources opened2000
distinct repo files opened54160
mkdtempSync scratch roots40
child processes (git)169 (158)0
git init / git clone / git ls-files4 / 2 / 340

So: it runs the same live-tree discovery the tool does, it builds real temporary git
repositories and drives changedPathsFromGit against them, and it sweeps the tracked
corpus. That is not "two files", and it is not a walk of packages/. None of these
numbers is quoted in the workflow comment
— they are evidence for this PR, on a named
commit, which is where a number can be checked.

discoverFamilies() — the population, since two cards want it

The card cited "176 families". That reading is discoverFamilies().byCheck.size, and on
this tree it is now 179. Its population is distinct check invocations appearing in
run: blocks across the 28 tracked workflow files
— not scripts on disk and not
manifest keys:

  • 128 keyed by a check:* npm alias
  • 51 keyed by a bare script path (scripts/check-adr-links.mjs, scripts/pm/ci-failure.mjs --self-test, ...)
  • 28 workflow files read (independently confirmed: git ls-files .github/workflows returns 28)
  • 174 distinct source files then opened for watch hints: the 51 resolved gate scripts plus 123 first-party modules they import one level down

⚠️ It is therefore a different population from the four counted on #12795, all of which
I re-derived here: 110 root check:* keys, 143 across all workspace manifests, 118
scripts/check-*.mjs, 129 including subdirectories. Each is exactly +1 against that
card's figures, which is what fa5d137 (#12942) adds — so those were taken pre-#12942
and mine post, a consistent offset rather than a disagreement. ⚠️ Note the collision: 128
is both that card's subdirectory count and this tree's alias-keyed half of
discoverFamilies(). Two different populations, one integer.

Sweep for the claim elsewhere

git grep over the whole tree for Reads two files, 0.3s and walks packages:

Changeset

Derived, not inherited: changeset-check in .github/workflows/pr-automation.yml
requires an added .changeset/*.md unless the skip-changeset label is present (or the
PR is the changesets release PR). It has no path-based exemption — a workflow-only
diff is not automatically excused. This diff is comment-only inside a CI workflow and
publishes nothing, so the label is the correct declaration and no changeset is written.

Gates

Derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
(re-derived after the final commit; family unchanged), then run on 7349a760a6. Each exit
code captured before any pipe.

All 28 green (exit 0): check:agent-test-spelling, check:node-version,
check:pnpm-acquisition, check:pnpm-filter-targets, check:required-contexts,
check:shard-attestation, check:stall-guard-budget, check:type-check-coverage,
check:workflow-status-functions, check-aggregator-roster.mjs,
check-required-contexts.mjs, check-self-test-wired.mjs,
check-self-test-workflow-commands.mjs, check-shard-attestation.mjs,
check-step-collectors.mjs, check-whole-set-label-write.mjs,
docs-audit/check-drift-comment.mjs, pm/ci-failure.mjs --self-test, plus the
human add-ons the derivation under-names for a lint.yml edit:
check:pm-dispatch-gates, check:nul-bytes, check:runner-env-posture,
check-ci-filter-parity.mjs (self-test and live), check-comment-mask-corpus.mjs,
check-comment-mask-adoption.mjs, check:pm-half-states,
check:partof-closing-keyword, check:single-claim-paths.

Declared narrowing — 1 of 29 not measured locally.check:type-check-debt exited 1
with its own verdict line: "--re-measure cannot run: 56 workspace dependencies of the
ledgered packages have no built type entry point on disk ... Build the closure first,
exactly as lint.yml does before this step"
. That is a prerequisite refusal, not a red
gate — lint.yml builds the closure before invoking it and CI will. The lint.yml-facing
half of that family is measured: check:type-check-coverage runs the same script and
printed check-type-check-coverage: OK, and its only assertions over this file are two
regex presence tests, both unmoved base to head (turbo run typecheck true/true,
typecheck:root false/false, against a negative control that is false/false).

Control-byte scan clean (grep -naP over the file returns nothing; the same instrument
returns 1 on a VT-seeded control file).

Generated by Claude Code


Generated by Claude Code

…step
The `PM dispatch-gates self-test` step's justification closed with "Reads two
files and walks packages/; ~0.3s". That described the 61-case self-test the
paragraph above it names, and the part of the self-test that grew since is
exactly the part the line denied: its live-tree cases run the same discovery
the tool does (every workflow file, then the source of every gate that
discovery finds), build temporary git repositories and drive
`changedPathsFromGit` against them, and sweep the tracked corpus.
The figure is deleted rather than re-measured. A replacement has to be read off
a real CI run of that step -- a reading taken in an agent container is a
reading of a contended box, not of a runner -- and that is a separate piece of
work. The defect being repaired is not that the number was inaccurate but that
it was endorsing a decision it had no standing to endorse.
No live counts replace it, for the same reason: they rot the same way. The
shape of the work is what the argument needs, and it needs no stopwatch.
The step stays UNCONDITIONAL and this change does not argue otherwise. Cost was
never what made it unconditional -- the first paragraph of the comment is, and
it stands untouched: an exemption is what a self-test must not have, or the gap
moves. A note added at the end says so explicitly, so the deletion cannot be
read as clearing the way for an `if:` or a paths filter.
Comment-only: 26 changed lines, 0 of them outside a `#` comment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cdsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-elon@claude