Skip to content

Fix to resolve Windows 32-bit Out Of Memory benchmark tests#57

Merged
frostney merged 3 commits into
mainfrom
cursor/windows-benchmark-memory-4b72
Mar 10, 2026
Merged

Fix to resolve Windows 32-bit Out Of Memory benchmark tests#57
frostney merged 3 commits into
mainfrom
cursor/windows-benchmark-memory-4b72

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Mar 10, 2026

Initialize Souffle GC and fix related memory management issues to resolve Windows OOM in benchmarks.

The Souffle garbage collector was never initialized, causing all Souffle heap objects to accumulate indefinitely and leading to out-of-memory errors. Enabling the GC exposed several bugs in its mark phase, including missing roots and infinite recursion for cyclic references, which were addressed by fixing the marking logic and disabling automatic collection during VM execution, opting for explicit collection at controlled safe points.


Open in Web Open in Cursor 

Summary by CodeRabbit

Release Notes

  • Documentation

    • Updated garbage collection lifecycle and initialization documentation
  • Bug Fixes

    • Enhanced garbage collection system with additional safeguards to prevent redundant marking operations
    • Improved external root coverage in garbage collection traversal

Root cause: TSouffleGarbageCollector.Initialize was never called anywhere
in the codebase, so the Souffle GC singleton was nil. All AllocateObject
calls were no-ops (guarded by 'if Assigned(FGC)'), and CollectIfNeeded
never triggered. Souffle heap objects (closures, arrays, records,
blueprints, strings, upvalues) accumulated without limit, causing
EOutOfMemory on Windows after ~29s of benchmark execution.

Changes:
- Goccia.Engine.Backend.pas: Initialize Souffle GC in
  TGocciaSouffleBackend.Create (with Enabled := False to prevent
  automatic collection during execution), run full Collect in
  destructor, add finalization section for Shutdown
- Souffle.Compound.pas: Add GCMarked cycle-breaking checks in
  TSouffleArray.MarkReferences and TSouffleRecord.MarkReferences
  (prevents infinite recursion on self-referential objects like
  globalThis.globalThis)
- Souffle.VM.Closure.pas: Add GCMarked check in
  TSouffleClosure.MarkReferences for upvalue marking
- Goccia.Runtime.Operations.pas: Add FMapDelegate, FSetDelegate,
  and FBlueprintSuperValues to MarkExternalRoots (previously
  unmarked Souffle heap objects)
- Update AGENTS.md and docs/souffle-vm.md with GC lifecycle docs

Automatic collection (CollectIfNeeded) is disabled because the mark
phase does not yet cover all cross-GC roots during bridge calls.
The per-backend-destruction Collect approach is sufficient to prevent
OOM in multi-file scenarios (benchmarks, test suites).

Co-authored-by: Johannes Stein <frostney@users.noreply.github.com>
@cursor
Copy link
Copy Markdown

cursor Bot commented Mar 10, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

This PR implements garbage collection lifecycle management for the Souffle backend system. Changes include: initializing the GC singleton with automatic collection disabled, adding GCMarked guards to prevent redundant marking in Souffle compound objects and closures, integrating collection during backend destruction, expanding external-root marking coverage for super-values and delegates, and updating documentation to reflect the new GC workflow.

Changes

Cohort / File(s) Summary
Documentation
AGENTS.md, docs/souffle-vm.md
Updated documentation to describe GC lifecycle: singleton initialization with disabled automatic collection, full collection in backend destructor, and finalization shutdown. Also noted test suite expansion (3,433 tests) and current disablement of threshold-based collection.
GC Marking Guards
souffle/Souffle.Compound.pas, souffle/Souffle.VM.Closure.pas
Added GCMarked condition checks before MarkReferences calls to prevent redundant marking of already-marked references in array/record entries and closure upvalues.
Backend Integration
units/Goccia.Engine.Backend.pas
Integrated SouffleGarbageCollector lifecycle: initialization in constructor with automatic collection disabled, full collection triggered on destruction, and finalization block for shutdown.
Runtime Operations
units/Goccia.Runtime.Operations.pas
Extended external-root marking in MarkExternalRoots to cover FBlueprintSuperValues and FMapDelegate/FSetDelegate, improving GC root coverage for bridge call paths.

