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
Setup: the permission-set detail header shows the English label under zh-CN, and the metadata list pages (Positions, Permission Sets, …) stay English under ja-JP and es-ES #26884
Filing gate ① a product defect with a reproduction. Found by the HotCRM full browser pass objectstack-ai/hotcrm#2320 on @objectstack/* 18.2.0: track 5 Setup (report comment 6442758420 on objectstack-ai/hotcrm#2320, finding D6, D7; screenshots on branch claude/project-thread-ptkrz3 under qa/ and in the HotCRM project files qa-2320/5-setup/). Filed by the repo:hotcrm seat (huangyiirene, session session_01J8VVAnPkgK6CWrJa6t7Fk5), which re-read each finding against its screenshot. Batch-of: hotcrm#2320 platform findings.
finding class a · reach: public door: the console on @objectstack/* 18.2.0, measured in Chromium against the HotCRM seed.
What is seen
zh-CN, permission-set detail. Setup → 权限集 lists the set as 销售代表; opening it, the header reads "Sales Representative" (53-zh-admin-01-permset-list.png, 52-zh-07-setup-permset-sales-rep.png).
ja-JP and es-ES, metadata lists. Setup → Positions under 日本語 or Español reads "Position · create-only · 19 items · New · All sources · All", and the column headers, "None" and "Artifact" stay English (54-ja-03-setup-positions.png, 55-es-03-setup-positions.png). The Setup sidebar and HotCRM's own position labels are translated, and zh-CN translates the same page (岗位 · 仅可新建 · 19 个条目 · 新建 · 全部来源, 52-zh-06-setup-positions.png).
Who loses: admins in those locales, on the pages they configure access from.
Expected
The detail header uses the translated label the list already shows; the metadata list chrome has ja-JP and es-ES catalog entries as it has zh-CN ones.
Dedupe
search_issues objectstack "Setup metadata list untranslated ja-JP es-ES permission set detail header English label": 10 hits — #26094 (closed, the built-in sets' labels under zh-CN), #25652 (closed, the bundle key for positions and permission sets, which is why the list now translates), #20666, #20653, #20493 (closed, ja-JP/es-ES bundle leaves). None is the detail header or the metadata list chrome on 18.2.0.
Reader who acts: the console Setup owner (domain:ui, area:i18n).
Dispatch order · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T00:44Z
You are the os-dev developer agent for exactly ONE card: #26884, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26884" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.
Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktree objectstack-issue-26884 on that branch from a fresh origin/main (git checkout --detach the main checkout first, then git worktree add --no-track -B <branch> ../objectstack-issue-26884 origin/main); pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).
Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26884 --file=F --json run ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26884, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran (merge origin/main first if it refuses as STALE TREE); node scripts/check-sdui-manifest.mjs is a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root .changeset/ for each published package your diff changes (app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and report premise_still_valid: false with the evidence; ⛔ never force a fix.
Ruling (cannot be re-ruled)
Triage 6452187239, verbatim: "Read the translated label the bundle carries for zh-CN, ja-JP and es-ES." No maintainer ruling on this card.
Scope cut (the seat, a card item that conflicts with a prior ruling):
Ruling-ref: 6431032267 (#25922 Q2, letter A), verbatim: "the other eight locales fall back to en (no invented translations)". The card's second symptom (the metadata list pages' chrome — engine.list.*, engine.badge.createOnly — staying English under ja/es) is that ruled fallback, not a defect, so it is cut from this card. A language gaining Studio/Setup chrome coverage is a new-catalogue decision, not this fix.
The Setup permission-set detail page is PermissionMatrixEditPage (ui/packages/app-shell/src/services/builtinComponents.tsx ≈L199). The header renders the authored label with no translation: ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx ≈L2171 {draft.label || draft.name} (Studio variant ≈L1932). draft comes from client.layered() (≈L831), the raw source the editor saves.
The list shows the translated label because the server translates it (translatePermissionSet, packages/spec/src/system/i18n-resolver.ts ≈L1517). The editor already reads that list (≈L786, client.list('permission', {}) into publishedSetsRef).
Show the served (translated) label in the header only; ⛔ never write it into draft, so a save keeps the authored text. A draft-only set with no served row keeps draft.label. Tests: zh-CN, served list {name:'sales_rep', label:'销售代表'}, layered label:'Sales Representative' ⇒ header shows 销售代表 and a save sends 'Sales Representative' unchanged; also ja-JP if the served label carries it. Ablation: put draft.label back in the header; the zh assertion goes red.
Scope
File surface: ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx (header label only), a new test beside it, root .changeset/ (@object-ui/app-shell patch, following #26955's precedent). ⛔ Do not edit PermissionAdvancedFacets.tsx (PR #26990) or AppNavInspector.tsx (PR #26977).
Tier
No path-derived mandate (dispatch-gates --tier, read 2026-10-28T00:44Z). TIER_DEFAULT, effort medium (S). Clause-②: no, Metadata-protocol: none expected.
Claim: PM loop round 1
Session: session_01JQwxbXpF772qWJjojJvRXw
Account: os-warren
Branch: claude/project-thread-2x7amc
Worktree: objectstack-issue-26884
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx (header label only), a new test beside it, root .changeset/ (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: the Setup permission-set editor header renders the raw authored label | the server already translates the served list row (translatePermissionSet) | every zh-CN Setup admin opening a permission set
Thread-read: 6457572362
Premise: corrected 6457572362 (the list-chrome half is the ruled en fallback and is cut, Ruling-ref 6431032267; the header half holds on origin/mainfd246c22)
Serial constraints cleared: PR #26990 holds PermissionAdvancedFacets.tsx and seat 5's PR #26977 holds AppNavInspector.tsx (neither edited); #26649 (seat 2) edits ResourceListPage.tsx/ResourceEditPage.tsx in the same directory, disjoint files.
Ruling-ref: 6431032267
Dispatch order: comment 6457572362. Card thread claude/project-thread-2x7amc may start editing.
{
"issue": 26884,
"status": "done",
"branch": "claude/project-thread-2x7amc",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27019",
"head": "53382fab",
"session": "session_01JQwxbZMgz2QbrsLJv3RD41",
"premise_still_valid": true,
"summary": "PermissionMatrixEditPage now keeps the label of the served GET /meta/permission row (localized by the server's translatePermissionSet; the editor already reads that list for the published-set check) and shows it in both header sites (Setup identity strip, Studio StudioItemHeader title) while draft.label equals the published authored label. Display only: never written into draft, so a save sends the authored label; a set the list does not hold keeps draft.label; a label edit shows the edit. PM mechanism assumptions measured true on b8f596cf. The ja/es list-chrome half is cut per Ruling-ref 6431032267.",
"tests": "new PermissionMatrixEditor.servedLabel-26884.test.tsx: Tests 4 passed (4). Ablation via scripts/ablation-replace.mjs (anchor '{headerLabel || draft.name}' x1->x0, replacement x0->x1, blob ac567046->420e05c5): 3 failed | 1 passed (never-published case green as expected); restored blob ac567046 = HEAD blob. No dist leg: the test imports the editor by relative path. pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/: Test Files 624 passed, Tests 6809 passed | 1 skipped. pnpm --filter @object-ui/app-shell type-check: exit 0.",
"gates": "on 53382fab (after merging origin/main; first derivation refused as STALE TREE on ci.yml): dispatch-gates --commands derived 34 families, each run, all exit 0 (incl. node scripts/check-sdui-manifest.mjs and its --self-test; pnpm --dir ui exec vitest run scripts/ under the lock). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Closure build --filter '@object-ui/app-shell^...' exit 0. CI check-runs: in_progress at report time.",
"line_budget": "PermissionMatrixEditor.tsx +24/-4; new test +140; changeset +12 (176 insertions, 4 deletions total)",
"files_changed": [
".changeset/26884-permission-set-header-served-label.md",
"ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx",
"ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.servedLabel-26884.test.tsx"
],
"deviations": [
"PR body folds .github/PULL_REQUEST_TEMPLATE.md headings (What changes, Verification, Human Minimum) into the os-dev order; the Why heading is carried by the 维护者速读 block.",
"Changeset names @object-ui/app-shell (patch) per the order's Scope line and existing app-shell changesets, although the order's Writes line notes app-shell is private."
],
"dogfood_battery": "n/a — no ! in the PR title and Clause-②: no",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST pulls, assignees) via fleet-write run 40616574766; this report comment via post-stamped (POST issues/26884/comments). git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": []
}
Landing held · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T02:10Z
PR #27019 (ACCEPT 6458438663) is green on head 53382fab30: 43 checks success, 10 skipped (the core / docs / dogfood path-filtered jobs a ui/-only diff does not trigger), mergeable_state clean, not governed. This session's permission classifier refused the same landing stroke (pr_ready + automerge_enable through the fleet-write relay, "Merge Without Review") on PR #27013 at 2026-10-28T01:44Z, so the seat does not retry it here and asks the maintainer to mark the PR ready for review and enable auto-merge.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: audit line · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T19:58Z⛔ Not a claim, ⛔ not a dispatch.
ui/); rationale: p3 ·domain:ui·area:i18n. Read the translated label the bundle carries for zh-CN, ja-JP and es-ES. The built-in positions' strings came with Setup → Positions under zh-CN lists the built-in positions in English (Platform Admin, Organization Owner, Everyone, Guest …) while the built-in permission sets are translated #26562 (PR fix(plugin-security): translate the built-in positions under zh-CN, ja-JP and es-ES #26606).Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Dispatch order ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T00:44ZYou are the os-dev developer agent for exactly ONE card: #26884, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26884" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktreeobjectstack-issue-26884on that branch from a freshorigin/main(git checkout --detachthe main checkout first, thengit worktree add --no-track -B <branch> ../objectstack-issue-26884 origin/main);pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=26884 --file=F --jsonrun ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and onerun_rerun_failedthrough the relay. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3Fixes #26884, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran(mergeorigin/mainfirst if it refuses as STALE TREE);node scripts/check-sdui-manifest.mjsis a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root.changeset/for each published package your diff changes (app-shell isprivate: true). ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and reportpremise_still_valid: falsewith the evidence; ⛔ never force a fix.Ruling (cannot be re-ruled)
Triage 6452187239, verbatim: "Read the translated label the bundle carries for zh-CN, ja-JP and es-ES." No maintainer ruling on this card.
Scope cut (the seat, a card item that conflicts with a prior ruling):
Ruling-ref: 6431032267 (#25922 Q2, letter A), verbatim: "the other eight locales fall back to en (no invented translations)". The card's second symptom (the metadata list pages' chrome —
engine.list.*,engine.badge.createOnly— staying English under ja/es) is that ruled fallback, not a defect, so it is cut from this card. A language gaining Studio/Setup chrome coverage is a new-catalogue decision, not this fix.PM mechanism assumptions (measure; disproof welcome)
On
origin/mainfd246c22(read-only check):PermissionMatrixEditPage(ui/packages/app-shell/src/services/builtinComponents.tsx≈L199). The header renders the authored label with no translation:ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx≈L2171{draft.label || draft.name}(Studio variant ≈L1932).draftcomes fromclient.layered()(≈L831), the raw source the editor saves.translatePermissionSet,packages/spec/src/system/i18n-resolver.ts≈L1517). The editor already reads that list (≈L786,client.list('permission', {})intopublishedSetsRef).49b50591); no catalogue rows are needed for this fix.PM suggested route (optional; measurement wins)
Show the served (translated) label in the header only; ⛔ never write it into
draft, so a save keeps the authored text. A draft-only set with no served row keepsdraft.label. Tests: zh-CN, served list{name:'sales_rep', label:'销售代表'}, layeredlabel:'Sales Representative'⇒ header shows 销售代表 and a save sends 'Sales Representative' unchanged; also ja-JP if the served label carries it. Ablation: putdraft.labelback in the header; the zh assertion goes red.Scope
File surface:
ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(header label only), a new test beside it, root.changeset/(@object-ui/app-shellpatch, following #26955's precedent). ⛔ Do not editPermissionAdvancedFacets.tsx(PR #26990) orAppNavInspector.tsx(PR #26977).Tier
No path-derived mandate (
dispatch-gates --tier, read 2026-10-28T00:44Z).TIER_DEFAULT, effortmedium(S).Clause-②: no,Metadata-protocol: noneexpected.objectstack-fleet commentedon Oct 28, 2026
Claim: PM loop round 1
Session:
session_01JQwxbXpF772qWJjojJvRXwAccount:
os-warrenBranch:
claude/project-thread-2x7amcWorktree:
objectstack-issue-26884Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(header label only), a new test beside it, root.changeset/(stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
the Setup permission-set editor header renders the raw authored label|the server already translates the served list row (translatePermissionSet)|every zh-CN Setup admin opening a permission setThread-read: 6457572362
Premise: corrected 6457572362 (the list-chrome half is the ruled en fallback and is cut, Ruling-ref 6431032267; the header half holds on
origin/mainfd246c22)Serial constraints cleared: PR #26990 holds
PermissionAdvancedFacets.tsxand seat 5's PR #26977 holdsAppNavInspector.tsx(neither edited); #26649 (seat 2) editsResourceListPage.tsx/ResourceEditPage.tsxin the same directory, disjoint files.Ruling-ref: 6431032267
Dispatch order: comment 6457572362. Card thread
claude/project-thread-2x7amcmay start editing.objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26884, "status": "done", "branch": "claude/project-thread-2x7amc", "pr": "https://github.com/objectstack-ai/objectstack/pull/27019", "head": "53382fab", "session": "session_01JQwxbZMgz2QbrsLJv3RD41", "premise_still_valid": true, "summary": "PermissionMatrixEditPage now keeps the label of the served GET /meta/permission row (localized by the server's translatePermissionSet; the editor already reads that list for the published-set check) and shows it in both header sites (Setup identity strip, Studio StudioItemHeader title) while draft.label equals the published authored label. Display only: never written into draft, so a save sends the authored label; a set the list does not hold keeps draft.label; a label edit shows the edit. PM mechanism assumptions measured true on b8f596cf. The ja/es list-chrome half is cut per Ruling-ref 6431032267.", "tests": "new PermissionMatrixEditor.servedLabel-26884.test.tsx: Tests 4 passed (4). Ablation via scripts/ablation-replace.mjs (anchor '{headerLabel || draft.name}' x1->x0, replacement x0->x1, blob ac567046->420e05c5): 3 failed | 1 passed (never-published case green as expected); restored blob ac567046 = HEAD blob. No dist leg: the test imports the editor by relative path. pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/: Test Files 624 passed, Tests 6809 passed | 1 skipped. pnpm --filter @object-ui/app-shell type-check: exit 0.", "gates": "on 53382fab (after merging origin/main; first derivation refused as STALE TREE on ci.yml): dispatch-gates --commands derived 34 families, each run, all exit 0 (incl. node scripts/check-sdui-manifest.mjs and its --self-test; pnpm --dir ui exec vitest run scripts/ under the lock). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Closure build --filter '@object-ui/app-shell^...' exit 0. CI check-runs: in_progress at report time.", "line_budget": "PermissionMatrixEditor.tsx +24/-4; new test +140; changeset +12 (176 insertions, 4 deletions total)", "files_changed": [ ".changeset/26884-permission-set-header-served-label.md", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.servedLabel-26884.test.tsx" ], "deviations": [ "PR body folds .github/PULL_REQUEST_TEMPLATE.md headings (What changes, Verification, Human Minimum) into the os-dev order; the Why heading is carried by the 维护者速读 block.", "Changeset names @object-ui/app-shell (patch) per the order's Scope line and existing app-shell changesets, although the order's Writes line notes app-shell is private." ], "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST pulls, assignees) via fleet-write run 40616574766; this report comment via post-stamped (POST issues/26884/comments). git push is not a REST write.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
ACCEPT → PR #27019 comment 6458438663 ·
domain:ui#2· head53382fab30· 2026-10-28T01:46Zobjectstack-fleet commentedon Oct 28, 2026
Landing held ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T02:10ZPR #27019 (ACCEPT 6458438663) is green on head
53382fab30: 43 checks success, 10 skipped (the core / docs / dogfood path-filtered jobs aui/-only diff does not trigger),mergeable_stateclean, not governed. This session's permission classifier refused the same landing stroke (pr_ready+automerge_enablethrough the fleet-write relay, "Merge Without Review") on PR #27013 at 2026-10-28T01:44Z, so the seat does not retry it here and asks the maintainer to mark the PR ready for review and enable auto-merge.