test(spec): put the pin file's two prose counts under the counting assertion (#6605) - #6689
Conversation
ADR-0122 pin 文件里的计数被一条计数断言盯着,但那条断言读的是 `export type Iso...` 声明,读不到旁边散文里写的同一个数字。于是文件里 两处散文各自漂了:分节注释停在 717、用例标题停在 755,而实测 pin 数 是 823。标题此前已被手工纠正过一次(751 -> 754,#6037),之后又漂了 第二次 —— 说明手工维护不是解法。 改为把散文纳入同一条计数机制:按短语匹配,而不是按固定行号,这样以后 新写的句子在写下的那一刻就已被覆盖。收据块里的历史数字(749 -> 822、 -7、136 - 17 - 40 - 5 - 1)刻意不匹配 —— 它们描述的是文件的过去状态。 另加一条"守卫的守卫":短语一个都匹配不到时直接判红,避免改写措辞后 这条检查静默失效。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
|
Review verdict is already recorded on #6605 (ACCEPT). Ready-flip and auto-merge wait for the dev's final report per this seat's flip precondition. Generated by Claude Code |
|
Correction, on the record — The check-run timestamps settle it:
So the sequence the PR body predicted is exactly what happened, and the PM action it asked for was required. What the note got right is the part that matters for re-runs: the gate reads the PR's live labels rather than the triggering event payload (#5625), so a plain Flipped ready and auto-merge armed: dev report landed and reconciled with the ACCEPT on #6605, head unchanged at Generated by Claude Code |
Fixes #6605
What drifted
packages/spec/src/type-alias-convention.pin.test.tsstates its pin count in threeplaces. One is asserted; two were not, and both had drifted:
:267):1620)expect(pins).toHaveLength(...)The assertion matches
/^export type Iso\d+ = Assertover the file's own source, so itreads the declarations and never the prose sitting beside them — which is exactly
why the other two could rot unwatched.
Re-counted on
origin/main@b127c8b22rather than taken from the card:grep -c '^export type Iso'= 823, andpnpm check:spec-parsed-aliasindependentlyreports
1517 bare z.input aliases, 823 pinned isomorphic, 694 paired with an XParsed.The card's 822 was correct when filed and went stale the same day — #6596 landed
GetMetaItemLayeredResponseSchemaon top of #4593's backfill.One correction to the issue's premise
The issue title calls the header "the only number not covered by a counting assertion".
It is not the only one — the counting case's own title is a second, and it had
drifted 68 behind. The substantive premise holds in full (the header stated 717, the
truth is 823, nothing asserted it); only the word "only" does not.
That second site also settles the design question, because it is a repeat offender:
the receipt above it records that the title was already hand-corrected once, from 751 to
754 (#6037) — and it drifted again anyway. Hand-maintenance has been tried here and
measured to fail.
The fix: extend the counting machinery, not the literals
Level 2 of the ruling, enforcement variant. The case already reads its own source to
count declarations; it now recomputes the prose against that same operand:
Three deliberate properties:
is covered the moment it is written. This is the property the alternative — deleting
the numbers and pointing at the assertion instead — does not have: removal resets the
drift but does nothing about re-introduction, and "N isomorphic aliases" is a very
natural thing for the next author (or agent) to write into a section header. Keeping
the number and making it unfalsifiable is the same bargain the pins themselves are
built on, in this file's own words at the top: "An exemption nobody can state falsely
is the only kind worth having."
with historical arithmetic —
749 -> 822,-7,136 - 17 - 40 - 5 - 1. Those aretrue about past states of the file and rewriting them to today's count would destroy
the receipts. The matched phrase is the narrow one that can only ever mean "how many
pins are in this file right now"; verified to match those two sites and nothing else.
pass over an empty list and the check would silently stop existing — the phantom-check
shape this repo keeps paying for.
toBeGreaterThanOrEqual(2)refuses that.Scope note:
docs/adr/0122-...mdalso carries pin counts (final: 1470 / 754 / 716),left untouched on purpose — that is the phase-2 flip's own dated outcome table, history
in the same sense as the receipts, not drift.
Reverse verification
Direction predicted before running, and both came out as predicted — plain red, no
inversion:
717in the header → the new assertion goes red naming thesentence, while
toHaveLength(823)above it still passes. This is the issue'smechanism, reproduced: the old machinery cannot see this defect.
check cannot pass vacuously.
Verification
pnpm --filter @objectstack/spec exec vitest run— 345 files / 8844 tests passedpnpm --filter @objectstack/spec typecheck— exit 0 (tsc --noEmit,check:scripts-typecheck,check:test-typecheck; the last is where these pins'compile-time proof actually lands, per [finding] ADR-0122 D6 措辞精度:同构 pin 的编译期证明实际落在 check:test-typecheck 一步,不在裸 tsc #6183)
pnpm check:spec-parsed-alias— OK; self-test 18 assertions. This gate reads this fileas its exemption registry, so it is the one that would notice a mangled pin line; the
diff touches only comments, a title string and the case body.
pnpm check:nul-bytes— OK (6237 files); plus a targeted control-byte self-scan of theedited file, clean.
pnpm exec eslint packages/spec/src/type-alias-convention.pin.test.ts— exit 0Changeset
None: the diff is a single
*.test.tsfile, so nothing user-visible is published.skip-changesetis the intended route — flagged here for the PM to apply at acceptancerather than self-applied. Precedent for test-only diffs carrying that label: #6607, #6658,
#6582.
Generated by Claude Code