Skip to content

backtest replay re-runs recorded findings through the current pipeline and scores them against the operator's noise labels and the assay lanes - #56

Open
opencdlee-dotcom wants to merge 1 commit into
mainfrom
agent/precision-s0/main
Open

opencdlee-dotcom wants to merge 1 commit into
mainfrom
agent/precision-s0/main

Conversation

@opencdlee-dotcom

@opencdlee-dotcom opencdlee-dotcom commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Step S0 of the precision plan: the ground-truth harness every later step is scored against.

What

aegis.py backtest replay [--days N] [--reobserve] re-runs the recorded findings of the last N days (default 30) through the current pipeline in a throwaway :memory: store and scores the result against the incidents the operator closed as noise.

  • Read-only. The live store is opened mode=ro in one read transaction. _event_connection is never called because it creates, migrates and chmods. _custody_remember is a no-op for the run, and no seen, sigcache or findings ledger is written.

  • Same pipeline. Batches are grouped by observed_at, because no writer sets events.scan_id. Each batch goes through:

    • route_findings, using the live suppression memory with the learning period forced OFF and a replay-local seen ledger kept the way emit() keeps it
    • _record_finding_events, the scan's own record-and-fold, extracted from record_security_state
    • _apply_correlations: chains, lineage, risk and incidents

    Risk accumulation receives the live per-category dismissal weights.

  • Scored. The report shows:

    • interrupts per category and the cases left open
    • every FALSE_POSITIVE incident, whatever its resolution, whose evidence would open an interrupt again, listed by id with title and path (noise re-opened: N of M)
    • open cases with no noise-labelled evidence (new interrupts from corpus: K)
  • Recall. The findings built by the 21 assay lanes go through the same gate (assay recall: X/21). Predicate-only lanes and quarantine-roundtrip, which writes live state, are named in the output rather than skipped.

  • --reobserve asks classify_signature and _grade_binary again about every process, listener, beacon or outbound subject still on disk, and re-derives severity from that sensor's own gate. That makes classifier and custody-ladder fixes scoreable, not only routing fixes.

  • Rule 17. Loaded rows, batching, the noise set (compared with a direct join query), routes and assay rows are all checked against the store. A failed check prints at the top and exits 1.

The scan-tail closers are deliberately not run. They key on what a scan re-asserted, but the event log only holds what the live fold chose to record.

Supporting changes, with no change to scan behaviour:

  • record_security_state's record-and-fold loop moved into _record_finding_events. The fold query now selects the incident id instead of 1.
  • route_findings(seen=None) gained an optional ledger. When it is not given, the function reads SEEN as before.

Baseline (reference Mac, main 49e38b3 plus this PR, last 30 days)

62,604 findings in 2,347 scans; 213 noise-labelled incidents with evidence in the window.

run noise re-opened new interrupts from corpus assay recall
plain 170 of 213 12 9/21 (11 predicate-only, 1 not run)
--reobserve 135 of 213 12 9/21

--reobserve re-observed 7,158 findings. For 422 of them the trust verdict changed; the largest group is 305 listener findings on Spotify that moved from unsigned to developer-id. For 2,091 the custody rung changed (actions-runner Listener → operator-vouched), and 117 would no longer be emitted.

Verification

  • python3 -m pytest tests/test_backtest_replay.py -q: 11 passed. The learning-OFF and no-custody-write tests were mutation-checked; each fails once its override is removed.
  • Full suite: python3 -m pytest tests/ -q -x passed on this Mac with 2082 passed, 6 skipped and 30 xfailed in 15m07s. After that run, the test file alone gained one platform-neutral stub (_exec_alert held open in the custody-write test) and passes 11/11 natively and under SIM_BODY=win|linux|mac.
  • On the live store, the sha256 of custody.jsonl, sigcache.json and seen.json was identical before and after the --reobserve run.

🤖 Generated with Claude Code

… code against the operator's own noise labels

Six false-alarm batches were each judged by the queue getting shorter,
which is also what broken detection looks like. The store already held
the answer key: every recorded finding, and every incident the operator
closed as noise. `aegis.py backtest replay [--days N] [--reobserve]`
re-runs the first through the CURRENT pipeline and scores it against the
second.

- Opens the live store read-only (mode=ro, one read transaction) and never
  calls _event_connection, which creates, migrates and chmods.
- Groups the recorded observation.finding events into scans by
  observed_at: no writer has ever set events.scan_id.
- Routes each batch with route_findings over the live suppression memory
  (learning period forced OFF) and a replay-local seen ledger kept the way
  emit() keeps it; records it through the scan's own fold; runs
  _apply_correlations (chains, lineage, risk, incidents) in a :memory:
  store. The live per-category dismissal weights ride in for risk
  accumulation; _custody_remember is a no-op for the run.
- Reports per-category interrupts, the open cases, every FALSE_POSITIVE
  incident (any resolution) whose evidence opens an interrupt again, by id
  with title and path ("noise re-opened: N of M"), and open cases with no
  noise-labelled evidence ("new interrupts from corpus: K").
- Runs the 21 assay lanes, captures the findings their detectors build and
  routes them through the same gate ("assay recall: X/21"). Predicate-only
  lanes and quarantine-roundtrip (writes live state) are named, not skipped.
- --reobserve re-asks classify_signature and _grade_binary about every
  process / listener / beacon / outbound subject still on disk and
  re-derives the severity from that sensor's own gate, so a classifier or
  ladder fix is scoreable.
- Rule 17: loaded rows, batching, the noise set (vs a direct join query),
  routes and assay rows are asserted against the store; a failure prints
  at the top and exits 1.

Deliberately not run: the scan-tail closers. They key on what a scan
re-asserted, and the event log holds only what the live fold recorded.

Two supporting changes, behaviour unchanged for the scan:
- record_security_state's record-and-fold loop is now
  _record_finding_events, shared with the replay. The fold query selects
  the incident id instead of 1 so the replay can attribute a folded
  finding to the case that absorbed it.
- route_findings takes an optional seen= ledger (default: SEEN, as before).

Baseline on the reference Mac (main 49e38b3 plus this change, last 30
days, 62,604 findings in 2,347 scans, 213 noise-labelled incidents):
  plain:       noise re-opened 170 of 213, new interrupts from corpus 12
  --reobserve: noise re-opened 135 of 213, new interrupts from corpus 12
               (7,158 re-observed; trust changed 422, custody 2,091)
  assay recall 9/21 interrupt (11 predicate-only, 1 not run)

Tests: tests/test_backtest_replay.py (11). The learning-OFF and
no-custody-write tests were mutation-checked: each fails with its
override removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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