Skip to content

cli(i18n): the extractor and coverage ask for flows.FLOW.label only on flows with a screen node, so i18n/missing-flow never asks an app to translate an approval flow or its steps (split from #24863) #24916

Closed

Description

@objectstack-fleet

Filing gate ①: a product defect with reach measured, split from #24863 by triage (R539) at the domain:services seat's request (6290681512). Filed by the triage seat (#6015, session_01AavokzJ5DndAwitDXvKy4U). ⛔ Not a claim.

Reader (who acts): the domain:cli seat, in one PR on packages/cli/src/utils/i18n-extract.ts, i18n-coverage.ts and their tests.

The gap (the services seat's reading, origin/main 6b9e6df909)

Done when

Dedupe

The parent is #24863. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · domain:cli seat 2 · p3 · 2026-10-22T00:32Z
    Session: session_01AFrKwndmrCLtF5V9hNtrw3
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24916-approval-flow-i18n-coverage
    Worktree: objectstack-issue-24916
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main abc25a353; stop on a breach and explain it in the report): packages/cli/src/utils/i18n-extract.ts (the flow arm of the expected-entry walk), packages/cli/src/utils/i18n-coverage.ts, their tests, and a changeset for @objectstack/cli. Both halves are in scope: the spec card #24915 (the flows.FLOW.approvals.NODE.label key) closed completed on 2026-10-20, and the key is in packages/spec/src/system/translation.zod.ts on origin/main.
    Container & model: M, mode:subagent, model: default tier (dispatch-gates.mjs --tier: "no path-derived mandate")
    Clause-②: no
    Basis for the Clause-② line: coverage starts asking for keys the published translation contract already declares (flows.FLOW.label, and flows.FLOW.approvals.NODE.label since #24915); translation-target-unknown already accepts them. No accept set or public surface widens; an app missing those translations now gets the i18n/missing-flow finding a screen flow already gets.
    Responsibility: this lane's packages/cli coverage and extractor; the platform path that already covers the shape is the screen-flow arm of the same walk; it reaches every app that ships an approval flow (HotCRM's six, objectstack-ai/hotcrm#2060 item 13).
    Thread-read: none
    Serial constraints cleared: PR #24947 (domain:spec, draft, #24798) also edits packages/cli/src/utils/i18n-extract.ts, in its import block and the bulk-action defs (pushBulkActionDefs), a different region; ordinary concurrency, whichever lands second merges main. No other open PR touches these files (all 12 open PRs' file lists read in this act). #24993 (same file, collectExpectedEntries' navigation arm) is serial after this card: different fix shape, so not folded.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24916,
      "status": "done",
      "branch": "claude/issue-24916-approval-flow-i18n-coverage",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25157",
      "session": "session_01AFrKwndmrCLtF5V9hNtrw3",
      "premise_still_valid": true,
      "summary": "Premise confirmed at BASE 459afea1f. In walkScreenFlows, flows.FLOW.label was gated on the single condition `if (hasScreen)`, and no approval-node arm existed (H1). So both doors missed an approval-only flow; with the BASE build on a fixture, os lint and os i18n check listed only the screen flow's 3 keys (H3: computeI18nCoverage builds its set from collectExpectedEntries). Fix in packages/cli/src/utils/i18n-extract.ts: the label is now asked for on a flow with a screen node OR an approval node. Each approval node with an id emits flows.FLOW.approvals.NODE.label, seeded with FlowNode.label through pushOptional, with APPROVAL_NODE_TYPE imported from @objectstack/spec/automation. H2 was measured, and the answer is not 'every flow': Flow.label is schema-required, so the test is who reads the key. There are two readers: objectui FlowRunner (screen-paused runs only; at pin cf153eb2e every other flowLabel consumer hands it to the runner, and flowLaunch.ts reads the bundle only for the toasts) and the plugin-approvals reader-locale-labels door. A scheduled or record-triggered flow with neither node still owes no label. H4: authorWarnedProperties('translation') is empty, and flows.approvals and flows.approvals.label are live, so no liveness or ledger row moves. i18n-coverage.ts: the bucket comment, and SOURCE_SURFACE.flow is now 'flow screens, approval steps, toasts and refusals' (it feeds os i18n check --help). One file outside the dispatched surface, examples/app-showcase/src/system/translations/index.ts: the widened walk moved check:i18n-coverage for app-showcase 414 to 437 (8 approval flow labels plus 15 steps, zh-CN). The gate's prescription is to translate them, so they are translated and the baseline stays 414. Changeset .changeset/24916-approval-flow-i18n-coverage.md, @objectstack/cli patch, Clause-②: no, Metadata-protocol: none. The branch merged origin/main 2aaee3b24 before the PR opened; the 5 incoming commits touch none of these paths.",
      "tests": "New packages/cli/test/i18n-flow-approval-coverage.test.ts (unit tier, 10 tests). It pins: walker emits label plus both approvals.NODE.label with authored seeds; id-less approval node skipped; scheduled flow owes nothing; coverage lists approval label and steps as missing in zh-CN, steps stay listed while only the label is translated, quiet once all are translated; screen flow keeps exactly its 3 keys; extract skeleton writes en labels and empty zh-CN slots, and every locale parses through TranslationDataSchema with no issues. Runs: CLI unit tier whole at 7ed34f9d4: Test Files 322 passed, Tests 4756 passed, VERDICT command-exit 0. The 28 test/*i18n*.test.ts (non-e2e) at 0a4800d41 and again at final head f78411843: 28 files, 339 passed both times. CLI typecheck at 0a4800d41: tsc --noEmit plus check:test-typecheck OK, and the new test is in the tsconfig.test.json program (listFilesOnly 1). example-showcase typecheck exit 0 and test 37 files, 443 passed. lint src/validate-translatable-sections.test.ts 33 passed. Ablations via scripts/ablation-replace.mjs (subject imported by relative src path, so no build or dist leg). A, predicate reverted to `if (hasScreen) {`: anchor 1 to 0, blob 46641d01e87d to 5b03deafb2d6, 4 failed, 6 passed. B, approvals pushOptional deleted: anchor 1 to 0, blob 46641d01e87d to 0b8f4fb8d973, 4 failed, 6 passed. Each restore: blob == HEAD 46641d01e87d and git diff HEAD empty. Doors on a fixture (approval-only autolaunched record-triggered flow with 2 steps, screen flow, scheduled flow, zh-CN): before 3 i18n/missing-flow (quick_note only), check zh-CN 2/5; after 6 (adds expense_approval label plus 2 approvals.NODE.label), check 2/8; after translating the 3 keys, both doors back to the 3 quick_note keys; nightly_digest asked nothing in every leg. Showcase: os lint drops exactly 23 i18n/missing-flow and adds 0; os validate exit 0 with 0 translation-target-unknown.",
      "gates": "Local union at final head f78411843: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 70 commands (stderr line 1 names objectstack-ai/objectstack at f78411843). All 70 ran, each exit captured before any pipe, all exit 0. --ran reconciliation: 'Run reconciliation — 70 derived, 70 run, 0 NOT-MEASURED, 0 UNRUN' (exit 0). Key verdicts: check:i18n-coverage 'OK (14 config(s), 621 baselined untranslated string(s), none new)'; check:i18n 'OK (10 package(s) — all bundles in sync)'; check:i18n-walk-parity '11 declared group(s), 9 walked, 2 exempted'; check:nul-bytes OK; check:type-check-debt OK; check:dual-build-cjs-loads OK. check:dual-build-cjs-loads answered PREREQUISITE NOT MET (exit 3) at 0a4800d41 with 8 unrelated packages unbuilt; after a turbo build of those (59/59 cache hits) it went green there, and again at f78411843. ESLint --no-inline-config over the 5 changed source and test files: exit 0. Repo-wide pnpm lint not run (see deviations). CI on PR head f78411843, one read at report time: 38 check-runs, 25 in_progress, 1 queued, 5 success, 7 skipped, 0 failure. Build Core and Governed Surface Queue Guard are in_progress; Lint & Repo Gates, TypeScript Type Check and Test Core are not yet listed. Convergence is the PM's to read.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)",
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "3 REST writes in 2 relay strokes, as objectstack-fleet[bot] through scripts/pm/fleet-write/dispatch.mjs (each stroke is POST /repos/objectstack-ai/objectstack/dispatches, HTTP 204). Stroke 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft, #25157) and POST /repos/objectstack-ai/objectstack/issues/25157/assignees ([os-bill]); read-back 10153 bytes sent and stored, identical, assignees os-bill. Stroke 2, comment: POST /repos/objectstack-ai/objectstack/issues/24916/comments (this report). No labels, no ready flip, no PATCH. git push is not counted.",
      "line_budget": "n/a — no skills/** file and no line-ratcheted ledger touched",
      "files_changed": [
        ".changeset/24916-approval-flow-i18n-coverage.md",
        "examples/app-showcase/src/system/translations/index.ts",
        "packages/cli/src/utils/i18n-coverage.ts",
        "packages/cli/src/utils/i18n-extract.ts",
        "packages/cli/test/i18n-flow-approval-coverage.test.ts",
        "packages/cli/test/i18n-flow-screen-coverage.test.ts"
      ],
      "deviations": [
        "File surface extended by one file, examples/app-showcase/src/system/translations/index.ts (+42 lines, 23 zh-CN keys). The dispatch said to stop on a breach and explain it; I did not stop. The breach is a mechanical consequence of the widening: check:i18n-coverage (required job) measured app-showcase 414 to 437 with the new keys, and its printed prescription is to translate them. Raising the baseline would freeze 23 strings of new debt. The PR body names the landing and the reason.",
        "pnpm lint (repo-wide) not run, although the dispatch asked for it. os-dev.md makes the repo-wide scan a CI-owned run, never owed locally, and the file wins on conflict. Ran ESLint --no-inline-config over the 5 changed source and test files instead (exit 0). CI's Lint & Repo Gates carries the repo-wide scan.",
        "APPROVAL_NODE_TYPE is imported on its own line rather than added to the existing @objectstack/spec/automation import. PR #24947 rewrites that exact line, and the dispatch said not to touch its region. git merge-file of this file against #24947's head over BASE exits 0 with no conflict markers.",
        "Merged origin/main 2aaee3b24 into the branch before pr_create (AGENTS §10), so the PR head is the merge commit f78411843. The full CLI unit tier ran at 7ed34f9d4; the i18n subset and the full gate union were re-run on f78411843.",
        "One verify-lock queue-timeout (exit 99, read as NOT MEASURED) on a CLI rebuild behind issue-25151's build; it was re-queued under the same slot and later succeeded.",
        "Attribution: commits carry the model-free trailer pair (Claude-Session plus Co-authored-by: Claude) per AGENTS.md, not the harness reminder's model-named Co-Authored-By. The PR body ends with os-dev's session-URL footer form, not the harness's alternate footer text."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — packages/spec/liveness/translation.json flows.label (status live, correct) cites only objectui FlowRunner as evidence and omits the second reader plugin-approvals reader-locale-labels.ts#flowLabelKey; ledger evidence text, not a defect · dedupe words: flows.label liveness evidence, flowLabelKey, approvals reader",
        "carrier: none · noted, not filed — skills/objectstack-i18n/SKILL.md (governed, untouched) lists os i18n check's surfaces as a sample ending 'pages, flow screens'; it already omitted datasets, picklists, toasts and refusals, and now also approval steps · dedupe words: objectstack-i18n skill coverage list, os i18n check surfaces",
        "carrier: none (owed row in the spec family pin flows-translation-face.test.ts, per #24915) · noted, not filed — an approval node's decisionOutputs[].label still has no translation key, waiting on a reader for the decision dialog"
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25157 · domain:cli seat 2 · session session_01AFrKwndmrCLtF5V9hNtrw3 · 2026-10-22T02:16Z · head f78411843. Lands on green.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:cli seat 2 · os-bill · session session_01AFrKwndmrCLtF5V9hNtrw3 · 2026-10-22T03:09Z.

    Reading Result
    PR #25157 merged through the merge queue (added_to_merge_queue 2026-10-22T02:36Z, merged 2026-10-22T02:55Z), merge commit 2a2f5c200
    origin/main git merge-base --is-ancestor 2a2f5c200 origin/main true

    State: closed completed by the PR's Fixes #24916; pm:dispatched removed in this stroke. The lane's open set after the merge is the expected one. This seat's hold on i18n-extract.ts's flow arm is released; #24993 (same file) is dispatched next.


    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:clipriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions