flows: flows build gates on flows check green — no bad digests
Tracked-only follow-up to slice A (#298, PR#316). No separate agent dispatch — this is a small standalone PR (or a follow-up commit on the same branch) once #298 lands.
Scope
Within flows build, invoke the same preflight pipeline that flows check uses. If any diagnostic surfaces at refusal severity, flows build exits 2 with the diagnostic printed on stderr and no artifact directory is created. --json produces the same report shape flows check --json produces.
Concretely:
flows build <flow> calls the existing checkAuthoredFlow / checkYamlFlow entry point that flows check uses.
- If
report.ok !== true (any severity: 'refusal' diagnostic present), exit 2 before any file capture, canonical spec write, digest computation, or bundle directory creation. Print diagnostics on stderr.
- If
--json is set, print the report as a single JSON object on stdout matching the exact shape flows check --json emits, then exit 2.
- On success, proceed to the existing build pipeline — canonical spec JSON → compiled TS → preflight declaration → identity signature → manifest → digest.
The refusal path never leaves partial artifacts. A previous dist/flows/<name>@sha256:<hex>/ directory from an earlier successful build is not touched.
Rationale
The immutable bundle is content-addressed — once it exists, its digest may be pushed to a registry, referenced from a deploy record, or run on any cell without a checkout (per SURFACE.md §4). A bundle that encodes a broken flow (bad model, missing MCP server, invalid schema, unresolved use: import) becomes a supply-chain hazard the moment it leaves the author's machine. The check-then-build sequence prevents this by construction rather than by convention.
Acceptance evidence
Depends on
Files
packages/sdk/src/cli/build.ts — insert preflight gate at the top of the build entry, before any file capture or canonical spec write.
packages/sdk/tests/build.test.ts (or new build-gate.test.ts) — three acceptance cases above.
Not in scope
- Warning-level diagnostics (e.g.,
vacuous_gate) do not block the build — they surface in the report but the digest still emits. Only severity: 'refusal' gates.
- Rebuild-on-source-change (would be a
flows build --watch follow-up; see slice L3 for the analogous flows check --watch).
- Signing / provenance beyond what slice A already covers.
flows:
flows buildgates onflows checkgreen — no bad digestsTracked-only follow-up to slice A (#298, PR#316). No separate agent dispatch — this is a small standalone PR (or a follow-up commit on the same branch) once #298 lands.
Scope
Within
flows build, invoke the same preflight pipeline thatflows checkuses. If any diagnostic surfaces at refusal severity,flows buildexits2with the diagnostic printed on stderr and no artifact directory is created.--jsonproduces the same report shapeflows check --jsonproduces.Concretely:
flows build <flow>calls the existingcheckAuthoredFlow/checkYamlFlowentry point thatflows checkuses.report.ok !== true(anyseverity: 'refusal'diagnostic present), exit2before any file capture, canonical spec write, digest computation, or bundle directory creation. Print diagnostics on stderr.--jsonis set, print the report as a single JSON object on stdout matching the exact shapeflows check --jsonemits, then exit2.The refusal path never leaves partial artifacts. A previous
dist/flows/<name>@sha256:<hex>/directory from an earlier successful build is not touched.Rationale
The immutable bundle is content-addressed — once it exists, its digest may be pushed to a registry, referenced from a deploy record, or run on any cell without a checkout (per SURFACE.md §4). A bundle that encodes a broken flow (bad model, missing MCP server, invalid schema, unresolved
use:import) becomes a supply-chain hazard the moment it leaves the author's machine. The check-then-build sequence prevents this by construction rather than by convention.Acceptance evidence
flows build good.flow.yamlproducesdist/flows/<name>@sha256:<hex>/with the full bundle. Exit0.flows build bad.flow.yamlwherebad.flow.yamlhas a refusal diagnostic (e.g., unknown model, missing CLI, invalidverificationblock) exits2. Nodist/flows/artifacts. Diagnostics printed on stderr.flows build --json bad.flow.yamlexits2and prints one JSON object on stdout matchingflows check --jsonshape. No artifacts.flows build --json good.flow.yamlprints the successful check report followed by the build artifacts summary (or the build report; PR to decide the exact--jsonshape).bad.flow.yamlis used, no filesystem side-effect occurs beyond stderr.Depends on
flows buildverb itself. This gate is a follow-up commit on the same branch or a small standalone PR once flows: content-addressed immutable bundle (flows build) — SURFACE §4 #298 merges.Files
packages/sdk/src/cli/build.ts— insert preflight gate at the top of the build entry, before any file capture or canonical spec write.packages/sdk/tests/build.test.ts(or newbuild-gate.test.ts) — three acceptance cases above.Not in scope
vacuous_gate) do not block the build — they surface in the report but the digest still emits. Onlyseverity: 'refusal'gates.flows build --watchfollow-up; see slice L3 for the analogousflows check --watch).