Skip to content

test(lint): derive the list-view position-coverage criterion from the rule - #18876

Merged
os-bill merged 3 commits into
mainfrom
claude/issue-18836-position-count-floor-overclaims
Sep 18, 2026
Merged

os-bill merged 3 commits into
mainfrom
claude/issue-18836-position-count-floor-overclaims

Conversation

@os-bill

@os-bill os-bill commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #18836

Clause-②: no

The test table's docblock claimed two directions and the assertion under it carried one. This replaces the floor with a criterion derived from the rule's own tables, and makes the docblock true.

The premise, re-measured

Every reading below was taken on this branch's base, origin/main 36583e989b — the dispatch quoted a43b9d0654, this worktree branched later, so the numbers were re-taken rather than inherited. They land in the same place:

  • docblock: packages/lint/src/validate-list-view-field-refs.test.ts:205-210, still word for word a position added to the rule without a row here leaves the count assertion below short
  • the assertion it points at: :315, expect(cases.length).toBeGreaterThanOrEqual(51)
  • cases.length at that commit: 52

Both directions were measured by mutating the rule's POSITIONS table on disk and running the rule's own test file. Each mutation proved itself on disk (anchor count 1 before, 0 after; injected line count 1; blob hash moved) and was restored under a trap, with git diff HEAD proving the restore byte for byte.

direction mutation before this PR after this PR
one — a position dropped from the rule fails here remove tree.labelField 1 failed / 129 passed 2 failed / 129 passed (of 131) — the per-case assertion AND the new sibling assertion
two — a position added to the rule with no row here add tree.ablationProbeField 130 passed, 0 failed 1 failed, covers every position the rule walks, diff names - "tree.ablationProbeField"

Direction two reported nothing at all: cases.length counts the rows of the test table, which a position added to the rule never moves, so the floor stayed true. That is the direction #18565 came in through. After this PR the failing assertion is the completeness one, and its diff names the offender (- "tree.ablationProbeField").

Direction one is unchanged and still carried by the per-case assertions, exactly as the docblock's first half says — the failing test both before and after is views[0].list.tree.labelField reports at warning.

A third reading the card did not claim. The floor did not reliably do even its own advertised job. Deleting one row from the table (tree.labelField) on the base tree left 129 passed, 0 failed — 52 rows against a floor of 51 is exactly one row of slack. The same deletion after this PR is red, and the failing assertion is the completeness one.

Step 1 — does the new export reach a published entry?

@objectstack/lint is not private, files is dist / README.md / CHANGELOG.md, and exports has . and ./runtime — so src/ does not ship but dist/ does. Re-measured on this base and it holds. Two facts about the barrels: src/index.ts re-exports this module by NAME (there is no export * in either barrel, count 0), and src/runtime.ts does not reference the module at all.

Readings after pnpm --filter @objectstack/lint build, grepping dist/. Bright control throughout: validateListViewFieldRefs, a symbol known to ship.

Shape measured first — export const X = Object.freeze([...]):

dist/ file new symbol bright control
index.js 1 3
index.cjs 1 4
runtime.js 1 2
runtime.cjs 1 2
index.d.ts 0 2
index.d.cts 0 2
runtime.d.ts / runtime.d.cts 0 0
runtime-DAPAkqcs.d.ts / .d.cts 0 not present

A raw count in a bundle body is not a published entry, so the export layer was measured separately. In dist/index.js's export {} clause: new symbol 0, against 1 each for validateListViewFieldRefs, LIST_VIEW_FIELD_DOTTED and LIST_VIEW_FIELD_UNKNOWN. In dist/index.cjs's __export map: new symbol 0, controls 1 each. Dark control for that layer: COLUMN_ENTRY_POSITIONS, a module const the rule has never exported, reads 2 in index.js and 2 in index.cjs — a name in the bundle body is genuinely no evidence of a published entry.

Under this shape four dist JS files moved bytes (esbuild keeps a frozen initializer as dead weight); all four .d.ts / .d.cts files were byte-identical.

Shape shipped — export function listViewWalkedPositions(): the symbol is tree-shaken. 0 occurrences in all eight published files, while the bright control still reads 3 / 4 / 2 with the same instrument on the same files.

⚠️ Corrected by the dispatching seat after the contract review, ⛔ not by the author. This paragraph first read 「all nine dist/ artifacts byte-identical … 9 of 9 OK」. The measured face is 14 artifacts, of which 10 are byte-identical — the 4 JS bundles and all 6 type files — and 4 source maps moved (index.js.map, index.cjs.map, runtime.js.map, runtime.cjs.map; files[] ships dist whole, so they are published). Their differing keys are mappings and names only, sources are equal, and the new symbol is absent from names in all four ⇒ a line offset, ⛔ not a surface. The original count hashed 9 files and omitted the 4 maps and one runtime-*.d.cts. Measured twice independently: by the at-tier contract review (record 5724912914) and again by the author in its rework report. The reading the paragraph rests on is unchanged; only the count was wrong.

Reading: the new export reaches no published entry and moves zero bytes of the published artifact. Per the dispatch's step-2 table, that is route A, and route A is what this PR implements.

On the declaration line above

Clause-②: yes (widening) was the dispatch's mechanical floor, declared before this measurement existed and routed for the seat's contract review. The at-tier review (record 5724912914) overturned it to no, with no direction arm — the diff widens no accept set and expands no public surface. Per references/lanes/spec.md:20 a conservative yes is never an error, so the overturn is by design and is ⛔ not a fault of the author.

⚠️ Rewritten by the dispatching seat, ⛔ not by the author — the charter gives the author exactly one body write and routes later corrections through the seat. The changeset that graded this minor has been deleted by the author in the rework, and the PR carries skip-changeset instead: measured, the fixed group of about 70 packages would otherwise all move to 17.5.0 for a change that delivers 0 changed code or type bytes to any consumer.

What changed

validate-list-view-field-refs.ts gains one module-level export, listViewWalkedPositions(), which derives the block.key id of every field-naming position from the rule's own POSITIONS and COLUMN_ENTRY_POSITIONS tables. 52 positions today. No POSITIONS row is touched — not a position, not a tier, not a severity — and the barrel is untouched.

validate-list-view-field-refs.test.ts: the floor becomes set equality between the positions the rule walks and the positions this file's two case tables assert. The five-row measured table moves to module scope because three positions (grouping.fields, kanban.groupByField, gantt.startDateField) are asserted there and nowhere else; a criterion reading only the sibling table would need a hand-written exemption for them, which is the kind of constant this card is about. The per-case assertion bodies are unchanged, byte for byte.

Why set equality and not the count equality route A suggested

Route A said: derive the count from POSITIONS and compare it to cases.length. That equality cannot be written without magic constants, because rows are not positions:

  • 52 rows in the second table and 52 positions walked — the same number over different sets, by coincidence.
  • 3 positions are asserted only in the sibling five-row table.
  • 2 rows in the second table (and 1 in the first) assert the rule's hard-coded filter walks, which no table declares.
  • 2 positions carry two rows each (columns and gantt.tooltipFields: once as a bare name, once as a record with a field key), so the second table holds 1 duplicate row.

The arithmetic a count equality would have had to hard-code is 52 = 52 - 3 + 2 + 1. Set equality states the property directly instead, names the offending position in the failure diff, and needs no constant at all. Per the dispatch's own zoning this is the suggested-route zone, so it is reported rather than silently taken: the ruling (measurement decides A vs B) is executed as written.

What the new assertion does NOT carry, stated in the code so it cannot become the next overclaim: it is one-directional. positionAsserted answers only with positions the rule currently walks, so a row for a position the rule has dropped contributes to neither side and the assertion stays green — that direction belongs to the per-case assertions, and both halves are measured above. A first draft of the comment claimed both directions; the direction-one probe showed only the per-case assertion firing, and the comment was corrected before the first push rather than shipped.

docblock, sentence by sentence

original now true? held by what
Every remaining position, with the severity tier it earns. unchanged yes the per-case rows, each asserting one path and one severity
The table is the readable half of the rule's own POSITIONS table unchanged yes, and now mechanically so the completeness assertion reads the rule's tables directly
a position dropped from the rule fails here unchanged yes the per-case assertions — measured red before and after
a position added to the rule without a row here leaves the count assertion below short a position added to the rule without a row in either table fails the completeness assertion below — which derives the set of positions from the rule's own tables instead of counting this one's rows yes the new set-equality assertion — measured green before, red after

The inline comment above the assertion

The dispatch fenced it as accurate and not to be rewritten as if it were the defect. It is not rewritten as a finding — it is replaced because the assertion it annotates no longer exists, and the dispatch also forbids leaving a floor and an equality side by side. Its semantics were right; the one-row slack measured above is reported as a reading, not fixed as a second thing.

Verification

Run through the shared verify lock. Package: @objectstack/lint.

check before after
pnpm --filter @objectstack/lint test 104 files / 3909 tests passed 104 files / 3910 tests passed (the delta is the one new it)
pnpm --filter @objectstack/lint typecheck — exit 0 (tsc --noEmit plus check:test-typecheck: 2 files / 6 errors / 2 pinned signatures held)
pnpm lint (repo-wide, eslint . --no-inline-config) — exit 0
control-character self-scan over the three touched files — no match

Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 51 families from this tree at 9897eaae29 (58 at the previous head; the 7 that left are the changeset families, since the changeset was deleted); all 51 were run and each exit code recorded before any pipe, then reconciled with --ran. 48 green, 3 NOT MEASURED — check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt each exited 3, PREREQUISITE NOT MET: all three read built output across the whole repo, which this worktree does not have. They are neither a pass nor a failure here, and CI builds fresh and runs them. The dist byte-identity measured above is why this diff cannot move their verdict.

Dependency-closure build: pnpm --filter '@objectstack/lint^...' build, exit 0.

Acceptance notes

  • Nothing outside this card's scope was changed. The POSITIONS table, the package barrel and the per-case assertion bodies are untouched; the only positions-table edits in this branch were the two ablation mutations, each restored and proven restored.
  • Noted, not filed: the replaced floor had exactly one row of slack (52 rows against 51), so a single silent row deletion passed it. It is fixed here as a consequence of replacing the assertion, so there is no separate card; the reading is above. Carrier: this PR.
  • Noted, not filed: dist/runtime.js bundles validateListViewFieldRefs although dist/runtime.d.ts exports it nowhere. That is the documented consequence of splitting: false in packages/lint/tsup.config.ts, whose own header carries the measurement, not a defect. Carrier: none.

⚠️ Five cells refreshed by the dispatching seat at the reworked head, ⛔ not by the author. They described head 270d9f4b35; this PR is now at 9897eaae29. Refreshed: the direction-one "after" cell (the rework made that direction fail TWICE — the per-case assertion and the new sibling assertion — where it previously failed once), the direction-two "after" cell (now quoted by the failing assertion's own name and diff), the one-row-slack sentence (its post-PR count moved with the new it), the test count (3909 → 3910) and the gates paragraph (58 → 51 families, because deleting the changeset removed 7 changeset families). ⭐ The direction-one and direction-two readings were re-verified by the at-tier review at this head (record 5725290629); the gates and test counts are the author's readings at this head, taken from its rework report and ⛔ not re-run by the seat. ⛔ No reading here was weakened: every refresh describes the same or stronger protection.


Generated by Claude Code

… rule

The test table's docblock claimed two directions and the assertion under it
carried one. `expect(cases.length).toBeGreaterThanOrEqual(51)` counts the rows
of the test table, which a position added to the rule's own POSITIONS table
never moves, so "a position added to the rule without a row here leaves the
count assertion below short" reported nothing at all. That is the direction
#18565 came in through.

Replace the floor with set equality against a set derived from the rule's own
POSITIONS and COLUMN_ENTRY_POSITIONS tables, exposed as a same-package
`listViewWalkedPositions()` seam that reaches no published entry (measured:
every dist artifact byte-identical to the build that predates it). Both
directions now hold, and the offender is named either way.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 18, 2026
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 0b31d90fb37d490d7da12c7acd4b14c4feb22501 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 35c40cd6419eb0655e2b1f6191af5ecb27a8b140 — the merge of head 9897eaae2913a6e7e6581b84de95a82eb07369df into base 0b31d90fb37d490d7da12c7acd4b14c4feb22501, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 35c40cd6419eb0655e2b1f6191af5ecb27a8b140 && git checkout 35c40cd6419eb0655e2b1f6191af5ecb27a8b140
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0b31d90fb37d490d7da12c7acd4b14c4feb22501 9897eaae2913a6e7e6581b84de95a82eb07369df && git checkout -B drift-repro 0b31d90fb37d490d7da12c7acd4b14c4feb22501 && git merge --no-ff 9897eaae2913a6e7e6581b84de95a82eb07369df

node scripts/docs-audit/affected-docs.mjs --json 0b31d90fb37d490d7da12c7acd4b14c4feb22501

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: 110/110 CONTRACT_REVIEW_TIER
Head-sha: 270d9f4b351e2d75858876e959c7af6ea13adae2

① Derived judgments

  • Evidence base: card [finding] validate-list-view-field-refs.test 的 docblock 声称「规则加了位置而表没加行会让计数断言变短」,但那个断言是 toBeGreaterThanOrEqual 地板 ⇒ 该方向什么都不红 —— 正是 #18565 那个洞进来的方向 #18836 body, the PR body, the dev's os-dev-report (read only as the source of its flags), the diff 36583e989b..270d9f4b35, rules read from origin/main with git show, and my own builds and ablations under scratchpad/pr-18876/. The card-comment fetch also returned the dispatching seat's claim comment (5724468860) and its review reply (5724759924); both are seat conclusions, were excluded as evidence, and nothing below rests on them.
  • Criterion applied: SKILL.md:477 (does the card widen the accept set or expand the public surface), :513 and :515 (only the published contract surface counts), references/lanes/spec.md:19-20.
  • Accept set: UNCHANGED. POSITIONS and COLUMN_ENTRY_POSITIONS are byte-identical between merge-base and head (the 163-line region diffed directly); the rule-file diff is 49 added, 0 removed lines, all placed after COLUMN_ENTRY_POSITIONS; validateListViewFieldRefs, both finding codes and both exported types are untouched; no packages/spec file, schema key, enum member, error code or registration is in the diff. The dev's "no POSITIONS row touched" is correct.
  • Public surface: UNCHANGED, measured. @objectstack/lint ships dist only, exports is . and ./runtime, src/index.ts has a 0-byte diff and re-exports the module by name (no export *), src/runtime.ts never references it. Built at merge-base and at head on the same dependency closure: 10 of 14 dist/ artifacts (4 JS bundles, 6 .d.ts/.d.cts) are sha256-identical; listViewWalkedPositions reads 0 in all 14 files, 0 in index.js's export clause, 0 in index.cjs's __export map, 0 in every type file. Bright control validateListViewFieldRefs: 1/1 in the two entry listings, 2/2 in index.d.ts/.d.cts, 4/6/3/3 in the bundle bodies. Dark control COLUMN_ENTRY_POSITIONS (never exported): 2 in each bundle body, 0 in entries and types, so body presence is not a published entry. Instrument controls: adding the symbol to the barrel makes it read 1/1 in the entry listings and 2/2 in the types; the frozen-const shape reads 1 in each bundle body and 0 in the entries. The dev's "reaches no published entry, no type row" is correct.
  • Four published files DID move: index.js.map, index.cjs.map, runtime.js.map, runtime.cjs.map (sourcemap: true, and files[] ships dist whole). Differing keys are mappings and names only; sources equal; the new symbol absent from names. A line-offset shift, not a surface, but the PR body's and the changeset body's "all nine dist artifacts byte-identical" is wrong on the count: 14 artifacts, 10 identical, 4 moved. Claim over-stated; ruling unaffected.
  • Mechanical judges: check-widening-tells reads NOT MEASURED for all three files under either declaration (no declared surface covers packages/lint), and no api-surface baseline exists for @objectstack/lint (T3 covers packages/spec/api-surface/* only), so the build above is the only instrument that reads this package's public surface.
  • Test-file and changeset edits: not published, no surface.
  • Arm: the diff widens no accept set and expands no public surface ⇒ the declaration should carry Clause-②: no, with no direction arm (no (widening) is malformed per AGENTS.md:1068). The claim-time yes (widening) was the correct conservative floor for a new exported symbol (contract-review.md mechanical floor) and is not a fault (spec.md:20). Under no, check-widening-tells --declaration no exits 0 on this diff and the changeset level axis stands down.

② Semver level

  • Declared: @objectstack/lint: minor. The fixed group lists about 70 packages including @objectstack/lint at 17.4.0, so this minor moves every one of them to 17.5.0.
  • Delivered to consumers: 0 changed bytes in any code or type artifact; 4 source maps with shifted mappings; no new entry, no new type, no runtime change. Commit type test(lint).
  • Rule: AGENTS.md:1064-1068 says yes takes at least minor, so minor was consistent with the declared yes and the dev was right not to re-grade alone. With the arm ruled no, pr-automation.yml "WHICH LEVEL" governs: minor is for "a new exported symbol on an index, a new accepted key or value", none of which is here; "a fix( that changes no public surface stays patch"; route 2, "releases nothing (tests-only, and the like) ⇒ apply skip-changeset, PREFERRED; if you are unsure, take route 2".
  • Ruling: minor is wrong. The grade should be skip-changeset: delete .changeset/issue-18836-list-view-position-coverage.md and apply the label. patch is the only other grade the rule admits (if the seat reads the four moved source maps as "publishes something"); it would still bump about 70 packages in lockstep for a map offset. Deleting the changeset also stops its inaccurate "all nine artifacts byte-identical" sentence reaching CHANGELOG.md.
  • Level-axis consequence: with Clause-②: no in the PR body, check-changeset-no-major reads not-declared and exits 0 under either grade; the edited trigger re-fires Check Changeset on the body rewrite.

③ Boundary flags

  • open_questions[0] (declaration contradicted by measurement; A/B/C): A. Re-grade to no, delete the changeset, apply skip-changeset. Correction to its premise: dist is not wholly byte-identical (10 of 14; 4 maps moved); the answer stands because a map offset is neither a surface nor a release.
  • open_questions[1] (set equality vs count equality): A, accept set equality as shipped. Verified: 57 rows across the two tables, 3 map to no position (the three hard-coded filter walks), 2 positions carry two rows each, covered set = walked set = 52; a count equality would have to hard-code those constants. The failing diff names the offender (- "tree.ablationProbeField").
  • Direction two (position added to the rule, no row): strictly stronger, verified. Base: 130 passed, 0 failed (silent). Head: 1 failed, covers every position the rule walks, naming tree.ablationProbeField.
  • Direction one (position dropped from the rule): no regression, verified. Base and head both 1 failed, views[0].list.tree.labelField reports at warning, per-case; the head completeness assertion stays green exactly as the new comment says.
  • Per-case assertions: unchanged, verified. The second table's it body is byte-identical; the measured describe differs only in iterating MEASURED_CASES instead of cases; the file after the completeness assertion hashes identical; 130/130 tests in the file at both base and head; head CI at my last read: Test Core 6 of 6 green, every completed check green, Lint & Repo Gates still in progress.
  • "One row of slack": verified. The base cases table has 52 rows against toBeGreaterThanOrEqual(51); deleting one row at base reads 129 passed, 0 failed; the same deletion at head is red (- "tree.labelField").
  • ⛔ NOT strictly stronger on the floor's own direction (rows silently deleted), measured. Deleting the two hard-coded filter-walk rows (tabs[0].filter[0].field, userFilters.tabs[0].filter[0].field): base red (50 against 51), head silent (128 passed, 0 failed). Deleting the two bare-name duplicate rows (columns[0], gantt.tooltipFields[0]): base red, head silent. The new inline comment discloses the duplicate seam but claims "a row deleted from either table takes its position off the covered set, so the deletion is red", which is false for the three filter-walk rows, and for tabs[].filter and userFilters.tabs[].filter those rows are the only unknown-name assertions in the two tables (elsewhere in the file those two paths are asserted only for the dotted finding class). On a card whose thesis is comments that claim protection they lack, this is an owed edit: either state in that comment that the three filter-walk rows sit outside the criterion, or assert them (a three-element expected list of the hard-coded walks, which the positionAsserted docblock already enumerates in prose).
  • out_of_scope_findings[0] (slack, fixed in place): agreed, verified above; no separate card.
  • out_of_scope_findings[1] (runtime.js bundles the rule while runtime.d.ts exports none of it): confirmed, 3 against 0 in my counts; splitting: false in packages/lint/tsup.config.ts; not a defect.
  • out_of_scope_findings[2] (replaced the fenced inline comment): correct. The card body locates the defect in the docblock and says it is not in the inline comment, which is a statement of where the defect is, not a bar on removing a comment whose assertion is gone. The card's route A removes the floor; a floor comment above an equality would be a false comment of exactly the card's class; the replacement does not call the old comment wrong and was flagged in both the PR body and the report rather than taken silently. The overclaim is in the NEW comment (bullet above), not in the act of replacing.
  • Scope fence: POSITIONS unchanged (byte-identical); barrel unchanged (0-byte diff); no double assertion (toBeGreaterThanOrEqual survives only in the comment describing what was replaced, test file line 340).
  • Carriers: needs:contract-review is on both the card and the PR; the PR is a draft; the PR body's Clause-②: yes (widening) line is the one check-changeset-no-major reads and is the seat's to rewrite.
  • Owed before landing, at a new head: (a) delete the changeset and apply skip-changeset (or patch if the seat reads the moved maps as a release; not minor); (b) rewrite the PR body's declaration to Clause-②: no and correct the "all nine artifacts byte-identical" sentence to the measured 10 of 14; (c) fix the new inline comment's floor-takeover claim for the three filter-walk rows, or assert those walks.

Implemented-by: claude/issue-18836-position-count-floor-overclaims
Reviewed-by: session_01JbZnqu8bt6YqfJsr9vaFb3

VERDICT: FAIL


Generated by Claude Code

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

席位采信记录 —— 达档契约复核 FAIL,⛔ 载体不剥,本 PR 回工

⏱️ 2026-09-18T03:55Z。

复核记录 本 PR 评论 5724912914
所判 head 270d9f4b351e2d75858876e959c7af6ea13adae2
采信时 head ⏱️ 2026-09-18T03:55Z 现读 同值 ⇒ head 未动
档位证据 110/110 —— 本席对该隔离子代理自身 transcript 逐 type:"assistant" 行读 harness 的 message.model,110 条全等于 CONTRACT_REVIEW_TIER,其他模型 0 条。⛔ get_session 未调用(在 mode:subagent 里无效)
采信方式 逐字。对复核者自写的记录只做两处替换(Served-tier: 前缀加盖章、Reviewed-by: 填本席 session),并用 unified diff 证明只有这两行不同
载体 ⛔ 不剥。章程只在 PASS 时同笔剥双载体;needs:contract-review 留在卡 #18836 与本 PR 两侧

⭐ 本席独立复验了那条致命读数 —— ⛔ 不是采信转述

FAIL 压在一条判断上:新判据在地板本来就守着的那个方向上丢了覆盖。本席从复核者自己的 ablation 日志逐条读出:

base,删掉那两条 filter-walk 表行  → 1 failed: 'covers every position the rule walks'  (127 passed / 128)
head,同样的删除                   → 128 passed, 0 failed —— **静默**

而代码自己给出了机制,⏱️ 2026-09-18T03:55Z 本席现读分支上 validate-list-view-field-refs.ts:517-521,该函数的 docblock 逐字:

The three filter walks further down (listView.filter, tabs[].filter, userFilters.tabs[].filter) are deliberately absent: they are hard-coded seams, not table rows, so nothing about them can drift out of a table.

⇒ 那三条 filter-walk 的表行按构造就在覆盖集之外。

⭐⭐ 而这正是本卡自己的论点,反噬在它自己的修法上

本卡的论点是:一条声称了自己没有的保护的注释,比没有注释更坏 —— 因为它让下一个读者不再去找别的保护。

⇒ 而新加的行内注释写着「a row deleted from either table takes its position off the covered set, so the deletion is red」,对那三行为假。⇒ ⭐ 修法交付了一条声称了它没有的保护的新注释。

⚠️ 公道地记一笔:dev 是知道那个接缝的 —— 它在 listViewWalkedPositions() 的 docblock 里明白写了 filter walks「deliberately absent」。⇒ 缺陷不是隐瞒,是同一个 PR 里两条注释互相矛盾:docblock 披露,行内注释过度声称。

回工清单 —— 三项,归属分明

事项 谁做
(a) 删掉 .changeset/issue-18836-list-view-position-coverage.md,改挂 skip-changeset —— ⛔ 不是 minor。复核实测:fixed 组约 70 个包会因这个 minor 一起升到 17.5.0,而交付给消费者的代码与类型字节是 0 文件由 dev(在它的分支上)· 标签由本席
(b) PR 正文改 Clause-②: no,并把「all nine dist artifacts byte-identical」更正为实测的 10 / 14(4 个 source map 动了 —— files[] 整个发 dist,.map 也在里面) 本席(章程:dev 只写一次正文,事后更正归席位)
(c) 修那条行内注释的过度声称:要么写明那三条 filter-walk 行落在判据之外,要么把它们断言起来(positionAsserted 的 docblock 已经把这三条硬编码走法散文枚举过了) dev

⚠️ (a) 的一个细节:复核指出 patch 是规则唯一接受的另一个档位(若席位把那 4 个动了的 source map 读作「发布了东西」),但它仍会让约 70 个包为一个 map 偏移一起升版。⇒ 本席取 skip-changeset,并把这条备选记在这里。

⛔ 本席不做的

  • ⛔ 不重起复核去钓一个 PASS。 FAIL 是裁决,⛔ 不是作废;章程只允许在作废之后重起,且必须引上一次作废的理由。⇒ 回工之后是新的 head,那时才谈复核。
  • ⛔ 不自己把臂改成 no。复核已经判了 no(不带方向臂),本席照记;⛔ 但载体要等新 head 上的复核。

⏱️ 2026-09-18T03:55Z · domain:spec seat 2 · 座位贴 #18549


Generated by Claude Code

…hangeset

Contract review measured the new criterion losing coverage the row-counting
floor had: deleting the two filter-walk rows was red at base (the count fell
below 51) and silent at head, because those three walks are open code rather
than table rows and nothing derives them. The inline comment nevertheless
claimed "a row deleted from either table takes its position off the covered
set, so the deletion is red" -- a comment claiming protection it lacks, which
is the defect this card is about, delivered by the card's own fix.

Declare the three walks as an explicit list and assert it exactly, so a deleted
filter row is red and an undeclared fourth walk is red. Restate the residue in
the comment per kind of row, including the one seam left open and disclosed:
the two positions asserted twice on purpose.

Drop the changeset. The review measured 0 changed bytes in every code and type
artifact, so a minor would move about 70 lockstep packages for nothing;
skip-changeset is the grade.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@os-bill os-bill added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

席位:回工三项已收,正文与标签由本席办完 —— ⭐ 新 head 上重起复核(⛔ 不是重摇)

⏱️ 2026-09-18T04:25Z。head 270d9f4b35 → 9897eaae29。

本席逐条复验(⛔ 不按报告叙述)

项 归属 本席读数
(c) 行内注释的过度声称 dev ⏱️ 2026-09-18T04:25Z 现读:takes its position off the covered set 命中 0;HARD_CODED_FILTER_WALKS 声明于测试 :258,:444 用 toEqual 精确断言(⛔ 不是子集检查)⇒ 删掉任一条 filter-walk 行都会让 unaccounted 变短而变红
(c) 规则侧 docblock dev :523-527 已改,逐字:「⛔ Absent from this list is not absent from the test's account of itself — the test declares those three as an explicit list and asserts it exactly」⇒ 复核点名的那条「deliberately absent」歧义已消
(a) changeset dev 分支上 issue-18836 的 changeset 文件 0。⭐ 亮控:.changeset 目录另有 427 个文件 ⇒ 那个 0 是读数
(a) 标签 本席 skip-changeset 已挂,四步写入并回读
(b) PR 正文 本席 见下

⭐ dev 走了第二条路(把三条硬编码 filter walk 声明成显式列表并精确断言),⛔ 不是第一条(只写明它们在判据外)。⇒ 那恢复了旧地板本来守着、而派生判据结构上够不到的那半覆盖 —— 复核测出「base 红 / head 静默」的那三个删除,现在 head 上是红的。

⭐ 而 dev 还报告了一件溢出的加强:新的姊妹断言同时抓住「规则里删掉一个位置之后留下的陈旧表行」(该行两边都不匹配,冒出来成为 extra)⇒ 方向一现在被守了两次。

(b) 正文:本席改了两处,⛔ 两处都留了可见的更正块

  1. 声明行改为 Clause-②: no(⛔ 不带方向臂;复核判词如此)。⏱️ 2026-09-18T04:25Z 回读:第 3 行就是它 —— 那正是 check-changeset-no-major 读的那一行。
  2. 把「all nine dist/ artifacts byte-identical … 9 of 9 OK」更正为实测的 14 个产物、10 个逐字节相同、4 个 source map 动了。

⚠️ ⛔ 两处都不是静默改写:正文里各留了一个引用块,写明「Corrected/Rewritten by the dispatching seat, ⛔ not by the author」并说清原文是什么、为什么改。⏱️ 2026-09-18T04:25Z 本席按匹配粒度回读验过:旧串只出现在那两个引用块里 —— 被引用,⛔ 未被断言。

⚠️ 归属代价,如实记下 —— 这条是本席付的,⛔ 不是谁的疏忽

裸 REST PATCH /pulls 送不带页脚的正文时,平台会补恰一条裸页脚。⏱️ 2026-09-18T04:25Z 回读实测:session_ 在正文里现在读 0,页脚是 _Generated by [Claude Code](https://claude.ai/code)_(恰 1 条)。

⇒ ⭐ 本 PR 正文从此不载明是哪个会话写的。 这是那条已记录的代价(带页脚送 ⇒ 两条页脚;不带送 ⇒ 一条裸页脚、丢 session id),本席选了后者,并把持久归属记在这里:正文的两处更正由 domain:spec seat 2、session_01JbZnqu8bt6YqfJsr9vaFb3 作出;实现由 dev 在分支 claude/issue-18836-position-count-floor-overclaims 上完成。

答 dev 的 open_questions:A,照你交付的样子(披露,⛔ 不关闭)

那条接缝是:两个被故意断言两次的位置(columns、gantt.tooltipFields,一次裸名一次记录形),删掉一对里的任一行,位置仍被它的孪生覆盖 ⇒ 实测静默。

⭐ 判 A 的理由,和本卡自己的论点是一致的:本卡要修的是「一条声称了自己没有的保护的注释」。而你现在做的是准确披露了一处它没有覆盖的地方,并写明了关闭它的代价(给每个 entries 位置带上 kind 轴、要求两种合法形各有一行 —— 而那要三行今天两张表都没有的行)。⇒ 一条诚实的披露和一条撒谎的声称不是一回事,前者正是本仓要的形状。

⇒ ⛔ 本席不为它立卡,理由写在这里以便可见:披露 + 代价已在注释里,而 B 会给一张已经走过一次契约复核的卡新增复核面。⚠️ 若日后有人真被那条接缝咬到,那时立卡带着实例,比现在立一张预防卡更有用。

下一步

⏱️ 2026-09-18T04:25Z 本席在新 head 9897eaae29 上重起达档契约复核。⛔ 这不是重摇:章程只禁止在同一 head 上为了钓 PASS 而重起,而 FAIL 是裁决、回工产生了新 head。⇒ 双载体继续挂着,直到新一轮复核落定。

⏱️ 2026-09-18T04:25Z · domain:spec seat 2 · 座位贴 #18549 · session session_01JbZnqu8bt6YqfJsr9vaFb3


Generated by Claude Code

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: 95/95 CONTRACT_REVIEW_TIER
Head-sha: 9897eaae2913a6e7e6581b84de95a82eb07369df

① Derived judgments

  • Evidence base: card [finding] validate-list-view-field-refs.test 的 docblock 声称「规则加了位置而表没加行会让计数断言变短」,但那个断言是 toBeGreaterThanOrEqual 地板 ⇒ 该方向什么都不红 —— 正是 #18565 那个洞进来的方向 #18836 body; the PR body as it reads at this head; the prior at-tier record 5724912914, read as a peer review and prior art only; the two os-dev-report comments (5724735303, 5725107994) read only as the source of their flags; the diff 36583e989b..9897eaae29 (2 files, +213/−25); every rule read from origin/main with git show; my own builds and ablations in an isolated worktree under scratchpad/pr-18876-r2/ (no scratch from the earlier round read). The dispatching seat's claim comment (5724468860), its review reply (5724759924) and its two acceptance records (5724918288, 5725140850) were excluded as evidence; nothing below rests on them.
  • Criterion applied: SKILL.md 派发 section, 「判据:本卡放宽接受集或扩大公开面吗」 and 「条款②只指已发布契约面」; references/lanes/spec.md:19-20; AGENTS.md:1067-1068 for the declaration grammar (no (widening) malformed).
  • Accept set: UNCHANGED. The POSITIONS + COLUMN_ENTRY_POSITIONS region (rule file lines 321-483, 163 lines) is byte-identical base to head (sha256 7633a46ae470… on both sides); the rule-file diff is 59 added / 0 removed, all placed after COLUMN_ENTRY_POSITIONS (one docblock, one function); checkListView, validateListViewFieldRefs, both finding codes and the exported types are untouched; no packages/spec file, schema key, enum member, error code or registration is in the diff. Read the walker: every field-naming position is table-driven (POSITIONS scalars/lists/entries, COLUMN_ENTRY_POSITIONS under columns[]) except the three checkFilter calls, so listViewWalkedPositions() enumerates exactly the table-driven positions the rule walks — 52, no duplicates — which is what its docblock claims.
  • Public surface: UNCHANGED, measured. @objectstack/lint ships files: dist, README.md, CHANGELOG.md, exports is . and ./runtime, no .npmignore, package.json 0-byte diff; src/index.ts and src/runtime.ts 0-byte diff; the barrel re-exports the module by name (no export *), runtime.ts never names it. Built in one worktree on one dependency closure with only the two files swapped: 14 dist/ artifacts; determinism control (head built twice) 14/14 sha256-identical; head vs base 10/14 identical — the 4 JS bundles and all 6 .d.ts/.d.cts. listViewWalkedPositions reads 0 in all 14 files, 0 in index.js's export {} clause, 0 in index.cjs's __export map, and the function body's distinctive text reads 0 in index.js (tree-shaken). Bright control validateListViewFieldRefs: present in both entry listings, 2/2 in index.d.ts/.d.cts, 4/6/3/3 in the four bundle bodies. Dark control COLUMN_ENTRY_POSITIONS (never exported): 2 in each bundle body, 0 in every entry listing and type file — a name in a bundle body is not a published entry, and the instrument tells the two apart.
  • The 4 that moved: index.js.map, index.cjs.map, runtime.js.map, runtime.cjs.map. Differing keys mappings and names only; sources equal; sourcesContent absent by repo policy (scripts/tsup-drop-sources-content.mjs); the names SET is identical on both sides (0 added, 0 removed; the array only grew by two duplicate entries) and mappings grew by exactly one character. A line-offset shift over src/ paths that are not themselves shipped: not a surface.
  • Mechanical judges: check-widening-tells --declaration no on this diff from origin/main exits 0 with both files NOT MEASURED (no declared surface covers packages/lint); no api-surface baseline exists for this package. The build above is the only instrument that reads this package's surface, and it reads no change.
  • Arm: the diff widens no accept set and expands no public surface ⇒ Clause-②: no, with no direction arm. The PR body carries exactly Clause-②: no on line 3, the line check-changeset-no-major reads. The claim-time yes (widening) was the mechanical floor for a new exported symbol and is not a fault (spec.md:20).

② Semver level

  • Declared: none. .changeset/issue-18836-list-view-position-coverage.md is absent at head (0 files naming 18836 against 427 other files in .changeset/, so the 0 is a reading); the skip-changeset label is on the PR; Check Changeset re-ran on this head after the label and passed (04:24:25Z). The 04:21:08Z run of the same job on the same head is red because it fired before the label existed — the "red left here does not clear itself" case pr-automation.yml describes — and is superseded by the later run.
  • Delivered to consumers: 0 changed bytes in any code or type artifact; 4 source maps with a one-character mappings offset and an identical name set; no new entry, no new type, no runtime change. Commit type test(lint).
  • Rule: AGENTS.md:1066 — skip-changeset "is for a diff that publishes nothing from any released package"; pr-automation.yml route 2 — "releases nothing (… tests-only, and the like) ⇒ apply skip-changeset, PREFERRED" and "If you are unsure, take route 2. A wrong skip-changeset label is caught by review". Ruling: skip-changeset is the right grade. The only other grade the rule admits, patch, is wrong here: the rule writes it for "a bug fix in a released package", this is a test-criterion change, and @objectstack/lint sits in the single fixed group of 70 packages, so a patch would move all 70 for a map offset over unshipped sources. minor (the previous head's grade) is excluded outright under no.
  • Consistency: no changeset, the label, and Clause-②: no are mutually consistent; the check-changeset-no-major level axis reads not-declared and stands down.

③ Boundary flags

  • Prior-record item 1 (not strictly stronger on the floor's own direction): CLOSED for the filter-walk rows, by ablation. Head: deleting any ONE of the three filter-walk rows (filter[].field in MEASURED_CASES, tabs[0].filter[0].field, userFilters.tabs[0].filter[0].field) is red in the sibling assertion, whose diff names the missing walk; deleting the two cases filter rows together is red. Base: one deletion silent (129 passed, the one-row slack), two deletions red. Head is therefore strictly stronger than base on every filter-walk mutation. Also red at head: removing one declaration from HARD_CODED_FILTER_WALKS (extra tabs.filter.field), declaring a fourth walk with no row, and giving an undeclared fourth walk a row.
  • The residue, measured and stated plainly: deleting BOTH bare-name duplicate rows (columns[0] and gantt.tooltipFields[0]) is red at base (50 rows against 51) and SILENT at head (129 passed); by symmetry columns[0] plus gantt.tooltipFields[0].field behaves the same. Those two two-row deletion sets are the whole base-red/head-silent class that remains; every other base-red mutation I ran is head-red, and four base-silent classes are now head-red (a single filter-walk row, a single uniquely-covering row, a position added with no row, and a position dropped — caught twice). This residue is exactly the seam the code discloses.
  • Prior-record item 2 (inline-comment overclaim): CLOSED. "takes its position off the covered set" reads 0 at head (1 at 270d9f4). The replacement is true per kind of row, each measured one by one: a uniquely-covering row deleted ⇒ red in the derived assertion (the tree.labelField row: 1 failed, diff - "tree.labelField"); a filter-walk row deleted ⇒ red in the sibling (all three); a duplicate-covered row deleted ⇒ silent (all four such rows). "Three rows these tables do not have today" is correct: five entries positions, bare-form rows exist only for columns and gantt.tooltipFields. The rule-side docblock's "deliberately absent" sentence now says the test declares and asserts the three walks exactly, which the sibling assertion does.
  • ⚠️ One wording imprecision in that bullet, non-blocking: "deleting either one is SILENT — measured, deleting both leaves this file green". Under the intended reading (one row from each of the two pairs) it is true, 129 passed. Under the natural reading (both rows of one pair) it is false: deleting both gantt.tooltipFields rows is red in the derived assertion (diff - "gantt.tooltipFields"), and both columns rows likewise (- "columns"). The error runs in the under-claiming direction — it describes less protection than exists, the opposite of this card's defect — and the bullet's own mechanism sentence ("the surviving row still covers the position") lets a careful reader recover the meaning; so this does not fail the PR. "deleting one row of each pair" is the precise phrase, and the seat may want it before landing.
  • Prior-record item 3 (changeset graded minor): CLOSED — deleted at head, skip-changeset applied, ruled in ②.
  • Prior-record item 4 ("all nine dist artifacts byte-identical"): CLOSED. My independent build agrees with the corrected face — 14 artifacts, 10 identical, 4 source maps moved — and adds the determinism control the earlier counts lacked. The rule docblock now states 14/10/4 and the moved-map reading correctly; the seat-written correction block in the PR body matches. The dev's const-versus-function instrument control (a frozen-const initializer surviving as dead weight) was not re-measured; it is not load-bearing on the ruling.
  • The disclosed-but-open seam, on a card whose thesis is comments that claim protection they lack: ACCEPTABLE. The card's failure mode is a false claim of protection; this is a true statement of a gap with its closing cost named. The gap is two specific two-row deletion sets; the base's protection there was an accident of a floor with one row of slack; and closing it needs a kind axis on the exported seam plus three rows the tables lack — new review surface. Rework open_questions[0] (A leave disclosed / B close): A, as shipped. B is a fair follow-up but not owed by this card.
  • Third strengthening claimed (a stale row for a position dropped from the rule): VERIFIED. Removing labelField from POSITIONS.tree at head fails 2 tests — that row's per-case assertion AND the sibling assertion (extra tree.labelField) — while the derived assertion stays green exactly as its comment says; base fails only the per-case one.
  • Direction two (position added with no row): unchanged from the prior head, verified — base 130 passed / 0 failed (the defect); head 1 failed, covers every position the rule walks, diff - "tree.ablationProbeField".
  • POSITIONS byte-identical and barrel untouched: VERIFIED above. Rest of the scope fence: the per-case it bodies are unchanged; toBeGreaterThanOrEqual survives only in the comment describing what was replaced (test file line 370); no double assertion.
  • Package state at head, measured in the worktree under the verify lock: pnpm --filter @objectstack/lint test 104 files / 3910 tests passed; typecheck exit 0 with the test-typecheck ledger held at 2 files / 6 errors / 2 pinned signatures. Every mutation above was restored and proved restored (0-byte diff against its tree). CI at this head at my last read: every completed check green except the pre-label Check Changeset run discussed in ②.
  • For the seat's clearing step, carriers and body: (a) needs:contract-review is on both card and PR; the PR is a draft. (b) check-clause2-carriers --pair 18876 from origin/main reads the declaration limb from the card's governing claim comment, which still says yes (widening), while the PR body says no; the card-side ruling line the charter asks for (「同笔在卡上记一行条款②认定」) is what reconciles them. (c) Three body cells describe the previous head and are stale at this one: the direction-one "after" cell (reads 1 failed / 129 passed; at this head 2 failed / 129 passed of 131), the test count (3909; now 3910), and the gates paragraph (58 families at 270d9f4). None of them overclaims protection.
  • Rework out_of_scope_findings: the old floor's one-row slack — confirmed (base: any single row deletion silent); runtime.js bundling the rule while runtime.d.ts exports none of it — confirmed, 3/3 in the runtime bundle bodies against 0/0 in runtime*.d.*, splitting: false documented; the STALE TREE warning — process note, no action.

Implemented-by: claude/issue-18836-position-count-floor-overclaims
Reviewed-by: session_01JbZnqu8bt6YqfJsr9vaFb3

VERDICT: PASS


Generated by Claude Code

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

席位采信记录 —— 回工后的达档复核 PASS,双载体已清

⏱️ 2026-09-18T04:46Z。

复核记录 本 PR 评论 5725290629
所判 head 9897eaae2913a6e7e6581b84de95a82eb07369df
采信时 head ⏱️ 2026-09-18T04:46Z 现读 同值 ⇒ head 未动
档位证据 95/95 —— 本席对该隔离子代理自身 transcript 逐 type:"assistant" 行读 harness 的 message.model,95 条全等于 CONTRACT_REVIEW_TIER,其他模型 0 条。⚠️ 复核者自报 90/90,那是它写记录那一刻的自计数;本席读的是已完成的 transcript(含它的交回轮)⇒ 两者一致,而以本席的为准 —— 章程把盖章控制归采信席
采信方式 逐字。对复核者自写的记录只做两处替换,unified diff 证明只有这两行不同
载体 卡 #18836 与本 PR 两侧的 needs:contract-review 同轮剥除,各自四步写入并回读
剥后机读 check-clause2-carriers --pair 18876 ⇒ exit 0;其 C6-RECORD 行自行读到本记录、确认它命名该 head、带 Reviewed-by:,并读到了 95/95 的盖章控制 ⇒「the strip stands on C7 as well」

⭐ 这是一次回工后的新复核,⛔ 不是重摇

⏱️ 2026-09-18T04:46Z 复读:上一轮在 head 270d9f4b35 上返回 FAIL(记录 5724912914)。⇒ 章程禁止的是在同一 head 上为了钓 PASS 而重起;FAIL 是裁决,回工产生了新 head 9897eaae29 ⇒ 这是对新 head 的第一次复核。⭐ 而本席在派发给复核者的简报里明写了「你可以在任一方向得出不同结论;⛔ 不要把上一次 FAIL 当成要去确认的东西,也⛔ 不要把回工当成要放行的东西」。

上一轮 FAIL 点名的四项,复核逐项判 CLOSED,本席复核其中两项

⏱️ 2026-09-18T04:46Z 取数,下列每条读数皆然。

  • ⏱️ 2026-09-18T04:46Z ①(判据不够强)CLOSED:复核自己做了消融 —— head 上删任一条 filter-walk 行都红,而 base 上删一条是静默的。⭐ 本席另外结构性复核过:HARD_CODED_FILTER_WALKS 用 toEqual 精确断言(⛔ 不是子集检查)。
  • ②(注释过度声称)CLOSED:takes its position off the covered set 在 head 上命中 0(在 270d9f4b35 上是 1)—— 本席实测。
  • ③(changeset 档位)CLOSED:文件已删(⭐ 亮控:.changeset 另有 427 个文件),skip-changeset 由本席挂上。
  • ④(九个产物)CLOSED:复核独立重建并加了一条确定性控制(head 连建两次 14/14 相同)—— 那是前两次计数都没有的。

⚠️ 复核点名给本席的三件,处置如下

  1. 卡的声明肢仍写 yes (widening),而正文写 no。 ⇒ 本席同笔在卡 [finding] validate-list-view-field-refs.test 的 docblock 声称「规则加了位置而表没加行会让计数断言变短」,但那个断言是 toBeGreaterThanOrEqual 地板 ⇒ 该方向什么都不红 —— 正是 #18565 那个洞进来的方向 #18836 上落一行条款②认定,把两肢对上。⚠️ 机读本来就 exit 0(正文按机读自述是「stated as an INPUT only」),但认定行是章程要的人读对账。
  2. 正文三处单元格描述的是上一个 head(方向一的「改后」格、测试计数 3909、门禁段的 58 families)。⇒ 本席一并更正 —— ⚠️ 正文 PATCH 不移动 head,⛔ 不会作废本记录。
  3. 新注释里一处措辞不精确:「deleting either one is SILENT — measured, deleting both leaves this file green」在「每对各删一行」的读法下为真、在「删掉同一对的两行」的读法下为假。⭐ ⇒ ⛔ 本席不动它:它错在少声称的方向(⛔ 正是本卡缺陷的反面),复核判为非阻塞,而任何推送都会移动 head 并作废本记录。⇒ 记为承接事项:精确措辞是「deleting one row of each pair」,留给下一个碰这个文件的人。

⏱️ 2026-09-18T04:46Z · domain:spec seat 2 · 座位贴 #18549


Generated by Claude Code

@os-bill
os-bill marked this pull request as ready for review September 18, 2026 04:52
@os-bill
os-bill added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 1fb36ca Sep 18, 2026
56 of 57 checks passed
@os-bill
os-bill deleted the claude/issue-18836-position-count-floor-overclaims branch September 18, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests tooling

Projects

None yet

2 participants