RESEARCH_AUDIT_LOG.md — the pipeline's own measurement series
Append-only. One dated block per run of the Thales research audit routine
(ops/RESEARCH_AUDIT.md), carrying M1–M5 and the G1 residue count.
The series is the point, not any single block. Every measurement here is about the machinery that produces beliefs, and drift is invisible from inside a single run — a reviewer softening by 5% a month looks like a normal day every day. So the run appends even on a quiet month: a gauge with gaps is not a series, and a missing block is indistinguishable from a healthy one.
Recomputable by construction: every entry should name its source (a git range, a queue diff, a registry count) so the next reader can check it rather than trust it.
Baseline note — 2026-08-11 (seeded, no run yet)
Seeded when the procedure was written; the first real block lands on the routine's first run. For orientation, the state at seeding:
- pipeline age: panel live 2026-08-06, triage 2026-08-10, implementer never yet had an approved item to build;
- queue: 9 open, 0 approved, 0 built, 7 dismissed;
- trial registry: 412 rows (
results/research_registry.jsonl); - closed questions since the pipeline started: 0 via the pipeline — every closure so far predates it;
- known unmeasured: G1 residue (no prior fresh-context audit), G2 time-to-loud, G4 capture-gap census.
The honest read at seeding: the pipeline has produced findings but has not yet closed a question, and its most valuable output to date has been defects in its own scaffolding (the beacon transport, the runner-loss window, the capture-QA branch). That is a legitimate early phase, and M5 exists to notice if it becomes a permanent one.
2026-09-03 — run 1 (window: 2026-08-11 seeding → 2026-09-03)
Run context, recorded first: the scheduled 2026-09-01 first run completed its
measurements and died on the shared Fable quota before writing anything
(NORTHSTAR §7b; healthchecks alarmed correctly). This re-run is therefore the
series' first real block; the window is everything since the 2026-08-11
seeding. Environment: routine container, no broker keys, no data/raw, no
owner Mac; memory/ is absent from the checkout (relevant to M4 below).
Facts below come from the repo's git history and files unless a GitHub
source is named.
M1 — proposal-survival drift · source: git log over research/queue/ + the run commits' own diffs
Panel runs 1–17 (2026-08-06 → 2026-09-02). The frozen archive alone
under-reports — the run-6/7/8 narratives were deleted from it (incident
already recorded at research/RESEARCH_QUEUE.md:2003); counts were
recovered from each run commit's diff. Survival = items added to
queue/open/ ÷ candidates considered, over runs whose denominator was
recorded at all:
| period | runs | considered | survived review | added to open | rate |
|---|---|---|---|---|---|
| 08-06..08-12 | 1–5 | 10 | 4 | 4 | 0.40 |
| 08-13..08-19 | 6–10 | 6 | 1 | 1 | 0.17 |
| 08-20..08-21 | 11–12 | 4 | 3 | 3 | 0.75 |
| 08-24..09-02 | 13–17 | 11 | 8 | 7 | 0.64–0.73 |
Verdict: RISING at roughly constant volume — the softening signature this
measurement exists for. Two recorded mitigations before reading it as
reviewer rot: the reviewer is still visibly cutting (run 15 killed 2 of 4,
528793d; run 14's row survived only "with three required edits",
56825fb; run 16's rows were "adversarially narrowed", 86152c2), and the
high-survival fortnight coincides with a genuinely defect-rich delta (queue
migration 47e8e73, the displaced-cron regime, the phantom equity mark
29c6f23) — run 13 pre-empts the charge in its own text ("volume is
delta-justified, not quota-shaped"). One month cannot separate softening
from a rich delta. Next month's block recomputes this table; a second
rising month without a matching delta is the finding.
Metric-integrity finding: the "considered" denominator is NOT-RECORDED in 5 of 17 runs (1, 4, 6, 10, 17) and got worse post-migration — run 17's count exists nowhere in git (PR #131 names only the surviving row). The gauge is degrading at its source. → feedback item 2 below.
Cadence: 17 runs over 20 weekdays; the run numbering is contiguous, so
2026-08-25/26/27 are genuinely missed runs, not quiet days (quiet runs
6/7/9/10 all committed narrative anyway). The window matches the
displaced-cron regime (research/2026-08-31_displaced_cron_regime.md);
the panel runs on claude.ai infra, so the cause is not recoverable from git.
M2 — registration before computation (G5) · source: commit dates, hashes below
Population since seeding: 5 guard builds (queue/built/), 1 recorded
measurement (RWG-1 leg 2), 1 evaluator pinning (VRP forward-gate), and 0
thales evaluate runs (trial registry untouched since 2026-08-01,
4286d89).
- RWG-1 leg 2: registered
8359538(2026-08-20, panel run 11) + ridera3dfe8c(08-21 06:47) → measured9b2e268(08-21 15:20). Order correct. - 5 built items: proposal commits 2026-08-10..08-28 (
9fc741e,a3dfe8c,5972694,56825fb) all precede build commits 2026-08-26..09-02 (2072f4b,8c0f731,6321abb,100cf61). Order correct. - VRP forward-gate evaluator (
fc389d7, #136): pinned 2026-09-02, ~4 months before its ~Jan-2027 clock matures — the exam pinned before any student can see it, as §6 demands.
Inversions: 0.
M3 — kill-criterion honesty · source: git show of proposal vs built text, all 5 queue/built/ items
5/5 IDENTICAL wording from proposal to verdict — byte-for-byte through the
08-24 queue migration — and every criterion was actually evaluated, with
negative controls run and revert-reds shown (proposal/built hashes as in M2;
the one pre-build edit, STAMP-1 at a1b0bb6, is a dated insertions-only
triage annotation, +44 lines, criterion untouched).
Honesty-positive disclosures: AMG-4's built note says plainly its
pre-registered end-to-end probe PR was NOT run ("recorded as not done, not
as done"); all five record the route around queue/approved/.
One minor unflagged under-execution: STAMP-1's pre-registered negative
control says "replay the captured_at timestamps of the last 20 committed
capture days"; the shipped test replays 5 representative instants
(tests/test_utils/test_market_session_date.py) and the built note does not
flag the reduction. Not a criterion change — the 20-trading-day forward
shadow is separately pinned — but a control's sample size is part of the
registration, and shrinking it deserves a sentence.
Silent divergence: 0. Unflagged control under-execution: 1 (minor).
M4 — reject-ledger integrity · source: queue/open/ (12) vs queue/dismissed/ (10) + web/public/data/killlist.json (13) + RESEARCH.md kill headers
9 NONE / 3 SUPERFICIAL / 0 RESTATEMENT. The three superficials share
territory but not the killed question — CNT-1 ~ f2-reopen (both "digest
count disagrees with truth", but F2 killed a queue-count regex parser and
CNT-1 is a clean-clock counting convention split); PIT-1 ~ b4-notch (both
"row-count floor", but PIT-1 is a writer-side persistence guard on the pit
stream, touching neither the skew stream nor the affirmed ≥400 pin);
SKW-2 ~ b4-notch (B4-adjacent, but proposes no floor amendment and itself
flags the mid-accrual sensitivity check). Owner can disagree; the full
quotes are in this run's transcript. No dismissed idea has been re-proposed
— notably, cron-delay-capture predicted itself "the single most likely
re-proposal next time the scheduler misbehaves"; the scheduler then
misbehaved for a week and the panel routed the pain into writer/QA hardening
instead. The tripwire was tested by events and held.
Caveat on source coverage: memory/strategic-posture.md is absent from the
routine checkout — exactly the state open item MEM-1 documents — so the
public kill list + in-repo kill records served as the standing-kills source.
M5 — closure rate and cost (G3) · source: results/research_registry.jsonl, results/diagnostics/oos_verdict_history.jsonl, triage commits
- Trial-registry rows added since seeding: 0 (413 rows, last touched
2026-08-01
4286d89). Deflated-Sharpe hurdle movement: none. Correction to the seed block: it recorded 412 rows at seeding; a recount says the file already held 413 (both registry commits are 08-01, the file untouched since). The seed miscounted by one. - Questions closed since seeding: 5 — the built detectors, each with a
reported criterion verdict (M3). Triage dismissals (4 on 08-24
f51c479, 3 at the 12-cap on 08-31a1b0bb6) are grooming, counted separately, not closures. The oos-monitor's 09-01 append (oos_verdict_history.jsonlrow 3, INSUFFICIENT_DATA) is a ledger row, not a closure. - Cost per closed question: 0 registry rows / 5 closures. All five are instrument/operational closures; zero strategy questions closed — the charter's intended shape (apparatus over weather), and free. M5's warning direction (rows spent without closures) is not present; the inverse is.
- Route counter — keep this in the series: builds via
queue/approved/0 of 5. All five built items were built on owner-interactive instruction, each citing "the EXQ-1 precedent", honestly recorded and human-merged — no rails breach. Butqueue/approved/has never held an item (its only history is the gate's own creation,47e8e73), and the Wednesday implementer has never had work. The designed panel→triage→approve→implement path has never once run end-to-end, and precedent is accreting around the unexercised gate. Recorded as a counter, not a proposal: if this reads 0/N again next month while the interactive route keeps building queue items, the pipeline's approval gate is a drawing, not a door, and that becomes the finding.
G1 — auditor's residue · target: PR #132 / commit 100cf61 (STAMP-1+STAMP-2, market-session stamping)
Method: a fresh-context adversarial audit of the change as if no routine had reviewed it, then compared against everything reported at the time (panel run 14, the two built records, the 09-02 self-audit, the PR). The change's core claim VERIFIES — the four incident instants and the pinned edge probes replay correctly, the idempotency gate now keys on the session, and the 30-run negative control is genuinely in the test file.
Residue: 7 = 1 MAJOR (3) + 4 MINOR (4). None of the five items appear in any record made at the time.
- MAJOR — the pre-open→previous-day rule inverts for current-state
captures.
market_session_datemaps any pre-09:30-ET instant to the previous trading day, on the rationale "the only data that exists then is that day's close" — true for chains, false forsnapshot-shortability, whose content is a current-state-only snapshot (the call site's own comment: "a threaded historical date would FABRICATE state",cli.py:2153-2157). A skew-snapshot run delayed into the 04:00–13:30Z window (measured dispatch delays reach 9 h; 9 h past 19:00Z lands exactly at midnight ET) writes morning-refreshed ETB/HTB flags permanently to yesterday's parquet, and the TIME-GATED flip panel dates an overnight flip to the wrong session. The pre-fix UTC stamp was content-correct for this one stream; #132 made it wrong. No test covers a pre-open instant reaching this writer. → filed as queue item STAMP-3 (feedback item 1). - MINOR — the "a holiday stays the holiday" promise holds only after 09:30
ET; a pre-open holiday instant jumps two calendar days back
(
2026-09-07T12:00Z→2026-09-04), contradicting the docstring; the pinned holiday test probes only 14:35Z. - MINOR — the per-sleeve digest's no-run canary still judges the UTC date
(
digest.py:49viacli.py:4378,today=None→date.today()): the backwards fire #132 fixed in the fleet path survives in the manual single-sleeve path, and the retained clock-hermeticity entry sanctions it. - MINOR — failure-alert email subjects stamp
date.today()(UTC) (cli.py:3628,:4392): a post-midnight displaced failure emails tomorrow's date in the one channel a human reads to pick which session to investigate. - MINOR (hygiene) — duplicate in-function import of the helper
(
cli.py:4713,:4760); the commit message's "capture-qa" rewiring claim is loose (capture_qatakes no date);export-public'sdate.today()feeds a dead parameter.
Series note: this is G1 datum #1 (residue 7 on one change). The 09-02 self-audit's residue 23 was whole-system scope — not comparable; the comparable series starts here, same method, one change per month.
Feedback filed this run (each with its motivating measurement)
research/queue/open/stamp-3-preopen-current-state-inversion.md— the G1 MAJOR plus the three same-class UTC residuals as riders, full contract with a pre-registered, negative-controlled kill criterion (motivated by G1).- PR editing
ops/RESEARCH_PANEL.md(will not auto-merge, deliberately): every panel run record must carry the tripleconsidered / survived-review / opened, zero days included (motivated by M1's denominator being unrecorded in 5 of 17 runs and worsening). - Deliberately NOT proposed: any reaction to the rising M1 survival rate (one month cannot separate softening from a rich delta — the recompute next month decides), and any machinery for the 0/5 approved-route counter (the series carries it; machinery would be a sixth opinion).
Post-measurement note, same day: while this block was being written, CNT-1
moved open→built on main (b50ae9b, #141) — route again owner-interactive
("recorded honestly" in the file), so the M5 route counter closes the
window at 0 of 6 and M4's open-set is now 11. The closure count for
this window stays 5 (CNT-1's verdict belongs to next month's window).
Kill-criterion status of this routine (procedure §4): run 1 — adopted-change counter starts now; the 09-01 quota death counts against the beacon record, not this criterion.