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
i18n gates: a marketplace.* namespace key read outside the marketplace pages' frame passes every gate and renders as a raw key #30645
Filing gate: ③ a follow-up named by the CONTRACT_REVIEW_TIER review of PR #30640 (#30588), record 6668069937, should-fix 1. ⛔ Not a claim. Triage sets the grade and the lane. Starts after PR #30640 merges (it adds the namespace this card is about).
What happens
PR #30640 moves most marketplace.* strings out of the eager language packs into the lazy @object-ui/i18n/namespaces/marketplace catalogue. Only the two marketplace pages fetch it, through MarketplaceNamespaceGate. A key that lives only in the namespace therefore renders only under that frame; read anywhere else it shows as a raw key (nothing fetched) or as English (only en fetched by an earlier visit).
Two pins guard this at the head of PR #30640, and both leave one path open:
ui/packages/app-shell/src/console/marketplace/__tests__/marketplaceNamespaceBoundary.test.ts walks the files that reach console/marketplace/ by an import from outside it, and holds that every marketplace.* key they spell is in the resident pack. A source elsewhere that spells a namespace key WITHOUT importing from that directory is read by no pin.
ui/scripts/check-i18n-call-site-keys.mjs accepts the key, because its key set includes the namespace catalogues (PACK_NAMESPACE_DIRS, :1329, read into the defined keys at :1363).
No such reader exists at that head (a git grep "marketplace\." over ui/ outside the directory hits only CHANGELOGs, a README, gate docblocks and the drift baseline). The gap is the next one written, for example a Studio or Setup page that reuses a marketplace label.
Wanted
The call-site gate refuses a key defined only in a namespace catalogue when it is spelled in a file outside the directories that namespace's frame wraps, or the boundary census reads every ui/** source rather than only the importers of console/marketplace/. Either way a positive control: a fixture that spells a namespace-only key outside the frame turns the check red.
The rule is written so a second lazy namespace inherits it (the gate already names the namespace directories in one list).
Reader: domain:ui (ui/scripts/check-i18n-call-site-keys.mjs or the boundary test, both in PR #30640).
Dedupe: namespace key outside frame, call-site keys namespace (is:issue) → none.
Claim: PM loop round 3 · 2026-11-06T06:02Z
Session: session_01L9qibxW6qraU2Z3mwupUGp
Account: os-tesla (the card's assignee)
Branch: the card thread's designated claude/project-thread-* branch, named in a claim amendment once the thread reports it
Worktree: objectstack-issue-30645
Domain: domain:ui
Seat: domain:ui#3 (left to this seat by domain:ui#2, mailbox #30819 6678145460)
File surface: ui/scripts/check-i18n-call-site-keys.mjs (+ its self-test / fixtures) or ui/packages/app-shell/src/console/marketplace/__tests__/marketplaceNamespaceBoundary.test.ts, whichever the dev shows closes the gap; the rule is written over the gate's one list of namespace directories so a second lazy namespace inherits it; a positive control (a fixture that spells a namespace-only key outside the frame turns the check red). ⛔ No new workflow, ⛔ no edit to language packs or marketplace pages beyond a fixture. Stop on breach and explain in the report.
Container & model: M, mode:thread, model: default (opus), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6669138980
Premise: holds — the card's start condition (PR #30640 merged) is met: d996c3817e; the dev re-reads PACK_NAMESPACE_DIRS and the boundary test on origin/mainfd749a45 first.
Serial constraints cleared: domain:ui#2's #30511 (PR #30595) and #30325 (PR #30545) touch ui/packages/i18n and the marketplace pages, not these two files; if their landing adds a namespace key read outside the frame, the later lander fixes it.
{
"issue": 30645,
"status": "done",
"branch": "claude/project-thread-sw8poh",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30853",
"session": "session_01L9qibxDqYaHT7GBjAY9FzB",
"premise_still_valid": true,
"summary": "The i18n call-site gate gains class 9 namespace-key-outside-frame: a key only a lazy pack-shaped namespace defines is refused at a call site outside the directories its frame wraps (literal key incl. plural forms, returnObjects subtree, template head with no resident leaf). Frames are declared on the one namespace list (PACK_NAMESPACE_FRAMES; PACK_NAMESPACE_DIRS derived from its keys), so a second namespace is judged the day it is declared and cannot be added without a frame. 0 findings on main's tree; the frame of marketplace reads 183 keys, and a namespace whose frame reads none fails as a collapsed scan. marketplaceNamespaceBoundary.test.ts unchanged (it keeps the inside-the-directory doors).",
"tests": "head f4a22f9b: pnpm --dir ui exec vitest run scripts/__tests__/check-i18n-call-site-keys.test.ts -> Tests 152 passed (152), 10 new cases incl. positive control and a synthetic second namespace; pnpm --dir ui exec vitest run scripts/ under os-verify-lock -> Test Files 170 passed | 2 skipped, Tests 4989 passed | 2 skipped, VERDICT command-exit 0. Real-tree probe: an uncommitted Probe30645.tsx calling t('marketplace.title') outside the frame -> gate exit 1 [namespace-key-outside-frame]; removed -> exit 0. No ablation: config/script change, per os-dev.",
"gates": "dispatch-gates --commands: 20 derived, all exit 0; --ran: 20 run, 0 NOT-MEASURED. Beyond derivation, exit 0: check-sdui-manifest, ui check:i18n-keys, ui check:new-line-citations, ui type-check:scripts (red once on an earlier head, green on f4a22f9b). CI check-runs: in_progress at report time. Record: /mnt/project-files/ui-seat-3/r2026-11-06/30645/gates-ran-f4a22f9b.list",
"line_budget": "282 changed lines (+264 / -18) over 2 files, under the 3000 threshold",
"files_changed": [
"ui/scripts/check-i18n-call-site-keys.mjs",
"ui/scripts/__tests__/check-i18n-call-site-keys.test.ts"
],
"deviations": [
"marketplaceNamespaceBoundary.test.ts (unchanged) NOT MEASURED locally: stops at import on @objectstack/spec/ui with no dist in the worktree; Test UI runs it",
"label skip-changeset sent with pr_create (ui/scripts is in the private object-ui-monorepo root)"
],
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 relay writes — pr_create (fleet-write run 42176056427, PR #30853, label skip-changeset) and this os-dev-report comment via post-stamped.mjs",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · noted in the PR's Acceptance notes: a key built by a helper or passed as a variable is outside class 9, the same blind spot class 1 has"
]
}
Landed 2026-11-06T14:59Z: PR #30853 merged through the merge queue as de0f692b94 (2026-11-06T14:36Z on the PR; seat ACCEPT 6679198959; enqueued by the seat under the maintainer's 「你应该是使用 pm-dispatch 技能自主审核和落地 pr」, 2026-11-06T14:09Z). The PR said Fixes #30645, so the card is closed. pm:dispatched removed in this round.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:ui· 2026-11-05T20:52Z⛔ Not a claim.
marketplace.*key read outside the marketplace pages' frame passes every gate and renders as a raw key. Widen the existingmarketplaceNamespaceBoundary.test.tswalk; it extends an existing test and adds no new gate. Serial after PR perf(i18n, app-shell)!: the marketplace pages' strings leave the eager language packs for a lazymarketplacenamespace #30640.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp
Claim: PM loop round 3 · 2026-11-06T06:02Z
Session:
session_01L9qibxW6qraU2Z3mwupUGpAccount:
os-tesla(the card's assignee)Branch: the card thread's designated
claude/project-thread-*branch, named in a claim amendment once the thread reports itWorktree:
objectstack-issue-30645Domain:
domain:uiSeat:
domain:ui#3(left to this seat bydomain:ui#2, mailbox #30819 6678145460)File surface:
ui/scripts/check-i18n-call-site-keys.mjs(+ its self-test / fixtures) orui/packages/app-shell/src/console/marketplace/__tests__/marketplaceNamespaceBoundary.test.ts, whichever the dev shows closes the gap; the rule is written over the gate's one list of namespace directories so a second lazy namespace inherits it; a positive control (a fixture that spells a namespace-only key outside the frame turns the check red). ⛔ No new workflow, ⛔ no edit to language packs or marketplace pages beyond a fixture. Stop on breach and explain in the report.Container & model:
M,mode:thread,model: default (opus),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6669138980
Premise: holds — the card's start condition (PR #30640 merged) is met:
d996c3817e; the dev re-readsPACK_NAMESPACE_DIRSand the boundary test onorigin/mainfd749a45first.Serial constraints cleared:
domain:ui#2's #30511 (PR #30595) and #30325 (PR #30545) touchui/packages/i18nand the marketplace pages, not these two files; if their landing adds a namespace key read outside the frame, the later lander fixes it.objectstack-fleet commentedon Nov 6, 2026
domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp
席位核对 · Amendment · 2026-11-06T06:04Z · claim 6678221203 branch named
Branch:
claude/project-thread-sw8poh(the card thread's designated branch; sessionsession_01L9qibxDqYaHT7GBjAY9FzB), cut fromorigin/main. Everything else in claim 6678221203 stands.objectstack-fleet commentedon Nov 6, 2026
domain:ui#3 · os-tesla · session_01L9qibxDqYaHT7GBjAY9FzB
os-dev-report
{ "issue": 30645, "status": "done", "branch": "claude/project-thread-sw8poh", "pr": "https://github.com/objectstack-ai/objectstack/pull/30853", "session": "session_01L9qibxDqYaHT7GBjAY9FzB", "premise_still_valid": true, "summary": "The i18n call-site gate gains class 9 namespace-key-outside-frame: a key only a lazy pack-shaped namespace defines is refused at a call site outside the directories its frame wraps (literal key incl. plural forms, returnObjects subtree, template head with no resident leaf). Frames are declared on the one namespace list (PACK_NAMESPACE_FRAMES; PACK_NAMESPACE_DIRS derived from its keys), so a second namespace is judged the day it is declared and cannot be added without a frame. 0 findings on main's tree; the frame of marketplace reads 183 keys, and a namespace whose frame reads none fails as a collapsed scan. marketplaceNamespaceBoundary.test.ts unchanged (it keeps the inside-the-directory doors).", "tests": "head f4a22f9b: pnpm --dir ui exec vitest run scripts/__tests__/check-i18n-call-site-keys.test.ts -> Tests 152 passed (152), 10 new cases incl. positive control and a synthetic second namespace; pnpm --dir ui exec vitest run scripts/ under os-verify-lock -> Test Files 170 passed | 2 skipped, Tests 4989 passed | 2 skipped, VERDICT command-exit 0. Real-tree probe: an uncommitted Probe30645.tsx calling t('marketplace.title') outside the frame -> gate exit 1 [namespace-key-outside-frame]; removed -> exit 0. No ablation: config/script change, per os-dev.", "gates": "dispatch-gates --commands: 20 derived, all exit 0; --ran: 20 run, 0 NOT-MEASURED. Beyond derivation, exit 0: check-sdui-manifest, ui check:i18n-keys, ui check:new-line-citations, ui type-check:scripts (red once on an earlier head, green on f4a22f9b). CI check-runs: in_progress at report time. Record: /mnt/project-files/ui-seat-3/r2026-11-06/30645/gates-ran-f4a22f9b.list", "line_budget": "282 changed lines (+264 / -18) over 2 files, under the 3000 threshold", "files_changed": [ "ui/scripts/check-i18n-call-site-keys.mjs", "ui/scripts/__tests__/check-i18n-call-site-keys.test.ts" ], "deviations": [ "marketplaceNamespaceBoundary.test.ts (unchanged) NOT MEASURED locally: stops at import on @objectstack/spec/ui with no dist in the worktree; Test UI runs it", "label skip-changeset sent with pr_create (ui/scripts is in the private object-ui-monorepo root)" ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 relay writes — pr_create (fleet-write run 42176056427, PR #30853, label skip-changeset) and this os-dev-report comment via post-stamped.mjs", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted in the PR's Acceptance notes: a key built by a helper or passed as a variable is outside class 9, the same blind spot class 1 has" ] }objectstack-fleet commentedon Nov 6, 2026
domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp
Landed 2026-11-06T14:59Z: PR #30853 merged through the merge queue as
de0f692b94(2026-11-06T14:36Z on the PR; seat ACCEPT 6679198959; enqueued by the seat under the maintainer's 「你应该是使用 pm-dispatch 技能自主审核和落地 pr」, 2026-11-06T14:09Z). The PR saidFixes #30645, so the card is closed.pm:dispatchedremoved in this round.