Skip to content

bp-137 — AP4: 'low stakes' refuses on ABSENCE exactly as it refuses on violation - #2

Open
ascalva wants to merge 3 commits into
mainfrom
worktree-agent-a25e8e55678c3749c
Open

bp-137 — AP4: 'low stakes' refuses on ABSENCE exactly as it refuses on violation#2
ascalva wants to merge 3 commits into
mainfrom
worktree-agent-a25e8e55678c3749c

Conversation

@ascalva

@ascalva ascalva commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Merge train — position 2, behind #1

Do not merge before #1. That branch owns finding-02710273; this one was renumbered to 0274 to clear a live collision (see below). When #1 is staged, this branch rebases onto it and re-runs its green gate before it may land.

What this builds

bp-137 (AP4), against ratified dn-autopilot-and-delegated-blessing. A conjunctive structural predicate where a missing input is not a pass.

scripts/autopilot_eligibility.py (599 L) · tests/unit/test_autopilot_eligibility.py (796 L, 109 passed in 0.33s)

⚑ The core property — absence refuses, and it is structural

Not a guard clause: conjoin takes a keyed mapping requiring {P1..P5}, so all() has no empty overload to be vacuously true over. All 243 combinations enumerated — exactly one PASS, and no UNDETERMINED-containing combination passes.

absence the vacuous reading it refuses verdict
empty/absent write_scope "every glob is inside the worktree" P1, P2 UNDETERMINED
glued # entry (finding-0085) intersection empty on a scope naming eval/ P2 FAIL
zero ### Item headings "every item carries the flag as no" P3 UNDETERMINED
§7 absent/item-less "no acceptance step runs deploy" P4 UNDETERMINED
incomplete term set all(...) over empty conjoin FAIL

This is finding-0249's lesson — a check that passes without testing its claim — built into the type rather than bolted on.

Mutation campaign

12 mutants planted, 12 killed, 0 survivors — including all(t is not FAIL), fence-skipping, empty-scope→PASS, startswith("no"), dropped truncation, and a forbidden-set omitting .claude/hooks/**. Source diff-verified restored.

Census over 137 real plans

13 pass / 124 fail. P1 137/0/0 · P2 100/37/0 · P3 32/80/25 · P4 104/27/6 · P5 137/0/0. Not a constant function; no term is constant-UNDETERMINED. bp-120 passes all five.

Falsifiers

  • Item 14 (matchers disagree) — did not fire; 5 real scopes × 11 probes, identical.
  • Item 15fires partially: 9 plans fold the flag onto another bullet, causing 5/25 UNDETERMINED. Below §10's "dominated by" threshold (20%), and ⚑ safe by construction — a folded flag yields UNDETERMINED ⇒ FAIL, never a false PASS. The pinned §6 regex was not widened. Filed as finding-0274.
  • Item 16 — fires as predicted; 27/137 P4 FAIL. ⚑ The clearest false fire is bp-137 itself (its §7 enumerates the deny-list). Not disqualifying, so recorded in the tool's docstring and report output rather than tuned away.
  • Item 17 — did not fire.

Green gate — five legs, run separately

ruff All checks passed · scoped mypy no issues, 263 files · argless mypy 69 errors — baseline asserted · type_gate exit 0 · pytest 4 failed / 2511 passed.

⚑ Those 4 are pre-existing and the cause is documented: 3 pass under env -u OUROBOROS_HOOKS_OFF — tonight's hook disabling makes scope-guard return ALLOW, so the enforcement tests correctly redden. See finding-0275 on main, which records that as an accepted, dated condition clearing at bp-149. The 4th is worktree-nesting.

⚑ The id collision this PR also fixes

bp-136 and this plan ran in parallel and both minted a finding-0271 — two different findings, same number. Nothing in the tree allocates ids. Renumbered here to 0274.

That is precisely the race bp-140 exists to remove, demonstrating itself on the night the design note was ratified. We were lucky the paths collided and git would have conflicted loudly; the silent case is worse.

Reviewer notes

Cost: 160k by harness accounting against a 200k estimate. (Self-reported ~145k — per the delegate skill, self-reports aren't evidence.)

Scope: diff is exactly write_scope + journal + the one finding. plan.md untouched, no status flip. Verified by the orchestrator — with no hook enforcing it.

Nothing left undone.

ascalva and others added 3 commits July 27, 2026 19:39
dn-autopilot-and-delegated-blessing §2.4 defines low-stakes work structurally
and §2.8 makes those five predicates *the* reversibility guarantee. This
computes them, and refuses on ABSENCE exactly as it refuses on VIOLATION.

Two-valued conjunction is where the vacuous pass lives: "every glob resolves
inside the worktree" is true over an empty write_scope, and "every item carries
the flag as no" is true over a plan with no items. So a term the input did not
answer returns UNDETERMINED, and UNDETERMINED is absorbing (invariant 7).
`conjoin` takes a keyed mapping and requires the complete {P1..P5} key set, so
`all(...)` has no empty-sequence overload to be vacuously true on; a test
enumerates all 3**5 = 243 combinations and asserts exactly one passes.

P3 carries the finding-0263 correction: §2.4 names a machine-readable per-item
field that does not exist, so a P3 built to the note's text passes on every plan
in the repository. Implemented instead as a pinned regex over the §7 item body
whose value must normalize to exactly `no`; bp-137 §6 is authoritative until a
superseding note says otherwise. The banner is sliced out of __doc__ rather than
duplicated, and `report` emits it so the caveat reaches the owner's phone, not
just a builder reading the source. P4's lexical blind spot and P5's uncheckable
runtime half are named in the same output.

Glob math is _lib.matches_any — the matcher scope-guard itself runs, asserted by
identity and by an AST test that no local glob function exists. Two matchers that
disagree would bless a scope the guard reads differently.

Mutation campaign: 12 mutants, 12 killed, 0 survivors — including the
load-bearing `all(t is not Result.FAIL)`, dropping the fence scan, and returning
PASS on an empty scope.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTYQT2QsWskJW4HmgobyrV
… spot, measured

Item 15's falsifier fires partially: 9 plans fold `**Touches stored data?**`
onto another field's bullet, which §6's bullet-anchored regex misses, and 5 of
the 25 plans P3 calls UNDETERMINED are undetermined for that reason. Not §10's
"dominated by" threshold (20%), and the folded form is not the template's shape,
so the build continued against §6 as pinned rather than widening the parse on a
builder's authority.

The miss is safe by construction and the finding says so: a folded flag leaves
its item with no anchored line, so the item is UNDETERMINED and the plan FAILs.
It can never produce a false PASS, not even on a folded `Yes`.

Journal records the 243-combination proof, the 12/12 mutation campaign, the
137-plan census (13 pass all five — not a constant function), all four
falsifier verdicts, and the evidence that the 4 remaining suite failures are the
owner's OUROBOROS_HOOKS_OFF escape hatch plus a worktree-nesting artifact.
…id collision

bp-136 and bp-137 ran in parallel worktrees and BOTH independently minted a
finding-0271 — two entirely different findings on the same number. Nothing in the
tree allocates ids; each agent eyeballed the highest existing (finding-0270) and
picked the next.

bp-136 keeps 0271-0273 (it filed three, sequentially); this one takes 0274.

Recorded because it is the exact defect bp-140 exists to remove, demonstrating
itself on the night dn-typed-workflow-registry was ratified. We were lucky: the
paths collided, so git would have conflicted loudly at merge. The silent case —
two agents choosing different paths — is the one that corrupts quietly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant