Skip to content

Performance - #18

Merged
LZL0 merged 1 commit into
masterfrom
perf/linear-bulk-fold
Jun 22, 2026
Merged

Performance#18
LZL0 merged 1 commit into
masterfrom
perf/linear-bulk-fold

Conversation

@LZL0

@LZL0 LZL0 commented Jun 22, 2026

Copy link
Copy Markdown
Member

Measured impact (benchmark, since deleted)

Operation Before After Speedup
replayCommands (16k) 5831 ms 1.3 ms ~4500×
importSlice (8k) 1284 ms 2.6 ms ~490×
cascadeRetract (4k) 399 ms 2.0 ms ~200×

Scaling went from quadratic to linear (16k replay now costs the same as 2k did). All 546 existing tests pass; only the pre-existing, unrelated zod optional-peer-dep build error remains.


Summary by cubic

Make replay, import, and cascade operations run in linear time by folding commands in place instead of cloning per command. Replay of 16k events drops from 5831 ms to 1.3 ms, with similar wins for import and cascade.

  • Performance
    • Added applyCommandInPlace and retractItemsInPlace; immutable applyCommand now clones only touched maps and delegates.
    • replayCommands/replayFromEnvelopes fold into shared maps (O(N)), preserving skip-on-error semantics.
    • importSlice imports memories/edges in place (O(M)); intents/tasks stay on immutable reducers.
    • cascadeRetract and getDependents use buildChildrenIndex and batch retract once (post‑order) to avoid rescans.
    • Benchmarks and scaling tests added (bench/memex.bench.ts, tests/in-place-fold.test.ts), new bench script, and bench/ excluded from publish.
    • Measured impact: replay 16k 5831ms → 1.3ms (~4500×), import 8k 1284ms → 2.6ms (~490×), cascade 4k 399ms → 2.0ms (~200×).

Written for commit 414ef81. Summary will update on new commits.

Review in cubic

The immutable applyCommand clones the whole items/edges Map per command.
Callers that fold N commands paid that clone N times, so replay, import,
and cascade were all O(N^2).

- reducer: add applyCommandInPlace (the single source of command
  semantics) and retractItemsInPlace; applyCommand now clones only the
  touched map(s) once and delegates, preserving immutability and the
  structural sharing of the untouched map.
- replay: replayCommands / replayFromEnvelopes fold into one pair of maps
  in place -> O(N). applyCommandInPlace is atomic per command, so the
  skip-on-error contract is preserved.
- transplant: importSlice imports the memory graph in place -> O(M).
- integrity/query: add buildChildrenIndex; cascadeRetract and
  getDependents walk it instead of rescanning the graph per node, and
  cascadeRetract retracts in a single clone -> O(N). Post-order cascade
  ordering is unchanged.

Measured: replay 16k 5831ms -> 1.3ms; importSlice 8k 1284ms -> 2.6ms;
cascadeRetract 4k 399ms -> 2.0ms.

Add bench/memex.bench.ts (npm run bench) and tests/in-place-fold.test.ts
covering applyCommand immutability, applyCommandInPlace/replay equivalence
with the immutable fold, retractItemsInPlace edge cascade, and a 50k-item
scaling guard. 556 tests pass.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 11 files

You’re at about 96% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Re-trigger cubic

@LZL0
LZL0 merged commit 683904e into master Jun 22, 2026
5 checks passed
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