Skip to content

Screen-flow runner applies the flows translation overlay — the runner half of objectstack#11287 (client-side pick) #5920

Description

@os-steve

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) and ScreenFieldSpec.name are 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 flows either, 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

  1. The ledger flip is NOT yours but is triggered by you: flows / children.label / children.screens liveness rows in objectstack packages/spec/liveness stay planned + authorWarn until a shipped reader exists. When this lands, comment on objectstack#11287 (or ping the objectstack spec seat) so that seat flips the rows to live with the evidence pointer — do not edit objectstack's ledger from here.
  2. Screen description is the open measuring point: the wire carries ScreenSpec.description and the console renders it, but the translation face guidance-refuses description (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

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 24, 2026
  2. added theissue type on Aug 24, 2026
  3. claude commented on Aug 24, 2026

    @claude
    Contributor

    Triage (daily round, session session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24): release-gated consumer half of objectstack#11287 → domain:ui + pm:on-hold (not pm:blocked: the producer is MERGED but ships in no npm release, so a queue return would burn a dev on premise_still_valid: false — the cross-repo unlock criterion is consumer can install, not upstream merged).

    Restart-when: npm @objectstack/spec latest > 17.2.0 AND the installed package exports translateFlow/resolveFlowScreenTitle from system/i18n-resolver (re-check: npm view @objectstack/spec version)
    Restart-touch: apps/console screen-flow runner surface

    On restart: bump the spec pin first, then dispatch the runner overlay per the side-pick already recorded in the body.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    解除挂起 → pm:queue · 定级 priority:p2 —— 重开条件已满足;中文用户今天看到的流程向导仍是英文

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ,objectstack 座位贴 #6015),2026-09-24T01:38Z。objectui 清理第一批:本席逐张读完卡面与全部评论,把结论与理由报给维护者,维护者答复后执行。 维护者答:「其他同意」。

    读数

    • 本仓安装的 spec 17.4.0: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

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 — domain:ui execution seat
    Session: session_01BA3nKVUwKQJf8DBxrSVtNC
    Branch: claude/issue-5920-flow-runner-translation-overlay
    Worktree: objectui-issue-5920
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/app-shell/src/views/FlowRunner.tsx (and ScreenView.tsx / packages/app-shell/src/utils/flowResponse.ts only 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 the description measurement 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.tsx or flowResponse.ts. objectui#10231 edits packages/app-shell/src/views/metadata-admin/previews/FlowRunsPanel.tsx and apps/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/spec 17.4.0 (triage reading 5805904436, re-verified by the dev before any edit).
    Earlier claims on this thread: none.

    Why Clause-②: no

    The runner starts reading translation keys the spec already declares (TranslationData.flows, through the spec's own resolveFlowScreenTitle and 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 translating description through one).

    domain:ui seat #1 · session_01BA3nKVUwKQJf8DBxrSVtNC · claim · 2026-09-24T09:11Z


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    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

  7. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT — PR objectui#10234 at 577fa817 · pm:dispatched → pm:blocked on objectui#10229

    domain:ui seat #1, session_01BA3nKVUwKQJf8DBxrSVtNC. Report 5811676525 read in full. Reviewed against the diff, the tree and CI.

    Implemented-by:  claude/issue-5920-flow-runner-translation-overlay
    Reviewed-by:     session_01BA3nKVUwKQJf8DBxrSVtNC
    
    item reading
    shape draft · base main · Fixes #5920 · Clause-②: no at line start (added by this seat in this act; see below)
    scope 5 files: FlowRunner.tsx, one new pin file, one changeset, plus packages/app-shell/package.json and one pnpm-lock.yaml specifier line. The last two are outside the claimed surface, declared: @objectstack/spec ^17.0.0 → ^17.3.0 is required because 17.0.0–17.2.0 do not export resolveFlowScreenTitle / 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).
    the fix, read by this seat The heading goes through the spec's resolveFlowScreenTitle (addressed by ScreenSpec.nodeId, falling back to the authored title). Field copy goes through the imported FLOW_SCREEN_FIELD_COPY_KEYS, addressed by ScreenFieldSpec.name, with a fallback per key. The bundle is read back from the i18next tree that loadLanguage already filled; there is no second loader. With no bundle, shown === screen. ScreenView holds no hook keyed on screen identity, and ObjectForm stays keyed by nodeId, so a fresh shown each render resets nothing. The run is still driven by the payload screen. description, the chrome and successMessage are untouched. No export and no prop changed.
    pins + ablation 7 pins. Removing the overlay turns (1) (2) (6) (7) red and leaves the pure-fallback pins (3) (4) (5) green; restore proven by blob equality
    review-tier record PASS at 577fa817 (5811889943 on the PR)
    CI 45 check-runs, all terminal: 41 green, 3 skipped by design, 1 red = Spec Main Shape Gate: the same 21 TS2345 errors on the three untouched test files ⇒ the objectui#10229 drift, ⛔ not this PR's

    PR body: one line added by the seat

    The claim carries Clause-②: no, and .claude/agents/os-dev.md requires 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 run 35983486644).

    Rides this card ① — the description measurement (the input to the widen-or-not question)

    • Drawn prominently: whenever ScreenSpec.description is non-empty, it is the dialog's second line, directly under the heading, and its accessible description (announced on open; pin (7) asserts it).
    • Authored use, over all 6 screen nodes in the objectstack examples:
      • 4 author a description. On 2 of those (message-only screens) it is the whole body under the heading.
      • 1 of the 4 is a template (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.
    • Net today: on notice and confirmation screens a zh-CN user reads a translated heading above an English sentence.
    • ⛔ No widening was taken: the PR ignores an off-spec description in 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.screens is backed by FlowRunner.tsx, pinned by the new test file;
    • flows › children.label is not backed (nothing in objectui draws a flow's label from the flows group), so that row stays planned;
    • plus the description measurement above.
      ⛔ Not before the merge: the evidence is valid only once the reader ships.

    Out of scope

    • filed objectui#10235 (class a): the console drops a spec translation payload with no objects.*.fields entry, un-namespaced, so a bundle that translates only apps, dashboards, pages or flows is never read. Filed bare.
    • Acceptance notes:
      • A translated heading draws a {var} token literally, because the wire title is already interpolated. 0 of 6 example headings carry a token.
      • Spec 17.4.0 exports no per-field flow resolver, so the runner mirrors the spec's non-empty-string rule.

    State in this act

    Landing waits on Spec Main Shape Gate (objectui#10229) ⇒ body lines Blocked-by: #10229 and Unlock-action: re-check PR #10234; pm:dispatched → pm:blocked. The card's original Blocked-by line (objectstack#11287 + the pin bump, both spent) is reworded so it no longer reads as a live directive. The assignee stays.

    domain:ui seat #1 · review + state transition · 2026-09-24T09:54Z

  8. added a commit that references this issue on Sep 28, 2026
    5d895c1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions