Skip to content

docs(market-data): the envelope builder states its own reason for returning None, not a claim about what parse accepts - #651

Merged
atomchung merged 1 commit into
mainfrom
claude/laughing-agnesi-bdef8d
Jul 31, 2026
Merged

docs(market-data): the envelope builder states its own reason for returning None, not a claim about what parse accepts#651
atomchung merged 1 commit into
mainfrom
claude/laughing-agnesi-bdef8d

Conversation

@atomchung

Copy link
Copy Markdown
Owner

to_price_feed_envelope justified its None return by borrowing a rule from a different module:

Returns None when the bundle priced nothing — there is no such thing as an envelope with no prices, and parse rightly refuses one.

#647 (closing #642) makes an envelope carrying only fx valid and accepted, so that borrowed justification is about to be false. The rule it justifies is fine; only the reason was wrong.

What this does

States this lane's own reason instead, which is invariant: the envelope is defined over instrument closes and dates itself from them — as_of is max(row date), read off the rows themselves — so with no rows there is no observed session to declare one from.

Deliberately not written as "parse now accepts fx-only envelopes". #647 is still open, so on main that statement would be false today, and permanently false if #647 never lands. Phrasing it as this lane's own rule reads correctly either way, and explicitly disclaims being a restatement of what parse accepts, which is what stops the same drift recurring.

Two smaller corrections in the same docstring:

  • None does not mean only "the bundle priced nothing" — the split-basis rule above can drop everything the bundle did price.
  • Notes that the coverage fact outlives the None (dropped instruments are recorded as gaps on the bundle before the early return), so the return value does not conceal anything.

Mirrored surface: tests/test_market_data.py's test_i_a_bundle_that_priced_nothing_yields_no_envelope carried the same borrowed justification in its own docstring. Corrected there too. The assertions are untouched.

Behavior is unchanged, and that is checked rather than asserted

The diff is provably docstring-only: both files' ASTs are identical to HEAD once docstrings are stripped, and differ only when they are kept.

  • python3 tests/run_all.py → 49/49 suites pass
  • tests/test_market_data.py standalone → 51/51, and the edited test was confirmed to actually execute rather than skip (this suite has no skips at all — worth stating explicitly, since a suite that skips itself and still prints green is a failure mode this repo has hit)

Relationship to #647

No conflict: #647 does not touch market_data.py. This can land before or after it in either order, which is the point of the invariant phrasing.

Filed, not fixed: #648

Noticed while in here. fx is assembled below the if not rows: return None guard, so a bundle that priced nothing but did resolve a currency rate discards the rate. Bundle.usable names that exact state as worth caching, so a bundle can be usable solely on the strength of a rate this function then throws away. Reproduced against the recorded fake provider.

Harmless on main today (nothing accepts a lone rate); #647 is what makes it bite, since that rate is precisely the rate-only repair #642 built the lane for. Not fixed here because it needs a contract decision — what date a rate declares when no close is present to date it from — rather than moving a block. Details and repro in #648.

Closes nothing; #648 tracks the follow-up.

…urning None, not a claim about what parse accepts

`to_price_feed_envelope`'s docstring justified its `None` by asserting "there
is no such thing as an envelope with no prices, and `parse` rightly refuses
one". #647 (closing #642) makes an envelope carrying only `fx` valid and
accepted, so that borrowed justification is about to be false — a host that can
read one public FX rate but not every close can now hand back a rate-only
repair for the #612 refusal.

The rule itself is unchanged and correct; only the reason given for it was
wrong. This lane dates itself from its own rows (`as_of` is `max(row date)`),
so with no rows there is no observed session to declare one from — a reason
that holds whether or not #647 lands, which is why it is stated that way rather
than restating the post-#647 contract on a branch where it is not yet true.

Stated as one condition rather than a list of causes, because the claim being
replaced went stale by enumerating and a first draft of this one repeated the
mistake: it said `None` meant "priced nothing, or the split rule dropped
everything", which a bundle whose only priced symbol is a benchmark falsifies —
that yields no envelope while having priced something the split rule never
touched.

Also corrects the same borrowed justification in the mirroring test docstring.

Behavior is unchanged — the diff is provably docstring-only (ASTs are identical
to origin/main once docstrings are stripped). Flagged while in here and filed
as #648: a currency rate the bundle did resolve is discarded along with the
envelope, because `fx` is assembled below the early return.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@atomchung
atomchung force-pushed the claude/laughing-agnesi-bdef8d branch from 86e74c7 to 98d26f0 Compare July 31, 2026 02:21
@atomchung

Copy link
Copy Markdown
Owner Author

Self-review before merge caught a real defect in the first draft of this docstring, fixed in 98d26f0.

The replacement paragraph originally glossed the None return as "the bundle priced nothing, or the split-basis rule above dropped everything it did price". That enumeration is incomplete. Probed against the recorded fake provider:

request  : instruments=["DEAD"], benchmarks=["SPY"], instruments_only=True
priced   : ['SPY']
envelope : None

The bundle did price something, and the split rule never fired — benchmarks are simply outside this envelope's scope by default. So both stated causes were false while the return value was still None.

That is the same failure mode as the claim this PR exists to remove: an enumeration that was true when written and silently stopped being exhaustive. Rewritten as a single condition — nothing priced was both in scope and reconcilable onto one split basis — which covers all three ways rows empties, and the docstring now says why it is phrased that way so the next editor does not re-enumerate.

Also re-verified the paragraph's other load-bearing claim, that a dropped instrument is recorded as a gap before the early return, so the coverage fact outlives the None. It holds: the resolver stamps symbol_unpriced (DEAD: the provider returned no usable close) before this function is called, and the split-drop path appends its own.

Re-checked after the fix: 49/49 suites, and both files still AST-identical to origin/main once docstrings are stripped.

@atomchung
atomchung merged commit 22417a7 into main Jul 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[defect·P2] The resolver discards a rate it did resolve when nothing else priced — #642's rate-only repair cannot reach consider's live lane

1 participant