Skip to content

Commit ab6fb02

Browse files
docs(cli): say why the flows translation group stays author-warned (#20383)
Fixes #20339 Clause-②: no ## What this changes Comment text only, in `packages/cli`. Four sentences there said nothing reads the `flows` translation group, and two named an objectui runner's landing as the flip trigger. Since PR #20328, the shipped liveness ledger's `flows` row (`packages/spec/liveness/translation.json`) says otherwise: `children.screens` is `live`, because the console's screen-flow runner reads it, and only `children.label` is still read by nothing (#20318). The container keeps `planned` + `authorWarn: true`, and that warn bit is group-level. So the gating these comments describe is unchanged and still correct. Only the reason they gave was stale. | where | before | after | |---|---|---| | `packages/cli/src/utils/i18n-extract.ts`, the `authorWarnedTranslationGroups` docblock (site 2) | "no shipped runner reads the group, so a translated wizard string really is stored and never shown" | "Only part of the group is read: the console's screen-flow runner reads `screens`, but the flow's own `label` is read by nothing yet (#20318), so a translated flow label really is stored and never shown. The warn is group-level, so it still covers the whole group." | | the same docblock, its "Shape" paragraph | "the day the objectui screen-flow runner lands and the row flips to `live`" | "the day the row flips to `live` (dropping its `authorWarn`; for `flows` that waits on #20318)" | | `packages/cli/test/i18n-flow-liveness-gate.test.ts`, the header's ledger sentence (site 3) | "no shipped runner reads the group" | "only part of the group is read: the console's screen-flow runner reads `screens`, but the flow's own `label` is read by nothing yet (#20318)" | | the same header, its warn-side paragraph (site 3) | "Nothing reads the group, so a translated wizard string really is stored and never shown" | "The flow's own `label` is read by nothing yet (#20318), so a translated flow label really is stored and never shown [...] The warn is group-level, so it still covers the whole group." | | the same file, the comment inside the cell `never lets both rules speak about the same keys` | "nothing reads the group, so this copy is stored and never shown" | "the flow's own `label` is read by nothing yet, so its translated copy is stored and never shown" | | `packages/cli/test/i18n-flow-screen-coverage.test.ts`, the header's flip-trigger sentence (patch round 1) | "it turns itself back on the day an objectui screen-flow runner lands and the row flips" | "it turns itself back on the day the row flips to `live` (dropping its `authorWarn`; for `flows` that waits on #20318)" | The "Shape" sentence is changed because it sits in the same docblock and named the wrong trigger. The screen-flow runner has already shipped (objectui at the `.objectui-sha` pin `f8a9d0fb`), and the row did not flip. The ledger's `screens` note says the container bit drops when #20318 lands. The in-cell comment is changed because the claim's file surface names every `packages/cli` sentence that gives this reason. Only its comment lines move, and the cell's code is unchanged (proof below). The header of `i18n-flow-screen-coverage.test.ts` named the same wrong trigger under the same rule, so patch round 1 gives it the Shape clause's wording. `packages/cli` now states one trigger. The file is the one the gate header points readers to, and the claim names it. ## Evidence - **Premise.** Measured on base `5a6267f48`, and unchanged through the merge of `862b6ce86`. The `flows` row is `status: planned` and `authorWarn: true`; `children.label` is `planned`; `children.screens` is `live` (`verifiedAt: 2026-09-27`). Its `authorHint` reads: "Only part of this group is read. The console's screen-flow runner reads `screens` [...] The flow's own `label` is read by nothing yet, so a translated flow label is stored and never shown". The new sentences follow that row. - **Comment-only proof.** Instrument: the TypeScript parser, printing both files with `removeComments: true`. The print at base and the print at HEAD are identical: 48261 of 48261 characters for `i18n-extract.ts`, 5544 of 5544 for the gate test, and 18534 of 18534 for `i18n-flow-screen-coverage.test.ts` (patch round 1; measured against both `bd7b473e2` and merge base `c577e6663`). Control legs: the same instrument detects a one-identifier rename of the exported function, and a one-identifier rename of the screen-coverage file's mocked `authorWarnedProperties`. No assertion, fixture or behaviour moves. - **Published surface.** After `pnpm --filter @objectstack/cli build`, both `dist/utils/i18n-extract.d.ts` and `dist/utils/i18n-extract.js` carry the new sentence (1 hit each) and not the old one (0 hits each). Positive control: the `authorWarnedTranslationGroups` export line gets 1 hit in each. `files: ["dist"]` ships both files, so this PR carries an `@objectstack/cli` `patch` changeset. ## Local verification (HEAD `bd7b473e2`; patch round 1 at `dbff132d7`) - **Patch round 1**, at `dbff132d7`, after merging `origin/main` `c577e6663`: - `pnpm lint` exit 0; - `node scripts/check-issue-citations.mjs --base origin/main` exit 0: 2 added citations judged, both live; - `vitest run --project unit --maxWorkers=2` over `i18n-flow-screen-coverage.test.ts` and `i18n-flow-liveness-gate.test.ts`: 2 files and 29 tests passed; - the 63 derived gates, re-run on this head: 63 run, 0 NOT-MEASURED, 0 UNRUN. The bullets below are the first round, at `bd7b473e2`. - `pnpm --workspace-concurrency=2 --filter '@objectstack/cli^...' build` exit 0. `pnpm --filter @objectstack/cli build` exit 0. - Targeted unit run (`vitest run --project unit --maxWorkers=2`) over the 18 test files that import `i18n-extract`: 18 files and 250 tests passed. The gate file on its own, verbose: 8 of 8 cells passed. - The full `unit` layer of `@objectstack/cli`: 231 files and 3309 tests passed. The `integration` layer is left to CI, because no spawn entry or integration-tier file is touched. - `pnpm --filter @objectstack/cli run typecheck` exit 0 (`tsc --noEmit`, then `check:test-typecheck` OK). - `pnpm --filter @objectstack/spec run check:liveness` exit 0. - `pnpm lint` (the full `eslint . --no-inline-config`) exit 0, no findings. - `node scripts/check-issue-citations.mjs --base origin/main` exit 0. It judged the 2 added citations (#20318, #20339), and both are live issue numbers. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 63 commands, and all 63 ended at exit 0. The `--ran` reconciliation found 63 run, 0 NOT-MEASURED and 0 UNRUN. Three first attempts measured nothing and were re-run green after their prerequisites were built: - `check:dual-build-cjs-loads` (exit 3, PREREQUISITE NOT MET): 104 entry points load. - `check:i18n-coverage` (exit 3, PREREQUISITE NOT MET): 13 configs, none new. - `check:type-check-debt` (hit a 300 s per-command cap): 4 entries, none above its record. - The roster gates whose roster directory holds one of these paths all exit 0: `check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`. So does `check:nul-bytes`. ## Acceptance notes - **Site 1 is not in this PR.** Site 1 is `packages/spec/src/system/metadata-form-zod-reconciliation.test.ts`, the `why` of the `onSuccess` omit entry. Triage routed it to the spec lane. It is still stale on `origin/main` `c577e6663`. #20362 was a spec-lane PR that touched that file after triage, and it did not carry the fix. - **Other copies of the same stale wording, not edited here:** - `packages/cli/CHANGELOG.md`, the same entry in `packages/lint/CHANGELOG.md`, and `packages/spec/CHANGELOG.md`. These are release-owned, and each sentence was true when it was released. - The `flows` bullet in `content/docs/ui/translations.mdx`. This customer-facing page still says "no shipped screen-flow runner reads the group yet, so a wizard still renders the strings authored on the flow". It is outside `packages/cli`, so it goes to the seat. - **One sentence left as it is.** The test header's "(a) it self-activates when the row flips to `live` with the objectui runner" stays byte-identical, as the dispatch directs. It holds under #20318's ENFORCE proposal, whose reader surface is objectui `FlowRunner.tsx` plus the launcher. #20318 still waits for the maintainer's ENFORCE-or-RETIRE decision. --- _Generated by [Claude Code](https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0d7ed5a commit ab6fb02

4 files changed

Lines changed: 42 additions & 16 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
docs(cli): give the true reason the `flows` translation group stays author-warned (#20339)
6+
7+
The doc comment on `authorWarnedTranslationGroups` (published in `dist/` as
8+
`utils/i18n-extract.js` and `.d.ts`) said no shipped runner reads the `flows`
9+
group, so a translated wizard string is stored and never shown. That stopped
10+
being true when the liveness ledger flipped `translation.flows.screens` to
11+
`live`: the console's screen-flow runner reads each screen's `title` and each
12+
field's `label` / `placeholder`. The comment now matches the ledger's `flows`
13+
row: only the flow's own `label` is read by nothing yet (#20318), and the warn
14+
is group-level, so it still covers the whole group.
15+
16+
No behaviour moves. The `flows` row is still `planned` with `authorWarn`, so
17+
`os lint` and `os i18n extract` still hold back every `flows.*` key exactly as
18+
before; that lifts when the row flips, with no edit to the CLI.
19+
20+
Clause-②: no

‎packages/cli/src/utils/i18n-extract.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,16 +1055,18 @@ function walkObjectTabs(config: any, out: ExpectedEntry[]): void {
10551055
* `i18n/missing-*` family. Under `--i18n-strict` the demand side is an error,
10561056
* so a project could be *forced* to author keys it is then warned for.
10571057
*
1058-
* ⛔ The warn side is not the bug and must not be softened: no shipped runner
1059-
* reads the group, so a translated wizard string really is stored and never
1060-
* shown. The demand is the half that is premature.
1058+
* ⛔ The warn side is not the bug and must not be softened. Only part of the
1059+
* group is read: the console's screen-flow runner reads `screens`, but the
1060+
* flow's own `label` is read by nothing yet (#20318), so a translated flow
1061+
* label really is stored and never shown. The warn is group-level, so it still
1062+
* covers the whole group. The demand is the half that is premature.
10611063
*
10621064
* ## Shape
10631065
*
10641066
* Group-general, not `flows`-specific, and read from the ledger rather than a
1065-
* switch of our own: the day the objectui screen-flow runner lands and the row
1066-
* flips to `live` (dropping its `authorWarn`), the bucket turns itself back on
1067-
* with no edit here — and any FUTURE group that acquires a warn is covered on
1067+
* switch of our own: the day the row flips to `live` (dropping its
1068+
* `authorWarn`; for `flows` that waits on #20318), the bucket turns itself back
1069+
* on with no edit here — and any FUTURE group that acquires a warn is covered on
10681070
* the day it is marked, rather than re-opening this collision one group at a
10691071
* time.
10701072
*

‎packages/cli/test/i18n-flow-liveness-gate.test.ts‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
// `flow` coverage bucket, new in #11615, harvested `flows.<f>.label`,
1010
// `flows.<f>.screens.<n>.title` and the per-field `label`/`placeholder`. The
1111
// `flows` row of `@objectstack/spec/liveness/translation.json` is
12-
// `status: planned` + `authorWarn: true` — no shipped runner reads the group.
12+
// `status: planned` + `authorWarn: true` — only part of the group is read: the
13+
// console's screen-flow runner reads `screens`, but the flow's own `label` is
14+
// read by nothing yet (#20318).
1315
//
1416
// Measured on one stack before the fix:
1517
//
@@ -22,10 +24,11 @@
2224
// restored. Under `--i18n-strict` the demand side is an ERROR, so a project
2325
// could be forced to author keys it is then warned for.
2426
//
25-
// ⛔ The warn side is NOT the bug and is not softened here. Nothing reads the
26-
// group, so a translated wizard string really is stored and never shown —
27-
// the failure mode `validationMessages` was removed in 17.0.0 for. The demand
28-
// is the premature half, and it is what is gated.
27+
// ⛔ The warn side is NOT the bug and is not softened here. The flow's own
28+
// `label` is read by nothing yet (#20318), so a translated flow label really is
29+
// stored and never shown — the failure mode `validationMessages` was removed in
30+
// 17.0.0 for. The warn is group-level, so it still covers the whole group. The
31+
// demand is the premature half, and it is what is gated.
2932
//
3033
// ## What is pinned
3134
//
@@ -165,9 +168,9 @@ describe('the liveness gate on the i18n coverage walk', () => {
165168
expect(flowWarnings(app(false))).toEqual([]);
166169

167170
expect(flowDemands(app(true))).toEqual([]);
168-
// ⛔ The warning is true and stays: nothing reads the group, so this copy is
169-
// stored and never shown. Its rule id says `planned`, i.e. "keep it", not
170-
// "remove it".
171+
// ⛔ The warning is true and stays: the flow's own `label` is read by
172+
// nothing yet, so its translated copy is stored and never shown. Its rule
173+
// id says `planned`, i.e. "keep it", not "remove it".
171174
const warned = flowWarnings(app(true));
172175
expect(warned.length).toBeGreaterThan(0);
173176
for (const f of warned) expect(f.rule).toBe('liveness-planned-property');

‎packages/cli/test/i18n-flow-screen-coverage.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838
// `authorWarn`, and `os lint` runs this bucket in the SAME pass as
3939
// `lintLivenessProperties`, so demanding the keys while the ledger warns
4040
// authors for writing them left the author with no move that satisfies both.
41-
// The bucket is now gated on that row, and it turns itself back on the day an
42-
// objectui screen-flow runner lands and the row flips.
41+
// The bucket is now gated on that row, and it turns itself back on the day the
42+
// row flips to `live` (dropping its `authorWarn`; for `flows` that waits on
43+
// #20318).
4344
//
4445
// So these pins are re-anchored, not retired: the mock below is the ledger
4546
// warning on nothing, i.e. exactly the post-flip world. Retiring them instead

0 commit comments

Comments
 (0)