Sequence Diagram

sequenceDiagram
    participant Backend as TGocciaSouffleBackend
    participant GC as TSouffleGarbageCollector
    participant Runtime as MarkExternalRoots
    participant SouffleObj as Souffle Objects<br/>(Compound, Closure)
    
    Backend->>GC: Create() - Initialize singleton
    Backend->>GC: Disable automatic collection
    note over GC: Enabled := False
    
    Runtime->>Runtime: Mark external roots
    Runtime->>SouffleObj: MarkReferences(obj)
    activate SouffleObj
    alt GCMarked = False
        SouffleObj->>SouffleObj: Recursively mark references
    else GCMarked = True
        note over SouffleObj: Skip (already marked)
    end
    deactivate SouffleObj
    
    Backend->>GC: Destroy() - Explicit collection
    activate GC
    GC->>GC: Collect() - Free Souffle heap
    deactivate GC
    
    note over Backend: Module Finalization
    Backend->>GC: Shutdown()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 The GC hops with purpose clear,
Marks are guarded, doubles disappear,
From backend birth to final rest,
Memory managed at its best! 🌱✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary focus of the pull request: resolving Windows 32-bit Out Of Memory issues in benchmark tests through Souffle GC initialization and memory management fixes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/windows-benchmark-memory-4b72

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 10, 2026

Benchmark Results

254 benchmarks (no baseline)

