2026-10-09 — the cutover landed, and the one email arrived cut
Daily audit record. Window 2026-10-08 22:30Z → 2026-10-09 22:30Z (Friday).
Three things happened today that are worth keeping: the tbx-win cutover succeeded and the fleet traded off GitHub Actions for the first time; the first Friday digest under the owner delegation was delivered with all five of its owner decisions cut mid-sentence; and a position the risk layer has been trying to exit since August turned out to be un-exitable, with no alarm ever raised.
1. The cutover happened, and the evidence is a commit trailer
scripts/win/cutover.sh squash-merged its own docs PR #206 at
2026-10-09 01:00:22Z (HEAD c680133) and then removed its own launchd
agent. From that point the Windows box runs the day locally and pushes state,
rather than dispatching GitHub workflows.
Today's state commits carry Runner: tbx-win:
| leg | commit | time (UTC) | trailer |
|---|---|---|---|
| vrp | 6b9029d | 14:37:04 | Runner: tbx-win |
| momentum | f179461 | 14:56:11 | Runner: tbx-win |
| meanrev | fc572e7 | 15:02:04 | Runner: tbx-win |
| skew capture | 4688879 | 19:08:20 | Runner: tbx-win |
4 of 4 legs, on the first day, including the skew slot — the one that missed 5 of its last 16 sessions (31%) from the Mac. The GitHub backup crons fired later and behaved as designed: meanrev and vrp stopped at their cheap bash early-exit in 16 and 18 seconds, and momentum ran full-fat for 13 minutes (by design — it is the leg that keeps the daily pre-trade test gate) and committed one macro parquet, no trades, the idempotency gate holding.
Two residuals worth naming rather than assuming away:
- The box's real
commit()/push()path and a non-drythales runexecuted for the first time ever today. The three practice gates certified dry runs only (scripts/win/session.py:332,live_onlysteps skipped under--dry-run), as panel run 38 re-verified. Today's four clean commits are the first evidence of the live path, not a continuation of it. - A session that trades and then fails
persistleaves real broker positions with no state commit, which is observationally identical to "the box never ran".thales portfolio reconcileis the discriminator; theRunner:trailer alone is not. No cloud routine can run it (no broker credentials).
2. The one email the owner reads cut every decision in it
Since 2026-10-07 the Friday fleet digest is the owner's only email, and the
NEEDS-OWNER: lines in it are the decisions the steward may not make for him.
Both renderers cut each one at n[:240] — fleet_digest.py:828 (text) and
:1051 (HTML).
ops/STEWARD.md pins the field order <decision> — <recommendation> — <deadline> (:243) and requires a one-paragraph recommendation (:64). The
cap therefore discards exactly the payload. Measured on the real reports behind
today's 20:25:54Z send:
| ask | chars | what the owner did not receive |
|---|---|---|
| 1 tbx-win cutover | 655 | My recommendation: spend ten minutes before 10-16 reading the cutover log… |
| 2 B4 post-close append | 590 | My recommendation: countersign with a 60-minute grace past the close… |
| 3 the 60-day unit | 408 | My recommendation is captured sessions, because the criterion's own test… |
| 4 FRZ-1 | 263 | …1's ruling waits on it. |
| 5 VRP twin total | 344 | Record the choice as a dated append before the gate matures (~2027-01). |
5 of 5 truncated; the word "recommendation" appears zero times in the email, though three of the five asks contain one. Fixed in #233 (both twins, four observability-tier tests, both caps negative-controlled independently).
Found by panel run 38 (research/queue/open/nol-1-owner-decision-lines- truncated.md, #232) hours before the send; verified here against the live
function and the real reports.
The lesson is not the cap. It is that yesterday's fix (#228, the inclusive lower edge) made each report reach exactly one Friday digest — which also makes every rendering defect in that path permanent rather than merely late. Ask 1's recommendation concerned a deadline of 10-16; it had one delivery and lost it. Exactly-once delivery raises the cost of every bug downstream of it, and nothing in #228 or in this system's records said so.
3. #224's refresh could never fast-forward — and today was its first exercise
#224 (merged yesterday, to stop the false SLEEVE DID NOT RUN — meanrev of
10-07) gave the digest job two halves: wait for an in-flight sleeve run, then
git pull --ff-only so the detector reads that run's state. The second half
cannot work: the Restore data cache step writes into data/macro, which is
tracked, so the tree is dirty on every run, and git refuses a fast-forward
that would overwrite a modified file. Every momentum state commit carries a
data/macro parquet (8 of the last 8), so the refresh fails on precisely the
commits it exists to pick up.
Today, run 37986381726: the wait worked (7 polls), then
error: Your local changes to the following files would be overwritten by merge: data/macro/credit.parquet → could not fast-forward main.
It passed on 10-08 only because there was nothing to fast-forward to, which
prints state already current and is indistinguishable from success. A green
you cannot believe is worse than a red. Fixed in #234, with the real failure
reproduced in a scratch clone and the same pull then succeeding.
No harm today. The live harm case is momentum pushing after the digest's checkout: the wait succeeds, the pull refuses, and the no-run canary falsely names momentum — the 10-07 incident with a different sleeve.
4. meanrev's largest position cannot be sold, and nothing has ever said so
AVB was bought on 2026-08-14. That is its last successful order. Since
2026-08-17 every attempt to exit it has failed at the broker with
APIError: {"code":40010001,"message":"asset AVB is not active"}:
- 22 failed orders over 22 attempted sessions (08-17 → 09-18, then 10-09 — the gap is the September Actions outage plus days the exit rule did not fire).
- 21 of 22 were sells, 19 of them
cause: emergency_exit— i.e. the risk layer's forced-exit rule, firing correctly and unable to execute. - As of today's live broker read it is still meanrev's #1 holding at 1.1% of the sleeve.
WBDjoined today with the same error on aselectionbuy (first failure in 11 orders since July).
What never happened: no alarm, in two months. The surfacing is a
##[warning]meanrev: 2 NEW failed order(s) annotation on a green run, plus a
!! 2 FAILED order(s) line in the digest body. The annotation is keyed on
newness, so a symbol that fails every day is new once and silent thereafter,
and the digest line was in a daily email that is now weekly. Nothing anywhere
tracks persistence: a position the book has decided to exit and cannot.
Two reasons this matters despite meanrev being the never-promotable negative control:
- Kind, not size. "An order failed" is routine. "The risk layer decided to
exit and the broker refuses, every session, for two months" is a different
class, and it is the class a kill-switch depends on being able to act in.
Momentum shares the same broker path (its one lifetime failure,
SATSon 2026-07-01, was the same shape). - It silently distorts the control arm's own record — the placebo it exists to provide — alongside the known min-notional residue (today: 184 sells wanted, 37 submitted; 287 broker positions against 131 targets).
Deliberately not fixed tonight. The remedy divides cleanly: dropping broker-deactivated assets from a tradable universe is trading-path logic, not an observability change, and so is outside this routine's rails entirely. The detector — raise an exception when a symbol's exit has failed N consecutive sessions — is in the rails, but its threshold and its escalation path are design choices, and a badly-calibrated new alarm trains the operator to ignore the class. That belongs in a pre-registered queue row ruled on by triage, not improvised by a routine at 22:30Z. Recommended to Monday's triage; escalated to the owner for the universe half.
5. What else held
The trading day was clean. No halt file at any sleeve or fleet level; both
weights sleeves' kill-switches inactive and stamped 2026-10-09; momentum
drawdown 7.78% and meanrev 2.94% against 20% triggers; gross 0.28× (binding
constraint vol_target) and 1.03× against a 3.0 cap; zero safety HALTs or
REJECTs. VRP opened a new cohort (SPY 764/763P, 2026-11-06, 28 DTE, $0.11/sh
credit, $89 max loss). Every capture stream passed QA on today's data. All 138
config keystones match. Full suite 1,749 passed / 1 skipped with both of today's
fixes in. The go-live clock is 83 / 126 live trading days; the VRP forward
gate 53 / 126. September's 8-day capture notch across 7 streams is
unchanged and permanent.
The outbox channel reconciled cleanly for the first time end-to-end under the
new policy: yesterday's report pushed 22:25:33Z, the relay logged
1 report(s) withheld from email by owner policy (weekly_digest_only) -- this branch is the record; the steward reads it, and the steward then merged #228
and #176 — both of yesterday's escalations — within 40 minutes.
Addendum, same evening — the two skew legs are complementary, not duplicates
Written after the report went out, because the fact is easy to misread and the misreading touches a decision the owner has open.
A second skew: snapshot 2026-10-09 commit landed at 23:09:01Z
(634fa7b), four hours after the box's in-session capture at 19:08:20Z
(4688879). The obvious reading — GitHub's backup cron re-ran the capture and
overwrote an in-session snapshot with a post-close one — is wrong, and it
matters because "post-close disqualifies" is exactly the B4 question awaiting
the owner's ruling.
What the two commits actually touched:
19:08Z, Runner: tbx-win | 23:09Z, GitHub backup cron | |
|---|---|---|
options_chains/2026-10-09 | ✅ written | — |
options_iv_term/2026-10-09 | ✅ written | — |
options_skew.jsonl | ✅ 883 records | — |
shortability/2026-10-09 | ✅ written | — |
short_volume/2026-10-08 | ✅ written | — |
short_interest/2026-09-30 | — | ✅ written (new file) |
Nothing was overwritten. The backup leg added exactly one file the box had not: the bi-monthly consolidated short-interest parquet, which is on a different cadence from the daily time-gated streams and was genuinely missing. Every daily stream kept its in-session capture.
So the post-cutover arrangement for this workflow is two legs with different jobs, not one leg running twice:
- the box, 12:00 PT / ~19:00Z — the daily time-gated streams, captured in session, which is the whole reason the slot exists;
- GitHub's cron, ~23:00Z — a late net that writes only what is still absent, so it contributes the off-cadence files and no-ops on the rest.
Two consequences worth holding. First, a 23:0xZ skew: snapshot commit is
not evidence of a post-close capture of the time-gated streams, and must not
be counted as one in the B4 census — check the commit's file list, not its
timestamp. Second, the options_iv_term post-close count that ask 2 of today's
digest cites ("15 of the 37 term-stream days were captured entirely after the
close") is a pre-cutover statistic: from 10-09 forward the box captures that
stream in session, so the ratio stops growing. That strengthens the owner's
option of countersigning a grace window rather than disqualifying post-close
days — the population it would disqualify is now closed, not open-ended.
This also corrects one phrase in the report sent at 22:30Z, which called the pending backup legs "pure duplicates anyway". They are not duplicates; they are a complement. No check or conclusion in that report changes — captures were PASS on either reading.