Observation
The human-face wording for an ADR-0087 D2 conversion notice is now written out three times, verbatim, in three sibling commands:
packages/cli/src/commands/compile.ts:191 printWarning(`...`)
packages/cli/src/commands/lint.ts:554 printWarning(`...`)
packages/cli/src/commands/validate.ts:408 warnings.push(`...`)
All three build the same sentence from the same fields — the converted path, the from/to spellings, the conversion id, and the protocol major the conversion retires in.
Why it is worth recording
The three are held equal only by convention. The source-level parity guard in packages/cli/test/validate-build-gate-parity.test.ts asserts that each of the three authoring commands passes an onConversionNotice sink to normalizeStackInput — it does not assert that they say the same thing once they have one. So a reworded notice in one command drifts from the other two silently, and the drift is invisible to every gate.
That matters a little more than ordinary duplication because the sentence is close to a contract: it is the only warning an old-shape author gets before the conversion retires and their metadata stops loading, and an author who runs two of the three commands over one tree is meant to be told the same thing in the same words.
Not proposed here
Whether to extract a shared formatter (packages/cli/src/utils/format.ts is the obvious home), to extend the parity guard to compare the rendered strings, or to leave three copies as acceptable, is a judgement call — the third is defensible, since validate.ts folds its copy into a warnings list that --strict gates on while the other two print theirs directly, so the three call sites are not quite interchangeable.
Provenance
Noticed while implementing #12297 (PR #13741), which added the third copy. That PR's dispatch fenced compile.ts and validate.ts read-only, so consolidating was not available to it — the duplication is recorded rather than fixed.
Filed unassigned. Observation class, not a specific defect.
Generated by Claude Code
Observation
The human-face wording for an ADR-0087 D2 conversion notice is now written out three times, verbatim, in three sibling commands:
All three build the same sentence from the same fields — the converted path, the from/to spellings, the conversion id, and the protocol major the conversion retires in.
Why it is worth recording
The three are held equal only by convention. The source-level parity guard in
packages/cli/test/validate-build-gate-parity.test.tsasserts that each of the three authoring commands passes anonConversionNoticesink tonormalizeStackInput— it does not assert that they say the same thing once they have one. So a reworded notice in one command drifts from the other two silently, and the drift is invisible to every gate.That matters a little more than ordinary duplication because the sentence is close to a contract: it is the only warning an old-shape author gets before the conversion retires and their metadata stops loading, and an author who runs two of the three commands over one tree is meant to be told the same thing in the same words.
Not proposed here
Whether to extract a shared formatter (
packages/cli/src/utils/format.tsis the obvious home), to extend the parity guard to compare the rendered strings, or to leave three copies as acceptable, is a judgement call — the third is defensible, sincevalidate.tsfolds its copy into awarningslist that--strictgates on while the other two print theirs directly, so the three call sites are not quite interchangeable.Provenance
Noticed while implementing #12297 (PR #13741), which added the third copy. That PR's dispatch fenced
compile.tsandvalidate.tsread-only, so consolidating was not available to it — the duplication is recorded rather than fixed.Filed unassigned. Observation class, not a specific defect.
Generated by Claude Code