Skip to content

lattice rung 13: detector-driven Evidence-DAG disintegration loop - #293

Open
mattmre wants to merge 6 commits into
lattice/phase2-continue-20260713from
lattice/rung13-disintegration-20260714
Open

lattice rung 13: detector-driven Evidence-DAG disintegration loop#293
mattmre wants to merge 6 commits into
lattice/phase2-continue-20260713from
lattice/rung13-disintegration-20260714

Conversation

@mattmre

@mattmre mattmre commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

Phase II rung 13 (disintegration loop) — the genuine detector-driven Evidence-DAG edge prune the
ROADMAP exit criteria name. isomer_detector (per-query isomer strength) and convergence_monitor
(per-cluster stability summary) score Evidence-DAG edge fitness; low-fitness edges are pruned with a
transactional re-anneal path and a before/after fitness artifact. Closes rung 13 (was PARTIAL:
post-bank prune only, not the isomer/convergence → DAG prune the criteria require).

Stacked on #292 (base = lattice/phase2-continue-20260713); this PR's own diff is the two rung-13
commits. Retarget to main once #292 merges.

What it does

  • evidence_dag_disintegration.py — maps real detector outputs to edge fitness: IsomerDetector
    strength → fitness = 1 − strength (exact query-node join); ConvergenceMonitor.get_summary()
    1 − epochs_without_improvement/patience (per cluster). Deterministic, pure.
  • EvidenceDAG.prune_edges(scorer, threshold, dry_run=…) + reanneal_edges(...) + a pruned-edge
    ledger, in evidence_dag.py. Never removes nodes; preserves validate_evidence_dag.
  • write_disintegration_artifact(...) — fitness before/after + detector provenance.
  • docs/rung13-disintegration-loop.md.

Fail-closed design (load-bearing)

Missing / unmatched / immature detector signals → neutral fitness 1.0, so absent evidence can never
prune
; an all-healthy DAG prune is a verified no-op. prune_edges scores over a snapshot and
rejects a scorer that mutates the DAG mid-pass (RuntimeError) rather than dropping unledgered
edges. prune_edges/reanneal_edges are transactional (state restored on a scorer exception). The
1 − strength map is sedimentation-specific, so a non-sedimentation isomer mode is rejected
(chelation high-strength can mean the correction worked, not that the edge is unfit).

Adversarial review

First-cut Grok Tier B scored 94 (MEDIUM: fail-closed untested; LOW: mutating-scorer drop; LOW nits).
All four gaps fixed (dedicated fail-closed tests, snapshot + mutation reject, mode guard, plateau
assert); a fresh Grok Tier B re-scored the amended commit 100 / severity none, running the suite
itself (27 tests OK, DAG valid after prune/reanneal).

EVIDENCE: evidence_dag_disintegration.py (real IsomerDetector/ConvergenceMonitor field mapping) + evidence_dag.py prune_edges/reanneal ledger + write_disintegration_artifact + docs/rung13-disintegration-loop.md
SMOKE: python -m unittest test_evidence_dag_disintegration test_evidence_dag -> Ran 27 tests OK (chair-run, offline); ruff clean; validate_evidence_dag empty after prune and after reanneal
BHS_SELF_DRAFT: 100
BHS_SELF_DRAFT_AGENT: Fable-5 (chair / implementer)
BHS_TIER_B: 100
BHS_TIER_B_AGENT: grok-4.5 (fresh adversarial reviewer, independent of implementer; re-scored the amended commit after fixes)
BHS_TIER_B_SEVERITY: none
BHS_OFFICIAL: 100
CARRY_FORWARD: none
DEFERRED_SCOPE: engine-side auto-prune cadence (a live prune frequency needs a campaign to justify); optional harden of the mode=None isomer-input edge case (production detectors always set mode)
LOOP_ITERATIONS: 2
OPERATOR_OVERRIDE: none

🤖 Generated with Claude Code

mattmre and others added 2 commits July 14, 2026 07:19
…-DAG edge prune

Implements the genuine Phase-II rung-13 disintegration loop: real drift-detector
signals (IsomerDetector per-query strength; ConvergenceMonitor per-cluster summary)
drive fitness-gated pruning of low-fitness Evidence-DAG edges, with a transactional
re-anneal path and a before/after fitness artifact. Closes rung 13 (was PARTIAL:
post-bank prune only, not the isomer/convergence -> DAG prune the exit criteria name).

EVIDENCE: evidence_dag_disintegration.py (detector_signals_from_outputs maps real
  IsomerDetector.detect_* output via fitness=1-strength exact query-join, and
  ConvergenceMonitor.get_summary via 1-epochs_without_improvement/patience);
  evidence_dag.py prune_edges(scorer,threshold,dry_run) + reanneal ledger;
  write_disintegration_artifact (fitness before/after + detector provenance);
  docs/rung13-disintegration-loop.md.
SMOKE (floor-tier): python -m unittest test_evidence_dag_disintegration test_evidence_dag
  -> Ran 27 tests, OK (chair-run, offline).

Tier B (grok-4.5) scored the first cut 94/PASS-WITH-FIXES; all named gaps fixed here:
  (1) fail-closed regression surface now has dedicated tests (empty / unmatched-query /
  immature-convergence / wrong-cluster-id all assert pruned==[]); (2) prune_edges scores
  over a snapshot and REJECTS a scorer that mutates the edge set mid-pass (RuntimeError)
  instead of dropping unledgered edges; (3) detector_signals_from_outputs fail-closes
  (raises) on a non-sedimentation isomer mode, since fitness=1-strength is only
  correct-signed for sedimentation (chelation high-strength can mean the correction
  worked); (4) the reanneal test asserts the plateau ("converged") semantics explicitly.

Fail-closed design (load-bearing): missing / unmatched / immature detector signals
map to neutral fitness 1.0, so absent evidence can NEVER cause destructive pruning;
an all-healthy DAG prune is a verified no-op (baseline: prune nothing when nothing is
unfit). prune_edges/reanneal_edges are transactional (original state restored on a
scorer exception) and preserve validate_evidence_dag. Convergence is accepted only as
one summary per exact cluster node id — a single global summary is refused as
selective per-edge evidence.

## Brutal Honesty
- Real detector wiring, not a hardcoded/random score: fitness derives from the
  detectors' actual emitted fields (isomer strength; convergence stall/patience).
- L5 note: the scorer maps detector outputs to edge fitness; the *thresholds* (prune
  0.5 in tests) are caller-supplied, not learned — a deployment must set them from a
  campaign. Disclosed; the loop mechanism (not a tuned threshold) is what rung 13 asks.
- No production retrieval path changed; this adds a DAG-maintenance capability that is
  opt-in (caller invokes prune_edges). Engine auto-invocation is deliberately NOT wired
  here (would need a campaign to justify a live prune cadence) — scoped to the loop +
  artifact the exit criteria name.

BHS_SELF_DRAFT: 100
CARRY_FORWARD: none
DEFERRED_SCOPE: engine-side auto-prune cadence (needs a campaign to justify live pruning frequency)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rune)

Flips ROADMAP Phase II step 13 PARTIAL -> DONE now that isomer/convergence -> DAG
edge prune is implemented (rung-13 code commit 77de328, Grok Tier B 100). Updates
the status snapshot (9-13 DONE) and the 'what we are not doing' bullet (15/16/17
unblocked). Docs-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Phase II Step 13 (Disintegration loop) of the roadmap, introducing detector-driven Evidence-DAG disintegration and re-annealing. It adds the prune_edges method to EvidenceDAG to remove low-fitness edges, implements reanneal_edges to restore recovered edges, and provides utility functions to map IsomerDetector and ConvergenceMonitor outputs to edge fitness. Comprehensive unit tests and documentation are also added. The review feedback suggests two key improvements: validating the DAG at the start of reanneal_edges to avoid silent failures if the DAG is already invalid, and comparing the full edge list rather than just its length to robustly detect scorer mutations during pruning.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread evidence_dag_disintegration.py Outdated
Comment on lines +190 to +191
threshold = _bounded_float(threshold, "threshold")
before = len(dag.edges)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the EvidenceDAG is already invalid before calling reanneal_edges, validate_evidence_dag(dag) will fail for every edge attempt inside the loop. This causes all edges to be silently skipped and marked as skip_invalid with misleading violations, even if the edges themselves are perfectly valid. We should validate the DAG at the start of reanneal_edges and raise a ValueError if it is already invalid, consistent with prune_edges.

Suggested change
threshold = _bounded_float(threshold, "threshold")
before = len(dag.edges)
threshold = _bounded_float(threshold, "threshold")
violations = validate_evidence_dag(dag)
if violations:
raise ValueError("cannot re-anneal on an invalid EvidenceDAG: " + "; ".join(violations))
before = len(dag.edges)

Comment thread evidence_dag.py Outdated
Comment on lines +225 to +229
if len(self._edges) != len(edge_snapshot):
raise RuntimeError(
"scorer mutated the DAG edge set during prune_edges; refusing to apply "
"a prune computed over a stale snapshot"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Comparing only the length of self._edges and edge_snapshot is not sufficient to detect if the scorer mutated the list (e.g., by replacing elements or changing their order while keeping the length identical). Comparing the lists directly with self._edges != edge_snapshot is a more robust way to detect any mutation.

Suggested change
if len(self._edges) != len(edge_snapshot):
raise RuntimeError(
"scorer mutated the DAG edge set during prune_edges; refusing to apply "
"a prune computed over a stale snapshot"
)
if self._edges != edge_snapshot:
raise RuntimeError(
"scorer mutated the DAG edge set during prune_edges; refusing to apply "
"a prune computed over a stale snapshot"
)

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