---
mode: CREATE
adr_id: ADR-0.0.71
branch: main
timestamp: "2026-06-13T08:48:23Z"
agent: claude-code
obpi_id: OBPI-0.0.71-02-gz-obpi-repudiate-cli
session_id:
continues_from: .gzkit/handoffs/20260613T070047Z-OBPI-0.0.71-01-completed.md
last_lock_event_timestamp: "2026-06-13T08:18:47.662330+00:00"
last_commit_sha: 37433a8276dabf658ccbc887523e517f5347d9ce
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-13T08:48:23Z -->

## ⚠️ 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-02-gz-obpi-repudiate-cli is **attested_completed** (Gate-5 operator
attestation "attest completed", Jeffry Babb, 2026-06-13). The `gz obpi repudiate`
CLI verb is landed and merged into the working tree (not yet committed). All
quality gates passed: ruff clean, typecheck clean, full unittest suite (6097
tests) green, mkdocs --strict clean, `gz cli audit` 105/105, `gz validate
--documents` clean, behave smoke (5 scenarios) green.

The OBPI completion required two non-default Stage-5 decisions, both made in this
session:
1. A behave-coverage waiver for REQ-04/06/07 (dry-run ledger-count is unit-only;
   06 is structural-fence; 07 is support) registered in
   `data/behave_coverage_waivers.json`.
2. A `--accept-security-floor` override at `gz obpi complete` — `obpi_cmd.py` is a
   registered `auth_boundaries` security surface, the project has no security
   scanner configured yet (GHI #462), and the operator authorized the override
   (the verb is additive + structurally defensive).

The work is NOT yet git-synced. The pipeline is mid-Stage-5: completion succeeded,
lock release is pending this handoff (token-block coupling), and two git-sync
cycles remain.

## Important Context

- **`obpi_cmd.py` is a security surface** (`data/security_surfaces.json`,
  `auth_boundaries` category). Any future edit there re-triggers the security
  floor at completion until the `pool.agentic-security-review` toolchain ADR lands
  (GHI #462).
- **`repudiated_receipt` is auto-derived**, not a CLI flag — the command scans the
  ledger for the most recent `obpi_receipt_emitted` completion event and uses its
  `ts`. This is intentional (REQs don't require a flag; deterministic UX).
- **Brief allowlist was amended** via `gz brief reconcile --apply` (attestor Jeffry
  Babb) to add `src/gzkit/cli/main.py`. The coupled-surface edits (manpage index,
  runbooks, doc-coverage manifest, `_NO_SKILL_VERBS`, behave waivers) were
  mandatory for REQ-05 (cli audit green) and REQ-07 (manpage/index/command-doc
  parity).
- **governance-core.md bumped to rule v0.4.0** (withdraw-vs-repudiate
  disambiguation); sync propagated to all vendor mirrors + `AGENTS.md`.

## Decisions Made

- **Decision:** Auto-derive `repudiated_receipt` from the ledger rather than a CLI flag.
  **Rationale:** The brief's REQs never list it; the most-recent completion receipt
  is deterministic. Cleaner operator UX.
  **Alternatives rejected:** `--repudiated-receipt` flag (unnecessary operator typing).

- **Decision:** Place `obpi_repudiate_cmd` in `obpi_cmd.py` (not a new module).
  **Rationale:** The brief names `obpi_cmd.py`; co-located with `obpi_withdraw_cmd`.
  **Alternatives rejected:** Separate `obpi_repudiate_cmd.py` (violates brief allowlist).

- **Decision:** Behave-waive REQ-04/06/07; tag REQ-01/02/03/05 in scenarios.
  **Rationale:** REQ-04's no-write assertion needs a completed-OBPI ledger fixture
  (unit-tested with mocks); 06 is structural-fence; 07 is support — none is a
  behave-appropriate BEHAVIOR REQ.
  **Alternatives rejected:** Standing up a completed-OBPI behave fixture (integration
  belongs at ADR-0.0.71 closeout).

- **Decision:** Accept the security floor via `--accept-security-floor`.
  **Rationale:** Operator-authorized; the repudiate verb is purely additive and
  structurally defensive (operator-gated, fail-closed, ledger-witnessed) and handles
  no credentials/subprocess/crypto.
  **Alternatives rejected:** Declaring `sensitivity: security` and blocking until the
  scanner toolchain lands (would strand a defensive feature indefinitely).

## Immediate Next Steps

1. Release the OBPI lock: `uv run gz obpi lock release OBPI-0.0.71-02-gz-obpi-repudiate-cli`
   (this handoff is the register entry that unblocks the fail-closed release).
2. Remove the legacy pipeline marker `.claude/plans/.pipeline-active.json` (the
   per-OBPI marker was already removed).
3. Git-sync #1: `uv run gz git-sync --apply` (commits completion + governance edits).
4. Reconcile: `uv run gz obpi reconcile OBPI-0.0.71-02-gz-obpi-repudiate-cli` and
   refresh ADR view: `uv run gz adr status ADR-0.0.71 --json`.
5. Git-sync #2: `uv run gz git-sync --apply` (commits reconcile + ADR status refresh).

## Pending Work / Open Loops

- **ADR-0.0.71 closeout is now eligible** — both OBPIs (01 event model, 02 CLI verb)
  are attested_completed. The ADR closeout ceremony (`gz closeout ADR-0.0.71`,
  attest, audit, emit-receipt) is the next ADR-level work after this OBPI syncs.
- **Full `features/` behave sweep** is deferred to ADR closeout (cross-OBPI
  interactions) per pipeline Stage 3 scope discipline.
- **GHI #608** (the forcing instance: OBPI-0.0.70-02 fabricated Gate-5) can now be
  closed once `gz obpi repudiate` is used to repudiate that completion — a concrete
  destination for the GHI.

## Verification Checklist

- [ ] `uv run -m unittest -q` passes (6097 tests; verified green this session)
- [ ] Branch matches: `git branch --show-current` → `main`
- [ ] `uv run gz cli audit` → 105/105 covered
- [ ] `uv run gz obpi reconcile OBPI-0.0.71-02-gz-obpi-repudiate-cli` → coherent
- [ ] No uncommitted changes conflict with handoff state (tree is pre-sync)

## Evidence / Artifacts

- `src/gzkit/commands/obpi_cmd.py` — new `obpi_repudiate_cmd()` (lines ~96-167)
- `src/gzkit/cli/parser_artifacts.py` — `repudiate` subparser + `_LAZY_IMPORTS` entry
- `docs/user/manpages/obpi-repudiate.md` — per-verb manpage
- `features/obpi_repudiate.feature` — 5 behave scenarios
- `tests/test_obpi_repudiate_cli.py` — 5 unit tests (REQ-01..05 @covers)
- `.gzkit/rules/governance-core.md` — rule v0.4.0 withdraw-vs-repudiate disambiguation
- `data/behave_coverage_waivers.json` — REQ-04/06/07 waiver entry
- `docs/design/adr/foundation/ADR-0.0.71-completion-repudiation/obpis/OBPI-0.0.71-02-gz-obpi-repudiate-cli.md` — completed brief with req_atomic + evidence

## Environment State

Python 3.13, uv-managed. No new runtime dependencies. macOS (darwin). Working tree
on `main`, pre-sync; pipeline mid-Stage-5.
