Skip to content

docs(i18n): restate the orphan-key table from the emitter, sibling packages included - #19839

Draft
objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/issue-19626-i18n-must-name-table
Draft

objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/issue-19626-i18n-must-name-table

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19626
Clause-②: no

What changed

The orphan-key table under Orphan Keys and Option Keys in content/docs/protocol/kernel/i18n-standard.mdx is rewritten as one unit, row by row from the emitter of translation-target-unknown on origin/main (1cacfe4a). It no longer uses the old rule.

  • Row 1 was false and is corrected. objects.{object} said "an object this stack defines, or a platform object". On the per-package pass, an object that a sibling package of the same artifact declares also resolves, and its subtree is judged against that sibling's declaration. The row now says so. It also names rung 2b, which was missing: an object an objectExtensions[] entry extends but no package of the artifact declares is skipped whole.
  • "Declared" is now defined once, above the table. It means declared by the stack being checked or by a sibling package of the same artifact. The six vague rows (_views, _sections, _actions, apps.*, dashboards.*, globalActions) now inherit that meaning instead of each implying "this stack". A short rule also covers what happens when the package and a sibling declare the same name: the package's own record is used to judge options, params, widgets and header actions, and flow screens.
  • Rows the emitter judges but the table never listed are added: _tabs, _validations, flows.{flow}, .screens.{node} and .fields.{field}. The contributed-into app level (navigationContributions) is also added.
  • Rows that were vague but not false are made exact: _views (the key the registry assigns, default for an unnamed default list), _sections (all three anchors), fields (extension-merged fields and system columns), and globalActions (a bound action gets a redirect, not a match).
  • content/docs/deployment/validating-metadata.mdx: the per-package sentence ("so a sibling package's object still resolves") now also names the collections a translation key resolves the same way, and links to the table.

The emitter covers more than the card listed. The card named six understated rungs. artifactProvidedRecords is also called for flows and pages, and pages feeds _tabs and record:details _sections. So a sibling's flow, filter-preset tab or page section resolves too. Where the emitter and the card disagree, the table follows the emitter.

Code sites each row is backed by

All in packages/lint/src/validate-translation-references.ts at 1cacfe4a:

Row Site
sibling reach (all rows) artifactProvidedRecords :919 (reads packages[].manifest.COLLECTION); calls for objects :1019, views :1081, pages :1114, actions :1152, apps :1211, dashboards :1282, flows :1331
own-record precedence ownDeclaration in collectObjectRecord :950, collectActionRecord :1137, collectDashboardRecord :1261, collectFlowRecord :1306
objects.{object} :1379-1421: universe hit, isPlatformProvidedObjectName skip, universe.extended skip (rung 2b), otherwise orphan; objectExtensionsByTarget :834 reads stack and packages[]
.fields.{field} IMPLICIT_FIELDS :284 (SYSTEM_FIELDS + _id/name/space); extension fold :1042-1070; check :1423
.options.{key} checkOptionKeys :1778 (warning, translation-option-key-unknown)
._views.{view} collectViewRecord :421, defaultListViewKey :574, namedViewKeys :612 (composer-derived keys)
._sections.{section} fieldGroups[].key in collectObjectRecord; addSections for formViews, the default form and the view record in collectViewRecord; record:details properties.sections in collectPageRecord :1093
._tabs.{tab} collectPageTabs :525 (interfaceConfig.source, else page.object; userFilters.tabs[].name); check :1484
._validations.{rule} collectValidationRuleNames :238 (conditional branches), extension fold; check :1513
._actions.{action} / .params.{param} collectActionRecord (owner = objectName / object); checkActionParams :1834
globalActions.{action} :1564-1597, bound-action redirect via actionOwners
apps.{app} / .navigation.{id} collectAppRecord (declared + sibling), contributedNavItemsByApp :738 (stack manifest + packages[]), contributedOnlyApps pass; check :1599-1652
dashboards.* collectDashboardRecord; check :1653-1695
flows.* collectFlowRecord (walkFlowNodes, type: 'screen', config.fields[].name, object-form diagnosis); check :1696-1760

The sibling behaviour for each rung is pinned in validate-translation-references.test.ts, in the two describe blocks for objects a sibling package of the artifact declares (from :1253) and for collection rungs a sibling package declares (from :1463).

Scope and changeset

