v1.2.0 to v1.3.0

21 added, 19 removed. Audit A to A.

---
name: ready-to-release
description: >
Deep release-readiness gate for a single letterbox service — checks CI green, contracts in
sync, deploy-order prereqs satisfied, feature toggle present, and unpushed work vs the live
deploy. Emits a gate table and a single verdict. Use before deciding to ship one service.
- allowed-tools: "Read,Skill,Bash(make git-status:*),Bash(make ci-status:*),Bash(make deploy-status:*),Bash(make feature-toggles:*),Bash(./scripts/mgit log:*),Bash(./scripts/pact-graph:*)"
+ allowed-tools: "Read,Skill,Bash(make git-status:*),Bash(make ci-status:*),Bash(make deploy-status:*),Bash(make feature-toggles:*),Bash(./scripts/mgit log:*),Bash(./scripts/release-order:*)"
model-tier: standard
model: sonnet
effort: medium
- version: "1.2.0"
+ version: "1.3.0"
author: "flurdy"
---
# Ready to Release
A focused, per-service readiness gate. Where `/release-manager` scans everything and prompts,
this answers one question thoroughly: **is `<service>` safe to ship right now?** Read-only —
it reports a verdict, it does not push.
This is the deploy-side cousin of `/ready-to-merge` (which gates a PR *merge*). This gates a
*release* of an already-merged service: built locally, CI green, contracts honoured, deploy
order respected, toggle in place.
## Usage
```
/ready-to-release dispatch
```
A service argument is required.
## Instructions
Run these checks for the named service and present a gate table (✅ / ⚠️ / ❌ per row):
1. **Unpushed work** — `make git-status <service>`. Show commits ahead (`N`) and whether the
tree is dirty (`*`). `N = 0` → nothing to release (note it and stop). Dirty tree → ⚠️
(commit first). List the unpushed commits with `./scripts/mgit log <service> --oneline @{u}..HEAD`.
2. **CI** — `make ci-status <service>`. `success` → ✅; `running` → ⚠️ (wait); `failed`/`error`
→ ❌ (blocker); `unknown` (no CircleCI key) → ⚠️.
3. **Contracts** — if the service has connectors/pacts, run `Skill /contract-check status` and
read the rows for this service. Covers both contract *state* (staleness / unsynced /
uncommitted → ❌) and *verification coverage* — if this service is a provider with a
coverage `GAP` (CI doesn't verify all its consumer pacts, e.g. commented-out consumers),
flag ⚠️ (a contract change may break an unverified consumer).
- 4. **Deploy order** — run `./scripts/pact-graph` (a project symlink installed by
- /release-manager — see its Setup if missing) and read `docs/release-manifest.yaml`. Build
- the effective dependency map = `(order.derived ∪ order.manual) − order.suppress`, and take
- this service's prereqs. A prereq blocks only if it is *co-changing* — has unpushed commits,
- is mid-rollout (`make deploy-status <prereq>` shows a Deployment `N/M`, N<M, or a CronJob
- service — digest/patrol/reconciler — showing `cron:rollout`), or was pushed-but-not-rolled.
- A stable, already-live prereq (a Deployment `1/1` at current tag, or a CronJob service showing
- the settled `cron` marker) does **not** block. All clear → ✅; any
- co-changing prereq → ❌ (waiting on `<prereq>`). (Contract coverage is checked in step 3, not
- here — this step is purely deploy ordering.)
+ 4. **Deploy order** — run `./scripts/release-order` (a project symlink installed by
+ /release-manager — see its Setup if missing) and use its `---GRAPH---` as the effective
+ dependency map. Take this service's prereqs directly from that graph; do not parse or merge
+ manifest order sections in the skill. A prereq blocks only if it is *co-changing* — has
+ unpushed commits, is mid-rollout (`make deploy-status <prereq>` shows a Deployment `N/M`, N<M,
+ or a CronJob service — digest/patrol/reconciler — showing `cron:rollout`), or was
+ pushed-but-not-rolled. A stable, already-live prereq (a Deployment `1/1` at current tag, or a
+ CronJob service showing the settled `cron` marker) does **not** block. All clear → ✅; any
+ co-changing prereq → ❌ (waiting on `<prereq>`). `provider=none` is a valid empty map and reports
+ ✅ `no deploy ordering configured`. (Contract coverage is checked in step 3, not here — this
+ step is purely deploy ordering.)
- 5. **Feature toggle** — if `docs/release-manifest.yaml` `toggles` has an entry whose `service`
- is this one, report the flag, its live value (`make feature-toggles`), and the `flip_when`
- condition so you know whether shipping needs a follow-up toggle flip. Missing-but-expected
- toggle → ⚠️. A toggle with `status: dark-release` means the service is in a shadow launch —
- report it as `🌓 dark-release` (flip is a later manual call), not a blocker. If the service
- has a `parked` flag, note it as informational only (deliberately off, `superseded_by` /
- `reconsider_if`) — never treat it as a pending flip.
+ 5. **Feature toggle** — If `docs/release-manifest.yaml` is absent, report `no manifest toggle`
+ and continue without a toggle blocker. Otherwise, if its `toggles` map has an entry whose
+ `service` is this one, report the flag, its live value (`make feature-toggles`), and the
+ `flip_when` condition so you know whether shipping needs a follow-up toggle flip.
+ Missing-but-expected toggle → ⚠️. A toggle with `status: dark-release` means the service is in
+ a shadow launch — report it as `🌓 dark-release` (flip is a later manual call), not a blocker.
+ If the service has a `parked` flag, note it as informational only (deliberately off,
+ `superseded_by` / `reconsider_if`) — never treat it as a pending flip.
6. **Live deploy** — `make deploy-status <service>`: show current `ready/tag/age` so you can see
what's running versus what you're about to ship. For a CronJob service (digest/patrol/reconciler)
this is the `cron`/`cron:rollout` marker + tag + last-run age, not replicas.
## Verdict
End with one line:
- **READY ✅** — unpushed commits, CI green, contracts in sync, prereqs rolled out. Suggest
`make git-push <service>` (the user runs it, or use `/release-manager`).
- **NOT READY ❌** — list the blocking rows.
- **HOLD ⚠️** — only soft warnings (CI running, dirty tree, toggle follow-up); say what to wait for.
Read-only: never push here. Pushing is an explicit action via `/release-manager` or `make git-push`.