Skip to content

Commit e7d5124

Browse files
committed
test(spec): 分节注释与用例标题的 pin 计数改由计数断言校验 (#6605)
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
1 parent b127c8b commit e7d5124

1 file changed

Lines changed: 45 additions & 5 deletions

File tree

packages/spec/src/type-alias-convention.pin.test.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,14 @@ import type * as M167 from './ui/view.zod.js';
264264
import type * as M170 from './ui/component.zod.js';
265265

266266
// ---------------------------------------------------------------------------
267-
// 717 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared.
267+
// 823 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared.
268+
//
269+
// That number is machine-checked, not hand-kept. The runtime companion at the
270+
// bottom of this file recomputes the pin count from the source and asserts that
271+
// every sentence stating it — this header and that case's own title — agrees
272+
// (#6605). Before the check existed this line had been left at 717 while the
273+
// list grew past 800, because the counting assertion reads the `export type
274+
// Iso...` declarations and never the prose sitting beside them.
268275
// ---------------------------------------------------------------------------
269276

270277
// ai/agent.zod.ts
@@ -1604,10 +1611,13 @@ export type AFamilyParsedIsParseState = Assert<
16041611
// ---------------------------------------------------------------------------
16051612

16061613
describe('ADR-0122 type-alias convention', () => {
1607-
// The title tracks the assertion below; it had been left at 751 when #6037
1608-
// moved the count to 754, so it is corrected here rather than left two
1609-
// numbers behind.
1610-
it('still declares all 755 isomorphic pins', () => {
1614+
// The title states the count as well, and hand-tracking it did not hold: it
1615+
// was corrected once, from 751 to 754 (#6037), and had drifted again to sit
1616+
// 68 behind by the time #6605 looked. Both prose statements of the number —
1617+
// this title and the section header above the pin list — are now asserted
1618+
// against the recomputed count below, so neither can go stale without a red
1619+
// test naming it.
1620+
it('still declares all 823 isomorphic pins', () => {
16111621
// The truth of each pin is proved by tsc, not here — an `Assert<Eq<...>>`
16121622
// that stops holding is a compile error with the alias named. What tsc
16131623
// cannot notice is a pin that was DELETED: removing the assertion removes
@@ -1746,6 +1756,36 @@ describe('ADR-0122 type-alias convention', () => {
17461756
const self = readFileSync(fileURLToPath(import.meta.url), 'utf8');
17471757
const pins = self.match(/^export type Iso\d+ = Assert</gm) ?? [];
17481758
expect(pins).toHaveLength(823);
1759+
1760+
// The count is stated in PROSE twice as well — this case's title and the
1761+
// section header above the pin list — and until #6605 nothing read either
1762+
// one. Both had drifted, by different amounts: the header sat 106 behind,
1763+
// the title 68. Correcting them is not the fix, because correcting was
1764+
// already tried on the title once (the receipt at the top of this case)
1765+
// and it drifted a second time. So the prose is recomputed against the
1766+
// same operand as the assertion above: the file.
1767+
//
1768+
// Matched by PHRASE, deliberately, rather than at two fixed line numbers.
1769+
// A sentence a later author writes is then covered the moment it is
1770+
// written — the property a merely-corrected literal does not have, and the
1771+
// reason this is preferred over deleting the numbers outright: a number
1772+
// nobody may state cannot be re-stated wrongly, but a number anybody may
1773+
// state and nobody may state falsely is worth more, and it is the bargain
1774+
// the pins themselves are built on ("an exemption nobody can state falsely
1775+
// is the only kind worth having", top of this file).
1776+
//
1777+
// Everything else above is HISTORY — `749 -> 822`, `-7`,
1778+
// `136 - 17 - 40 - 5 - 1` — and is deliberately NOT matched. Those numbers
1779+
// are true about a past state of the file, and rewriting them to today's
1780+
// count would destroy the receipts. The phrase caught here is the narrow
1781+
// one that can only ever mean "how many pins are in this file right now".
1782+
const stated = [...self.matchAll(/(\d+) isomorphic \w+/g)].map((m) => m[0]);
1783+
// Guard the guard: if a reword leaves nothing matching, the check below
1784+
// passes over an empty list and silently stops existing.
1785+
const phrasingMoved = 'no prose states the pin count any more — has the phrasing moved?';
1786+
expect(stated.length, phrasingMoved).toBeGreaterThanOrEqual(2);
1787+
const wrong = stated.filter((s) => !s.startsWith(`${pins.length} `));
1788+
expect(wrong, `prose disagreeing with the ${pins.length} pins counted above`).toEqual([]);
17491789
});
17501790

17511791
it('leaves the A-family parse behaviour untouched', () => {

0 commit comments

Comments
 (0)