Docs only: content/docs/**, which is not a governed surface and publishes no package. No .changeset file is needed; by the files[] criterion this is skip-changeset territory, and the label is left to the PM seat. skills/objectstack-i18n/SKILL.md is deliberately not touched, per the triage ruling.

Verification

  • Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at head c61ae6d4: 40 commands. All 40 ran with exit 0. Four of them (check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift) first exited 3 (PREREQUISITE NOT MET, nothing measured). I built their named prerequisites (the lint, formula and client-react closures, plus spec) and re-ran them: all exit 0.
  • --ran reconciliation: "40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN", which it calls a derived zero because every line recorded an exit code.
  • Relevant verdicts: check-doc-anchors: 368 internal #fragment link(s) across 410 source file(s) all resolve to a real heading (this covers the two new links); check-nul-bytes: OK; check-doc-frontmatter OK.
  • NOT MEASURED locally, left to CI: the Build Docs job (the Next.js docs build), the type-check lanes and the other families listed outside the derived set.

Acceptance notes

  • The ladder comment in the emitter's own header (validate-translation-references.ts:122-123) still says rungs 3 and 4 "warn on the object key only", but both go through orphan() at TRANSLATION_TARGET_UNKNOWN_SEVERITY = 'error'. This is comment drift inside the code, not a defect under class a, b or c, and it was not changed here (docs-only scope). No carrier.
  • collectViewRecord also registers a view record's root name as a _views key. The table describes the composer's keys (map key, or default) as the canonical spelling and does not list this edge.

Generated by Claude Code

…ckages included

The "Must name" table under Orphan Keys and Option Keys still stated the
pre-fix rule: `objects.{object}` resolved only against "an object this stack
defines", which is false on the per-package pass, where a sibling package of
the same artifact is resolution context. Rewrite the table as one unit from
`validate-translation-references.ts`: define "declared" once (this stack or a
sibling package), add the rungs the emitter judges and the table omitted
(`_tabs`, `_validations`, `flows.*`, contributed-into apps, objectExtensions
targets), and extend the per-package sentence in validating-metadata.mdx to
the collections that resolve the same way.

Claude-Session: https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c61ae6d474d2280767a9b35462e43f85ac581eed

① Derived judgments

All against packages/lint/src/validate-translation-references.ts on origin/main unless noted.

  • "Declared = this stack or a sibling package of the same artifact": artifactProvidedRecords :919-927 reads packages[].manifest[collection]; folded for objects :1019, views :1081, pages :1114, actions :1152, apps :1211, dashboards :1282, flows :1331. True.
  • "keys beneath it are judged against the sibling's own declaration … a typo under a sibling's object is still an error": sibling objects go through the same collectObjectRecord (:1019-1021) and their fields/views/etc. are then checked at :1423-1590. True.
  • "own record wins for options, params, widgets/header actions, flow screens": ownDeclaration guards at :960/:966 (fields/actions), :1137-1139 (bound actions), :1261-1264 (dashboards), :1306-1309 (flows). True. (For same-named dashboards/flows the sibling record is skipped whole; the sentence's "every other name … adds up" is accurate for the Set-add facts — views, sections, tabs, validations, nav ids.)
  • objects.{object} row: universe hit else isPlatformProvidedObjectName skip else universe.extended skip else orphan :1379-1400; objectExtensionsByTarget :834-850 reads stack + packages[]. True.
  • .fields.{field} row: IMPLICIT_FIELDS :284-287 = SYSTEM_FIELDS (packages/lint/src/system-fields.ts:53-56 = FIELD_GROUP_SYSTEM_FIELDS [audit provenance, organization_id, tenant_id, is_deleted, deleted_at] + SystemFieldName values incl. id, owner_id) + _id/name/space; extension fields folded :1052-1060; check :1423-1426. True (the parenthetical is an illustrative subset; the exemption is unconditional, not per-object injection — imprecise, not false).
  • .options.{key} row unchanged; checkOptionKeys :1778.
  • ._views.{view} row: collectViewRecord :421-471 registers listViews/formViews registry keys (namedViewKeys :612) and defaultListViewKey :574-583 (default when unnamed). True; heading #objectui-integration exists (i18n-standard.mdx:897).
  • ._sections.{section} row: fieldGroups[].key :989-992; addSections for formViews/default form/view record :439-471; page properties.sections :1093-1107. True.
  • ._tabs.{tab} row: collectPageTabs :525-540 (interfaceConfig.source else page.object, userFilters.tabs[].name); check :1484; "list view's own tabs has no renderer" per :488-495 and the emitter's own hint. True.
  • ._validations.{rule} row: collectValidationRuleNames :238-243 recurses then/otherwise; extension fold :1064-1066; check :1513. True.
  • ._actions / .params rows: collectActionRecord owner = objectName ?? object :1137-1148; object-embedded actions :963-968; checkActionParams :1834. True.
  • globalActions.{action} row: bound action → orphan with objects.{owner}._actions redirect :1564-1597. True.
  • apps.{app} / .navigation.{id} rows: collectAppRecord walks navigation (+children) and areas[] (id + navigation) :1157-1191; contributedNavItemsByApp :738-760 reads stack manifest + packages[].manifest; contributed-only apps :1194-1202; check :1599-1652. True.
  • dashboards.* row: widgets id ?? name, header actions actionUrl ?? url ?? name :1264-1278. True.
  • flows.* rows: flow.name; walkFlowNodes (packages/lint/src/flow-walk.ts:196-240, branches/regions with depth); type: 'screen' + config.fields[].name :1306-1327; object-form diagnosis :1737-1745. True.
  • validating-metadata.mdx addition ("so does a translation key naming a sibling's view, page, action, app, dashboard or flow"): the seven folds above. True; link target #orphan-keys-and-option-keys exists (i18n-standard.mdx:1014).
  • No accept set or public surface touched; Clause-②: no is right. No generated/release/governed path; skills/objectstack-i18n/SKILL.md untouched.

② Semver level

Docs-only content/docs/** (two files); not in any files[]; no .changeset/*.md. No changeset is correct; skip-changeset is the route.

③ Boundary flags

  • none crossed: skills/** (Tier H, fenced by triage) untouched; PR feat(spec)!: split the translation bundle type — settings is a platform group, not a per-app one (#15178) #19600 serial rider cleared (merged before claim).
  • Minor imprecision, not misleading: .fields row's "a system column the registry injects" reads as per-object injection while the exemption is the full SYSTEM_FIELDS set unconditionally (:284-287); _sections row names only record:details while the emitter reads properties.sections on any object-bound page component (:1099-1105) — matches the emitter's own diagnostic wording.

Implemented-by: claude/issue-19626-i18n-must-name-table
Reviewed-by: session_01VDtqoecgES7ScQYGbFVDRv

VERDICT: PASS

Isolated at-tier reviewer, adopted by the domain:devx#1 seat. Reviewed with the seat's own ACCEPT excluded from its inputs.


Generated by Claude Code

This branch has not been deployed

No deployments
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

Projects

None yet

1 participant