---
mode: CREATE
adr_id: ADR-0.0.71
branch: main
timestamp: "2026-06-13T07:00:47Z"
agent: claude-code
obpi_id: OBPI-0.0.71-01-completion-repudiation-event
session_id:
continues_from:
last_lock_event_timestamp: "2026-06-13T06:04:03.639942+00:00"
last_commit_sha: f428154d403b9a1bb510af4ec230661df4b66f1a
branch_state: "main, level with origin/main at handoff time (pre-Stage-5-sync)"
---

<!-- Handoff document for ADR-0.0.71 — created by claude-code at 2026-06-13T07:00:47Z -->

## ⚠️ This handoff ADVISES next moves — it is NOT authorization to execute them

**Read this before anything else.** A handoff records a *proposed* plan and its
context. It is **NOT** a clearance to unilaterally execute that plan. On resume —
at **every** freshness level, Fresh included — you MUST:

1. Present the advised next steps and current state to the operator.
2. **Obtain explicit operator authorization before executing any of them** — no
   file mutation, no `gz` ceremony, no migration until the operator says go.
3. Treat the human-as-final-witness doctrine as binding from the first step: you
   advise; the operator rules; you note variance and stop.

Barreling into execution from this document is the exact failure this handoff
exists to prevent. The plan is the destination; operator authorization is the
ignition.

## Current State Summary

OBPI-0.0.71-01-completion-repudiation-event is **Completed and operator-attested**
(2026-06-13, attestor Jeffry Babb). The engine layer for ADR-0.0.71 governed
completion-repudiation landed and is green across the full suite.

Delivered:
- `src/gzkit/events.py` — `ObpiCompletionRepudiatedEvent` Pydantic model (fields
  `repudiated_receipt`, `cause` closed-enum, `attestor`/`reason` `min_length=1`),
  added to the `TypedLedgerEvent` discriminated union.
- `src/gzkit/ledger_events.py` — `obpi_completion_repudiated_event()` factory.
- `src/gzkit/ledger.py` — `_apply_obpi_completion_repudiated_metadata()` wired
  into `_apply_graph_event_metadata`; `_apply_obpi_receipt_metadata` clears
  `repudiated` on genuine re-completion; factory re-exported.
- `src/gzkit/schemas/ledger.json` — `obpi_completion_repudiated` schema entry.
- `tests/test_completion_repudiation.py` — 13 unit tests, all green.
- `tests/test_schemas.py` — `_EVENT_MODELS` registry entry.

Last action: `gz obpi complete` succeeded (EXIT 0) with an operator-authorized
`--accept-security-floor` override; lock release is the only remaining Stage 5
step pending this handoff (register entry), followed by git-sync #1, reconcile,
ADR status refresh, and git-sync #2.

## Important Context

- **Security floor override (GHI #462):** OBPI-0.0.71-01 edits `src/gzkit/ledger.py`
  and `src/gzkit/ledger_events.py`, both registered `ledger_integrity` security
  surfaces in `data/security_surfaces.json`. The security-scan canonical slot is
  unfilled because the toolchain ADR (promoting `pool.agentic-security-review`)
  has not landed. Completion required `--accept-security-floor` with an
  additive/defensive reason; the operator explicitly authorized this override
  (2026-06-13). The brief does NOT declare `sensitivity: security` — a latent gap
  the operator chose to clear via override rather than re-declaration.
- **req_atomic exemption:** the brief declares `req_atomic:` for all 7 REQs — the
  engine layer was one indivisible labor unit (model + factory + resolver + schema
  + tests landed together), so the pipeline-minted seq=01 buckets are the true
  labor shape, not coarse defaults (GHI #590).
- **behave waiver:** an entry in `data/behave_coverage_waivers.json` waives all 7
  REQs — the engine layer has no operator-runnable CLI surface for behave to
  drive; the behave smoke test is scoped to OBPI-02 (the CLI verb) per the ADR
  decomposition.
- **brief reconcile amendment:** `src/gzkit/traceability.py` was added to the
  brief allowlist (operator-attested) because the test imports `covers` from it.

## Decisions Made

- **Decision:** Override the security floor via `--accept-security-floor` rather
  than halt or re-declare sensitivity.
  **Rationale:** the change is structurally additive/defensive (preserves
  append-only Boundary Invariant 3, tested); the scanner slot is unfilled by a
  pending infra ADR, not by this OBPI; operator authorized the override.
  **Alternatives rejected:** (a) add `sensitivity: security` + override — still
  requires the override since the scan receipt cannot be produced; (b) halt and
  file a GHI — leaves the OBPI implemented-but-unattested for an infra gap outside
  its scope.
- **Decision:** Declare `req_atomic:` for all 7 REQs.
  **Rationale:** the engine layer is genuinely one indivisible labor unit.
  **Alternatives rejected:** subdividing via `gz task start --seq next` would
  manufacture false labor boundaries.

## Immediate Next Steps

1. **Finish Stage 5 of THIS pipeline first** (not OBPI-02 yet): release the lock
   via `uv run gz obpi lock release OBPI-0.0.71-01-completion-repudiation-event`
   (this handoff is the register entry that unblocks it), then git-sync #1
   (`uv run gz git-sync --apply`), then
   `uv run gz obpi reconcile OBPI-0.0.71-01-completion-repudiation-event`, then
   `uv run gz adr status ADR-0.0.71 --json`, then git-sync #2.
2. **Then begin OBPI-0.0.71-02-gz-obpi-repudiate-cli** via
   `/gz-obpi-pipeline OBPI-0.0.71-02` — the `gz obpi repudiate` CLI verb, parser,
   manpage, `gz cli audit` green, behave smoke test, and the AGENTS.md
   withdraw-vs-repudiate disambiguation. This is the user-facing abuse-surface
   verb; expect the heavy-lane behave smoke to be required here (no waiver).
3. **Consider** whether OBPI-02's brief should declare `sensitivity: security`
   given it adds the executable repudiation verb on the ledger-integrity surface.

## Pending Work / Open Loops

- ADR-0.0.71 closeout (Stage 5 of the parent ADR) remains pending both OBPIs.
- The security-scan canonical slot remains unfilled project-wide; every future
  `ledger_integrity`-surface OBPI will hit the same floor until
  `pool.agentic-security-review` promotes. Not this ADR's scope but worth tracking.
- GHI #608 (the forcing instance — fabricated Gate-5 on OBPI-0.0.70-02) is the
  use case this ADR repairs; it can be revisited once OBPI-02 lands the CLI verb.

## Verification Checklist

- [ ] `uv run -m unittest -q` passes (was green: 6092 tests at completion)
- [ ] `uv run -m unittest tests.test_completion_repudiation -v` — 13/13 pass
- [ ] Branch matches: `git branch --show-current` → `main`
- [ ] `uv run gz obpi reconcile OBPI-0.0.71-01-completion-repudiation-event` agrees
- [ ] No uncommitted changes conflict with handoff state

## Evidence / Artifacts

- `tests/test_completion_repudiation.py` — 13 unit tests (REQ-01..05 via @covers)
- `src/gzkit/events.py` — `ObpiCompletionRepudiatedEvent` model
- `src/gzkit/ledger_events.py` — `obpi_completion_repudiated_event` factory
- `src/gzkit/ledger.py` — `_apply_obpi_completion_repudiated_metadata` resolver
- `src/gzkit/schemas/ledger.json` — `obpi_completion_repudiated` schema entry
- `docs/design/adr/foundation/ADR-0.0.71-completion-repudiation/obpis/OBPI-0.0.71-01-completion-repudiation-event.md` — completed brief with evidence
- `data/behave_coverage_waivers.json` — behave waiver for OBPI-0.0.71-01

## Environment State

Python 3.13, uv-managed. macOS (darwin). No DB state relevant.
