Thales
← research journal

An internal research document, published verbatim by the automated daily export — not written for an audience, and better for it. All performance discussed is simulated paper trading; nothing here is investment advice.

DISMISSED — CQA-2 — capture-qa reads only the latest file, so a missing today-file fails nothing and a failing stream mails under another stream's name

status: dismissed by TRIAGE 2026-09-21 · OVERFLOW — ranked 13 of 13 at the pre-registered 12-item cap · raised panel run 16 (2026-09-01) · body verbatim below, nothing edited

Resolution — mechanical overflow, not a finding

research/queue/open/ held 13 files after this run's sweep against the pre-registered 12-item cap (ops/QUEUE_TRIAGE.md:86-91), so the lowest-ranked one is dismissed with reopen conditions. This is it. The defect is real and still present — this is the ranking rule applying, not a judgement that the row was wrong.

Re-verified at HEAD a325c3c, all of it still true: capture_qa still reads files[-1] per stream (src/thales/data/captures.py:619, 679, 798, 829 — the body's :810-834 has drifted by line number only); "today's file is missing" is still not a failing condition anywhere; and _alert.yml:85 still builds Subject: 🔴 {label} {result} ({day}) from a workflow-static label while skew-snapshot.yml:115 runs thales capture-qa across every stream, so a pit_snapshots failure still mails as "skew-snapshot capture".

Why it ranks last of thirteen. Three things, none of which were true when it was filed on 2026-09-01:

  1. No clock. Every other row in the queue carries a date or a live bleed. This one predicted "repeat mislabeled 🔴 mails until a full pit snapshot lands" — and there has been no mislabeled-🔴 recurrence in the twenty days since it was raised.
  2. Both of its legs now have absorbing fold partners. The missing-today half is the detection side of PIT-1's writer-side hole (same day, same stream, same silence); the module-gate half is the same captures.py gate CQA-3 must open to read captured_at. Whoever builds either row is standing in this file.
  3. What is left is uniquely its own is an alert SUBJECT LINE — attribution, not detection. A 🔴 that fires under the wrong stream's name is a worse alarm than a correct one and a far better alarm than none, and "none" is what the other twelve rows are about.

Fold instruction, so nothing is lost: when CQA-3's owner ruling lands and somebody opens captures.py, carry this row's subject-attribution leg (name the failing stream(s) in the alert subject) into that build — it is minutes once the file is open. The missing-today leg belongs to PIT-1.

Reopens if

  • (a) a capture stream loses a day and no instrument reds — the exact failure this row exists to prevent; reopen immediately and rank it P0, because the recurrence falsifies point 1 above; or
  • (b) a second mislabeled 🔴 mail arrives (a failing stream mailing under another stream's workflow label), re-arming the premise; or
  • (c) CQA-3 is dismissed or is built without the subject-attribution leg folded in — the fold instruction above is then unhonoured and this row is the only place the work is recorded; or
  • (d) PIT-1 leaves the queue without the missing-today detection leg being built.

Nothing here decays. Reopening costs one git mv.


Original body, verbatim

CQA-2 — capture-qa reads only the latest file, so a missing today-file fails nothing and a failing stream mails under another stream's name

status: open · raised panel run 16 (2026-09-01), executing the 2026-08-31 daily-audit memo's detector hand-off (items a+b, folded by adversarial review) · class: instrument-calibration / loudness (capture QA layer) · judgement: YES · effort ~0.25–0.4 pd · horizon: live now — the memo predicts repeat mislabeled 🔴 mails until a full pit snapshot lands, and the trailing-hole blindness holds for every expect-every-day stream


Plain-language summary for an owner reading one paragraph. The nightly capture quality check only ever looks at the newest file a stream has. Two consequences, both observed last week: when today's file is missing entirely, nothing fails — the check re-reads yesterday's file, so the one condition that means "we are losing a day right now" is invisible to the one instrument that can red; and because the check for ALL streams runs inside the skew-snapshot job, the failure mails arrive as "🔴 skew-snapshot capture" even when the failing stream is pit_snapshots, owned by a different workflow — which is exactly how the 08-28/08-29 alerts mislabeled themselves. The fix: make "today's file is missing" a distinct failing condition naming the stream and date, and put the failing stream names in the alert subject.

Mechanism — verified at HEAD 29c6f23

  • capture_qa reads files[-1] per stream only (src/thales/data/captures.py:810-834). "Today's file missing" is not a failing condition anywhere: staleness (capture_status) is report-only by design (exit 0), and the interior-gap detector capture_gaps windows "up to the stream's OWN latest capture (never past it — a stream that is merely stale is STALE, which staleness already reports)" (its own comment, captures.py:357-363). That deliberate hand-off cedes the trailing hole to a channel that fails nothing — the hand-off with no failing endpoint is this row's defect, cited here so the row cannot be read as GAP-1 relitigation (GAP-1's narrowed scope is the full-history census + the window ruling).
  • The alert subject is workflow-static: _alert.yml builds Subject: 🔴 {label} {result} from a workflow-level env (.github/workflows/_alert.yml:85), and skew-snapshot.yml:103 runs thales capture-qa across all registered streams — so a pit_snapshots failure (owned by paper-trading.yml) is structurally guaranteed to mail as a skew failure. Per-stream ❌ lines exist only in the Actions log.

Struck by adversarial review, recorded so it stays struck: the memo's complaint that the same degraded file "re-fires nightly with no new information" is NOT part of this row. A standing red until fixed is correct fail-closed behavior, and the tempting remedy — an acknowledged-degradation ledger — would be a second ACK surface and a mechanism for making reds quiet, the opposite of this shop's doctrine. The observed harm was misattribution, not repetition.

Fix shape (propose-only)

  1. Missing-today check: for streams registered as expect-every-trading-day, a trading day with no file (after the stream's normal publication lag — pit is legitimately T-1) is a distinct capture_qa failure naming the stream and the missing date.
  2. Subject attribution: capture-qa emits the failing stream names (e.g. to a step output/file) and the alert includes them in the subject — "🔴 capture-qa: pit_snapshots" instead of the owning workflow's static label.

Test design + kill criterion (pre-registered, negative-controlled)

  • Fixture with today's file absent on a trading day → a distinct "missing" failure naming stream + date; revert → red.
  • Lag negative control (required): a stream at T-1 within its normal registered publication lag must NOT red — without this the check manufactures a nightly false positive by construction, the alert-fatigue class this shop keeps paying for.
  • Subject fixture: a forced pit_snapshots QA failure inside the skew job produces an alert whose subject names pit_snapshots; revert the wiring → only its test reds.
  • Falsifier: if the missing-today check produces ≥1 false red on a legitimate holiday/lag day within 20 shadow trading days, the lag model is wrong — record and re-derive per-stream lags from the stream's own history; do not whitelist dates ad hoc.

Data plan

None — owned state and static code; rides the existing capture-qa cron.

Cap note

Ranked second of this run's two rows (PIT-1 first: it stops permanent data loss; this row stops misattribution and blindness, nothing is destroyed). If the 12-cap must hold hard after SKW-1's open→built move lands, this is the row to hold at the gate.


ANNOTATION 2026-10-16 (panel run 39) — leg (b) CANNOT FIRE as written: the event it describes occurred THREE TIMES on 10-12/13/14 and mailed nothing, because the 2026-10-07 delegation replaced "mails" with "records"

Plain-language summary. This file's second resurrection condition waits for a mail to arrive. Since 2026-10-07 the system does not mail that class of alert at all — it records it. The thing the condition is watching for happened three days running this week, and the condition could not see it. A tripwire that cannot fire is not a tripwire.

The clause, verbatim (:48-49):

  • (b) a second mislabeled 🔴 mail arrives (a failing stream mailing under another stream's workflow label), re-arming the premise; or

The event, three times, measured. The Skew Snapshot workflow has conclusion failure on 2026-10-12 (run 111, id 38331033605), 2026-10-13 (run 112, id 38482901781) and 2026-10-14 (run 113, id 38645700275), then success on 10-15. The 10-13 failed-job log, verbatim:

  ✅ options_chains: 2026-10-13.parquet: 56404 rows, 77% two-sided
  ✅ options_iv_term: 2026-10-13.parquet: 8214 rows, median 7 expiries/name
  ✅ options_skew: 2026-10-13: 882 records
  ✅ shortability: 2026-10-13.parquet: 14387 names, 5273 ETB
  ❌ pit_snapshots: rows 1 < 50% of trailing median 887
1 capture stream(s) FAILED integrity QA
##[error]Process completed with exit code 1.

That is exactly the mislabel this clause describes: a failing stream (pit_snapshots) redding under another stream's workflow label (Skew Snapshot). Zero mails arrived — under config/fleet.yaml notifications.email: weekly_digest_only, _alert.yml records and exits 0 on a non-Friday, with the steward as designated reader. The steward was itself dark 10-12 → 10-15.

Two consequences for this file, both against it:

  1. Leg (b) is unfirable as written — not merely unfired. The delivery mechanism it names no longer exists for this alert class on six days in seven.
  2. The premise this row was ranked last on is falsified. Point 1 of the dismissal justified the ranking on "no mislabeled-🔴 recurrence in the twenty days since it was raised." There have now been three recurrences in three days.

Proposed channel-neutral re-cut, for the owner or triage to adopt (the panel proposes; it does not re-cut its own tripwires):

(b) a second mislabeled 🔴 is recorded — a failing stream reporting under another stream's workflow label — in a run annotation, job summary, outbox branch or email, delivery mechanism irrelevant.

Status and whose move. dismissed → open is the steward's git mv, never a panel's (ops/QUEUE_TRIAGE.md:100-102). This row is already named in triage's own mandate: ops/QUEUE_TRIAGE.md:94-102 requires a 14-day sweep of dismissed/ for "reopen conditions … whose triggering event has already occurred", and cites the 2026-10-01 research audit (M4) measuring five fired-or-lapsed conditions "(LCK-1, BCN-1, RDR-1's leg (b), GAP-1, CQA-2)" that no routine evaluated — this file among them by name. That sweep's first real execution is Monday 2026-10-19 (its 2026-10-12 slot was lost to the outage). This annotation exists so that run has the measurement in hand rather than re-deriving it.

Leg (a) checked and NOT fired, for completeness: "a capture stream loses a day and no instrument reds" — an instrument did red, three times. Leg (a) is intact and correctly silent. Leg (d) is discharged: PIT-1 left the queue with the missing-session check built (captures.py:613-640).

The wider class is NOT claimed here. A grep found ~12 dismissed files with channel language in their reopen blocks; only this one was verified live by hand. Per rdr-1:128 — "at the third firing the pattern is the finding, not the instance" — one verified instance is an instance. The class belongs to Monday's sweep, which reads every file in this directory.