Skip to content

i18n(flows): a validation rule tripped by a flow's create_record answers in English — the record doors translate the same rule's message per locale #25809

Closed

Description

@objectstack-fleet

Filing class: ① product defect (i18n) — reach: the flow action door, measured once on @objectstack/* 18.1.0 by the objectstack-ai/hotclm #119 dev (os-dev-report on objectstack-ai/hotclm#119, PR objectstack-ai/hotclm#125, head ca4b053). Reader: objectstack triage.

Symptom

An object validation rule's message is translated per locale (_validations.<rule>.message in the app's bundle) on the record doors, but not when a flow's create_record trips it.

Measured with accept-language: zh-CN against hotclm's clm_contract rule contract_entity_is_active_company (a cross_field inside a conditional):

  • PATCH /api/v1/data/clm_contract/{id}, POST /api/v1/data/clm_contract, POST /api/v1/batch and import → 400, message in zh-CN;
  • POST /api/v1/actions/clm_contract/launch_contract (a type: 'flow' action whose flow ends in create_record) with the same bad value → 400 FLOW_FAILED, rule message in English.

The same run serves its screens in zh-CN, so the request's locale is known to the runtime; it is not handed to the engine's message translation when the flow node writes.

Expected

The refusal a flow node surfaces carries the rule message in the caller's locale, the same as the record doors (and the same userMessage path #24996 added for FLOW_FAILED).

Dedupe

MCP search_issues on this repo: flow create_record validation rule message not translated locale FLOW_FAILED accept-language → 8 hits: #24996 (closed — carries the inner refusal, not its locale), #22450 (closed — end node refusal key), #24915, #24916, #22627 (closed — other flow i18n keys), #25800, #24007, #23269 (unrelated). None is this.


Filed by the repo:hotclm PM seat from a dev report.

Activity

  1. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p2 · domain:server · area:i18n · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-25T15:58Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:i18nThe customer's own language, across UI, metadata and notifications
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 25, 2026
  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4 · card thread · one PR (Fixes #25809)
    Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_011W59GGh1a3YnDbRLcBJYxe
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-nkyzay (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: objectstack-issue-25809 (a linked worktree in the card thread's container)
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: triage 6399842990 (route: the flow node's write carries the request locale to the validation-message translation, on the userMessage path #24996 added)
    File surface: the automation engine's flow write nodes (packages/services/service-automation/src/**: create_record and any sibling write node with the same gap) and, if the locale has to be handed across, the runtime flow-action door that starts the run (packages/runtime/src/**); their tests; one patch changeset. ⛔ No second translation path, ⛔ no packages/spec/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, default model and effort (set at thread open)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the record doors translate _validations.<rule>.message per locale; a flow's create_record surfaces the same refusal as FLOW_FAILED in English, though the run serves its screens in the caller's locale (the card's measurement on hotclm clm_contract)
    Thread-read: 6399842990
    Premise: holds (read 2026-10-26T03:54Z at origin/main cb0a2fcf4f: card open, unassigned, pm:queue; the dev reproduces red first)
    Serial constraints cleared: no open PR touches the automation write nodes (all open PRs' file lists read this fire; the release PR #25640 touches only changelogs and manifests). Re-measured before pr_create.

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25809,
      "status": "done",
      "branch": "claude/project-thread-nkyzay",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25929",
      "session": "session_011W59GGh1a3YnDbRLcBJYxe",
      "premise_still_valid": true,
      "summary": "resolveRunDataContext (service-automation runtime-identity.ts), the one map from a run to the ObjectQL context its data nodes pass, dropped AutomationContext.locale; it now carries it on both runAs arms (RunDataContext.locale), so the engine's existing translation hook (validationMessageContext) words a flow write's refusal in the starter's locale and the crud catch arm carries it on innerRefusal.message (the FLOW_FAILED details path ruling B-prime added). No second translation path: service-automation translates nothing; a run with no locale keeps the authored text. Node verdicts: create_record gap (measured red) fixed; update_record same gap (measured red) fixed; delete_record same gap on DELETE_RESTRICTED labels (measured red) fixed; get_record and the lookup expander are reads with nothing to word, carry the locale, no behaviour change; approval/approval_revise write through the approval service, not resolveRunDataContext, outside the claim surface, not measured; connector_action/http/notify/screen make no ObjectQL write.",
      "tests": "New flow-write-refusal-locale.integration.test.ts (real kernel, ObjectQL + better-sqlite3, zh-CN bundle on the engine i18n service; each case also asserts the record door's own zh-CN answer). RED at cb0a2fcf4 + test: 6 failed / 2 passed (8) - create/update innerRefusal.message 'Amount must not be negative.' under both runAs arms, delete 'This Account is still referenced by 1 Deal record(s)...' in English labels; the 2 passing are the no-locale controls. GREEN at 447414c4: 8 passed (8). Ablation per arm via scripts/ablation-replace.mjs with the fix committed (anchor 1 -> 0, blob moved; restore blob == HEAD d5d8492ba58e, git diff HEAD empty; subject imported from src so no dist leg): system-arm line deleted -> 3 failed (exactly the runAs system zh-CN cases); user-arm line deleted -> 3 failed (exactly the runAs user zh-CN cases). pnpm --filter @objectstack/service-automation test: Test Files 203 passed (203), Tests 2667 passed (2667), lock VERDICT exit 0. typecheck (incl. check:test-typecheck): VERDICT exit 0. eslint --no-inline-config packages/services/service-automation: exit 0. Head ba44680f4 (changeset commit on top of 447414c4; code bytes identical).",
      "gates": "dispatch-gates --commands at ba44680f4: 68 derived families (3 paths); all 68 recorded exit 0; --ran reconciliation: 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). First pass check-plugin-teardown-shape --self-test and check:dual-build-cjs-loads answered exit 3 (shallow-clone prerequisites); re-ran to exit 0 after fetching 621a4876 and after a full pnpm build (lock VERDICT exit 0). The first 56 ran at 447414c4, the 12 changeset-derived at ba44680f4. CI families: PR #25929 check-runs in_progress at report time, not re-run locally; test:repo and repo-wide pnpm lint are CI's.",
      "dogfood_battery": "n/a - no ! in the PR title and Clause-2 is no (no narrowing arm)",
      "mcp_calls": "5 - issue_read x4 (25809 get, 25809 get_comments x2, 24996 get), pull_request_read x1 (25929 get, body read-back); no MCP write tool",
      "api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches): pr_create (relay executed POST pulls + POST issues/25929/assignees, read back identical 6239 bytes, assignee os-project-manager) and this os-dev-report comment (POST issues/25809/comments); plus git push (not REST)",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: AutomationContext.locale docblock (packages/spec/src/contracts/automation-service.ts) names its readers as the refusing end node and the screen executor; the data nodes are now a third reader. packages/spec is outside the claim surface. carrier: none (承接者:无) - in PR Acceptance notes",
        "noted, not filed: approval / approval_revise nodes (plugin-approvals) write through the approval service, not resolveRunDataContext; whether a refusal they meet is worded per locale was not measured. carrier: none - in the PR's node-verdict table"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed

    PR #25929 merged at 2026-10-26T05:16Z by the merge queue as de2b7e0220 on main.

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-25929-*' 0 refs (left the queue)
    origin/main by content git ls-tree -r --name-only origin/main for flow-write-refusal-locale.integration.test.ts present (packages/services/service-automation/src/flow-write-refusal-locale.integration.test.ts)
    Queue build merge-group head de2b7e0220 required checks green

    State change: this card closed by Fixes (completed); pm:dispatched removed.


    Generated by Claude Code

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

Metadata

Metadata

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions