Skip to content

feat(scripts): report-only present-tense phrase reading on the spec docblock corpus - #20057

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-19017-present-tense-docblock-report
Sep 25, 2026
Merged

os-litant merged 1 commit into
mainfrom
claude/issue-19017-present-tense-docblock-report

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19017
Clause-②: no

Executes ruling 5805901449 on #19017 (batch #219 item 2, letter 甲, 「只报告」; maintainer 「同意」): the spec docblock gate family gains a narrow present-tense phrase reading, report-only.

What changed

One file: scripts/check-spec-docblock-symbol-anchors.mjs (+403 / -3).

  • PRESENT_TENSE_PHRASES is exactly the ruled list: this phase, is a follow-up, not yet implemented, currently no. Matching is case-insensitive and whole-word (currently no does not match currently none). Comment delimiters and the JSDoc gutter are blanked and whitespace is folded across lines, so a phrase wrapped over two lines is one hit, reported at the line where it starts.
  • Population and projection are the anchor corpus's own: the files sweepCorpus walked (its byDoc), read through commentProse. So "docblock" means what it means for this gate: every comment, line or block, and never code or a string literal. Test sources are skipped.
  • Report-only by construction. reportPresentTense has no exit path and sets no exit code. It turns any throw into a NOT MEASURED line. It runs before the anchor verdict, so it also prints on a red run and cannot move the verdict. Each hit prints as a 📝 [present-tense] FILE:LINE "phrase" line, followed by one summary line.
  • A new --present-tense arm prints the reading alone and always exits 0. It is also what the exit-0 self-test spawns.
  • The header records the list and its growth rule: a phrase joins only with its own measured reading in PRESENT_TENSE_CENSUS, and the self-test goes red on a listed phrase that has no reading. The header also records today's count per phrase. PRESENT_TENSE_REFUSED_WIDE records why there is no stays out.
  • ⛔ No workflow edit, no package.json edit, no required check, and no docblock edited.

Extend vs sibling: extended, and why

I extended the existing script instead of adding a sibling script. It is the smaller change:

  1. The reading is taken where it will be read. lint.yml already runs this script's default arm and --self-test on every PR, so the report lands in that step's log with no new wiring. A sibling would need either a workflow edit (out of scope for this claim) or nothing to run it at all. An instrument no one runs takes no reading.
  2. One population, not two. The report reuses the sweep the gate already makes (byDoc), so the corpus definition is the family's and cannot drift from it. A sibling would need its own walker, or would have to import this one's internals.
  3. The existing verdict is left alone. It stays byte-identical apart from the added report lines (proof below). The new self-test cases are a separate battery, so the existing battery still registers exactly 124 cases.

Today's reading, and the judgement on each hit

origin/main at 5581d3000f27daa19991cf9d13d5ad1ed8cf8913: 1,046 non-test sources read and 504 test sources skipped.

phrase hits file, line judgement
this phase 0
is a follow-up 0
not yet implemented 1 packages/spec/src/api/errors.zod.ts line 114 still true. A trailing line comment that glosses what the NOT_IMPLEMENTED error code means. It defines the code and makes no claim about the repository's state.
currently no 0

Positive control. I also ran the same instrument on the card's own tree, 43f4766889e39d7a4590c5787d38e5956d0b4cb6. It reads 2, 1, 1 and 0 for the four phrases. The first three are the packages/spec/src/data/api-derivation.ts sites that #18991 repaired (lines 129, 130 and 196, all rotted). I checked on that tree that plugin-hono-server's current-user-endpoints.ts already passed a real allowExport-derived userExportAllowed. The fourth is the same errors.zod.ts gloss. The card's probe also counted one currently no. That one is in a string literal (packages/spec/src/data/driver/common.zod.ts), outside this projection.

The wide phrase, measured with this instrument. there is no gets 320 comment-prose hits in 149 files today, and 286 on the card's tree. It stays out.

Proof the existing gate is unchanged apart from the report lines

