Skip to content

Fast-forward main onto the fork - #409

Open
userFRM wants to merge 1514 commits into
deepentropy:mainfrom
userFRM:main
Open

Fast-forward main onto the fork#409
userFRM wants to merge 1514 commits into
deepentropy:mainfrom
userFRM:main

Conversation

@userFRM

@userFRM userFRM commented Aug 26, 2026

Copy link
Copy Markdown

This is userFRM:main, offered as a fast-forward.

TL;DR

Commits 1,465 — 797 fixes, 162 features, 131 test, 201 docs, 73 refactors
Files 452
Merge Clean fast-forward. main..upstream/main is 0, nothing of yours rewritten or dropped
Undo git reset --hard 9367845
CI Green on the head — actions
Tested 154 phases against a real session, on paper and live — last run green in full 9 September 2026. 3,421 offline tests + 197 broker-session tests
Soak 14 hours held open on one session, through the venue's maintenance window — 0 losses, 0 reconnects
Order fields dropped 0 of 154
Call arguments dropped 0 of 572
API parity 77 of 78 calls served on both languages
Order types 24
Requests on the wire 72 of 80

Merge safety

  • git merge-base upstream/main main = 9367845 = the tip of main here.
  • git rev-list --count main..upstream/main = 0 — nothing to resolve, no conflicts.
  • Nothing of yours is rewritten, reordered or dropped.
  • One command undoes it: git reset --hard 9367845.
  • Partial take: cut at 7cfa6e56 (see Taking it).

How it was tested

  • Reproduced first. Fixes were reproduced before they were made, and landed with tests that fail without them — 127 test commits.
  • Against a real session. 153 phases end to end: order placement, replacement, cancellation, brackets and legs, executions, commission reports, account and position downloads, market data, depth, historical series, contract lookups, reconnection.
  • Live as well as paper. Paper and live speak the same wire — identical messages, fields and sequencing, differing only in which prints arrive. Order paths have additionally been run against a live account, real fills, a real book.
  • No silent passes. A phase cannot skip on silence — each names what refused it. A phase cannot pass on an order that never reached the wire.
  • Held open. One session run for 14 unbroken hours across the venue's nightly maintenance window: no losses, no reconnects, quotes and orders still answering at the end.
  • Counted by script, re-derived in CI. A documentation claim fails the build when the source stops supporting it.
python scripts/gate.py          # runs what CI runs; --list prints the suites first
cargo test --lib
git diff --exit-code docs/      # the generated reference matches its source

IB_USERNAME=... IB_PASSWORD=... cargo test --test ib_paper_compat -- --test-threads=1 --nocapture

Orders — 110 fixes

Was Now
Algo params, conditions and unmodelled params dropped between caller and wire Travel as stated; condition flags sit on the tags that mean them
Flags the caller never set were sent anyway An algo flag, time or aversion not stated is not sent
Pegged orders lost offset, cap, snap-to offset, benchmark price All carried, including an offset of zero
Prices truncated; sign lost on prices with no whole part Rounded; sign kept
13 order types the venue replaces were refused Accepted, plus volatility, both relative combinations, passively relative, peg-to-best, peg-by-minute, delayed activation
Replace kept terms the venue had refused The venue's word settles it; refused terms do not stand
A correction the venue sent twice reopened a finished order and republished its quantity as working Read once; the second copy changes nothing
A second refusal for the same cancel read the echoed name as digits and retired an unrelated live order Resolved through the cancel's own name
The async client's two withdrawal calls waited out a reconnect's replay on the reactor Off it, as every other order call there
An order's quantity was bounded where a double stops multiplying exactly, so a cash order stated in currency units was refused Bounded where the field itself ends, four orders of magnitude further; the whole part scales in integer arithmetic
A rejection answering a replace was read as how the order finished It is not the order's state
A replacement could not itself be replaced It can
Type change on a linked order corrupted links Refused; links kept both ways
Trigger survived a replace to a type without one Dropped
A working order this client did not place was placed again Replaced
Bracket legs lost group and parent on replace Kept
A held parent withdrawn orphaned its children Children go with it; a parent releases them
A set that could not be placed whole left partial legs Withdrawn
Filled orders reported as working Not reported as working
Orders done but unfilled tracked forever Stop being tracked
Order ids counted from a file Counted from what the account is working, past every id the venue has named
A cancel the venue refused left the order reading as working Reads correctly
A failed write reported as a rejection Reported as unknown
A refusal with no words did not end the order Ends it

Python surface — 74 fixes

Was Now
Programs written against the reference client would not import Its module layout, constants, enumerations and run-together names all answered
A model calculation on a described contract claimed the watch the request already held, and cancelling it withdrew that subscription Only a watch this call opened is its own
A handler that closed the session from inside connectAck still received the accounts and the next order id The startup stops with the session
Constructor spellings rejected The reference API's own spelling accepted
Enum-typed fields handed back raw values Hand back the member
KeyboardInterrupt / SystemExit swallowed in callbacks Propagate
A raising callback lost its answer Keeps it
A raising position handler ended the dispatch loop Does not
A handler raising during connect failed the session Does not
GIL held across blocking engine calls and blocking waits Released
Two connects could both win Cannot
A client holding itself was never collected Collected
Request ids truncated; callbacks handed partial contracts Whole ids, whole contract
Ticks named differently from the reference Every tick the venue numbers named as the reference names it
5 places Python answered differently from Rust Answer the same
4 things the model classes changed or dropped in transit Carried

Engine — 65 fixes

Was Now
Slots reused while something still pointed at them Not reused; resident while holding market data
Withdrawing a quote took the decoder mapping for a news subscription asked for under its own request News is withdrawn only by its own withdrawal
A historical or calendar farm that came up long past its deadline was installed anyway Each farm's clock is read before its result is taken
A slot that changed hands carried the wrong contract's order An order states the contract it means
A slot did not return when its last order ended Returns to the table
5 answers belonged to another question Go to the request that asked
5 requests answered from something other than the venue Answer from the venue
4 answers taken after the moment they belonged to Discarded
6 answers said something had happened when it had not Do not
Transports shared one recovery clock Each has its own
Hot loop spun with every transport down Parks
Hot loop could wait on something that never comes Cannot
A quote feed the venue would not take back killed the session Ends the feed only
Fills lost for orders the session does not track Booked
A duplicate execution suppressed the whole report Suppresses the fill only
Missing position quantity read as flat Read as no quantity
Orders unaccounted for after recovery were silent Reported

Historical data — 40 fixes

Was Now
7 series the venue carries were refused, incl. ADJUSTED_LAST Served
Midpoint, rate, volatility asked under names the venue does not answer Asked under the venue's names
TRADES meant something other than the vendor's TRADES Same meaning
Corporate actions discarded Read
Bars dated on the wrong clock, written in the wrong shape Dated on the venue's clock, written as the request asked
A bar the fold could not build was folded anyway Refused
A refusal ended queries it did not name Reaches only the query it names
A withdrawal took more than it withdrew Takes what it withdrew, only
A sloppy answer came back as a plausible wrong number Refused
The historical farm gave up after six attempts Keeps retrying

Market data — 41 fixes

Was Now
A contract named by id alone was refused Looked up at the venue
The slot getter answered from the cache after the engine had given the slot to another contract Answers through the same lookup every other reader uses
Dropping a live-bar stream never sent its withdrawal, so the venue went on closing bars at a reader that had gone Withdrawn under the mark its subscribe was numbered with
An unknown contract was assumed a US stock The venue is asked what it is
A request joining a live subscription got no quote Owed the quote as it stands, and its tickReqParams
A snapshot was handed to a second caller as a subscription It is not; the chargeable snapshot is asked for
A finished snapshot withdrew what replaced it Withdraws itself
A snapshot ended on a pause Ends where the venue ends it
A stream was withdrawn by the wrong number Withdrawn by the number the venue gave it
A feed given up on kept taking subscriptions Takes none; refused where the caller asks
L1 did not survive a disconnect Re-subscribes from the surviving record
A drop mid-replay lost what the replay had not reached Kept
A refused book kept being asked for Stops

Session, second factor, connection — 41 fixes

Was Now
The logon was judged on the last message type in the answer Judged on what it answered with
An acknowledgement sharing its type with account traffic was missed Found wherever in the answer it sits
A fill riding in with the reconnect acknowledgement was dropped Kept
4 ways a login ended that the venue had not ended Closed
5 ways a connection could be held open or given up wrongly Closed
Second factor ran on first login only Runs on reconnect too
The code provider ran on the socket thread Runs off it
A code was spent on a login already lost Not spent
The code was submitted while the socket was busy Submitted only while quiet, as soon as it resolves
The session token reached the log Kept out
An unstamped reconnect left the logon time behind, so the next reconnect read this session's own logon as a competitor and gave the account up The logon time moves on
A takeover could not be told from this session's stale logon Told apart
A signal interrupting a read counted as silence, so the venue's routing answer went unread and the connection failed A signal is retried, not counted

Protocol — 17 fixes

Was Now
Fields searched for rather than read where the format puts them Read at stated positions
Length and signature read from the wrong offsets Read where the header puts them
A message borrowed the next one's bits Ends where its own length says
A compressed header split across reads failed to frame Frames
A read taking two messages kept one Keeps both
A pause inside a frame read as a failed frame Does not
9 ways a frame could say something it did not carry Closed

Account, contracts, options — 42 fixes

Was Now
The account could be read before it was stated whole Reads wait for the download; every download ends
A holding the new statement never names stayed open Closed
P&L did not survive a trading reconnect Renewed
Contract hours stated on the wrong clock Stated on the clock they are named with
Market-rule ids not surfaced Surfaced on contract details
A lookup bounded on answer length Bounded on silence
con_id=0 reported as a contract Reported as "not found"
An option's model read from the wrong contract Read for the contract asked about
An option on a future priced as one on a share Priced as a future option
A non-number price yielded a volatility; an overflowed tree yielded a price Both refused
Time to expiry taken from the local clock Taken from the venue

What 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.

Was Now
A change to an order reached the venue only for the terms the replace names; a new display size, discretionary amount, all-or-none or algorithm parameter was dropped, while this client's own answer already read back the new value Every replace goes behind the caller's own statement, and the latest statement stands
A site that was down was reported as credentials being refused, and stopped the retry ladder The venue numbers its refusals; the two that mean "not now" are waited out
A host that stopped answering ended the session Its two standbys are named after it and tried first, as the venue names them
An order naming a model portfolio was refused outright The model rides the placement, the replacement and the withdrawal
Day-till-cancelled went out as good-till-date, carrying an expiry nobody named Good-till-cancelled with the flag that stands it down at the day's end
A combination's legs stated open or close on the field that carries a leg's number On the field that carries the intent; a short leg states its borrow in full
An account summary asked for by currency answered nothing The per-currency set is named by a prefix, not a figure name
Delayed and frozen quotes were collapsed to one entry, so the trade half never arrived Both halves, as every live subscription already asked for
A withdrawal omitted three companions its subscription had stated States what it withdraws
Six bar and tick series the venue serves were refused before they were sent Sent under the venue's own names
A news article delivered as a document, or as a refusal, reached the caller as article text Delivered as what it is
What the venue says to the account holder was counted as wire nobody reads Reaches the caller
A symbol search was sent exactly as typed Trimmed and collapsed, refused only where the venue refuses it

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.

Was Now
Calendar requests expired locally after 30s; a later answer was discarded The venue's answer ends them; the gateway sets no timer
An execution reported the reconciled difference as its own quantity Reports the quantity the venue stated; the reconciliation still uses the difference
An unmodelled risk level or algo flag was refused, then silently dropped Travels as the caller wrote it; the venue answers for its own vocabulary
Adjusted history was refused on a contract stated by description Sent; the venue resolves it
A historical-news request naming a time window was refused Carries the window; the element names and their format are the ones this client's other queries already send to the same service
A caller asking the time got the stamp on the last message the venue happened to send — frozen on a quiet link, refused before any arrived The venue states how far its clock sits from this one; the answer is this machine's clock moved by that, and a connected session is always told the time
An order stating an advisor group, method or percentage had them dropped, under a note claiming the protocol carries no field All three ride the order and its replacement
A profit request naming another account was warned about, then answered with this account's figures under the caller's own number Refused, and refused before it takes the one subscription slot
A market rule this session has not seen was refused under this client's own number and code Refused under the ones the venue uses, on both surfaces
A withdrawal arriving while its subscription was still opening was refused, and the subscription went on Recorded and answered; the registration reads it before publishing and takes back down what it opened
A session held as many quote subscriptions as this client's own table, ignoring the number the venue states on the logon Reads the allowance and refuses past it under the venue's own code
Margin figures the venue had not stated carried a stand-in number Stay empty, as the reference client leaves them
One account summary at a time, ended at its own first answer Two at once, each lasting until it is cancelled
An ordinary exception from a Python callback was logged and dispatch continued Leaves dispatch and closes the session, as the reference client's loop does
Values the reference decoder reads as absent arrived as sentinel numbers Arrive as
Repeated order-status reports were suppressed when the status was unchanged All delivered; the venue sends them and the reference client hands them on

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_fa reach 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.
  • Some paper phases skip rather than pass. Each names what refused it — venue or account, not the client: an order type an exchange will not take for that security type, a lot size rule, a subscription the account does not hold.
  • One process holds one session. A gateway process rents its session out over a local socket; this has no socket. That is issue #2, unaddressed here.

Taking it

  • All of it: fast-forward.
  • Part of it: cut at 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.
git log --reverse --oneline upstream/main..main | head -742
  • None of it: close it. If a particular subsystem would be more useful on its own, say which and I will open it against your layout.

This was referenced Aug 26, 2026
userFRM and others added 30 commits September 10, 2026 14:37
…f the message

The venue states no length for a handful of series; its own reader takes what
that series' shape needs and says how much it used, so where such a record ends
is the reader's to know. This client treated the remainder of the message as
the record's payload, on the reading that a message carries exactly one of
them. Nothing in the venue's framing says that, and a message may carry more
behind one.

Nothing here reads any of those series, so the rest of the message now goes
unread rather than being handed on as one record's payload with the records
behind it mistaken for part of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
An advisor places for several models inside one account, and every report says
which. Nothing read it, so each fill and each order came back attributed to the
account at large and a caller could not tell one model's position from
another's.

It is stated on the same tag an order states it on going out, beside the
account. A report naming an account-only specification states no model whatever
else it carries, so the field is left empty there rather than filled from a tag
that is about something else.

The default sleeve is not stated on an order going out, but a report that names
it is naming it, and what arrives is what a caller is told.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The price stream carries two entries this client stepped over: one saying
whether each side may be dealt on without a human, one saying whether the quote
is a pre-open indication and whether either side has run past its limit. Every
bid and ask therefore went out with all three attributes false, whatever the
venue said, and the note beside the delivery claimed the feed carries no
attributes at all.

The venue states both sides in one mask and a caller is owed an attribute
beside each price, so the side is read off the number the price goes out
under — including the delayed numbers, which are the same two prices from
another feed. Pre-open is stated once and belongs to both.

They are kept beside the quote rather than in it. A quote is read on the hot
path and sized to the cache lines it occupies; these change seldom, so they are
held where widening costs nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The venue keeps an average option volume for each side and publishes the two
added; either side left unstated leaves the whole figure unstated rather than
counted as none.

For a share yet to open it states up to three prices — the top, the middle and
the bottom of its estimate — with a flag word saying which of them stand. The
middle stands while the estimate does; the figure it finally opened at stands
once the flags say it is final. Neither is published while the venue's own
not-stated value is in the field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The venue sends them as compressed text behind an eight-byte header it does not
describe. Inflated and trimmed, they go out as the one string the reference
client publishes them as.

Held to what one inflated payload may become, as every other inflate here is:
what arrives is bounded on the wire and what it becomes is not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…s them in

A ledger reply is not the name-and-value stream the other account messages are.
It opens a bucket, names the currency it is in, and states each figure on a tag
of its own. Read as name-and-value it matched nothing, so the standard way to
ask for per-currency cash, exchange rate and profit came back with no rows —
which a caller cannot tell from an account holding no cash at all.

Each figure now goes out under the name the venue publishes it by, in the
currency of the bucket it was stated in, at least two places and at most seven,
as the venue writes them.

An insured-deposit balance is stated apart and belongs to the cash balance
unless the session splits the two, which this one does not, so it is added in
rather than published beside it. The name is a ledger figure after all and goes
back into the set a ledger request answers with.

Five tags the venue states have a place in its own formatter and no name in the
map it publishes from. They are left out. A figure with a name invented for it
is worse than a figure withheld, because a caller reads it as the venue's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
A report carries every term the order holds, and this client read the handful
that identify it. So an order read back from the venue came back as the
defaults for the rest — no display size, no trigger method, not hidden, no
discretionary amount, no clearing account — whatever the venue was actually
working. A caller reading an order it had not placed itself, or reading one
back after a reconnect, was handed a different order from the one on the book.

Fifty-three more terms are read now, each onto the field a caller already has
for it, and each only where the report states it: a term the report does not
mention is one the order does not carry, and the default already says so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…eclares

This engine states when the venue said it, as the current reference client
does. ib_async predates that argument and declares four, so a wrapper attached
to this engine was handed five and raised on the first error or notice of the
session — and a callback that raises there closes the session, which turned any
refusal at all into a disconnection.

Their wrapper is handed four now. The engine's own wrapper keeps the five it
shares with the reference client, because that is what a caller writing against
the current API expects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The models a caller builds an order from carry this API's own "not set" value
as the default for a trailing percentage, so an ordinary limit order arrives
with it in that field. Checked as a number it fails every bound there is, and
every order that never mentioned a trailing percentage was refused for the one
thing it did not say.

Exempted the way the dozen price fields beside it already are. What the check
exists for — a percentage that is not a number, or negative, or past what the
wire carries — still fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The venue states a rule id for each venue a contract trades on, and a caller
reads the ids and the venues side by side to know which price increment applies
where. This client parsed the field into a single number, so a contract listed
on several came back with none at all: the parse of a list fails, and what a
caller read was empty.

The field is kept as the venue stated it. It is still read as a number as well,
where it is one, because the rule lookup takes a number and a contract on a
single venue states a single id.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The venue states a suggested size for the contract itself, apart from any rule,
and the suggestion is the larger of that and the size the contract's rule deals
in. This client stood it on the rule alone and never read the contract's own
figure, so a contract dealt in fractions suggested a ten-thousandth of a share
where the venue suggests one.

The note beside the field claimed the counterpart falls back to the rule where
nothing separate is stated. It does not; it takes the larger of the two. The
note now says that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Two fields the venue states and this client dropped.

A contract's definition names the reasons it may not be dealt in by number,
and the reply names those numbers once, after the last contract in it. Read
record by record only the last contract could say what its own numbers
meant, so the table is read from the whole reply and every contract in it is
named from that. Callers read them as `ineligibilityReasonList`, which
raised an `AttributeError` before.

A report names who entered the order on tag 109. It was being read as the
number of the client that placed it, which it is not: a report naming a
person left the order under client nought and lost the name as well. It now
reaches `Order.submitter` and `Execution.submitter`, and the account the
order sits in no longer stands in for the person who entered it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…s on its own callback

Two answers the venue sends that reached nobody.

The venue answers an advisor configuration request with its own reply,
carrying back the number the request went out under and either the
configuration itself or, for a replacement, whether it stands. Nothing read
it, so `receiveFA` and `replaceFAEnd` were documented as callbacks nothing
fires. They fire now, matched to the caller by that number, and a venue that
will not take a replacement says why on `error` under the code the reference
client reports a failed save on.

A lookup for fixed income — a bond, a bill, and the type the venue spells
`FIXED` — is answered on `bondContractDetails`, not on `contractDetails`.
It was answered on the ordinary one, so a program written against the
reference client waited through its own answer. A bill and a fixed-income
contract now also file their date as the details' maturity, as a bond
already did, because the venue answers all three the same way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…eads

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Every one of these was asked for, served by the venue, and stepped over: the
payload arrived and was logged as something nothing here reads.

Now read, each under the number a caller reads it by: the extremes of the last
quarter, half-year and year with the ordinary day's volume; an index's premium
over its future; the mark, under either of the two numbers it is asked for by;
what the contract pays out; a fund's value per share — last, frozen and the
day's two extremes; what has traded over the last three, five and ten minutes;
and what traded on a trade report, stated as a trade rather than as the totals
it is read from.

The running-volume reader already did that last computation for the other
series and now keeps a baseline per series as well as per contract: one
baseline for both stated each series' trade against the other's totals.

Two things the venue does that this client was doing differently. A figure it
does not hold is stated as the largest a double carries, and on the callback
that takes a plain number nothing at all is sent rather than that figure. And a
record that states no length of its own is not unreadable — its width is its
reader's to know, which is how the mark is read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…tion

A caller who watches a contract, stops, and watches it again was handed a
print measured from a total the venue stated in the earlier subscription:
everything that traded in between as one trade, or a negative number of
shares where the venue had started its day over. The baseline is released
with the contract now, and with the connection that issued it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
On the callback that takes text the reference client sends a reading only
where there is one, and an empty string is not a reading. Sent anyway, a
program reading the dividend line or the ratios was handed a blank to parse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
… does

A program that asks for delayed data is told the feed is delayed and then
reads its option model under the number the reference client gives a delayed
one. It was arriving under the live number, indistinguishable from a reading
the caller had not been given.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
It rides the auction record, past the auction's own type and six figures the
venue keeps for itself. Three of the record's fields were read and the rest
stepped over, so a caller watching an auction was told what was crossing and
which way, and not the one figure the venue is obliged to state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…eduled

Three tests spawn a thread to answer a registration and then wait the one
millisecond a test states when it wants the wait to fire. Under a loaded
suite the answer arrives late, the caller reads it as an engine that went
away, and the answering thread dies on a send nobody is listening for. All
three now state a wait that outlasts being scheduled, and none of them dies
over a caller that stopped waiting.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The least size was read only off the tag the venue states for a contract
dealt in whole units, so every fractional contract came back saying nothing
about the smallest order it takes — the tag is for the other kind. A
fractional contract takes it from its own size rule, where the least that
can be dealt and the step between sizes are one figure.

One case is left out and said so in the source: the venue holds a fund to
whole units despite a fractional rule, on a flag this client does not read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
…t way

A quote entry whose number does not fit five bits states it in a byte, then
states how far to move the decimal point in four bits and how wide the value
is in four more. This read the two nibbles as one byte of width, and they
multiply: a value two places out and four bytes wide read as thirty-six bytes
wide, which is wider than this decoder takes — so the entry was stepped over
by two hundred and eighty-eight bits instead of thirty-two, and every tick
behind it in the message was decoded out of step.

The shift is carried on the entry. An entry that states one is not counted in
the contract's own increments at all — the venue divides by ten to that power
instead — so it is left out rather than published as a number nobody sent,
and said once so the gap is visible.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
Two more series a caller can ask for, and the first of the kind whose record
says where it ends rather than stating a length in the framing. This client
abandoned the rest of the message on one of those, so the mark arrived and
reached nobody; the record is handed over now and read.

The price is the field numbered two, on the venue's own field grammar — the
same grammar the quote stream is written in, so it is read in one place now
rather than twice. A word of flags numbered thirteen carries the venue saying
the price does not stand, and one that says so is not published.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
The two prices nobody has to deal in round lots at, their sizes, and where
each is quoted. It arrives on a record that says where it ends rather than
stating a length, which this client abandoned rather than read, so a caller
who asked for it was told nothing at all.

Where each side is quoted is read off the same bits over the same venue list
the ordinary quote's exchanges are read from. A price with no size behind it
is left out: the venue states one and withdraws it by leaving the size at
nothing, so a side is handed over only where there is something to deal in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C9qDHkbkXiSNP7gjQ7PXxc
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.

1 participant