test(docs): give the translated view rosters a coverage rule too - #1561
Merged
Merged
Conversation
`test/docs-view-rosters.test.ts` runs two complementary directions on the English face — coverage (every view the app ships is named in its page's roster) and name exactness (the name column names only views the app ships). #1551 gave the translated faces name exactness plus a structural rule pinning each face to the English page's roster row count, and no coverage. Those three leave one shape open: a roster that keeps the row count, names only lawful names, but names one view twice and omits another. Measured before writing anything, on the tree #1556 landed: `revenue/ products.zh-Hans` with both rows renamed to 全部产品 — dropping 产品目录, two rows in and two rows out — ran 9 passed. Green over the defect. The rules read the NAME COLUMN, not the section body. The English coverage rule asks `body.includes(label)`, a pure existence question over prose as well as table, so it cannot see a duplicate at all and misses the omission whenever the prose mentions the dropped name — measured, 9 of the 55 names on each of the three faces are echoed in the body outside their own row, and on one of them a body-shaped rule stays green over this exact defect. Coverage and not set equality, deliberately: set equality implies name exactness and would make #1551's two rules dead weight. The count rule keeps its place too — coverage and exactness pin the SET of names and say nothing about multiplicity, so an extra row repeating a lawful name fails only the count rule. `revenue/approvals` stays out structurally, inherited rather than restated: the rules walk PAGE_OBJECT and `rosterOf`, and that page has no roster heading on any face. No exemption list grew and #1552 is untouched. Nothing under `content/docs/**` or `src/` changes, and nothing needed to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019hUuCQStzXGMFSX4dzww5t
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-sales
marked this pull request as ready for review
September 3, 2026 12:07
os-sales
pushed a commit
that referenced
this pull request
Sep 3, 2026
The English coverage rule asks `body.includes(label)` — does the name appear anywhere in the roster section, prose and bullets included. That is a pure existence question, so it is blind to multiplicity by construction and blind to an omission whenever the section's prose still names the dropped view. Measured on the tree #1561 landed: `service/cases.mdx`'s **Escalated Cases** row renamed to **All Cases** leaves the name column naming *All Cases* twice and never naming *Escalated Cases*, row count unchanged, and the file ran `Tests 11 passed (11)`. Nine of the fifty-five English name cells echo their view name in the section body outside their own table row, so those nine rows had no rule protecting them. This adds the name-column coverage rule the translated faces got in #1557, reusing `nameColumns('')` and `expectNameColumnIsReadable` unchanged so it inherits the `revenue/approvals` exclusion and the vacuity floor structurally. The body-shaped rule is kept, and is now labelled for the job it does. Measured, it is not the wider net it was taken for: name-column coverage strictly implies body coverage, so every label the body rule reports missing is one the new rule reports missing too. It stays as a diagnostic — both firing means the view is named nowhere in the section, only the new rule firing means it is named in prose but has no row — and the header says that rather than claiming coverage it does not add. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019hUuCQStzXGMFSX4dzww5t
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1557
test/docs-view-rosters.test.tsruns two complementary directions on the English face — coverage (every view the app ships is named in its page's roster) and name exactness (the name column names only views the app ships) — and the file's own header explains why neither subsumes the other. #1551 gave the translated faces name exactness plus a structural rule pinning each face to the English page's roster row count. It did not give them coverage.Those three rules leave one shape open: a
.zh-Hans.mdxor.zh-Hant.mdxroster that keeps the row count, names only lawful view names, but names one view twice and omits another.The premise, measured first
Before writing anything, on the tree #1556 landed (
f4068c4d):content/docs/revenue/products.zh-Hans.mdxwith both rows renamed to**全部产品**— dropping**产品目录**, two rows in and two rows out — ranGreen over the defect, on the file whose whole purpose is that defect's class. Mutation confirmed on disk (blob
f30cd07→add6646, removed anchor 1 → 0, injected 1 → 2); restored and proved by an emptygit diff HEADwith the blob back atf30cd07.The rules read the NAME COLUMN, not the section body
Pointing the English coverage rule at the translated faces does not work, and the reason is worth recording rather than rediscovering. That rule asks
body.includes(label)— does the name appear anywhere in the section — which is a pure existence question over prose as well as table. So it is blind to multiplicity by construction and cannot see a duplicate at all, and it is blind to the omission whenever the section's prose happens to mention the dropped name.That is not a corner: measured, 9 of the 55 names on each of the three faces are echoed in the section body outside their own table row. On one of those nine —
service/cases.zh-Hanswith its**已升级工单**row renamed to**全部工单**, on a page whose bullets below the table still say 已升级工单 — a body-shaped coverage rule stays green (1 passed), as does the suite (9 passed).So the new rules reuse the
nameColumnsparse the name rules already share, and read the first column.Coverage, deliberately, and not set equality
Asserting the name column's set equals the source set closes this in one line, and it was rejected: it implies name exactness, which would make #1551's two rules dead weight, and this file is deliberate that each rule earns its place. Coverage is the missing direction and only that, so each face now carries the same complementary pair the English face has carried since #1326.
They are two parallel rules sharing the parse, not one parameterised rule, because what a failure means differs: on zh-Hans a page and a live pack disagree; on zh-Hant a page and a hand-written table do.
The row-count rule is not made redundant either
Measured, not argued. Coverage and exactness together pin the set of names on a face and say nothing about multiplicity. An extra row repeating a lawful name —
| **全部产品** | 重复行 |inserted onproducts.zh-Hans— fails only the count rule:This card's shape is the other way round: with the count pinned, a duplicate forces an omission, and the omission is what coverage sees. (That ablation is an insertion, so its proof is the injected anchor 0 → 1 and the blob hash — the removed-count assertion is deliberately not read, per the trap #1551's harness voided a run over.)
Reverse verification
Every mutation confirmed on disk by blob hash and anchored counts on the removed and injected text; every restore proved by state — blob hash back at its HEAD value and an empty
git diff HEAD.products.zh-Hans**产品目录**→**全部产品**(the card's shape)never names "产品目录", the zh-CN spelling of a view crm_product shipscases.zh-Hans**已升级工单**→**全部工单**(prose still names it)never names "已升级工单", the zh-CN spelling of a view crm_case shipscontracts.zh-Hant**合約時間線**→**全部合約**never names "合約時間線", the pinned Traditional name of a view crm_contract shipsproducts.zh-Hans/.zh-Hantroster sections this rule read no name column out of: …, not on coverageThe vacuity guard matters most for a coverage rule: an empty cell list is exactly what would let it pass by checking nothing.
expectNameColumnIsReadableis called first thing in both new rules, so a lost roster section is reported as a lost roster section.Neither new rule carries a source-side floor of its own, deliberately: the
zh-CNproducer rule already fails below 40 resolved pack spellings and the pin audit already fails below 40 pinned names, exactly as vacuity guard #2 carries that floor for the English coverage rule.revenue/approvalsand #1552Still outside these rules structurally, inherited rather than restated: they read
nameColumns, which walksPAGE_OBJECTandrosterOf, and that page carries no roster heading on any of its three faces — re-measured here,rosterOfis null for all three (its headings are## Where to find pending approvals/## 在哪里找到待处理的审批/## 在哪裡找到待處理的審批). No exemption list grew, and #1552 is left as open as it was.Scope
Nothing under
content/docs/**orsrc/changes, and nothing needed to: all 55 name cells on each translated face are distinct and each face names exactly the 55 views its objects ship. This is a hole in the guard, not a defect in the docs — the same reason #1326 was worth landing while its pages were already correct. The pages were mutated only inside ablations, each restored and verified by state.Verification
pnpm verify—validate && typecheck && lint && lint:i18n-gate && hygiene && hygiene:tokens && build && test— green end to end on0ec6dd09:Changeset uses the sanctioned empty-frontmatter form — this releases nothing to HotCRM users.
One finding out of scope, filed separately rather than folded in: the English face carries this same shape, because its coverage rule reads the body. Measured with these rules in place —
cases.mdxnaming**All Cases**twice and dropping**Escalated Cases**runs 11 passed. Closing it is a third rule, which this card did not scope.🤖 Generated with Claude Code
https://claude.ai/code/session_019hUuCQStzXGMFSX4dzww5t
Generated by Claude Code