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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(app-shell/inspectors,i18n): the dashboard widget inspector's field combo shows the English literal Search fields… as its search placeholder — engine.form.searchFields exists in en-US and zh-CN and its sibling inspector reads it #10696
Filing-gate category: ① a product defect with a named site (class a), read from source with a lit control. Reader: triage first (route and grade), then the seat that claims it.
Filed by the domain:ui seat 5 (session_01KUxVUa7e39aNjhkKi1gsoy) from the at-tier contract review of PR objectui#10678 (objectui#10586, merged as d02974d), which named it as out of scope. The seat re-read it on objectui origin/main7afc81d. ⛔ Filed bare, not graded here.
Fact
packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx:442 passes searchPlaceholder="Search fields…" to InspectorComboField as a string literal.
Every other label in the same inspector goes through t('engine.inspector.…', locale). Its dataset combo's placeholder does too (:339-340).
packages/app-shell/src/views/metadata-admin/i18n.ts already carries engine.form.searchFields: 'Search fields…' in en-US (:1319) and '搜索字段…' in zh-CN (:3594).
⇒ A zh-CN author opening a dashboard widget's field picker reads the English Search fields… on an otherwise translated inspector.
Lit control:DatasetDefaultInspector.tsx:579 and :633 pass searchPlaceholder={tr('engine.form.searchFields')} to the same combo, and render 搜索字段… under zh-CN.
Direction (for triage, not a ruling)
Read the existing engine.form.searchFields key there, the way DatasetDefaultInspector does. No new key is needed, which keeps the objectui#4662 engine.* carve-out (en-US and zh-CN only) untouched.
Dedupe
Searched this repo with the MCP semantic issue search, including closed issues: DashboardWidgetInspector Search fields English placeholder untranslated ⇒ objectui#9652 (closed; the designer's unknown-value markers, a different literal), objectui#4748 (closed; WidgetConfigPanel in plugin-dashboard, a different surface) and older closed i18n cards. None covers this literal, and the hits show the instrument is lit.
Triage: lands in packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx (the field combo's searchPlaceholder is the English literal Search fields…) ⇒ domain:ui; rationale: a zh-CN author reads English on an otherwise translated inspector, although the key engine.form.searchFields exists in both locales and the sibling DatasetDefaultInspector reads it. It was read from source with a lit control and has no measured reach: ⇒ p3, the designer hard-coded-English family (objectui#9652, p3). objectui#10586, that family's last card, is closed, so this card is its closure card for any string the census missed.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T19:39Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectui origin/main.
Execution note: first, measure under zh-CN. Then read the existing engine.form.searchFields key here (no new key, so the objectui#4662 engine.* carve-out stays untouched), and census the inspectors for any other literal passed where a key exists.
Claim: PM loop round 6 — domain:ui execution seat 2
Session: session_014mXUNuFomfj24w7s1pZzhN
Branch: claude/issue-10696-widget-search-placeholder
Worktree: objectui-issue-10696
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx (the field combo's searchPlaceholder reads engine.form.searchFields), plus any other inspector the census (triage execution note) finds passing an English literal where an engine.* key already exists; tests; one changeset ('@object-ui/app-shell': patch). ⛔ No new i18n key (the objectui#4662 engine.* carve-out stays untouched). Stop on breach and explain it in the report
Container & model: S, mode:subagent, model: opus — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes triage 5838471955 (bug · p3, family closure card: measure under zh-CN first, read the existing key, census the inspectors)
Clause-②: no — a translated string replaces an English literal; no declared surface moves
Thread-read: 5838471955
Serial constraints cleared: open-PR file lists read 2026-09-25T20:14Z: no open PR touches metadata-admin/inspectors/ or metadata-admin/i18n.ts. check-governed-queue-guard.mjs --test packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx: NOT GOVERNED.
Release: domain:ui seat 2, session session_014mXUNuFomfj24w7s1pZzhN — shift closed on the maintainer's instruction (「继续,当前任务处理完就下班」, this session's chat, 2026-09-27); the dispatched os-dev stopped on a usage limit (weekly; the API reported the reset as 2026-10-01 21:00 UTC) before reporting ⇒ assignee cleared, pm:dispatched → pm:queue; the next holder claims it afresh.
State at release (read from GitHub and the dev's worktree):
Branch claude/issue-10696-widget-search-placeholder is pushed at 68eedfed1 (1 commit: inspector literals with an existing catalogue row read it, including DashboardWidgetInspector's search placeholder and ViewVariantInspector.tsx, plus inspectorStrings.i18n-10696.test.tsx; 6 files, +415/-8). Worktree clean. No PR was opened and no report exists.
The dev's last stated step was the pin file, so the red-on-base / green-on-head evidence and the gates are unmeasured.
What the next holder owes: verify the pin (red on base, green on head, per-site ablation), the census table, the gates, then open the draft PR (Fixes #10696, Clause-②: no) and review it.
Claim: PM loop round 6 — domain:ui execution seat 2
Session: session_014mXUNuFomfj24w7s1pZzhN
Branch: claude/issue-10696-widget-search-placeholder
Worktree: objectui-issue-10696
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx (the field combo's searchPlaceholder reads engine.form.searchFields), plus any other inspector the census (triage execution note) finds passing an English literal where an engine.* key already exists; tests; one changeset ('@object-ui/app-shell': patch). ⛔ No new i18n key (the objectui#4662 engine.* carve-out stays untouched). Stop on breach and explain it in the report
Container & model: S, mode:subagent, model: fable (the ceiling; opus subagents hit a weekly usage limit) — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes triage 5838471955 (bug · p3, family closure card: measure under zh-CN first, read the existing key, census the inspectors)
Clause-②: no — a translated string replaces an English literal; no declared surface moves
Thread-read: 5851632349
Serial constraints cleared: open-PR file lists read 2026-09-25T20:14Z: no open PR touches metadata-admin/inspectors/ or metadata-admin/i18n.ts. check-governed-queue-guard.mjs --test packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx: NOT GOVERNED.
Re-claim: this seat's own Release: (5851632349) is withdrawn on the maintainer's instruction 「你应该把你当前的pr 都处理完,跟进到合并」 (this session's chat, 2026-09-27). The session stays on this card until its PR merges; the seat itself stays vacant for new work.
{
"issue": 10696,
"status": "done",
"branch": "claude/issue-10696-widget-search-placeholder",
"pr": "https://github.com/objectstack-ai/objectui/pull/10741",
"session": "session_014mXUNuFomfj24w7s1pZzhN",
"premise_still_valid": true,
"summary": "Resumed the branch at 68eedfed1 (1 commit, 6 files: DashboardWidgetInspector, ViewVariantInspector, ObjectFieldInspector, FlowEdgeInspector, the pin inspectorStrings.i18n-10696.test.tsx, one app-shell patch changeset) and took nothing as verified. H1 measured on base 383a34f52 under zh-CN: the widget inspector's filter-binding combo search box rendered `Search fields…` while DatasetDefaultInspector's combo rendered `搜索字段…`. H3 census (AST walk over the 27 inspector sources, default and broad passes, base vs head, each literal matched byte-for-byte against the EN catalogue) confirms exactly seven sites had a literal whose `engine.*` row already existed, all now reading the row: searchFields, searchObjects, removeNamed, valuePlaceholder (lookup and summary), branchCustom, branchN; no key added. Every remaining English literal is either a code sample / stored value (the family's ruling) or has no row of the same value; those are tabled in the PR body for the seat. Draft PR #10741 opened through the fleet relay (Fixes #10696, Clause-②: no); no code change was needed on top of 68eedfed1. The card's assignee at claim was os-elon-musk (untouched); the PR assignee write was refused by the classifier (see deviations).",
"tests": "Head 68eedfed1, heavy runs through os-verify-lock (slot issue-10696). Pin `pnpm exec vitest run packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.i18n-10696.test.tsx`: head `Tests 17 passed (17)` VERDICT command-exit 0. Base leg (four inspector sources checked out from 383a34f52, pin from head; restore proven by git hash-object == HEAD blob per path and `git diff HEAD` 0 lines): `Tests 7 failed | 10 passed (17)`, run exit 1 — the seven zh cases (`Received: \"Search fields…\"`, `\"Search objects…\"`, `\"Remove region\"`, `\"value\"` x2, `\"— Custom —\"`, `\"Branch 1 · record.amount > 100\"`), en cases and lit controls green. Per-site ablation via objectstack scripts/ablation-replace.mjs (anchor declared to hit once; mutation and restore judged by blob hash on disk): S1..S7 each `Tests 1 failed | 16 passed (17)`, failing only its own zh case, each restored to the HEAD blob. Two recorded no-ops: the driver's first call ran the tool outside the repo (refused before writing, hashes unchanged), and the first S2 reinstated the wrong text at the caller (ReferenceError, zh+en both red — invalid, redone inside ViewObjectPicker). Type-check: `tsc --noEmit` exit 0 and `tsc -p tsconfig.test.json` exit 0 in packages/app-shell (run directly; the turbo type-check was a cache hit), `--listFiles` names the pin once. Tests: metadata-admin/inspectors 103 files `Tests 1428 passed | 1 skipped (1429)` exit 0; the other 210 metadata-admin files in two halves `881 passed` and `1287 passed`, exit 0 each (313 = the tracked population); views/studio-design 65 files `359 passed` exit 0; the rest of app-shell and the repo-wide lint/test shards declared to CI (the four inspectors are reached only through inspectors/index.ts and the registry; exports unchanged). eslint plain form on the 5 changed TS files: `--format json` 5 files, 0 errors, 26 warnings, per file equal to base via `--stdin` on the base blobs (11/2/11/2, pre-existing no-explicit-any + one preserve-manual-memoization), new pin 0; eslint.config.js has no type-aware linting (grep exit 1). Gates exit 0 with their own verdict lines: check-changeset-presence (5 source files of 1 released package, 1 changeset), changeset:check, check:new-line-citations (0 new), check:control-bytes (OK), check:i18n-keys, check:i18n-drift (0 en values changed), check:i18n-dead-keys, check:i18n-designer-parity, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:pending-changeset-literals, check:changeset-claims (no pending changeset names a touched file). H5: 10586-inspector-strings-i18n.md and -2.md sentences still hold, no dated note, frontmatter untouched. Serial: origin/main c3a26ccdaa fetched into refs/worktree/upstream-main-10696, touches none of my files since base, `git merge-tree --write-tree` exit 0; not merged. NOT MEASURED: check:eager-locale-catalogues and the eager-closure budget (need a built apps/console bundle).",
"mcp_calls": "0 — none",
"api_writes": "1 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay, op pr_create, draft forced; run 36290151106 success) which executed POST /repos/objectstack-ai/objectui/pulls (PR #10741). Refused before any request: label-write --assign os-elon-musk on PR 10741 (see deviations). This os-dev-report comment through post-stamped is the only other write attempted; its outcome is in the final message. REST reads only: GET issue 10696, its comments, pulls/10678 (+files), pulls?head=… .",
"deviations": [
"PR assignee not set: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 10741 --assign os-elon-musk` was refused by the Claude Code auto-mode classifier before running (reason given: External System Writes). Not retried, not rerouted; the seat applies it. Its --dry-run had read the route as dispatch (relay live).",
"H3 table column: the order asked for file:line; AGENTS.md #11 bans a line address in a PR body, so the PR body cites file · enclosing symbol/prop instead.",
"Worktree /home/user/objectui-issue-10696 removed after the PR opened (node_modules deleted, `git worktree remove` exit 0 on a clean tree), per the role file's cleanup step; a patch round needs a fresh worktree.",
"The turbo type-check reported a cache hit; both tsc projects were run directly and their exits echoed individually, which is the reading reported."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: none measured (read from source; the pin harness is the lit instrument) · designer inspectors still render English under zh-CN where NO catalogue row of the same value exists — this card forbids new keys, so listed, not fixed: DashboardWidgetInspector WIDGET_TYPES labels (KPI Metric, Bar Chart, …, Pivot Table) and InspectorEmpty messages; the untitled-widget fallback `Widget N` (3 sites); ObjectFieldInspector LOOKUP_OPERATORS labels (partial rows engine.inspector.condition.op.* exist without the symbol prefix, none for at least / at most / contains / in / not in); FlowEdgeInspector branch suffix ` · default`; FlowNodeInspector aria-label `nested node location` and the `Must be a JSON object` error shown via setAdvError; VariableTextInput PICK_LABEL / SEARCH_LABEL / EMPTY_LABEL · dedupe words: designer inspector English literal no key zh-CN · widget type labels untranslated · lookup operator labels untranslated · VariableTextInput Insert a reference · carrier: the seat, as this family-closure card's remainder (needs keys; objectui#4662 carve-out decision)"
]
}
{
"issue": 10696,
"status": "done",
"branch": "claude/issue-10696-widget-search-placeholder",
"pr": "https://github.com/objectstack-ai/objectui/pull/10741",
"session": "session_014mXUNuFomfj24w7s1pZzhN",
"premise_still_valid": true,
"summary": "Round 2 on PR #10741 after the contract review of 68eedfed1 (PR comment 5852290145) FAILED on one missed site. Head is now 7e724988e3 (pushed; 7 files, +174 -23 over 68eedfed1). The FlowNodeInspector nested-node breadcrumb's region crumb (Try / Catch / Branch N from flow-nested-selection.ts regionLabelOf) now reads engine.flowRegion.try / .catch / .branchN through displayRegionLabel — the canvas region header's own reader — so the canvas and the inspector show one word under zh-CN; Body and an authored branch name pass through; en byte-identical. Shape chosen: carry regionKey out of locateFlowNode (the key carries the branch index) and translate at the render site with the locale FlowNodeInspector already holds, rather than threading a locale into the pure codec (which stays English and i18n-free; its own test pins that it mirrors the canvas). displayRegionLabel itself is reused: moved verbatim from previews/flow-region-view.tsx into the leaf module previews/flow-region-label.ts (only runtime import ../i18n.js — no cycle, no new react-refresh warning), imported by both FlowRegionView and FlowNodeInspector, so the mapping is stated once. Census re-run over all 44 inspector sources (27 .tsx + 17 .ts): default pass 283 of 1276 candidates kept on head (289 of 1282 on base), broad pass 1982 of 3814 (1989 of 3821); the only base-minus-head rows are round 1's seven literals; the .ts helpers' remaining English is either another channel (flow-node-config.ts via FLOW_FIELD_ZH), stored values/type tokens, or the seat's list (Body, useFlowScope group headings, expression-validate messages). Changeset title now 'eight inspector words' with a breadcrumb bullet naming the canvas header as the rows' existing reader. No i18n.ts key added; no PR body PATCH — the full corrected body is in pr_body_replacement.",
"tests": "Head 7e724988e3, lock slot issue-10696. Closure build `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build` VERDICT command-exit 0 (the recreated worktree had no dist/, so the first tsc read was TS2307 noise and is not reported). tsc --noEmit exit 0 and tsc -p tsconfig.test.json exit 0 in packages/app-shell (each exit echoed), --listFiles names the pin once. `pnpm exec vitest run` pin + FlowNodeInspector.test.tsx + flow-nested-selection.test.ts + FlowCanvas.test.tsx + flow-canvas-layout.test.ts + flow-region-metrics.test.ts: `Test Files 6 passed (6)`, `Tests 99 passed (99)`, exit 0 (the pin now 22 cases). Base leg (six inspector-side sources from 383a34f52 — the four round-1 inspectors + FlowNodeInspector.tsx + flow-nested-selection.ts — pin from head; each mutated path hashed to its BASE blob, restored to its HEAD blob, `git diff HEAD` 0 lines): `Tests 10 failed | 12 passed (22)`, exit 1 — the seven round-1 zh cases plus the three crumb cases (`Received: \"Try\"`, `\"Catch\"`, `\"Branch 2\"` against 尝试 / 捕获 / 分支 2); en cases and lit controls green; the existing en crumb test in FlowNodeInspector.test.tsx is the outside control (green on head). Ablation S8 via objectstack scripts/ablation-replace.mjs (anchor hit once, blob 7acd18b100ea -> f5ba42c018de -> restored == HEAD): crumb back to `{loc?.regionLabel}` gives `Tests 3 failed | 19 passed (22)`, exactly the three zh crumb cases. Gates exit 0 with verdict lines: check-changeset-presence (10 source files of 1 released package, 1 changeset), check:changeset-claims --base 383a34f52 --head HEAD (no pending changeset names a touched file), changeset:check, check:new-line-citations (0 new), check:control-bytes (OK, 8868 files), check:i18n-keys, check:i18n-drift (0 en values changed), check:i18n-dead-keys, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots. eslint --format json on the 6 round-2 TS files: 0 errors, 3 warnings (FlowNodeInspector.tsx's pre-existing no-explicit-any + react-hooks/set-state-in-effect, equal to its 68eedfed1 blob via --stdin); the new module, codec, its test and the pin 0; eslint.config.js has no type-aware linting. Serial: origin/main 1fc77fd806 fetched into refs/worktree/upstream-main-10696, touches none of my files since base, `git merge-tree --write-tree` exit 0; not merged. NOT MEASURED: check:eager-locale-catalogues and the eager-closure budget (built apps/console bundle); the rest of app-shell and the repo-wide lint/test shards belong to CI (round 1 ran all 313 metadata-admin + 65 studio-design test files green at 68eedfed1).",
"mcp_calls": "0 — none",
"api_writes": "1 — this os-dev-report comment through post-stamped (POST /repos/objectstack-ai/objectstack/dispatches relaying POST /repos/objectstack-ai/objectui/issues/10696/comments); its relay run and read-back are in the final message. git push (not REST) of 7e724988e3. No PR body PATCH (pr_body_replacement carries the body); the PR assignee write was not attempted, per the round-2 order. REST reads: GET issues/comments/5852290145.",
"deviations": [
"Design: chose to carry `regionKey` out of `locateFlowNode` and translate at the render site (the seat's preferred shape); `displayRegionLabel` was MOVED from previews/flow-region-view.tsx to a new leaf module previews/flow-region-label.ts rather than exported from the component .tsx, to reuse it without a cycle and without adding a react-refresh/only-export-components warning. previews/flow-region-view.tsx is therefore touched (its private function replaced by the import; behaviour unchanged, canvas tests green).",
"The first tsc run in the recreated worktree reported ~1860 TS2307 module-resolution errors because `pnpm install` had produced no workspace dist/; the closure was built and tsc re-run (0 errors). The first reading is not a measurement and is not reported as one.",
"Worktree /home/user/objectui-issue-10696 removed again after this round (node_modules deleted, `git worktree remove` on a clean tree), per the role file's cleanup step; a further round recreates it (install + closure build, about 5 minutes).",
"H3 table column: file · enclosing symbol/prop instead of file:line (AGENTS.md #11), as in round 1."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: none measured (read from source; the pin harness is the lit instrument) · English under zh-CN in designer inspectors where NO catalogue row of the same value exists (this card forbids new keys): DashboardWidgetInspector WIDGET_TYPES labels and InspectorEmpty messages; the untitled-widget fallback `Widget N` (3 sites); ObjectFieldInspector LOOKUP_OPERATORS labels (partial rows engine.inspector.condition.op.* without the symbol prefix; none for at least / at most / contains / in / not in); FlowEdgeInspector branch suffix ` · default`; FlowNodeInspector aria-label `nested node location` and the `Must be a JSON object` error via setAdvError; VariableTextInput PICK_LABEL / SEARCH_LABEL / EMPTY_LABEL; flow-nested-selection.ts regionLabelOf `Body` (no same-concept row — the two Body rows are page-block body text); useFlowScope.ts GROUP_LABELS (Flow variables, Upstream outputs, Loop item, Trigger record) plus the three approval scope-group headings and the `pre-update row` detail; expression-validate.ts validateExpressionClient messages (Unbalanced parentheses/brackets, Expected a CEL expression…, Expected a text template…, the single-brace and map-literal explanations, Conditions are bare CEL) · dedupe words: designer inspector English literal no key zh-CN · widget type labels untranslated · lookup operator labels untranslated · VariableTextInput Insert a reference · useFlowScope group labels · carrier: the seat, as this family-closure card's remainder (needs keys; objectui#4662 carve-out decision)"
],
"pr_body_replacement": "Fixes #10696\n\nClause-②: no\n\nA zh-CN author read `Search fields…` in the dashboard widget inspector's filter-binding field picker, while the designer catalogue already carried `engine.form.searchFields` in en and zh and `DatasetDefaultInspector` read it for the same combo. That site now reads the row. The census the triage asked for found seven more inspector sites passing an English literal where an `engine.*` row with the same English already existed; each now reads its row. No catalogue row is added or changed, so the objectui#4662 `engine.*` carve-out does not move, and en-US renders the same words as before.\n\nThis branch resumes the work a previous `os-dev` left at `68eedfed1` (release note `5851632349`); nothing it did was taken as verified. Round 2 (`7e724988e3`) adds the site the contract review of `68eedfed1` found missed: the flow node inspector's nested-node breadcrumb.\n\n## Premise check — H1, measured under zh-CN\n\nBase `383a34f52` (the branch point), pin from this branch: `DashboardWidgetInspector`'s filter-binding combo search box rendered the English literal under zh-CN — `Expected: \"搜索字段…\"`, `Received: \"Search fields…\"`. The lit control on the same base, `DatasetDefaultInspector`'s dimension-field combo, rendered `搜索字段…` (its case passed on base). H1 holds as the card stated it.\n\n## Census — H3, over `metadata-admin/inspectors/*.ts` and `*.tsx` (44 source files: the 27 components and the 17 helpers whose strings they render)\n\nMethod: an AST walk (TypeScript compiler API) over every JSX attribute value (direct, or inside a ternary / template / binary expression), every JSX text and expression child, and every object-literal text prop (`label`, `placeholder`, `title`, `aria-label`, `emptyText`, `message`, `help`, and the like), plus a broad pass over every string literal in those files so a word that flows into a label through a variable or a helper's return is seen too; class-name-shaped and key-shaped strings dropped. Each surviving literal was compared byte-for-byte against the EN values of `metadata-admin/i18n.ts`. Both passes ran on the base tree and on this head. Counts: the default pass keeps 289 of 1282 candidate literals on base and 283 of 1276 on head; the broad pass keeps 1989 of 3821 on base and 1982 of 3814 on head. The rows that disappear between base and head are the seven literals fixed at `68eedfed1`. The eighth site is different in kind: `flow-nested-selection.ts` `regionLabelOf` still returns the English `Try` / `Catch` / `Branch N` (it is the pure, i18n-free mirror of the canvas layout's own fallbacks, and its test pins that), so the census still lists those literals on head with their same-value rows — what changed is their reader, which now translates them at render. The first round's census walked `*.tsx` only and missed that helper; the review of `68eedfed1` found it. Sites are cited by file and enclosing symbol or prop, not by line, per AGENTS.md #11 (a pull-request body has no same file).\n\n### Fixed — a row with the same English existed; the site now reads it\n\n| file · site | literal before | row read now |\n|:--|:--|:--|\n| `DashboardWidgetInspector` · filter-binding `InspectorComboField` `searchPlaceholder` | `Search fields…` | `engine.form.searchFields` |\n| `ViewVariantInspector` · `ViewObjectPicker` `searchPlaceholder` (now a prop its one caller fills) | `Search objects…` | `engine.inspector.dataset.searchObjects` |\n| `ObjectFieldInspector` · `LookupConfigFields` dependsOn chip, remove button `aria-label` | `Remove NAME` | `engine.form.removeNamed` |\n| `ObjectFieldInspector` · `LookupConfigFields` filter row value `placeholder` | `value` | `engine.inspector.condition.valuePlaceholder` |\n| `ObjectFieldInspector` · `SummaryConfigFields` filter row value `placeholder` | `value` | `engine.inspector.condition.valuePlaceholder` |\n| `FlowEdgeInspector` · decision-branch picker, custom row `label` | `— Custom —` | `engine.inspector.flowEdge.branchCustom` (the approval-branch picker beside it already read it) |\n| `FlowEdgeInspector` · decision-branch picker, unnamed branch name (`nm`) | `Branch N` | `engine.flowRegion.branchN` |\n| `FlowNodeInspector` · nested-node breadcrumb, region crumb (label from `flow-nested-selection.ts` `regionLabelOf`) — round 2 | `Try`, `Catch`, `Branch N` | `engine.flowRegion.try`, `.catch`, `.branchN`, through `displayRegionLabel` (the canvas region header's own reader, `previews/flow-region-view.tsx`) |\n\n### Listed for the seat — English words with no row of the same value (⛔ no key added here)\n\n| file · site | literal | nearest row |\n|:--|:--|:--|\n| `DashboardWidgetInspector` · `WIDGET_TYPES[].label` (the widget-type select) | `KPI Metric`, `Bar Chart`, `Horizontal Bar`, `Line Chart`, `Area Chart`, `Pie Chart`, `Donut Chart`, `Funnel`, `Table`, `Pivot Table` | none (`engine.inspector.view.type.*` covers view types, not widget types) |\n| `DashboardWidgetInspector` · `InspectorEmpty` `message` | `Unsupported selection kind: KIND`, `The selected widget was removed from the draft.` | none |\n| `DashboardWidgetInspector` header, `DashboardDefaultInspector` add-widget title and widget list | `Widget N` (untitled-widget fallback, 3 sites) | none (`engine.flowRegion.branchN` is `Branch {n}`, another word) |\n| `ObjectFieldInspector` · `LOOKUP_OPERATORS[].label` | `= equals`, `≠ not equals`, the greater-than and less-than rows, `≥ at least`, `≤ at most`, `contains`, `in (any of)`, `not in` | partial: `engine.inspector.condition.op.equals` / `.notEquals` / `.greaterThan` / `.lessThan` carry the words without the symbol prefix; no row for at least, at most, contains, in, not in |\n| `FlowEdgeInspector` · decision-branch option `suffix` | ` · default` | none (`engine.inspector.flowEdge.typeDefault` is `Normal`; `engine.inspector.pageBlock.option.colorVariant.default` is `Default`, another meaning) |\n| `FlowNodeInspector` · nested-location `aria-label` | `nested node location` | none |\n| `FlowNodeInspector` · `commitAdvanced`, shown through `setAdvError` | `Must be a JSON object` | none |\n| `VariableTextInput` · `PICK_LABEL`, `SEARCH_LABEL`, `EMPTY_LABEL` | `Insert a reference`, `Search references…`, `No matching references.` | none |\n| `flow-nested-selection.ts` · `regionLabelOf` for the `body` region (the loop-body crumb) | `Body` | none of the same concept (the two `Body` rows, `engine.inspector.pageBlock.option.variant.body` and `engine.inspector.pageBlock.field.record:alert.body`, are page-block body text) |\n| `useFlowScope.ts` · `GROUP_LABELS` and the three approval scope-group headings (rendered as `VariableTextInput` `CommandGroup` headings) | `Flow variables`, `Upstream outputs`, `Loop item`, `Trigger record`; `Current record (live at node entry)`, `Trigger snapshot (at submit)`, `Flow variables`; the `pre-update row` detail | none |\n| `expression-validate.ts` · `validateExpressionClient` messages (rendered by `FlowExprIssue` and the edge condition) | `Unbalanced parentheses in …`, `Unbalanced brackets in …`, `Expected a CEL expression but got a … dialect.`, `Expected a text template but got a … expression.`, the single-brace and map-literal explanations, `Conditions are bare CEL (e.g. …).` | none |\n\n### Not words, or another channel — left literal, as PR objectui#10678 and PR objectui#10651 ruled for this family\n\n- Code samples and syntax hints in `placeholder`s: `record.amount * 0.2`, `record.status != 'draft'`, the arrow-function samples in the hook and action script boxes, `comma,separated,values`, the reference-syntax hint in `FlowObjectListField` (`current.FIELD · trigger.FIELD · vars.NODE.KEY`), `/api/v1/…`, `{ }`, `building` (an icon name), the CEL samples in `flow-node-config.ts`.\n- Sample values: `status`, `done` (its byte match with `engine.flowSim.status.done` is a coincidence — that row names a simulator status, this is a sample value in a field), `100`, `0`, `255`, `10`.\n- Stored values and type names rendered as code, or compared rather than shown: HTTP methods, `script`, currency codes (`USD ($)` …), the scope roots `previous` / `previous.FIELD`, `columns[N]`, the operator names in `datasetFilterCondition.ts` (`equals` is a stored operator, not a label), the type tokens `string` / `number` / `boolean` / `expression` / `true` the helpers compare against.\n- `flow-node-config.ts` field labels, help and option labels (`Trigger`, `Object`, `Record created`, `Cron schedule` …): translated at render through `localizeField` from `FLOW_FIELD_ZH` — a different channel, not this card's class.\n- `ViewVariantInspector`'s `TYPE_LABELS` map: read only after `t('engine.inspector.view.type.' + type)` echoes the key back, i.e. for a view type the catalogue lacks — a fallback behind the row, not a literal passed where a row exists.\n- `DashboardDefaultInspector`'s `New widget` / `New TYPE`: the default title written into the draft — author data, not chrome (the objectui#10678 boundary).\n\n## Round 2 — the nested-node breadcrumb (`7e724988e3`)\n\nThe review of `68eedfed1` (PR comment `5852290145`) found that `flow-nested-selection.ts` `regionLabelOf` returns `Try`, `Catch` and `Branch N`, `locateFlowNode` stores it as `regionLabel`, and `FlowNodeInspector` renders it in the `aria-label=\"nested node location\"` crumb, while `engine.flowRegion.try` / `.catch` / `.branchN` exist with the same English and the canvas region header already reads them — so a zh-CN author saw `尝试` on the canvas and `Try` in the inspector.\n\n**Shape chosen: carry the region key out of `locateFlowNode` and translate at the render site.** `NodeLocation` gains `regionKey` (the key `branch-N` carries the branch index), set beside the unchanged English `regionLabel`; `FlowNodeInspector` renders `displayRegionLabel({ key, label }, locale)` with the `locale` it already holds. The pure codec stays English and i18n-free (its own test pins that it mirrors the canvas layout's fallbacks), and the translation happens once, where the locale is. Threading a locale into the helper would have made every `locateFlowNode` caller locale-aware and duplicated the canvas's mapping in the codec.\n\n**Reused `displayRegionLabel` itself, no cycle.** It was a module-private function of `previews/flow-region-view.tsx`; it moved verbatim into `previews/flow-region-label.ts`, a leaf module whose only runtime import is `../i18n.js` (the `LabeledRegion` import is type-only). `FlowRegionView` and `FlowNodeInspector` both import it, so the mapping is stated once and the canvas header and the crumb read one word. A leaf `.ts` module rather than an `export` from the component `.tsx`, so no `react-refresh/only-export-components` warning is added; the parameter is `Pick` of `key` and `label`, so both callers fit. `Body` has no same-concept row and passes through, as does an authored branch name (the function's existing `Branch N` gate); en output is byte-identical (the en rows are the literals).\n\nRound-2 name-status against `68eedfed1`: M `.changeset/10696-inspector-literals-read-existing-keys.md` · M `inspectors/FlowNodeInspector.tsx` · M `inspectors/flow-nested-selection.test.ts` · M `inspectors/flow-nested-selection.ts` · M `inspectors/inspectorStrings.i18n-10696.test.tsx` · A `previews/flow-region-label.ts` · M `previews/flow-region-view.tsx`. Numstat: changeset +8 −2 · FlowNodeInspector +7 −1 · flow-nested-selection.test +2 −0 · flow-nested-selection +12 −0 · pin +105 −0 · flow-region-label +35 −0 · flow-region-view +5 −20; 7 files, +174 −23.\n\n## Pins — red on base, green on head, per-site ablation\n\n`inspectors/inspectorStrings.i18n-10696.test.tsx`, 22 cases: one zh case per fixed site reading the rendered attribute or text (the open combo's search box, a button's `aria-label`, an input's `placeholder`, the select trigger's text, the crumb's region segment) against the catalogue's zh row behind a guard (not the echoed key, not the en row); an en case per site; and a lit control on the same mount, already translated before this change (`DatasetDefaultInspector` for the card's own control; the nested-id hint for the breadcrumb). The breadcrumb block's outside control is the existing en crumb test in `FlowNodeInspector.test.tsx` (`opens a nested node with a container › region › node breadcrumb`), unchanged and green.\n\n- Head `7e724988e3`: the pin, `FlowNodeInspector.test.tsx`, `flow-nested-selection.test.ts`, `FlowCanvas.test.tsx`, `flow-canvas-layout.test.ts` and `flow-region-metrics.test.ts` together: `Test Files 6 passed (6)`, `Tests 99 passed (99)`, exit 0 (the pin's 22 among them). Round 1 head `68eedfed1`: `Tests 17 passed (17)`.\n- Base leg, round 2 — the six inspector-side sources (`DashboardWidgetInspector`, `FlowEdgeInspector`, `ObjectFieldInspector`, `ViewVariantInspector`, `FlowNodeInspector`, `flow-nested-selection.ts`) from `383a34f52`, pin from head: `Tests 10 failed | 12 passed (22)`, exit 1 — the ten failures are the seven zh cases of round 1 (`Received: \"Search fields…\"`, `\"Search objects…\"`, `\"Remove region\"`, `\"value\"` twice, `\"— Custom —\"`, `\"Branch 1 · record.amount > 100\"`) plus the three zh crumb cases (`Received: \"Try\"`, `\"Catch\"`, `\"Branch 2\"`); the en cases and the lit controls pass. Restore proven: each path's `git hash-object` equals its HEAD blob and `git diff HEAD` is 0 lines. Round 1's base leg (four sources) read `Tests 7 failed | 10 passed (17)`.\n- Per-site ablation, with objectstack's `scripts/ablation-replace.mjs` (one anchor declared to hit once; the write and the restore judged by blob hash on disk): each of the eight sites with its literal put back alone fails exactly its own zh case(s) and restores to the HEAD blob. Round 1, S1–S7: `1 failed | 16 passed (17)` each — S1 `searchFields`; S2 `searchObjects` (mutated inside `ViewObjectPicker`, so the passed prop is ignored); S3 `removeNamed`; S4 lookup `valuePlaceholder` (the summary case stays green); S5 summary `valuePlaceholder` (the lookup case stays green); S6 `branchCustom` (anchor lengthened to the decision-branch block, since the approval-branch picker carries the same row); S7 `branchN`. Round 2, S8 — the crumb back to `{loc?.regionLabel}`: `Tests 3 failed | 19 passed (22)`, exactly the three zh crumb cases (try, catch, unnamed branch); the en crumb case, the lit control and the other 17 stay green.\n- Two no-op attempts in round 1, recorded rather than hidden: the driver's first call ran the tool from outside the repository (refused before writing; hashes unchanged), and the first S2 reinstated the wrong text at the caller (`ReferenceError`, so zh and en fell over together — a broken-harness shape, not a reading). Both were redone; the readings above are from the redone legs.\n\n## Gates — at `7e724988e3`; heavy runs through `os-verify-lock`\n\n| gate | exit | reading |\n|:--|:--|:--|\n| `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build` (the closure, so `tsc` reads real `dist/*.d.ts`) | 0 | |\n| `tsc --noEmit` and `tsc -p tsconfig.test.json` in `packages/app-shell`, run directly | 0, 0 | 0 errors; `--listFiles` names the pin once in the test project |\n| `pnpm exec vitest run` over the six files above | 0 | `Test Files 6 passed (6)`, `Tests 99 passed (99)` |\n| round 1, at `68eedfed1`: `metadata-admin/inspectors/` (103 files), the rest of `metadata-admin/` in two halves (105 + 105 = all 313 tracked test files), `views/studio-design/` (65 files) | 0 each | `1428 passed | 1 skipped`, `881 passed`, `1287 passed`, `359 passed` |\n| eslint, plain form, on the 6 TS files round 2 touches | 0 | `--format json`: 6 files, 0 errors, 3 warnings — `FlowNodeInspector.tsx`'s pre-existing `no-explicit-any` and `react-hooks/set-state-in-effect`, equal to its blob at `68eedfed1` (`--stdin`); the new module, the codec, its test and the pin have 0. Round 1's 5 files: 0 errors, 26 warnings, per file equal to base |\n| `check-changeset-presence` | 0 | 10 source files of 1 released package, 1 changeset |\n| `check:changeset-claims` (base `383a34f52`, head) | 0 | no pending changeset names a file this change touches |\n| `changeset:check` (fixed group, no major) | 0 | |\n| `check:new-line-citations` | 0 | 0 new citations |\n| `check:control-bytes` | 0 | OK |\n| `check:i18n-keys`, `check:i18n-drift`, `check:i18n-dead-keys` | 0 each | drift: 0 en values changed, 0 keys added or removed in the designer table |\n| `check:vi-mock-specifiers`, `check:vi-mock-inherit`, `check:vi-mock-override-shape`, `check:test-path-roots` | 0 each | the pin's two new `vi.mock` calls resolve |\n| round 1 only: `check:i18n-designer-parity`, `check:pending-changeset-literals` | 0 each | |\n\n- The eslint narrowing is a measurement: the population is the changed `.ts`/`.tsx` files, which the config's `**/*.{ts,tsx}` block covers; the JSON output counts the files; `eslint.config.js` configures no type-aware linting (a grep for `projectService` or a `parserOptions` project exits 1), so this diff cannot move an untouched file's verdict.\n- The test narrowing: the inspectors are reached only through `inspectors/index.ts` and the inspector registry; `displayRegionLabel`'s two importers are `flow-region-view.tsx` (whose canvas tests ran) and `FlowNodeInspector.tsx`; the package's `exports` do not change. The rest of `packages/app-shell` and the repo-wide `pnpm lint` / `pnpm test` shards belong to CI.\n- NOT MEASURED: `check:eager-locale-catalogues` and the eager-closure budget, which read a built `apps/console` bundle (`performance-budget.yml` runs both).\n\n## Published prose — H5\n\nPending changesets that name these strings: `10586-inspector-strings-i18n.md` (PR 1 of the family: \"plus the existing `engine.form.add` and `engine.form.searchFields`… The dataset inspector reads the `locale` its host already passes\") and `10586-inspector-strings-i18n-2.md` (PR 2: the combo's defaults, \"A label the caller passes still wins\"). Neither sentence is falsified: this change adds callers that pass a translated label, which is exactly the case both describe. No dated note is needed and no frontmatter moved. This PR's own changeset now titles eight words and carries a bullet for the breadcrumb naming the canvas header as the rows' existing reader.\n\n## Serial\n\n`origin/main` `1fc77fd806` (fetched into a private per-worktree ref just before this round's push) touches none of this branch's files since the base `383a34f52`, and `git merge-tree --write-tree` against it is clean (exit 0). Not merged.\n\n## Acceptance notes\n\n- The seat's list above (widget-type labels, `InspectorEmpty` messages, `Widget N`, the lookup operator labels, ` · default`, the nested-location `aria-label`, `Must be a JSON object`, `VariableTextInput`'s three labels, the `Body` region crumb, `useFlowScope`'s group headings, `expression-validate`'s client messages) needs new rows, which this card forbids; it is the family's remaining English under zh, read from source with the pin's harness as the instrument.\n- `ViewVariantInspector`'s `ViewObjectPicker` takes `searchPlaceholder` as a required prop rather than reading `useMetadataLocale()` itself, because its host already carries `locale` — the `locale` prop channel PR objectui#10678 named for hosted inspectors.\n- `flow-region-view.tsx` loses its private `displayRegionLabel` and imports the moved one; its behaviour is unchanged and `FlowCanvas.test.tsx`, `flow-canvas-layout.test.ts` and `flow-region-metrics.test.ts` ran green.\n\n---\n_Generated by [Claude Code](https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN)_\n"
}
✅ ACCEPT: objectui#10741 at 7e72498; body, ready and auto-merge follow this ACCEPT
domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. Claim 5851771741 (a re-claim; the first was 5838948159). It executes triage 5838471955 (bug · p3, the family-closure card).
eight designer-inspector sites that passed an English literal now read the engine.* row carrying the same English, so a zh-CN author sees Chinese there. The sites: Search fields…, Search objects…, Remove NAME, value ×2, — Custom —, Branch N, and, in round 2, the nested-node breadcrumb's Try / Catch / Branch N. The breadcrumb reads the canvas header's own displayRegionLabel, moved to the leaf module previews/flow-region-label.ts, so the canvas and the inspector show one word. No catalogue row is added or changed, and en output is byte-identical
surface
the move touches previews/flow-region-view.tsx and adds previews/flow-region-label.ts, outside inspectors/. The review judged it minimal. Exporting in place would trip react-refresh/only-export-components (measured) and pull the canvas component graph into the inspector. The seat accepts it within the ruling to reuse displayRegionLabel
pins
22 cases: one zh case per site against the catalogue row, en cases, and lit controls. Base: 10 red of 22. Head: 22 green. There is a per-site ablation for all eight sites, each proven on disk, plus the reviewer's canvas-local-copy leg
Clause-②: no / semver
'@object-ui/app-shell': patch; exports untouched; the objectui#4662 engine.* carve-out does not move
reviews
two rounds, both at CONTRACT_REVIEW_TIER. Round 1 FAIL at 68eedfe (5852290145): one missed site, the breadcrumb, found because the census had walked *.tsx only. Round 2 PASS at 7e72498, posted with this landing. The seat read both transcripts: every model turn ran at tier
seat edits to the dev's body
four, each from the PASS record: the Fixed row 8 parenthetical names flow-region-label.ts; "moved verbatim" becomes "moved, with its body unchanged (the signature gains export …)"; the Serial line notes the re-read at ee6f6c6a45; the control test's full title
serial
git merge-tree --write-tree against main ee6f6c6a45 is clean; no open PR touches the 11 files
governed
NOT GOVERNED (check-governed-queue-guard --test, 11 real paths)
CI
head 7e72498: 39 green, 3 skipped, 1 red. The red check is Inert vi.mock Specifier Check, main-red (objectui#10731, this seat's p1, in progress)
assignee
none: the dev's label-write --assign on the PR was refused by the permission classifier, and the seat has surfaced it to the maintainer rather than re-issue it
closing keywords
Fixes #10696 only
Findings, each with its disposition
The family's remaining English under zh-CN, where no row of the same value exists (widget-type labels, InspectorEmpty messages, Widget N, the lookup operator labels, · default, the nested-location aria-label, Must be a JSON object, VariableTextInput's three labels, the loop Body crumb, useFlowScope's group headings, expression-validate's client messages) ⇒ one card from this seat. Closing it needs new catalogue rows, so it is a decision on the objectui#4662 carve-out.
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: the customer's language | i18n.surface-matrix | P2
Triage: first grade (family closure card) —
bug·priority:p3·domain:ui·area:i18n·pm:queue(findingremoved — graded)Triage: lands in
packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx(the field combo'ssearchPlaceholderis the English literalSearch fields…) ⇒domain:ui; rationale: a zh-CN author reads English on an otherwise translated inspector, although the keyengine.form.searchFieldsexists in both locales and the siblingDatasetDefaultInspectorreads it. It was read from source with a lit control and has no measuredreach:⇒ p3, the designer hard-coded-English family (objectui#9652, p3). objectui#10586, that family's last card, is closed, so this card is its closure card for any string the census missed.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T19:39Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/main.Execution note: first, measure under zh-CN. Then read the existing
engine.form.searchFieldskey here (no new key, so the objectui#4662engine.*carve-out stays untouched), and census the inspectors for any other literal passed where a key exists.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 6 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-10696-widget-search-placeholderWorktree:
objectui-issue-10696Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx(the field combo'ssearchPlaceholderreadsengine.form.searchFields), plus any other inspector the census (triage execution note) finds passing an English literal where anengine.*key already exists; tests; one changeset ('@object-ui/app-shell': patch). ⛔ No new i18n key (the objectui#4662engine.*carve-out stays untouched). Stop on breach and explain it in the reportContainer & model:
S,mode:subagent,model: opus—dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes triage5838471955(bug · p3, family closure card: measure under zh-CN first, read the existing key, census the inspectors)Clause-②: no — a translated string replaces an English literal; no declared surface moves
Thread-read: 5838471955
Serial constraints cleared: open-PR file lists read 2026-09-25T20:14Z: no open PR touches
metadata-admin/inspectors/ormetadata-admin/i18n.ts.check-governed-queue-guard.mjs --test packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx: NOT GOVERNED.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
Release:
domain:uiseat 2, sessionsession_014mXUNuFomfj24w7s1pZzhN— shift closed on the maintainer's instruction (「继续,当前任务处理完就下班」, this session's chat, 2026-09-27); the dispatchedos-devstopped on a usage limit (weekly; the API reported the reset as 2026-10-01 21:00 UTC) before reporting ⇒ assignee cleared,pm:dispatched→pm:queue; the next holder claims it afresh.State at release (read from GitHub and the dev's worktree):
claude/issue-10696-widget-search-placeholderis pushed at68eedfed1(1 commit: inspector literals with an existing catalogue row read it, includingDashboardWidgetInspector's search placeholder andViewVariantInspector.tsx, plusinspectorStrings.i18n-10696.test.tsx; 6 files, +415/-8). Worktree clean. No PR was opened and no report exists.What the next holder owes: verify the pin (red on base, green on head, per-site ablation), the census table, the gates, then open the draft PR (
Fixes #10696,Clause-②: no) and review it.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
Claim: PM loop round 6 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-10696-widget-search-placeholderWorktree:
objectui-issue-10696Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx(the field combo'ssearchPlaceholderreadsengine.form.searchFields), plus any other inspector the census (triage execution note) finds passing an English literal where anengine.*key already exists; tests; one changeset ('@object-ui/app-shell': patch). ⛔ No new i18n key (the objectui#4662engine.*carve-out stays untouched). Stop on breach and explain it in the reportContainer & model:
S,mode:subagent,model: fable(the ceiling;opussubagents hit a weekly usage limit) —dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes triage5838471955(bug · p3, family closure card: measure under zh-CN first, read the existing key, census the inspectors)Clause-②: no — a translated string replaces an English literal; no declared surface moves
Thread-read: 5851632349
Serial constraints cleared: open-PR file lists read 2026-09-25T20:14Z: no open PR touches
metadata-admin/inspectors/ormetadata-admin/i18n.ts.check-governed-queue-guard.mjs --test packages/app-shell/src/views/metadata-admin/inspectors/DashboardWidgetInspector.tsx: NOT GOVERNED.Re-claim: this seat's own
Release:(5851632349) is withdrawn on the maintainer's instruction 「你应该把你当前的pr 都处理完,跟进到合并」 (this session's chat, 2026-09-27). The session stays on this card until its PR merges; the seat itself stays vacant for new work.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{ "issue": 10696, "status": "done", "branch": "claude/issue-10696-widget-search-placeholder", "pr": "https://github.com/objectstack-ai/objectui/pull/10741", "session": "session_014mXUNuFomfj24w7s1pZzhN", "premise_still_valid": true, "summary": "Resumed the branch at 68eedfed1 (1 commit, 6 files: DashboardWidgetInspector, ViewVariantInspector, ObjectFieldInspector, FlowEdgeInspector, the pin inspectorStrings.i18n-10696.test.tsx, one app-shell patch changeset) and took nothing as verified. H1 measured on base 383a34f52 under zh-CN: the widget inspector's filter-binding combo search box rendered `Search fields…` while DatasetDefaultInspector's combo rendered `搜索字段…`. H3 census (AST walk over the 27 inspector sources, default and broad passes, base vs head, each literal matched byte-for-byte against the EN catalogue) confirms exactly seven sites had a literal whose `engine.*` row already existed, all now reading the row: searchFields, searchObjects, removeNamed, valuePlaceholder (lookup and summary), branchCustom, branchN; no key added. Every remaining English literal is either a code sample / stored value (the family's ruling) or has no row of the same value; those are tabled in the PR body for the seat. Draft PR #10741 opened through the fleet relay (Fixes #10696, Clause-②: no); no code change was needed on top of 68eedfed1. The card's assignee at claim was os-elon-musk (untouched); the PR assignee write was refused by the classifier (see deviations).", "tests": "Head 68eedfed1, heavy runs through os-verify-lock (slot issue-10696). Pin `pnpm exec vitest run packages/app-shell/src/views/metadata-admin/inspectors/inspectorStrings.i18n-10696.test.tsx`: head `Tests 17 passed (17)` VERDICT command-exit 0. Base leg (four inspector sources checked out from 383a34f52, pin from head; restore proven by git hash-object == HEAD blob per path and `git diff HEAD` 0 lines): `Tests 7 failed | 10 passed (17)`, run exit 1 — the seven zh cases (`Received: \"Search fields…\"`, `\"Search objects…\"`, `\"Remove region\"`, `\"value\"` x2, `\"— Custom —\"`, `\"Branch 1 · record.amount > 100\"`), en cases and lit controls green. Per-site ablation via objectstack scripts/ablation-replace.mjs (anchor declared to hit once; mutation and restore judged by blob hash on disk): S1..S7 each `Tests 1 failed | 16 passed (17)`, failing only its own zh case, each restored to the HEAD blob. Two recorded no-ops: the driver's first call ran the tool outside the repo (refused before writing, hashes unchanged), and the first S2 reinstated the wrong text at the caller (ReferenceError, zh+en both red — invalid, redone inside ViewObjectPicker). Type-check: `tsc --noEmit` exit 0 and `tsc -p tsconfig.test.json` exit 0 in packages/app-shell (run directly; the turbo type-check was a cache hit), `--listFiles` names the pin once. Tests: metadata-admin/inspectors 103 files `Tests 1428 passed | 1 skipped (1429)` exit 0; the other 210 metadata-admin files in two halves `881 passed` and `1287 passed`, exit 0 each (313 = the tracked population); views/studio-design 65 files `359 passed` exit 0; the rest of app-shell and the repo-wide lint/test shards declared to CI (the four inspectors are reached only through inspectors/index.ts and the registry; exports unchanged). eslint plain form on the 5 changed TS files: `--format json` 5 files, 0 errors, 26 warnings, per file equal to base via `--stdin` on the base blobs (11/2/11/2, pre-existing no-explicit-any + one preserve-manual-memoization), new pin 0; eslint.config.js has no type-aware linting (grep exit 1). Gates exit 0 with their own verdict lines: check-changeset-presence (5 source files of 1 released package, 1 changeset), changeset:check, check:new-line-citations (0 new), check:control-bytes (OK), check:i18n-keys, check:i18n-drift (0 en values changed), check:i18n-dead-keys, check:i18n-designer-parity, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:pending-changeset-literals, check:changeset-claims (no pending changeset names a touched file). H5: 10586-inspector-strings-i18n.md and -2.md sentences still hold, no dated note, frontmatter untouched. Serial: origin/main c3a26ccdaa fetched into refs/worktree/upstream-main-10696, touches none of my files since base, `git merge-tree --write-tree` exit 0; not merged. NOT MEASURED: check:eager-locale-catalogues and the eager-closure budget (need a built apps/console bundle).", "mcp_calls": "0 — none", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay, op pr_create, draft forced; run 36290151106 success) which executed POST /repos/objectstack-ai/objectui/pulls (PR #10741). Refused before any request: label-write --assign os-elon-musk on PR 10741 (see deviations). This os-dev-report comment through post-stamped is the only other write attempted; its outcome is in the final message. REST reads only: GET issue 10696, its comments, pulls/10678 (+files), pulls?head=… .", "deviations": [ "PR assignee not set: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 10741 --assign os-elon-musk` was refused by the Claude Code auto-mode classifier before running (reason given: External System Writes). Not retried, not rerouted; the seat applies it. Its --dry-run had read the route as dispatch (relay live).", "H3 table column: the order asked for file:line; AGENTS.md #11 bans a line address in a PR body, so the PR body cites file · enclosing symbol/prop instead.", "Worktree /home/user/objectui-issue-10696 removed after the PR opened (node_modules deleted, `git worktree remove` exit 0 on a clean tree), per the role file's cleanup step; a patch round needs a fresh worktree.", "The turbo type-check reported a cache hit; both tsc projects were run directly and their exits echoed individually, which is the reading reported." ], "open_questions": [], "out_of_scope_findings": [ "class: a · reach: none measured (read from source; the pin harness is the lit instrument) · designer inspectors still render English under zh-CN where NO catalogue row of the same value exists — this card forbids new keys, so listed, not fixed: DashboardWidgetInspector WIDGET_TYPES labels (KPI Metric, Bar Chart, …, Pivot Table) and InspectorEmpty messages; the untitled-widget fallback `Widget N` (3 sites); ObjectFieldInspector LOOKUP_OPERATORS labels (partial rows engine.inspector.condition.op.* exist without the symbol prefix, none for at least / at most / contains / in / not in); FlowEdgeInspector branch suffix ` · default`; FlowNodeInspector aria-label `nested node location` and the `Must be a JSON object` error shown via setAdvError; VariableTextInput PICK_LABEL / SEARCH_LABEL / EMPTY_LABEL · dedupe words: designer inspector English literal no key zh-CN · widget type labels untranslated · lookup operator labels untranslated · VariableTextInput Insert a reference · carrier: the seat, as this family-closure card's remainder (needs keys; objectui#4662 carve-out decision)" ] }Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{ "issue": 10696, "status": "done", "branch": "claude/issue-10696-widget-search-placeholder", "pr": "https://github.com/objectstack-ai/objectui/pull/10741", "session": "session_014mXUNuFomfj24w7s1pZzhN", "premise_still_valid": true, "summary": "Round 2 on PR #10741 after the contract review of 68eedfed1 (PR comment 5852290145) FAILED on one missed site. Head is now 7e724988e3 (pushed; 7 files, +174 -23 over 68eedfed1). The FlowNodeInspector nested-node breadcrumb's region crumb (Try / Catch / Branch N from flow-nested-selection.ts regionLabelOf) now reads engine.flowRegion.try / .catch / .branchN through displayRegionLabel — the canvas region header's own reader — so the canvas and the inspector show one word under zh-CN; Body and an authored branch name pass through; en byte-identical. Shape chosen: carry regionKey out of locateFlowNode (the key carries the branch index) and translate at the render site with the locale FlowNodeInspector already holds, rather than threading a locale into the pure codec (which stays English and i18n-free; its own test pins that it mirrors the canvas). displayRegionLabel itself is reused: moved verbatim from previews/flow-region-view.tsx into the leaf module previews/flow-region-label.ts (only runtime import ../i18n.js — no cycle, no new react-refresh warning), imported by both FlowRegionView and FlowNodeInspector, so the mapping is stated once. Census re-run over all 44 inspector sources (27 .tsx + 17 .ts): default pass 283 of 1276 candidates kept on head (289 of 1282 on base), broad pass 1982 of 3814 (1989 of 3821); the only base-minus-head rows are round 1's seven literals; the .ts helpers' remaining English is either another channel (flow-node-config.ts via FLOW_FIELD_ZH), stored values/type tokens, or the seat's list (Body, useFlowScope group headings, expression-validate messages). Changeset title now 'eight inspector words' with a breadcrumb bullet naming the canvas header as the rows' existing reader. No i18n.ts key added; no PR body PATCH — the full corrected body is in pr_body_replacement.", "tests": "Head 7e724988e3, lock slot issue-10696. Closure build `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build` VERDICT command-exit 0 (the recreated worktree had no dist/, so the first tsc read was TS2307 noise and is not reported). tsc --noEmit exit 0 and tsc -p tsconfig.test.json exit 0 in packages/app-shell (each exit echoed), --listFiles names the pin once. `pnpm exec vitest run` pin + FlowNodeInspector.test.tsx + flow-nested-selection.test.ts + FlowCanvas.test.tsx + flow-canvas-layout.test.ts + flow-region-metrics.test.ts: `Test Files 6 passed (6)`, `Tests 99 passed (99)`, exit 0 (the pin now 22 cases). Base leg (six inspector-side sources from 383a34f52 — the four round-1 inspectors + FlowNodeInspector.tsx + flow-nested-selection.ts — pin from head; each mutated path hashed to its BASE blob, restored to its HEAD blob, `git diff HEAD` 0 lines): `Tests 10 failed | 12 passed (22)`, exit 1 — the seven round-1 zh cases plus the three crumb cases (`Received: \"Try\"`, `\"Catch\"`, `\"Branch 2\"` against 尝试 / 捕获 / 分支 2); en cases and lit controls green; the existing en crumb test in FlowNodeInspector.test.tsx is the outside control (green on head). Ablation S8 via objectstack scripts/ablation-replace.mjs (anchor hit once, blob 7acd18b100ea -> f5ba42c018de -> restored == HEAD): crumb back to `{loc?.regionLabel}` gives `Tests 3 failed | 19 passed (22)`, exactly the three zh crumb cases. Gates exit 0 with verdict lines: check-changeset-presence (10 source files of 1 released package, 1 changeset), check:changeset-claims --base 383a34f52 --head HEAD (no pending changeset names a touched file), changeset:check, check:new-line-citations (0 new), check:control-bytes (OK, 8868 files), check:i18n-keys, check:i18n-drift (0 en values changed), check:i18n-dead-keys, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots. eslint --format json on the 6 round-2 TS files: 0 errors, 3 warnings (FlowNodeInspector.tsx's pre-existing no-explicit-any + react-hooks/set-state-in-effect, equal to its 68eedfed1 blob via --stdin); the new module, codec, its test and the pin 0; eslint.config.js has no type-aware linting. Serial: origin/main 1fc77fd806 fetched into refs/worktree/upstream-main-10696, touches none of my files since base, `git merge-tree --write-tree` exit 0; not merged. NOT MEASURED: check:eager-locale-catalogues and the eager-closure budget (built apps/console bundle); the rest of app-shell and the repo-wide lint/test shards belong to CI (round 1 ran all 313 metadata-admin + 65 studio-design test files green at 68eedfed1).", "mcp_calls": "0 — none", "api_writes": "1 — this os-dev-report comment through post-stamped (POST /repos/objectstack-ai/objectstack/dispatches relaying POST /repos/objectstack-ai/objectui/issues/10696/comments); its relay run and read-back are in the final message. git push (not REST) of 7e724988e3. No PR body PATCH (pr_body_replacement carries the body); the PR assignee write was not attempted, per the round-2 order. REST reads: GET issues/comments/5852290145.", "deviations": [ "Design: chose to carry `regionKey` out of `locateFlowNode` and translate at the render site (the seat's preferred shape); `displayRegionLabel` was MOVED from previews/flow-region-view.tsx to a new leaf module previews/flow-region-label.ts rather than exported from the component .tsx, to reuse it without a cycle and without adding a react-refresh/only-export-components warning. previews/flow-region-view.tsx is therefore touched (its private function replaced by the import; behaviour unchanged, canvas tests green).", "The first tsc run in the recreated worktree reported ~1860 TS2307 module-resolution errors because `pnpm install` had produced no workspace dist/; the closure was built and tsc re-run (0 errors). The first reading is not a measurement and is not reported as one.", "Worktree /home/user/objectui-issue-10696 removed again after this round (node_modules deleted, `git worktree remove` on a clean tree), per the role file's cleanup step; a further round recreates it (install + closure build, about 5 minutes).", "H3 table column: file · enclosing symbol/prop instead of file:line (AGENTS.md #11), as in round 1." ], "open_questions": [], "out_of_scope_findings": [ "class: a · reach: none measured (read from source; the pin harness is the lit instrument) · English under zh-CN in designer inspectors where NO catalogue row of the same value exists (this card forbids new keys): DashboardWidgetInspector WIDGET_TYPES labels and InspectorEmpty messages; the untitled-widget fallback `Widget N` (3 sites); ObjectFieldInspector LOOKUP_OPERATORS labels (partial rows engine.inspector.condition.op.* without the symbol prefix; none for at least / at most / contains / in / not in); FlowEdgeInspector branch suffix ` · default`; FlowNodeInspector aria-label `nested node location` and the `Must be a JSON object` error via setAdvError; VariableTextInput PICK_LABEL / SEARCH_LABEL / EMPTY_LABEL; flow-nested-selection.ts regionLabelOf `Body` (no same-concept row — the two Body rows are page-block body text); useFlowScope.ts GROUP_LABELS (Flow variables, Upstream outputs, Loop item, Trigger record) plus the three approval scope-group headings and the `pre-update row` detail; expression-validate.ts validateExpressionClient messages (Unbalanced parentheses/brackets, Expected a CEL expression…, Expected a text template…, the single-brace and map-literal explanations, Conditions are bare CEL) · dedupe words: designer inspector English literal no key zh-CN · widget type labels untranslated · lookup operator labels untranslated · VariableTextInput Insert a reference · useFlowScope group labels · carrier: the seat, as this family-closure card's remainder (needs keys; objectui#4662 carve-out decision)" ], "pr_body_replacement": "Fixes #10696\n\nClause-②: no\n\nA zh-CN author read `Search fields…` in the dashboard widget inspector's filter-binding field picker, while the designer catalogue already carried `engine.form.searchFields` in en and zh and `DatasetDefaultInspector` read it for the same combo. That site now reads the row. The census the triage asked for found seven more inspector sites passing an English literal where an `engine.*` row with the same English already existed; each now reads its row. No catalogue row is added or changed, so the objectui#4662 `engine.*` carve-out does not move, and en-US renders the same words as before.\n\nThis branch resumes the work a previous `os-dev` left at `68eedfed1` (release note `5851632349`); nothing it did was taken as verified. Round 2 (`7e724988e3`) adds the site the contract review of `68eedfed1` found missed: the flow node inspector's nested-node breadcrumb.\n\n## Premise check — H1, measured under zh-CN\n\nBase `383a34f52` (the branch point), pin from this branch: `DashboardWidgetInspector`'s filter-binding combo search box rendered the English literal under zh-CN — `Expected: \"搜索字段…\"`, `Received: \"Search fields…\"`. The lit control on the same base, `DatasetDefaultInspector`'s dimension-field combo, rendered `搜索字段…` (its case passed on base). H1 holds as the card stated it.\n\n## Census — H3, over `metadata-admin/inspectors/*.ts` and `*.tsx` (44 source files: the 27 components and the 17 helpers whose strings they render)\n\nMethod: an AST walk (TypeScript compiler API) over every JSX attribute value (direct, or inside a ternary / template / binary expression), every JSX text and expression child, and every object-literal text prop (`label`, `placeholder`, `title`, `aria-label`, `emptyText`, `message`, `help`, and the like), plus a broad pass over every string literal in those files so a word that flows into a label through a variable or a helper's return is seen too; class-name-shaped and key-shaped strings dropped. Each surviving literal was compared byte-for-byte against the EN values of `metadata-admin/i18n.ts`. Both passes ran on the base tree and on this head. Counts: the default pass keeps 289 of 1282 candidate literals on base and 283 of 1276 on head; the broad pass keeps 1989 of 3821 on base and 1982 of 3814 on head. The rows that disappear between base and head are the seven literals fixed at `68eedfed1`. The eighth site is different in kind: `flow-nested-selection.ts` `regionLabelOf` still returns the English `Try` / `Catch` / `Branch N` (it is the pure, i18n-free mirror of the canvas layout's own fallbacks, and its test pins that), so the census still lists those literals on head with their same-value rows — what changed is their reader, which now translates them at render. The first round's census walked `*.tsx` only and missed that helper; the review of `68eedfed1` found it. Sites are cited by file and enclosing symbol or prop, not by line, per AGENTS.md #11 (a pull-request body has no same file).\n\n### Fixed — a row with the same English existed; the site now reads it\n\n| file · site | literal before | row read now |\n|:--|:--|:--|\n| `DashboardWidgetInspector` · filter-binding `InspectorComboField` `searchPlaceholder` | `Search fields…` | `engine.form.searchFields` |\n| `ViewVariantInspector` · `ViewObjectPicker` `searchPlaceholder` (now a prop its one caller fills) | `Search objects…` | `engine.inspector.dataset.searchObjects` |\n| `ObjectFieldInspector` · `LookupConfigFields` dependsOn chip, remove button `aria-label` | `Remove NAME` | `engine.form.removeNamed` |\n| `ObjectFieldInspector` · `LookupConfigFields` filter row value `placeholder` | `value` | `engine.inspector.condition.valuePlaceholder` |\n| `ObjectFieldInspector` · `SummaryConfigFields` filter row value `placeholder` | `value` | `engine.inspector.condition.valuePlaceholder` |\n| `FlowEdgeInspector` · decision-branch picker, custom row `label` | `— Custom —` | `engine.inspector.flowEdge.branchCustom` (the approval-branch picker beside it already read it) |\n| `FlowEdgeInspector` · decision-branch picker, unnamed branch name (`nm`) | `Branch N` | `engine.flowRegion.branchN` |\n| `FlowNodeInspector` · nested-node breadcrumb, region crumb (label from `flow-nested-selection.ts` `regionLabelOf`) — round 2 | `Try`, `Catch`, `Branch N` | `engine.flowRegion.try`, `.catch`, `.branchN`, through `displayRegionLabel` (the canvas region header's own reader, `previews/flow-region-view.tsx`) |\n\n### Listed for the seat — English words with no row of the same value (⛔ no key added here)\n\n| file · site | literal | nearest row |\n|:--|:--|:--|\n| `DashboardWidgetInspector` · `WIDGET_TYPES[].label` (the widget-type select) | `KPI Metric`, `Bar Chart`, `Horizontal Bar`, `Line Chart`, `Area Chart`, `Pie Chart`, `Donut Chart`, `Funnel`, `Table`, `Pivot Table` | none (`engine.inspector.view.type.*` covers view types, not widget types) |\n| `DashboardWidgetInspector` · `InspectorEmpty` `message` | `Unsupported selection kind: KIND`, `The selected widget was removed from the draft.` | none |\n| `DashboardWidgetInspector` header, `DashboardDefaultInspector` add-widget title and widget list | `Widget N` (untitled-widget fallback, 3 sites) | none (`engine.flowRegion.branchN` is `Branch {n}`, another word) |\n| `ObjectFieldInspector` · `LOOKUP_OPERATORS[].label` | `= equals`, `≠ not equals`, the greater-than and less-than rows, `≥ at least`, `≤ at most`, `contains`, `in (any of)`, `not in` | partial: `engine.inspector.condition.op.equals` / `.notEquals` / `.greaterThan` / `.lessThan` carry the words without the symbol prefix; no row for at least, at most, contains, in, not in |\n| `FlowEdgeInspector` · decision-branch option `suffix` | ` · default` | none (`engine.inspector.flowEdge.typeDefault` is `Normal`; `engine.inspector.pageBlock.option.colorVariant.default` is `Default`, another meaning) |\n| `FlowNodeInspector` · nested-location `aria-label` | `nested node location` | none |\n| `FlowNodeInspector` · `commitAdvanced`, shown through `setAdvError` | `Must be a JSON object` | none |\n| `VariableTextInput` · `PICK_LABEL`, `SEARCH_LABEL`, `EMPTY_LABEL` | `Insert a reference`, `Search references…`, `No matching references.` | none |\n| `flow-nested-selection.ts` · `regionLabelOf` for the `body` region (the loop-body crumb) | `Body` | none of the same concept (the two `Body` rows, `engine.inspector.pageBlock.option.variant.body` and `engine.inspector.pageBlock.field.record:alert.body`, are page-block body text) |\n| `useFlowScope.ts` · `GROUP_LABELS` and the three approval scope-group headings (rendered as `VariableTextInput` `CommandGroup` headings) | `Flow variables`, `Upstream outputs`, `Loop item`, `Trigger record`; `Current record (live at node entry)`, `Trigger snapshot (at submit)`, `Flow variables`; the `pre-update row` detail | none |\n| `expression-validate.ts` · `validateExpressionClient` messages (rendered by `FlowExprIssue` and the edge condition) | `Unbalanced parentheses in …`, `Unbalanced brackets in …`, `Expected a CEL expression but got a … dialect.`, `Expected a text template but got a … expression.`, the single-brace and map-literal explanations, `Conditions are bare CEL (e.g. …).` | none |\n\n### Not words, or another channel — left literal, as PR objectui#10678 and PR objectui#10651 ruled for this family\n\n- Code samples and syntax hints in `placeholder`s: `record.amount * 0.2`, `record.status != 'draft'`, the arrow-function samples in the hook and action script boxes, `comma,separated,values`, the reference-syntax hint in `FlowObjectListField` (`current.FIELD · trigger.FIELD · vars.NODE.KEY`), `/api/v1/…`, `{ }`, `building` (an icon name), the CEL samples in `flow-node-config.ts`.\n- Sample values: `status`, `done` (its byte match with `engine.flowSim.status.done` is a coincidence — that row names a simulator status, this is a sample value in a field), `100`, `0`, `255`, `10`.\n- Stored values and type names rendered as code, or compared rather than shown: HTTP methods, `script`, currency codes (`USD ($)` …), the scope roots `previous` / `previous.FIELD`, `columns[N]`, the operator names in `datasetFilterCondition.ts` (`equals` is a stored operator, not a label), the type tokens `string` / `number` / `boolean` / `expression` / `true` the helpers compare against.\n- `flow-node-config.ts` field labels, help and option labels (`Trigger`, `Object`, `Record created`, `Cron schedule` …): translated at render through `localizeField` from `FLOW_FIELD_ZH` — a different channel, not this card's class.\n- `ViewVariantInspector`'s `TYPE_LABELS` map: read only after `t('engine.inspector.view.type.' + type)` echoes the key back, i.e. for a view type the catalogue lacks — a fallback behind the row, not a literal passed where a row exists.\n- `DashboardDefaultInspector`'s `New widget` / `New TYPE`: the default title written into the draft — author data, not chrome (the objectui#10678 boundary).\n\n## Round 2 — the nested-node breadcrumb (`7e724988e3`)\n\nThe review of `68eedfed1` (PR comment `5852290145`) found that `flow-nested-selection.ts` `regionLabelOf` returns `Try`, `Catch` and `Branch N`, `locateFlowNode` stores it as `regionLabel`, and `FlowNodeInspector` renders it in the `aria-label=\"nested node location\"` crumb, while `engine.flowRegion.try` / `.catch` / `.branchN` exist with the same English and the canvas region header already reads them — so a zh-CN author saw `尝试` on the canvas and `Try` in the inspector.\n\n**Shape chosen: carry the region key out of `locateFlowNode` and translate at the render site.** `NodeLocation` gains `regionKey` (the key `branch-N` carries the branch index), set beside the unchanged English `regionLabel`; `FlowNodeInspector` renders `displayRegionLabel({ key, label }, locale)` with the `locale` it already holds. The pure codec stays English and i18n-free (its own test pins that it mirrors the canvas layout's fallbacks), and the translation happens once, where the locale is. Threading a locale into the helper would have made every `locateFlowNode` caller locale-aware and duplicated the canvas's mapping in the codec.\n\n**Reused `displayRegionLabel` itself, no cycle.** It was a module-private function of `previews/flow-region-view.tsx`; it moved verbatim into `previews/flow-region-label.ts`, a leaf module whose only runtime import is `../i18n.js` (the `LabeledRegion` import is type-only). `FlowRegionView` and `FlowNodeInspector` both import it, so the mapping is stated once and the canvas header and the crumb read one word. A leaf `.ts` module rather than an `export` from the component `.tsx`, so no `react-refresh/only-export-components` warning is added; the parameter is `Pick` of `key` and `label`, so both callers fit. `Body` has no same-concept row and passes through, as does an authored branch name (the function's existing `Branch N` gate); en output is byte-identical (the en rows are the literals).\n\nRound-2 name-status against `68eedfed1`: M `.changeset/10696-inspector-literals-read-existing-keys.md` · M `inspectors/FlowNodeInspector.tsx` · M `inspectors/flow-nested-selection.test.ts` · M `inspectors/flow-nested-selection.ts` · M `inspectors/inspectorStrings.i18n-10696.test.tsx` · A `previews/flow-region-label.ts` · M `previews/flow-region-view.tsx`. Numstat: changeset +8 −2 · FlowNodeInspector +7 −1 · flow-nested-selection.test +2 −0 · flow-nested-selection +12 −0 · pin +105 −0 · flow-region-label +35 −0 · flow-region-view +5 −20; 7 files, +174 −23.\n\n## Pins — red on base, green on head, per-site ablation\n\n`inspectors/inspectorStrings.i18n-10696.test.tsx`, 22 cases: one zh case per fixed site reading the rendered attribute or text (the open combo's search box, a button's `aria-label`, an input's `placeholder`, the select trigger's text, the crumb's region segment) against the catalogue's zh row behind a guard (not the echoed key, not the en row); an en case per site; and a lit control on the same mount, already translated before this change (`DatasetDefaultInspector` for the card's own control; the nested-id hint for the breadcrumb). The breadcrumb block's outside control is the existing en crumb test in `FlowNodeInspector.test.tsx` (`opens a nested node with a container › region › node breadcrumb`), unchanged and green.\n\n- Head `7e724988e3`: the pin, `FlowNodeInspector.test.tsx`, `flow-nested-selection.test.ts`, `FlowCanvas.test.tsx`, `flow-canvas-layout.test.ts` and `flow-region-metrics.test.ts` together: `Test Files 6 passed (6)`, `Tests 99 passed (99)`, exit 0 (the pin's 22 among them). Round 1 head `68eedfed1`: `Tests 17 passed (17)`.\n- Base leg, round 2 — the six inspector-side sources (`DashboardWidgetInspector`, `FlowEdgeInspector`, `ObjectFieldInspector`, `ViewVariantInspector`, `FlowNodeInspector`, `flow-nested-selection.ts`) from `383a34f52`, pin from head: `Tests 10 failed | 12 passed (22)`, exit 1 — the ten failures are the seven zh cases of round 1 (`Received: \"Search fields…\"`, `\"Search objects…\"`, `\"Remove region\"`, `\"value\"` twice, `\"— Custom —\"`, `\"Branch 1 · record.amount > 100\"`) plus the three zh crumb cases (`Received: \"Try\"`, `\"Catch\"`, `\"Branch 2\"`); the en cases and the lit controls pass. Restore proven: each path's `git hash-object` equals its HEAD blob and `git diff HEAD` is 0 lines. Round 1's base leg (four sources) read `Tests 7 failed | 10 passed (17)`.\n- Per-site ablation, with objectstack's `scripts/ablation-replace.mjs` (one anchor declared to hit once; the write and the restore judged by blob hash on disk): each of the eight sites with its literal put back alone fails exactly its own zh case(s) and restores to the HEAD blob. Round 1, S1–S7: `1 failed | 16 passed (17)` each — S1 `searchFields`; S2 `searchObjects` (mutated inside `ViewObjectPicker`, so the passed prop is ignored); S3 `removeNamed`; S4 lookup `valuePlaceholder` (the summary case stays green); S5 summary `valuePlaceholder` (the lookup case stays green); S6 `branchCustom` (anchor lengthened to the decision-branch block, since the approval-branch picker carries the same row); S7 `branchN`. Round 2, S8 — the crumb back to `{loc?.regionLabel}`: `Tests 3 failed | 19 passed (22)`, exactly the three zh crumb cases (try, catch, unnamed branch); the en crumb case, the lit control and the other 17 stay green.\n- Two no-op attempts in round 1, recorded rather than hidden: the driver's first call ran the tool from outside the repository (refused before writing; hashes unchanged), and the first S2 reinstated the wrong text at the caller (`ReferenceError`, so zh and en fell over together — a broken-harness shape, not a reading). Both were redone; the readings above are from the redone legs.\n\n## Gates — at `7e724988e3`; heavy runs through `os-verify-lock`\n\n| gate | exit | reading |\n|:--|:--|:--|\n| `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build` (the closure, so `tsc` reads real `dist/*.d.ts`) | 0 | |\n| `tsc --noEmit` and `tsc -p tsconfig.test.json` in `packages/app-shell`, run directly | 0, 0 | 0 errors; `--listFiles` names the pin once in the test project |\n| `pnpm exec vitest run` over the six files above | 0 | `Test Files 6 passed (6)`, `Tests 99 passed (99)` |\n| round 1, at `68eedfed1`: `metadata-admin/inspectors/` (103 files), the rest of `metadata-admin/` in two halves (105 + 105 = all 313 tracked test files), `views/studio-design/` (65 files) | 0 each | `1428 passed | 1 skipped`, `881 passed`, `1287 passed`, `359 passed` |\n| eslint, plain form, on the 6 TS files round 2 touches | 0 | `--format json`: 6 files, 0 errors, 3 warnings — `FlowNodeInspector.tsx`'s pre-existing `no-explicit-any` and `react-hooks/set-state-in-effect`, equal to its blob at `68eedfed1` (`--stdin`); the new module, the codec, its test and the pin have 0. Round 1's 5 files: 0 errors, 26 warnings, per file equal to base |\n| `check-changeset-presence` | 0 | 10 source files of 1 released package, 1 changeset |\n| `check:changeset-claims` (base `383a34f52`, head) | 0 | no pending changeset names a file this change touches |\n| `changeset:check` (fixed group, no major) | 0 | |\n| `check:new-line-citations` | 0 | 0 new citations |\n| `check:control-bytes` | 0 | OK |\n| `check:i18n-keys`, `check:i18n-drift`, `check:i18n-dead-keys` | 0 each | drift: 0 en values changed, 0 keys added or removed in the designer table |\n| `check:vi-mock-specifiers`, `check:vi-mock-inherit`, `check:vi-mock-override-shape`, `check:test-path-roots` | 0 each | the pin's two new `vi.mock` calls resolve |\n| round 1 only: `check:i18n-designer-parity`, `check:pending-changeset-literals` | 0 each | |\n\n- The eslint narrowing is a measurement: the population is the changed `.ts`/`.tsx` files, which the config's `**/*.{ts,tsx}` block covers; the JSON output counts the files; `eslint.config.js` configures no type-aware linting (a grep for `projectService` or a `parserOptions` project exits 1), so this diff cannot move an untouched file's verdict.\n- The test narrowing: the inspectors are reached only through `inspectors/index.ts` and the inspector registry; `displayRegionLabel`'s two importers are `flow-region-view.tsx` (whose canvas tests ran) and `FlowNodeInspector.tsx`; the package's `exports` do not change. The rest of `packages/app-shell` and the repo-wide `pnpm lint` / `pnpm test` shards belong to CI.\n- NOT MEASURED: `check:eager-locale-catalogues` and the eager-closure budget, which read a built `apps/console` bundle (`performance-budget.yml` runs both).\n\n## Published prose — H5\n\nPending changesets that name these strings: `10586-inspector-strings-i18n.md` (PR 1 of the family: \"plus the existing `engine.form.add` and `engine.form.searchFields`… The dataset inspector reads the `locale` its host already passes\") and `10586-inspector-strings-i18n-2.md` (PR 2: the combo's defaults, \"A label the caller passes still wins\"). Neither sentence is falsified: this change adds callers that pass a translated label, which is exactly the case both describe. No dated note is needed and no frontmatter moved. This PR's own changeset now titles eight words and carries a bullet for the breadcrumb naming the canvas header as the rows' existing reader.\n\n## Serial\n\n`origin/main` `1fc77fd806` (fetched into a private per-worktree ref just before this round's push) touches none of this branch's files since the base `383a34f52`, and `git merge-tree --write-tree` against it is clean (exit 0). Not merged.\n\n## Acceptance notes\n\n- The seat's list above (widget-type labels, `InspectorEmpty` messages, `Widget N`, the lookup operator labels, ` · default`, the nested-location `aria-label`, `Must be a JSON object`, `VariableTextInput`'s three labels, the `Body` region crumb, `useFlowScope`'s group headings, `expression-validate`'s client messages) needs new rows, which this card forbids; it is the family's remaining English under zh, read from source with the pin's harness as the instrument.\n- `ViewVariantInspector`'s `ViewObjectPicker` takes `searchPlaceholder` as a required prop rather than reading `useMetadataLocale()` itself, because its host already carries `locale` — the `locale` prop channel PR objectui#10678 named for hosted inspectors.\n- `flow-region-view.tsx` loses its private `displayRegionLabel` and imports the moved one; its behaviour is unchanged and `FlowCanvas.test.tsx`, `flow-canvas-layout.test.ts` and `flow-region-metrics.test.ts` ran green.\n\n---\n_Generated by [Claude Code](https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN)_\n" }Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
✅ ACCEPT: objectui#10741 at
7e72498; body, ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. Claim5851771741(a re-claim; the first was5838948159). It executes triage5838471955(bug · p3, the family-closure card).engine.*row carrying the same English, so a zh-CN author sees Chinese there. The sites:Search fields…,Search objects…,Remove NAME,value×2,— Custom —,Branch N, and, in round 2, the nested-node breadcrumb'sTry/Catch/Branch N. The breadcrumb reads the canvas header's owndisplayRegionLabel, moved to the leaf modulepreviews/flow-region-label.ts, so the canvas and the inspector show one word. No catalogue row is added or changed, and en output is byte-identicalpreviews/flow-region-view.tsxand addspreviews/flow-region-label.ts, outsideinspectors/. The review judged it minimal. Exporting in place would tripreact-refresh/only-export-components(measured) and pull the canvas component graph into the inspector. The seat accepts it within the ruling to reusedisplayRegionLabelClause-②: no/ semver'@object-ui/app-shell': patch;exportsuntouched; the objectui#4662engine.*carve-out does not moveCONTRACT_REVIEW_TIER. Round 1 FAIL at68eedfe(5852290145): one missed site, the breadcrumb, found because the census had walked*.tsxonly. Round 2 PASS at7e72498, posted with this landing. The seat read both transcripts: every model turn ran at tierflow-region-label.ts; "moved verbatim" becomes "moved, with its body unchanged (the signature gainsexport…)"; the Serial line notes the re-read atee6f6c6a45; the control test's full titlegit merge-tree --write-treeagainst mainee6f6c6a45is clean; no open PR touches the 11 filescheck-governed-queue-guard --test, 11 real paths)7e72498: 39 green, 3 skipped, 1 red. The red check isInert vi.mock Specifier Check, main-red (objectui#10731, this seat's p1, in progress)label-write --assignon the PR was refused by the permission classifier, and the seat has surfaced it to the maintainer rather than re-issue itFixes #10696onlyFindings, each with its disposition
InspectorEmptymessages,Widget N, the lookup operator labels,· default, the nested-locationaria-label,Must be a JSON object,VariableTextInput's three labels, the loopBodycrumb,useFlowScope's group headings,expression-validate's client messages) ⇒ one card from this seat. Closing it needs new catalogue rows, so it is a decision on the objectui#4662 carve-out.Generated by Claude Code
fix(app-shell): inspector literals with an existing catalogue row rea…