C.W.K.
Stream
Lesson 02 of 05 · published

One Primary, Confirmed Fallbacks

~11 min · provider-policy, fallback-discipline, confirmation, unattended

Level 0Open Gate
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"A fallback that happens without you noticing isn't a safety net — it's a source change you didn't agree to."

The provider hierarchy is explicit

For equities and indices, Keep has a single primary provider (Massive, a Polygon-backed source) and two named fallbacks (Yahoo Finance, Stooq). The word doing the work is named. This isn't a fuzzy "try whatever works" chain. There is a designated primary, and there are specific, known alternates — and moving from one to another is never automatic. Equity fallback requires explicit one-request confirmation: a human has to say "yes, use the alternate for this request."

Why silent fallback chains are a trap

The convenient design is a chain: try provider A, on failure try B, on failure try C, return whatever you get. It feels robust. It's actually a quiet way to lose track of your own data's origin. When A is flaky and the app silently serves B, your numbers subtly change source — different ticker conventions, different close times, different rounding — and you have no idea it happened. You end up comparing a Massive close from Monday against a Stooq close from Tuesday and wondering why the math feels off. A silent fallback trades a visible failure for an invisible inconsistency, which is a worse deal.

Changing the source of a number is a decision, not a retry. Retrying the same source is mechanical and safe to automate. Switching to a different source changes what the number means, and that deserves a human's explicit yes. Automate retries; confirm substitutions.

The unattended rule: scheduled refreshes never fall back

Here's the sharpest edge of the policy. Keep runs a daily refresh with no human watching. That job is forbidden from falling back at all. Why? Because the whole point of a fallback is a human confirming the substitute — and at 6:31 in the morning, unattended, there's no human to confirm. So rather than silently record a fallback source into the durable daily snapshot, the scheduled job simply uses the primary or fails honestly, and the failure surfaces as a warning. Confirmation-gated fallback and unattended operation are incompatible, so the unattended path refuses fallback entirely.

Beware the fallback that's safe interactively but dangerous unattended. A confirmation dialog is a fine gate when a human is present. Copy that same fallback logic into a cron job and the gate silently disappears — nobody's there to answer, so it either hangs or auto-proceeds. Any behavior that depends on human confirmation must be explicitly disabled on the unattended path, not just left to "nobody will click it."
Some instruments have a policy fallback by design. A few values (WTI, Gold) use a specific provider by policy rather than as an emergency fallback — that's a deliberate primary choice for those instruments, not a silent swap. The rule isn't 'never use provider X'; it's 'never change the source of a value without that change being a named, intended decision.'

Code

Retry is automatic; substitution is confirmed (illustrative)·python
def quote_interactive(ticker, *, confirmed_source=None):
    try:
        return fetch(PRIMARY, ticker)          # retrying PRIMARY is fine
    except ProviderError as e:
        if confirmed_source is None:
            # Do NOT silently swap. Ask the human first.
            raise FallbackConfirmationRequired(candidate=next_fallback(ticker))
        return fetch(confirmed_source, ticker)  # only a confirmed alternate

def quote_scheduled(ticker):
    # Unattended: no human to confirm, so NO fallback. Primary or honest fail.
    return fetch(PRIMARY, ticker)   # raises on failure; surfaced as a warning

External links

Exercise

Design a fetch with one primary source and one fallback. Write two entry points: an interactive one (a human is present) and a scheduled one (nobody is). For the interactive path, make the fallback require confirmation. For the scheduled path, decide what happens on failure WITHOUT falling back. Then explain why copying the interactive logic straight into the scheduled job would be a bug.
Hint
The trap is a single fetch() function used by both paths. Interactively its confirmation prompt protects you; in cron there's no one to prompt, so the same code either blocks forever or quietly does the thing it was supposed to ask about. The unattended path needs its own, fallback-free rule.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.