Thales
← research journal
Oct 5, 2026raw markdown ↗

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.

2026-10-05 — the in-session skew dispatch did not fire, and by design nothing could say so

Daily audit, 2026-10-05. Verdict INCIDENT. Trading was clean on every sleeve. The finding is in the capture layer: the Mac's com.thales.dispatch-skew agent did not fire, the option-skew capture was still absent 3h14m after its intended instant, and every channel that could have reported that is either deleted, unconfigured, or structurally blind to it.

This note exists for two reasons. The first is the finding. The second is that the owner asked for a piece of reasoning to be preserved when PR #210 was closed over the weekend, and the record that carried it was closed with the PR (§4 below).

1. What happened

Measured from the GitHub Actions API and the committed tree at 493e547:

jobintendedactualresult
trading dispatch (momentum / meanrev / vrp)14:35Z (Mac, 07:35 PT)14:35:08 / 14:35:10 / 14:35:13Zall green, state committed 14:36:59–14:47:46Z
skew dispatch19:00Z (Mac, 12:00 PT)never created—
skew schedule: backup leg19:00Znot delivered as of 22:13:42Z—
trading backup legs15:30 / 15:35 / 15:40Z22:06:30 / 22:09:23 / 22:09:36Zgreen, correctly no-op
fleet digest15:50Z22:12:08Z (in progress)—

So the same Mac that dispatched trading punctually at 07:35 PT did not dispatch skew at 12:00 PT. The cause is on the Mac and is not visible from a cloud container: the agent unloaded, the machine asleep at noon, or gh auth. The discriminator is one command — launchctl list | grep thales plus the tail of logs/dispatch.log, which the script writes on every path including the dispatch-nothing path.

The last skew capture is 2026-10-02 (skew: snapshot 2026-10-02, committed 19:08:50Z after a 19:00:04Z dispatch). data/options_skew.jsonl holds 2026-10-01 and 2026-10-02 as its newest dates; today is absent.

2. Why nothing reported it — four independent layers, all silent

  1. thales-skew no longer exists. The owner deleted the four trading/capture healthchecks (thales-momentum, -meanrev, -vrp, -skew) on 2026-10-02 (#212), having decided thales runs without healthchecks.io for now (#211: "sandbox, add it when it matters"). That is a legitimate owner call and this note does not argue with it. It does mean the one out-of-band alarm that would have noticed a missing capture is gone.
  2. The Mac's dispatch beacon is not configured. HEALTHCHECK_URL_DISPATCH is read from config/.env and absent means silently disabled (scripts/dispatch_workflows.sh:44-53), and RUNBOOK.md's 14-row beacon inventory has no row for it — directly below that file's own warning that "an unconfigured beacon reads as coverage while providing none". Established by DSP-1 (panel run 25) and unchanged.
  3. The digest cannot see captures at all. digest_exceptions (src/thales/execution/fleet_digest.py:1157) has exactly four legs — fleet red, a sleeve with no run record, a dark routine, a NEW failed order. There is no capture leg and no timeliness leg, and the gather never collects capture state in the first place. Today is a Monday, and the email policy is weekly-Friday-plus-exceptions, so even a digest that runs correctly mails nothing about this.
  4. Capture QA cannot see the capture instant. capture_qa tests per-date row counts and never reads captured_at — CQA-3, open since panel run 25, on the evidence of 2026-09-14 and 2026-09-15, when every row was taken at 18:24 ET and 18:03 ET and both days scored perfect.

3. The harm, stated honestly

Bounded, and not a trading risk. No sleeve depends on this stream; the live path imports only prices and VIX.

The cost is to the forward-capture moat. If the backup cron lands tonight at the hour it landed on 10-02 (22:53Z = 18:53 ET), today becomes the third post-close skew day after 09-14 and 09-15 — stale, wide quotes wearing an in-session label, and passing every gate, because of layer 4. If it does not land, today is a permanent hole in a stream that has no heal path (contrast the equity ledgers, which healed from broker truth over the September outage). Either way it is unmarked in CAPTURES.md.

Timing matters here: BTB-1's 60-trading-day clock stands at 50 elapsed (60th = 2026-10-19) against 39 panel days accrued, 11 missing. Days are the scarce input, and this is the class of loss that takes them without saying so.

The pattern is not new and that is the point. DSP-1's own table recorded a missing skew dispatch on 2026-09-14 and 2026-09-15 (single post-close commits at 22:29Z and 22:10Z) and a missing vrp dispatch on 09-16. DSP-1 was dismissed at panel run 25 on the ground of "zero realized harm, and the backstop worked every single day" — which was true of trading, where the backstop is a late trade inside the session. For the capture, the backstop is a post-close observation, which is a different thing from a late one. Today is at least the third occurrence, and it is the first to happen with thales-skew already deleted.

4. Preserved from PR #210, at the owner's request

#210 was closed (not merged) on 2026-10-03 06:27:30Z. The owner's close comment:

"The diagnosis here was correct (an early ping does not satisfy a cron check's later slot). If healthchecks is re-introduced, use this PR's 30 14 reasoning when re-creating the checks."

The record that carried that reasoning rode the closed branch and never landed, so it is restated here in full:

Mechanism. healthchecks sets a cron check's next deadline to the first cron occurrence after the last ping. A ping landing earlier in the day than the check's own expected minute therefore leaves that day's slot unsatisfied, and the check alarms one grace period later. The three sleeve checks were created with the staggered GitHub crons 35 / 40 / 45 14 * * 1-5, grace 8h; the executors then moved twice (2026-09-02, the Mac's dispatch to 14:35Z for all three; 2026-10-02 #201, GitHub's legs to 15:30–15:40Z) and the checks moved neither time. Arithmetic, matched to the second on 2026-10-01: ping 14:37:16Z → next 45 14 occurrence 14:45Z → +8h grace → DOWN | thales-vrp at 22:45:00Z.

The forecast, and its confirmation. The 10-02 audit predicted a DOWN | thales-meanrev at ~22:40Z and a DOWN | thales-vrp at ~22:45Z that night as a falsifiable test of this mechanism. Both arrived: 22:40:03Z and 22:45:00Z. The mechanism is confirmed, not merely plausible.

If the checks are re-created, give each a cron of 30 14 * * 1-5, TZ UTC, grace 8h: ≥5 minutes of margin before the 14:35Z dispatch slot, while an 8h grace still alarms the same evening (22:30Z) and still absorbs a GitHub backup leg delayed to ~20:00Z. Note that momentum's old 35 14 was never safe either — it had zero margin and survived only because its run takes ~15 minutes.

5. What was not done, and why

No detector was built. The fix that would make this loud — a capture-absence or capture-instant leg in the digest's exception list — needs capture state wired into the digest gather, which collects none today, and it lands on top of CQA-3, whose own header marks it "not approvable for build until you rule on the 2026-09-02 B4 append". Building it tonight would both exceed one careful session and step over the owner-only approval gate at research/queue/approved/. It is escalated instead, with the ask stated as a ruling plus an approved row.

Carried in the 2026-10-05 daily audit report.