|
| 1 | +--- |
| 2 | +"@objectstack/cli": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(cli): `os build --json` carries the computed advisory lists on every failure exit, not the success payload alone (#11772) |
| 6 | + |
| 7 | +**Machine-contract widening on the `--json` failure payloads.** A consumer that |
| 8 | +today branches on `warnings` being ABSENT from an `os build --json` failure |
| 9 | +payload sees a different shape after this change. |
| 10 | + |
| 11 | +## What was wrong |
| 12 | + |
| 13 | +The text face prints its advisory blocks before the gates that can stop the |
| 14 | +run — the #11529 author-time advisories at step 3b, the #3786 undeclared |
| 15 | +authoring-key findings at 3d — and both end in `— re-run with --json for the |
| 16 | +full list`. But `warnings` lived on the TERMINAL SUCCESS payload only (plus, |
| 17 | +for `ruleAdvisories` alone, the author-time-rules failure). On a tree with 60 |
| 18 | +undeclared authoring keys *and* a package-docs error: |
| 19 | + |
| 20 | +``` |
| 21 | +os build Undeclared authoring keys (60) … 50 rows … |
| 22 | + … and 10 more … — re-run with --json for the full list |
| 23 | +os build --json {"success":false,"error":"docs validation failed","issues":[…]} |
| 24 | + ^ the 60 keys nowhere |
| 25 | +``` |
| 26 | + |
| 27 | +The remedy the notice named returned a payload that did not contain the list, |
| 28 | +and the author could not reach the withheld entries by any route until an |
| 29 | +unrelated later failure was fixed — the "the remedy named is unreachable" |
| 30 | +shape of #11643 and #11391. |
| 31 | + |
| 32 | +## Which exits gain the field |
| 33 | + |
| 34 | +All nine failure exits of `os build --json`. Six already had a payload of their |
| 35 | +own; three more were found while enumerating (the filing card's table listed |
| 36 | +six). `warnings` is now present on every one, alongside each exit's existing |
| 37 | +keys, which are unchanged: |
| 38 | + |
| 39 | +| exit (step) | existing keys | `warnings` before | after | |
| 40 | +| --- | --- | --- | --- | |
| 41 | +| `strict-body: missing body` (2b) | `issues` | absent | `[]` | |
| 42 | +| protocol parse failure (3) | `errors` | absent | `[]` | |
| 43 | +| `author-time rules failed` (3b) | `issues` | `ruleAdvisories` | unchanged | |
| 44 | +| `capability provider preflight failed` (3c) | `issues` | absent | rule + capability | |
| 45 | +| `access matrix drift` (3e) | `changes` | absent | rule + key + capability | |
| 46 | +| `docs validation failed` (3f) | `issues` | absent | all four lists | |
| 47 | +| `--no-runtime-bundle` refusal (4b) | `error` | absent | all four lists | |
| 48 | +| `runtime bundle failed` (4b) | `error` | absent | all four lists | |
| 49 | +| thrown / caught (bottom) | `error` | absent | what the run had computed | |
| 50 | + |
| 51 | +The success payload is unchanged in content: its |
| 52 | +`[...ruleAdvisories, ...docWarnings, ...unknownKeyWarnings, ...capProviderWarnings]` |
| 53 | +spread — `os validate --json`'s order minus its trailing `structuralWarnings` |
| 54 | +— moved to a single `warningsSoFar()` site that every exit now reads, so the |
| 55 | +member order cannot drift between exits. |
| 56 | + |
| 57 | +## What a consumer keying off its absence should do instead |
| 58 | + |
| 59 | +⛔ `warnings` is no longer a signal of which exit produced the payload. Read |
| 60 | +`success` (and `error` / `errors`) for that; a consumer that inferred "this is |
| 61 | +a failure payload" from a missing `warnings` must switch to `success === false`. |
| 62 | + |
| 63 | +⛔ `warnings: []` on a failure payload does NOT mean "this tree raises no |
| 64 | +advisories". It means **this run stopped before those advisories were |
| 65 | +computed** — the two early exits above (`strict-body`, protocol parse) run |
| 66 | +before any advisory step, so their list is empty by construction. A consumer |
| 67 | +that needs the full advisory set for a tree must read it from a run that |
| 68 | +reaches at least the gate that computes it, or from `os validate --json`. |
| 69 | + |
| 70 | +✅ `warnings` is always an array on every `os build --json` payload, success or |
| 71 | +failure, so it can be read unconditionally — that shape constancy is the point |
| 72 | +of the change (maintainer ruling 2026-08-25, option 1 of three; option 2, |
| 73 | +"carry them only where the text face printed them", was rejected as the hardest |
| 74 | +contract to declare). |
| 75 | + |
| 76 | +Advisories stay CARRIED, never recomputed: each list is still computed at |
| 77 | +exactly the step that owns it, so an exit upstream of a step legitimately |
| 78 | +reports that list empty and no failure path pays for a computation it did not |
| 79 | +already do. |
0 commit comments