types/patricia_trie: fold the stack instead of indexing it - #1582
Merged
Conversation
Working notes; the PR title and description are the commit message. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016HvbYkBMYWwQECL7myLhqs
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016HvbYkBMYWwQECL7myLhqs
Contributor
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
functionalscript | 899ccd1 | Commit Preview URL Branch Preview URL |
Aug 15 2026, 07:41 AM |
o2alexanderfedin
approved these changes
Aug 15, 2026
o2alexanderfedin
left a comment
Contributor
There was a problem hiding this comment.
Verified the fold is behavior-preserving, not just shape-preserving.
end:splitLastgivesrest = stack[0..len-2]pluslastHash, andreduceRightvisitslen-2 … 0— the same order as the old descending loop — threading[h, storage]throughcreatein the same sequence, sostorageaccumulates identically. Empty maps to[undefined, storage], single-element to the untouched seed.push: the doublesplitLastreproduces the old[len-1]/[len-2]/slice(0,-2), and the twonullbreaks fire on exactly lengths 0 and 1 that the oldlength >= 2guard rejected.splitLast'slast(a) === nullambiguity is moot here — stack elements areCandidatetuples, never null.
npm test green (2797 pass / 0 fail). Also ran a 20k-case differential fuzz (0–8 leaves) of old vs new with an order-sensitive create keyed on storage.length: identical root hash and identical storage node sequence in every case.
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.
Implements
fjs/types/patricia_trie/todo/declarative-stack-fold.md(deleted here).endIt was a right fold written as a descending index loop with a
letand a mutating destructuring assignment:splitLastsupplies the seed and the rest together, so the empty stack becomes thenullbranch and the separate length guard disappears:No
let, no index arithmetic, no mutation.pushThe TODO's call — that
push's loop is genuine carry propagation and can stay imperative, but should split rather than index — is right: each merge decides whether the next one happens, so it is sequential in a wayendis not. What it does not need isstack[stack.length - 1],stack[stack.length - 2]andstack.slice(0, -2), which are now twosplitLastcalls. Either split answeringnullis exactly where the oldstack.length >= 2guard stopped, so the guard is not lost, just expressed by the same operation that reads the elements.Verification
This builds content-addressed trees, so identical structure matters more than a green suite:
npx tscclean.fjs test: 2797 pass, 0 fail.npm run cov:fjs/types/patricia_trie/module.f.mjsat 100% lines/branches/functions.main. 246 sorted leaf sequences — every length 0 through 40, six deterministic pseudo-random 64-bit sets each — pushed one at a time and drained withend. Compared the root identity, the node count, and every(left, right, hash)triple in storage: 406 KB of output, byte-identical. That covers the empty stack, the single-leaf stack (whereendreturns the seed without folding), and deep carry chains.One note on the
splitLastdependency: its elements here areCandidate<T>tuples, nevernull, so the nullish-element defect filed asfjs/types/array/todo/split-accessors-nullish-element.mdcannot bite this caller.Changelog:
types/patricia_trie:endis a right fold over the candidate stack andpushsplits instead of indexing; identical output🤖 Generated with Claude Code
https://claude.ai/code/session_016HvbYkBMYWwQECL7myLhqs
Generated by Claude Code