brandon@seoul:~/posts/crucio-ship-two-phase-merge-gateen / ko
crucio-ship-two-phase-merge-gate/index.md0%
Back to posts

Two-Phase Invocation as a Manual Merge Gate

When a CI/CD automation skill supports an "all-in-one" mode (`/skill +flag`), the all-in-one mode should be opt-in, not the default. Splitting invocations preserves a meaningful pause point between CI green and the irreversible merge.

On this page
  1. Invoke twice, on purpose
  2. Why the gate is the value
  3. What the design got wrong
  4. When this fits
  5. Practical takeaway
  6. References

/crucio-ship runs three logical phases for a PR-to-prod ship. Each phase has very different reversibility properties, and bundling them into one invocation conflates the easy parts with the irreversible parts.

PhaseActionReversibility
1Dispatch + watch CI on the PR branchRead-only
1.5gh pr merge --merge --delete-branchIrreversible (without revert PR)
2Dispatch deploy + verify chain firesProduction-affecting

Phase 1.5 is the one that matters. Once gh pr merge --merge lands the commit on the base branch, the way back is a second pull request that reverts the merge commit — cheap, but no longer free, and it leaves a trail.

The skill supports +merge as an arg that runs all three phases in one invocation. Convenient — but it removes the “operator looks at green CI and decides to authorize merge” step. For a portfolio prod environment with manual smoke tests, that gate has real value. The skill itself doesn’t need modification — invoking with vs without +merge IS the gate.

Invoke twice, on purpose

The pattern is to invoke twice instead of once with +merge:

First invocation:  /crucio-ship       → Phase 1 only (CI dispatch + watch)
                                        → Hard-blocks on red CI
                                        → Reports green/red status
                                        → EXITS

[operator inspects logs, decides to ship]

Second invocation: /crucio-ship +merge → Phase 1 (re-runs — wasteful) +
                                          Phase 1.5 + Phase 2

The “Phase 1 re-runs” cost is real but the cycles are cheap (~10min CI run on a small change). For larger CI suites, the skill could grow a +from=phase1.5 arg to skip already-verified phases, but that’s YAGNI for now.

There’s an alternative for high-CI-cost cases: instead of re-invoking the skill, manually execute Phase 1.5 + 2 using the loaded skill content as a runbook. This skips the re-CI cost entirely. Trade-off: you’re hand-running steps the skill would otherwise script. Fine for an interactive session, not for unattended automation.

Why the gate is the value

Three reasons this pattern justifies its overhead:

  • High-blast-radius automation should default to multi-step. The single-shot mode should require an explicit flag, not be the default. Default behavior is what gets used when nobody is paying attention; the safe path should be the default.
  • The gate is the value, not the skill code. The skill itself doesn’t need new code; the invocation pattern provides the gate. Don’t conflate “skill design” with “skill use” — sometimes how you call a tool is the design.
  • Cheap re-runs make split-invocation viable. If Phase 1 cost $50/run, the re-run penalty would force a different design. Cheap CI is what makes this pattern affordable.
  • Document the split as the recommended path. Otherwise operators discover +merge first, use it once, and never go back.

What the design got wrong

Two things bit during use:

  • The naming is asymmetric. /crucio-ship (no flag) is “Phase 1 only” and /crucio-ship +merge is “all phases.” Reading skill docs, it’s not obvious that omitting the flag is the gated path. Clearer naming would be /crucio-ship-check + /crucio-ship-execute, but the flag-based design is already shipped, and renaming a deployed skill costs more than it gains.
  • Re-invoking the skill costs ~10min of CI re-run. For small changes this is acceptable; for large changes (full test suite) it’s not. Workaround: hand-execute Phase 1.5 + 2 from the skill content as a runbook in the same session, skipping the re-CI cost.

When this fits

Use a multi-invocation split when:

  • Production deploys where the operator should consciously authorize the irreversible step (merge, push to main, dispatch deploy).
  • Multi-phase automation where intermediate state (CI green) is itself meaningful information the operator wants to inspect.
  • Skills with hard-block gates (red CI = abort) — the gate is what you came for; don’t bypass it with auto-everything.

Don’t bother with the split when the automation is truly low-blast-radius (preview deploys, dev environments, internal tooling — all-in-one is fine), when shipping is unattended/cron-driven (CI bot, Renovate auto-merge — the gate is meaningless when no human is waiting), or when the gate would just be rubber-stamping. If the operator’s decision is always “yes, ship,” the gate is theater. Either improve pre-merge signals or accept auto-shipping.

Practical takeaway

For high-stakes automation, opt-in for the all-in-one path and split invocation as the default. The gate between “CI green” and “merge merged” is one of the cheapest places to insert a human check, and a 4-round AI-reviewed PR still benefits from one human “yes, merge now” before the irreversible step. The skill code doesn’t need to change — how you call the skill is the design.

References

Comments

Back to posts

0:home1:posts2:study3:b34:about