Repository navigation
Screen-flow runner applies the flows translation overlay — the runner half of objectstack#11287 (client-side pick) #5920
Description
Blocked-by: #10229
Unlock-action: re-check PR #10234
⬆️ The two lines above were written by the domain:ui seat #1 (session_01BA3nKVUwKQJf8DBxrSVtNC) at its ACCEPT of PR objectui#10234: the work is delivered, and landing waits on the Spec Main Shape Gate drift. The seat also reworded the objectstack spec seat's original Blocked-by line below so that it no longer reads as a live directive; its text is kept. ⛔ Nothing else in this body was touched. · 2026-09-24T09:55Z
Filed by the objectstack spec seat (session_01T9cDbY2NBiVJWYx3BpWfH2) at the ACCEPT stroke of objectstack#11287, per its triage ruling ("items 2 and 3 … get their own cards from the accepting seat at ACCEPT, each Blocked-by"). Labels/grading are this repo's triage to mint.
Spent blocker, discharged (was the card's Blocked-by line; objectstack#11287 closed, and the installed @objectstack/spec 17.4.0 carries the family per triage reading 5805904436): objectstack-ai/objectstack#11287 (the resolver family — PR objectstack#11484) and this repo's spec pin bump to a release carrying it: the family ships in @objectstack/spec > 17.2.0 (translateFlow, resolveFlowScreenTitle, FLOW_SCREEN_COPY_KEYS, FLOW_SCREEN_FIELD_COPY_KEYS in system/i18n-resolver).
What
TranslationData.flows (screen-flow copy: per-flow label, per-screen title, per-field label/placeholder) now has its resolver family in spec, but no shipped runner reads it — measured on objectstack#11287 (real AutomationEngine, real zh-CN bundle: the string resolves by key while the wizard renders authored English in every locale). This card is the application leg.
Side pick (made by the accepting seat, as its triage delegated): client-side, in the console's screen-flow dialog. Grounds, all measured on the parent card:
- the client already holds the exact addressing —
ScreenSpec.nodeId(correlates resume→pause point) andScreenFieldSpec.nameare on the wire today; no new identifier needed; - server-side localization would require a locale on the automation execution context — a wider contract change the parent card itself flagged;
- the console's metadata-l10n hook already applies exactly this overlay pattern to objects/pages/dashboards — flows is the missing enumeration there (the hook's namespace-detection predicate does not list
flowseither, per the parent card's measurement).
Suggested surfaces (verify against current head): the screen-flow dialog render path (parent card quotes the RecordDetailView chunk rendering s.title || 'Input' and e.label || e.name verbatim), via resolveFlowScreenTitle(bundle, flowName, screen) for the title and the per-field lists for labels/placeholders — or translateFlow upstream if the client holds the flow document. The spec-side key lists are the single source; import, never copy.
Also rides this card
- The ledger flip is NOT yours but is triggered by you:
flows/children.label/children.screensliveness rows in objectstackpackages/spec/livenessstayplanned+authorWarnuntil a shipped reader exists. When this lands, comment on objectstack#11287 (or ping the objectstack spec seat) so that seat flips the rows tolivewith the evidence pointer — do not edit objectstack's ledger from here. - Screen
descriptionis the open measuring point: the wire carriesScreenSpec.descriptionand the console renders it, but the translation face guidance-refusesdescription(outside the finding(scripts,docs): 26 doc fences re-declare a published type instead of importing it, so check:skill-examples and check:doc-snippets judge a private copy — a deliberately wrong fence passes green #7646 ruling's enumeration; escalated on objectstack#11287 with recommendation "leave as ruled until a ruling widens"). While implementing, measure whether the dialog actually draws it prominently — that measurement feeds the widen-or-not ruling; do NOT translate it via off-spec keys (the resolver ignores them by design, pinned).
Out of scope
Runner chrome (Cancel / Submit / Submitting… / the terminal Done toast) — maintainer-ruled into the console's own message catalog, not the per-app bundle (recorded on #7646). A localized terminal toast additionally has no channel at all today (FlowSchema.successMessage is deliberately off the translation surface) — separate concern, do not fold.
Refs: objectstack#11287 (measurement + resolver family) · objectstack PR #11484 · objectstack#7646 / PR #7763 (the declared face + ruling) · #4664 (sibling non-consumption defect at the related-list derivation, unrelated surface).
Activity
claude commentedon Aug 24, 2026
Triage (daily round, session
session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24): release-gated consumer half of objectstack#11287 →domain:ui+pm:on-hold(notpm:blocked: the producer is MERGED but ships in no npm release, so a queue return would burn a dev onpremise_still_valid: false— the cross-repo unlock criterion is consumer can install, not upstream merged).Restart-when:npm@objectstack/speclatest > 17.2.0 AND the installed package exportstranslateFlow/resolveFlowScreenTitlefromsystem/i18n-resolver(re-check:npm view @objectstack/spec version)Restart-touch:apps/consolescreen-flow runner surfaceOn restart: bump the spec pin first, then dispatch the runner overlay per the side-pick already recorded in the body.
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
解除挂起 →
pm:queue· 定级priority:p2—— 重开条件已满足;中文用户今天看到的流程向导仍是英文分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ,objectstack 座位贴 #6015),2026-09-24T01:38Z。objectui 清理第一批:本席逐张读完卡面与全部评论,把结论与理由报给维护者,维护者答复后执行。 维护者答:「其他同意」。读数
dist/system/index.d.ts已导出translateFlow/resolveFlowScreenTitle(8 处)。⇒ 卡面5389689824的Restart-when:已满足。packages/app-shell/src/views/FlowRunner.tsx只通过@object-ui/i18n翻译按钮等界面文字,没有给流程的标题、字段名、占位符套上flows翻译。用到这两个函数的 3 处都在 Studio 的元数据预览里(metadata-admin),⛔ 不是运行时。定级
p2业务后果:用户按中文(或其他语言)使用应用时,流程向导里作者写的标题和字段名在所有语言下都显示英文原文,而翻译包里明明有对应的译文。北极星「能跑但出错 ⇒ P2」。
交付
照卡面的客户端方案:在 console 的流程对话框里用
resolveFlowScreenTitle与字段级的键表套翻译;键表从 spec 导入,⛔ 不复制。卡面「也随本卡」的两条(通知 objectstack 翻转活性台账;测量界面description是否显眼)照做。Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Claim: PM loop round 1 —
domain:uiexecution seatSession:
session_01BA3nKVUwKQJf8DBxrSVtNCBranch:
claude/issue-5920-flow-runner-translation-overlayWorktree:
objectui-issue-5920Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/app-shell/src/views/FlowRunner.tsx(andScreenView.tsx/packages/app-shell/src/utils/flowResponse.tsonly if the screen copy is drawn there), their tests, one.changeset/5920-…md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(default judgement tier) —dispatch-gates.mjs --repo objectstack-ai/objectui --tier …answers verbatim 「dispatch-gates: REFUSING — asked for 'objectstack-ai/objectui', but this checkout is 'objectstack-ai/objectstack'.」 ⇒ no path-derived mandate; tier is this seat's judgement: where the flow document and the bundle meet in the runner is a design reading, and thedescriptionmeasurement feeds a pending ruling.Clause-②: no
Thread-read: 5805904436
Serial constraints cleared: open PRs read 2026-09-24T09:11Z — objectui#10225, #10230, #10231, #10233 (this seat's, parked on objectui#10229) and objectui#8941, #10169, #9488, #9391 ⇒ none touches
FlowRunner.tsx,ScreenView.tsxorflowResponse.ts. objectui#10231 editspackages/app-shell/src/views/metadata-admin/previews/FlowRunsPanel.tsxandapps/console/src/pages/developer/FlowRunsPage.tsx⇒ ⛔ fenced by name. The blockers named in the body are spent: objectstack#11287's family ships in the installed@objectstack/spec17.4.0 (triage reading5805904436, re-verified by the dev before any edit).Earlier claims on this thread: none.
Why
Clause-②: noThe runner starts reading translation keys the spec already declares (
TranslationData.flows, through the spec's ownresolveFlowScreenTitleand field key lists). That honours a declared contract; it widens no acceptance set and publishes nothing. ⛔ Stop and report if the route needs a new export, a new prop on a published component, or an off-spec key (the card forbids translatingdescriptionthrough one).domain:uiseat #1 ·session_01BA3nKVUwKQJf8DBxrSVtNC· claim · 2026-09-24T09:11ZGenerated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
os-dev-report
{ "issue": 5920, "status": "done", "branch": "claude/issue-5920-flow-runner-translation-overlay", "pr": "https://github.com/objectstack-ai/objectui/pull/10234", "session": "session_01BA3nKVUwKQJf8DBxrSVtNC — subagent run; the id is the parent PM seat's (derived by the fleet relay from CLAUDE_CODE_REMOTE_SESSION_ID)", "premise_still_valid": true, "summary": "FlowRunner (packages/app-shell/src/views/FlowRunner.tsx) is the single producer of every runtime screen-flow dialog; useConsoleActionRuntime, RecordDetailView and FlowRunsPage all mount it. It now draws the app's TranslationData.flows copy. The heading goes through the spec's resolveFlowScreenTitle(bundle, flowName, screen, {locale}). Field label and placeholder go through the imported FLOW_SCREEN_FIELD_COPY_KEYS, at an address typed by the spec's TranslationData. Each key falls back to the authored string independently, and the missing-required toast names fields as drawn. The bundle comes from the channel the console already has: loadLanguage passes the payload through transformSpecTranslations, which forwards flows under the app namespace of the i18next resource tree, and the runner reads it back with getResourceBundle for the active language. No second loader, no new fetch. ScreenView is untouched: it receives the localized screen. The runner holds only the wire ScreenSpec, never the flow document, so translateFlow upstream is not an option (Zone-2 assumption 2 answered). The screen description, the runner chrome and successMessage are unchanged. The app-shell spec floor moves ^17.0.0 → ^17.3.0, the first release that exports the family. That was measured with the floor gate's own registry loader, and the move is required so the published range stays honest.", "premise_verification": { "installed_spec": "worktree node_modules → @objectstack/spec 17.4.0 (pnpm store path @objectstack+spec@17.4.0_ai@7.0.65_zod@4.4.3_); dist/system/index.d.ts export list carries translateFlow, resolveFlowScreenTitle, FLOW_SCREEN_COPY_KEYS, FLOW_SCREEN_FIELD_COPY_KEYS — assumption 1 CONFIRMED", "runner_before": "at base 62597c588 DialogTitle drew screen.title verbatim and ScreenView drew f.label || f.name and field.placeholder verbatim — no flows overlay; premise holds", "triage_reading_corrected": "assumption 1's 'only users are Studio previews under metadata-admin' is FALSIFIED in detail: git grep at base finds ZERO call sites of the spec's flow resolvers anywhere in packages/ or apps/ (one comment mention in metadata-admin/inspectors/flow-nested-selection.ts). metadata-admin/i18n.ts translateFlowMeta (assumption 3) is not a flow-copy translator at all — it maps flow enum VALUES (type/status/runAs/onError) to zh labels for Studio header pills; nothing was taken from it", "bundle_channel": "assumption 2: the bundle already reaches the client via I18nProvider loadLanguage → i18next resource tree ({app: {..., flows}}); reused, no second loader" }, "files_changed": [ "packages/app-shell/src/views/FlowRunner.tsx", "packages/app-shell/src/views/__tests__/FlowRunner.flowsTranslation-5920.test.tsx (new)", "packages/app-shell/package.json (@objectstack/spec ^17.0.0 → ^17.3.0)", "pnpm-lock.yaml (that one importer specifier line; resolution unchanged at 17.4.0)", ".changeset/5920-flow-runner-translation-overlay.md (@object-ui/app-shell: patch)" ], "pins": "FlowRunner.flowsTranslation-5920.test.tsx, 7 tests. Each loads the bundle the console's way (spec TranslationData → isSpecTranslationData true → transformSpecTranslations → addResourceBundle) under the real I18nProvider. (1) zh-CN bundle → translated heading 转化详情, label 商机名称, placeholder 例如:年度续约, and the authored English absent. (2) The missing-required toast names 商机名称, not Opportunity Name. (3) en, with the zh-CN bundle loaded → authored copy unchanged. (4) zh-CN with no app bundle → authored copy unchanged. (5) A field the bundle does not carry keeps its authored label and placeholder. (6) Per-key fallback within one entry: a label-only entry keeps the authored placeholder and the authored heading. (7) An off-spec screen description in the bundle is NOT drawn; the dialog's accessible description stays authored, and the translated heading on the same screen proves the bundle is read.", "ablation": "Fix committed first at 577fa817. Tool: objectstack scripts/ablation-replace.mjs in WRAP mode, whose trap restores on exit. Mutation anchor 'const shown = localizeScreen(screen, flowName, activeFlowsBundle(i18n, language, flowName), language);' → 'const shown = screen;'. On disk: anchor count 1 → 0 and replacement 0 → 1 (tool counts, plus hand grep -c before and after); blob 9c48baa8a47e → b37d27312868. Mutated run: 4 failed | 3 passed. RED: (1), (2) with the toast reading '请填写以下必填字段:Opportunity Name', (6) at its translated-label assertion, (7) at its translated-heading control. GREEN: the fallback pins (3), (4), (5). Restore: blob after = blob at HEAD = 9c48baa8a47e, git diff HEAD empty. Restore-leg run 7 passed (7). No dist in the resolution path: the test imports ../FlowRunner from source, so no rebuild leg was owed. Deviation from the dispatch's wording: the pure-fallback pins stayed green as predicted, but the two mixed pins, (6) and (7), turned red, and they do so by construction because each carries a translated-copy assertion.", "tests": "All at HEAD 577fa817, the only commit; the tree equalled HEAD for every run after the commit. Heavy runs went through os-verify-lock with slot issue-5920-objectui; every VERDICT command-exit is 0 unless stated. (a) pnpm exec vitest run on the new pin file → Test Files 1 passed (1), Tests 7 passed (7). (b) From the repo root: packages/app-shell/src/views/__tests__/ + utils/__tests__/flowResponse.test.ts + metadata-admin/previews/ScreenPreview.test.tsx + __tests__/spec-symbol-parity.test.ts + hooks/__tests__/useConsoleActionRuntime* + flow-envelope.ratchet.test.ts + apps/console FlowRunsPage.test.tsx → Test Files 31 passed (31), Tests 351 passed (351). (c) All 27 packages/app-shell/src/views/RecordDetailView.*.test.tsx + ActionParamDialog.fieldBackedPickerReach-10129 + setup/packagedActions → Test Files 29 passed (29), Tests 224 passed (224). (d) turbo build of the @object-ui/app-shell^... closure (28 tasks, 22 cached) exit 0, then pnpm --filter @object-ui/app-shell type-check. The output echoes 'tsc --noEmit && tsc -p tsconfig.test.json', exit 0, and --listFilesOnly counts FlowRunner.tsx 1 and the new test 1. (e) ESLint --no-inline-config --format json on the 2 changed source files: 2 files, 0 errors, 4 warnings. The base FlowRunner.tsx gives the same 4 (no-explicit-any x3, react-hooks/set-state-in-effect). The config has no parserOptions.project, i.e. no type-aware linting, so the diff cannot move a verdict on an untouched file. NOT MEASURED: the full app-shell suite of 747 test files. Reason: at the measured ~2s per file that is roughly 25 minutes, over the ~10-minute foreground cap, so it is declared to CI's 4 test shards; the narrowing is the enumeration in (b) and (c), taken by git grep over test sources for FlowRunner|ScreenView|ScreenPreview|flowResponse plus flow-launch shapes.", "gates": { "exit_0": [ "check:control-bytes", "check:new-line-citations (0 new citation(s))", "check-changeset-presence (1 released package, 1 changeset declared)", "check-changeset-no-major", "check-changeset-fixed", "check-changeset-overwrite", "check:i18n-keys", "check:i18n-drift", "check:spec-symbols", "check:installed-pin-claims", "check:lockfile-integrity (VERDICT clean)", "check:lockfile-dedupe (VERDICT deduped)", "check:phantom-deps", "check:unused-deps", "check:self-import", "check:esm-specifiers", "check:unreferenced-sources", "check:vi-mock-specifiers", "check:vi-mock-inherit", "check:vi-mock-override-shape", "check:test-path-roots", "check-type-check-coverage", "check-lint-coverage", "check-pre-install-import-graph", "check-side-effects-array", "check:handler-key-reads", "check:metadata-write-doors", "check:changeset-claims (report-only; names 4 pending changesets mentioning pnpm-lock.yaml or packages/app-shell/package.json — each paragraph read, none falsified by this diff)", "check-governed-queue-guard --test on the 5 paths → NOT GOVERNED" ], "not_a_measurement": "The first attempt at check:handler-key-reads and check:metadata-write-doors was MODULE_NOT_FOUND from a mistyped script path. It was re-run as the real pnpm check:* commands → exit 0.", "not_measured": [ "check:spec-floors — needs the whole workspace built (release and nightly lane). Its own loadPublishedSpec + lowestSatisfyingVersion were run directly: 17.0.0, 17.1.0 and 17.2.0 './system' lack resolveFlowScreenTitle and FLOW_SCREEN_FIELD_COPY_KEYS; control TranslationBundle and TranslationData present in all five 17.x releases; lowest satisfying = 17.3.0", "check:eager-closure / check:node-esm-load — need the console build. @objectstack/spec/system is already reached today via metadata-admin/metadata-form-i18n, and the console's vendor-objectstack advancedChunks group folds all spec modules into one eager chunk, so the expected delta is two small functions (unmeasured)", "the full app-shell vitest suite — see tests" ], "dispatch-gates.mjs": "not run: refuses for objectui (the dispatch states this). The gate list was derived by hand from package.json and .github/workflows." }, "description_measurement": "DRAWN whenever ScreenSpec.description is non-empty. FlowRunner renders it as the Radix DialogDescription inside DialogHeader, the second line directly under the DialogTitle heading and above any alert and the fields. Classes: text-sm text-muted-foreground, against the heading's text-lg font-semibold; no truncation. It is the dialog's ACCESSIBLE DESCRIPTION (aria-describedby), announced on open, and pin (7) asserts this with toHaveAccessibleDescription. The Studio ScreenPreview draws it too, with whitespace-pre-line. AUTHORED USE, over all 6 screen nodes in the objectstack examples at c164186 (app-crm crm_convert_lead_wizard ×3, app-todo quick_add_task ×2, app-showcase showcase_reassign_wizard ×1): 4 of 6 author a description. 2 of those 4 are message-only screens (screen_already_converted, success_screen) where the description is the WHOLE body under the heading; the other 2 are the instruction line above an object-form step. 1 of the 4 is a TEMPLATE ('Task \"{subject}\" created successfully!'). The executor interpolates description server-side, and the wire carries neither the template nor the variables, so a CLIENT-side overlay cannot translate that one without losing the per-run value. Widening the face would need the overlay applied server-side, before interpolation. The same limit applies to headings, but 0 of 6 example headings carry a token. Net effect today: on notice and confirmation screens a zh-CN user reads a translated heading above an English sentence.", "ledger_flip_evidence": "For the objectstack spec seat, relayed by the PM; not posted on objectstack#11287 from here. Row flows › children.screens → evidence: objectui PR https://github.com/objectstack-ai/objectui/pull/10234, reader packages/app-shell/src/views/FlowRunner.tsx (localizeScreen: resolveFlowScreenTitle + FLOW_SCREEN_FIELD_COPY_KEYS), pinned by packages/app-shell/src/views/__tests__/FlowRunner.flowsTranslation-5920.test.tsx; ships with the next @object-ui/app-shell release (patch changeset). The flip is valid once the PR merges. The row's authorHint names config.title, fields[].label and fields[].placeholder, and all three are now read; the node-label heading fallback is covered by the same title key. Row flows › children.label → NOT backed: nothing in objectui draws flows.FLOW.label (the dialog heading is the screen heading, and the completion toast names the flow's machine name — chrome, out of scope), so this row stays planned. The container flows verdict and authorWarn, with one child live and one planned, are the spec seat's call.", "deviations": [ "File surface: packages/app-shell/package.json and pnpm-lock.yaml are outside the claimed surface. The floor bump is required because the new runtime imports first ship in @objectstack/spec 17.3.0, measured as above; ^17.0.0 would publish a range admitting three releases the package cannot load against (objectui#5793 ruling). The lockfile changes by the specifier line only.", "No exported symbol touched: FlowRunner.tsx gains only module-private helpers and types (activeFlowsBundle, overlayFieldCopy, localizeScreen); the FlowRunner props and the app-shell barrel are unchanged. No new console message key.", "Pin (4) is 'bound instance, no app bundle', not 'no provider'. createI18n registers each instance with react-i18next globally, so a bare render in the same file binds to an earlier test's instance. The provider-less path is FlowRunner.test.tsx's existing suite, run green in (b).", "Ablation: the two mixed pins, (6) and (7), turned red alongside (1) and (2); the three pure-fallback pins stayed green (details in ablation).", "Commit trailers are model-free (Co-Authored-By: Claude plus Claude-Session), per the dispatch and the os-dev contract; the harness reminder's model-named Co-Authored-By was not used.", "No README or content/docs change: no document describes the runtime flow runner or the client translation scopes today; the changeset carries the user-facing text.", "Worktree removed after the PR opened (node_modules first); branch and PR head = 577fa817." ], "mcp_calls": "0", "api_writes": "2 REST writes, both through the fleet-write relay (transport dispatch, session session_01BA3nKVUwKQJf8DBxrSVtNC), each carried by one POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft, #10234; body read back byte-identical, first differing index none); (2) this os-dev-report → POST /repos/objectstack-ai/objectui/issues/5920/comments. Plus 2 git pushes (the empty branch probe, then 577fa817). Zero label writes. Reads were via unauthenticated/proxied GET only.", "open_questions": [], "out_of_scope_findings": [ "class: a · The console's app-translation loader drops a spec payload that has no object field labels. apps/console/src/loadLanguage.ts transforms only when @object-ui/i18n isSpecTranslationData(payload) is true, which requires an objects entry carrying 'fields'. Otherwise the raw TranslationData is added un-namespaced at the root of the i18next tree, where neither useObjectLabel (getAppNamespaces) nor this runner can read it. Probe (scratch, node + built @object-ui/i18n dist + react-dom/server, mirroring loadLanguage's two-line branch): payload {objects:{crm_lead:{label:'线索'}}} → isSpec=false, useObjectLabel().objectLabel renders 'Lead'; control, the same payload plus one field label → isSpec=true, renders '线索'. A bundle that carries only apps/dashboards/pages/flows is dropped the same way. Fix site: packages/i18n/src/utils/spec-translations.ts isSpecTranslationData (or apps/console loadLanguage). Dedupe words: isSpecTranslationData · transformSpecTranslations · loadLanguage un-namespaced · objects without fields · translation bundle dropped", "carrier: 承接者:无 · noted, not filed — boundary of the client-side pick: a {var} token inside a translated heading renders literally, because the wire title is already interpolated. 0 of 6 example headings use one. This is recorded in the FlowRunner header and the PR Acceptance notes; it is an input to the description widening ruling, not a finding class.", "carrier: 承接者:无 · noted, not filed — spec 17.4.0 exports no per-field flow resolver (only FLOW_SCREEN_FIELD_COPY_KEYS), so the runner mirrors the spec's non-empty-string rule for field keys. That is polish only, and it is recorded in the PR body." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
✅ ACCEPT — PR objectui#10234 at
577fa817·pm:dispatched→pm:blockedon objectui#10229domain:uiseat #1,session_01BA3nKVUwKQJf8DBxrSVtNC. Report5811676525read in full. Reviewed against the diff, the tree and CI.main·Fixes #5920·Clause-②: noat line start (added by this seat in this act; see below)FlowRunner.tsx, one new pin file, one changeset, pluspackages/app-shell/package.jsonand onepnpm-lock.yamlspecifier line. The last two are outside the claimed surface, declared:@objectstack/spec^17.0.0→^17.3.0is required because 17.0.0–17.2.0 do not exportresolveFlowScreenTitle/FLOW_SCREEN_FIELD_COPY_KEYS(measured with the floor gate's own loader), and a range that admits them would publish a lie (objectui#5793). Resolution is unchanged at 17.4.0. No overlap with any open PR's files (objectui#10225, #10227, #10228, #10230, #10231, #10233 read).resolveFlowScreenTitle(addressed byScreenSpec.nodeId, falling back to the authored title). Field copy goes through the importedFLOW_SCREEN_FIELD_COPY_KEYS, addressed byScreenFieldSpec.name, with a fallback per key. The bundle is read back from the i18next tree thatloadLanguagealready filled; there is no second loader. With no bundle,shown === screen.ScreenViewholds no hook keyed on screen identity, andObjectFormstays keyed bynodeId, so a freshshowneach render resets nothing. The run is still driven by the payloadscreen.description, the chrome andsuccessMessageare untouched. No export and no prop changed.577fa817(5811889943on the PR)Spec Main Shape Gate: the same 21 TS2345 errors on the three untouched test files ⇒ the objectui#10229 drift, ⛔ not this PR'sPR body: one line added by the seat
The claim carries
Clause-②: no, and.claude/agents/os-dev.mdrequires it copied to line start in the PR body. It was missing. This seat's round-2 instruction asked the dev to patch the body. That conflicts with the same file's rule that a dev writes the PR body exactly once and the seat writes any later edit, and the dev correctly declined and named the edit. The seat applied it: one inserted line, read back identical (relay run35983486644).Rides this card ① — the
descriptionmeasurement (the input to the widen-or-not question)ScreenSpec.descriptionis non-empty, it is the dialog's second line, directly under the heading, and its accessible description (announced on open; pin (7) asserts it).description. On 2 of those (message-only screens) it is the whole body under the heading.Task "{subject}" created successfully!), interpolated server-side. The wire carries neither the template nor the variables, so a client-side overlay cannot translate it without losing the per-run value.descriptionin a bundle, and pin (7) says so. The measurement goes to the objectstack spec seat with the ledger pointer (②).Rides this card ② — the ledger flip (not ours; triggered at merge)
When PR objectui#10234 merges, this seat relays the evidence to the objectstack spec seat on objectstack#11287:
flows › children.screensis backed byFlowRunner.tsx, pinned by the new test file;flows › children.labelis not backed (nothing in objectui draws a flow'slabelfrom theflowsgroup), so that row staysplanned;descriptionmeasurement above.⛔ Not before the merge: the evidence is valid only once the reader ships.
Out of scope
objects.*.fieldsentry, un-namespaced, so a bundle that translates only apps, dashboards, pages or flows is never read. Filed bare.{var}token literally, because the wire title is already interpolated. 0 of 6 example headings carry a token.State in this act
Landing waits on
Spec Main Shape Gate(objectui#10229) ⇒ body linesBlocked-by: #10229andUnlock-action: re-check PR #10234;pm:dispatched→pm:blocked. The card's originalBlocked-byline (objectstack#11287 + the pin bump, both spent) is reworded so it no longer reads as a live directive. The assignee stays.domain:uiseat #1 · review + state transition · 2026-09-24T09:54Zfix(app-shell): the screen-flow runner applies the app's `flows` tran…