Split out of #10504 while checking its brief's fencing item #2 ("check the --json path for the same drop"). Filed unassigned — not routed, not graded.
Measured
On the blank-shaped zero-apps scaffold at current main head, comparing os validate (text) against os validate --json for the identical config:
Text output includes:
⚠ No apps or plugins defined — this stack may not do much
⚠ Missing manifest.namespace — required for multi-app hosting
--json output for the same run:
{
"valid": true,
"stats": { "objects": 1, ..., "apps": 0, ... },
"warnings": [],
...
}warnings is empty. Not a zero-vs-absent-key nuance (the stats.apps: 0 key is present fine, per #10504's own scope) — the four advisories are structurally unreachable in the JSON path. In packages/cli/src/commands/validate.ts, the JSON payload is emitted and the command returns before the block that computes them:
if(flags.json){awaitemitJson({ ...,warnings: [...ruleAdvisories, ...docWarnings, ...unknownKeyWarnings, ...capProviderWarnings], ... });return;// ← json path exits here}// 5. Warnings (non-blocking) — everything below only ever feeds the text pathconstwarnings: string[]=[];
...
if(stats.objects===0)warnings.push('No objects defined — this stack has no data model');if(stats.apps===0&&stats.plugins===0)warnings.push('No apps or plugins defined — this stack may not do much');if(!config.manifest?.id)warnings.push('Missing manifest.id — required for deployment');if(!config.manifest?.namespace)warnings.push('Missing manifest.namespace — required for multi-app hosting');This is the exact "computed, then discarded" shape the file's own comment (line ~81-82, on unknownKeyWarnings) says it already had to fix once — recurring here for these four checks. A CI script consuming os validate --json to gate on advisories (the documented reason --json exists) cannot see any of these four, regardless of whether the underlying condition is true.
This lane has already seen a text/--json divergence of this general shape on os compile (#10678/#10912).
Suggested landing
packages/cli/src/commands/validate.ts — hoist the four conditions (or compute a shared structuralWarnings: string[] once) above the if (flags.json) branch, the same move already made for unknownKeyWarnings, and include it in both the JSON warnings array and the text-path warnings array.
Split out of #10504 while checking its brief's fencing item #2 ("check the
--jsonpath for the same drop"). Filed unassigned — not routed, not graded.Measured
On the
blank-shaped zero-apps scaffold at currentmainhead, comparingos validate(text) againstos validate --jsonfor the identical config:Text output includes:
--jsonoutput for the same run:{ "valid": true, "stats": { "objects": 1, ..., "apps": 0, ... }, "warnings": [], ... }warningsis empty. Not a zero-vs-absent-key nuance (thestats.apps: 0key is present fine, per #10504's own scope) — the four advisories are structurally unreachable in the JSON path. Inpackages/cli/src/commands/validate.ts, the JSON payload is emitted and the commandreturns before the block that computes them:This is the exact "computed, then discarded" shape the file's own comment (line ~81-82, on
unknownKeyWarnings) says it already had to fix once — recurring here for these four checks. A CI script consumingos validate --jsonto gate on advisories (the documented reason--jsonexists) cannot see any of these four, regardless of whether the underlying condition is true.This lane has already seen a text/
--jsondivergence of this general shape onos compile(#10678/#10912).Suggested landing
packages/cli/src/commands/validate.ts— hoist the four conditions (or compute a sharedstructuralWarnings: string[]once) above theif (flags.json)branch, the same move already made forunknownKeyWarnings, and include it in both the JSONwarningsarray and the text-pathwarningsarray.