#000012 Phase 1c follow-through: wire #000037 §12 Trigger 1 probe to fork_score_branches

trigger_1_branch_density in bench/prometheus_sigma_trigger_probe.py read
the fork_score_branches table via branch_set_density() instead of the
"density check not yet implemented" stub. It groups rows by branch_set_id,
fires when the most-recently-recorded checkpoint carries >= 4 branches
(BRANCH_DENSITY_FLOOR), and surfaces n_checkpoints / latest_density /
max_density / n_checkpoints_clearing_floor in the markdown report so
section 12's "regularly" qualifier stays visible. Density sums across
shards per branch_set_id.

With no branch sets persisted yet the probe reports "table present but
empty across shards" (data_available True, fires False) rather than a
false negative. Re-ran the probe against the live shards:
bench/results/prometheus-sigma-triggers-2026-05-11.md.

6 new tests in tests/test_prometheus_trigger_probe.py (probe loaded via
importlib): no-table to no-data, empty-table to data-available-no-fire,
latest-checkpoint->=4 to fires, earlier-dense-but-latest-sparse to no-fire,
density-sums-across-shards, report-renders-density-lines.

Updated #000012 Phase 1c landing receipt, #000037 section 12 Trigger 1
note, and the TICKETS.md index rows for both. Pure measurement: no
mutation, no LLM call, no schema change.
This commit is contained in:
russell@unturf.com 2026-05-11 06:56:09 -04:00
parent da62f8047c
commit dbe824944a
No known key found for this signature in database
6 changed files with 388 additions and 42 deletions

View file

@ -3,15 +3,16 @@
Phase 1 of #000037 (the recursive falsification controller) gates on Phase 1 of #000037 (the recursive falsification controller) gates on
one of four §12 triggers firing. Triggers 1-3 are measurable from one of four §12 triggers firing. Triggers 1-3 are measurable from
already-committed state; trigger 4 is operator decision. This script already-committed state; trigger 4 is operator decision. This script
walks every shard's ``audit_events`` and ``capital_ledger`` tables, walks every shard's ``audit_events``, ``capital_ledger``, and
computes the §12 quantities, and emits a markdown report. ``fork_score_branches`` (#000012 Phase 1c) tables, computes the §12
quantities, and emits a markdown report.
Pure measurement. No mutation. No LLM call. No schema change. The Pure measurement. No mutation. No LLM call. No schema change. The
report is the deliverable; fox uses it to decide go/no-go on Phase 1. report is the deliverable; fox uses it to decide go/no-go on Phase 1.
The probe is defensive about data-availability: it explicitly reports The probe is defensive about data-availability: it explicitly reports
"no data" when a trigger structurally cannot fire yet (e.g. trigger 1 "no data" when a trigger structurally cannot fire yet (e.g. trigger 1
on a single-validator deployment with no fork-score cache table) when no branch sets have been persisted to ``fork_score_branches``)
rather than synthesising a false signal. rather than synthesising a false signal.
""" """
@ -31,6 +32,7 @@ DIVERGENCE_VARIANCE_RATIO_FLOOR = 0.5
DIVERGENCE_ABS_STDDEV_FLOOR = 0.10 DIVERGENCE_ABS_STDDEV_FLOOR = 0.10
WITNESS_COST_SHARE_FLOOR = 0.30 WITNESS_COST_SHARE_FLOOR = 0.30
DIVERGENCE_EPSILON = 1e-6 # max(mean, ε) guard against div-by-zero DIVERGENCE_EPSILON = 1e-6 # max(mean, ε) guard against div-by-zero
BRANCH_DENSITY_FLOOR = 4 # §12 trigger 1: ≥4 candidate branches per checkpoint
def _read_witness_events(shards: list[Path]) -> list[dict]: def _read_witness_events(shards: list[Path]) -> list[dict]:
@ -91,45 +93,110 @@ def _read_capital_ledger(shards: list[Path]) -> list[dict]:
return rows return rows
def _has_fork_score_table(shards: list[Path]) -> bool:
for sp in shards:
try:
conn = sqlite3.connect(sp)
row = conn.execute(
"SELECT name FROM sqlite_master "
"WHERE type='table' AND name LIKE '%fork_score%' LIMIT 1"
).fetchone()
conn.close()
if row:
return True
except sqlite3.OperationalError:
continue
return False
# -------------------------------------------------------------- triggers # -------------------------------------------------------------- triggers
def trigger_1_branch_density(shards: list[Path]) -> dict: def trigger_1_branch_density(shards: list[Path]) -> dict:
"""Trigger 1 — branch density: ≥4 candidate branches per checkpoint. """Trigger 1 — branch density: ≥4 candidate branches per checkpoint.
Requires multi-branch ForkScore (#000012) to be persisting candidate Reads the ``fork_score_branches`` sibling table (#000012 Phase 1c)
sets. Phase 1a (closed 2026-05-08) is single-validator, so no via :func:`arborist.substrate.fork_score.branch_set_density`. Each
branch-set table exists; the trigger structurally cannot fire yet. distinct ``branch_set_id`` is a checkpoint; the trigger fires when
the most-recently-recorded checkpoint carries 4 distinct branches.
The report also surfaces how many of *all* recorded checkpoints
clear the floor so §12's "regularly" qualifier stays visible.
Density is summed across shards per ``branch_set_id`` (each
``arborist substrate score --persist-shard`` invocation writes one
shard; a checkpoint normally lives in exactly one). When the table
is absent across every shard the common case, since ForkScore
Phase 1a is single-validator and ``arborist substrate score`` only
persists branch sets when ``--branch-set`` is passed the trigger
reports "no data" rather than synthesising a false signal.
""" """
has_table = _has_fork_score_table(shards) from arborist.substrate.fork_score import branch_set_density
density: dict[str, int] = {}
last_ts: dict[str, int] = {}
table_present = False
for sp in shards:
try:
conn = sqlite3.connect(sp)
except sqlite3.OperationalError:
continue
try:
checkpoints = conn.execute(
"SELECT branch_set_id, MAX(recorded_at) "
"FROM fork_score_branches GROUP BY branch_set_id"
).fetchall()
except sqlite3.OperationalError:
# Pre-#000012-Phase-1c shard, or one that has never had a
# branch set persisted. Not a probe-failure mode.
conn.close()
continue
table_present = True
for sid, ts in checkpoints:
density[sid] = density.get(sid, 0) + branch_set_density(conn, sid)
last_ts[sid] = max(last_ts.get(sid, 0), ts or 0)
conn.close()
if not table_present:
return {
"trigger": 1,
"name": "branch density (≥4 branches/checkpoint)",
"fires": False,
"reason": (
"no fork_score_branches table across shards; ForkScore is "
"single-validator (Phase 1a) and `arborist substrate score` "
"only persists branch sets when `--branch-set` is passed. "
"Multi-branch fork-score persistence is the prerequisite — "
"see #000012 Phase 1c."
),
"data_available": False,
"n_checkpoints": 0,
}
if not density:
return {
"trigger": 1,
"name": "branch density (≥4 branches/checkpoint)",
"fires": False,
"reason": (
"fork_score_branches table present but empty across shards; "
"no branch sets persisted yet"
),
"data_available": True,
"n_checkpoints": 0,
}
latest_sid = max(density, key=lambda s: last_ts[s])
latest_density = density[latest_sid]
max_density = max(density.values())
n_clear = sum(1 for d in density.values() if d >= BRANCH_DENSITY_FLOOR)
fires = latest_density >= BRANCH_DENSITY_FLOOR
if fires:
reason = (
f"latest checkpoint `{latest_sid}` carries {latest_density} "
f"branches ≥ {BRANCH_DENSITY_FLOOR}; "
f"{n_clear}/{len(density)} recorded checkpoints clear the floor"
)
else:
reason = (
f"latest checkpoint `{latest_sid}` carries {latest_density} "
f"branch(es) < {BRANCH_DENSITY_FLOOR}; "
f"{n_clear}/{len(density)} recorded checkpoints clear the floor "
f"(max density seen: {max_density})"
)
return { return {
"trigger": 1, "trigger": 1,
"name": "branch density (≥4 branches/checkpoint)", "name": "branch density (≥4 branches/checkpoint)",
"fires": False, "fires": fires,
"reason": ( "reason": reason,
"no fork_score branch-set table found across shards; " "data_available": True,
"ForkScore Phase 1a is single-validator. Multi-branch " "n_checkpoints": len(density),
"fork-score persistence is the prerequisite — see #000012." "latest_branch_set_id": latest_sid,
) "latest_density": latest_density,
if not has_table "max_density": max_density,
else "branch-set table found but density check not yet implemented", "n_checkpoints_clearing_floor": n_clear,
"data_available": has_table,
} }
@ -349,8 +416,9 @@ def render_markdown(
out.append("") out.append("")
out.append( out.append(
"Phase 1 of ticket #000037 gates on one §12 trigger firing. " "Phase 1 of ticket #000037 gates on one §12 trigger firing. "
"This probe walks `audit_events` + `capital_ledger` and reports " "This probe walks `fork_score_branches` + `audit_events` + "
"the empirical state of triggers 13. Trigger 4 is operator-stated." "`capital_ledger` and reports the empirical state of triggers "
"13. Trigger 4 is operator-stated."
) )
out.append("") out.append("")
out.append("## Verdict") out.append("## Verdict")
@ -381,6 +449,18 @@ def render_markdown(
out.append("") out.append("")
t1 = triggers[0] t1 = triggers[0]
out.append(f"- Data available: {t1['data_available']}") out.append(f"- Data available: {t1['data_available']}")
if t1.get("n_checkpoints"):
out.append(f"- Recorded checkpoints: {t1['n_checkpoints']}")
out.append(
f"- Latest checkpoint: `{t1['latest_branch_set_id']}` "
f"{t1['latest_density']} branches "
f"(floor {BRANCH_DENSITY_FLOOR})"
)
out.append(f"- Max density across checkpoints: {t1['max_density']}")
out.append(
f"- Checkpoints clearing the floor: "
f"{t1['n_checkpoints_clearing_floor']} / {t1['n_checkpoints']}"
)
out.append(f"- {t1['reason']}") out.append(f"- {t1['reason']}")
out.append("") out.append("")
out.append("## Trigger 2 — divergence variance") out.append("## Trigger 2 — divergence variance")

View file

@ -0,0 +1,59 @@
# Prometheus-Σ §12 trigger probe
**Date:** 2026-05-11T10:54:01Z
**Shards directory:** `/home/fox/.arborist/shards`
**Shards walked:** 7 (000.db, 001.db, 002.db, 003.db, crawl_appliedcombinatorics_org.db, qa.db, snapshots.db)
Phase 1 of ticket #000037 gates on one §12 trigger firing. This probe walks `fork_score_branches` + `audit_events` + `capital_ledger` and reports the empirical state of triggers 13. Trigger 4 is operator-stated.
## Verdict
| # | Trigger | Fires? | Reason |
|---|---------|--------|--------|
| 1 | branch density (≥4 branches/checkpoint) | no | fork_score_branches table present but empty across shards; no branch sets persisted yet |
| 2 | divergence variance | **YES** | ratio 0.575 > 0.5; abs σ 0.435 > 0.1 |
| 3 | witness cost share (material > 0.30) | no | witness material / total material = 0.008158 / 0.540638 = 0.015 |
| 4 | operator mission need | n/a | operator decision; not measurable from committed state |
**Phase 1 trigger has fired.** Prometheus-Σ Phase 1 may proceed.
## Trigger 1 — branch density
- Data available: True
- fork_score_branches table present but empty across shards; no branch sets persisted yet
## Trigger 2 — divergence variance
- Sample count (N): 37 (N_min = 30)
- Mean divergence rate: 0.7568
- Stddev: 0.435
- Ratio (σ/mean): 0.5748
- Threshold ratio: > 0.5 OR absolute σ > 0.1
- ratio 0.575 > 0.5; abs σ 0.435 > 0.1
Agreement-label distribution across all shards:
| label | count |
|-------|-------|
| `KERNEL-LLM-DIVERGED` | 22 |
| `KERNEL-LLM-AGREE` | 6 |
| `LLM-DIVERGED` | 6 |
| `STRICT-WITNESSED` | 3 |
## Trigger 3 — witness cost share
- Witness material (kWh proxy): 0.008158
- Total material: 0.540638
- Ratio: 0.0151 (threshold > 0.3)
- Witness financial: 5e-06
- Total financial: 5e-06
- Witness rows: 37
- Total ledger rows: 39
- witness material / total material = 0.008158 / 0.540638 = 0.015
**Caveat:** ledger reflects ad-hoc activity, not a controlled #000026 sweep — ratio is informational. Re-run after a #000026 baseline sweep for a workload-anchored answer.
## Trigger 4 — operator mission need
- Operator-stated; not measurable from committed state.
- Bypasses §12 measured-pressure gates per ticket §12.

View file

@ -100,7 +100,7 @@ Newest first. Update on every open/close.
| #000040 | Phase 5 resolver fix — phrase + content-token cascade (Hilbert terminology mismatch surfaced) | closed · cascade landed 2026-05-09; lift blocked by 1902-vs-modern vocab; follow-up #000042 | 2026-05-09 | — | | #000040 | Phase 5 resolver fix — phrase + content-token cascade (Hilbert terminology mismatch surfaced) | closed · cascade landed 2026-05-09; lift blocked by 1902-vs-modern vocab; follow-up #000042 | 2026-05-09 | — |
| #000039 | Optional `sqlite-vec` retrieval backend (A/B vs FTS5, hybrid not replacement) | open · awaiting go/no-go (doc-only Phase 0) | 2026-05-09 | — | | #000039 | Optional `sqlite-vec` retrieval backend (A/B vs FTS5, hybrid not replacement) | open · awaiting go/no-go (doc-only Phase 0) | 2026-05-09 | — |
| #000038 | Phase 4 content acquisition — proprietary textbook license decisions for warrant coverage | closed · obviated 2026-05-10 by alias-substitution sprint under #000031 (74 rows in #000041 + 13 rows in #000042); 92/92 records now resolve. Residue (multilingual PD, Hilbert-Ackermann OCR, Knuth permission, personal-copy path B) preserved as design log §8 | 2026-05-09 | — | | #000038 | Phase 4 content acquisition — proprietary textbook license decisions for warrant coverage | closed · obviated 2026-05-10 by alias-substitution sprint under #000031 (74 rows in #000041 + 13 rows in #000042); 92/92 records now resolve. Residue (multilingual PD, Hilbert-Ackermann OCR, Knuth permission, personal-copy path B) preserved as design log §8 | 2026-05-09 | — |
| #000037 | Prometheus-Σ recursive falsification controller (bicameral substrate) | in progress · Phases 0 + 1 + 1.b + 1.c + 2 landed 2026-05-10; **§12 Trigger 2 fired** (divergence variance 0.575 / N=37); §22 Findings 2 + 3 RESOLVED (kernel/llm cost split + sweep_weights §15.4 + per-mode τ_qa); `controller_events` carries 4 event kinds (decision · difficulty · budget_allocation · falsification_proposal) feeding `arborist controller-events` inspector + live-harvest third bucket in `bench/scripts/harvest_falsification_proposals.py`; Phase 3 sleep-sweep scheduler tracked under #000045 (gating ticket) | 2026-05-09 | — | | #000037 | Prometheus-Σ recursive falsification controller (bicameral substrate) | in progress · Phases 0 + 1 + 1.b + 1.c + 2 landed 2026-05-10; **§12 Trigger 2 fired** (divergence variance 0.575 / N=37); §22 Findings 2 + 3 RESOLVED (kernel/llm cost split + sweep_weights §15.4 + per-mode τ_qa); `controller_events` carries 4 event kinds (decision · difficulty · budget_allocation · falsification_proposal) feeding `arborist controller-events` inspector + live-harvest third bucket in `bench/scripts/harvest_falsification_proposals.py`; §12 Trigger 1 probe wired 2026-05-11 (`trigger_1_branch_density` reads `fork_score_branches` — measurable, not yet fired); Phase 3 sleep-sweep scheduler tracked under #000045 (gating ticket) | 2026-05-09 | — |
| #000036 | T3 per-window covert-channel budget bound | in progress · Phase 1 + dav1d review returned 2026-05-11; Tier-1 polish applied (wording → "CANNOT CERTIFY", structured `certification_status`/`b1_model` fields, bool/NaN/inf validation, `g=0` accepted, test cwd fix; 53 → 75 tests); **closure blockers: B1 conservative-envelope v2 calculator (awaits fox go/no-go) + active KAT fixture** | 2026-05-09 | — | | #000036 | T3 per-window covert-channel budget bound | in progress · Phase 1 + dav1d review returned 2026-05-11; Tier-1 polish applied (wording → "CANNOT CERTIFY", structured `certification_status`/`b1_model` fields, bool/NaN/inf validation, `g=0` accepted, test cwd fix; 53 → 75 tests); **closure blockers: B1 conservative-envelope v2 calculator (awaits fox go/no-go) + active KAT fixture** | 2026-05-09 | — |
| #000035 | PRG choice for φ_PRG (HMAC-SHA-512 expansion) | in progress · Phase 1 landed 2026-05-10; v7 §9.10 amendment awaits maintainer review | 2026-05-09 | — | | #000035 | PRG choice for φ_PRG (HMAC-SHA-512 expansion) | in progress · Phase 1 landed 2026-05-10; v7 §9.10 amendment awaits maintainer review | 2026-05-09 | — |
| #000034 | Hessian alignment under φ_linear | in progress · Phase 1a landed 2026-05-10 (synthetic-ablation probe + KAT fixture); Phase 1b parks for v7 ramp-up | 2026-05-09 | — | | #000034 | Hessian alignment under φ_linear | in progress · Phase 1a landed 2026-05-10 (synthetic-ablation probe + KAT fixture); Phase 1b parks for v7 ramp-up | 2026-05-09 | — |
@ -125,7 +125,7 @@ Newest first. Update on every open/close.
| #000015 | π* domain library + cross-domain composition | closed · landed 2026-05-07 | 2026-05-07 | — | | #000015 | π* domain library + cross-domain composition | closed · landed 2026-05-07 | 2026-05-07 | — |
| #000014 | SelfModel: schema, falsification, integration | closed · landed 2026-05-07 | 2026-05-07 | — | | #000014 | SelfModel: schema, falsification, integration | closed · landed 2026-05-07 | 2026-05-07 | — |
| #000013 | Spatial-temporal substrate (Merkle-AGI v7-W) | closed · landed 2026-05-09 (substrate paper + frontier catalog + namespace stub) | 2026-05-07 | — | | #000013 | Spatial-temporal substrate (Merkle-AGI v7-W) | closed · landed 2026-05-09 (substrate paper + frontier catalog + namespace stub) | 2026-05-07 | — |
| #000012 | Selection & consensus protocol (Merkle-AGI v8) | in progress · Phase 1a (ForkScore) landed 2026-05-08; Phase 1b (consensus paper, `docs/_source/merkle-agi-v8-consensus.rst` 834 lines) landed 2026-05-10; Phase 1c (branch-set persistence — `fork_score_branches` sibling table, `persist_branch_score` + `branch_set_density`, 6 new CLI flags on `arborist substrate score`, default-off) landed 2026-05-10 — feeds #000037 §12 Trigger 1 | 2026-05-07 | — | | #000012 | Selection & consensus protocol (Merkle-AGI v8) | in progress · Phase 1a (ForkScore) landed 2026-05-08; Phase 1b (consensus paper, `docs/_source/merkle-agi-v8-consensus.rst` 834 lines) landed 2026-05-10; Phase 1c (branch-set persistence — `fork_score_branches` sibling table, `persist_branch_score` + `branch_set_density`, 6 new CLI flags on `arborist substrate score`, default-off) landed 2026-05-10 — feeds #000037 §12 Trigger 1; Trigger 1 probe wired 2026-05-11 (`trigger_1_branch_density` reads `fork_score_branches` via `branch_set_density()` — measurable, not yet fired: no branch sets persisted) | 2026-05-07 | — |
| #000011 | SOFT_PREFLIGHT_HINT model-assisted sidecar | closed · landed 2026-05-04 (zero-shot full impl) | 2026-05-04 | D1 (preserves) | | #000011 | SOFT_PREFLIGHT_HINT model-assisted sidecar | closed · landed 2026-05-04 (zero-shot full impl) | 2026-05-04 | D1 (preserves) |
| #000010 | Meta-Cognition Preflight Guard (M0 / MCTL) | closed · landed 2026-05-03 (Phases 14); DAG binding shipped via #000009 | 2026-05-03 | D1, D3 | | #000010 | Meta-Cognition Preflight Guard (M0 / MCTL) | closed · landed 2026-05-03 (Phases 14); DAG binding shipped via #000009 | 2026-05-03 | D1, D3 |
| #000009 | Preflight run-DAG node binding (#000008+#000010) | closed · re-landed 2026-05-04 (§8 corrections: reject-path DAG, nested CTI clauses) | 2026-05-03 | D3, D4 | | #000009 | Preflight run-DAG node binding (#000008+#000010) | closed · re-landed 2026-05-04 (§8 corrections: reject-path DAG, nested CTI clauses) | 2026-05-03 | D3, D4 |

View file

@ -374,15 +374,33 @@ empirical surface. Implementation pinned below.
inputs (algorithm change, weight semantics, hard-regression inputs (algorithm change, weight semantics, hard-regression
policy). Persisted on every row so a reader can filter by policy). Persisted on every row so a reader can filter by
estimator generation. estimator generation.
- **Tests:** 5 new in `tests/test_fork_score.py` - **#000037 §12 Trigger 1 probe wired (2026-05-11):** original
migration-creates-table, persist-writes-one-row, upsert-on-pk, proposal step 4 — `bench/prometheus_sigma_trigger_probe.py`
branch_set_density-counts-by-set, breakdown_blob-round-trips-as- `trigger_1_branch_density` now reads `fork_score_branches` via
json. Test count 18 → 23. `branch_set_density()` instead of returning the
"density check not yet implemented" stub. It groups rows by
`branch_set_id`, fires when the most-recently-recorded checkpoint
carries ≥ 4 branches (`BRANCH_DENSITY_FLOOR`), and surfaces
`n_checkpoints` / `latest_density` / `max_density` /
`n_checkpoints_clearing_floor` in the markdown report so §12's
"regularly" qualifier stays visible. With zero branch sets
persisted yet, the probe correctly reports "table present but
empty across shards; no branch sets persisted yet" —
`data_available: True`, `fires: False` — not a false negative.
- **Tests:** 5 in `tests/test_fork_score.py` (migration-creates-
table, persist-writes-one-row, upsert-on-pk, branch_set_density-
counts-by-set, breakdown_blob-round-trips-as-json; suite 18 → 23)
+ 6 in `tests/test_prometheus_trigger_probe.py` (probe loaded via
`importlib`; no-table → no data, empty-table → data-available-no-
fire, latest-checkpoint-≥4 → fires, earlier-dense-but-latest-
sparse → no fire, density-sums-across-shards, report-renders-
density-lines).
- **Hard constraints honored:** sibling table never enters - **Hard constraints honored:** sibling table never enters
`audit_events.event_hash` preimage; no behavioral change to `audit_events.event_hash` preimage; no behavioral change to
single-validator scoring; default-off CLI; no mesh wire format single-validator scoring; default-off CLI; no mesh wire format
change; `weights_id` opaque (folding weights into a hash stays a change; `weights_id` opaque (folding weights into a hash stays a
Phase 1b/wire concern). Phase 1b/wire concern). The probe stays pure-measurement — no
mutation, no LLM call, no schema change.
The original Phase-1c proposal text is preserved below for design- The original Phase-1c proposal text is preserved below for design-
log continuity. Re-read it as the authoritative spec; the bullets log continuity. Re-read it as the authoritative spec; the bullets

View file

@ -725,7 +725,15 @@ quantities.
**Trigger 1 — branch density.** ForkScore (#000012 Phase 1a) **Trigger 1 — branch density.** ForkScore (#000012 Phase 1a)
regularly receives ≥ 4 candidate branches per checkpoint AND the regularly receives ≥ 4 candidate branches per checkpoint AND the
operator wants probability-weighted compute allocation across operator wants probability-weighted compute allocation across
them. them. *Probe wired 2026-05-11 (#000012 Phase 1c follow-through):*
`prometheus_sigma_trigger_probe.py:trigger_1_branch_density` now
reads the `fork_score_branches` table via `branch_set_density()`
it groups rows by `branch_set_id` and fires when the most-recently-
recorded checkpoint carries ≥ 4 branches. As of that date no branch
sets have been persisted (`arborist substrate score --branch-set`
has not been run on a production checkpoint), so the probe reports
"table present but empty" — `data_available: True`, `fires: False`.
The trigger is now measurable; it has not fired.
**Trigger 2 — divergence variance.** #000028 witness sweep **Trigger 2 — divergence variance.** #000028 witness sweep
observes divergence-rate variance large enough that fixed observes divergence-rate variance large enough that fixed

View file

@ -0,0 +1,181 @@
"""Probe-side tests for ``bench/prometheus_sigma_trigger_probe.py``
trigger 1 (branch density), wired to the #000012 Phase 1c
``fork_score_branches`` table.
Trigger 1 was a stub until #000012 Phase 1c landed the
``fork_score_branches`` sibling table and the ``branch_set_density``
helper. These tests pin the wired behaviour: no-table no data;
table-present-but-empty data available, does not fire; latest
checkpoint with 4 branches fires.
The probe lives outside the ``arborist`` package, so it is loaded via
``importlib`` (same pattern as ``tests/test_bench_qa_sweep.py``).
"""
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import pytest
from arborist.store import connect, invalidate_migration_cache, transaction
from arborist.substrate.fork_score import ScoredFork, persist_branch_score
@pytest.fixture(scope="module")
def probe():
path = (
Path(__file__).parent.parent
/ "bench"
/ "prometheus_sigma_trigger_probe.py"
)
spec = importlib.util.spec_from_file_location(
"prometheus_trigger_probe_under_test", path
)
mod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = mod
spec.loader.exec_module(mod)
return mod
def _scored(score: float = 0.5, verdict: str = "ACCEPT") -> ScoredFork:
return ScoredFork(
score=score, verdict=verdict, breakdown={"t": score}, flags=[], weights={}
)
def _make_shard(tmp_path: Path, name: str) -> Path:
"""Create a shard DB with the Phase 1c migration applied."""
db = tmp_path / name
invalidate_migration_cache(db)
conn = connect(db) # runs _migrate_fork_score_branches
conn.close()
invalidate_migration_cache(db)
return db
def _persist(db: Path, *, branch_set_id: str, branch_id: str, ts: int) -> None:
invalidate_migration_cache(db)
conn = connect(db)
try:
with transaction(conn):
persist_branch_score(
conn,
branch_set_id=branch_set_id,
branch_id=branch_id,
parent_root="parent-root",
child_root=f"child-{branch_id}",
scored=_scored(),
ts=ts,
)
finally:
conn.close()
invalidate_migration_cache(db)
def test_trigger1_no_table_reports_no_data(probe, tmp_path):
"""A shard with no fork_score_branches table → data unavailable,
does not fire, points at #000012 Phase 1c."""
import sqlite3
db = tmp_path / "bare.db"
sqlite3.connect(db).close() # empty DB, no migration
out = probe.trigger_1_branch_density([db])
assert out["trigger"] == 1
assert out["fires"] is False
assert out["data_available"] is False
assert out["n_checkpoints"] == 0
assert "#000012" in out["reason"]
def test_trigger1_table_empty_reports_data_available_no_fire(probe, tmp_path):
"""Table present (migration ran) but no branch sets persisted →
data available, does not fire."""
db = _make_shard(tmp_path, "empty.db")
out = probe.trigger_1_branch_density([db])
assert out["fires"] is False
assert out["data_available"] is True
assert out["n_checkpoints"] == 0
assert "empty" in out["reason"]
def test_trigger1_fires_when_latest_checkpoint_has_floor_branches(probe, tmp_path):
"""Latest checkpoint (by recorded_at) carries ≥4 branches → fires;
reason names the checkpoint and the floor count."""
db = _make_shard(tmp_path, "dense.db")
# Older checkpoint with only 1 branch — should NOT be the one the
# trigger reads.
_persist(db, branch_set_id="cp-old", branch_id="solo", ts=1_700_000_000)
# Newer checkpoint with 4 branches — this is the latest.
for i in range(4):
_persist(
db, branch_set_id="cp-new", branch_id=f"b{i}", ts=1_700_001_000 + i
)
out = probe.trigger_1_branch_density([db])
assert out["fires"] is True
assert out["data_available"] is True
assert out["n_checkpoints"] == 2
assert out["latest_branch_set_id"] == "cp-new"
assert out["latest_density"] == 4
assert out["max_density"] == 4
assert out["n_checkpoints_clearing_floor"] == 1
assert "cp-new" in out["reason"]
def test_trigger1_no_fire_when_latest_checkpoint_below_floor(probe, tmp_path):
"""An earlier checkpoint clearing the floor does NOT make the
trigger fire if the *latest* checkpoint is below it §12 reads
the most recent checkpoint."""
db = _make_shard(tmp_path, "mixed.db")
for i in range(5): # old, dense checkpoint
_persist(
db, branch_set_id="cp-dense", branch_id=f"d{i}", ts=1_700_000_000 + i
)
for i in range(2): # newest checkpoint, sparse
_persist(
db, branch_set_id="cp-sparse", branch_id=f"s{i}", ts=1_700_009_000 + i
)
out = probe.trigger_1_branch_density([db])
assert out["fires"] is False
assert out["data_available"] is True
assert out["latest_branch_set_id"] == "cp-sparse"
assert out["latest_density"] == 2
assert out["max_density"] == 5
assert out["n_checkpoints_clearing_floor"] == 1
assert "max density seen: 5" in out["reason"]
def test_trigger1_density_sums_across_shards(probe, tmp_path):
"""A checkpoint split across two shards sums to its full density."""
db_a = _make_shard(tmp_path, "a.db")
db_b = _make_shard(tmp_path, "b.db")
_persist(db_a, branch_set_id="cp-split", branch_id="b0", ts=1_700_000_000)
_persist(db_a, branch_set_id="cp-split", branch_id="b1", ts=1_700_000_001)
_persist(db_b, branch_set_id="cp-split", branch_id="b2", ts=1_700_000_002)
_persist(db_b, branch_set_id="cp-split", branch_id="b3", ts=1_700_000_003)
out = probe.trigger_1_branch_density([db_a, db_b])
assert out["n_checkpoints"] == 1
assert out["latest_density"] == 4
assert out["fires"] is True
def test_trigger1_renders_density_lines_in_report(probe, tmp_path):
"""render_markdown surfaces the density numbers when a checkpoint
exists."""
db = _make_shard(tmp_path, "render.db")
for i in range(4):
_persist(
db, branch_set_id="cp-r", branch_id=f"b{i}", ts=1_700_000_000 + i
)
triggers = [
probe.trigger_1_branch_density([db]),
probe.trigger_2_divergence_variance([]),
probe.trigger_3_witness_cost_share([]),
probe.trigger_4_operator_need(),
]
md = probe.render_markdown(tmp_path, [db], triggers, [], [])
assert "## Trigger 1 — branch density" in md
assert "Latest checkpoint: `cp-r`" in md
assert "Recorded checkpoints: 1" in md
assert "Checkpoints clearing the floor: 1 / 1" in md