Product Commands
A product spec is one TOML file at products/<name>.toml. It declares WHAT a data product must be: its grain, columns, checks, freshness, and classifications. The spec adds no new runtime machinery. Every field lowers onto something the engine already enforces — a contract, declarative tests, sidecar metadata, or the policy posture. A field that cannot lower is refused at parse time, never shimmed.
The verbs on this page are the deterministic half of spec fulfillment. They parse, verify, lower, and approve. The agent loop that drafts SQL is rocky fulfill, and it is gated by the same policy plane as every other agent action.
products/<name>.toml ──verify──▶ posture + tags + collisions │ ├──approve──▶ immutable snapshot + approval record (one transaction) │ └──compile──▶ Phase A: models/<model>.contract.toml Phase B: metadata merged into models/<model>.toml (staged writes; the manifest rename commits)rocky product verify
Section titled “rocky product verify”Check that a product may be fulfilled, without writing anything.
rocky product verify revenue_dailyThree checks run in order, fail-closed:
- Trust posture.
rocky.tomlmust carry the frozenpropose_onlyposture: a[policy]block withdefault_agent_effect = "require_review", an agentproposerule that resolvesallowand is scoped to exactly this product’s output model (noany, no glob, no extra predicates, no autonomy budget), and agentapplyresolvingrequire_reviewordeny. A policy that merely happens to resolve safely is rejected — authority that reaches past the product is global agent authority. The verdicts come from the engine’s own policy evaluator, run against the attributes the lowering is about to create (the post-image), so the gate cannot be evaded by the change under review. - Classification tags. Every tag in
output.classificationsmust resolve to a[mask]strategy, a[mask.<env>]override, or[classifications].allow_unmasked. This is an error here; plainrocky compileonly warns (W004). Resolution only: whether masking is applied is warehouse-dependent. - Identity collisions. The product name must not be claimed by another spec file, and the output model must not be claimed by another product.
Exit codes: 0 pass · 1 needs input (a paste-ready [policy] block is printed) · 2 fail.
JSON output
Section titled “JSON output”ProductVerifyOutput: status (pass | needs_input | fail), reason, paste_block, and the resolved propose_effect / apply_effect.
rocky product compile
Section titled “rocky product compile”Verify, then lower the spec. Refuses unless verify passes.
rocky product compile revenue_dailyLowering runs in two phases because the drafting tool rewrites the model sidecar wholesale — metadata lowered before drafting would be destroyed:
- Phase A (before drafting) renders
models/<model>.contract.toml— the spec-owned contract the draft must compile against. - Phase B (after the drafted sidecar exists) merges the spec-owned metadata into
models/<model>.toml: sources, the product tag, classifications, freshness, and the generated tests (grain uniqueness,not_nullper non-nullable column, oneexpressiontest per check). The worker’sname,intent, and appended tests survive.
The command picks the phase itself: Phase A on a fresh product, Phase B once models/<model>.toml exists. Re-running is safe — the merge is idempotent.
Every generation commits through staged same-directory writes, journaled, with the lowering manifest renamed last as the commit marker. A crash at any point rolls back on the next run: the previous generation is restored exactly. The journal is treated as untrusted input during recovery — forged, traversing, symlinked, or foreign entries are refused before anything mutates.
If an approval exists, compile re-verifies the snapshot’s bytes against the approval digest before doing anything. A mismatch is tamper, and nothing proceeds.
JSON output
Section titled “JSON output”ProductCompileOutput: the committed phase, each artifact with its sha256, the manifest_path, and the approval echo (spec_matches_approval is false when the working spec has moved past the approved revision — not an error; the loop treats it as supersession).
rocky product approve
Section titled “rocky product approve”Record a human’s approval of the current spec revision.
rocky product approve revenue_dailyApproval is one authority transition, in a fixed order:
- The approved bytes are written to
.rocky/fulfillment/<name>/approved-<digest-hex>.toml— immutable and digest-addressed. A digest-named file is never overwritten, so no reader can ever observe new-digest-old-bytes. - One state-store transaction records the approval, moves the product’s fulfillment state to
spec_approved, and appends the journal row. All or nothing.
A crash between step 1 and step 2 leaves only an orphan snapshot file — harmless; the next approve completes over it. Approving the already-approved digest is a no-op. When two people race, the second approve loses its compare-and-swap cleanly and prints the winning digest.
The approver identity is the same best-effort git identity the review marker records. It is an attribution, not an authentication.
JSON output
Section titled “JSON output”ProductApproveOutput: spec_digest, approver, approved_at, snapshot_path, previous_state, and already_approved.
rocky product status
Section titled “rocky product status”Read-only report. Writes nothing, recovers nothing.
rocky product status revenue_dailyReports: the spec’s identity (or its parse error), the committed lowering phase, byte-verification of every committed artifact against the manifest, whether a crashed commit’s journal is pending (the next compile resolves it), the approval record with snapshot integrity, whether the working spec still matches the approved revision, and the persisted fulfillment state with its journal row count.
JSON output
Section titled “JSON output”ProductStatusOutput — every field above, machine-readable.
Validation codes
Section titled “Validation codes”rocky validate checks products/ offline with its own code band:
| Code | Severity | Meaning |
|---|---|---|
V050 |
ok | Every spec in products/ parsed. |
V051 |
error | A spec fails the strict parser; the message carries the parser’s stable reject code. |
V052 |
error | A spec’s product.name disagrees with its file name. |
V053 |
error | Two specs claim the same output model. |