From 135fb9c65b113a11d9675d5448538e9c4cba60ba Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 23:47:42 +0000 Subject: [PATCH] Stop the Windows bar wrapper discarding the finals gate's answer Found on the real box. The wrapper this repo ships ran --metadata straight after --bars with no guard, and a .cmd exits with the code of its LAST command. So a deferral's exit 1 was overwritten by --metadata's exit 0: Task Scheduler recorded SUCCESS, restart-on-failure never fired, and the task waited until the next day having fetched nothing. That is the precise failure --require-final exists to prevent, reintroduced one layer out. The gate computed the right answer every night and the wrapper threw it away, and the symptom is the one this whole session keeps circling -- a green run that did nothing. The fix keeps the bars exit code and stops there. Skipping --metadata on a defer is deliberate rather than incidental: restart-on-failure turns this task into a poll loop, and each retry should be the cheap date compare the gate is, not a full contract-spec fetch of every symbol against NDU. `if errorlevel 1` tests >= 1 and needs no expansion, so it is safe on one line. `|| exit /b %ERRORLEVEL%` would NOT be, and is worth naming because it is the obvious thing to reach for: cmd expands %ERRORLEVEL% when it PARSES the line, before the command on that line has run, so it returns the previous command's code. On its own line, after the command, it is correct. Not executable in this sandbox -- there is no cmd here -- so this is reasoned from cmd's parse-time expansion rules and from the exit codes on the Python side, which were read rather than remembered: a deferral returns 1, --metadata returns 0. Confirm on the box with Last Run Result on a deferred run: it must be 0x1, not 0x0. --- docs/WINDOWS_SCHEDULING.md | 23 +++++++++++++++++++--- docs/examples/windows/run-prices.cmd | 29 +++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/docs/WINDOWS_SCHEDULING.md b/docs/WINDOWS_SCHEDULING.md index 3a0fef2..d5a578f 100644 --- a/docs/WINDOWS_SCHEDULING.md +++ b/docs/WINDOWS_SCHEDULING.md @@ -34,11 +34,28 @@ Create **two** wrapper scripts — they run *different* commands from *different ```bat @echo off -set MARKETDATA_STORE=REPLACE_WITH_MARKETDATA_STORE_PATH -"REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" --bars --domain futures --require-final -"REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" --metadata +setlocal +set "MARKETDATA_STORE=REPLACE_WITH_MARKETDATA_STORE_PATH" +set "MDEXE=REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" + +"%MDEXE%" --bars --domain futures --require-final +if errorlevel 1 exit /b %ERRORLEVEL% + +"%MDEXE%" --metadata +exit /b %ERRORLEVEL% ``` +> **Those two `exit /b` lines are load-bearing.** A `.cmd` exits with the code of its LAST +> command, so running `--metadata` after `--bars` with no guard lets its exit 0 overwrite a +> deferral's exit 1. Task Scheduler then records **success**, restart-on-failure never fires, +> and the task waits until tomorrow having fetched nothing — the gate answering correctly and +> the wrapper discarding the answer. Skipping `--metadata` on a defer also keeps each retry a +> cheap gate check instead of a full contract-spec fetch against NDU. +> +> `if errorlevel 1` tests `>= 1` and needs no variable expansion, so it is safe. `|| exit /b +> %ERRORLEVEL%` would **not** be: cmd expands `%ERRORLEVEL%` when it parses the line, before +> the command on that line has run, so it returns the *previous* command's code. + `run-cot.cmd` — COT (note the **different** command, `--cot-all`): ```bat diff --git a/docs/examples/windows/run-prices.cmd b/docs/examples/windows/run-prices.cmd index 14cac4a..4d02c79 100644 --- a/docs/examples/windows/run-prices.cmd +++ b/docs/examples/windows/run-prices.cmd @@ -15,6 +15,29 @@ REM REM --require-final defers (exits non-zero, having fetched nothing) until Norgate REM holds a newer settled bar than the store does; pair it with Task Scheduler REM "restart on failure". See docs/WINDOWS_SCHEDULING.md. -set MARKETDATA_STORE=REPLACE_WITH_MARKETDATA_STORE_PATH -"REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" --bars --domain futures --require-final -"REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" --metadata +REM +REM THE EXIT CODE IS THE WHOLE POINT, so read the two lines that carry it before +REM editing this file. A .cmd exits with the code of its LAST command. An earlier +REM version of this wrapper ran --metadata after --bars with no guard, so a +REM deferral (exit 1) was overwritten by --metadata's exit 0: Task Scheduler +REM recorded SUCCESS, restart-on-failure never fired, and the task sat until the +REM next day having fetched nothing. The gate worked and the wrapper discarded its +REM answer -- exactly the stale-bar failure --require-final exists to prevent. +REM +REM `if errorlevel 1` tests >= 1 and needs no expansion, so it is safe here. +REM `|| exit /b %ERRORLEVEL%` would NOT be: cmd expands %ERRORLEVEL% when it parses +REM the line, which is BEFORE the command on that line has run, so it would return +REM the previous command's code. On its own line, after the command, it is correct. +setlocal +set "MARKETDATA_STORE=REPLACE_WITH_MARKETDATA_STORE_PATH" +set "MDEXE=REPLACE_WITH_VENV_PATH\Scripts\marketdata-update.exe" + +"%MDEXE%" --bars --domain futures --require-final +REM Stop here on a defer OR a failure, and keep the code. Skipping --metadata on a +REM defer is deliberate as well as convenient: restart-on-failure turns this task +REM into a poll loop, and each retry should be the cheap gate check rather than a +REM full contract-spec fetch of every symbol against NDU. +if errorlevel 1 exit /b %ERRORLEVEL% + +"%MDEXE%" --metadata +exit /b %ERRORLEVEL%