fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix: secondary index cache invariant bug in update/remove - #5

Open
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant
Open

fix: secondary index cache invariant bug in update/remove#5
paulgnz wants to merge 1 commit into
XPRNetwork:masterfrom
paulgnz:fix/secondary-index-cache-invariant

Conversation

@paulgnz

@paulgnzpaulgnz commented Feb 5, 2026

Copy link
Copy Markdown

Summary

Two bugs fixed in v0.2.15:

  1. vm.ts — Cache invariant bug: genericIndex.update() and genericIndex.remove() fail to cache the table before accessing it, causing "an invariant was broken, table should be in cache" assertion failures
  2. table.ts — Operator precedence bug in IndexObject.compare (already fixed on master but present in published v0.2.15): Due to || having higher precedence than ?:, the comparator returns 0 (EQUAL) for entries from different tables, causing BTree lookups to return wrong secondary index entries and triggering spurious "db access violation" errors

Problem 1: Cache Invariant

When contracts update or remove rows in tables with secondary indexes, db_idx64_update/db_idx64_remove call cache.getTable(obj.tableId), which asserts the table is already cached. This invariant is not guaranteed.

genericIndex methodCaches table?
store()Yes
find_secondary()Yes
find_primary()Yes
update()No (FIXED)
remove()No (FIXED)

Problem 2: Operator Precedence (v0.2.15 only)

// BUGGY (v0.2.15):staticcompare(a,b): number{returnIndexObject.compareTable(a,b)||(a.ignorePrimaryKey||b.ignorePrimaryKey)
? 0// <-- returns 0 when compareTable is non-zero!
: (primaryKeycomparison);}

Due to || binding tighter than ?:, when compareTable returns -1 or 1 (different tables), the expression (-1 || false) is truthy, so the ternary returns 0 (EQUAL). This makes the BTree unable to distinguish entries from different tables, causing find_primary to return secondary index objects belonging to the wrong contract.

Reproduction: Any test scenario where multiple contracts store rows in tables with secondary indexes and then one contract calls an inline action on another that updates its own table.

Fix

  1. vm.ts: Retrieve table from bc.store.getTableById() and re-cache it (matching the pattern used by store()/find_secondary()/find_primary())
  2. table.ts: Already fixed on master — the compare function was rewritten with explicit early returns

Test Results

  • 114 passing tests across 4 contract test suites (agentcore: 32, agentfeed: 23, agentvalid: 28, agentescrow: 31)
  • 0 pending/skipped
  • All previously-failing scenarios (token transfer handlers, cross-contract inline actions) now pass

Generated with Claude Code

…te and remove
The `genericIndex.update()` and `genericIndex.remove()` methods assume the
table is already present in the IteratorCache when called, but this invariant
is not guaranteed. When a secondary index entry is stored via `store()`, the
table is cached, but by the time `update()` or `remove()` is called, the
cache may no longer contain the table reference (e.g., after table resets or
across separate action invocations).
This causes "an invariant was broken, table should be in cache" assertion
failures during `db_idx64_update` and `db_idx64_remove` operations,
particularly when contracts update tables with secondary indexes inside
token transfer notification handlers.
Fix: Instead of calling `cache.getTable(obj.tableId)` (which asserts the
table is cached), retrieve the table from the authoritative store via
`this.bc.store.getTableById(obj.tableId)` and re-cache it. This matches
the pattern already used by `find_secondary()` and `find_primary()`.
Affected methods and their caching behavior (before fix):
- store() → caches table ✓
- find_secondary() → caches table ✓
- find_primary() → caches table ✓
- update() → assumes cached ✗ (NOW FIXED)
- remove() → assumes cached ✗ (NOW FIXED)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
Apply patch-package fix for @proton/vert v0.2.15 secondary index cache
invariant bug where genericIndex.update() and remove() fail to call
cache.cacheTable() before lookup. Unskip dispute and escrow tests that
were blocked by this bug. PR submitted upstream: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paulgnz added a commit to XPRNetwork/xpr-agents that referenced this pull request Feb 6, 2026
… remaining tests
Second @proton/vert v0.2.15 bug: IndexObject.compare() in table.ts has
a JS operator precedence issue where || binds tighter than ?:, causing
BTree lookups to return secondary index entries from wrong tables. This
triggered "db access violation" in cross-contract inline actions (e.g.,
approve/arbitrate calling incjobs on agentcore).
Fix: add parentheses around the ternary expression. All 114 tests now
pass with zero pending. Updated upstream PR: XPRNetwork/vert#5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for freeto 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

@paulgnz