Correct the retry mechanism: trigger repetition, not restart-on-failure - #22
Merged
Merged
Conversation
This README told you to give the bars task a **restart on failure** to turn "fire at 9pm" into "run the moment the Finals land". That does not work, and it did not work in production. Task Scheduler's "if the task fails, restart every N minutes" fires when the scheduler cannot LAUNCH the action. It does not fire on a non-zero exit code from the action -- which is exactly what a `--require-final` defer is. A run whose action returns 1 is recorded as event 102, "Task Scheduler successfully finished", and no restart is scheduled. Measured on the reference box, which had RestartCount 20 / RestartInterval PT15M set on that task: 2026-08-12 to 08-15, the action returned exit 1 each night and the task was launched exactly once each night. Four consecutive nights, no retry, no bars captured. Events 111 and 322-324 never appeared at all. The failure stayed invisible because the gate self-heals -- a missed night is captured by the next run that finds Norgate ahead of the store -- so the data was never permanently wrong, only a day late, and `--check` a week later looked fine. The fix is a repetition on the trigger, which fires on schedule regardless of what the previous run returned. cotdata's guide has carried the correction since #111; this page and docs/design.md were still giving the old advice, which is worse than no advice: a reader who follows it believes the gate has a retry loop behind it. Also documents the equities producer, which had no coverage here at all. It is a separate task rather than a step in run-prices.cmd for three reasons, all of which survive the change above -- the futures wrapper exits early by design, the two halves fail differently, and Yahoo needs no finals gate. Includes why it takes neither --require-final (refused, not ignored) nor --metadata, why it must be daily rather than weekly, and why its retry belongs inside the wrapper rather than on the task. "Two producers" on the Windows box is now three scheduled producers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mspinola
force-pushed
the
claude/correct-restart-on-failure-advice
branch
from
August 21, 2026 12:47
63cb9e1 to
a8a42c8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The advice was wrong, and it was wrong in production
This README told you to give the bars task a restart on failure to turn "fire at 9pm" into "run the moment the Finals land". That setting fires when the scheduler cannot launch the action. It does not fire on a non-zero exit from the action — which is exactly what a
--require-finaldefer is. Such a run is recorded as event 102, "Task Scheduler successfully finished", and no restart is scheduled.Measured on the reference box, which had
RestartCount 20/RestartInterval PT15Mset on that task:It stayed invisible because the gate self-heals: a missed night is captured by the next run that finds Norgate ahead of the store, so the data was never permanently wrong, only a day late, and
--checka week later looked fine.The fix is a repetition on the trigger, which fires on schedule regardless of what the previous run returned:
cotdata's guide has carried this correction since mspinola/cotdata#111. This page and
docs/design.mdwere still giving the old advice — which is worse than no advice, because a reader who follows it believes the gate has a retry loop behind it when it has nothing.docs/design.mdmattered as much as the README here: the finals-gate design section explained the exit-code contract and then named restart-on-failure as the thing that consumes it. The gate's whole design assumes something re-runs it, so naming the wrong mechanism undercuts the design it is documenting.Also: the equities producer had no documentation here
The Windows box runs three scheduled producers across two packages; this README described two. Adds Scheduling the equities half, covering:
run-prices.cmd— the futures wrapper exits at its first command once the futures half has captured, so anything chained behind it is unreachable on the repeats; a single flaky Yahoo symbol fails the whole equities run and would otherwise abort the futures replica syncs; and Yahoo needs no finals gate, so it can run at 17:30 and stay clear of the 20:55 task's replica mirroring.--require-final— futures-only, and refused rather than ignored (update.pyexits 2). The protection comes from cadence:period="max"+ full-parquet replace means every run restates the whole history, so a provisional bar captured today is overwritten tomorrow. That is why the task must be daily — the store keeps no per-bar provisional flag, so on a monthly cadence a bad capture sits unmarked for a month.Tests
205 passed, 12 deselected(-m "not network"). Docs-only change; no source touched.🤖 Generated with Claude Code