Repository navigation
Read earnings estimates and bank financials in Google's sparse array form - #6
Merged
Merged
Conversation
…form
Since 2026-10-09 the gl=US earnings calendar sends each event's figure
record in Google's sparse array encoding (a 19-slot list ending in a
{"108": ..} object, or a lone {"9": .., "17": .., "18": ..} object). The
parser accepted only the dense 18/106 widths, so revenue_estimate,
eps_estimate, currency and period_end were null on every event while the
run reported complete; the canary has been red on it since.
The figure record is now expanded (field N -> slot N-1, so the existing
slot map applies) and recognised by its currency and period-end slots
rather than its exact width. That also reads a bank's detailed quarters,
which arrive 105 slots wide: BAC's eight detailed quarters were dropped.
New fixtures cut from real pages: the 2026-10-14 canary dump (gl=US,
both sparse forms), gl=DE on 2026-10-15 (still dense), BAC:NYSE on
2026-10-15. Values pinned; BAC's matched against its rendered table.
make_fixtures.py keeps already-generated fixtures whose capture is absent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before the US open the movers blob is [null, null, [4 most-active]], and early in a session gl=DE had no gainers list. The parser required three populated lists, so --mode movers returned 0 rows (exit 4) and the most-active rows were counted as --mode markets rows instead. Found by a canary dispatch at 12:51 UTC on 2026-10-15. Fixtures cut from that dump and from a live gl=DE page; values pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jehrr
marked this pull request as ready for review
October 15, 2026 13:03
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.
Problem
The scheduled canary has been red since 2026-10-09 on one assertion:
no event carries an estimate. Every--mode earningsrow on gl=US came back withrevenue_estimate,eps_estimate,currencyandperiod_endnull, while the run reportedstatus: completeand exit 0.Cause: Google now sends each event's figure record in its sparse array encoding (protobuf-as-JSON: position i is field i+1, and far-apart high fields go into one trailing object keyed by field number):
[null ×8, 10094598350, null, 1.8334, …, "EUR", [2026,9,30]](18)[…18 slots…, {"108": 12.93, "109": 10.78}](19)[{"9": 1460392943930, "11": 4.52, "17": "TWD", "18": [2026,9,30], "109": 4.51}]The parser only accepted the dense 18/106 widths. Checking further found a second silent loss with the same root: BAC:NYSE publishes its detailed quarters 105 slots wide, so
--mode financialsdropped all eight and its newest row was 2024 Q2.A canary dispatch on this branch at 12:51 UTC on 2026-10-15 then found a third:
--mode moversreturned 0 rows (exit 4) because Google sends a list it has no data for yet asnull—[null, null, [4 most-active]]before the US open,[null, [4 losers], [4 most-active]]on gl=DE early in its session — and the parser required three populated lists (the most-active rows were also leaking into--mode markets).Fix
_jspb_denseexpands the sparse form ("9"→ slot 8 = revenue estimate,"17"/"18"→ slots 16/17 = currency/period end), so the existing slot map applies unchanged._mover_sublistsaccepts a null list; the gainers/losers label check runs on whichever is present, and falls back tomovers_Nwhen neither is. Fixturesmovers_us_premarket(the canary's own dump) andmovers_de_partial(live gl=DE)._fin_figuresrecognises a figure record by structure (currency string at slot 16, date at slot 17) as well as by the two verified widths;detailednow means "carries every mapped slot" (≥ 39) instead of exactly 106.Evidence
canary_earnings.html): 5/5 events now have both estimates, currency and period end (ASML EUR 11,716,143,870 / 10.76; TSM TWD 1,460,392,943,930 / 4.52).earnings_us_sparse,earnings_de_dense,financials_bank, cut bymake_fixtures.py(trimmed fixture verified to parse identically to the capture; no secret-shaped strings). Existing 22 fixtures byte-identical.main'sproduct_parser.pythe new checks fail (11 value checks red, then the decoder check errors); with this branch the suite is green.Not changed
make_fixtures.pynow keeps already-generated fixtures whose capture is not on disk (it used to drop them all), so adding a fixture no longer needs every original capture.🤖 Generated with Claude Code