Conversation
This was referenced Aug 26, 2026
Closed
Closed
Closed
Closed
Closed
The page is read from three clients: the two it compares against and this one. Installing the two was half the fix — the job that regenerates every generated file and compares it against what is committed does not build the extension, so `import ibx` fails there and the whole table of what this client carries beyond the documented surface drops out of the page it produces. The comparison moves to the job that already builds the extension for the Python suite, and that job installs the two reference clients beside it. Nothing else needs a second Rust build. Reproduced before committing: a regeneration against the pinned clients and a freshly built extension leaves `docs/` and the readme unchanged, which is what the runner does. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The venue states a count of entries and then a currency and a balance for each.
This client read the count as a selector saying which figure followed, and took
the last balance on the frame as its value — so it published "an account figure
of kind 3" carrying a number that belonged to whichever currency came last,
under a label that named nothing at all.
Captured whole from a live session:
6040=77 1=DU… 6566=3 15=BASE 9806=1492751.1917
15=GBP 9806=1105714.0700
15=USD 9806=0.0000
and the sterling figure is that account's cash balance in sterling to the penny,
which it already states under a name of its own. So the frame carries nothing a
caller does not have, the kind was never a kind, and the diagnostic that said
otherwise is gone rather than reworded.
Two statements go with it. The estimated-opening record carries up to three
prices and two of them reach no caller; the documented API has one number for
it and this client will not pick a second, so the ones not handed over are
written down under their position rather than passing unseen. And the insider
and institutional series was documented as stating a float. It does not: it
states what institutions and insiders hold, the day each was counted, and how
many shares are on issue, and a float is worked out from those.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
… venue states one Tick 586 carries three prices and a set of flags. The flags say which of the three the venue is actually stating: all three where the estimate stands, the first alone once the figure is final, and none otherwise. The note this client keeps of the prices it cannot hand to a caller was written without consulting them, so it named a price under flags that state none, and named the third position under flags that state only the first. It now writes down a position only where the flags make it a price, and only where that price is a number, which is the same bar the published prices clear. Two explanations went with it. The dispatch comment above the company series said an ownership reply states a float; it states what institutions and insiders hold beside the shares on issue, and a float is worked out from those.
… read The venue states what it holds about the company behind a contract, and about the terms of dealing in it, as runs of KEY=VALUE text on a series of its own. This client read three of those series and let the other thirteen go past: the ratios it keeps a history of, how a company scores against the principles an account can screen on and whether it passes a religious screen, what margin a contract takes and what a fund will take part in, the technical readings, the fund-family figures, the two scores worked out from what is written about the company, the lens over its accounts, and the reference price. They are read now, and reach a caller through the same two calls the three already did — company_data and company_data_series — keyed by the venue's own number for the series, with the venue's own field names unchanged. What separates them is only the frame in front of the text. Two analyst ratings are text from the first byte. Four series state four bytes of their own first. The remaining ten state the text's length as a count and pad what follows to a four-byte boundary, so reading to the end of the payload puts padding inside the last value and trusting a length that overruns reads bytes that never arrived. Both are now read as the venue frames them. Five of the series state their text in an alphabet of one byte to the character. Held to the alphabet the rest are read in, a single accented character made the whole record unreadable and nothing at all was published for it. The request already sent any series a caller named by number, so nothing changes in what goes out.
…wn count The venue states that series' text behind a count of its length, and this client read it as text beginning at the first byte. The count's low byte is a letter for any record between sixty-five and ninety characters long, or between ninety-seven and a hundred and twenty-two, and that letter then joined the first name in the record: three contracts subscribed at once stated the same field under three different names, each one the length of its own record. Read from behind the count, the three state it under the one name. The first analyst rating is stated the same way and was read the same way; its records are long enough that the byte which leaked was punctuation rather than a letter, so the name it produced was the right one and the fault did not show.
… session The venue leaves figures out of the option model it publishes, and this surface hands those on as nothing at all, which is what a caller written against the reference client is given. The wrapper's own method declared them as numbers, so that method refused the call, and the refusal travelled out of the reading loop and closed the session. It reached any caller that watched an option and did not write `tick_option_computation` itself: one model without a dividend in it and the session was over. Every test here had written the method, so the default was never the one called.
…read The venue states figures about a contract on series the documented API has no call for: a bond's analytics and its accrued interest, the margin a future takes, what one contract delivers, the volatility its own model settles on, the volume a contract usually opens and closes on and what an average minute trades, the close it keeps through the session and the close stated in money, what an option is worth in and out of the money and what of that is time, the yield it works out from a price, the two halves of a sentiment reading, what a perpetual contract funds at, and a dozen more. They reach a caller through stated_figures and stated_figures_series, on both surfaces, keyed by the venue's own number for the series. The figures arrive in the venue's order, read at the venue's widths, with the number it uses to say it holds nothing left standing. None of them is republished under a tick number of this client's own choosing: a caller reading the venue's numbers would be reading an invention. Three of the series end with fields the venue writes only sometimes, so a record that stops short states the fields before it and no more. Read against a live session on a share, an option, a future and an index. The deliverable per contract came back as the contract's own multiplier times its modelled price on each of them, the twenty-day volatility as the daily figure for three shares whose volatilities differ threefold, and the four-week volume as a figure that states a count, a flag and a second figure rather than the two counts a record of two long figures would have made of it.
Four series state their figures as two numbered tables — whole numbers first, then fractional ones, each opening with how many entries it carries and each entry naming what it is before stating it. One of the four was read for the two numbers that have a documented call to arrive on and for nothing else; the other three were not read at all. All four are read by one reader now, and every figure is kept under the number the venue gave it, reachable through numbered_figures and numbered_figures_series on both surfaces. The two numbers that have a documented call still go out as the ticks they always did, and the share count and the year-ago open are still kept against the contract as before. The figures that have no documented call are not republished under a tick number of this client's own choosing: read for a fixed list and dropped otherwise, a figure the venue started stating went unseen until someone here wrote its number down. The two tables are kept apart because the venue numbers them apart: the whole table states four bytes to the figure as a count and the fractional one four bytes as a fraction, so the same number in each is not the same figure. Read against a live session on three shares. One of the three series states its figures against a span of days and dates each one, giving nine points of a contract's price history back to five years on a single tick; another states the average close over thirty days; the third states one month and twelve months back. Their five-year points matched what those contracts traded at.
…e are read Three more of the venue's series reach a caller. Two of them state a run of paired figures: a count, then that many pairs of two eight-byte figures. One holds the volatility the venue's own model puts against each point of a curve; the other holds the weight it puts on each price a contract might reach, and states a version in front of its count and a figure of its own behind the pairs. They reach a caller through paired_figures and paired_figures_series on both surfaces, under the venue's own number. The third is the same option model this client already reads, worked out as the contract closed rather than as it stands — the same shape down to the flags that say which fields it carries, so it is read by the reader that already existed. It is kept apart from the standing model and reached through closing_option_model, because a figure worked out at yesterday's close standing where a caller reads what a contract is worth today is worse than not having it. That model carries every greek the venue states, including the several the documented API has no field for at all. Asked for and acknowledged on a live session against two options, and none of the three stated anything: the venue assigns each a subscription and then answers with silence, which is how it answers a series an account cannot see. The third is the model at the close and the session was hours before one. So these are read but not yet seen, unlike the series already landed.
…ing model is The venue serves its option model only to a subscription that names the model's own venue rather than the one the contract trades on. The model worked out at the close is the same kind of record — same flags, same fields, same reader, differing only in which moment it was worked out for — and it is asked for through the same path. It was going out on the contract's own venue. This does not make that model arrive. Asked for either way it is acknowledged and then never stated, on a paper and a live login for the same account minutes apart, so what withholds it is not the venue named in the request.
…or the default that broke The page on what the API does not forward now covers the contract series. A quote subscription carries dozens of them — the venue's own named fields as text, figures at the venue's widths, two numbered tables, runs of paired figures, and the option model as a contract closed — and the page shows how to ask for each and what came back on a real session. One of the numbered series is a five-year price history with the date of each point, off a quote subscription and with no historical-data request behind it. It also states plainly that a series can be refused by silence: the venue acknowledges the subscription, assigns it a tag and says nothing, which is how it answers a series an account is not entitled to. Six behaved that way on the session this was written from, identically over a paper and a live login, so an empty result means either the venue has nothing for that contract or the account cannot see that series. And a check, because the suite structurally cannot see what it guards. The dispatcher hands a caller nothing at all for a figure the venue left out. A wrapper method declaring that figure as a number refuses the call, and the refusal leaves the reading loop and closes the session — on every caller that did not write the method itself. Every test here writes its own, so the broken default was never the one called. The check reads each call against the signature it lands on and fails when one could be handed nothing it cannot take.
Reading what the venue states about a contract's company meant going through the shared state and the reference store by hand — three hops and a type a caller should not have to name. The two calls the Python surface has always had are on the Rust client now, beside the other market data reads. Read by the venue's id for the contract rather than by request number, because what these state is a fact about the contract and outlives the subscription that fetched it.
The venue states a contract's calendar — what the company has coming and when, in which time zone — as the same runs of KEY=VALUE the rest of the company series state, behind eight bytes of its own and compressed. It was the one of these series this client did not read. It reaches a caller through the same two calls the other sixteen do, under the venue's own number, with the venue's own field names unchanged. What it inflates to is bounded the way every other inflate here is: what arrives is bounded on the wire and what it becomes is not. Bytes that are not what the venue compressed publish nothing and leave what it last stated standing, rather than replacing it with whatever they happen to inflate to.
…ng them Five places said sixteen and listed the series without the calendar, which was read after they were written. The count and the lists now match what the dispatch reads.
What one contract states is kept for the life of the session and is not dropped when the subscription that fetched it ends, because it is a fact about the contract rather than about the watch. That was three series and is now seventeen, so the cost per contract grew with it: about twenty-three kilobytes for a share that states every one of them, held against contracts a session has watched rather than the ones it is watching. A program watching a few hundred contracts will not notice. One sweeping a scanner across thousands is holding a couple of hundred megabytes of this, and should be able to find that out from the call that returns it rather than from a memory graph.
…he ceiling Every job now states how long it may take. None did, so a step that stops making progress sat until the six-hour ceiling and was killed there — and a job killed that way keeps no log, so there was nothing to read afterwards to say where it stopped. One of them has been doing exactly that. Bounded, the same hang fails as a failure, and a failed job keeps its output. The test runner names each test as it finishes, so the last one it named is the one that did not. The limits are what each job takes on a runner with room to spare, not what it takes when it is healthy: the point is to catch a stall, not to fail slow work.
Fifty-nine series now reach a reader on an ordinary subscription, and the venue is not the only thing that can put bytes in front of one. Each is handed an empty record, records cut off at one, three and seven bytes, counts of nothing, of minus one and of the largest a signed integer carries, a count that overruns what arrived, and bytes that open like something compressed and are not. None may panic, and none may hand a caller a figure that is not a number — the venue states a figure it does not hold as the largest its field carries, and that is its way of saying so rather than a reading.
The job limit added before does not do what it was meant to. A job that reaches its limit is recorded as cancelled, and a cancelled job keeps no log at all — so a run that stalls still says nothing about where it stalled. Two of them have now been lost that way. The bound belongs inside the step. A step that times out fails, the job fails with it, and a failed job keeps every line it printed. The test runner names each test as it finishes, so the last name in that log is the one that did not finish — which is the whole question. The job limits stay as a backstop, above the step limits so the step is always the one that fires.
Bounding the step was not enough on its own. The runner kills the command it started, which is cargo, and the binary cargo spawned to run the tests is a generation further down — it survives, and it holds the pipe the step's output is read through. So the step went on waiting for an end-of-output that the orphan was never going to give it, and ran for an hour under a bound of twenty-five minutes. The output goes to a file instead, which severs that pipe: the step ends when the bound fires, whatever the orphan does. What the file holds is printed afterwards — all of it where the step failed, because that is the run worth reading, and three lines where it passed.
Bytes the reader cannot find a header in are discarded, and what went was written to the log as hex so a framing error could be told from a genuinely malformed frame. The whole of it was written: this buffer holds whatever the socket has delivered and not yet been read out of, so one discard of eight megabytes built a string of sixteen million characters and wrote it as a single line. Three of those in one run of the suite came to fifty megabytes of output. Five hundred and twelve bytes of it now, with the size that went stated beside it, which answers the same question. The longest line the suite produces falls from sixteen million characters to one thousand two hundred, and its whole output from about fifty megabytes to one. It cost more than a large file. A reader that takes output a line at a time stalls on a line that size, and the test step it was running under stalled with it — for hours, against a suite that finishes in two minutes when its output goes somewhere that does not care.
… read Four more of the venue's series reach a caller, each read as its own handler reads it. The other news series states one story rather than a batch of them, and frames every string of it with a count of its bytes and padding out to a multiple of four. It reaches a caller on the callback the batch series already uses: it is news about the contract, and which of the two carried it is not something a caller asked about. Read against a live session, it carries stories the batch series was not asked for. Both news series now share one reading of a headline. The venue writes a marker in braces in front of some of them and a caller is shown what follows it — which the batch series did and the new one did not, so the same story reached a caller in two spellings until they were made one. The book the venue keeps for contracts dealt in size rather than on a screen is stated in two forms, told apart by the record: an older one of two rows of a count and a price, and a newer one of rows of a count and two prices behind a version. A row of no quantity, or one withdrawn by stating its price as minus one, is not a row the venue stands behind and is left out. A scan states its strategies and the legs of each, and the legs are kept against the strategy they belong to — the venue numbers neither, so the strategy's place in the record is what names it. A leg sold reads as a negative size. A scan's points are stated behind a version that says how much of the record is there. Where that version is nought the six figures behind it are not in the record at all, so a reader stepping over them anyway reads every figure after them from the wrong place.
…e would not read Five series were set aside as unreadable. They are not: the tool that produced the source gave up on three classes, and the instructions those classes hold are readable without it. The moving averages the venue keeps over a contract's close state a number and a figure in pairs from end to end — which is why the record's length is always a multiple of eight, and which of two branches the build keeps is decided by that. The first pair's number says a count follows and its figure is that count, read whole; every pair behind it states its figure to four bytes. The reader's own words for a record that does not start that way are what settled it. Four more — a contract's quotes once dealing has closed, the same delayed, the underlying's, and the request-for-quote stream — are written in the packed record the quote stream itself uses, which this client has read all along. They are read by that reader now, and kept as the record states them: the venue's own number for each field, the figure, and how far its decimal point moves. No scale is put on them, because which fields are prices and which are sizes is the one thing only the unreadable class would say. Two remain unread and will stay so for a reason rather than for want of trying. One states no payload at all — its reader returns before touching the record. The other hands the record to whichever component subscribed, and there are many of those; there is no single layout to read, only the one belonging to a subscription this client does not make. And a test that failed about one run in eight, which took most of a day to catch because it left nothing behind to identify it. Three tests spawn an engine and then wait on a reply from it, and a test waits a millisecond by default: under a suite running on every core that thread is not always scheduled inside one, so the wait ended in a timeout whose code is not the one the engine refused under. They wait long enough now. Verified across three runs with every core busy, which is what provoked it.
…es are kept by Both were read off a live session rather than left as the record's own numbering. On the packed quotes the venue numbers its fields itself, and the numbers mean the two sides of the quote and the size behind each. An option stated its underlying's two sides on one of these series and the option's own on another, and both matched what those contracts were quoted at to the penny. A side the venue is not standing behind reads as minus one hundred. The figures are counted in the contract's own increments, as every packed figure is, and no scale is put on them here — which fields are prices and which are counts is the venue's to change, and that is the one thing its own reader would say and this cannot read. The moving averages are kept under the days they run over. A share around three hundred and thirty stated twelve days at three hundred and twenty-three, fifty at three hundred and fifteen and two hundred at two hundred and eighty-eight, falling as the window lengthens the way a rising share's averages do. Two of them are numbered below nought and are not days; nothing here says what they are. The call a caller reads these from described one series and now carries all three, on both surfaces.
…is read The venue scans an underlying for combinations worth putting on. Nothing in the documented API asks for that, and this client could not either. The scan goes out as one run of named fields beside a subscription for the series that answers it, which is how the venue takes it: the series carries the answer and the scan says what to look for. A field the caller leaves unstated is left out of the run entirely rather than sent empty. What comes back is a version, an error where the venue refuses the scan rather than answering it, how many it left out, and then the strategies — each with its legs as a contract and a size apiece, a leg sold reading as a negative, which shape of strategy it is and how pressing the venue takes it to be, thirteen figures about it, where it comes out even at each price it can, and one figure behind those. The thirteen are handed over in the order stated: what each one is is the venue's, and it names them nowhere this client can read, so naming them here would be naming them for it. req_spread_scan and scanned_strategies, on both surfaces. This is the one series that could not be read from the record alone. Its answer has two shapes and which one arrives is decided by the kind of subscription it answers, so reading it meant making that subscription rather than guessing which shape to expect.
…n down The venue declares a portfolio figure on a series of its own, and the plumbing to subscribe it, and then nothing anywhere asks for it or says how to read what it would answer with. Every class the terminal ships was searched: three mention the reader that series would need — the reader itself, the handler that would call it, and the thing that would subscribe it — and none of them is one. So there is no layout to read here, not because the record is hard but because nothing reads it. A message that does arrive is written into the record of what this client cannot read, rather than passing in silence, so that it is visible if the venue ever states one. This was skipped before for a reason that was not true: that the record goes to whichever component subscribed and there were many of those. There are none.
…lity is worth against its own past The terminal keeps a register of the series it reads, and some are built there rather than in a class of their own. Every inventory taken here was taken from the classes, so those were never in it. Read from the register instead, fourteen more are served and none of them needed a new reader. Six say where a contract's volatility stands against its own history — its rank, its percentile, and its high and low — for the volatility the market implies and again for the one the contract has actually shown. They are stated as the same two numbered tables the price extremes are, so the reader that already reads those reads these. The number each figure is kept under is weeks, and the venue keeps a quarter, a half year and a year; on the two that state a high and a low, the window is written negative for the low and positive for the high. Read against a live session, where a share stood at the same rank across all three windows while a fund's moved with each. Seven more state a single figure and one states a figure and a flag: a volatility taken at the close, the close's own, a mark the venue keeps behind the live one, and five it states under numbers of its own. All eight are layouts the table of figures already had. The documented API has no call for any of it.
…wn five A second register builds five more series, all sharing one reader on the class they descend from: a whole number and then a figure. Five volatilities taken at or around the close. And one more the venue compresses. It puts a single byte in front of what it squeezed where the calendar puts eight, so the two differ in nothing but that and are read together now. What this does not read, and why, so nobody looks again: - One states nothing at all: its reader logs that it cannot be served and returns before touching the record. - One carries the dividends, line by line, each line tagged by a letter. This client already asks the venue for what a contract pays out and is answered with named fields; reading the same thing again as tagged letters would be worse than what a caller already has. - Three are second numbers for series already read under their first.
…st not miss Everything this client reads was already listed. What it does not read was in the commit log and the guide and nowhere a reader would look, so somebody pointing a program at a series that answers with nothing had no way to tell whether it was the account, the contract, or a bug here. It is stated now: the six series that are read and have never been seen, the readers that have not met their instrument, the three that state no payload at all, the dividends already served better elsewhere, the second numbers for series read under their first, and the nine callbacks the venue states nothing for. And the thing a reader most needs — an empty result means either the venue holds nothing for that contract or the account cannot see the series, and this client cannot tell them apart. The page also uses the alert kinds the site renders, for the handful of things that are worth stopping on: one session per login and the second factor, what a migration does not have to change, the calls that will not run against a gateway, and that this places orders against real money. Written outside the block the matrix generator owns, and the generator was run to confirm it leaves it alone.
Two pages described them as "the part of this client that is not a drop-in". That reads as a hole in the thing, and it is the opposite of what is true: the venue states all of it on an ordinary session, the documented API never gave it a message, and so a program had no way to ask for a contract's float, where its volatility stands against its own year, what margin it takes, or five years of its price with the date of each point. Reaching those is why this exists. What is actually true is narrower and worth saying once: the door opens one way. A program moves to this client without changing a line; a program that then calls one of these cannot move back to a gateway, because a gateway has no message to carry it. That is the trade, and it is named where the calls are named so it is visible before it is made.
It described what this is and listed what it carries, and stopped there. A reader deciding whether to use it had no answer to why it exists, what it gets them that a gateway does not, how it behaves when something drops, or what to do when a series comes back empty. Added, in the order someone reads them: why the arrangement it replaces costs something; installation and a first program before three hundred lines of tables rather than after; what the venue states that the documented API never named, with the figures a session actually returned — a contract's float to the share, where its volatility stands against its own year, five years of its price with the date of each point, what one contract delivers; how the connections are held and rebuilt; nine questions a reader arrives with, folded; what the tests cover and how a reader of the venue's records is held to more than passing; how to contribute something useful; and how not to leak an account. The alert kinds the site renders are used where stopping is worth it — one session per login, the second factor, what a migration need not change, real money — and the calls beyond the documented API are now framed as the reason this exists rather than as a shortfall in it. Everything stated is checked by what already checks this file: nothing here says more than the client can see, every page and example named exists, and every count matches what is there.
This branch has not been deployed
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.
This is
userFRM:main, offered as a fast-forward.TL;DR
main..upstream/mainis 0, nothing of yours rewritten or droppedgit reset --hard 9367845Merge safety
git merge-base upstream/main main=9367845= the tip ofmainhere.git rev-list --count main..upstream/main= 0 — nothing to resolve, no conflicts.git reset --hard 9367845.7cfa6e56(see Taking it).How it was tested
Orders — 110 fixes
Python surface — 74 fixes
connectAckstill received the accounts and the next order idKeyboardInterrupt/SystemExitswallowed in callbacksEngine — 65 fixes
Historical data — 40 fixes
ADJUSTED_LASTTRADESmeant something other than the vendor'sTRADESMarket data — 41 fixes
tickReqParamsSession, second factor, connection — 41 fixes
Protocol — 17 fixes
Account, contracts, options — 42 fixes
con_id=0reported as a contractWhat the gateway does that this did not — 15
The sweep above asks where this client is more than the gateway. This one asks the reverse,
against the decompiled build: what does the gateway do that a caller here cannot reach? Every
row was verified by three independent readers before it was written.
Thirty-nine further differences were found and left alone, each recorded with what closing it
would take. Most are one shape: a family of order types, or a request whose answer has nowhere
to go — a new type, a new channel, or a refactor across files rather than a smaller diff.
Matching the gateway rather than improving on it — 13
This client stands in for the gateway, so a caller who switches must get the same
answers. In each of these it was being more careful than the thing it replaces.
Kept deliberately, with reasons: the SRP group check, the server-proof requirement
and the DH range check, since no caller can see them and dropping them would only
widen what a hostile peer can do; and the permanent-id derivation, because the
gateway's own parse throws on this venue's identifiers and zeroes the field.
Known gaps
request_fa/replace_fareach the server; their reply is not parsed. Pinning the shape needs an advisor account I do not have. These are the 1 of 78 not served on both languages.Taking it
7cfa6e56("tests move beside the code they test"), which moves twelve source files into directories. Commits before it are written against your current layout and cherry-pick with ordinary conflicts; commits after it assume the new paths.