03 - Deploy Plan & Rollback
03 - Deploy Plan & Rollback
O6 · doc 3 of 8 · 2026-05-21 · Gate G2 — deploy plan lock. This plan is authored and locked but NOT executed — G3 is blocked on the source-availability gap (doc 04). The plan is the command-review-ready artifact for the macro that resolves the gap.
1. Prerequisite that must be satisfied BEFORE this plan can run
The v0.6 source tree at HEAD
6625f76must be present on a Contabo-reachable path. See doc 04 §3 for the four accepted ways to deliver it. Until then, every step below is a plan, not a log.
2. Deploy target decision
| Strategy | Description | Verdict |
|---|---|---|
| Replace in-place | overwrite /opt/incomex/dot/iu-cutter (v0.4→v0.6) |
rejected for first deploy — destructive |
| Side-by-side | new dir /opt/incomex/dot/iu-cutter-v0.6/; v0.4 left intact |
CHOSEN |
| Timestamped release | /opt/incomex/deploys/iu-cutter-v0.6-6625f76-<stamp>/ + pointer |
acceptable alternative |
Decision: side-by-side, non-destructive.
deploy_target: /opt/incomex/dot/iu-cutter-v0.6/
backup_of_v0.4: not required to MOVE v0.4 — it stays in place untouched;
additionally /opt/incomex/dot is a git repo (history = backup)
release_stamp: record HEAD 6625f76 + UTC stamp in a DEPLOY-MANIFEST.txt
inside the target dir
invocation: orchestrator is a manual CLI — callers use an explicit
path; no symlink/service switch needed
promotion: replacing v0.4 in-place is deferred until AFTER O7
post-deploy dry-run PASS (separate, reviewed step)
Rationale: iu-cutter is not a long-running service, so a new
directory introduces zero runtime risk; rollback is a single rm -rf
of a dir the macro itself created; v0.4 is never at risk.
3. Backup rule
v0.4_tree: left in place, untouched; dot-repo git history is its backup
pre_state: record sha256 of the deploy target's parent listing before
creating the new dir; record that the new dir did not pre-exist
no overwrite of any pre-existing path
4. Rollback command (exact)
# side-by-side rollback — removes ONLY what O6 created:
rm -rf /opt/incomex/dot/iu-cutter-v0.6
# v0.4 at /opt/incomex/dot/iu-cutter is untouched → nothing else to undo
# no service to restart; no DB change; no .env change
If a later macro promotes v0.6 in-place, rollback becomes
git -C /opt/incomex/dot checkout -- iu-cutter (or restore the
timestamped backup) — out of scope for O6.
5. Smoke command set (to run in G5/G6 once deployed)
G5_static_and_unit:
- py_compile: python3 -m compileall /opt/incomex/dot/iu-cutter-v0.6
- import: python3 -c "import cutter_agent, cutter_agent.orchestrator"
- version: assert cutter_agent.__version__ startswith 0.6
- kill_switch: assert orchestrator.__execution_enabled__ is False
- tests: python3 -m pytest tests/ -q (expect 366/366)
- status: python3 cli.py orchestrate inspect / status
→ milestone O4/O6-ready, execution_enabled=False
G6_readonly_dryrun_smoke:
- mode: Mode.DRYRUN only
- role: context_pack_readonly (read-only, proven in O3/O4)
- txn: BEGIN READ ONLY ... ROLLBACK around every live SQL
- assert: pre/post production counts identical; Mode.LIVE refused
- forbidden: no INSERT/UPDATE/DELETE; no fn_iu_create/fn_iu_enact;
no review_decision/verify_result write
6. No-secret logging rules
- no `set -x` in any deploy/smoke wrapper
- never read or print .env / .env.production VALUES; env-var NAMES only
- artifact dir: timestamped, chmod 700
- redact any DSN/password if a tool would echo it
- KB reports: secrets stripped on serialize (kb_reporter doctrine)
7. Runtime skeleton plan (G4 — deferred, not executed)
To be provisioned only after a successful deploy, non-secret only:
dirs: /var/lib/cutter/runs , /var/lib/cutter/batches , /var/lib/cutter/locks
config: orchestrator.* keys (sidecar_root, batch_dir, global_locks_dir,
expected_grant_matrix_sha = 45d25e38...e2d600 from O4,
run_hard_cap_minutes, phase_soft_cap_minutes)
secrets: NONE written by O6; existing env-file secrets used read-only
for read-only smoke if needed, values never logged
execution_enabled: stays False
O6 did not create these dirs — the host is left 100% untouched because the deploy is blocked (doc 04). They are planned here so the follow-up macro can provision them in one reviewed step.
8. STOP condition check
The G2 mandate says "If unsafe/ambiguous: STOP." The plan above is safe and unambiguous as a plan, but it cannot be executed: its §1 prerequisite (v0.6 source on a Contabo-reachable path) is not met. → Proceed to doc 04, which records the exact block.
9. G2 result
G2_deploy_plan: LOCKED (authored, command-review-ready)
G2_executable_now: NO — blocked on the §1 source-availability prerequisite
target: /opt/incomex/dot/iu-cutter-v0.6/ (side-by-side, non-destructive)
rollback: rm -rf /opt/incomex/dot/iu-cutter-v0.6 (v0.4 untouched)