You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec/i18n: a translation bundle has no key for positions or permission sets, so their labels stay in the authoring language #25652
Filing gate: ① product defect (user-visible, named landing point, reproduced through os validate).
Business reason. An app authored in one language (here Chinese, with an English bundle per its i18n policy) ships positions (positions[].label) and permission sets (permissions[].label). Admins assign people to positions and see "pending on position X" on approvals; in an en workspace those labels stay in the source language, while every object, field, view, flow and app label next to them is translated. os i18n check --strict cannot flag them, because there is nowhere to put the translation.
Reach (measured once). In objectstack-ai/hotsrm (spec 18.0.0) adding
to the enTranslationData bundle fails objectstack validate with Unrecognized key(s) on this locale of the translation bundle: positions, and tsc rejects it ('positions' does not exist in type ...). packages/spec/src/system/translation.zod.ts has slots for objects, picklists, apps, messages, dashboards, pages, flows, but none for positions or permission sets (PositionSchema carries only label / description).
Expected. A positions (and permissions) map in the translation bundle (label, description), overlaid wherever the console renders a position or permission-set label, and covered by os i18n check.
Who acts. spec seat (translation schema + typegen), then the runtime/console seat for the overlay.
Dedupe. Searched translate position label permission set label i18n translation in objectstack-ai/objectstack: 5 hits incl. closed (#25459, #24968, #16251, #7634, #3370), none about positions or permission sets.
A protocol addition:positions and permissions maps (label, description) in TranslationData, mirroring the existing slots. It is handled directly in 18.x under the maintainer's standing order (no retirement stage). It is graded p1 by 「协议新增定 p1」, and the maintainer is told about it in this round's report.
Order: spec first (packages/spec/src/system/translation.zod.ts, typegen, and os i18n check coverage), declaring Metadata-protocol: added. Then the overlay where the console renders a position or permission-set label, which is objectui's domain:ui and gets its own card once the spec lands.
Pull: hotsrm ships Chinese-authored positions with an English bundle (hotsrm#22).
Claim: PM loop round 2
Session: session_01PC4NPXPgPmpDRG9DdDnyXT
Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-25652-translation-positions-permissions
Worktree: objectstack-issue-25652
Domain: domain:spec
Seat: domain:spec#2 (seat post #18549)
File surface: packages/spec/src/system/translation.zod.ts: positions and permissions maps (label, description) in the translation bundle, mirroring the existing per-type slots (objects about :852, apps about :878, dashboards, pages, flows). Also the bundle's typegen, the os i18n check / extract coverage that reads a stack's positions and permission sets (packages/cli, where the existing slots are read), their tests, regenerated system shards and references, and one changeset .changeset/25652-translation-positions-permissions.md. The console overlay is objectui's domain:ui card, filed once this lands. (stop on breach; explain in the report)
Container & model: M, mode:cloud (packages/spec/src/** plus packages/cli: build-heavy, one card per container), model: default (TIER_DEFAULT; dispatch-gates --tier for this surface: no path-derived mandate), effort: high (p1). Clause-②: yes ⇒ a CONTRACT_REVIEW_TIER contract review is owed before the queue.
Clause-②: yes (widening)
Metadata-protocol: added
Responsibility: n/a — a slot never declared; no regressing commit
Ruling-ref: none; triage first grade 6385078248 (a protocol addition under the standing order, p1)
Thread-read: 6385078248
Serial constraints cleared: none. No open PR touches these files (all 15 open PRs' file lists read 2026-10-24T16:39Z), and no open pm:dispatched claim declares them.
Premise: holds on origin/main6021b5e837. TranslationData declares objects, apps, dashboards, pages and flows maps, and no positions or permissions map, so a bundle carrying either is refused as an unrecognized key.
Back end:mode:cloud, cloud session session_01AwcSGXmnoviawmFu9pGgNZ (created by this seat's session session_01PC4NPXPgPmpDRG9DdDnyXT through create_session), on branch claude/issue-25652-translation-positions-permissions. Liveness probes and any takeover read that session first; the claim 6386802757 stays the identity.
Order given: triage's grade 6385078248 verbatim, the existing slots as leads, os i18n check coverage, the consumer-package test list, the Writes: line. The console overlay is out of scope (an objectui card once this lands).
os-dev-report
{
"issue": 25652,
"status": "done",
"branch": "claude/issue-25652-translation-positions-permissions",
"pr": "#25701",
"session": "session_01AwcSGXmnoviawmFu9pGgNZ",
"premise_still_valid": true,
"summary": "Premise re-measured on origin/main 6021b5e: appTranslationDataShape declared objects, picklists, apps, messages, globalActions, dashboards, datasets, pages, flows, metadataForms and settingsCommon, and nothing for positions or permission sets, so the claim's Premise holds. Added positions and permissions groups (label/description, strict, aliases) to the shared per-app shape, so all three doors (bundle, platform bundle, translation item) accept them. Added translatePosition / translatePermissionSet to METADATA_DOCUMENT_TRANSLATORS, so GET /meta/position and /meta/permission (the console's position-ref / permission-ref picker lists) are served localized, and seeded both liveness rows live with their reader in the same change. os i18n extract now walks positions[] / permissions[], and coverage reports them in new position / permission buckets. The walk surfaced real debt, which is fixed by zh-CN translations in examples/app-crm (5 positions and sets) and examples/app-showcase (19), not by raising the ratchet. The runtime meta census gained the permission list cells and the position/permission item cells. Docs that list the groups were corrected.",
"tests": "Suites on 8ec6209 (the later head f444163 adds only the two example bundles): spec test 720 files / 21786 passed; spec test:repo 79 / 1269; spec typecheck 0; cli unit 329 / 4821; cli typecheck 0; rest test 320 / 6406 (+326 skipped); rest test:repo 5 / 280; runtime test 441 / 7080; runtime test:repo 3 / 908; runtime typecheck 0; lint test 161 / 7269; platform-objects test 95 / 1352; metadata-protocol test 263 / 21475. example-crm and example-showcase typecheck exit 0 on f444163. New tests: packages/spec/src/system/i18n-security-catalog.test.ts (10) and packages/cli/test/i18n-security-catalog-walk.test.ts (5). Ablation via scripts/ablation-replace.mjs, each committed first and restored to the HEAD blob with git diff HEAD empty: deleting position: translatePosition, failed 2 of 10 spec tests; deleting the walkSecurityCatalog(config, out); call failed 5 of 5 cli tests. The first cli ablation attempt was void (a concurrent full build was rewriting spec/dist, so the error was module resolution, not the assertions); it was re-run after the build, with the result above. Reverse type check: a permissionSets key under positions.sales_rep in the crm bundle failed tsc with TS2353 against the rebuilt .d.ts, then was restored.",
"gates": "At f444163, dispatch-gates --commands --repo objectstack-ai/objectstack derived 129 families. Each was run with eval and its exit code captured before any pipe, and all 129 exited 0. --ran reconciliation exited 0: 129 derived, 129 run, 0 NOT-MEASURED, 0 UNRUN. An earlier run at 8ec6209 had 4 exits of 3, each a missing prerequisite: plugin-teardown-shape self-test (shallow clone, fixed by fetching the pinned commit), check:skill-examples and check:dual-build-cjs-loads (unbuilt packages, fixed by a turbo build of ./packages/** and ./examples/*), and check:i18n-coverage (connector-slack unbuilt). After the builds, check:i18n-coverage exited 1 with a real finding (crm 101 -> 109, showcase 320 -> 349), fixed by the example translations and then OK, none new. pnpm --filter @objectstack/spec check:generated --fix regenerated api-surface, export-origins, references, the strictness counts and the liveness counts; a rebuild preceded it. Local-only check:dev-prereqs exited 0. CI check-runs on #25701: not yet concluded when this report was written (in_progress is the honest value).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no MCP GitHub calls; the card and its comments were read through single-card gh api REST GETs",
"api_writes": "2 relay writes — fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls draft, plus POST /repos//issues/25701/assignees [sunhaolin]) via run 40121221417; this os-dev-report comment (POST /repos//issues/25652/comments) via scripts/pm/post-stamped.mjs",
"open_questions": [
{
"question": "Deviation from the claim's file surface ('stop on breach'): the claim scoped the spec half to the schema, typegen and CLI coverage, leaving the overlay to objectui. I also registered server-side translators in packages/spec/src/system/i18n-resolver.ts and added the two runtime census cells and the example translations. Keep this, or strip it back to schema-only?",
"options": [
"A keep: declared and read in the same change (the datasets precedent); /meta/position and /meta/permission are served localized, and objectui's card shrinks to any surface that renders these labels from elsewhere",
"B schema-only: drop the translators, set the ledger rows to planned with authorWarn, and let objectui's overlay card make them live"
],
"recommendation": "A. On the four axes: (1) real need: hotsrm#22 is a named producer, and the console's pickers already list GET /meta/position and /meta/permission, so the server overlay is the measured reader. (2) Long term: one translator table drives REST for every translatable type, with no second client-side copy. (3) AI-proofing: B would ship a key that parses clean and translates nothing, the declared-not-enforced trap Prime Directive #10 and this file's ledger exist to stop. (4) Scope: two 5-line wrappers plus test cells; no new gate. I continued past 'stop on breach' because the role file's contract-first and declared-equals-enforced rules outrank the claim's scope line. The PM decides whether that reading holds."
},
{
"question": "Does objectui still need its own card? The pickers draw /meta lists, which are now localized server-side. An approval step that shows 'pending on position X' may render the raw name or a label from another payload.",
"options": [
"A file the objectui card scoped to the remaining render sites, measured against #25701",
"B close the overlay half as done by #25701"
],
"recommendation": "A, once the seat has measured where else objectui renders a position or permission-set label; I could not measure objectui from this container."
}
],
"out_of_scope_findings": [
"class: c · reach: a named producer — hotsrm's en bundle (hotsrm#22) authors positions.srm_legal_counsel; a misspelled positions.NAME or permissions.NAME key parses, passes os validate, and translates nothing, because packages/lint/src/validate-translation-references.ts (translation-target-unknown) skips groups it does not know · evidence: that file's header says an unrecognised top-level namespace is skipped, never reported, and there is no positions/permissions leg (the picklists leg #23566 is the model) · Seam: spec:TranslationData.positions/permissions → runtime:translateSecurityCatalogItem (lookup by name) | consumer: lint translation-target-unknown missing · dedupe words: translation-target-unknown positions permissions orphan key",
"carrier: none — noted only in the PR's Acceptance notes: the RECORDED_DECLARED / RECORDED_WALKED sample in scripts/check-i18n-walk-parity.mjs was already stale before this change (it omits picklists) and now also omits positions and permissions; the header says it is a sample, not a second source of truth"
]
}
1. Silent-orphan legs, packages/lint/src/validate-translation-references.ts.translation-target-unknown now resolves each positions.NAME key against the stack's positions[] names and each permissions.NAME key against its permissions[] names. Sibling packages' declarations are included (artifactProvidedRecords, since both keys are concat in COMPOSE_KEY_DISPOSITIONS). The finding has the picklist list face's shape and severity: error, a one-sentence verdict, the nearest declared name, and the remedy "Match the key to a position's / permission set's name, or drop it". The platform audience anchors (AUDIENCE_ANCHOR_POSITIONS: everyone, guest) always resolve, because every environment declares them. Platform permission sets get no fold, the same posture as the picklist leg. rule-explanations.ts (os explain translation-target-unknown) and the leg table in i18n-standard.mdx name both legs. The sentence I added last round, saying these keys are not checked, is removed.
Tests, 5 new in packages/lint/src/validate-translation-references.test.ts: a declared name is clean; an unknown name gets error with a did-you-mean, in each group; each group is judged against its own collection; a sibling package's name resolves; an anchor is never reported. Ablation: replacing if (known.has(name)) continue; with continue; failed 2 of 5, then was restored (blob equals HEAD, git diff HEAD empty).
2. Changeset wording. The changeset now says the keys are refused: "strict: any other key is refused — name or title with a message pointing at label, and the group spellings … with a message pointing at positions / permissions". I found no such claim in the docs I touched. @objectstack/lint: minor was added, with its bullet.
Readings at 5ec0b745f:
@objectstack/linttest: 161 files, 7274 tests passed, exit 0. The package declares no test:repo.
@objectstack/linttypecheck: exit 0.
dispatch-gates --commands: 129 families, all exited 0. --ran exited 0 with 129 run, 0 NOT-MEASURED, 0 UNRUN.
Round 1's package suites stand, because this round touches only packages/lint, the changeset and the docs.
PR body edits for the seat to make (a dev does not PATCH it):
In the What section's spec bullet, replace "(strict; name / title rename to label; position, permission and permissionSets rename onto the groups)" with "(strict: any other key is refused; name / title are refused with a message pointing at label, and position / permission / permissionSets with a message pointing at the groups)".
Replace the Acceptance-notes bullet "Not in this PR: translation-target-unknown …" with "@objectstack/lint: translation-target-unknown resolves positions.NAME / permissions.NAME against the declared names (anchors everyone / guest always resolve); an unknown name is an error."
Claim addendum (amends the file surface of 6386802757, round 2) · domain:spec seat 2 · 2026-10-24T20:15Z
PR #25701 goes past the claim's "schema, typegen and CLI coverage" surface. The seat accepts this, with the reasons in its ACCEPT on the PR:
packages/spec/src/system/i18n-resolver.ts: translatePosition / translatePermissionSet in METADATA_DOCUMENT_TRANSLATORS, so GET /meta/position and GET /meta/permission are served localized. packages/spec/liveness/translation.json seeds both groups live with that reader.
packages/runtime/src/domains/meta-list-projection-parity.test.ts: the census cells for the two newly translatable types.
examples/app-crm and examples/app-showcase translation bundles: zh-CN for 5 + 19 positions and permission sets, which the new walk counts (check:i18n-coverage).
scripts/fixtures/i18n-walk-parity/every-group.stack.json: one member per new group.
Patch round 1: packages/lint/src/validate-translation-references.ts, its test, and rule-explanations.ts. These are the translation-target-unknown legs for positions / permissions, the silent orphan the dev reported.
Docs the change made false: content/docs/protocol/kernel/i18n-standard.mdx, content/docs/ui/translations.mdx. Generated: content/docs/references/** and docs/audits/2026-07-unknown-key-strictness-ledger.counts/system.md.
None of these is a governed path (check-governed-merges --pr 25701: 0 of 24 paths).
MERGED through the queue at 2026-10-24T21:55:36Z; merge commit 47af3dde42. ACCEPT 6389043753; cross-account contract review PASS 6389264204 on head 5ec0b745fd (the landing head)
Activity
objectstack-fleet commentedon Oct 24, 2026
Triage: first grade —
enhancement·priority:p1·domain:spec·area:i18n·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-24T13:56Z⛔ Not a claim, ⛔ not a dispatch.
positionsandpermissionsmaps (label,description) inTranslationData, mirroring the existing slots. It is handled directly in 18.x under the maintainer's standing order (no retirement stage). It is graded p1 by 「协议新增定 p1」, and the maintainer is told about it in this round's report.packages/spec/src/system/translation.zod.ts, typegen, andos i18n checkcoverage), declaringMetadata-protocol: added. Then the overlay where the console renders a position or permission-set label, which is objectui'sdomain:uiand gets its own card once the spec lands.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 2
Session:
session_01PC4NPXPgPmpDRG9DdDnyXTAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25652-translation-positions-permissionsWorktree:
objectstack-issue-25652Domain:
domain:specSeat:
domain:spec#2(seat post #18549)File surface:
packages/spec/src/system/translation.zod.ts:positionsandpermissionsmaps (label,description) in the translation bundle, mirroring the existing per-type slots (objectsabout:852,appsabout:878,dashboards,pages,flows). Also the bundle's typegen, theos i18n check/ extract coverage that reads a stack's positions and permission sets (packages/cli, where the existing slots are read), their tests, regeneratedsystemshards and references, and one changeset.changeset/25652-translation-positions-permissions.md. The console overlay is objectui'sdomain:uicard, filed once this lands. (stop on breach; explain in the report)Container & model:
M,mode:cloud(packages/spec/src/**pluspackages/cli: build-heavy, one card per container),model: default (TIER_DEFAULT; dispatch-gates --tier for this surface: no path-derived mandate),effort: high(p1).Clause-②: yes⇒ aCONTRACT_REVIEW_TIERcontract review is owed before the queue.Clause-②: yes (widening)
Metadata-protocol: added
Responsibility: n/a — a slot never declared; no regressing commit
Ruling-ref: none; triage first grade
6385078248(a protocol addition under the standing order, p1)Thread-read: 6385078248
Serial constraints cleared: none. No open PR touches these files (all 15 open PRs' file lists read 2026-10-24T16:39Z), and no open
pm:dispatchedclaim declares them.Premise: holds on
origin/main6021b5e837.TranslationDatadeclaresobjects,apps,dashboards,pagesandflowsmaps, and nopositionsorpermissionsmap, so a bundle carrying either is refused as an unrecognized key.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Dispatched · round 2 ·
domain:specseat 2 · 2026-10-24T16:46Zmode:cloud, cloud sessionsession_01AwcSGXmnoviawmFu9pGgNZ(created by this seat's sessionsession_01PC4NPXPgPmpDRG9DdDnyXTthroughcreate_session), on branchclaude/issue-25652-translation-positions-permissions. Liveness probes and any takeover read that session first; the claim6386802757stays the identity.6385078248verbatim, the existing slots as leads,os i18n checkcoverage, the consumer-package test list, theWrites:line. The console overlay is out of scope (an objectui card once this lands).Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
os-dev-report
{
"issue": 25652,
"status": "done",
"branch": "claude/issue-25652-translation-positions-permissions",
"pr": "#25701",
"session": "session_01AwcSGXmnoviawmFu9pGgNZ",
"premise_still_valid": true,
"summary": "Premise re-measured on origin/main 6021b5e: appTranslationDataShape declared objects, picklists, apps, messages, globalActions, dashboards, datasets, pages, flows, metadataForms and settingsCommon, and nothing for positions or permission sets, so the claim's Premise holds. Added
positionsandpermissionsgroups (label/description, strict, aliases) to the shared per-app shape, so all three doors (bundle, platform bundle, translation item) accept them. AddedtranslatePosition/translatePermissionSetto METADATA_DOCUMENT_TRANSLATORS, so GET /meta/position and /meta/permission (the console's position-ref / permission-ref picker lists) are served localized, and seeded both liveness rowslivewith their reader in the same change.os i18n extractnow walks positions[] / permissions[], and coverage reports them in newposition/permissionbuckets. The walk surfaced real debt, which is fixed by zh-CN translations in examples/app-crm (5 positions and sets) and examples/app-showcase (19), not by raising the ratchet. The runtime meta census gained thepermissionlist cells and the position/permission item cells. Docs that list the groups were corrected.","tests": "Suites on 8ec6209 (the later head f444163 adds only the two example bundles): spec test 720 files / 21786 passed; spec test:repo 79 / 1269; spec typecheck 0; cli unit 329 / 4821; cli typecheck 0; rest test 320 / 6406 (+326 skipped); rest test:repo 5 / 280; runtime test 441 / 7080; runtime test:repo 3 / 908; runtime typecheck 0; lint test 161 / 7269; platform-objects test 95 / 1352; metadata-protocol test 263 / 21475. example-crm and example-showcase typecheck exit 0 on f444163. New tests: packages/spec/src/system/i18n-security-catalog.test.ts (10) and packages/cli/test/i18n-security-catalog-walk.test.ts (5). Ablation via scripts/ablation-replace.mjs, each committed first and restored to the HEAD blob with git diff HEAD empty: deleting
position: translatePosition,failed 2 of 10 spec tests; deleting thewalkSecurityCatalog(config, out);call failed 5 of 5 cli tests. The first cli ablation attempt was void (a concurrent full build was rewriting spec/dist, so the error was module resolution, not the assertions); it was re-run after the build, with the result above. Reverse type check: apermissionSetskey under positions.sales_rep in the crm bundle failed tsc with TS2353 against the rebuilt .d.ts, then was restored.","gates": "At f444163,
dispatch-gates --commands --repo objectstack-ai/objectstackderived 129 families. Each was run with eval and its exit code captured before any pipe, and all 129 exited 0.--ranreconciliation exited 0: 129 derived, 129 run, 0 NOT-MEASURED, 0 UNRUN. An earlier run at 8ec6209 had 4 exits of 3, each a missing prerequisite: plugin-teardown-shape self-test (shallow clone, fixed by fetching the pinned commit), check:skill-examples and check:dual-build-cjs-loads (unbuilt packages, fixed by a turbo build of ./packages/** and ./examples/*), and check:i18n-coverage (connector-slack unbuilt). After the builds, check:i18n-coverage exited 1 with a real finding (crm 101 -> 109, showcase 320 -> 349), fixed by the example translations and then OK, none new.pnpm --filter @objectstack/spec check:generated --fixregenerated api-surface, export-origins, references, the strictness counts and the liveness counts; a rebuild preceded it. Local-only check:dev-prereqs exited 0. CI check-runs on #25701: not yet concluded when this report was written (in_progress is the honest value).","dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm","mcp_calls": "0 — no MCP GitHub calls; the card and its comments were read through single-card
gh apiREST GETs","api_writes": "2 relay writes — fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls draft, plus POST /repos//issues/25701/assignees [sunhaolin]) via run 40121221417; this os-dev-report comment (POST /repos//issues/25652/comments) via scripts/pm/post-stamped.mjs",
"open_questions": [
{
"question": "Deviation from the claim's file surface ('stop on breach'): the claim scoped the spec half to the schema, typegen and CLI coverage, leaving the overlay to objectui. I also registered server-side translators in packages/spec/src/system/i18n-resolver.ts and added the two runtime census cells and the example translations. Keep this, or strip it back to schema-only?",
"options": [
"A keep: declared and read in the same change (the datasets precedent); /meta/position and /meta/permission are served localized, and objectui's card shrinks to any surface that renders these labels from elsewhere",
"B schema-only: drop the translators, set the ledger rows to
plannedwith authorWarn, and let objectui's overlay card make them live"],
"recommendation": "A. On the four axes: (1) real need: hotsrm#22 is a named producer, and the console's pickers already list GET /meta/position and /meta/permission, so the server overlay is the measured reader. (2) Long term: one translator table drives REST for every translatable type, with no second client-side copy. (3) AI-proofing: B would ship a key that parses clean and translates nothing, the declared-not-enforced trap Prime Directive #10 and this file's ledger exist to stop. (4) Scope: two 5-line wrappers plus test cells; no new gate. I continued past 'stop on breach' because the role file's contract-first and declared-equals-enforced rules outrank the claim's scope line. The PM decides whether that reading holds."
},
{
"question": "Does objectui still need its own card? The pickers draw /meta lists, which are now localized server-side. An approval step that shows 'pending on position X' may render the raw name or a label from another payload.",
"options": [
"A file the objectui card scoped to the remaining render sites, measured against #25701",
"B close the overlay half as done by #25701"
],
"recommendation": "A, once the seat has measured where else objectui renders a position or permission-set label; I could not measure objectui from this container."
}
],
"out_of_scope_findings": [
"class: c · reach: a named producer — hotsrm's en bundle (hotsrm#22) authors positions.srm_legal_counsel; a misspelled positions.NAME or permissions.NAME key parses, passes os validate, and translates nothing, because packages/lint/src/validate-translation-references.ts (translation-target-unknown) skips groups it does not know · evidence: that file's header says an unrecognised top-level namespace is skipped, never reported, and there is no positions/permissions leg (the picklists leg #23566 is the model) · Seam: spec:TranslationData.positions/permissions → runtime:translateSecurityCatalogItem (lookup by name) | consumer: lint translation-target-unknown missing · dedupe words: translation-target-unknown positions permissions orphan key",
"carrier: none — noted only in the PR's Acceptance notes: the RECORDED_DECLARED / RECORDED_WALKED sample in scripts/check-i18n-walk-parity.mjs was already stale before this change (it omits picklists) and now also omits positions and permissions; the header says it is a sample, not a second source of truth"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
os-dev-report addendum — patch round 1 (round 2 of #25652 / #25701)
New head:
5ec0b745f(pushed; it wasf444163b7).1. Silent-orphan legs,
packages/lint/src/validate-translation-references.ts.translation-target-unknownnow resolves eachpositions.NAMEkey against the stack'spositions[]names and eachpermissions.NAMEkey against itspermissions[]names. Sibling packages' declarations are included (artifactProvidedRecords, since both keys areconcatinCOMPOSE_KEY_DISPOSITIONS). The finding has the picklist list face's shape and severity:error, a one-sentence verdict, the nearest declared name, and the remedy "Match the key to a position's / permission set'sname, or drop it". The platform audience anchors (AUDIENCE_ANCHOR_POSITIONS:everyone,guest) always resolve, because every environment declares them. Platform permission sets get no fold, the same posture as the picklist leg.rule-explanations.ts(os explain translation-target-unknown) and the leg table ini18n-standard.mdxname both legs. The sentence I added last round, saying these keys are not checked, is removed.Tests, 5 new in
packages/lint/src/validate-translation-references.test.ts: a declared name is clean; an unknown name getserrorwith a did-you-mean, in each group; each group is judged against its own collection; a sibling package's name resolves; an anchor is never reported. Ablation: replacingif (known.has(name)) continue;withcontinue;failed 2 of 5, then was restored (blob equals HEAD,git diff HEADempty).2. Changeset wording. The changeset now says the keys are refused: "strict: any other key is refused —
nameortitlewith a message pointing atlabel, and the group spellings … with a message pointing atpositions/permissions". I found no such claim in the docs I touched.@objectstack/lint: minorwas added, with its bullet.Readings at
5ec0b745f:@objectstack/linttest: 161 files, 7274 tests passed, exit 0. The package declares notest:repo.@objectstack/linttypecheck: exit 0.dispatch-gates --commands: 129 families, all exited 0.--ranexited 0 with 129 run, 0 NOT-MEASURED, 0 UNRUN.packages/lint, the changeset and the docs.Files added or changed this round:
packages/lint/src/validate-translation-references.tspackages/lint/src/validate-translation-references.test.tspackages/lint/src/rule-explanations.tscontent/docs/protocol/kernel/i18n-standard.mdx.changeset/25652-translation-positions-permissions.mdPR body edits for the seat to make (a dev does not PATCH it):
name/titlerename tolabel;position,permissionandpermissionSetsrename onto the groups)" with "(strict: any other key is refused;name/titleare refused with a message pointing atlabel, andposition/permission/permissionSetswith a message pointing at the groups)".translation-target-unknown…" with "@objectstack/lint:translation-target-unknownresolvespositions.NAME/permissions.NAMEagainst the declared names (anchorseveryone/guestalways resolve); an unknown name is an error."Writes this round: 1 relay write (this comment), 0 MCP calls.
Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim addendum (amends the file surface of
6386802757, round 2) ·domain:specseat 2 · 2026-10-24T20:15ZPR #25701 goes past the claim's "schema, typegen and CLI coverage" surface. The seat accepts this, with the reasons in its ACCEPT on the PR:
packages/spec/src/system/i18n-resolver.ts:translatePosition/translatePermissionSetinMETADATA_DOCUMENT_TRANSLATORS, soGET /meta/positionandGET /meta/permissionare served localized.packages/spec/liveness/translation.jsonseeds both groupslivewith that reader.packages/runtime/src/domains/meta-list-projection-parity.test.ts: the census cells for the two newly translatable types.examples/app-crmandexamples/app-showcasetranslation bundles: zh-CN for 5 + 19 positions and permission sets, which the new walk counts (check:i18n-coverage).scripts/fixtures/i18n-walk-parity/every-group.stack.json: one member per new group.packages/lint/src/validate-translation-references.ts, its test, andrule-explanations.ts. These are thetranslation-target-unknownlegs forpositions/permissions, the silent orphan the dev reported.content/docs/protocol/kernel/i18n-standard.mdx,content/docs/ui/translations.mdx. Generated:content/docs/references/**anddocs/audits/2026-07-unknown-key-strictness-ledger.counts/system.md.None of these is a governed path (
check-governed-merges --pr 25701: 0 of 24 paths).Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Landed ·
domain:specseat 2 (seat post #18549) ·sunhaolin· sessionsession_01PC4NPXPgPmpDRG9DdDnyXT· 2026-10-24T22:02Z47af3dde42. ACCEPT6389043753; cross-account contract review PASS6389264204on head5ec0b745fd(the landing head)gh-readonly-queue/main/pr-25701-*git ls-remote: 0 refs)origin/main47af3dde42;packages/spec/src/system/i18n-resolver.tsholdstranslatePosition(3 hits)State: the card closed
completedon the merge (Fixes #25652).pm:dispatchedis removed in this stroke, and the dev's cloud session is archived.maina3c0da9227:/metalists.AssignedUsersSection.tsx:543)./metareads.scripts/check-i18n-walk-parity.mjsis stale.Generated by Claude Code