# Incident sequence — PARTIAL_SUCCESS → cleanup → destroyed commit, and the structural remedy

_Source: `system/_operator/plans/2026-05-13-promote-session-resilience-push-before-prune.md` (Objective
~L76, Defect D1 ~L92, failure narrative ~L96) and the current gate scripts. The incident is internal
tooling: `apps/rentos-canary` is an internal canary app and `cc1fc8a` is an internal commit — both are
retained here because they are load-bearing for the claim, not sensitive. No secrets, credentials, or
customer data appear._

## What happened

During the Cure v2 **blind-benchmark contamination-barrier** work, a canary commit `cc1fc8a` was
authored on a **non-`main` branch inside the `apps/rentos-canary` submodule**, then destroyed during
close-out cleanup. The plan's Objective names the eliminated condition directly: "the structural
conditions that allowed canary commit `cc1fc8a` to be destroyed during the Cure v2 blind-benchmark
contamination barrier work."

### The sequence (pre-2026-05-13 three-gate shape)

1. **Close** minted a promotion-request. The old `detectSessionTouchedSubmodules` used
   `git diff --submodule=short forkPoint..HEAD`. For `cc1fc8a` on a non-`main` branch, detection either
   missed the entry, or hit it without correct `branch` metadata for the push step to land it on a
   remote. Either way, **push never published `cc1fc8a` to any submodule origin.**
2. **Promote** ran `promote-session-execute.mjs`, which pushes session-owned submodules and returns
   `EXIT.SUCCESS` (0) or `EXIT.PARTIAL_SUCCESS` (21). Because no push was even attempted for the
   unpublished SHA, execute recorded **no push failure** and returned SUCCESS.
3. **Prune, buried inside promote as "Step 5.5",** ran `git worktree remove --force` then
   `git branch -d` whenever the execute exit was in `{SUCCESS, PARTIAL_SUCCESS}`. Failures were labelled
   **"NON-FATAL — promote success is the higher-priority outcome"**, emitting a WARN plus a
   "Manual cleanup: git -C …" line and exiting 0.
4. The worktree was removed and the branch deleted. `cc1fc8a` — which had never been pushed — **became
   unreachable.** Recovery required hand-reconstructing the work as `202cec2` and re-advancing the
   gitlink.

## The three structural defects (plan Defects D1–D3)

- **D1 — Prune runs on `PARTIAL_SUCCESS`** (~L92): prune fired even in the post-CAS-push-failure state,
  "the very state in which push reachability is known broken. Latent data-loss path."
- **D2 — Prune embedded inside promote** rather than gated as its own boundary — the same conflation the
  earlier close-merge-and-deploy redesign had already repaired on a different surface.
- **D3 — Prune failures are "non-fatal" with logged remediation** — lock, branch-delete, and unexpected
  exceptions all logged a WARN and exited 0, which the Robustness Directive forbids (deferred cleanup
  with "manual cleanup later" framing).

## The structural remedy

The failure was not fixed by patching the buried step; the buried step was **eliminated** by promoting
prune to its own gate and making three properties enforceable:

1. **Separate the four states** — close / promote / prune / deploy each become a distinct command
   boundary (see `four-gate-contract.md`). Prune, the destructive step, is no longer buried where
   "best-effort" is the natural framing.
2. **Push-before-prune becomes binding** — the prune gate verifies every session-touched submodule SHA
   is reachable from a pushed remote ref (trace cross-reference **plus** a live `ls-remote`) before any
   destructive operation. Critically, `promote-session.mjs` **must not spawn** `prune-session.mjs` on
   Exit 21 (`PARTIAL_SUCCESS`) or when `all_inputs_reachable` is false — the exact D1 state that
   destroyed `cc1fc8a` (see `prune-exit-codes.md`).
3. **Ambiguous reachability is a HALT with fail-closed exit codes** — an unreachable SHA exits 30
   without removing the worktree; a missing/ambiguous `.gitmodules` branch line exits 33; every failure
   mode has a named code and a sidecar. No inference, no WARN-and-continue.

**Caliber C112 (Critical, no grace, no kill switch)** keeps the isolation installed — its five
dimensions (see `c112-contract.md`) mechanically re-assert, on every graded run, that the destructive
tokens stay out of promote, that prune is fail-closed, and that the "non-fatal / best-effort / Manual
cleanup" framing that made the incident possible can never re-enter the prune gate.
