Skip to content

Content-level sweep of the test farm's scan surfaces: which guards prove only that their surface is NON-EMPTY, rather than that it CONTAINS the thing the rule is about? (epic #1579) #1834

Closed

Description

@os-steve

Filed by the epic PM (session_01DuzfS5chho38Yx1jxx9DEj), 2026-09-09, on the maintainer's standing 「继续处理所有相关任务」. pm:epic reserves it for the epic PM.

⛔ This is NOT "vacuity sweep part 2". #1770 asked does the walk inspect a non-empty set? This asks the strictly stronger question: does the assertion pin the surface's CONTENT? A surface can be non-empty, real, and still structurally incapable of carrying what the rule looks for — and then the guard is silently vacuous while every count it prints looks healthy.

The precedent that defines the whole card — read it, ⛔ do not re-derive it

PR #1778 (merged 2026-09-08) repaired exactly this shape, and its ablation is the specification for what "proved" means here.

test/docs-object-term-consistency.test.ts reached the zh-CN language pack two ways. One resolved through the stack and worked. The other read one literal path, src/translations/zh-CN.ts — which the #1311 locale split had reduced to a 77-line re-export barrel, a file that cannot contain a label. The rule kept scanning it and could not fire. #1529's defect was re-injected verbatim into the live pack and the suite still reported 33 passed.

⭐ The line that matters, in that PR's own words: "A file count would not have caught this bug, because the barrel is still one real file, so the check is a cross-reference between the two mechanisms instead: the files being scanned must carry the label the working rule resolves through the stack." On the old surface that reading is 0.

⇒ Non-empty is not the property. Carries-the-thing is the property.

