Skip to content

fix(verify): stop re-compaction poison from fail-closing the verification gate - #73

Merged
alpertarhan merged 1 commit into
mainfrom
fix/issue-72-recompaction-gate
Sep 23, 2026
Merged

alpertarhan merged 1 commit into
mainfrom
fix/issue-72-recompaction-gate

Conversation

@alpertarhan

Copy link
Copy Markdown
Owner

Fixes #72

Root cause (confirmed in code)

Three poison classes fed the verification gate stale/self-referential "constraints":

  1. Own error prose — the operator pastes a VerificationGateError back into the session; the next run mines "do not bypass verification" as a prohibition. Retrying adds evidence the next retry is checked against.
  2. [x] completion records — the prior summary's Done items are records, not rules.
  3. Superseded rules — "Do not push/open PR yet…" released later by the user; the factually correct new summary contradicts the stale rule → semantic-contradiction = −20, gaps.length > 0 → 80/100 → permanent fail-closed (inconsistency gaps are not deterministically patchable).

Fix — three layers

Layer Change
Extraction isNonLiveConstraintText filters own gate/notify prose, [x] items, and compaction status lines from constraint mining + state sanitization
Retirement retireSupersededConstraints marks a constraint superseded when a later user message releases it. Deferral rules ("do not push yet") accept a terse release ("ok push it now") via anchor polarity flip; standing rules ("never commit directly to main") keep the strict rich-contradiction check — a terse imperative sharing one verb cannot silently drop a live rule. The replacement is kept as critical context
Wiring Extract step computes overrides once (rc.factOverrides); post-synthesis and post-state gates consume them via VerificationEvidence.factOverrides; buildState persists them so applyContinuityOverrides drops the stale rule from the merged state and the continuity capsule cannot re-poison the next generation

Verified

  • Exact issue signature reproduced in a test: poisoned extraction + faithful new-state summary → inconsistency gap, ok: false. With retirement → 100/100, zero gaps.
  • 19 new regression tests (poison classes, retirement semantics, gate, persistence).
  • Full suite: 1008 pass / 0 fail; bun run typecheck (4 tsconfigs) and bun run build clean.

Notes for the reporter

  • The fail-closed posture is unchanged — only the extraction/gate inputs got smarter.
  • Stale compact-extraction-<session>.json caches replay old constraints, but the gate-side isNonLiveConstraintText + retirement filters apply to cache-derived constraints too, so an in-place upgrade self-heals without clearing caches.

…tion gate (#72)

The deterministic extraction re-mined the prior compaction's embedded
summary text and this extension's own error prose as live constraints.
One stale constraint contradicting the factually correct new state cost
the full 20 points, and inconsistency gaps are not deterministically
patchable — so a second compaction cycle could never pass the gate.

Three layers, mirroring the issue's poison classes:

- Extraction: isNonLiveConstraintText filters own gate/notify prose,
  [x] completion records, and compaction status lines out of constraint
  mining and state sanitization.
- Retirement: retireSupersededConstraints marks a constraint superseded
  when a later user message releases it. Deferral rules ("do not push
  yet") accept a terse release via anchor polarity flip; standing rules
  ("never commit directly to main") still require the full rich
  contradiction check, so a terse imperative sharing one verb cannot
  silently drop a live rule. The replacement is kept as critical
  context, not as a rule.
- Wiring: the extract step computes the overrides once; both the
  post-synthesis and post-state gates consume them via
  VerificationEvidence.factOverrides, and buildState persists them so
  applyContinuityOverrides drops the stale rule from the merged state
  and the continuity capsule cannot re-poison the next generation.

19 regression tests cover the poison classes, retirement semantics
(terse/verbose release, standing-rule conservatism, restatement,
index guard, upsert), the exact gate signature from the issue, and
persistence through buildState.
@alpertarhan
alpertarhan merged commit 1d5f3d8 into main Sep 23, 2026
2 checks passed
@alpertarhan
alpertarhan deleted the fix/issue-72-recompaction-gate branch September 23, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant