Repository navigation
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
Conversation
… 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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=roin one read transaction._event_connectionis never called because it creates, migrates and chmods._custody_rememberis 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 setsevents.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 wayemit()keeps it_record_finding_events, the scan's own record-and-fold, extracted fromrecord_security_state_apply_correlations: chains, lineage, risk and incidentsRisk accumulation receives the live per-category dismissal weights.
Scored. The report shows:
FALSE_POSITIVEincident, whatever its resolution, whose evidence would open an interrupt again, listed by id with title and path (noise re-opened: N of M)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 andquarantine-roundtrip, which writes live state, are named in the output rather than skipped.--reobserveasksclassify_signatureand_grade_binaryagain 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 of1.route_findings(seen=None)gained an optional ledger. When it is not given, the function readsSEENas 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.
--reobserve--reobservere-observed 7,158 findings. For 422 of them the trust verdict changed; the largest group is 305 listener findings on Spotify that moved fromunsignedtodeveloper-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.python3 -m pytest tests/ -q -xpassed 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_alertheld open in the custody-write test) and passes 11/11 natively and underSIM_BODY=win|linux|mac.custody.jsonl,sigcache.jsonandseen.jsonwas identical before and after the--reobserverun.🤖 Generated with Claude Code