fix(cluster-tool): parse a bare slug cell as a slug, not a decimal - #101
Merged
Merged
Conversation
Split slugValue by ABI carrier, which is what the old string-sniffing
decodeSlugString could not do: a bare string is a slug_name field and is
parsed as a SLUG, while the transitional { value } wrapper holds a packed
u64 and stays numeric. Preferring the decimal reading mis-decoded every
digit-only or JS-numeric-syntax code — "7", "101", "1E3", "0X10".
The wrapper arm now rejects anything but an unsigned decimal, mirroring
the depot's checked_packed_value (fc/slug_name.hpp) so both sides of the
wire refuse the same shapes.
Change-Id: I604b0c660b501cc340368af08d8149ad55d65f60
OperatorAction.chain_code is uint64 in attestations.proto, not a slug_name ABI field, so it renders as a number — or a quoted decimal above 0xffffffff, which every real chain code exceeds. Reading it as a slug spelling threw. flow-batch-operator-termination is the one call site that reaches it, via operators.recent_actions. packedSlugValue takes that carrier; slugValue keeps the slug_name fields. Only the field's declared type can tell a decimal spelling from a slug spelling, which is why the split is per-field rather than per-shape. Change-Id: I428d2e0136eab8fb42edf3567933c3a3cc062ac2
jglanz
approved these changes
Sep 17, 2026
This was referenced Sep 17, 2026
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.
The merged-consumer prerequisite wire-sysio#619 needs, raised as a P2 on that PR: "Please update the merged consumer to mirror the carrier rule documented here … before merging this PR."
The defect
slugValue's string arm ranNumber(value)first and fell back toSlugName.fromonly when that producedNaN. So a code that looks numeric was read as a decimal:The slug alphabet contains digits, so every one of those is a legitimate registry code.
decodeSlugString's own JSDoc conceded the ambiguity was unresolvable by string-sniffing and named the fix: "split this decoder by the field's ABI carrier, after which this helper and both string arms below are deleted." That is what this does.The split — per FIELD, not per shape
slugValueservesslug_name-typed ABI fields:""is the zero sentinel.{ value }wrapper — the transitional shape a pre-builtin depot emits, carrying the packedu64directly, so its inner value stays numeric. This arm goes when no depot emits the wrapper.packedSlugValueserves code fields declareduint64, which are a genuinely different carrier:OperatorAction.chain_code/reserve_codeareuint64inattestations.proto, reachable throughoperators.recent_actions. Those never render as a spelling — they arrive as a number, or as a quoted DECIMAL once past0xffffffff, which every real chain code exceeds ("ETH"is 23373212024832).flow-batch-operator-terminationis the one call site that reads one, and it now uses the packed decoder.That per-field split is the whole point: a decimal spelling and a slug spelling are indistinguishable by shape, so only the field's declared type can decide.
decodeSlugStringis deleted.I classified all 44 call sites against the contract headers to find that one: every other reads a
sysio::slug_namerow field (opreg::balances/wtdwqueue,uwrit::locks/uwreqs,reserv::reserves,tokens), which is{value}pre-#619 and a canonical string after — so those are correct under either merge order.The wrapper arm is now checked
fc::jsonquotes auint64above0xffffffff, so the wrapper legitimately arrives as a decimal string — but only ever as digits.Number()would coerce"ETH"toNaNand truncate"1.5"rather than reject them, so the arm now requires an unsigned decimal and throws otherwise. This deliberately mirrors the depot's ownchecked_packed_value(fc/slug_name.hpp, added in #619 for the same reason), so both sides of the wire refuse the same shapes.Throwing rather than returning
NaNfollows the contract already documented onslugValue:NaNnever equals itself, so aNaNslug silently matches zero rows in a filter and surfaces minutes later as a poll timeout instead of at the decode that caused it.Behaviour this intentionally changes
Two assertions on master pinned the old compromise and are inverted here, deliberately:
slugValue("101")was pinned to101; it is nowSlugName.from("101").slugValue({ value: "ETH" })was pinned to decode as a slug; the wrapper holds a packedu64, so it now throws.A top-level decimal is no longer a carrier at all —
slugValue("84606581215232")throws, because a slug is at most 8 symbols.Verification
slugUtils17/17. Fullcluster-toolunit suite 1505/1506 (run before the packed-carrier commit; the three files it touches are covered by the 17).The one failure —
SystemContractSteps.test.ts, "Unknown sysio.system action: setscorecfg" — is pre-existing and unrelated: the siblingwire-libraries-ts/packages/sdk-corehassetscorecfginsrc/(dated 2026-09-14) but its builtlib/cjsoutput is from 2026-08-14, so the symbol is absent from what resolves at build time. The same staleness makespnpm buildred on master here (setoutpost,SysioChainsOutpostAddrsType,SysioSystemSetscorecfgAction,rank_score). That test file references nothing this change touches, and this diff is two files.eslintclean on both.