arraybuffer.js — 14 benchmarks
Benchmark Interpreted Bytecode
create ArrayBuffer(0) 422,249 145,291
create ArrayBuffer(64) 412,397 139,482
create ArrayBuffer(1024) 316,893 125,314
create ArrayBuffer(8192) 140,451 84,139
slice full buffer (64 bytes) 508,960 376,971
slice half buffer (512 of 1024 bytes) 428,321 328,982
slice with negative indices 442,373 363,622
slice empty range 494,561 371,496
byteLength access 1,476,389 1,062,730
Symbol.toStringTag access 1,149,794 538,217
ArrayBuffer.isView 694,775 457,297
clone ArrayBuffer(64) 371,582 320,622
clone ArrayBuffer(1024) 281,036 252,027
clone ArrayBuffer inside object 253,407 152,563
arrays.js — 19 benchmarks
Benchmark Interpreted Bytecode
Array.from length 100 13,489 12,703
Array.from 10 elements 222,793 150,637
Array.of 10 elements 298,912 214,100
spread into new array 331,314 564,308
map over 50 elements 27,000 22,714
filter over 50 elements 23,251 21,685
reduce sum 50 elements 26,075 19,516
forEach over 50 elements 22,635 24,008
find in 50 elements 33,795 26,512
sort 20 elements 11,714 3,359
flat nested array 116,931 286,571
flatMap 72,078 187,637
map inside map (5x5) 20,630 67,853
filter inside map (5x10) 15,996 13,546
reduce inside map (5x10) 18,823 13,743
forEach inside forEach (5x10) 16,127 15,277
find inside some (10x10) 13,171 10,621
map+filter chain nested (5x20) 5,100 4,494
reduce flatten (10x5) 37,282 4,894
async-await.js — 6 benchmarks
Benchmark Interpreted Bytecode
single await 335,971 243,655
multiple awaits 151,449 97,731
await non-Promise value 723,607 695,368
await with try/catch 328,074 235,162
await Promise.all 47,589 41,051
nested async function call 172,273 177,893
classes.js — 31 benchmarks
Benchmark Interpreted Bytecode
simple class new 112,080 338,019
class with defaults 91,419 235,280
50 instances via Array.from 5,540 6,231
instance method call 56,943 154,714
static method call 88,902 366,582
single-level inheritance 46,377 150,460
two-level inheritance 37,836 120,179
private field access 53,996 164,787
private methods 59,968 201,952
getter/setter access 62,998 171,058
class decorator (identity) 79,959 52,762
class decorator (wrapping) 48,190 36,543
identity method decorator 57,680 42,963
wrapping method decorator 47,651 39,437
stacked method decorators (x3) 33,058 28,014
identity field decorator 65,469 44,218
field initializer decorator 56,179 40,583
getter decorator (identity) 55,597 41,238
setter decorator (identity) 48,198 35,633
static method decorator 58,511 61,812
static field decorator 68,967 66,389
private method decorator 43,265 37,284
private field decorator 47,115 38,780
plain auto-accessor (no decorator) 86,015 53,731
auto-accessor with decorator 51,890 37,218
decorator writing metadata 40,308 41,574
static getter read 91,955 385,457
static getter/setter pair 70,820 207,175
inherited static getter 52,087 261,898
inherited static setter 60,370 208,366
inherited static getter with this binding 50,450 154,506
closures.js — 11 benchmarks
Benchmark Interpreted Bytecode
closure over single variable 121,837 599,398
closure over multiple variables 113,528 390,307
nested closures 111,960 564,883
function as argument 85,645 490,186
function returning function 102,832 592,481
compose two functions 60,536 347,462
fn.call 130,676 131,243
fn.apply 100,280 92,273
fn.bind 123,830 142,153
recursive sum to 50 10,680 38,656
recursive tree traversal 17,580 57,727
collections.js — 12 benchmarks
Benchmark Interpreted Bytecode
add 50 elements 6,851 5,716
has lookup (50 elements) 92,742 88,817
delete elements 48,128 36,968
forEach iteration 14,633 15,726
spread to array 27,716 23,856
deduplicate array 37,737 30,822
set 50 entries 5,555 5,777
get lookup (50 entries) 93,575 100,499
has check 137,886 159,128
delete entries 49,240 36,391
forEach iteration 15,053 16,008
keys/values/entries 7,732 102,415
destructuring.js — 22 benchmarks
Benchmark Interpreted Bytecode
simple array destructuring 367,698 606,066
with rest element 245,953 454,958
with defaults 356,282 646,820
skip elements 384,771 717,182
nested array destructuring 155,396 349,738
swap variables 454,697 976,512
simple object destructuring 260,559 521,333
with defaults 322,419 326,811
with renaming 275,234 572,795
nested object destructuring 124,896 251,266
rest properties 171,597 231,942
object parameter 81,563 187,369
array parameter 109,030 319,979
mixed destructuring in map 33,674 35,424
forEach with array destructuring 59,446 136,690
map with array destructuring 54,813 165,829
filter with array destructuring 57,837 174,596
reduce with array destructuring 65,453 169,881
map with object destructuring 76,072 65,988
map with nested destructuring 59,655 55,916
map with rest in destructuring 38,796 46,374
map with defaults in destructuring 53,937 36,415
fibonacci.js — 8 benchmarks
Benchmark Interpreted Bytecode
recursive fib(15) 301 1,130
recursive fib(20) 27 100
recursive fib(15) typed 332 1,435
recursive fib(20) typed 28 125
iterative fib(20) via reduce 10,615 16,807
iterator fib(20) 8,458 10,480
iterator fib(20) via Iterator.from + take 8,207 8,644
iterator fib(20) last value via reduce 6,823 7,837
for-of.js — 7 benchmarks
Benchmark Interpreted Bytecode
for...of with 10-element array 48,420
for...of with 100-element array 5,438
for...of with string (10 chars) 34,233
for...of with Set (10 elements) 42,783
for...of with Map entries (10 entries) 25,237 11,459
for...of with destructuring 35,968
for-await-of with sync array 38,628 44,916
iterators.js — 20 benchmarks
Benchmark Interpreted Bytecode
Iterator.from({next}).toArray() — 20 elements 10,197
Iterator.from({next}).toArray() — 50 elements 4,312
spread pre-wrapped iterator — 20 elements 9,671
Iterator.from({next}).forEach — 50 elements 3,268
Iterator.from({next}).reduce — 50 elements 3,299 3,524
wrap array iterator 55,339
wrap plain {next()} object 6,863
map + toArray (50 elements) 3,098 3,124
filter + toArray (50 elements) 3,224
take(10) + toArray (50 element source) 16,332
drop(40) + toArray (50 element source) 4,170
chained map + filter + take (100 element source) 4,859 4,861
some + every (50 elements) 1,925
find (50 elements) 4,161
array.values().map().filter().toArray() 3,542 4,318
array.values().take(5).toArray() 54,658 54,506
array.values().drop(45).toArray() 15,540
map.entries() chained helpers 5,257 2,156
set.values() chained helpers 8,286
string iterator map + toArray 7,016
json.js — 20 benchmarks
Benchmark Interpreted Bytecode
parse simple object 157,042
parse nested object 103,222
parse array of objects 50,338
parse large flat object 47,884
parse mixed types 68,244
stringify simple object 140,722
stringify nested object 73,131
stringify array of objects 36,233
stringify mixed types 69,972
reviver doubles numbers 43,090
reviver filters properties 37,565
reviver on nested object 51,218
reviver on array 26,933
replacer function doubles numbers 44,240
replacer function excludes properties 56,984
array replacer (allowlist) 106,125
stringify with 2-space indent 81,519
stringify with tab indent 80,115
parse then stringify 46,498
stringify then parse 27,571
jsx.jsx — 21 benchmarks
Benchmark Interpreted Bytecode
simple element 194,182
self-closing element 207,590
element with string attribute 165,602
element with multiple attributes 139,748
element with expression attribute 151,066
text child 183,182
expression child 183,823
mixed text and expression 173,959
nested elements (3 levels) 68,167
sibling children 52,129
component element 131,000
component with children 83,208
dotted component 115,915
empty fragment 196,380
fragment with children 51,458
spread attributes 104,497
spread with overrides 85,381
shorthand props 138,931
nav bar structure 24,778
card component tree 30,072
10 list items via Array.from 13,146
numbers.js — 11 benchmarks
Benchmark Interpreted Bytecode
integer arithmetic 504,828
floating point arithmetic 553,478
number coercion 182,351
toFixed 99,129
toString 149,344
valueOf 201,321
toPrecision 130,521
Number.isNaN 273,986
Number.isFinite 274,944
Number.isInteger 274,878
Number.parseInt and parseFloat 231,348
objects.js — 7 benchmarks
Benchmark Interpreted Bytecode
create simple object 448,111
create nested object 190,468
create 50 objects via Array.from 8,637
property read 582,384
Object.keys 283,693
Object.entries 96,056
spread operator 169,435
promises.js — 12 benchmarks
Benchmark Interpreted Bytecode
Promise.resolve(value) 457,940
new Promise(resolve => resolve(value)) 159,379
Promise.reject(reason) 481,221
resolve + then (1 handler) 144,108
resolve + then chain (3 deep) 57,243
resolve + then chain (10 deep) 18,900
reject + catch + then 81,216
resolve + finally + then 68,526
Promise.all (5 resolved) 27,219
Promise.race (5 resolved) 27,322
Promise.allSettled (5 mixed) 21,920
Promise.any (5 mixed) 25,878
strings.js — 11 benchmarks
Benchmark Interpreted Bytecode
string concatenation 376,324
template literal 407,572
string repeat 366,939
split and join 132,275
indexOf and includes 165,063
toUpperCase and toLowerCase 229,067
slice and substring 149,675
trim operations 169,728
replace and replaceAll 227,497
startsWith and endsWith 123,754
padStart and padEnd 185,157
typed-arrays.js — 22 benchmarks
Benchmark Interpreted Bytecode
new Int32Array(0) 285,132
new Int32Array(100) 266,398
new Int32Array(1000) 161,899
new Float64Array(100) 250,099
Int32Array.from([...]) 171,636
Int32Array.of(1, 2, 3, 4, 5) 275,273
sequential write 100 elements 3,450
sequential read 100 elements 3,454
Float64Array write 100 elements 3,225
fill(42) 45,539
slice() 189,281
map(x => x * 2) 6,500
filter(x => x > 50) 7,432
reduce (sum) 7,247
sort() 174,546
indexOf() 424,188
reverse() 321,873
create view over existing buffer 360,178
subarray() 438,530
set() from array 565,965
for-of loop 4,760
spread into array 15,472

Measured on ubuntu-latest x64. Changes within ±7% are considered insignificant.

The Windows CI uses i386-win32 FPC (32-bit), limiting the process to
~2 GB of address space. In bytecode mode, the Souffle VM creates heap
objects (closures, arrays, records, blueprints) that were never tracked
or collected — TSouffleGarbageCollector.Initialize was never called
anywhere in the codebase. On 64-bit platforms this leak is invisible
(sufficient address space), but on 32-bit Windows the benchmark runner
exhausts memory after ~29 seconds across 254 benchmarks.

Initialize the Souffle GC in TGocciaSouffleBackend.Create with automatic
collection disabled (Enabled := False). A full Collect runs in the
destructor to free all Souffle heap objects between backend instances.

Also fix latent bugs in the Souffle GC mark phase (never triggered
before because the GC was never initialized):
- Add GCMarked cycle-breaking checks in TSouffleArray.MarkReferences,
  TSouffleRecord.MarkReferences, and TSouffleClosure.MarkReferences
- Add FMapDelegate, FSetDelegate, and FBlueprintSuperValues to
  MarkExternalRoots

Mid-execution Collect (like the GocciaScript GC does between benchmark
measurement rounds) is not yet possible because the Souffle mark phase
does not cover all cross-GC roots in bridge call paths. Per-backend
destruction collection is sufficient to bound memory on 32-bit.

