Found while implementing #12047, which closes exactly this defect one FIELD over (warnings). Out of that card's scope: the maintainer ruling inherited by #12047 is worded for the advisory lists that ride warnings, and conversions is a separate top-level payload field — widening it is its own machine-contract decision (Clause ②), not a mechanical extension. Recorded rather than fixed.
Measured
At origin/main2ba4329, two runs over the SAME stack, byte-identical except for one field's type ('text' vs an invalid type, to steer the run into the parse-failure exit):
converts + otherwise VALID (success exit)
valid: true
keys: ['conversions', 'duration', 'manifest', 'specVersionGap', 'stats', 'valid', 'warnings']
conversions: [{"code":"OS_METADATA_CONVERTED","conversionId":"page-kind-jsx-to-html",
"surface":"page.kind","toMajor":11,"retiresIn":12,
"from":"jsx","to":"html","path":"pages[0].kind", ...}]
converts + parse error (parse-failure exit)
valid: false
keys: ['duration', 'errors', 'valid', 'warnings']
conversions: <key absent>
The stack in both runs carries pages: [{ name: 'landing', label: 'Landing', kind: 'jsx', source: '<div>hi</div>' }], which the live page-kind-jsx-to-html conversion (ADR-0087 D2, protocol 11, retires in 12) rewrites at load.
Why this is the same shape as the warnings family
conversionNotices is filled by the onConversionNotice callback passed to normalizeStackInput — which runs abovesafeParse in packages/cli/src/commands/validate.ts. So on the parse-failure exit the notice has already been computed and is then discarded, which is precisely the "computed, then dropped" shape of #11643 / #11391 / #11772 / #12047. conversions reaches the payload on the success exit only.
os build has the identical gap: packages/cli/src/commands/compile.ts computes conversionNotices at its step 2 and publishes conversions: on the terminal success payload alone. PR #12079 (for #11772) added warnings to all nine of its failure exits and deliberately left conversions untouched, so closing #11772 and #12047 does not close this.
Why it matters
A deprecated-shape key that was auto-converted at load is the one advisory with an expiry attached — retiresIn names the protocol major where the source stops loading. An author whose stack also trips any later gate gets a payload with no notice in it, so a CI job gating on os validate --json / os build --json cannot see that the tree depends on a conversion that is about to retire, until the unrelated failure is fixed.
Not proposed here
Whether the failure payloads should carry conversions — and, if so, whether it follows the same "carry what the run has already computed" rule the 2026-08-25 ruling set for warnings, or whether the two fields should be folded — is a decision for triage, not this filing. #12047 is not addressed by this issue and remains open on the warnings side.
Filed unassigned, no labels — severity and route are triage's call.
Generated by Claude Code
Found while implementing #12047, which closes exactly this defect one FIELD over (
warnings). Out of that card's scope: the maintainer ruling inherited by #12047 is worded for the advisory lists that ridewarnings, andconversionsis a separate top-level payload field — widening it is its own machine-contract decision (Clause ②), not a mechanical extension. Recorded rather than fixed.Measured
At
origin/main2ba4329, two runs over the SAME stack, byte-identical except for one field'stype('text'vs an invalid type, to steer the run into the parse-failure exit):The stack in both runs carries
pages: [{ name: 'landing', label: 'Landing', kind: 'jsx', source: '<div>hi</div>' }], which the livepage-kind-jsx-to-htmlconversion (ADR-0087 D2, protocol 11, retires in 12) rewrites at load.Why this is the same shape as the
warningsfamilyconversionNoticesis filled by theonConversionNoticecallback passed tonormalizeStackInput— which runs abovesafeParseinpackages/cli/src/commands/validate.ts. So on the parse-failure exit the notice has already been computed and is then discarded, which is precisely the "computed, then dropped" shape of #11643 / #11391 / #11772 / #12047.conversionsreaches the payload on the success exit only.os buildhas the identical gap:packages/cli/src/commands/compile.tscomputesconversionNoticesat its step 2 and publishesconversions:on the terminal success payload alone. PR #12079 (for #11772) addedwarningsto all nine of its failure exits and deliberately leftconversionsuntouched, so closing #11772 and #12047 does not close this.Why it matters
A deprecated-shape key that was auto-converted at load is the one advisory with an expiry attached —
retiresInnames the protocol major where the source stops loading. An author whose stack also trips any later gate gets a payload with no notice in it, so a CI job gating onos validate --json/os build --jsoncannot see that the tree depends on a conversion that is about to retire, until the unrelated failure is fixed.Not proposed here
Whether the failure payloads should carry
conversions— and, if so, whether it follows the same "carry what the run has already computed" rule the 2026-08-25 ruling set forwarnings, or whether the two fields should be folded — is a decision for triage, not this filing. #12047 is not addressed by this issue and remains open on thewarningsside.Filed unassigned, no labels — severity and route are triage's call.
Generated by Claude Code