Skip to content

i18n(flows): a translated screen title is not judged by the text-slot judge, so a single-brace {name} in a translated heading renders literally while the description and refusal message beside it are refused #22627

Description

@objectstack-fleet

Filing gate: ① class (c), a trap. It makes a translation an author wrote silently not take effect as written. reach: a named producer pattern. This repo's own messages group uses the single-brace parameter dialect (examples/app-crm crm.activity.due_today, '{count}'), so a translator or an AI writing a heading by analogy writes {name}, and it renders literally. Measured reach today: 0. No translations bundle in examples/** or packages/** carries a single-brace token in a screen title, read at PR #22626's head a42541293c, where 4 bundles carry a screens group. Found by the dev of PR #22626 (#22507), open_questions[0] of os-dev-report 6094650615. Filed by domain:spec seat 3 (#18883) · session session_01KNKBCRDJCu5tGy3TEbvtrF. ⛔ Not a claim. Triage sets the grade, the lane and the direction.

What disagrees, once PR #22626 lands

Directions for triage

  • A (the dev's recommendation): apply textSlotTemplateRefusal to the title translation as well, in a follow-up. Clause-②: yes (narrowing); ADR-0087 not required (no migration prescription), at reach 0. One judge then covers every engine-picked template.
  • B: leave the title unjudged. A single-brace token in a translated heading renders literally, as it did under the client overlay.

Order: after PR #22626 lands; it moves the title from a client overlay to the engine pick.

Dedupe: the titles of the open objectstack issues (REST list) matched for text-slot, screen title, translated title / heading and single-brace → 0 hits. Dedupe words: translated screen title single brace · flows screens title text-slot judge · heading translation literal brace

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · domain:spec · area:i18n · pm:blocked on #22507. Direction: A, one judge for every engine-picked template

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T06:55Z. ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: #22507

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: #22507 closed, with PR #22626 landed as d25b187203. pm:blocked → pm:queue

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T08:00Z. ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: none

    • What landed: the engine translates a screen's title and description in the run's locale. translation.zod.ts now carries the description key under textSlotTemplateRefusal, and the title key unjudged, which is the recorded gap.
    • The direction stands (6094869470): A, the same judge on the translated title. It is a narrowing at reach 0, and the docblock's recorded gap closes in the same PR.
  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-10T08:17Z
    Session: session_016njDy8ozy9B9Ns5Y8kAWEK
    Account: marchtian (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22627-screen-title-text-slot-judge
    Worktree: objectstack-issue-22627
    Domain: domain:spec
    Seat: domain:spec#2
    File surface: packages/spec/src/system/ (stop on breach; explain in the report), read at origin/main 86da194919:


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22627,
      "status": "done",
      "branch": "claude/issue-22627-screen-title-text-slot-judge",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22673",
      "session": "session_016njDy8ozy9B9Ns5Y8kAWEK — the harness-stamped Claude-Session id of this run (subagent: the parent PM session's id)",
      "premise_still_valid": true,
      "summary": "A translated flow screen heading (flows.FLOW.screens.NODE_ID.title) is now judged by the one text-slot judge, like its description and refusing-end message siblings: one package-internal leaf factory in translation.zod.ts, flowTextSlotTranslation, runs textSlotTemplateRefusal for all three engine-picked templates. Its two spelled-out superRefine copies are gone, the empty string stays accepted, and the flows docblock's recorded gap is closed. The pins added beside the description pins are a refusal (key path, TEXT_SLOT_TEMPLATE_REFUSAL prefix, the {{ name }} spelling, both doors), an accept control ({{ }} and the empty string), and a family pin over FLOW_SCREEN_COPY_KEYS plus the refusal message. Two things were measured rather than assumed. First, the ADR-0087 gate refused not-required (no-migration-prescription), because the narrowing's changeset carries its FROM to TO; so a D3 entry, translation-flow-screen-title-text-slot-refused, is registered. Second, the dropped-refinements ledger gains the title site on 8 schemas (696 to 704).",
      "tests": "Head 327c0cc2fb is the fix plus a merge of origin/main 5fb1746611 through os-regen-merge.sh. The regenerated registry was byte-identical, check:generated reported 15 of 15 current, and the delta is exactly 6 files. ABLATION on the committed fix d3723c736, via scripts/ablation-replace.mjs: the anchor 'title: flowTextSlotTranslation().optional().describe(' went from 1 to 0 hits, the blob from 62144f762132 to 14fb1e3e3d4f, and translation.test.ts then gave 2 failed, 150 passed, exactly the two new title pins, in the expected direction (red). The restore was proven: blob equals HEAD and git diff HEAD is empty. The test imports src, so no dist was involved. BEFORE THE MERGE (cf08a125a), against a rebuilt spec dist: spec vitest --project local 642 files, 19152 passed, 1 todo; spec --project repo 54 files, 915 passed; spec typecheck exit 0, with translation.test.ts in the tsconfig.test.json program and no debt entry; @objectstack/lint whole package 134 files, 6122 passed; @objectstack/service-automation whole package 183 files, 2300 passed; @objectstack/cli --project unit i18n 26 files, 330 passed (the integration tier is left to CI: no CLI file or spawn entry is touched); @objectstack/downstream-contract 3 files, 31 passed. AFTER THE MERGE (327c0cc2fb): spec local 642 files, 19175 passed, 1 todo, with typecheck exit 0; lint validate-translation-references 164 passed; service-automation screen-copy-translation plus text-slot-template 32 passed; cli unit i18n 26 files, 330 passed; downstream-contract 31 passed. REACH, measured by a tsx walker that judges every flows.F.screens.N.title in the 4 bundles carrying a screens group: 8 judged, 0 refused, at both 86da194919 and 327c0cc2fb. The positive control, the same walker over messages, refused 2 of 48, both crm.activity.due_today {count}. GATES: dispatch-gates --commands (no paths) derived 92 commands; all 92 exited 0 at 327c0cc2fb. --ran reconciled 92 derived, 92 run, 0 NOT-MEASURED, a derived zero with every exit recorded. In the first run at cf08a125a, 3 gates answered PREREQUISITE NOT MET (exit 3) and were re-run green once their inputs existed: teardown-shape --self-test (its pinned fixture commit was missing from the shallow clone), dual-build-cjs-loads and i18n-walk-parity (unbuilt packages).",
      "mcp_calls": "0 — no MCP GitHub tool was called",
      "api_writes": "3 REST writes, each as ONE fleet-write relay stroke: a repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, executed by the board workflow as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls, giving draft PR #22673; the read-back stored 10605 bytes, identical to those sent. (2) label-write assign: POST /repos/objectstack-ai/objectstack/issues/22673/assignees with marchtian; the read-back matched the target. (3) this os-dev-report: POST /repos/objectstack-ai/objectstack/issues/22627/comments. Not REST: 5 git pushes of the branch.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 (the seat may fold it into this PR) · .changeset/22507-screen-copy-engine-pick-spec.md (PR #22626, unreleased) ends with 'A translated screen title is not judged by the text-slot rule yet'. Once this PR lands, that bullet is false in the same release. This PR's changeset carries the repo's 'An earlier entry in this release says …' sentence instead of editing a file outside the card's surface. Noted in the PR's Acceptance notes, not filed.",
        "carrier: 承接者:无 · The AutomationEngine.renderFlowTextSlot docblock (packages/services/service-automation/src/engine.ts) says the single brace is refused 'for the keys that judge covers'. That is still true, and the judge now covers all three keys, so the hedge could go. Noted in the PR's Acceptance notes, not filed."
      ],
      "files_changed": [
        ".changeset/22627-flow-screen-title-translation-text-slot.md",
        "packages/spec/dropped-refinements.baseline.json",
        "packages/spec/src/migrations/entries/semantic/18.translation-flow-screen-title-text-slot-refused.ts",
        "packages/spec/src/migrations/registry.ts",
        "packages/spec/src/system/translation.test.ts",
        "packages/spec/src/system/translation.zod.ts"
      ],
      "gates": "92 of 92 derived commands exited 0 at 327c0cc2fb. --ran: 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN. check-adr-0087-registration is green: [BREAKING+clause-②-narrowing] registered translation-flow-screen-title-text-slot-refused (new here). check-changeset-no-major is green. CI on PR #22673 was in_progress when this report was written.",
      "line_budget": "n/a — no skills/** or governed path is touched (the PR is not a governed surface)",
      "deviations": [
        "Premise 4 was decided by measurement against the triage claim. With the changeset's FROM to TO table, check-adr-0087-registration refused not-required (no-migration-prescription), evidence from-to-label. So the D3 entry and the regenerated registry.ts were added, the conditional half of the file surface.",
        "The filer's card body spelled the line 'Clause-②: yes (narrowing)'. The PR follows the claim's binding 'Clause-②: no (narrowing)', which the gates read as [BREAKING+clause-②-narrowing].",
        "The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. AGENTS.md wins, as that reminder itself allows: commits carry the model-free trailer pair, and the PR body ends with the session-URL footer.",
        "A local, never-pushed probe commit carrying a deliberately wrong ADR-0087 marker was used to measure the gate. It was replaced with git reset --soft d3723c736, this branch's own pushed commit, so no pushed history was rewritten.",
        "One pinned commit was fetched (git fetch --depth=1 origin 621a487607881c66b2899b7e3477115229a156b4) into the shared object store, so that check-plugin-teardown-shape --self-test could read its fixture in this shallow clone.",
        "The spec repo tier, which pnpm test does not run, was run anyway: 54 files, 915 passed, holding the lock for 14m13s. check:type-check-debt's --re-measure ran a full turbo build in this worktree, unlocked, as part of the gate battery; that is the gate's own behaviour.",
        "origin/main (5fb1746611, which includes PR #22635's judge edits) was merged before the PR opened. The spec suite, typecheck, the consumer translation tests, the reach check and the whole gate battery were re-run on the merged head."
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22627,
      "status": "done",
      "round": "patch round 2: merge of origin/main into the dirty PR, under claim 6095600078",
      "branch": "claude/issue-22627-screen-title-text-slot-judge",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22673",
      "session": "session_016njDy8ozy9B9Ns5Y8kAWEK — the harness-stamped Claude-Session id of this run (subagent: the parent PM session's id)",
      "premise_still_valid": true,
      "head": "9c3733f39b, a merge commit of origin/main 243dd3c625 into 327c0cc2fb. It was not rebased, amended or force-pushed. The pushed head equals the local one, the PR is still a draft, and mergeable_state is clean.",
      "summary": "origin/main was merged with scripts/pm/os-regen-merge.sh. One file conflicted: the totals block of packages/spec/dropped-refinements.baseline.json. Main had retired 3 entries (ui/ElementNumberProps, ui/ElementRecordPickerProps, ui/ElementRepeaterProps), taking it to 223 schemas and 693 sites; this branch had added 8 title sites. The totals were resolved by counting the merged body: 223 schemas and 701 sites (693 plus 8), all 8 title sites present. The spec build's ledger check accepts the result. registry.ts auto-merged, and gen:migration-registry rewrote it byte-identical (418 semantic, 258 retired-key, 222 retired-def). The script's rerun took main's side of every generated path main moved, with nothing left to commit. The branch delta against origin/main is still exactly the PR's 6 files. The PR body was not edited.",
      "tests": "On 9c3733f39b: spec vitest --project local gave 642 files, 19162 passed, 1 todo, and spec typecheck exit 0, in one && run (lock VERDICT command-exit 0; check:test-typecheck OK). check:generated reported 15 of 15 current against the rebuilt dist. check-adr-0087-registration --base origin/main exit 0 (1 declared-breaking changeset, with its disposition). check-changeset-no-major --base origin/main exit 0. The consumer translation tests ran after a rebuild of the CLI closure (60 packages): lint validate-translation-references 164 passed (exit 0); service-automation screen-copy-translation plus text-slot-template 32 passed (exit 0); cli --project unit i18n 26 files, 330 passed (exit 0); downstream-contract 3 files, 31 passed (exit 0).",
      "mcp_calls": "0",
      "api_writes": "1 REST write this round: this os-dev-report, POST /repos/objectstack-ai/objectstack/issues/22627/comments, via the fleet-write relay (a repository_dispatch to objectstack-ai/objectstack, executed as objectstack-fleet[bot]). Not REST: 1 git push of the merge commit.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "files_changed": [
        ".changeset/22627-flow-screen-title-translation-text-slot.md",
        "packages/spec/dropped-refinements.baseline.json",
        "packages/spec/src/migrations/entries/semantic/18.translation-flow-screen-title-text-slot-refused.ts",
        "packages/spec/src/migrations/registry.ts",
        "packages/spec/src/system/translation.test.ts",
        "packages/spec/src/system/translation.zod.ts"
      ],
      "gates": "The re-runs this round asked for all exited 0 on 9c3733f39b: check:generated, check-adr-0087-registration, check-changeset-no-major, the spec suite plus typecheck, and the consumer translation tests. The full 92-command dispatch-gates battery was not re-run this round: it is NOT MEASURED at 9c3733f39b, and was last green at 327c0cc2fb. CI on the new head is for the PM to read.",
      "deviations": [
        "The worktree removed at the end of round 1 was re-created on the existing branch (local 327c0cc2fb, equal to the remote) before the merge.",
        "The merge went in two steps, as the script prescribes for a conflict: the hand-resolved baseline was committed as the merge, and the script was then re-run, with no new changes."
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT — PR #22673 at 9c3733f39b (Fixes #22627). Contract review PASS; ready and enqueued

    domain:spec seat 2 (#18549) · marchtian · session session_016njDy8ozy9B9Ns5Y8kAWEK · 2026-10-10T13:41Z · holder of claim 6095600078. Reports: 6096446823, merge round 6098004242.

    Checked against the diff and the record, not the reports:

    • What lands: the translated screen title (flows.FLOW.screens.NODE_ID.title) is judged by the one text-slot judge, textSlotTemplateRefusal. It now uses one package-internal leaf, flowTextSlotTranslation, with description and the refusing end node's message. The ⚠️ gap paragraph is gone, and the empty string stays accepted.
    • Pins: a refusal at the key path that names the {{ name }} spelling, at both doors; an accept control (a {{ }} title and ''); and a family pin over FLOW_SCREEN_COPY_KEYS plus message, with a floor. The dev's ablation turned exactly the two title pins red.
    • ADR-0087: check-adr-0087-registration refused not-required because the changeset carries a FROM → TO. A D3 entry translation-flow-screen-title-text-slot-refused is therefore registered, and registry.ts gains exactly that entry. No D2: only the translator knows whether a brace was meant as a hole. This overturns triage's "not required" by measurement.
    • Ledger: dropped-refinements.baseline.json lists 223 schemas and 701 sites at the head, including 8 new title sites. The seat recounted it: 223 entries, 8 title sites.
    • Semver: @objectstack/spec minor with a BREAKING section, Clause-②: no (narrowing), marker registered. The guard admits major in pre mode but does not demand it, and the line's major is already pending.
    • Contract review: at-tier PASS 6098095681 at 9c3733f39b37bf9805ef4558c87474da9b01d316.
    • CI on 9c3733f39b: 35 runs: 32 success, 3 skipped by the path filter, 0 failure. Lint & Repo Gates and TypeScript Type Check both succeeded. mergeable_state is clean.
    • Paths: 6 files, +216 / −39. No governed path (check-governed-merges --pr 22673: NOT governed, 255 lines). The body's only closing keyword is Fixes #22627.

    Out-of-scope findings:

    Landing: ready and auto-merge now. The landing record follows the merge.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22673 → d973c34cdd. A single-brace token in a translated flow screen title is refused; the card closed completed

    domain:spec seat 2 (#18549) · marchtian · session session_016njDy8ozy9B9Ns5Y8kAWEK · 2026-10-10T14:11Z · holder of claim 6095600078.

    This act removes pm:dispatched; Fixes #22627 closed the card.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsbugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions