Skip to content

test(scan-surfaces): content-level sweep of the test farm, and pin the ctx-shape surface to its call sites - #1838

Merged
os-steve merged 2 commits into
mainfrom
claude/issue-1834-content-level-sweep
Sep 9, 2026
Merged

os-steve merged 2 commits into
mainfrom
claude/issue-1834-content-level-sweep

Conversation

@claude

@claude claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Part of #1834 (epic #1579). ⛔ No closing keyword is placed on it: this PR delivers
the sweep and one repair, and deliberately leaves four measured surfaces reported
rather than repaired. #1834 stays open for the epic PM to triage those four and
decide whether the card is done. #1755, #1778, #1770, #1529, #1311, #802, #1133,
#616 and #1581 are named below for provenance only; none of them is addressed here.

What this card asked, and what the tree answered

Not #1770's question ("does the walk inspect a non-empty set?") but the stronger
one: does the assertion pin that the surface still CARRIES the class the rule
matches?

34 scan surfaces measured. 1 repaired. 1 believed blind and falsified by its own
ablation. 4 reported, not repaired. 28 already content-pinned.

The farm is in better shape than the card's worst case. The dominant reason is
structural rather than lucky: for most of these guards the class the rule matches
is any member of the surface — an absence sweep over "every .mdx page under
content/docs" is judging pages, so a page count really is a content proof. The
#1755 shape needs a narrower class than the surface: the barrel was one real
file that could not carry a label. So the sweep's discriminator was, per surface:
is the class a proper sub-kind of the member? — and only then, is that sub-kind
pinned?

⚠️ The measurement method has a false-negative mode, and it fired on me

My first pass classified surfaces by grepping their self-checks for
toBeGreaterThan / toHaveLength. That misses equality-form content pins, and
it produced one wrong verdict which the ablation caught before it shipped. It is
recorded here because it is a finding about how to run this sweep, not a detour:
a guard that reads count-only at its own vacuity block can be content-pinned by a
rule three blocks away. Every verdict below was re-derived with the wider net.

The inventory

Verdicts: pinned (any-member) — the class is any member of the surface, so the
size assertion is a content proof. pinned (sub-kind) — the class is narrower
and the file carries an explicit pin for it. detector-pinned — plus positive
probes proving the matcher still reads the spellings. reported — a real gap,
below.

# surface (owner) what the guard asserts about the surface itself verdict
1 PACK_FILES (docs-object-term-consistency) files scanned must carry the label the working rule resolves through the stack pinned (sub-kind) — #1778
2 HANS_PAGES / HANT_PAGES (same) > 50, plus carrying(HANS_PAGES, hans) >= term.minPages in the surviving terms are actually there pinned (sub-kind)
3 TEST_FILES (same) > 100 only; the ROW_LABEL content pin beside it reads one literal path reported — uncrossed pair
4 sources (hook-input-shape) nothing — detector probes on planted text only REPAIRED
5 hookFiles() (hook-write-shape) > 10 and covers every update( call site — equality against the writes the runtime half exercises pinned (sub-kind) — falsified my blind verdict
6 hookFiles (hook-query-predicate) > 10 and toContain('_line-item-price-fill.ts') reported — filename proxy, not content
7 readdirSync(OBJECT_DIR) (collaboration-capabilities) nothing at all reported — no self-assertion
8 PAGES + VERBATIM_PAGES (docs-drift) > 100; the six carrier pages are proved by existsSync, not through the walk reported — uncrossed pair
9 pages + CARRIERS (docs-conversion-rate-spelling) > 50; carriers read by literal path, not through the walk reported — uncrossed pair
10 LEAVES / NAV (app-navigation-shape) > 20 and it.each(REQUIRED_KINDS) — one exemplar of each kind must survive pinned (sub-kind)
11 FILES / DOC_PAGES (docs-zh-hant-justification) > 400 / > 100 and conventionBlocks >= MIN_CONVENTION_BLOCKS pinned (sub-kind)
12 PAGES (docs-retired-personas) > 50, plus a 7-probe detector test, plus every HISTORICAL exemption must still name a persona in the live tree detector-pinned
13 STRINGS (persona-copy) > 5000 strings off the resolved stack, plus positive probes detector-pinned
14 PAGES (docs-role-hierarchy) > 50, a 15-probe detector test, plus every exemption still covers a real occurrence detector-pinned
15 files (lead-duplicate-management) > 50 and exactly 2 occurrences, in two named files, one of them a stamp pinned (sub-kind)
16 allSites (verify-log-decoy-pin) >= the known gate-spawning files, named — the scanner is not vacuous pinned (sub-kind)
17 SCRIPTS (script-main-guard) >= 8, and each script must print something pinned (sub-kind)
18 predicates (view-predicate-dialect) >= authored — finds a predicate for every one authored in src/views pinned (sub-kind)
19 rules / globs (labeler-config) > 0 rules, > 0 globs each, and every glob matches ≥1 real file pinned (sub-kind)
20 objectSources (line-item-conventions) > 10 and formulaNames > 0 pinned (sub-kind)
21 hookNames / flowNames (runtime-coverage) >= 20 each, off the resolved stack pinned (sub-kind)
22 references (hot-lead-threshold-parity) registered > 0 and references > 0 in src/views pinned (sub-kind)
23 mounters (sharing-posture-declaration) > 0, and posture must precede the mount in every member pinned (sub-kind)
24 recordChangeFlows (actions-flows-integrity) >= 9 — the filter still matches pinned (sub-kind)
25 constants module (deal-threshold-parity) the sweep can actually see the constants module — anti-vacuity pinned (sub-kind)
26 dashboards + 磁-family words (docs-dashboard-tiles) five separate "has gone vacuous" pins, per locale and per pair pinned (sub-kind)
27 claims (docs-metadata-counts) the scan finds a claim of every kind it guards pinned (sub-kind)
28 page pairs + callouts (docs-locale-callouts) > 50 pairs and > 5 callouts to compare pinned (sub-kind)
29 agent: values (docs-runnable-samples) > 0 values found in a fence or script pinned (sub-kind)
30 INSTRUCTIONS_DIR + doc pages (docs-src-tree-paths) per-page: names no src/<dir>/ at all — this guard has gone vacuous over it pinned (sub-kind)
31 name cells / label sets (docs-view-rosters) four pins, each > 40 resolved cells or labels pinned (sub-kind)
32 nav + app labels (docs-setup-navigation-names) the roster this file judges against is real — six size pins on resolved rosters pinned (sub-kind)
33 nav nodes / views / src text / console bundles (docs-revenue-approvals-navigation) four pins incl. bundles > 5 and bundle text > 1,000,000 pinned (sub-kind)
34 anchoredLinks (docs-anchor-links via helpers/docs-anchors) > 20 anchored links, not pages pinned (sub-kind)

Any-member surfaces where the count is the content proof, and correctly so:
ALL_PAGES (docs-analytics-vocabulary, > 100), walk(dir) per collection
(docs-app-workflow-paths, > 0 plus content/docs and content/blog named).

The 11 hardcoded literal single-path reads (package.json, README.md,
CHANGELOG.md, src/objects/_thresholds.ts, src/objects/lead.hook.ts,
src/objects/account.hook.ts, src/dashboards/executive.dashboard.ts,
src/data/service.seed.ts, content/docs/guides/importing-your-data.mdx) cannot
go silently vacuous the way the #1755 barrel did — readFileSync throws on a
missing path — and the two that could go quiet by CONTENT
(deal-threshold-parity, hot-lead-threshold-parity) each carry an explicit
anti-vacuity pin already.

The one repair — test/hook-input-shape.test.ts

Rules A and B walk every .ts under test/ and key on one token: a hook handler
being invoked, handler(. The file already guards its detector with
planted probes. Nothing in it claimed the scanned tree still holds a call site for
that detector to read — and a file count could not have claimed it: 175 real files
stay 175 real files whichever way they invoke a hook.

Measured on this branch's base 965933b:

reading value
files in the surface (test/**/*.ts) 175
files that invoke a handler directly (handler() 31
files already reaching a hook via runHookBody(...) — a form neither rule matches 13

The class these rules discriminate within is actively migrating out of the
surface
. That is the whole exposure: finish the migration and both rules report
clean over a real, non-empty tree carrying nothing they can judge.

The repair is the card's option 3 — no second mechanism to cross-reference here,
so the honest check is that the surface holds at least one instance of the class,
said plainly. It went into the existing self-test block: no new it, no new
gate, the file stays at 16 tests. CALLS_HANDLER is single-sourced so rule B
and the surface check cannot come to discriminate different classes.

The ablation — three readings, one mutation, exit codes captured before any pipe

A hand-built plain-object ctx (the #1133 defect) planted in the tree, proved on
disk before any result was read — decoy blob a45e2d80…, test/*.test.ts
165 → 166, planted defect line count 1.

CONTROL  defect present, surface UNMUTATED, shipped guard
         VERDICT control-unmutated-surface-exit=1
         × A · no hook handler is called with an object literal
         × B · a file that calls a hook handler builds its ctx with the shared harness
             + "test/zzz-ablation-defect.test.ts:11"        ← the defect IS real and detectable

MUTATION surface swapped to a real, non-empty, class-free tree
         guard blob 0ab6129c… → 5d5fcf14…   (a no-op mutation is refused, and was, once)
         swapped surface: 44 real .ts files; files invoking a hook handler = 0

LEG A    same mutation, OLD assertion (HEAD~1)      VERDICT legA-prefix-exit=0
         Test Files 1 passed (1)   Tests 16 passed (16)     ← the defect is MISSED

LEG B    same mutation, NEW assertion (HEAD)        VERDICT legB-repaired-exit=1
         × the guard reports the shape it is meant to report (self-test)
         AssertionError: no file in the scanned tree invokes a hook handler at all,
         so rules A and B are reading past every hook invocation in the repo …
           ❯ test/hook-input-shape.test.ts:502:7

Restored under a trap … EXIT INT TERM and proved by bytes, not by an exit
code: post-restore blob 0ab6129c9285b6e4dcb8ddae0a0b253002502e80, identical to
HEAD; decoy absent; git diff HEAD --name-only empty; git status --porcelain
empty.

The verdict I got wrong, and the ablation that caught it

test/hook-write-shape.test.ts looked like the textbook case, on evidence one
step stronger than a hunch: same surface as hook-query-predicate
(readdirSync('src/objects').filter('.ts')), self-check length > 10, and the
sibling guard on that identical surface already carries a surface pin while this
one appeared not to. The asymmetry read as the defect.

Measured, it is real: 44 files, of which 27 are *.object.ts schemas and shared
modules that never call the facade; all 18 write call sites are in the 17
*.hook.ts files; readdirSync does not recurse, so relocating the hooks to a
subdirectory leaves 27 real files and 0 write call sites.

The ablation refused it. With the #616 defect injected (blob 3629056b… →
eaa1cc6c…, anchor count 1 → 0, bare-id line 0 → 1) and the 17 hooks relocated
with their imports carried:

LEG A  defect present, OLD assertion   VERDICT legA-prefix-exit=1     ← NOT blind
       × covers every `update(` call site under src/objects/
       AssertionError: src/objects/ has 0 update() call sites but this file exercises 18.

hook-write-shape.test.ts:444 already holds an equality cross-reference
between the scanned surface's call-site count and the writes its runtime half
exercises — strictly stronger than what I had written. Per the card
(⛔ do not add a check to a surface that is already content-pinned) the commit
was reverted; this branch contains no trace of it. The surface was restored by
bytes and git status verified clean before proceeding.

Reported, not repaired — four surfaces, and what each needs

⛔ None of these is repaired here: three would need a judgement call about how far
a cross-reference should reach, and one is #1770's question rather than this
card's. Filing them rather than fixing them is the card's own instruction.

  1. TEST_FILES in docs-object-term-consistency.test.ts — the retired-spelling
    sweep over the test ledgers. > 100 only. The block beside it does pin
    content (scannable('test/sharing-coverage.test.ts') must contain ROW_LABEL)
    but reaches it by literal path, not through TEST_FILES — the same
    walk-vs-literal pair test(i18n): point the #802 term guard's pack rule at the real zh-CN tree #1778 crossed for PACK_FILES, left uncrossed here. Needs:
    one line asserting the walk's output contains that ledger file. Low risk, but it
    is an edit to the precedent file itself and belongs in a card that owns it.
  2. hook-query-predicate.test.ts — > 10 plus toContain('_line-item-price-fill.ts').
    That pins a filename, not content: it proves the shared-module family is in
    the surface, not that any file in it issues a query. 18 of 44 files carry a
    where: key today. Needs a decision on whether a filename proxy is deemed
    sufficient; if not, the honest form is the same shape as row 5's equality pin.
  3. collaboration-capabilities.test.ts — the feeds: true sweep over
    src/objects/*.object.ts asserts nothing at all about its surface. This is
    Vacuity sweep of the test farm — which walking assertions actually inspect a non-empty set? (epic #1579, read-only, needs no release) #1770's question (non-emptiness), not this card's, and the class here is any
    .object.ts, so a plain count would be the right and sufficient answer. Left
    for whoever owns the vacuity sweep, to avoid two cards editing one line.
  4. docs-drift and docs-conversion-rate-spelling — both hold a carrier list
    (VERBATIM_PAGES, CARRIERS) proved by literal path while the sweep runs over
    a walk, uncrossed. Practical exposure is low: both walks are rooted at
    content/docs and the count (> 100 / > 50) plus existsSync means the
    carriers cannot silently fall out. Needs: a one-line expect(PAGES).toContain(carrier)
    in each, or an explicit ruling that the count plus existsSync is the pin.

Gates — pnpm verify, exit codes captured before any pipe

Every step run in the foreground, redirected to a file, $? read before any pipe.
All eight on final HEAD c453f11, after the changeset commit (.changeset/ is
inside the hygiene scan surfaces):

step exit
validate · typecheck · lint · lint:i18n-gate 0 · 0 · 0 · 0
hygiene · hygiene:tokens · build 0 · 0 · 0
test — Test Files 165 passed (165), Tests 3454 passed | 1 skipped (3455) 0

Test count: 3455 before, 3455 after — unchanged. No new it, no new gate, no
new file under test/. Nothing to justify against scope rule 3, because nothing
was added.

pnpm lint --json, both on this branch's own base 965933b (raw_decode from
the first {; pnpm appends ELIFECYCLE):

errors warnings suggestions
before 0 13 12
after 0 13 12

Neither number moved, as the card predicted.

Scope

One file of behaviour — test/hook-input-shape.test.ts — plus a changeset. No
src/** change: the repair needed none, and the two ablations' src/ mutations
were restored and proved by bytes. content/docs/releases/ untouched. No governed
surface touched. No surface widened. The --strict flip, field-no-consumers, and
the family cards are out of scope and untouched.

The changeset carries empty frontmatter — the sanctioned "this PR releases
nothing" declaration that .github/workflows/changeset-check.yml documents in its
own comment, and the form #1778 used for the same kind of work. ⚠️ The dispatch
asked for frontmatter that is "honest … but not empty"; for test-only work those
two halves collide, and the gate's documented semantics plus the precedent decide
it. Flagged rather than chosen silently — if the maintainer wants a named package
bump instead, it is a one-line change, but it would accrete a CHANGELOG row for
something no user can see.

维护者速读(草稿)

改了什么 —— 把 test/** 里的扫描面按「内容级」重新量了一遍:不是问「走查到
的集合非空吗」,而是问「断言有没有钉住这个面仍然携带规则要找的那类东西」。
34 个面,28 个本来就已经钉住内容,1 个修了,1 个我判错、被自己的消融推翻,4 个如
实上报不动手。唯一改的是 test/hook-input-shape.test.ts:它的两条规则只认
handler( 这一个调用形态,而仓库里已经有 13 个文件改走 runHookBody(...) —— 那
个形态两条规则都不认。等这轮迁移走完,两条规则会在一棵真实、非空、却什么都不含
的树上报绿。

为什么改 —— 与 #1755 同一失败方向:静默。改动只加一条断言,进的是已存
在
的自检块,没有新 it、没有新门禁,测试数 3455 → 3455 一个没涨。

风险与代价(含回滚) —— 风险低:只动 test/**,src/ 一个字节没动,不向用户
发布任何东西。回滚 = revert 这两个 commit。

⚠️ 我判错的一处,以及它为什么留在这里 —— hook-write-shape.test.ts 我一度认
定是瞎的(证据是:同一个扫描面上的姊妹守卫已经加了面级钉子,它没有),代码也写
了。消融第一腿就把它否掉了:该文件 :444 早就有一条等式交叉引用,比我写的更
强。那个 commit 已经撤掉,分支上不留痕迹。这段写进正文,是因为它是本卡的一个真结
论:一个在自己 vacuity 块里读起来「只数数」的守卫,可能被三个块之外的规则钉住 ——
用 toBeGreaterThan 扫一遍来分类,会漏掉等式形态的内容钉子。

你要做的 —— 三件。① 确认上报不修的那四个面是否要各自立卡(我没动它们,理由
在正文)。② 确认 changeset 的空 frontmatter:门禁注释与 #1778 都是这个形态,但派
发词要求「非空」,我按门禁走并在此点明。③ 本 PR 停在 draft 等你复审 —— 「等总监复
审」。


🤖 Generated with Claude Code

https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj


Generated by Claude Code

`test/hook-input-shape.test.ts` rules A and B walk every `.ts` under `test/`
and key on one token — a hook handler being INVOKED, `handler(`. The file
already guards its detector with planted probes, but nothing in it claimed the
scanned tree still holds a call site for that detector to read.

Measured on this branch's base 965933b: 175 real `.ts` files in the surface, of
which 31 call a handler directly and 13 already reach a hook through
`runHookBody(...)` instead — a form neither rule matches. The class these rules
discriminate within is migrating out of the surface while the surface stays 175
real files, so a file count could not report it. That is #1755's shape one tree
over: a real member that cannot carry the thing keeps the rule green.

Strengthened in place, inside the existing self-test block — no new `it`, no
new gate, the file stays at 16 tests (#1778's shape). The invocation pattern is
single-sourced as `CALLS_HANDLER` so rule B and the surface check cannot come
to discriminate different classes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
Test-only; empty frontmatter is the sanctioned "releases nothing" declaration
the Changeset Check gate documents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Sep 9, 2026 3:24pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants