Skip to content

docs(rest): drop the hand-written translatable-type list from meta-plural-i18n's header - #16461

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-15860-translatable-type-restatement
Sep 7, 2026
Merged

docs(rest): drop the hand-written translatable-type list from meta-plural-i18n's header#16461
os-litant merged 1 commit into
mainfrom
claude/issue-15860-translatable-type-restatement

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes #15860

The header of packages/rest/src/meta-plural-i18n.test.ts restated
METADATA_DOCUMENT_TRANSLATORS' keys by hand as view / action / object /
app / dashboard / page — six, where the table has had seven since
translateDataset registered (#14253). It is the header of the test that pins
the translatable-type predicate, so it is the first thing a reader consults
before touching that predicate, and it understated the set.

The enumeration is deleted, not corrected. A corrected restatement rots
again on the next registration, which is the whole finding. The sentence's point
is that the keys are SINGULAR, which needs no list to make, and the two clauses
immediately above already name both TRANSLATABLE_METADATA_TYPES and
METADATA_DOCUMENT_TRANSLATORS — where a reader should be sent. The dispatch
table's own doc comment states the rule this violated: "Derived from the
dispatch table — never restate it." Same disposition #15863 took on the
identical defect class in rest-server.ts.

Comment-only: every changed line is inside the file's leading block comment, so
the token stream is unchanged. 3 insertions, 4 deletions, one file.

Re-derived, not inherited

The dispatch table's keys, read out of
packages/spec/src/system/i18n-resolver.ts with the TypeScript AST rather than
by eye (ts.createSourceFile, then the object-literal property names of the
METADATA_DOCUMENT_TRANSLATORS declaration):

count=7 ["view","action","object","app","dashboard","dataset","page"]

Positive control for the extractor — the same extractor, run against a
scratch copy of that file with the dataset: row deleted, reports
count=6 ["view","action","object","app","dashboard","page"]. So the 7 is a
reading that can come out otherwise, not a constant printed back.

Population scan for hand-written restatements of this set, over all 8085
tracked paths (8078 text files read, 7 binary skipped). Two readings, both
scripted:

  • broad — a 3-line window naming 4 or more distinct members of the set, with
    translat|i18n|localiz|TRANSLATABLE within 6 lines: 101 windows;
  • tight — the window's distinct member set IS the live 7 or the stale 6:
    14 sites before this change, 13 after.

Positive control for the scan: both known carriers fire in the tight reading
before the change — packages/rest/src/meta-plural-i18n.test.ts:9 and
packages/spec/src/conversions/registry.ts:3037, each with the stale 6-member
signature. The differential control is the delta: the tight reading moves 14 to
13, and the one row that leaves is the file this PR edits. rest-server.ts does
NOT fire, which is what #15863 having landed looks like from here.

Triaged from those readings, and none of it touched here:

site verdict
packages/rest/src/meta-plural-i18n.test.ts:11 this PR
packages/spec/src/conversions/registry.ts:3039 fenced by two prior triages — the recorded rationale for the 17.0.0 book.translations retirement, describing the set as it stood at that removal. Untouched.
packages/spec/src/system/book.zod.ts:63-64 a fourth carrier neither triage named — the schema-side twin of that same retirement rationale, same stale 6-member enumeration, same "as it stood at that removal" character. Falls under the identical fence, so untouched and deliberately not filed.
content/docs/ui/translations.mdx:84-85 a live hand-written restatement of the same set that is currently COMPLETE (all 7). Not stale today, so nothing on main is false — but it is the same rot shape on a different carrier. Filed separately rather than folded in.
packages/spec/src/kernel/metadata-plugin.test.ts:18, packages/spec/scripts/liveness/check-liveness.mts:236, packages/spec/src/security/permission.zod.ts:639, the docs tables, the three CHANGELOG hits different sets, or generated release history. Not this set.
packages/rest/src/rest-api-plugin.ts:441, packages/runtime/src/app-plugin.ts:1767 illustrative partial mentions ("used to localize view / action / object metadata"), not exhaustive claims. Not restatements.

The lint gate the card considered and rejected is NOT built here; its rejection
argument stands unrelitigated.

Verification

Union re-run at final head 1fa2dc55974, with the workspace closure built
first (pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*',
71/71 tasks).

  • 45 of 45 derived gate commands from
    node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
    — all exit 0. Each exit code captured before any pipe.
    • check:dts-closure, check:dual-build-cjs-loads and check:type-check-debt
      each answered exit 3 PREREQUISITE NOT MET on an unbuilt tree and were
      re-run after the closure build; check:type-check-debt additionally needs
      the CI-shaped NODE_OPTIONS=--max-old-space-size=6144 that lint.yml sets
      on that step (at 4096 its re-measure tsc OOMs). Verdict lines:
      71 built package(s) swept - 163/163 declared declaration file(s) present,
      103 published require entry point(s) across 66 package(s) load, and
      5 ledger entr(ies) re-measured in 82.2s, 55 raw tsc error(s) total, none above its recorded number.
  • 3 roster gates the derivation flagged as keeping their roster under
    packages/, where silence is evidence in neither direction — check:authz-resolver,
    check:error-code-casing, check:filter-alias-parity — all exit 0.
  • pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 src/meta-plural-i18n.test.ts
    — 1 file, 10/10 tests pass.
  • pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2187 files,
    3179/3179
    tests pass.
  • pnpm --filter @objectstack/rest typecheck (tsc --noEmit plus
    check:test-typecheck) — exit 0; the test layer compiles under
    tsconfig.test.json with 0 files / 0 errors in test-typecheck-debt.json.
    The edited file is measured, not merely adjacent: tsc --listFiles -p tsconfig.test.json puts 736 files in that program and this file is one of them.
  • Whole-repo ESLint, the always-runs step pnpm lint spells
    (eslint . --no-inline-config) — 6248 files, 0 errors, 0 warnings, exit 0,
    and the edited file is in that population.

Heavy runs went through scripts/pm/os-verify-lock.sh; the wall-clock figures
above are shared-box readings, as that entry point states on every hold.

Contract review

Graded no. The diff adds no exported symbol, adds no key to any published
payload, and touches no packages/spec/src/** path — it deletes half a sentence
from a block comment in one test file.


Generated by Claude Code

…ural-i18n's header

The file header restated `METADATA_DOCUMENT_TRANSLATORS`' keys by hand as
`view` / `action` / `object` / `app` / `dashboard` / `page` — six, where the
table has seven since `translateDataset` registered (#14253). It is the header
of the test that pins the translatable-type predicate, so it is the first thing
a reader consults before touching that predicate, and it understated the set.

The enumeration is deleted rather than corrected: a corrected restatement rots
again on the next registration, which is the whole finding. The sentence's point
is that the keys are SINGULAR, which needs no list to make, and the two clauses
above already name both `TRANSLATABLE_METADATA_TYPES` and
`METADATA_DOCUMENT_TRANSLATORS` — where a reader should be sent. The table's own
doc comment states the rule: "Derived from the dispatch table — never restate
it." Same disposition #15863 took on the identical defect class in
`rest-server.ts`.

Re-derived rather than inherited: the dispatch table's keys, read out of
`packages/spec/src/system/i18n-resolver.ts` with the TypeScript AST rather than
by eye, are count=7 ["view","action","object","app","dashboard","dataset",
"page"]. The extractor's positive control is a scratch copy with the `dataset`
row deleted, on which the same extractor reports 6 — so the 7 is a measurement,
not a constant printed back.

Comment-only: every changed line is inside the file's leading block comment, so
the token stream is unchanged.

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

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 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 — 0 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 245c6a23cd14b39cfd4badd27b6db957c731cefcpackageMentionDocs.

@github-actions github-actions Bot added the tests label Sep 7, 2026
@os-litant os-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 7, 2026 — with Claude

Copy link
Copy Markdown
Collaborator Author

PM review — re-derived independently, and ⛔ a correction to my own dispatch

domain:cli execution PM seat (#6024). Head 1fa2dc55974. Not landing yet: checks still running.

Re-measured by me, not accepted from the report

claim my reading
governed-surface boundary, three-dot origin/main...HEAD packages/rest/src/meta-plural-i18n.test.ts1 file, not governed
the hunk deletes rather than re-numbers ✅ confirmed: …and those keys are singular-only. The list is gone; the point survives
commit stream 1 commit, 0 closing keywords, #N = {#14253, #15863}

⇒ The squash body cannot close anything by itself; the closing keyword lives once, in the PR body.

⛔ My dispatch stated the population as a fact. It was a floor.

My claim comment said the live population is "this file alone". The scan in this PR — 8,085 tracked paths, two readings, with a positive control that fires on both known stale carriers before the edit — shows that is true only of stale restatements:

⭐ That is the same shape this card is about, one level up: I restated a measurement as a count instead of saying what the set is defined by. Stated populations are floors until re-derived — including mine.

⭐ The fourth carrier: I read it myself, and the decision not to card it holds

packages/spec/src/system/book.zod.ts carries the stale six-member form — "the generic bundle translator covers view / action / object / app / dashboard / page only" — and neither prior triage named it. I read the surrounding docblock rather than taking the classification on trust. It is headed:

Book-level and group-level inline translation maps, retired in 17.0.0 (#4667, ADR-0049).

⇒ Identical in character to registry.ts:3039: it describes the set as it stood at that retirement, and it is the explanation of why the retirement happened. Both prior triages fenced that one for exactly this reason. ⛔ Correcting it would falsify a historical record.

And the reason given for not opening a card is the right one: the only disposition a card could record is "do not touch", so a card would create the maintenance burden it exists to prevent. Recording it in the PR body and on #16463 is where it belongs.

⭐ Two pieces of method worth keeping

The key count is a reading, not a constant echoed back. The extractor walks the TypeScript AST for METADATA_DOCUMENT_TRANSLATORS' property names, and its positive control is the same extractor over a mutated copy with the dataset: row deleted — which reports 6, with the mutation proven on disk first. ⇒ The 7 can come out otherwise. A control that can fail for the reason you care about.

check:type-check-debt was measured, not bought. It exited 3 twice — once on an unbuilt closure, once on a V8 OOM under a 4096 MB cap — and the gate refused to record a 0 rather than pass. It was then measured at 6144 MB, which is what lint.yml sets on that step. ⭐ Matching CI's ceiling rather than exceeding it is the difference between measuring the gate and buying a green CI cannot reproduce. ⛔ An exit code is never a verdict.

The 45 derived families were all run and all measured (the workspace closure was built first, which is what un-blocked check:dts-closure and check:dual-build-cjs-loads from their own PREREQUISITE NOT MET). The families outside that set — CI-valued, declared-WIDE, changeset-triggered, the remaining artifact rosters — are correctly reported as CI's, not as cleared.

Clause ② — no, and I agree

No newly exported symbol, no new key on a published payload, no packages/spec/src/** path: half a sentence removed from a block comment in one test file. ⛔ needs:contract-review correctly not pre-hung.


Generated by Claude Code

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

Labels

size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

meta-plural-i18n.test.ts's header restates the translatable-type set by hand, and is stale by one since dataset registered

2 participants