I ran the default arm on 5581d3000f before any edit and again on 27cd45335e after the edit:

  • The exit code is 0 before and 0 after, and stderr is empty both times.
  • Stdout gains exactly three lines, inserted after the last day-one residual row and before the unchanged final line: one 📝 [present-tense] hit line, its excerpt line, and the summary line. Every other line is byte-identical: diff reports a single 34a35,37 hunk.
  • --self-test still exits 0 and gains one line (the new battery's success line). The existing verdict line is unchanged. The existing battery was probed at exactly 124 cases, and the new battery registers 38.

The exit-0-with-hits case lives in the self-test. It spawns --present-tense over a fixture tree with one planted hit per phrase, then asserts exit 0 and each printed FILE:LINE "phrase" line. It also asserts the following:

  • The wide phrase, the near misses (currently none, this phased, follow-upper) and a string literal print nothing.
  • A .test.ts that carries all four phrases is in the population but skipped.
  • The instrument does find there is no when asked directly, so it is kept out by the list and not by a blind matcher.
  • In-process calls with hits, an unreadable source and a population with only test files each leave process.exitCode untouched and print NOT MEASURED instead of throwing.

Ablations (one-time, run through scripts/ablation-replace.mjs, which checks the mutation landed on disk and proves the restore: blob equals HEAD and git diff HEAD is empty; no permanent test file):

  • A1: process.exit(1) when the report has hits. Red at the report arm must exit 0 WITH hits, got 1. My first A1 attempt was a no-op, because the replacement still contained the anchor and the tool refused (anchor count 1 to 1, restored). I discarded it and re-ran with a different anchor.
  • A2: gutter blanking removed. Red at the planted "this phase" must be ONE hit at packages/spec/src/pt/rotted.ts line 3, got [].
  • A3: there is no added to the list. Red at the fixture must plant exactly one hit per listed phrase.

Gates (on 27cd45335e)

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 31 commands. Results:

  • 30 of 31 exit 0, including check-spec-docblock-symbol-anchors (both arms), check-scripts-symbol-anchors (both), check-self-test-wired (both), check-self-test-workflow-commands (both), check-comment-mask-corpus, check:nul-bytes, check:entry-guard, check:parse-guard and check:watch-hint-literal.
  • pnpm check:pm-dispatch-gates is longer than the foreground cap on this shared box, so I ran its two halves separately. The --self-test half exits 0. The scan half also exits 0 (dispatch-gates self-test: 1925 cases pass; it took 876 s).
  • --ran reconciliation: 31 derived famil(ies) accounted for — 31 run, 0 NOT-MEASURED, with every exit code recorded before any pipe.
  • Roster families under scripts/ that the derivation flagged: check-published-list-mirrors (both), check:console-injection, check:engine-double-contract, check:i18n-stale-fill and check-dts-references --self-test exit 0. check:dts-closure and check:published-readme-exports exit 3 (their own PREREQUISITE NOT MET: no built package dist/ in this worktree). These are NOT MEASURED, and this diff touches no package.
  • eslint, narrowed to the one changed file and measured: ① it is in the population of eslint's own config object files: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}'], and --print-config resolves 2 rules for it; ② --format json reports 1 file, 0 errors and 0 warnings; ③ the config never enables type-aware linting (the resolved parserOptions carry only ecmaVersion and sourceType), so this diff cannot move any other file's verdict.
  • Changeset: none. This is a root scripts/** change and the root package is "private": true, so nothing publishes. The repo's documented route is the skip-changeset label. This dispatch forbids me any label write, so the owning seat applies it, and Check Changeset stays red until it does.

Acceptance notes


Generated by Claude Code

…ocblock corpus

The spec docblock anchor gate gains a second, separate reading: the four
narrow present-tense phrases the ruling names ("this phase",
"is a follow-up", "not yet implemented", "currently no"), matched
case-insensitively and whole-word over the corpus's own comment-prose
projection with test sources skipped, folded across the JSDoc gutter so a
wrapped phrase is one hit.

Report-only by construction: printed before the anchor verdict, inside a
catch that prints NOT MEASURED instead of throwing, with no exit path. The
anchor gate's exit code and every line it printed before are unchanged; a
`--present-tense` arm prints the reading alone and exits 0. A separate
self-test battery plants one hit per phrase, refuses the wide phrase and
near misses, skips a test source, and spawns the arm to hold exit 0 with
hits. The header records the list, its growth rule and today's reading.

Claude-Session: https://claude.ai/code/session_019c3Hi6ZMU1p6m6aA6Bz45d
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

PM review — ACCEPT at head 27cd45335e, 2026-09-25T00:17Z

domain:spec seat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d), claim 5823892493. Governing ruling: 5805901449 (batch #219 item 2, letter 甲, report-only; maintainer 「同意」).

  • Scope matches the ruling. One file, scripts/check-spec-docblock-symbol-anchors.mjs (+403 / −3). Exactly the four ruled phrases (PRESENT_TENSE_PHRASES). there is no stays out and is recorded with its measured width (320 today, 286 on the card's tree). No workflow, package.json or docblock edit.
  • Report-only holds. The diff adds no exit path. The self-test asserts exit 0 with planted hits and an unchanged process.exitCode, and ablation A1 (exit 1 on hits) goes red. Default-arm stdout differs from the base only by the three added report lines.
  • Reading today: 1 hit, packages/spec/src/api/errors.zod.ts:114 not yet implemented. The dev judged it still true (it glosses the NOT_IMPLEMENTED code). The seat concurs: dismissed in one line, as the ruling prescribes. Positive control on the card's tree 43f4766889: all three [finding] ResolveApiOptions.userExportAllowed still documents itself as "always true this phase" — #3544 wired the bit in, and #18931 is what that costs #18991 sites found.
  • Changeset: none. A root scripts/** change publishes nothing, so the seat applied skip-changeset in this act (AGENTS.md changeset rule).
  • Contract review: not owed. Clause-②: no; no accept set or published surface moves.
  • Promotion to a required gate is ⛔ outside this PR. Per the ruling it needs the maintainer's own word after the readings.

Generated by Claude Code

@os-litant
os-litant marked this pull request as ready for review September 25, 2026 01:12
@os-litant
os-litant enabled auto-merge September 25, 2026 01:12
@os-litant
os-litant added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 66ac73d Sep 25, 2026
36 of 37 checks passed
@os-litant
os-litant deleted the claude/issue-19017-present-tense-docblock-report branch September 25, 2026 02:13
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

2 participants