Co-authored-by: Johannes Stein <frostney@users.noreply.github.com>
@cursor cursor Bot force-pushed the cursor/windows-benchmark-memory-4b72 branch from a11a150 to 795ad62 Compare March 10, 2026 08:58
@frostney frostney marked this pull request as ready for review March 10, 2026 09:02
@frostney frostney changed the title Windows benchmark memory Fix to resolve Windows 32-bit Out Of Memory benchmark tests Mar 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AGENTS.md`:
- Line 173: The documented test count is inconsistent: AGENTS.md currently
states "3,433" while docs/souffle-vm.md's "Known Limitations" section still
shows "3,406"; update the numeric string in both documents so they match
(replace "3,406" with "3,433" or vice versa to the authoritative current value)
and ensure the "Known Limitations" heading text remains intact so search/links
still work.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c58fa0f1-3c2e-4802-a386-79a6855472e7

📥 Commits

Reviewing files that changed from the base of the PR and between d2aea53 and 795ad62.

📒 Files selected for processing (6)
  • AGENTS.md
  • docs/souffle-vm.md
  • souffle/Souffle.Compound.pas
  • souffle/Souffle.VM.Closure.pas
  • units/Goccia.Engine.Backend.pas
  • units/Goccia.Runtime.Operations.pas

Comment thread AGENTS.md
| GocciaScript Runtime | `Goccia.Runtime.Operations.pas` | `TGocciaRuntimeOperations` — GocciaScript semantics for Souffle VM, bridge caches (`FClosureBridgeCache`, `FArrayBridgeCache`, `FArrayBridgeReverse`, `FRecordBridgeCache`, `FBlueprintBridgeCache`), cross-GC rooting, array bridge sync (`SyncCachedGocciaToSouffle` at bridge entry, `SyncSouffleArrayToCache` after native mutations), native delegate methods (array, string, number, Map, Set), `FBlueprintSuperValues` for built-in subclass static property inheritance |

**Souffle VM known limitations:** The bytecode backend passes 100% of the test suite (3,406 tests). Most language features execute natively in the VM: user-defined classes with constructors, named methods, getters, setters, static members, private fields/methods, computed property names, and instance fields compile to `TSouffleBlueprint` with `__fields__` initializer closures; classes extending built-in constructors (`Array`, `Map`, `Set`, `Promise`, `Object`) compile natively via `FBlueprintSuperValues` and `TGocciaSuperCallHelper`; array and string iteration uses `TGocciaSouffleArrayIterator`/`TGocciaSouffleStringIterator`; Map and Set iteration uses direct `TGocciaMapIteratorValue`/`TGocciaSetIteratorValue` creation; built-in constructors use a `TGocciaBridgedFunction` fast path; Map/Set property access and method calls use native delegates (`FMapDelegate`/`FSetDelegate`). The bridge still delegates to the interpreter for: module imports, async/await (microtask queue), and decorator evaluation. Bridged arrays use a dual-representation model with `SyncCachedGocciaToSouffle` at bridge entry and `SyncSouffleArrayToCache` after native mutations; `FArrayBridgeReverse` preserves reference identity across round-trips. `FBlueprintBridgeCache` persists across bridge calls to maintain `instanceof` identity for blueprint-backed classes. Only classes with decorators are deferred to the interpreter via `FPendingClasses` / `GOCCIA_EXT_EVAL_CLASS`. `.sbc` binary format uses native endianness (not yet portable). ABC-encoded instructions limit constant pool references to 255 per prototype. See [docs/souffle-vm.md § Known Limitations](docs/souffle-vm.md#known-limitations) for the full list.
**Souffle VM known limitations:** The bytecode backend passes 100% of the test suite (3,433 tests). Most language features execute natively in the VM: user-defined classes with constructors, named methods, getters, setters, static members, private fields/methods, computed property names, and instance fields compile to `TSouffleBlueprint` with `__fields__` initializer closures; classes extending built-in constructors (`Array`, `Map`, `Set`, `Promise`, `Object`) compile natively via `FBlueprintSuperValues` and `TGocciaSuperCallHelper`; array and string iteration uses `TGocciaSouffleArrayIterator`/`TGocciaSouffleStringIterator`; Map and Set iteration uses direct `TGocciaMapIteratorValue`/`TGocciaSetIteratorValue` creation; built-in constructors use a `TGocciaBridgedFunction` fast path; Map/Set property access and method calls use native delegates (`FMapDelegate`/`FSetDelegate`). The bridge still delegates to the interpreter for: module imports, async/await (microtask queue), and decorator evaluation. Bridged arrays use a dual-representation model with `SyncCachedGocciaToSouffle` at bridge entry and `SyncSouffleArrayToCache` after native mutations; `FArrayBridgeReverse` preserves reference identity across round-trips. `FBlueprintBridgeCache` persists across bridge calls to maintain `instanceof` identity for blueprint-backed classes. Only classes with decorators are deferred to the interpreter via `FPendingClasses` / `GOCCIA_EXT_EVAL_CLASS`. `.sbc` binary format uses native endianness (not yet portable). ABC-encoded instructions limit constant pool references to 255 per prototype. The Souffle GC is initialized by `TGocciaSouffleBackend.Create` with automatic collection disabled; a full `Collect` runs in the backend destructor to free Souffle heap objects between files (critical on 32-bit Windows where address space is limited to ~2 GB). See [docs/souffle-vm.md § Known Limitations](docs/souffle-vm.md#known-limitations) for the full list.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep the test-count docs in sync.

This now says 3,433 tests, but docs/souffle-vm.md still says 3,406 in the Known Limitations section. Please update both sources together so contributors do not end up with conflicting baseline numbers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` at line 173, The documented test count is inconsistent: AGENTS.md
currently states "3,433" while docs/souffle-vm.md's "Known Limitations" section
still shows "3,406"; update the numeric string in both documents so they match
(replace "3,406" with "3,433" or vice versa to the authoritative current value)
and ensure the "Known Limitations" heading text remains intact so search/links
still work.

@frostney frostney merged commit b78b6f9 into main Mar 10, 2026
7 checks passed
@frostney frostney deleted the cursor/windows-benchmark-memory-4b72 branch March 10, 2026 09:13
@frostney frostney added the bug Something isn't working label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants