Skip to content

docs(spec): translation liveness WALK BOUNDARY excepts settingsCommon and states its own boundary - #16567

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-16135-liveness-translation-walk-boundary
Sep 7, 2026
Merged

docs(spec): translation liveness WALK BOUNDARY excepts settingsCommon and states its own boundary#16567
huangyiirene merged 1 commit into
mainfrom
claude/issue-16135-liveness-translation-walk-boundary

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #16135

What changed

packages/spec/liveness/translation.json only — two sentences of prose — plus a patch changeset. No status value moves at any nesting level; no schema, export or authorable key moves.

  1. The _note header's WALK BOUNDARY sentence: every group is a z.record keyed by target names becomes every group but settingsCommon is a z.record keyed by target names, followed by two new sentences stating what the boundary IS for that group (below).
  2. The datasets row's WALK BOUNDARY as for every other group here — the second instance the triage found, which inherited the universal by reference — becomes as for the other RECORD groups here (the header names the one group that is not a record). Its content was already right (datasets is a record; the drill sees its value shape one level) and is unchanged.

The summary-count sentence in the same header (A BOUNDARY and not a total, deliberately: …, #15775 via PR #16138) is byte-identical to the base — verified by diffing that span of _note between b1b978c8df and HEAD. #15775 is not addressed here.

The choice, and why: option 1 — except settingsCommon and state its boundary

The card names three repairs and declines to pick. I took the first; the other two were rejected on measurements, not preference:

  • Option 2 (grow settingsCommon a declared blanket verdict of its own) is already in place. scripts/liveness/undrilled-containers.baseline.json carries translation/settingsCommon as one of its 58 container rows — alongside the seven record groups whose value shapes are undrilled (apps, dashboards, globalActions, metadataForms, objects, pages, settings) — and check:liveness --undrilled prints translation/settingsCommon 1 key(s): sourceLabels. The blanket verdict was never undeclared; what was wrong was the header's account of WHERE the walk's one level lands for that group. No new pinned artifact is added, so the triage's flip condition is not met: 「⛔ 若承接席在动手后发现某一支要求给 settingsCommon 新增一条 undrilled-containers.baseline.json 形状的 blanket verdict(那会新增一个受钉的产物),请在 PR 里说明并把本卡改挂 needs-user-decision」— the header now CITES that row rather than creating one.
  • Option 3 (narrow the claim) would make the header say less than the ledger knows. The sentence is the file's declaration of its walk granularity, the premise every per-row blanket verdict leans on. For settingsCommon the boundary differs in KIND — the one level lands on a named member, not on a record's value shape — and the keys beneath it are a closed set rather than author-chosen target names. A reader asking whether tenant is a ledgered key needs exactly that stated, not elided.
  • Option 1 keeps the universal true and says what is true instead. The new sentences state where the walk's one level lands for settingsCommon (sourceLabels), that the layer keys beneath sit below the boundary, who reads them, and that the blanket verdict over them is the declared kind, citing the baseline row. No integer totals were introduced — the discipline spec(liveness): translation.json header says "11 of 12 groups live" while its own props hold 11 groups with 10 live #15775 applied to this header.

sourceLabels, looked at rather than assumed

Read off packages/spec/src/system/translation.zod.ts (lines 1198–1218 at b1b978c8df) and probed with safeParse on TranslationDataSchema:

  • settingsCommon is a strictObject with one named member, sourceLabels; catchall never.
  • sourceLabels is a strictObject of exactly five optional strings — env, global, tenant, user, default, the ADR-0010 resolution layers; catchall never. Its own comment: "The layers are a closed set (ADR-0010 / the settings resolution order), so an unknown one here is a badge that will never render, not a layer the platform is about to grow."
  • The closure is enforced, not merely described. safeParse({ settingsCommon: { sourceLabels: { env: 'Env', workspace: 'Workspace' } } }) gives success: false, code unrecognized_keys at path settingsCommon.sourceLabels, message beginning Unrecognized key(s) on the settings source-badge labels: workspace. Did you mean workspacetenant?. The retired spellings (org / workspacetenant, systemglobal, fallbackdefault, environmentenv) are declared as aliases, so the rejection points at the layer meant and never accepts them. The legal pair { env, tenant } parses.
  • Readers: resolveSettingsSourceLabel (packages/spec/src/system/i18n-resolver.ts:2570, reads settingsCommon?.sourceLabels?.[source] with source typed to the five-literal union) and objectui's useSettingsLabel().sourceLabel (apps/console/src/pages/settings/useSettingsLabel.ts:141 at objectui 51a402f, resolveCommon('sourceLabels.' + source) over every namespace carrying a settingsCommon block). Both read the five keys as one unit beneath the boundary; no reader addresses a sixth.

Eleven-group census, re-taken at b1b978c8df

Off TranslationDataSchema — whose shape is translationDataShape() and nothing else — unwrapping lazy/optional wrappers (the probe script is quoted in the report comment on the issue):

group zod def value / member keys
objects record object: label, pluralLabel, description, fields, _views, _actions, _sections, _tabs, _validations
apps record object: label, description, navigation
messages record string
globalActions record object: label, description, confirmText, successMessage, params, resultDialog
dashboards record object: label, description, actions, widgets
datasets record object: label, description, dimensions, measures
pages record object: label, description, title, subtitle, components
flows record object: label, screens
settings record object: title, description, groups, keys, actions
metadataForms record object: label, description, sections, fields
settingsCommon object sourceLabels

records=10 objects=1 — the card's reading at 1f2a02ba still holds at b1b978c8df.

Clause-②: no — measured, and both gates proven able to go red

No export, no authorable key, no accept-set movement. check:api-surface: @objectstack/spec public API surface + factory signatures unchanged ✓ (exit 0). check:authorable-surface: authorable-defaults/ verified against upstream b1b978c8df15 — 1211 default(s) unchanged, 1585 schemas generated (exit 0). The spec build left the tree clean, so every regenerated artifact is byte-identical.

Red-proof on the CHECKED-IN baselines, no rebuild (the mutate-build-check trap the dispatch named is therefore not in play):

leg mutation (checked-in shard) anchor blob HEAD → disk gate predicted observed
api-surface api-surface/system.json, row "TranslationDataSchema (const)" removed 1 → 0 d1b46c8a41d189 check:api-surface exit 1 exit 1 — public API changed: 0 breaking (removed/narrowed), 1 added.
authorable-surface authorable-surface/system.json, row "system/TranslationData:settingsCommon" removed 1 → 0 853963456b98a4 check:authorable-surface exit 1 exit 1 — ❌ authorable-surface/ is out of date (1 key(s) not recorded).

Neither gate rewrote the shard (blob unchanged after the run). Restores: git checkout HEAD -- PATH, then git diff HEAD empty, blob hash equal to HEAD's, anchor count back to 1, git status --porcelain empty; the script carried an EXIT INT TERM trap with absolute paths.

Verification

Every exit code below was captured by redirect-then-capture, never through a pipe; verdict lines are the gates' own.

  • Build: pnpm --filter '@objectstack/spec^...' build matched no projects (spec has no workspace deps); pnpm --filter @objectstack/spec build under the verify lock: VERDICT command-exit 0, tree clean after.
  • pnpm --filter @objectstack/spec check:liveness: ✓ every governed-type property at the walk's one-level granularity is classified … every container inheritance is declared … and ✓ state-counts.md is current — the same 36 row(s) (exit 0). Read as shape-only, per the dispatch: it caught nothing about the sentence and was not expected to.
  • pnpm --filter @objectstack/spec typecheck (tsc, check:scripts-typecheck, check:test-typecheck) under the lock: VERDICT command-exit 0.
  • Tests under the lock, VERDICT command-exit 0: spec vitest run scripts/liveness scripts/zod-graph.test.tsTest Files 12 passed (12), Tests 314 passed (314); lint vitest run src/lint-liveness-properties.test.ts src/component-field-specs-liveness.test.tsTest Files 2 passed (2), Tests 75 passed (75).
  • pnpm check:nul-bytes: OK (scanned 8145 text file(s) … no raw ASCII control bytes); plus a control-character self-scan of both touched files: no hit.
  • Gate roster from node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at df3ad1c0c2 (merge-base b1b978c8d, 2 paths): 53 families derived, 53 run, --ran reconciliation 53 run, 0 NOT-MEASURED, 0 UNRUN. 52 exit 0. check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET … ⛔ This is NOT a pass: nothing was measured (80 sibling packages have no dist/ in this worktree) — declared to CI, not read as red or green. check:dts-closure (40/40 declaration files) and check:sourcemap-no-sources-content (52 maps) measured the 4 packages built here (spec, formula, sdui-parser, lint); CI's population is every built package.
  • Newer-tree re-derivation: the reconciliation flagged the derivation tree as 8 commits behind origin/main, so the same two paths were re-derived from a detached worktree at 90e7e6de11 — 53 families, none added, none dropped relative to the set run.

Affected-package narrowing, declared

turbo ls --affected from b1b978c8df lists 76 of 81 packages: spec plus every dependent. Run here: spec (typecheck, and the vitest sets above) and lint (the one runtime reader of the shipped liveness/ directory: packages/lint/src/lint-liveness-properties.ts:66). Declared to CI: the two cli unit tests that read the real flows row through @objectstack/lint (packages/cli/test/i18n-flow-liveness-gate.test.ts, packages/cli/test/i18n-flow-screen-coverage.test.ts — cli's workspace closure is 49 packages, unbuilt here), and the remaining dependents' suites. Why this is a measurement rather than a skip: git grep over tracked *.ts / *.mts / *.mjs / *.tsx finds no import of liveness/translation.json; every reader of the ledger is one of the liveness scripts (run), the lint rule (run), the two cli tests (declared), or a gate (run); and the diff is a string literal in a JSON data file plus a changeset, with every status value those readers consult untouched.

Changeset

Owed and added — .changeset/translation-liveness-walk-boundary.md, @objectstack/spec: patch. liveness/ is in @objectstack/spec's files array, so the _note ships in the npm tarball, and the same-file precedent (PR #16138 for #15775) carried one. Not skip-changeset.

Not touched

validation.json / view.json / state-counts.md (#16542) and manifest.json / README.md (#16532): untouched, no collision. No per-prop status moved. No other ledger's similar wording was harmonised (the triage's ⛔). Draft; not flipped ready, not enqueued.

🤖 Generated with Claude Code


Generated by Claude Code

…n` and states its boundary

The `_note` header claimed every translation group is a z.record keyed by target
names. Measured off `translationDataShape()`, ten of the eleven are; `settingsCommon`
is a fixed strictObject whose one member `sourceLabels` is itself a fixed strictObject
keyed by the ADR-0010 resolution layers, a closed set. The sentence now excepts it and
states where the walk's one level lands for it (`sourceLabels`, the walker's own
`--undrilled` reading), that the layer keys beneath sit below the boundary, and that
its blanket verdict is the declared kind (a row of undrilled-containers.baseline.json
already). The `datasets` row's "as for every other group here" inherited the same
universal by reference and now cites the record groups only.

Prose only: no `status` moves, no schema change, no gate verdict change. The
summary-count sentence in the same header is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
@github-actions github-actions Bot added the size/s label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/translation.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/translation.json) — pages documenting those are invisible to this run
  • 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 — 130 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 90e7e6de114af2586da89dd417101b24db716d39packageMentionDocs.

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/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] spec(liveness): translation.json's WALK BOUNDARY sentence claims "every group is a z.record" — settingsCommon is a plain strictObject

2 participants