fix(tooling): summarise the whole list in the probe, and restore the field it hid - #232
Merged
Conversation
…field it hid `shape_of` reduced a list to `[shape_of(value[0]), "... N items"]`, so every probe validated ONE element and reported a match for the whole collection. Live, `trading_pairs` returns 89 pairs in two distinct key-sets: 63 carry `min_order_amount` -- BTC-USD (`0.1`) and ETH-USD among them -- and 26 do not, and `results[0]` is BILL-USD, one of the 26. The probe reported 5/5 and then 6/6 matched while blind to a field present on 71% of pairs, including every asset keel trades. #218 then deleted that field from `rh_trading_pairs.json` believing the report, and #198's prerequisite list, the README and `get_trading_pairs`' docstring all record "the venue exposes no minimum-order field" on the same basis. `shape_of` now merges every element of a list: the union of the keys, with a key carried by only some elements marked `min_order_amount (63/89)`, and a key the venue types inconsistently across elements rendered `Decimal|str (77 str, 12 Decimal)` rather than silently taking the first. One summary row and a count come back however long the list is. A partially present key is compared as an ordinary key. A fixture is one representative object and cannot say "63 of 89", so the convention is that it carries the UNION of what a row can hold -- `rh_trading_pairs.json`'s row is BTC-USD, which is sent the minimum -- and the count reaches the operator through `annotations_in` as a note printed after the verdict, not as a difference. That makes the #218 regression a reported `NEW AT VENUE` and a correct fixture a clean match, without failing every run against a venue behaving exactly as measured. A mixed type is not bare-equal to either of its halves, so it still reports `TYPE DIFFERS`. Also restores `min_order_amount` to the fixture with BTC-USD's real `0.1` (and its real `max_order_size`, `20.0000000000000000`), corrects the README section and the transport docstring, and scopes the module docstring's shape-validation claim: a run corroborates only what the account's data exercises, and the `orders` probe on an account with no history still proves path, signature and envelope only. The read-only guarantee is untouched. Closes #230 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Closes #230.
D1 —
shape_ofonly ever inspectedresults[0]It reduced a list to
[shape_of(value[0]), "... N items"], so every probe validated one element and reported a match for the whole collection. Live,trading_pairsreturns 89 pairs in two distinct key-sets: 63 carrymin_order_amount(BTC-USD0.1and ETH-USD among them), 26 do not — andresults[0]is BILL-USD, one of the 26. The probe reported 5/5 and then 6/6 matched while blind to a field on 71% of pairs, including every asset keel trades.shape_ofnow merges every element: the union of the keys, a key carried by only some of them markedmin_order_amount (63/89), and a key the venue types inconsistently renderedDecimal|str (77 str, 12 Decimal)instead of silently taking the first. One summary row and a count come back however long the list is — an 89-pair response never prints 89 shapes.How a partially present key compares against a fixture
A fixture is a single representative object and cannot express "63/89", so the convention is that the fixture carries the union of what a row can hold, and the count is reported as information rather than as a mismatch.
rh_trading_pairs.json's one row is BTC-USD, and BTC-USD is sent the minimum, so:min_order_amount→NEW AT VENUE results[].min_order_amount— the fix(brokers): read robinhood's real estimated_price shape, correct every fixture #218 regression, now catchable;Mechanically: every note lives in a trailing
(...)suffix on the shape token, andcompare_shapescompares tokens with that suffix stripped. It rides on the key, so a partially present key whose value is an object is annotated the same way as one whose value is a leaf, and it survives--jsonverbatim. Treating partial presence as a difference instead would fail thetrading_pairsprobe on every run against a venue behaving exactly as measured — the same cry-wolf failure #217 F5 taught this script to avoid.A mixed type is deliberately not bare-equal to either of its halves, so it still reports
TYPE DIFFERSwith both tallies in the message. At a venue already caught quoting the same kind of value two ways in one object (#217 F6), that is a finding, not a formatting detail.The report, on the measured 63/26 split
and in
--json:That exact run — 89 rows, BILL-USD first, 63 carrying the key — is asserted end to end in
test_the_real_63_of_89_split_matches_the_fixture_and_is_reported, including exit code 0 and the note line.D2 — the regression
min_order_amountis restored totests/fixtures/rh_trading_pairs.jsonwith BTC-USD's real0.1. The row'smax_order_sizeis corrected to the measured20.0000000000000000at the same time (it read10.00000000); the increments were already correct.The false claim is corrected in
packages/keel-broker-robinhood/README.md(§ "No published minimum order size" → "The minimum order size is published, but only on some pairs"), inRobinhoodTransport.get_trading_pairs' docstring, and in the two suite tests that asserted the field's absence. Dated documents underdocs/experiments/are left alone. #198's prerequisite list still needs its comment corrected —min_order_amountis a lower-bound source for every asset keel trades, read as optional per pair.D3 — regression test
test_a_key_only_a_LATER_element_carries_is_still_reported. Against the oldshape_of:Also
The module docstring's shape-validation claim is now true and scoped: a run corroborates only what the account's own data exercises, and no report line distinguishes "the venue has no such field" from "this account produced no row carrying it". The
ordersprobe on an account with no crypto history still proves path, signature and envelope only, never field names.The read-only guarantee is untouched —
_ReadOnlystill installs the GET-only guard onto_request, andtest_running_every_probe_issues_only_gets(including the probes-actually-succeeded assertion) passes unchanged.Gates
2444 → 2455 is the 11 tests added here; the one skip is the expected conformance candles probe.
Not run live — this branch has no credential. The proof is in the tests; a live re-run against the venue is yours.
References #218 (removed the field) and #198 (carries the false claim).
🤖 Generated with Claude Code