---
mode: CREATE
adr_id: ADR-0.0.41
obpi_id: OBPI-0.0.41-03
branch: main
timestamp: "2026-06-11T23:24:27Z"
agent: claude-code
session_id: build-to-1.0-2026-06-11
---

# Handoff — Build-to-1.0 Campaign, Phase A, OBPI-0.0.41-03 complete

## Current State Summary

Build-to-1.0 campaign (`docs/governance/build-to-1.0-campaign-2026-06-10.md`), Phase A.
This session: (1) **A.4 + A.3 DONE and PUSHED** — ADR-0.0.69 reached lifecycle
**Validated** via the Phase-2 audit ceremony (operator "accept audit"); two independent
reviewers GREEN; campaign A.3/A.4 boxes checked. Commits 9249afeb + ef93d441 are on
origin/main. (2) **A.5 split authorized** (operator): build OBPI-03 -> 04, park OBPI-05.
(3) **OBPI-0.0.41-03 is attested_completed** (operator "attest completed", Jeffry Babb) —
release fail-closed (exit 3) + auditable reaping (abandoned_by_reaper handoff +
obpi_lock_released event). ADR-0.0.41 is now **3/5**. Committed locally as **bfe6519b**.

BLOCKER: **bfe6519b is NOT pushed.** `gz git-sync --apply` reports "failed to push some
refs" despite ahead=1 / behind=0 (clean fast-forward); direct `git push origin main` is
auto-mode policy-gated (needs explicit operator authorization). The OBPI-03 work is
durable locally but absent from origin.

## Important Context

- OBPI-03 flipped `gz obpi lock release` to fail-closed: releasing without --abandon or a
  matching register entry now exits 3. Consequence: **the OBPI-03 work lock is still HELD**
  because its own new rule blocks a plain release. This handoff is scoped `obpi_id:
  OBPI-0.0.41-03-...` precisely so it is the register entry that `find_handoff_for_release`
  matches — `gz obpi lock release OBPI-0.0.41-03-release-fail-closed-and-reaping` should now
  succeed. (The auto-handoff-on-release flow is OBPI-05, which is being parked.)
- The 2026-06-07 OBPI-0.0.41 briefs drifted from the brief-reconcile gate; 03/04/05 were
  reshaped to the `REQUIREMENT:`-per-acceptance-criterion convention + discovery line-ref
  fixes (04 dropped refs to the ADR-0.0.69-deleted closeout_proof_binding.py). All four now
  reconcile clean. These reshapes are in bfe6519b.
- reap_expired_locks ledger param is a structural `_LedgerSink` Protocol (LedgerEvent under
  TYPE_CHECKING); gzkit.ledger is force-loaded in the lazy import to settle the
  ledger/ledger_events load-order cycle (else isolated-test runs — the REQ-coverage gate —
  fail). Do not "simplify" this back to a direct import.
- ultraplan-brief.md is mid-move (root deletion + untracked docs/governance/ copy) from a
  PRIOR session; operator was asked (revert / complete / leave) and has NOT answered. Kept
  OUT of every commit this session. Still unresolved.

## Decisions Made

- A.5 = SPLIT: build OBPI-03 (done) + OBPI-04 (lock-handoff-coupling validator), PARK
  OBPI-05. Rationale: the ADR's own Boundary Invariant 1 binds OBPI-02/03/04 (not 05), so
  parking 03/04 would leave the foundation invariant unsatisfiable; OBPI-05 IS the
  session_orientation.py + handoff-skill surface Phase C.2/C.4 rebuilds (~4 of 6 REQs
  redone by C), and the lock-safety engine is OBPI-03 not 05 — parking 05 loses no safety.
- OBPI-03 BDD deferred to ADR-0.0.41 closeout (waiver added): OBPI-03 SUPERSEDES the
  existing @REQ-0.0.41-02-07 staging scenario in features/obpi_lock.feature (which asserts
  the now-removed warn-and-succeed behavior); the integrated lock-feature scenarios land
  with OBPI-04's validator at ADR closeout.
- Security-floor accepted (GHI #462) on OBPI-03 completion: lock_manager.py is a registered
  security surface but the scanner slot is structurally unfilled project-wide; the change
  is defensive/additive.

## Immediate Next Steps

1. **PUSH bfe6519b to origin/main** — diagnose the `gz git-sync` push failure (pre-push
   gate? auth? remote state) and get the OBPI-03 commit onto origin. The work is local-only
   until this lands. Operator authorization required for any push to main.
2. **Release the OBPI-0.0.41-03 lock**: `uv run gz obpi lock release
   OBPI-0.0.41-03-release-fail-closed-and-reaping` (this handoff is the register entry it
   needs).
3. **Build OBPI-0.0.41-04** (lock-handoff-coupling validator) via gz-obpi-pipeline: plan
   already reshaped + reconciles clean; implements validate_lock_handoff_coupling (currently
   a return [] stub at src/gzkit/governance/trust_audits/lock_handoff_coupling.py), registers
   --lock-handoff-coupling, wires into _build_check_steps(). STOP-on-BLOCKERS satisfied (03
   landed).
4. **Park OBPI-0.0.41-05** with operator-attested reason citing C.4 absorption (ADR-0.0.65
   precedent) — see the A.5 assessment in this session.
5. **ADR-0.0.41 closeout -> Validated**: write the integrated lock-feature BDD scenarios
   (reconciling @REQ-02-07 to fail-closed) + run the Phase-2 audit ceremony.

## Pending Work / Open Loops

- bfe6519b unpushed (blocker #1 above).
- OBPI-03 lock held (step 2 above).
- OBPI-04 build, OBPI-05 park, ADR-0.0.41 closeout (steps 3-5).
- ultraplan-brief.md move unresolved — operator decision pending (revert/complete/leave).
- F1-class reviewer findings on OBPI-03 were FIXED; F2 (gz obpi lock list reaps globally,
  CQS smell) noted as pre-existing reap-on-list design, not addressed (non-blocking).
- After ADR-0.0.41 terminal: Phase A exit gate met -> Phase B (CMS completion) opens.

## Verification Checklist

```bash
uv run gz adr report ADR-0.0.41        # expect 3/5, OBPI-03 attested_completed
git log --oneline -1                    # expect bfe6519b (OBPI-03) HEAD
git status -sb                          # expect ahead 1 (bfe6519b unpushed) + ultraplan move
uv run gz obpi lock list --json         # OBPI-03 lock still held until step 2
uv run -m unittest -q                   # full suite green (6033)
```

## Evidence / Artifacts

- `docs/design/adr/foundation/ADR-0.0.41-token-block-lock-discipline/obpis/OBPI-0.0.41-03-release-fail-closed-and-reaping.md`
- `src/gzkit/lock_manager.py`
- `src/gzkit/commands/obpi_lock.py`
- `docs/design/adr/foundation/ADR-0.0.69-channels-first-closeout-proof/audit/AUDIT.md`
- `docs/governance/build-to-1.0-campaign-2026-06-10.md`
- `data/behave_coverage_waivers.json`
