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.
2026-10-01 — run 2 (window: 2026-09-03 → 2026-10-01)
Run context first. The routine fired on schedule and completed. Environment:
routine container, no broker keys, no config/.env, no data/raw, no
data/lab, no owner-Mac access; memory/ is absent for the second
consecutive month (the state mem-1-memory-dir-missing.md documents,
dismissed 09-14 as queue overflow). Facts below come from this repo's git
history and files, or from the GitHub API where named.
Two measurement-integrity notes that the next reader needs before anything else, because they silently corrupt this block's method:
- The routine's checkout arrives SHALLOW (depth 50, oldest commit
2026-09-15).
git log --since=2026-09-03on it returns 50 commits and appears to show a twelve-day hole onmainthat does not exist. Every count below was recomputed aftergit fetch --unshallow(864 commits), with date filtering applied by hand and no--since. A committer-date histogram oforigin/mainshows commits on every weekday from 09-03 onward; the only real gap is 09-18 → 09-26, which is the billing outage below. mainLAGGED the pipeline's real state for twelve days. GitHub refused every Actions job on this repo from the 09-19/20 weekend until 2026-10-01 01:18:22Z (GitHub Free, allowance spent, no payment method; root causeb10cbfe/ #182, signaturerunner_id 0,steps: 0, 3–13 s). The auto-merge guard is itself an Actions workflow, so routine PRs stopped landing: 11 were open at the time of this run. The claude.ai routines (panel, triage, implementer, the audits) ran throughout and pushed their beacons normally — the outage cost merges, not runs. Any measurement taken frommainalone in this window under-reports; each measurement below says where it looked.
M1 — proposal-survival drift · source: origin/beacon/panel markers (all 14 runs) + panel PR bodies (#149, #162, #165, #170, #172, #173, #175, #179, #183, #188, #192, #194, #195); the two carriers agree in all 13 PR-carrying runs
Panel runs 18–32. Window totals: considered N=113 · survived-review M=34 · opened K=8.
| period | runs | considered | survived review | added to open | K/N | M/N |
|---|---|---|---|---|---|---|
| 09-03..09-04 | 18–19 | 22 | 1 | 1 | 0.05 | 0.05 |
| 09-11 | 21 | 8 | 2 | 2 | 0.25 | 0.25 |
| 09-14..09-18 | 22–26 | 40 | 8 | 3 | 0.08 | 0.20 |
| 09-21..09-25 | 27–28 | 20 | 16 | 0 | 0.00 | 0.80 |
| 09-28..10-01 | 29–32 | 23 | 7 | 2 | 0.09 | 0.30 |
| window | 14 runs | 113 | 34 | 8 | 0.07 | 0.30 |
Verdict: the rising series recorded last month is BROKEN on the opened rate
— and that rate has stopped measuring what M1 was built to measure. K/N fell
0.64–0.73 → 0.07 window-wide and never exceeded 0.25 in any sub-period. But
the survived-review rate did not fall: M/N is 0.30 window-wide with a 0.80
spike in runs 27–28 (6 of 8, then 10 of 12). The two series decoupled, and the
cause is mechanical and traceable, not inferred: from run 23 onward every
beacon marker records queue/open/ at or over its pre-registered 12-item cap
(ops/QUEUE_TRIAGE.md:86-91; 12 at runs 23–25, 13 at runs 26–31), and
survivors were routed to pre-merge PR comments, dismissal annotations or the
run note instead of rows — run 27 "ZERO rows opened… no incumbent displaced",
run 28 "ZERO rows opened… stays at 13", run 31 "NOTHING evicted".
So: K/N now measures the cap, not reviewer permissiveness. M/N is the gauge that still measures the reviewer, and on M/N the verdict is NO CLEAR DRIFT at high variance (0.05 → 0.25 → 0.20 → 0.80 → 0.30), n far too small to separate from the delta. Last month's RISING watch is neither confirmed nor cleared; it is now being read on the wrong instrument. → feedback item 3.
Outlier recorded: run 19's N=21 is 3.4× the window median N=7.5.
Triple-recording compliance: 14 of 15 run numbers = 0.93, against last
month's 12 of 17 = 0.71. Of runs that produced any artifact, 14/14 = 1.00.
Both carriers are in use exactly as ops/RESEARCH_PANEL.md §4 now requires,
and every one of the 13 PR bodies contains the literal triple. Last month's
feedback item 2 (PR #145, owner-merged 2026-09-03T03:49:17Z) worked, and is
measurably the reason this month's M1 could be diagnosed at all. The single
gap is run 20, which produced no artifact of any kind.
Cadence: 21 weekdays, 14 runs recorded, 15 run numbers consumed (18–32, contiguous). Seven weekdays with no run, in two blocks:
- 09-07..09-10 (4 days) — the Fable 7-day model quota went into overage on
09-07 and every Fable routine died on turn 1 (
ops/ROUTINES.md:52-57, owner decision 2026-09-12 "Opus everywhere", PR #164). This is where run 20 went: a run that consumed a number and wrote nothing. 1 lost record. - 09-22..09-24 (3 days) — panel genuinely dark,
beacon/paneldid not move. Cause NOT-ESTABLISHABLE from git (the scheduler control plane exposes only the most recent run). Recorded as dark, not diagnosed.
M2 — registration before computation (G5) · source: commit order on the full log, plus results/lab/ledger.jsonl
Inversions: 8 — the first non-zero M2 in this series. All eight are in the hypothesis lab; the queue and the forward clocks are clean.
Clean populations, for the record:
- 8 queue builds landed on main, 0 inversions. SKW-1 (
528793d08-31 →6ea316009-05) · KSP-1, IGD-1 (6ea316009-05 →47ea02409-06) · SKW-3 (8a656f509-04 →877dce609-06) · SKW-4 (6ea3160→877dce6) · FOS-1 (f09b15e09-02 →ee68ebe09-06) · CNT-1 (ec8e80e08-29 →b50ae9b09-02) · STAMP-3 (f5abbbe09-02 19:39:45 →99656aa19:58:53 — 19 min 08 s, the tightest order-correct gap in the series). Post-build edits to built files are append-only; criteria untouched (M3's domain). - Both forward clocks that matured 2026-09-09, 0 inversions. Placebo
evaluator built
c0166322026-07-18, band pinned in-module, numbers first committed82e802e09-09 — 39 days. oos-monitor pinnedfab0945/7a709eb2026-06-11, verdict row 09-09. Recorded without calling it an inversion: the oos-monitor's maturity counter changed unit inside its own clock window (b50ae9b, CNT-1, 7 days before firing).
The lab's eight. Only results/lab/ledger.jsonl is committed
(.gitignore:104-105); reports stay local. For every study, the spec YAML
and its own result row entered git in the SAME commit, and the run clock
pre-dates that commit. Lab run clocks and lab commit timestamps are both the
owner-Mac clock (−0700), so they are directly comparable.
| study (verdict) | run clock | spec+result commit | gap |
|---|---|---|---|
| cross_index_v1 run A (NULL/NULL) | 09-27 22:39:33 | 547950a 22:55:24 | −15m51s |
| comprehensive_v1 run A (NULL/NULL) | 09-27 23:12:51 | 864da4e 23:21:00 | −8m09s |
| cross_index_v1 run B | 09-27 23:15:08 | spec 547950a 22:55 | +19m44s — CORRECT |
| comprehensive_v1 run B | 09-27 23:15:11 | 864da4e 23:21:00 | −5m49s |
| the declared error budget | ledger registered_at 09-28 21:05:07 | e53fa72 22:30:04 | −1h24m57s |
| trend_us_1926 (INCONCLUSIVE, slot 1/5) | 09-28 21:05:16 | e53fa72 22:30:04 | −1h24m48s |
| trend_parity_1962 (INCONCLUSIVE, 2/5) | 22:38:11 | a9cffcd 23:53:46 | −1h15m35s |
| vol_manage_1936 (KILL, 3/5) | 22:38:21 | a9cffcd 23:53:46 | −1h15m25s |
| treasury_carry_1962 (KILL, 4/5) | 22:38:22 | a9cffcd 23:53:46 | −1h15m24s |
| turn_of_month_1927 (KILL, 5/5) | 23:56:51 | ada5bff 23:59:38 | −2m47s |
State the finding precisely, because the loose version would be an
accusation and would be wrong. Nothing here shows a spec written after its
result. What it shows is that for 8 of 9 lab runs the pre-registration is
ASSERTABLE but not VERIFIABLE — the only evidence that the spec pre-dated the
run is the ledger row that also carries the verdict, written by the same
process in the same second. That is the exact property G5 exists to buy ("git
makes it verifiable rather than assertable", NORTHSTAR §3). Sharpest instance:
config/lab.yaml's error_budget block did not exist in git at all before
e53fa72 — the commit that also carries confirmatory result #1 — so the
declared p≤0.005 one-shot budget has no git existence preceding the first
verdict charged against it. Run B of cross_index_v1 is the one order-correct
case and shows the mechanism works when the spec is committed first.
Counter-evidence, measured and weighed: no spec was edited after its run.
Each of the 8 YAMLs has exactly one commit, and I independently recomputed all
9 of 9 run rows' spec_sha256 against sha256(file)[:16] at HEAD —
9/9 match, and spec_text is byte-identical to the file. Practical
exposure today is nil: every verdict is NULL, KILL or INCONCLUSIVE, nothing is
promoted, and the reserve is 5 of 5 spent.
Partially-overlapping record made at the time, credited so this is not claimed
as wholly novel: panel run 29's note (PR #188 §4) records that both committed
exploratory runs are stamped code_version +lab-dirty — i.e. the code
was uncommitted at run time. Nobody recorded the spec and budget commit
order, nor extended it to the five confirmatory studies. → feedback item 2.
M3 — kill-criterion honesty · source: git show of proposal vs built text for all 8 new-in-window queue/built/ items; all 11 open PRs checked for stranded records (none touch queue/built/)
New-in-window set = 8 (cnt-1, stamp-3, skw-1, ksp-1, igd-1, skw-3, skw-4,
fos-1). Last month's block measured 5 items, not 8 — igd-1/ksp-1/skw-1 reached
built/ on 09-05/06, and cnt-1/stamp-3 merged after the run-1 commit window
opened. The populations are disjoint; the series is continuous.
Criterion wording IDENTICAL 8 of 8. Every built file is a pure append —
diff proposal→HEAD is one hunk each, the pre-registered body byte-identical.
Silent divergence: 0 (third consecutive month).
But the control-execution reading got worse, 1 → 3, and that is this section's finding:
- CRITERION NOT EVALUATED: 1 — SKW-1. Its built footer carries no verdict
at all. Criterion as registered: "A test asserting every Alpaca SDK client
construction site in
src/applies the deadline wrap (negative control: remove the wrap at the skew site → the test reds)" plus a "Falsifier: if the wrapped client breaks the skew capture within 5 shadow trading days … revert." Shipped: four per-site tests, no enumeration ofsrc/sites — a fifth construction site would not red the suite. The 5-shadow-day falsifier is reported nowhere inbuilt/,RESEARCH.md, #125 or #150. - UNFLAGGED CONTROL UNDER-EXECUTION: 2 new. SKW-1 as above (census scope
shipped as per-site tests, not flagged). CNT-1 leg 1 — criterion: "assert
the digest's
live_oos_daysequalsload_live_returns(...).size"; shipped (test_digest.py:214-225) asserts the literal== 1with a comment, the loader comparison existing only on thepublic_exportsurface. The footer describes the edit, not the narrowing. (CNT-1 leg 3, the decisive control, is at full scope.) - CARRIED, UNCORRECTED, STILL UNDISCLOSED: STAMP-1. Last month flagged it;
nothing changed. Criterion: "replay the
captured_attimestamps of the last 20 committed capture days"; shipped_NORMAL_CAPTURES= 5 instants, unchanged at HEAD. Correcting last month's own phrasing: the test holds 35 parametrized cases, but 30 are run instants — the capture-day population the criterion names is 5 of 20. Its second leg ("then shadow 20 trading days") is also unreported. - Honesty-positive, recorded at full value: three disclosed leg shortfalls (ksp-1's test 3 "Not built", skw-4's leg 3 re-routed, igd-1's legs 3/5 flagged). Verdict reported in the PR body: 3 YES, 4 PARTIAL, 1 NO.
And one finding about this routine itself, which belongs here rather than in a footnote. STAMP-3's proposal (PR #144) was authored by run 1 of this very audit, and its negative control reads "replay the committed capture band (20:14–20:43Z normal days, the 09-01 post-close instant, and the pinned incident instants)" — a verbatim description of the already-shipped 5-instant set that the same run had just flagged as a reduction of STAMP-1's "last 20 committed capture days." The STAMP-3 criterion is satisfied as written and the relation is stated in neither #144 nor the STAMP-3 footer. The measurement is that a shrinkage flagged by this auditor was then normalized by this auditor into a new pre-registration within twenty minutes. No remedy is proposed; it is recorded so the series carries it and so next month can check whether it recurs.
M4 — reject-ledger integrity · source: queue/open/ (13 on main, +LAB-1 pending in #188) vs queue/dismissed/ (32) + web/public/data/killlist.json (13) + CLAUDE.md "Key Decisions"/"Research stance" + RESEARCH.md kill headers
8 NONE / 5 SUPERFICIAL / 0 RESTATEMENT over the 13 live open items (last
month: 9 / 3 / 0 over 12). 11 of the 13 are new this window. No open slug
exists in dismissed/; no dismissed idea was re-proposed verbatim or near-
verbatim. The five SUPERFICIALs each carry their distinction on the record —
BTB-1 and CQA-3 touch other clauses of the B4 pin than b4-notch resolved;
DGX-1 absorbed fos-2 as a declared fold; PIT-1 is unchanged from last
month and re-verified; FRZ-1 is the sharpest resemblance of the window
(sibling-killed lab-3 the same panel run) and its distinction is itself a
measurement — lab-3 died because the auto-merge guard denies writes to
the files at risk, where FRZ-1 measures ALLOW for its own two files. Last
month's three SUPERFICIALs all stand in hindsight (CNT-1 built, SKW-2
dismissed un-built, PIT-1 open).
The section's real finding is not a restatement; it is that the tripwires
themselves have no reader. Five dismissed items' reopen conditions have
fired or had their date pass, and not one was evaluated by any routine:
LCK-1 (fired ~09-11, survived triage 09-14 and panel runs 21–23, caught by
hand on 09-16) · BCN-1 (fired 09-21, annotated "the dismissal has lapsed by its
own terms", not reopened) · RDR-1 (its own leg (b) fired; pre-registered action
"reopen immediately" declined on the record) · GAP-1 (reopen "immediately if a
seventh permanent capture-day is found" — massively exceeded by the 8-session
outage; escalated, not reopened, now with a dated expiry of 2026-10-19) ·
CQA-2 (named by panel run 29 as the fourth fired-unevaluated instance).
grep -i reopen over ops/QUEUE_TRIAGE.md, ops/RESEARCH_PANEL.md,
ops/prompts/triage.md and ops/prompts/panel.md returns only write-side
instructions. → feedback item 1.
Two further records-integrity facts, both recomputable:
- A dismissal rests on a premise since measured false.
b4-notch's dismissal asserts "The pin is hash-frozen"; FRZ-1 measures that no hash was ever cut for either the B4 or the B5 pin. - CLK-1's reopen date (2026-10-06) has not passed, but both its legs are
already true at HEAD.
NORTHSTAR.md§6 carries no row for the shortability clock or foroptions_iv_term— the only two forward clocks maturing before the December gate (slipped by the outage to ~2026-10-29 and ~2026-11-05 per panel run 29 §7) — against §6's own header rule that "every entry must have a pinned evaluator before maturity." Four independent records now name this gap (CLK-1's dismissal 08-31, triage 09-14, LCK-1's annotation 09-16, RDR-1) and it has never been a row. Owner-only: adding a §6 row needs an evaluator this routine may not invent, and §6 is a living section so the edit crosses no C0 boundary. Escalated, not acted on.
M5 — closure rate and cost (G3) · source: results/research_registry.jsonl, results/lab/ledger.jsonl, origin/beacon/implementer, build commits
- Trial registry: 413 → 413, delta 0. Untouched since
4286d892026-08-01. Deflated-Sharpe hurdle movement: none. No hurdle recomputed at N=413 exists in any repo artifact (last recorded figure 3.32 at ~250 trials,RESEARCH.md:2318) — NOT-RECORDED, and worth noticing: the registry's purpose is to move that hurdle, and nothing has read it in two months. - Lab ledger: 0 → 10 rows (1 budget + 9 runs), 1,370 trials = 1,344
exploratory + 26 confirmatory; 1,370 distinct rule ids. Runs 3–4 are
same-settings re-runs charging
n_new_trials: 0, exactly as CLAUDE.md claims. Segregation HOLDS: zero lab-shaped rows inresearch_registry.jsonland no commit to it after 08-01. - Closures: 17. 8 built queue items with a reported criterion verdict
(M3's set; SKW-1 counted as a build, not a closure, would make it 7 — kept at
8 to match M3's population, with the caveat visible) + 7 lab study verdicts
(2 NULL, 2 INCONCLUSIVE, 3 KILL — null results at full value per NORTHSTAR
G3) + 2 fired forward clocks (placebo: live = 2nd percentile of 200
random 50-name nulls, null median +0.912; oos-monitor first non-INSUFFICIENT:
OK, n_live 61). Excluded and counted separately: 22 queue dismissals
(grooming), the
oos_verdict_history.jsonlappend (the clock's own carrier, counted once), and all 11 stranded PRs. - Cost per closed question: 0 registry rows / 17 closures. M5's warning direction — registry rows spent without closures — is again absent; the inverse holds for a second month. Lab: 1,370 trials / 7 closures = 196 trials per closure (672 per exploratory closure, 5.2 per confirmatory). The confirmatory reserve is 5 of 5 spent, 0 passes, and a sixth study is refused in code.
- ROUTE COUNTER — the pre-registered trigger from run 1 is now MET. Last
month recorded 0 of 6 and pre-registered: "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."
It reads 0 of 13 cumulative.
research/queue/approved/has never held an item: its entire history is47e8e732026-08-21 addingREADME.md, and nothing else, ever. All 6 new builds record the route honestly ("built on the owner's direct instruction … NOT viaqueue/approved/") — no rails breach. The Wednesday implementer has 5 run records in its existence (origin/beacon/implementer: 08-12, 08-19, 09-02, 09-16, 09-30), every one "nothing approved, no PR opened"; 2 of this window's 4 Wednesdays carry a record at all. Independently corroborated by triage's own counter firing 8 of 8 weeks unused on 2026-09-28 (PR #190) and by panel run 29's "eight weeks, thirteen proposals, zero approvals". So the finding, stated plainly: the designed panel→triage→approve→implement path has never once run end-to-end in two months, and the pipeline's actual throughput is panel-finds → triage-dismisses-to-fit-the-cap → owner-interactive hotfix. No machinery is proposed. Two routines already carry this counter; a third instrument would be a sixth opinion, and the only remedy — use the gate, move it, or retire the implementer — is the owner's alone.
G1 — auditor's residue · target: the hypothesis lab's research-integrity machinery (547950a, 864da4e, e53fa72, a9cffcd, ada5bff, 2026-09-27/28; src/thales/lab/, ~15 families, 1,370 trials)
Method: a fresh-context adversarial audit, given the lab's seven published
integrity claims and told to falsify each, with no access to what anyone
reported at the time; then compared by this session against the full record —
the five commit messages (which self-report a pre-run adversarial review that
found and fixed three MAJOR honesty holes), panel run 29's note (PR #188 §4),
panel run 30's lab-3/LAB-4 dismissal, and the weekly audit of 09-28.
Residue: 6 = 1 MAJOR (3) + 3 MINOR (3). Last month: 7 = 1 MAJOR + 4 MINOR on a single-commit target. Two data points do not make a trend, and the targets are not comparable in size — this one is a whole new subsystem. Recorded flat, not improving.
The most important G1 number this month is not the residue. Of the three
MAJORs the fresh audit surfaced, two were already on the record before it
looked: lab confirm printing the vault verdict before charging the ledger
(panel run 29's fold instruction, #188 §4, same file:line) and the vault's α
ladder being drawn from the study spec, unbounded, and outside the declared
budget (panel run 30's lab-3/LAB-4, reproduced twice at the time). A fourth
candidate — the ledger-integrity tripwire being weekday-cron only — was
considered and struck at review by run 29, with its reasoning recorded.
So the pipeline's own reviewers independently found two thirds of the MAJOR
class on this target, ahead of a fresh adversarial pass with a falsification
brief. That is the most encouraging measurement in this block, and it is
comparable next month.
MAJOR (residue) — every lab-wide guard becomes silently vacuous under a
non-editable install, and the warning that exists cannot fire.
src/thales/lab/data.py:61-67: repo_root() is Path(__file__).parents[3]
and _resolve makes every lab path relative to it. Verified in this
container, which installs exactly as the routine prompts prescribe
(pip install . -c requirements-ci.lock, non-editable):
repo_root() -> /home/user/thales/.venv/lib/python3.11
results_dir(real cfg) -> .../lib/python3.11/results/lab (absent)
prices_dir / data_dir -> .../lib/python3.11/data/lab (absent)
ledger.load(results_dir) -> 0 rows
ledger.budget(rows) -> None
ledger.known_trials(rows) -> set()
ledger.vault_dates(rows) -> set()
ledger.confirmations(rows) -> {}
Consequences, simultaneously and with no error: check_vault
(study.py:103-115) short-circuits on if seen and … and passes vacuously —
the vault date is unpinned; check_budget returns None, so
exploratory_alpha (study.py:95-100) falls back to defaults.fwer_alpha
= 0.05, double the declared 0.025 pool; known_trials is empty so the
lab-wide ratio collapses to 1.0 and the lab-wide correction is switched
off; confirmations is empty so all five confirmatory slots read
re-spendable and confirmatory.py's len(done) >= slots refusal cannot
fire. The --config note at cli.py:54-62 is built from the same broken
repo_root(), so canonical equals the mis-resolved directory and the
warning is unreachable. Default config loading does fail loudly first
(FileNotFoundError on .venv/lib/python3.11/config/lab.yaml), so reaching
this state takes an absolute --config and a fresh lab fetch — stated
plainly so the reachability is not overclaimed. The owner-Mac install mode is
NOT-RUN (no access).
Two things make this more than a packaging nit:
- The house already learned this exact lesson one module over and wrote the
guard.
src/thales/backtest/cpcv.py:486-497uses the identicalparents[3]idiom, wraps it inif candidate.exists(): … else "results", and documents why in its own docstring: "A cwd-relative default silently flipped the DSR trials count to N=1 when run from outside the repo … collapsing the multiple-testing hurdle." The lab reproduces the same defect class, with the same consequence, unguarded. These are the only twoparents[sites insrc/. - It falsifies the premise on which a related finding was struck. Run 29
struck the vault/floor-tripwire finding partly because "the runtime backstop
is not vacuous in the real repo, since
results/lab/ledger.jsonlholds four records all sealed under 2023-01-01 forcheck_vaultto refuse against." Under a mis-rooted install it holds zero records andcheck_vaultis precisely vacuous. It also bears onlab-3's "exposure is nil today" reasoning, two legs of which ("the reserve is exhausted, 5 of 5"; "vault openings to date: 0") are ledger reads that return unspent/zero in this state. Recorded as new grounds the owner may weigh, not as a fired reopen condition — anddismissed → openis a sanctioned move for no routine anyway, which is feedback item 1's whole point.
MINOR (residue) ×3.
- The never-shrinks test floors run rows, exploratory trials and
confirmatory runs, but nothing floors
confirmrows.tests/test_lab/test_repo_state.py:33-38;summary()'sn_confirmationsis computed and never asserted. Deleting oneconfirmline resetsk = len(done)+1(cli.py:~584) and re-opens the vault at the lowest bar with the full suite green. There is no hash chain and no per-row digest, so an edit to any row is equally undetectable while the floors hold. - CSCV PBO is computed on raw excess-of-cash Sharpe, not the benchmark
edge.
study.py:~266passesex = R - cash. DSR and the luck bar were explicitly fixed to the Q1 differential in864da4efor exactly this reason; PBO was not, so in an equity-heavy grid the in-sample winner is selected partly on equity beta. Reporting only — no headline verdict depends on PBO. - A study whose every rule errors is not charged.
_eval_chunk(study.py:160-167) correctly swallows and still charges per-rule failures, butstudy.py:~434'sif not ok: raise RuntimeError(...)aborts before_record, so N attempted rules go uncounted.
Claims the fresh audit tried to falsify and could NOT — recorded at full
value, because verification is the other half of this gauge. The vault seal
is physical at the panel layer: truncation happens at load for both panels
before any rule exists (data.py:571-573, :647-649; Panel.truncate on
close/open/signals/cash), sealed=True is the default with no study-settable
knob, and load_panel(sealed=False) has exactly one call site repo-wide —
lab confirm. lab expand, lab show and resolve_window all load sealed;
lab report only prints a saved file. The one-shot is keyed on
hypothesis_id, checked before any work, with no --force, ids derived from
canonical family+params so a rename cannot mint a second id, a fail-closed
holdout-overlap default of "2999-01-01", and k = len(done)+1 with
Σ α/2^k = α and no off-by-one. Charge-before-write holds in both run paths
(_record appends the ledger row as its first statement). The declared budget
is enforced in code, not merely reported — a sixth confirmatory study
raises BudgetError("the confirmatory reserve is exhausted (5 of 5)"), the
budget must pre-date any confirmatory result, and a study may not choose its
own bar. The lab-wide correction is the reported verdict. All 15 registered
families are truncation-tested with a seeded-peeking negative control, and the
per-run spot-check aborts before any charge. Lab/momentum segregation holds by
construction. Named gaps inside those verifications: the raw files under
data/lab are untruncated, so a new code path reading prices_dir directly
would bypass the seal and no test pins sealed=False to one call site; and the
run-time causality spot-check covers only the first hypothesis per family and
3 cut dates, so a lookahead on a particular parameter branch would pass at run
time (the static test's per-family cases cover this; the run-time one does not).
Feedback filed this run (each with its motivating measurement)
- PR editing
ops/QUEUE_TRIAGE.md§1 andops/prompts/triage.md(will not auto-merge, deliberately) — the two-part ask panel run 29 §3 drafted and could not execute: sweepqueue/dismissed/for reopen conditions dated within 14 days or already triggered and report each one, plus a clause naming who may act on a fired one, becausedismissed → openis currently a sanctioned transition for no routine. Motivated by M4's five fired-and-unevaluated conditions. Filed as a procedure edit rather than a queue row for the reason RDR-1 itself gives: the fix is prose in two mirrored files that must move in one sitting, which the implementer's rails forbid — so a PR from this routine is the only instrument that reaches it. This is not a relitigation of RDR-1; satisfying it retires RDR-1 permanently by its own "dies permanently" clause, and it lands before the terminal clause expires at Monday's triage. Clause (b) is drafted with the conservative option (reopening is the owner's move alone, granting no routine new power); the owner may substitute the other. - PR editing
ops/RESEARCH_IMPLEMENTER.md(same PR, will not auto-merge) — two clauses on the build standard: (i) a pre-registration must be committed in its own commit, before the computation it governs runs; a spec and its result in one commit is not a pre-registration (motivated by M2's 8 inversions); (ii) a built record must quote the registered negative control verbatim alongside what was executed, and label any reduction in scope or sample size (motivated by M3's 1 criterion-not-evaluated and 3 unflagged control under-executions, up from 1 last month). Falsifiable: next month's M2 counts inversions, target 0; next month's M3 counts unflagged under-executions, target 0. - PR editing
ops/RESEARCH_AUDIT.md§1 M1 (same PR, will not auto-merge) — make survived-review ÷ considered the primary survival gauge, with opened ÷ considered reported but explicitly marked cap-limited wheneverqueue/open/stands at or over the pre-registered 12-item cap. Motivated by M1's measured decoupling (K/N 0.64–0.73 → 0.07 while M/N held at 0.30 with a 0.80 spike, the queue at or over cap in every run from 23 on). Without this, next month's M1 reads a reviewer collapse that did not happen. Falsifiable: if the cap binds again the two rates diverge again; if the cap is lifted they should re-converge. - Deliberately NOT proposed, with reasons, so the restraint is auditable:
no machinery for the route counter (two routines already carry it and the
remedy is the owner's); no queue row for the G1 MAJOR (
queue/open/is at 13 against a 12 cap and #188's LAB-1 already spends the next eviction — the fix is a guardedrepo_root(), three lines, and this block is its record, the same posture run 29 took with its fold instruction); no NORTHSTAR §6 rows for the two October clocks (the row requires a pinned evaluator this routine may not invent — escalated to the owner instead); no reaction to M4's five SUPERFICIALs (none is a restatement and the distinctions are on the record).
Kill-criterion status of this routine (procedure §4): run 2 — adopted-change counter 1 of 1 runs. Run 1's two items were both adopted: PR #144 (STAMP-3 queue row) auto-merged 2026-09-03T02:39:46Z and was built within 20 minutes as the #147 hotfix; PR #145 (the panel triple) was owner-merged 2026-09-03T03:49:17Z. §4's inverse check applied honestly rather than flattered: neither was cosmetic — #144's MAJOR was a live capture-stamping defect fixed the same evening, and #145 lifted triple compliance 0.71 → 0.93 and is the sole reason M1's cap-decoupling could be diagnosed this month instead of being read as reviewer rot. Three consecutive runs with no adopted change would drop this routine to quarterly; the counter stands at 0.
Post-measurement note, same day: while this block was being written, PR #188
(panel run 29) merged to main — the first routine PR to land after the
auto-merge guard came back at 01:18Z. So LAB-1 is now live and M4's open set
reads 14 against the 12-item cap rather than 13, and the eviction decision
falls to Monday's triage. The measurements above are left as taken; M4's
classification of LAB-1 (NOT a restatement of lab-3 — gate isolation versus
registration hygiene) stands unchanged by the merge. Nine of the eleven PRs
stranded by the outage were still open at the close of this run.