STAMP-2 — the trading path shares STAMP-1's UTC-date defect: a midnight-crossing delayed run consumes the NEXT session's idempotency slot, the real session is silently skipped, and the no-run canary reads green
status: open · raised panel run 14 (2026-08-28) · class: loudness & safety (live path) · judgement: YES · effort ~0.5 pd (shares the ET-normalization helper STAMP-1 specifies — build together) · horizon: recurrence now measured twice in three weeks, outage-correlated
Plain-language summary for an owner reading one paragraph. GitHub's runner queue delayed all of yesterday's crons by ~9 hours. The momentum and VRP runs crossed UTC midnight and stamped their records 2026-08-28 — so when today's real crons fire during market hours, both sleeves will see "already ran today" and silently do nothing: no in-session kill-switch pass, no in-session VRP manage pass, for the second consecutive session (08-27's pass did execute — late, after the close). Every detector shows green, because the same wrong date that loses the session also fakes the record the detectors check. This is STAMP-1's defect (open since panel run 2) materializing on the trading path, which STAMP-1 explicitly did not cover.
Mechanism, code-verified. daily.py:1341-1342 and vrp_daily.py:488 default
today = date.today() — the runner's UTC calendar date. The paper-trading
workflows pass --skip-market-check (paper-trading.yml:172,
paper-trading-vrp.yml:88), so no session anchor remains except that UTC
date. state.py:180 (already_ran_today) then uses the same date as the
idempotency key, and daily.py:1360 / vrp_daily.py:498 skip the run when a
run_summary for it exists. A delayed run that starts before midnight UTC but
persists after (momentum: started 23:53:22Z, wrote 00:05:50Z), or fires
entirely after (VRP: 00:00:18Z), stamps TOMORROW — and tomorrow's real run
skips.
It materialised unattended, 2026-08-27→28 (second occurrence of the class; first on the trading path).
- momentum
run_summary {"date":"2026-08-28","vol_check_only":true}written 00:05:50Z (commit 2123220) on evening-of-08-27 equity → the real 08-28 session gets no kill-switch/vol pass (skip atdaily.py:1360). - vrp
run_summary {"date":"2026-08-28","action":"manage:hold"}written 00:01:57Z (9a6615d) → the real 08-28 manage pass is skipped (vrp_daily.py:498). - meanrev started 23:55:55Z — still 08-27 UTC — and stamped correctly; its 55 after-hours selection orders filled at the 08-28 open (TCA damage only). The four-minute spread between meanrev and VRP is the whole difference between "correct" and "slot consumed": the margin is minutes, not hours.
- momentum
equity_historynow carries{"date":"2026-08-28","equity":13687.36}— the 08-27-evening value. Friday's true close will never be recorded: the 08-27→28 return reads ~0 and Monday's row absorbs two days. This series feeds both 09-08 clocks (placebo decision-grade + oos-monitor first verdict). pit_snapshots/2026-08-27.parquet: 123 rows vs trailing median 890 — capture-qa caught it (the one loud alarm of the night; operator emailed 03:38Z).- the skew stream repeated STAMP-1 verbatim: the 03:31Z run stamped 894 skew records / 61,478 chain rows / 8,138 term rows / 14,279 shortability names 2026-08-28 on an 08-27 after-hours basis, QA-green. The 08-27 capture day is a permanent gap, and the real 08-28 session is lost when the 19:00Z run no-ops — now 4 of ~57 accrued dates on the B4-pinned stream holed or mislabelled. Stated honestly: no pinned B4 statistic is threatened — the pin samples one signal date per ISO week and week 35 is covered by 08-26 (893 valid rows, 2.2× the 400-row floor); the residual is that the mislabelled 08-28 rows, if left unquarantined, would be mechanically selected as week 35's signal date under the pin's "last qualifying date" rule (the relabel-vs-quarantine ruling from the 08-06/07 collision memo is still pending and has until mid-2027 to land).
Why this is a new row, not STAMP-1 relitigation (C0). STAMP-1 scopes itself
to the capture writers explicitly. TECH_DEBT.md:661-664 names
daily.py/vrp_daily.py but records only the LABEL error, rated "MED, low
practical" on a premise ("a manual/delayed run… would stamp the wrong trading
day") that stops one step short: the practical harm is not the wrong stamp, it
is the consumed idempotency slot — a silently skipped live session. That
consequence is recorded nowhere for the trading path.
The genuinely new half: the detector is blind by construction — and last
night it fired backwards. The digest's no-run canary
(fleet digest --fail-on-no-run; logic at fleet_digest.py:144-145) asks
"does a run record exist for this trading day?" — and the mislabelled record
satisfies it. Last night the digest itself crossed midnight (started
00:37:41Z), so its today was 08-28, and the sleeve its no-run job
reddened was meanrev — the one sleeve that behaved correctly (stamped
08-27, hence no 08-28 record yet), while momentum and vrp, whose real
sessions are the ones lost, read green off their mislabelled 08-28 records.
One run, a false positive on the healthy sleeve and false negatives on both
broken ones. Tonight it reads all-green while two sleeves skip their real
session. Defect and detector are coupled through the same bad date, the
exact shape GAP-1 recorded for capture staleness (max(date) cannot see
interior/mislabelled holes). A run-record census keyed on the trading calendar
would flag the missing day; nothing keyed on "does a record exist for today"
ever can.
Fix shape (propose-only, owner decides). One ET-trading-date helper — the same one STAMP-1's fix needs; build them together — plus a refuse-or-restamp guard at the two writers: a run whose wall-clock falls outside the stamped ET session (pre-open grace → close+grace) either restamps to the session it actually belongs to, or exits non-zero naming both dates. Never silently consume a future slot. (Whether a late run should still execute a catch-up vol-check for yesterday's session is a design choice the guard makes explicit instead of accidental.)
Kill criterion — pre-registered, negative-controlled in both directions. On
a temp copy with the clock frozen at 2026-08-28T00:05:50Z and 08-27's state in
place, the momentum writer must stamp 2026-08-27 or refuse with a non-zero
exit naming the date — never write an 08-28 run_summary. Negative
control: replay the stamp decision against the actual (date, start-time)
pairs of the 30 scheduled paper-trading runs ending 2026-08-26 — pinned
here so the 08-27→28 midnight-crossing incident runs are excluded from the
must-not-fire set by construction, not by post-hoc argument — and assert the
guard fires on none; replay a
same-session re-run and assert the idempotent skip still holds. Then shadow 20
trading days: if the guard fires on any normally-timed run, revert it and
record the miss as permanent rather than tuning the threshold after the data
exists.
Effort ~0.5 pd. Horizon: not time-critical in code, but each recurrence costs a full session's risk-monitoring pass on every affected sleeve and pollutes the equity series feeding pinned clocks; recurrence is outage-correlated — it fires precisely when the system is already degraded, same as STAMP-1's.
Owner flags recorded with the row (one-time surgery, deliberately NOT part of this row's scope; all propose-only):
- Decide whether to correct
data/processed/equity_history.jsonl's 08-28 row from broker truth before the 09-08 verdicts read the series (backfill-equityfills holes; it does not overwrite wrong values). - The mislabelled
2026-08-28skew/chains/iv_term/shortability files: STAMP-1's recorded recovery trap applies verbatim — a re-dispatch is a pure no-op, and--out data/<anything>silently overwrites;--out /tmp/...is the safe capture path if any of today's real session is to be salvaged before/after 19:00Z. fleet-digest.ymlcarries two contradictory comments about the digest beacon on the no-run path (~line 97-99: "deliberately … keeps the beacon pinging" vs ~line 117-118: "success() is false on the exit-2 no-run path … withholds the ping"). Observed behaviour last night: the beacon pinged. One comment is rot; the weekly audit should pick which is the design.
BUILT — 2026-09-02 (together with STAMP-1)
Outcome: shipped. DailyExecutionWrapper.run and VRPExecutionWrapper.run
resolve today through market_session_date() (the session the run observes:
ET date, pre-open → previous trading day), so a midnight-UTC-crossing run
stamps the session it belongs to and hits the EXISTING idempotency gate for
that date instead of consuming tomorrow's slot. The fleet digest's no-run
canary judges the same session date (the backwards fire of 08-28 cannot
recur). The design choice the row left explicit — catch-up vs refuse — is
answered as RESTAMP: a late run belongs to the session it observed; if that
session already ran it is the idempotent skip, if it did not it is the
catch-up. The divergence from the UTC date is logged loudly either way.
Route — recorded honestly: built on the owner's direct instruction in an
interactive session (2026-09-02 self-audit, finding M4), NOT via
queue/approved/; a human merges.
Kill criterion — met, negative-controlled both ways
(tests/test_utils/test_market_session_date.py): clock frozen at
2026-08-28T00:05:50Z with 08-27's state in place → the momentum wrapper
resolves 2026-08-27 and takes the "Already ran today (2026-08-27)" skip —
no 08-28 run_summary is written; the VRP instant 00:00:18Z likewise.
Negative control: the stamp decision replayed against the actual creation
instants of the 30 scheduled paper-trading runs ending 2026-08-26 (pinned
in the test, incident runs excluded by construction) fires on none —
every one stamps exactly its UTC date; a same-session re-run still takes the
idempotent skip. The 20-trading-day shadow the row asks for starts at merge.
Owner flags from the row: (1) the 08-28 momentum mark was corrected from broker truth in PR #125; VRP's 08-28 mark remains the known phantom (backfillable, no clock before ~Jan 2027); (2) the mislabelled 08-28 capture files remain as recorded in CAPTURES.md pending the relabel-vs-quarantine ruling; (3) the two contradictory fleet-digest beacon comments are untouched here (weekly audit's call).
Provenance recorded by triage 2026-09-07 (annotation only; the record above is untouched): shipped in PR #132 (100cf61, merged 2026-09-03), jointly with STAMP-1. The built section above cites #125 only for an owner flag, not for the shipping merge.