feat(compat): a floor, not an equality — and the ordering trap under it - #17
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
CIRISServer#497 moves the server's dependency to `ciris-client>=0.5.190,<0.6` so
the client can ship for the agent team without a paired server cut.
CIRISClient#16 is the other half: under a range, comparing the node's version to
ours for EQUALITY fires on every legitimately-mixed pair. A 0.5.192 node with a
0.5.193 client is the point of decoupling, and it would have greeted its
operator with a permanent nag. That trades a release dance for a nag, which is
worse.
It was never a bug while the versions were locked. They were always equal, the
comparison was always true, and the branch was never exercised. Widening the
range is what turns a held-still assumption into a defect.
THE ORDERING TRAP, WHICH IS THE PART THAT WOULD HAVE SHIPPED QUIETLY. Equality
never ORDERED anything, so it could not be wrong about order. A floor is nothing
but order, and string comparison is wrong at the versions this repo actually
ships:
"0.5.9" > "0.5.190" lexically, because '9' > '1'
"0.5.191" < "0.5.9" lexically
Three-digit patch numbers make that the common case here, not an edge — a floor
written the obvious way decides a 0.5.9 node clears a 0.5.190 floor.
`compareVersions` is numeric per component, and the test names the exact pairs.
TWO DIRECTIONS, WHICH EQUALITY CONFLATED:
node too old for this client MIN_NODE_VERSION, held here, because a node
that predates the idea of declaring a floor
cannot tell us anything about itself.
client too old for this node declared BY THE NODE, because only the node
knows which clients it supports. No
client-held constant can learn that a newer
node needs a newer client — it would call
itself compatible and be wrong.
Nothing declares the second today, so it is optional, and absent means "did not
say" rather than "is happy". The floor this side holds still applies, which
keeps the signal the nag exists for: a genuinely incompatible pair still says
so. Replacing equality with "never complain" would have deleted it, and someone
shipped a mismatched pair once already.
MIN_NODE_VERSION IS NOT YET EARNED, AND THE CODE SAYS SO. The server
mutation-tested its floor at both ends — 0.5.186 fails the id gate, 0.5.188
passes it and fails the wheel gate, so neither gate alone would have caught a
floor that breaks Android. Ours is the pairing both sides are standardising on
and nothing here proves this client cannot drive an older node. Until a gate
installs the floor and exercises the API surface this client calls, it is what
they called it: an untested bound is a guess with a version number on it.
Two existing tests changed meaning, and are rewritten rather than deleted.
`version_mismatch_ignores_the_v_prefix` paired 0.5.176 with itself and asserted
no flag — true only under equality; a 0.5.176 node is now genuinely too old, so
the prefix is demonstrated at versions where the answer is not about age.
`version_mismatch_fires_on_a_real_difference` is renamed to
`..._on_a_node_below_the_floor`: it still fires, for a different reason, and a
mere difference no longer fires at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGE52kPzjGFiPzGcs63ZC1
emooreatx
force-pushed
the
feat/compatibility-floor
branch
from
August 28, 2026 02:31
daa7261 to
646f130
Compare
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 #16. The client half of CIRISServer#497.
Yes to the decoupling. The measurement behind it is sound and the sequencing is right — a range without this ships a permanent nag.
The part that would have shipped quietly
Equality never ordered anything, so it could not be wrong about order. A floor is nothing but order, and string comparison is wrong at the versions this repo actually ships:
Three-digit patch numbers make that the common case here, not an edge — a floor written the obvious way decides a 0.5.9 node clears a 0.5.190 floor.
compareVersionsis numeric per component and the tests name those exact pairs.Two directions, which equality conflated
MIN_NODE_VERSION, held hereNothing declares the second today, so it's optional, and absent means "did not say", not "is happy". The floor this side holds still applies, which preserves the property you asked us to keep: a genuinely incompatible pair still says so.
One thing I want your view on
MIN_NODE_VERSION = 0.5.190is not earned the way your floor was, and the code says so in place. You mutation-tested both ends — 0.5.186 fails the id gate, 0.5.188 passes it and fails the wheel gate, so neither gate alone would have blessed a safe floor. Ours is just the pairing both sides are standardising on; nothing here proves this client cannot drive an older node.To match your rigour this needs a gate that installs the floor and exercises the API surface the client actually calls. Until then it's your phrase exactly: an untested bound is a guess with a version number on it. Happy to build that gate — it's the natural next corner for the walk-test harness in #10.
Behaviour changes, recorded rather than deleted
version_mismatch_ignores_the_v_prefixpaired 0.5.176 with itself and asserted no flag — true only under equality. A 0.5.176 node is now genuinely too old, so the prefix is demonstrated at versions where the answer isn't about age.version_mismatch_fires_on_a_real_difference→..._on_a_node_below_the_floor. It still fires, for a different reason; a mere difference no longer fires at all.🤖 Generated with Claude Code
https://claude.ai/code/session_01EGE52kPzjGFiPzGcs63ZC1