feat(rollout): promotion gate — enforce a consumed APPROVE review verdict, seal to evidence - #11
Open
mdheller wants to merge 1 commit into
Open
feat(rollout): promotion gate — enforce a consumed APPROVE review verdict, seal to evidence#11mdheller wants to merge 1 commit into
mdheller wants to merge 1 commit into
Conversation
…dict, seal to evidence Closes #10. Continuum owns the rollout promotion gate and its per-action evidence (LIFECYCLE §4); the review VERDICT is consumed from prophet-platform (CapD links.integration_target), not reviewed here. - tools/promotion_gate.py: verify the reviewer's sealed verdict recomputes, require verdict==APPROVE, and emit the decision (allow OR block) to artifacts/gate-decisions/. Fail-closed — a tampered, non-APPROVE, or unsealed verdict blocks promotion. - CapD composes_with.review_gate pins the reviewer (pin-not-vendor). - LIFECYCLE §4 documents the gate; `make rollout` now depends on `promotion-gate` and fails closed without an APPROVE VERDICT. - validate.py requires the gate tool; `make validate` passes. 7 tests (allow, reject, needs-human, tampered-approve, missing-seal, block-evidenced, exit codes). Known gap (explicit): the live pinned reviewer INVOCATION runs in the rollout pipeline where prophet-platform's reviewer is available; this wires the gate + evidence contract and enforces a verdict it is handed.
There was a problem hiding this comment.
Pull request overview
This PR adds a rollout promotion gate to Continuum that consumes a sealed review verdict (from the prophet-platform reviewer), requires an APPROVE outcome, and emits an allow/block decision into the per-action evidence bundle.
Changes:
- Introduces
tools/promotion_gate.py+ pytest coverage to enforceverdict == APPROVEand emit gate decisions as evidence. - Wires the gate into
make rollout(fail-closed if no verdict is provided) and repo validation (tools/validate.py). - Updates CapD + lifecycle documentation to reflect the consumed review-gate dependency and evidence emission location.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
tools/validate.py |
Requires the new promotion gate tool to exist as part of validation. |
tools/promotion_gate.py |
Implements the promotion gating logic and evidence emission. |
tools/test_promotion_gate.py |
Adds tests for allow/block behavior, seal recomputation, and exit codes. |
Makefile |
Adds promotion-gate target and makes rollout depend on it. |
docs/LIFECYCLE.md |
Documents the rollout promotion gate behavior and evidence location. |
capd/continuum.local-paas.capd.json |
Declares the composed review_gate dependency. |
artifacts/gate-decisions/.gitkeep |
Keeps the evidence directory tracked in git. |
.gitignore |
Prevents committing runtime-emitted gate decision JSON artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+28
to
+32
| """Recompute the reviewer's seal over the verdict body. This is an integrity check on | ||
| consumed evidence, not a reimplementation of the review — it only proves the verdict | ||
| bytes were not altered between the reviewer and this gate. The seal is a sha256 over the | ||
| canonical JSON of every field except the seal itself; that contract is shared with the | ||
| producer (prophet-platform review_gate._seal_review).""" |
Comment on lines
+60
to
+64
| reviewed = verdict.get("reviewed") or {} | ||
| key = str(reviewed.get("idempotency_key", "unknown")).replace("/", "_").replace("@", "-at-") | ||
| stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") | ||
| path = evidence_dir / f"{key}.{stamp}.json" | ||
| path.write_text(json.dumps(decision, indent=2, sort_keys=True) + "\n") |
Comment on lines
+78
to
+82
| try: | ||
| verdict = json.loads(args.verdict.read_text()) | ||
| except (OSError, json.JSONDecodeError) as exc: | ||
| print(f"BLOCK: cannot read a review verdict from {args.verdict}: {exc}", file=sys.stderr) | ||
| return 1 |
| @echo "[continuum] rollout — scaffold: promote via caps.infra.cluster-scaleup.hyperswarm" | ||
| promotion-gate: ## rollout gate: require an APPROVE review verdict (fail-closed, evidence-emitting) | ||
| @test -n "$(VERDICT)" || (echo "[continuum] promotion-gate BLOCKED: set VERDICT=<review-receipt.json>" && exit 1) | ||
| python3 tools/promotion_gate.py --verdict $(VERDICT) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10.
What
Continuum owns the rollout promotion gate and its per-action evidence (LIFECYCLE §4). The review verdict it gates on is consumed from
prophet-platform(tools/review_gate.py, this repo's CapDlinks.integration_target) — nothing is reviewed here.tools/promotion_gate.py— verifies the reviewer's sealed verdict recomputes, requiresverdict == APPROVE, and emits the decision (allow or block) toartifacts/gate-decisions/. Fail-closed: a tampered, non-APPROVE, or unsealed verdict blocks promotion.composes_with.review_gatepins the reviewer (pin-not-vendor).make rolloutnow depends onpromotion-gateand fails closed without an APPROVEVERDICT.validate.pyrequires the gate tool.Boundary (per CONTINUUM_SCOPE.md)
Owned here: the promotion gate + evidence. Consumed, not reimplemented: the review logic/model (prophet-platform), source/workspace/runtime-release/scale-up (their canonical owners).
Validation evidence
make validate→ok: sourceos-continuum validation passedpython3 -m pytest tools/test_promotion_gate.py→ 7 passed (allow · reject · needs-human · tampered-approve-still-blocks · missing-seal · block-is-evidenced · exit codes)make rollout(no verdict) → BLOCKED;make rollout VERDICT=<approve>→ promotes, seal verified, evidence written.Known gap (explicit)
The live pinned reviewer invocation runs in the rollout pipeline where prophet-platform's reviewer is available; this PR wires the gate + evidence contract and enforces a verdict it is handed. Pairs with prophet-platform#1125 (the reviewer).