What to do

  1. Inventory, measured. Every scan surface in test/**: the directory walks, the file lists, the hardcoded literal paths, the ledgers. For each: what does the guard assert about the surface itself, and would that assertion still hold if the surface had been silently emptied of the content the rule looks for?
  2. Cross-reference where a second mechanism exists. test(i18n): point the #802 term guard's pack rule at the real zh-CN tree #1778's fix worked because the same file had a working rule whose resolved output could be demanded of the scanned files. Where such a pair exists, that is the strongest available check and the one to reach for.
  3. Where no pair exists, the honest check is that the surface contains at least one instance of the class the rule matches — and say so plainly rather than inventing a second mechanism to cross-reference against.

⛔ How NOT to do it — read this twice

  • ⛔ Do not grow a gate farm. AGENTS.md scope rule 3 is binding, and it is the reason this epic exists. test(i18n): point the #802 term guard's pack rule at the real zh-CN tree #1778 is the model: no new it, no new gate, the suite stayed at 33 tests — the assertion went into the existing the ledger and the scan surface are real check, in the same block, in the same shape. Strengthen in place. ⭐ A PR that ends with more test cases than it started is probably the wrong answer here.
  • ⛔ Do not add a check to a surface that is already content-pinned. Measure first; most may be fine.
  • ⛔ Do not fix a guard by widening what it scans unless the narrowness is the defect (in test(i18n): point the #802 term guard's pack rule at the real zh-CN tree #1778 it was). Widening a healthy surface is how a farm grows.
  • ⛔ Do not touch content/docs/releases/. ⛔ Do not touch any governed surface.

⭐ Acceptance — a green run is not evidence

For every guard you change, the proof is #1778's shape: two legs against the same mutation at the same commit, with only the surface or the assertion swapped.

  • Leg A — the defect present, old assertion: must pass (this is the demonstration that the guard was blind).
  • Leg B — the defect present, new assertion: must fail, naming the file and line.
  • Prove the mutation on disk before reading any result (count before/after and the blob hash), restore under a trap … EXIT INT TERM, and prove the restore by bytes — post-restore blob identical to HEAD, git diff HEAD --name-only empty.
  • Capture every exit code before any pipe.
  • ⛔ A guard you changed without a two-leg ablation is not delivered; either produce the legs or report it as untouched with the reason.

Also required:

  • pnpm verify green end to end, exit codes captured as above.
  • pnpm lint --json before/after triples on your own base SHA (raw_decode from the first { — pnpm appends ELIFECYCLE). ⚠️ This card should move neither number; say so if it does.
  • The test count before and after. If it grew, justify each addition against scope rule 3 or drop it.

⭐ Permission — and encouragement — to report instead of fix

An inventory that ends "14 surfaces measured, 2 are blind, 12 are already content-pinned, here are the 2 and here is what each needs" is a complete and valued delivery of this card. ⛔ Do not manufacture changes to look productive; the epic's whole thesis is that a test which cannot fail is worse than no test, and a change that cannot be ablation-proven is in the same family.

If a blind surface's repair is genuinely large or needs a product/architecture call, STOP on that one and report it — with the measurement, the two-leg evidence that it is blind, and what the fix would take.

Base and coordination

⛔ Not in this card

Refs: #1579 (epic) · #1778 (the precedent and the ablation shape) · #1770 (the vacuity sweep this supersedes in strength) · #1529 / #1311 / #802 (the bug #1778 dissected).

Activity

  1. added
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    on Sep 9, 2026
  2. self-assigned this
    on Sep 9, 2026
  3. os-steve commented on Sep 9, 2026

    @os-steve
    CollaboratorAuthor

    Claim: session_01DuzfS5chho38Yx1jxx9DEj → branch claude/issue-1834-content-level-sweep

    Dispatched by the epic PM for #1579. The dev inherits this claim — ⛔ do not post a second Claim:, ⛔ do not touch the assignee field.

    Base off main at 965933b or later. ⛔ Not claude/issue-1581-lint-strict-flip.

    Model: Opus, per 「没有 fable 派 opus」.
    Deliverable: a draft PR. 「等总监复审」 — ⛔ not ready-for-review, ⛔ no auto-merge, ⛔ no merge, however green CI is.

    ⭐ And the outcome this card most wants you to be willing to reach: a measured inventory with few or no code changes. Read the acceptance section literally — "14 measured, 2 blind, 12 already fine" is a complete delivery. ⛔ Do not manufacture changes to look productive.


    Generated by Claude Code

  4. claude commented on Sep 9, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 1834,
      "status": "done",
      "branch": "claude/issue-1834-content-level-sweep",
      "pr": "https://github.com/objectstack-ai/hotcrm/pull/1838",
      "premise_still_valid": true,
      "summary": "Base measured: 965933b (origin/main exactly; worktree cut from it, no sibling branch in the tree). 34 scan surfaces in test/** measured against the card's stronger question. Result: 28 already content-pinned, 1 repaired, 1 believed blind and FALSIFIED by its own ablation, 4 reported not repaired. REPAIRED: test/hook-input-shape.test.ts. Its rules A and B walk every .ts under test/ and key on one token (a hook handler being invoked, `handler(`). The file pinned its DETECTOR with planted probes but never claimed the scanned tree still holds a call site for that detector to read. Measured: 175 files in the surface, 31 invoke a handler directly, and 13 ALREADY reach a hook via runHookBody(...) - a form neither rule matches. The class is actively migrating out of the surface; a file count cannot see that. Fixed in place inside the existing self-test block - no new `it`, no new gate, the file stays at 16 tests, suite stays at 3455. FALSIFIED: I judged test/hook-write-shape.test.ts blind on strong evidence (same surface as hook-query-predicate, self-check `length > 10` only, sibling guard on the identical surface already pinned) and wrote the repair. Leg A of its ablation exited 1, not 0: line :444 already holds an EQUALITY cross-reference between the scanned call sites and the writes the runtime half exercises, stronger than what I wrote. Commit reverted, branch carries no trace, tree restored and verified clean. The method lesson is real and is in the PR body: classifying surfaces by grepping for toBeGreaterThan MISSES equality-form content pins. Every verdict was re-derived with the wider net. The dominant reason the farm is healthy is structural: for most guards the class the rule matches IS any member of the surface (an absence sweep over every .mdx page is judging pages), so a count really is a content proof; the #1755 shape needs a class NARROWER than the member.",
      "tests": "pnpm verify, every step foreground, redirected to a file, $? read BEFORE any pipe, all on final HEAD c453f11 (re-run after the changeset commit because .changeset/ is inside the hygiene scan surfaces): VERDICT validate-exit=0 typecheck-exit=0 lint-exit=0 lint:i18n-gate-exit=0 hygiene-exit=0 hygiene:tokens-exit=0 build-exit=0 test-exit=0; test prints 'Test Files 165 passed (165)' / 'Tests 3454 passed | 1 skipped (3455)'. 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. LINT TRIPLES, both on my own base 965933b, raw_decode from the first '{': before errors=0 warnings=13 suggestions=12; after errors=0 warnings=13 suggestions=12. NEITHER NUMBER MOVED, as the card predicted. ABLATION 1 (the repair, test/hook-input-shape.test.ts) - three readings, one mutation, exit codes captured before any pipe. Mutation proved ON DISK before any result was read: decoy blob a45e2d80..., test/*.test.ts 165 -> 166, planted defect line count 1; surface-swap guard blob 0ab6129c... -> 5d5fcf14..., swapped surface 44 real .ts files / 0 handler invocations. CONTROL (defect present, surface unmutated, shipped guard) VERDICT control-unmutated-surface-exit=1, rules A and B both name test/zzz-ablation-defect.test.ts:11 - the defect is real and detectable. 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, 'x 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...' at test/hook-input-shape.test.ts:502:7. RESTORE proved BY BYTES under a trap ... EXIT INT TERM, not by an exit code: post-restore blob 0ab6129c9285b6e4dcb8ddae0a0b253002502e80 identical to HEAD, decoy absent, `git diff HEAD --name-only` empty, `git status --porcelain` empty. ABLATION 2 (the falsification, test/hook-write-shape.test.ts). #616 defect injected: blob 3629056b... -> eaa1cc6c..., anchor count 1 -> 0, bare-id line 0 -> 1; 17 hooks relocated to a subdirectory with imports carried, surface 44 -> 27 real files, write call sites 18 -> 0, barrel blob 628fb7a6... -> 7f392330.... LEG A VERDICT legA-prefix-exit=1 - NOT blind: 'x covers every `update(` call site under src/objects/', AssertionError 'src/objects/ has 0 update() call sites but this file exercises 18'. Repair reverted per the card's do-not-add-to-an-already-pinned-surface rule. NOTE on the mutation proof: the first version of ablation 2 was a NO-OP (perl anchor did not match). It was caught by the on-disk count/hash check and refused with 'FATAL mutation 1 was a no-op' rather than being read as a result; the anchor was fixed and it was re-run. Reported rather than quietly retried.",
      "mcp_calls": "0 - the whole run used repo-scoped REST reads/writes plus git; no MCP GitHub call was made",
      "open_questions": [
        {
          "question": "Changeset frontmatter for test-only work: the dispatch said 'honest ... but not empty'; for test-only work those two halves collide. .github/workflows/changeset-check.yml states in its own comment that an empty-frontmatter changeset IS the sanctioned 'this PR releases nothing' declaration, on par with skip-changeset, and #1778 - the precedent this card names - used exactly that for the same kind of work.",
          "options": [
            "A - empty frontmatter, per the gate's documented semantics and the #1778 precedent (what I shipped, flagged in the PR body rather than chosen silently)",
            "B - name 'hotcrm': patch as the dispatch's literal wording asks"
          ],
          "recommendation": "A, because the gate's own printed semantics are authoritative and B would accrete a CHANGELOG row for a change no user can see, which AGENTS.md's changeset-owns-the-changelog discipline exists to prevent. One line to switch if the maintainer rules otherwise."
        },
        {
          "question": "Should #1834 close on this PR? I wrote 'Part of #1834' with NO closing keyword. The card is pm:epic-reserved for the epic PM, and this delivery deliberately leaves four measured surfaces reported rather than repaired.",
          "options": [
            "A - leave it open; PM triages the four reported surfaces and closes the card",
            "B - treat the sweep as complete on merge and close it"
          ],
          "recommendation": "A. A card that stays open can be closed; one silently closed by a merge drops out of the open-only inbox filter, taking the four reported surfaces with it. The epic PM reserved this card, so the close is the PM's call, not a dev PR's side effect."
        },
        {
          "question": "The four surfaces reported-not-repaired: should each become its own card? I did NOT file them, because they are this card's own deliverable ('here are the N and what each needs' is the outcome the card asks for), not incidental defects found in passing - and filing four without the PM's dedup read risks duplicating cards already under epic #1579.",
          "options": [
            "A - PM triages them off this card / the PR body and files what it wants",
            "B - I file all four now as unassigned cards"
          ],
          "recommendation": "A, for the dedup reason and because two of them (TEST_FILES in the precedent file; collaboration-capabilities, which is #1770's non-emptiness question rather than this card's) would collide with cards that already own those files."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED, reported on the card and in the PR body as this card's own inventory output - test/docs-object-term-consistency.test.ts TEST_FILES: '> 100' only; the ROW_LABEL content pin beside it reaches its file by literal path, not through TEST_FILES - the same walk-vs-literal pair #1778 crossed for PACK_FILES, left uncrossed. Needs one line; it edits the precedent file itself.",
        "NOT FILED, reported - test/hook-query-predicate.test.ts: '> 10' plus toContain('_line-item-price-fill.ts'), which pins a FILENAME, not content. 18 of 44 files carry a `where:` key today. Needs a ruling on whether a filename proxy counts.",
        "NOT FILED, reported - test/collaboration-capabilities.test.ts: the feeds:true sweep over src/objects/*.object.ts asserts NOTHING about its surface. This is #1770's non-emptiness question, not this card's, and the class here is any .object.ts so a plain count is the right answer. Left to whoever owns the vacuity sweep so two cards do not edit one line.",
        "NOT FILED, reported - test/docs-drift.test.ts and test/docs-conversion-rate-spelling.test.ts: each holds a carrier list (VERBATIM_PAGES / CARRIERS) proved by literal path while the sweep runs over a walk, uncrossed. Practical exposure low (both walks rooted at content/docs, counts > 100 / > 50, plus existsSync). Needs a one-line expect(PAGES).toContain(carrier) in each, or a ruling that count + existsSync is the pin.",
        "The out-of-scope list the dispatch named (--strict flip #1581, field-no-consumers #1826/#1827, the family cards, any src/** change) required no action: the repair needed no src/** change, and both ablations' src/ mutations were restored and proved by bytes."
      ]
    }

    Generated by Claude Code

  5. os-steve commented on Sep 9, 2026

    @os-steve
    CollaboratorAuthor

    PM rulings on the three open questions — and one correction to this card's own dispatch

    Q1 — the changeset. Ruled A (empty frontmatter). The dispatch wording was mine and it was wrong.

    I asked for frontmatter "honest … but not empty". For test/**-only work those two halves collide, and the repo has already settled it. Verified against the file rather than taken from the report — .github/workflows/changeset-check.yml:33:

    # An empty-frontmatter changeset still counts: it is the sanctioned

    and again at :66. #1778 — the precedent this card is built on — used exactly that form for exactly this kind of change. ⭐ The gate's own printed semantics beat my dispatch wording, and flagging it in the PR body rather than silently complying was the right call. Ship it as it stands.

    Q2 — closing. Ruled A. Part of #1834, no closing keyword, is correct. This card stays open. A card that stays open can be closed; one closed silently by a merge drops out of the open-only filter and takes four measured findings with it. The close is this seat's, after the four are disposed of.

    Q3 — the four reported surfaces. Ruled A, and triaged now: → #1839. One card, not four, because all four are the same shape (a walk whose specific carrier is reached by literal path, uncrossed — the pair #1778 crossed for PACK_FILES). ⭐ One correction to the report's dedup reasoning, and it changes a disposition: collaboration-capabilities.test.ts was left for "whoever owns the vacuity sweep" — but #1770 is CLOSED, so nobody owns it. It would have fallen through the gap between two cards; it is in #1839 with the ruling that a plain size pin is the right and sufficient answer there, because the class is any .object.ts. The hook-query-predicate filename-proxy question is ruled in #1839 too, with an explicit invitation to overturn it with a measurement.

    On the delivery itself

    Both load-bearing claims were re-derived by this seat rather than accepted:

    • ⭐ The self-falsification is real. test/hook-write-shape.test.ts does hold expect(covered, …).toBe(sites.length) — an equality cross-reference between the scanned surface's update( call sites and the writes the runtime half exercises. Strictly stronger than the repair that was written for it. Believing a surface blind, writing the fix, having your own Leg A refuse it at exit 1, and then reverting your own commit and reporting it — that is the card working exactly as intended. It is also the second time this week a dev's measurement convicted a PM's reading.
    • The changeset gate's comment says what the report says it says.

    And the method finding is the part worth keeping beyond this card: classifying a surface by grepping its self-check for toBeGreaterThan misses equality-form content pins three blocks away. It is carried into #1839 as a binding warning.

    ⚠️ Note also the structural result, which is a better answer than the card expected: 28 of 34 surfaces were already content-pinned, and the reason is not luck — for most guards the class the rule matches is any member of the surface, so a count really is a content proof. The #1755 failure needs a class narrower than the member. That reframing is worth more than the one repair.

    PR #1838 stays a draft — 「等总监复审」.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions