Skip to content

Commit 2265bb0

Browse files
os-billclaude
andauthored
docs(lint): put translation-section-name-missing's warning on its own reading (#18970)
Fixes #18768 Clause-②: no `packages/lint/src/validate-translatable-sections.ts` justified its own `warning` severity by citing its sibling rule's reading. The sibling abandoned that reading at #16310, which promoted `translation-target-unknown` from `warning` to `error`. The conclusion is still right; the argument was not. This rewrites the Severity note so it stands on its own reading, and fixes the one other place that narrates the superseded note in the present tense. Comments and docblock prose only — no severity, no schema, no assertion moves. ## Subject leg — the Severity note, sentence by sentence **Before** (`validate-translatable-sections.ts:42-47`), four sentences: 1. `Same reading as its sibling rule (ADR-0072 D1): nothing crashes and nothing is dead — one heading renders in the source locale.` 2. `That is weaker than the dead references validate-object-references reports as errors, and the severity should say so.` 3. `Requiring name outright is a SCHEMA change (FormSection.name is optional today), …` 4. `… which is a breaking authoring change needing a maintainer decision and a migration — deliberately not taken here.` Sentence 1 is the whole defect: it is an appeal to a neighbour's position, and the neighbour moved. Sentences 2 to 4 were always this rule's own and are kept. **After**, the mapping: - Sentence 1 is **replaced** by two paragraphs. The first names the staleness instead of inheriting it — the sibling `stopped holding this reading at #16310`, and the verdict here `survives that; the borrowed argument for it did not`. The second states the reading that actually holds here: `A nameless section MISDESCRIBES NOTHING` — the section is real and renders, the whole cost is one heading staying in the source locale, and it `leaves behind no artefact for the next author to trust: there is no key, so there is nothing to grep`. The contrast with the orphan key the sibling gates on (a confident-looking hit, in every locale, for a surface that was DELETED) is the asymmetry that earns that one `error` and this one `warning`. - Sentences 2, 3 and 4 are **carried over unchanged in substance** (sentence 2 re-worded only to read as an addition: `It is weaker … too`). The reasoning is not invented here. `packages/lint/src/reference-integrity-suite.ts:406` already carries it — `warning-only on its own reading — NOT on its sibling's any more`. That file is read as evidence and is **not** touched by this PR; the rule's own header is now consistent with it. ## Second carrier — narration only `packages/lint/src/validate-translation-references.test.ts:24-28` described the superseded note in the present tense (`the rule's own Severity note argued an orphan key is inert`), inviting a reader to go find an argument that the same change deleted. The narration is now past-tense and self-limiting (`the rule's Severity note AS IT THEN STOOD argued that an orphan key was inert`), with a pointer that the note itself was rewritten. **No assertion moved.** All ten `severity: 'error'` sites in that file are byte-identical; only their line numbers shift by +2 because the docblock grew two lines. A diff restricted to non-comment lines in that file is empty: ``` git diff -U0 BASE -- packages/lint/src/validate-translation-references.test.ts \ | grep -E '^[+-]' | grep -v '^[+-][+-]' | grep -vE '^[+-] \*' (no output) ``` ## Firing control — the probe cannot be fooled by a line wrap Both anchors this round turns on are wrapped across comment lines, and so is the card's designated positive control (`skills/objectstack-i18n/SKILL.md:196-197`). A line-scoped `git grep -F` reads **0** on two of the three needles below — on the unedited tree, where all three are present. The census therefore strips comment leaders, collapses all whitespace including newlines to one space, and only then matches. | needle | line-scoped grep, unedited tree | fold-proof, before | fold-proof, after | |---|---|---|---| | `Same reading as its sibling rule (ADR-0072 D1)` | 1 | **1** | **0** | | `warning-only on its own reading — NOT on its sibling's any more` | 0 (wrapped) | **1** | **1** | | `` `translation-target-unknown` is an **error** and fails the run `` | 0 (wrapped) | **1** | **1** | Population: 8885 tracked text files (10 binary/non-file skipped). The two 1s are read in the *same run* as the 0, so the 0 is a reading and not a dead index. ## DARK `packages/lint` before and after, both through the shared verify lock: ``` Test Files 104 passed (104) Tests 3910 passed (3910) ``` identical on both sides, plus `pnpm --filter @objectstack/lint typecheck` green after. Repo-wide `eslint . --no-inline-config` at this branch's head: **6855 files, 0 errors, 0 warnings**, exit 0. ## Changeset — `skip-changeset`, measured rather than assumed `@objectstack/lint` publishes `files: ["dist","README.md","CHANGELOG.md"]`. Built at BASE and at BASE-plus-this-diff in two separate worktrees and compared file by file: - **byte-identical**: `index.js`, `index.cjs`, `runtime.js`, `runtime.cjs`, `index.d.ts`, `index.d.cts`, `runtime.d.ts`, `runtime.d.cts` — every executable and every type output. - **moved**: the four `.map` files, in exactly one field. `version`, `sources` and `names` are identical; `sourcesContent` is **absent on both sides** (this repo gates that with `check:sourcemap-no-sources-content`), so no source text — and therefore no comment prose — ships at all. What moved is `mappings`, the original-position index, because code moved 15 lines down a source file. - grep control over every `files[]` path: the changed prose scores **0** hits, while the positive control `translation-section-name-missing` scores hits in 6 `dist` files. So nothing an upgrading consumer can read, grep, type-check or execute differs. The `.map` shift is the unavoidable arithmetic of editing any comment above code in a built package, not a published change. Flagged here rather than assumed, because a byte-comparison of the tarball does technically move. ## Gates `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, derived on this tree, run one by one with each exit code landed to disk before anything read it, then reconciled with `--ran`: ``` Run reconciliation — 51 derived, 49 run, 2 NOT-MEASURED, 0 UNRUN. ``` The two NOT-MEASURED are `check:dual-build-cjs-loads` and `check:type-check-debt`. Both exited **3** — their own `PREREQUISITE NOT MET` code, which each gate's output states is neither a pass nor a failure. Both need the whole workspace built (83 packages and 27 dependency closures respectively); CI builds before running them. `check:lean-entry-closure` was in the same state, its one prerequisite package was built, and it then passed. ## Acceptance notes - `validate-translation-references.test.ts`'s docblock says `Eight assertions in this file pinned severity: 'warning'`. That is a statement about the #16310 cohort and is still exactly right — the landing commit flipped eight and added one. The file carries **ten** textual `'error'` sites today, the tenth having landed since. Noted, not filed: the sentence is not wrong, and nothing reads that number. - `docs/audits/2026-07-app-metadata-reference-integrity-assessment.md:93` still says `warning` for this rule. It is stamped `Landed 2026-07-28` and was true then; left alone deliberately. --- _Generated by [Claude Code](https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 873e0e8 commit 2265bb0

2 files changed

Lines changed: 27 additions & 10 deletions

File tree

‎packages/lint/src/validate-translatable-sections.ts‎

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,27 @@
3939
*
4040
* ── Severity: warning ────────────────────────────────────────────────────
4141
*
42-
* Same reading as its sibling rule (ADR-0072 D1): nothing crashes and nothing
43-
* is dead — one heading renders in the source locale. That is weaker than the
44-
* dead references `validate-object-references` reports as errors, and the
45-
* severity should say so. Requiring `name` outright is a SCHEMA change
46-
* (`FormSection.name` is optional today), which is a breaking authoring change
47-
* needing a maintainer decision and a migration — deliberately not taken here.
42+
* On this rule's OWN reading, and deliberately not on its sibling's: that
43+
* sibling stopped holding this reading at #16310, which promoted
44+
* `translation-target-unknown` from `warning` to `error`
45+
* (`TRANSLATION_TARGET_UNKNOWN_SEVERITY` in `validate-translation-references.ts`).
46+
* The verdict here survives that; the borrowed argument for it did not, so the
47+
* reading is spelled out rather than cited.
48+
*
49+
* A nameless section MISDESCRIBES NOTHING. The section is real and it renders;
50+
* the whole cost is that its one heading stays in the source locale while its
51+
* neighbours resolve — wrong-language and visible on the screen, not absent and
52+
* disguised. It leaves behind no artefact for the next author to trust: there is
53+
* no key, so there is nothing to grep, and nothing in the tree reads as
54+
* translated that is not. That is the asymmetry with the orphan key the sibling
55+
* now gates on — a confident-looking hit, in every locale, for a surface that
56+
* was DELETED — and it is why that one earns `error` while this one does not.
57+
*
58+
* It is weaker than the dead references `validate-object-references` reports as
59+
* errors too, and the severity should say so. Requiring `name` outright is a
60+
* SCHEMA change (`FormSection.name` is optional today), which is a breaking
61+
* authoring change needing a maintainer decision and a migration — deliberately
62+
* not taken here.
4863
*
4964
* ── The opt-in gate: the object must actually be translated ──────────────
5065
*

‎packages/lint/src/validate-translation-references.test.ts‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ import { SnapshotContact, SnapshotContactViews } from './showcase-shape.fixtures
2222
* ⭐ Severity, re-judged in place (#16310) — ⛔ not deleted.
2323
*
2424
* Eight assertions in this file pinned `severity: 'warning'` on
25-
* `translation-target-unknown`, and that silence was deliberate: the rule's own
26-
* Severity note argued an orphan key is inert — a few bytes and one untranslated
27-
* string, nothing crashes — so gating on it would be the over-statement
28-
* ADR-0072 D1 forbids.
25+
* `translation-target-unknown`, and that silence was deliberate: the rule's
26+
* Severity note AS IT THEN STOOD argued that an orphan key was inert — a few
27+
* bytes and one untranslated string, nothing crashes — so gating on it would
28+
* have been the over-statement ADR-0072 D1 forbids. ⛔ Do not go looking for
29+
* that argument in the rule: the same change rewrote the note, which now says
30+
* the opposite.
2931
*
3032
* The reading was measured wrong in the one direction that matters. An orphan
3133
* key is not inert; it is a confident-looking grep hit, in every locale, for a

0 commit comments

Comments
 (0)