Skip to content

feat(sqlite): inspect database snapshots and selected table rows - #1356

Closed
Y0UW1SH wants to merge 17 commits into
morluto:mainfrom
Y0UW1SH:feat/sqlite-inspection
Closed

Y0UW1SH wants to merge 17 commits into
morluto:mainfrom
Y0UW1SH:feat/sqlite-inspection

Conversation

@Y0UW1SH

@Y0UW1SH Y0UW1SH commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add standalone SQLite schema and selected-row inspection through inspect_sqlite_database and rea inspect-sqlite-database. Preserve original database/WAL identities and lossless integer, blob, and text values.

Requested enhancement; no linked issue.

Problem and expected behavior

Callers can inspect a quiescent SQLite database or application-created backup directly, without opening a native analysis target:

rea inspect-sqlite-database ./application.sqlite --table settings --row-limit 20 --json

Equivalent MCP arguments: {"path":"/artifacts/application.sqlite","table":"settings","row_limit":20}.

Review and CI corrections in this update:

  • Report SQLite runtime availability in rea capabilities before a database is selected. CLI and MCP share the runtime policy and upgrade note; Node 22 and Node 24.11–24.14 remain supported for other REA features.
  • Retain failed DB, WAL, journal, and worker-reply descriptor owners. Retry cleanup before another inspection and during shutdown, while preserving permission-denied and cancellation diagnostics.
  • Preserve the original CLI inspection failure alongside a later shutdown failure. Keep cancellation during reply reading typed as cancellation even when releasing its descriptor fails.
  • Set fixture statements to return BigInt row IDs. The previous default rounded a 64-bit row ID on Node 24 and rejected it on Node 26 before inspection ran.
  • Incorporate upstream cleanup fixes for browser, EVM, firmware, and shared-skill regressions. Keep selected path assertions exact on Windows by checking decoded CLI messages; normalize the SVG condition to repository formatting.
  • Share regression fixture setup and cleanup assertions without dropping failure-path cases, preserving the repository duplicate-code limit.
  • Add a reusable SQLite compatibility workflow covering the minimum supported runtime and rolling Node 22.x, 24.x and 26.x releases alongside the pinned Node 24 full suite.

Change and scope

Copy a checked DB/WAL file set into a private runtime root and inspect it in an owned, cancellable SQLite worker. Inventory tables, columns, indexes, views, triggers, and stored virtual declarations; optionally read bounded rows from one exact ordinary table. Preserve failed resource owners until release is confirmed.

Contract and boundary impact

  • Semantic owner: provider-neutral SQLite domain contracts, application service, and local SQLite adapter.
  • CLI/MCP/catalog: one additive, target-free artifact inspection contract with canonical effects and generated catalog registration.
  • Compatibility: inspection requires Node 24.x >=24.15 or 26+ and native DatabaseSync.limits support. rea capabilities exposes runtime availability and remediation before inspection; unsupported runtimes still run the inventory successfully.
  • Evidence: original paths, DB/WAL SHA-256 and byte counts, observed schema, exact selected table, explicit row limits and truncation.
  • Execution/cleanup: temporary filesystem writes and an owned worker with deadlines, native SQLite value/SQL limits, bounded JSON, and a JavaScript heap limit. Source database files remain unchanged.
  • Metadata/package: authored docs and skill guidance updated; generated outputs stay ignored. No new dependency.

Evidence and regression coverage

Executed real SQLite fixtures cover WAL commits, quoted identifiers, integer boundaries, blob and text encodings, nonfinite values, corrupt input, native resource limits, and journal handling. Filesystem cases cover replacement and changes across acquisition.

Fourteen descriptor cleanup regressions cover DB/WAL/journal/reply release, retry admission, sticky invalidated-handle failures, EACCES/EPERM, caller cancellation, and CLI shutdown diagnostics. The four latest regressions reproduced the diagnostic failures before their fixes; the permanent reply regression uses the production owned-worker launcher.

Representative selected values:

{"columns":["id","payload"],"values":[[{"type":"integer","value":"1"},{"type":"blob","hex":"01"}]],"returned_rows":1,"truncated":true}
  • Observed and unsupported outcomes remain distinct.
  • Original artifact identity and source provenance remain preserved.
  • Failed cleanup and truncation remain visible.

Update hardening

  • Move SQLite compatibility into a reusable workflow, leaving a small call in the shared CI file.
  • Cover Node 22.x unavailable-runtime diagnostics, the minimum supported 24.15.0 release, and rolling 24.x/26.x releases. The pinned runtime still runs the full suite.
  • Use one SQLite test command locally and in CI; directory filters automatically include new service and boundary tests.
  • Select the shared build when the SQLite workflow changes, and guard the required gate against omitted dependencies or failed, cancelled, skipped, or missing selected SQLite results.
  • Merge upstream through f998fcb1 and correct its two formatting failures without changing their behavior.

Validation of the tree published as 2d96bf77:

  • Build, all eight static-check tasks, architecture guards, documentation checks, and discovery of all 811 test files passed.
  • 58 CI selector/gate and reference-source regression tests passed. The workflow-only selector case failed before the fix.
  • npm run test:sqlite: 81 passed, 2 skipped, 17 worker-dependent failures due to this host's existing procps/PID namespace mismatch. Real worker coverage remains with CI; the previous GitHub run passed the Node 22 and Node 26 SQLite lanes.
  • Independent review found no actionable defects in the scoped hardening.
  • Fresh GitHub CI passed all four SQLite runtime jobs (22.x, 24.15.0, 24.x, 26.x), build, static checks, documentation generation, and workflow validation on this head. Remaining repository-wide jobs are still running. The previous run failed the separate binary-layout memory-limit verifier on process-identity cleanup; its new result is not yet complete.

These changes reduce avoidable integration drift and detect runtime regressions. They do not guarantee compatibility with arbitrary future changes to main.

Earlier validation

On local Node 24.19.0:

  • npm run check:ci: all eight tasks and architecture guards passed.
  • npm run test:prepare and npm run docs:check: passed.
  • node scripts/verify-test-discovery.mjs: all 800 test files discovered exactly once.
  • Runtime policy, capability inventory, SQLite service, CLI output/status and one-shot lifecycle coverage: 54 tests passed.
  • The compiled CLI discovery regression failed for the missing SQLite row before the fix. After the fix, the compiled CLI and real MCP discovery regression passed, including output-schema validation.
  • Follow-up validation: 59 path-resolution tests passed against current main; 15 Electron composition cases and the three compiled CLI/MCP preload and catalog cases passed on the feature branch.
  • Independent review: no actionable findings in the runtime-discovery or four-file CI fixture follow-up.
  • git diff --check: passed.

Full CI on the discovery fix exposed Electron fixtures missing the explicit imports required by current main and a catalog test with a narrower timeout than the configured suite budget. The follow-up declares inert Electron imports, preserves source-range assertions, and restores that catalog case's configured budget.

Fresh GitHub Actions CI passed on corrected head d63d1b15ca475548f408333be0268146c5ee475b: all 33 jobs, including the final CI required gate.

  • Full coverage suite: 7,274 passed, 91 skipped, 0 failed across 802 test files.
  • SQLite runtime compatibility: Node 22.23.1, 67 passed / 33 expected skips; Node 26.11.1, 98 passed / 2 expected skips. Both exercised real CLI and MCP runtime discovery.
  • Real Apple CLI/MCP, Windows capability/package, Linux x64/arm64 and macOS x64/arm64 package lanes passed.

Compatibility, safety, and release

Additive feature; no migration. Inspection accepts clean offline snapshots and inactive journals. A stable file set does not establish an atomic live backup. Arbitrary caller SQL, extensions, repair, encryption, and deleted-record recovery remain unsupported. Native heap/RSS is not fully capped; the worker and transport output budgets are separate.

Local owned-worker acceptance runs are blocked by this host's PID/procfs mismatch (procps: fatal library error, lookup self). The earlier GitHub Actions run on d63d1b15 passed the real CLI/MCP, process, and platform checks; validation for the hardening update is reported separately above.

Review checklist

  • Concrete requested enhancement and conventional title.
  • Named contracts and source identities reviewed.
  • Meaningful producer, resource, and failure-path tests.
  • Owning docs and canonical catalog sources updated.
  • Representative CLI/MCP output included.
  • Final diff checked for unrelated changes and build outputs.

Use direct, identifier-quoted table_xinfo PRAGMA statements so stored tables
or views named pragma_table_xinfo cannot break database inspection. Cover
both shadowing cases with real SQLite fixtures and preserved selected rows.

Keep the synthetic JADX cleanup-failure child alive after stdin EOF until
verified teardown kills it, avoiding natural-exit races in ownership scans.
Include the stop result in teardown assertion failures.

Validation: 21 focused SQLite tests, all eight check:ci tasks, runtime build,
and real fixture EOF/lifetime probes passed. Local owned-worker and public
SQLite tests remain blocked by this host's procps/PID namespace mismatch;
those existing tests passed in the original GitHub CI run.
Keep possible shadow tables unknown when their virtual module cannot be resolved, and reject row selection through CLI and MCP.

Read schema text directly as bytes without hex expansion or native sort records, preserving exact encodings and valid large definitions. Add real SQLite regressions for unknown modules, malformed text, UTF-16, large SQL, and long identifiers.
Declare unavailable function-body ranges and absent native API/value-flow evidence explicitly. The package fixture must satisfy the stricter function dossier contract now on main.

Reproduced the CI rejection against the PR merge commit, then verified the same managed CLI workflow passes with the completed fixture.
Resolve the overlapping managed-native fixture fixes by retaining main's shared, validated function dossier builder.

All SQLite changes are preserved. The merged tree passes 36 focused SQLite/MCP tests, all 8 static tasks, the runtime build, and the real managed CLI package verification.
@Y0UW1SH
Y0UW1SH marked this pull request as ready for review October 9, 2026 20:19
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

Accept stable empty or fully zeroed rollback journal headers left by clean TRUNCATE/PERSIST commits, while refusing active, malformed, symlinked or changing journals. Bind each member read to the original file-set observation and report disappearance or replacement as changed evidence.

Separate schema metadata preflight accounting from the final reply budget so names are not charged twice. Add real SQLite, filesystem-race and CLI/MCP regressions.

Verified 49 focused tests, all static checks, runtime build and generated docs.
Encode REAL negative zero as the explicit string -0 alongside the existing infinity representations, preventing JSON serialization from silently changing the observed value to positive zero.

Update the output contract and documentation, add a real SQLite regression that distinguishes REAL -0, REAL 0 and INTEGER 0, and extend CLI/MCP acceptance fixtures across rollback journal modes.
@morluto

morluto commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Review of 878b873: the offline DB/WAL acquisition, quoted table selection, read-only engine configuration, typed integers/REAL/blob/text representation and CLI/MCP parity are well covered. I independently ran the inspection/snapshot/real CLI+stdio MCP subset: 35 tests passed.

P2 — retain the cleanup owner when private snapshot removal fails. In src/sqlite/SqliteDatabaseProvider.ts:51,96-100,151-173, the runtime root is local to inspect(). If root.close() fails, the returned error contains its path and previous outcome, but the provider keeps no root handle and exposes no retry lifecycle. A fault-injection probe with a failing runtime close made two inspections allocate two roots with close-attempt counts [1,1]; the first owner was never retried. This can strand a database/WAL copy, and the Windows runtime wrapper also needs its owner retained.

Please retain failed roots in a supervised collection and provide an awaited retry/close path through the service/server lifecycle, with a failure-then-success regression. Reporting the residual path is useful, but does not substitute for retaining ownership.

Design follow-up: the hard 1000-row input ceiling (src/domain/sqlite/sqliteDatabase.ts:7,34) is independent of the already-enforced byte/deadline limits. Please explain its measured/format basis or rely on the actual resource budgets; a small 1001-row request currently fails validation even when it would fit the reply budget. This is distinct from the correctly reported sample truncation.

@CassieFox23

CassieFox23 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR: This works well on Node 24.18.0. Schema, lossless rows, WAL-only rows and the row bounds all check out. The source files stay untouched. On Node 22.23.1, the tool says it needs Node 24.15+, as the docs say. But 31 of the 63 new tests then fail on Node 22, instead of skipping.

I used Node 24.18.0, which is this repo's .nvmrc, and Node 22.23.1. Main at bf934d5 doesn't have this tool yet. Published 6.2.0 says COMMAND_NOT_FOUND.

Tests.

  • The five new test files pass on Node 24.18.0: 63 of 63.
  • The full suite on Node 24.18.0 passes too. That's 695 files and 6,295 tests, with 89 skipped and 0 failures.
  • On Node 22.23.1, 31 of the 63 new tests fail. Each one gets capability_unavailable, the "needs Node.js 24.15" error, where it expects success.

CI runs only the .nvmrc version, so it won't catch this. engines still allows ^22.19.0. So gating those tests on DatabaseSync.limits would keep a Node 22 run green.

Real checks. These ran on Node 24.18.0, through the CLI and over stdio MCP. The databases are ones I built with Python's sqlite3.

Check Result
3 tables (one WITHOUT ROWID), an index, a view, a trigger all listed
9007199254740993 and -9223372036854775808 exact, as strings
A 3-byte blob and an empty blob exact hex
Text stored as bytes c3 28 ff (not valid UTF-8) bytes_hex exact
A 2,002-row table 100 rows by default, marked truncated
--row-limit 1000 / 1001 1,000 rows / rejected
Rows only in an uncheckpointed -wal both rows returned
--table on a view refused, nothing run
--table "items; DROP TABLE log" refused, nothing run
A truncated file "database disk image is malformed"
A file that isn't SQLite "file is not a database"
Four calls in one MCP session all fine
Every source file after all runs same SHA-256, size and mtime

No -wal or -shm file appeared next to any source file. The WAL copy's own -wal and -shm stayed byte-identical.

One small UX note. On Node 22 the tool still shows in tools/list and in rea capabilities. And rea doctor and rea providers say nothing about SQLite. So a Node 22 user finds out only at call time. The error is clear, though. A doctor or providers line could flag it earlier.

I didn't test encrypted databases, any real app databases, or macOS and Windows.

Test setup
  • Box: Linux x86-64
  • Node: 24.18.0, 22.23.1
  • Head: 878b87379

🤖 Generated with Claude Code (Opus 5.5) 🦊

Retain failed snapshot cleanup owners for awaited retry and CLI/MCP shutdown. Accept row samples bounded by actual byte and worker budgets. Gate native-engine tests on DatabaseSync.limits and cover unsupported runtimes explicitly.

Merge current upstream main and resolve documentation/fixture conflicts.

Validation: build and check:fast pass; focused Node 24 tests 51 passed, 1 capability skip; Node 22 tests 30 passed, 18 capability skips. Local worker tests are blocked by the environment's ps/process-identity visibility and remain for CI.
Retain failed SQLite worker supervisors before attempting snapshot removal. Retry process cleanup before releasing the database/WAL runtime root, and keep failed MCP server instances reachable after SDK shutdown or stdin EOF.

Add regressions with a real owned child and the actual SDK stdio transport, including failure followed by successful cleanup and completed-owner release.

Validation: 62 focused tests passed on Node 24.18.0 (one unsupported-runtime test skipped), 18 cleanup/shutdown tests passed on Node 22.23.1; build, typecheck, lint, formatting and diff checks passed.
@CassieFox23

Copy link
Copy Markdown
Contributor

TL;DR: Fixed: on Node 22.23.1 the new tests now skip instead of failing. Fixed: a failed snapshot cleanup is kept and retried, and the 1,000-row cap is gone. Still open: a Node 22 user learns about the Node 24.15 need only when the tool runs.

This follows my earlier comment. I tested the new head a9ce5887d against the old head 878b87379. The base is main at 0d8997833.

Check Old head 878b87379 New head a9ce5887d
SQLite tests, Node 22.23.1 32 pass, 31 fail 41 pass, 0 fail, 33 skip
SQLite tests, Node 24.18.0 63 pass 72 pass, 2 skip
SQLite tests, Node 26.11.1 60 pass, 3 fail 69 pass, 2 skip, 3 fail (see below)
Tool on Node 22 (CLI and MCP) "needs Node 24.15+" same message
Tool on Node 24 and 26, 6 fixtures works same output, except the row cap
--row-limit 1001 on a 2,002-row table rejected 1,001 rows, marked truncated
--row-limit 3,000 on 8 KiB blobs rejected refused: over the 16 MiB reply budget
Failed cleanup, second MCP call runs fine, first copy stays same cleanup error, no new copy
Block lifted, then a call first copy stays call works, copy removed
MCP shutdown while cleanup fails exit 0, copy stays, no message exit 1, error logged, copy stays
MCP shutdown after the block is lifted copy stays exit 0, copy removed
npm run check:fast, Node 24.18.0 not run passes

The counts differ by head. The new set has 74 tests: the earlier 63, plus 4 in the new cleanup file, 4 in changed files and 3 shutdown tests in serverLifecycleMcp.test.ts. The two Node 24 skips are the tests that expect no native limits. The table counts those 74 tests. The Raw output fold counts all 77 tests in the seven files, which adds 3 older tests in serverLifecycleMcp.test.ts that are not about SQLite.

Fixed from my earlier comment.

  • The 31 Node 22 failures are now skips. The gate is "limits" in new DatabaseSync(":memory:").
  • The 1,000-row input cap is gone. Large samples are bounded by the 16 MiB reply budget, with a clear message.
  • The tool description on the MCP tools/list shows the new wording on all three Node versions.

P2 from the review. Fixed. A failed cleanup is now kept, retried before the next call, and retried again at shutdown. Details are in the fold below.

Two things I saw that are not fixes.

  • On Node 26.11.1, 3 acceptance tests fail on both heads. The test setup itself throws before REA runs: run() in Node 26's node:sqlite raises a RangeError for the number 9,007,199,254,740,993. The tool is fine on Node 26: its output matches Node 24, apart from the bundled SQLite (3.53.4 against 3.51.2).
  • On Node 22, rea capabilities, rea doctor and rea providers still say nothing about the Node 24.15 need.

The "local worker tests". The commit says they are blocked by process visibility. Here they were not. On Linux they ran and passed on Node 24.18.0 and 26.11.1. That is 15 of 15 in the provider file and 4 of 4 cleanup tests. The real CLI and MCP cases passed too. No test skips for process reasons. Node 22 skips them only for the native limit. So I could not reproduce the block here. I could not match the commit counts. The middle head's message says 51 and 30. The new head's says 62 on Node 24 and 18 on Node 22. Neither says which files it ran.

Not run

Thanks, Y0UW1SH, for the quick fixes and the real stdio shutdown tests.

P2 cleanup check, step by step

I made the private snapshot copy hard to delete. A read-only subfolder inside my own folder did it. The first MCP call reported cleanup_incomplete and named the folder. A second call, still blocked, returned the same error at once and made no new copy. After I lifted the block, the third call worked and the old folder was gone.

I then shut the server down with the block still on. It exited with code 1 and logged "Provider cleanup failed during server shutdown". It did not print the folder path. With the block lifted first, shutdown exited 0 and removed the folder.

On the old head, a second call worked and only the first copy stayed, even after I lifted the block and closed the server.

The CLI reports the same cleanup_incomplete with the path and exits 1. Its folder stays. From the code, a CLI run ends its process, so nothing can retry later.

Commands
# Node 22 is the system node; 24 and 26 are under ~/.local/opt/node24 and node26
env -i HOME=<fake> PATH=<node bin>:/usr/bin:/bin TMPDIR=/tmp \
  node node_modules/vitest/vitest.mjs run <files> --reporter=verbose --reporter=json
rea inspect-sqlite-database <db> [--table T] [--row-limit N] --json
# MCP: tools/call inspect_sqlite_database over stdio (rea mcp)
npm run check:fast

The test files: src/application/sqlite/SqliteDatabaseService.test.ts, tests/acceptance/sqliteDatabaseCli.test.ts, the four files in tests/boundary/sqlite/, and tests/boundary/mcp/serverLifecycleMcp.test.ts.

I built the fixtures with Python's sqlite3.

  • A normal database with a 2,002-row table.
  • A WAL database with two rows only in the -wal file.
  • A types database: blobs, REAL, negative zero, big integers, and text that is not UTF-8.
  • A database with an open writer.
  • A truncated file, and a file that is not a database.

Every source file kept the same SHA-256 after every run.

To block cleanup, a small script waited for the snapshot folder, then added blocker/f and ran chmod 500 blocker. Lifting the block was chmod 700 blocker.

Raw output
Node 22.23.1   old: 32 passed, 31 failed        new a9ce5887d: 44 passed, 33 skipped (incl. 6 lifecycle tests)
Node 24.18.0   old: 63 passed                   new: 75 passed, 2 skipped (incl. 6 lifecycle tests)
Node 26.11.1   old: 60 passed, 3 failed         new: 72 passed, 2 skipped, 3 failed (incl. 6 lifecycle tests)

MCP, new head, Node 24.18.0, block kept:
call 1 -> cleanup_incomplete, EACCES unlink '<root>/blocker/f'
call 2 -> cleanup_incomplete, same root, no new folder
unblock -> call 3 ok (5 rows), folder gone
shutdown with block: exit 1, "Provider cleanup failed during server shutdown"
shutdown after unblock: exit 0, folder gone
Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 22.23.1, 24.18.0, 26.11.1
  • Head / base: a9ce5887d / 0d8997833; old head 878b87379
  • Other: I also ran the tests, fixtures and a retry check on the middle head 75930f070, with the same pattern. I ran the shutdown checks only on a9ce5887d.

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

@Y0UW1SH
Y0UW1SH marked this pull request as draft October 10, 2026 21:32
…atibility

Merge upstream fixes for failing browser, firmware, EVM and shared-skill regressions. Preserve failed SQLite source and reply descriptors through cleanup retries, including original permission and cancellation diagnostics. Read fixture insertion row IDs as exact BigInts and exercise SQLite on Node 22 and 26.
@Y0UW1SH
Y0UW1SH marked this pull request as ready for review October 10, 2026 22:03
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@Y0UW1SH
Y0UW1SH marked this pull request as draft October 10, 2026 22:10
…anup

Retain primary CLI inspection errors alongside shutdown failures, and keep
reply-read cancellation typed when descriptor cleanup is incomplete.
Add four real-filesystem CLI and worker boundary regressions.
Merge current main while preserving the reviewed SQLite cleanup fixes.
Normalize the SVG context condition to the repository formatter and assert
selected paths in decoded CLI errors so Windows backslashes remain exact.
Merge upstream's decoded Windows path assertions and cleanup updates.
Share the SQLite snapshot fixture, unavailable-worker setup, and private
root removal assertion while preserving all failure injections and cases.
@Y0UW1SH
Y0UW1SH marked this pull request as ready for review October 10, 2026 23:01
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@CassieFox23

CassieFox23 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR: Still open: at the command line, a Node 22 user learns about the Node 24.15 need only when the tool runs. MCP clients can see it earlier. Fixed: the 3 Node 26 test failures are gone, and a failed cleanup no longer hides the original error.

Edit, 11 October, 03:23 UTC: I retested at d63d1b1, and the results are here. rea capabilities now has a SQLite row, but rea doctor still does not. MCP shutdown after the lock lifts now ran. Node 24.11 to 24.14 is still not run for real.

This follows my retest at a9ce588. I tested the new head eed34a6. Its base is 60fbb2f on main.

My open item: not fixed for the command line.

  • The package's engines field accepts Node 22.19 and newer. So npm does not object on 22.23.1.
  • rea capabilities and rea doctor print the same thing on Node 22.23.1 and 24.18.0, apart from the timestamp and the Node version. Neither has a SQLite row.
  • The first sign from the tool itself is the error when it runs: SQLite inspection requires the native DatabaseSync.limits API to bound untrusted values and SQL. Use Node.js 24.15 or newer in the supported 24.x line, or a compatible Node.js 26+ runtime. (code capability_unavailable, exit 1).
  • An MCP client does get an earlier hint. The tool description in tools/list says "Requires Node.js 24.x >=24.15 or 26+". The binary_session status tool lists the tool as provider_unavailable on Node 22.23.1, with a fix note. I missed that last time. The code for it is identical at a9ce588 and eed34a6; I did not run a9ce588 again.
  • The README table and docs/sqlite-databases.md also state the need.

A one-line row in rea doctor or rea capabilities would close it for the command line.

What changed since a9ce588

Only the PR's own code is listed. I compared the PR diff against its base at each head.

Change Where
File handles get a retained owner. A failed close is retried. 4 SQLite source files and 1 shared file
A failed cleanup keeps the first error. Failures, worker and CLI code
New CI job "SQLite runtime compatibility". It runs 8 test files on Node 22.23.1 and 26.11.1. ci.yml
New test file with 14 tests. Descriptor cleanup test
Test setup reads row ids as BigInt. It is the only change to that file, and the 3 Node 26 failures are gone. CLI acceptance test
Shared test helpers. 3 SQLite test files

Other callers of the shared file pass no scope and behave as before. The PR now touches 42 files with 4,684 added lines. At a9ce588 it was 39 files and 4,085 lines.

Results

I ran the CI job's 8 test files on each Node. Each run has 91 tests. At a9ce588 the same 7 files had 77. The new file adds 14.

Check Node 22.23.1 Node 24.18.0 Node 26.11.1
8 CI test files 58 pass, 33 skip, 0 fail 89 pass, 2 skip, 0 fail 89 pass, 2 skip, 0 fail
The 7 files at a9ce588. These are the counts in my last Raw output fold. They include all 6 lifecycle tests. 44 pass, 33 skip 75 pass, 2 skip 72 pass, 2 skip, 3 fail
Tool on 14 CLI cases refuses all 14, exit 1 14 as expected same output as Node 24
Schema refused 3 tables, index, view, trigger same; SQLite 3.53.4 against 3.51.2
Lossless rows refused exact same
WAL-only rows refused 3 rows, 2 only in the WAL same
Row bounds refused see Row checks same

The 33 skips on Node 22 are the tests that need native limits. So the new Node 22 job checks cleanup and shutdown, not inspection. The 2 skips on Node 24 and 26 are the tests that expect no native limits. The 3 Node 26 failures were in the test setup, and they pass now.

Row checks, Node 24 and 26 (identical output)
  • Big integers keep every digit. The test value was 2 to the power 53, plus 1.
  • A -0 stays "-0". Infinity and -Infinity are kept.
  • A blob keeps its hex, and so does an empty blob. Text that is not UTF-8 keeps bytes_hex c328ff.
  • --table items returns 100 rows. 1,000 and 1,001 both work, and both are marked truncated.
  • --row-limit 9007199254740991 on 2,002 rows returns all 2,002, not truncated.
  • 3,000 rows of 8 KiB blobs: refused, "Selected cells exceed the 16 MiB reply budget before text/hex expansion."
  • A view, a missing table and items; DROP TABLE log are each refused with "does not exist with that exact name".
  • A truncated file says "database disk image is malformed". A non-database says "file is not a database". A database with an open writer says "Rollback journal may require recovery".
  • All 8 source files kept the same SHA-256 after every run. No -shm or journal file appeared next to them.

Forced cleanup failure (Node 24.18.0). I made the private snapshot folder hard to delete, inside my own /tmp folder.

Case Result
Locked subfolder, normal read cleanup_incomplete names the folder: EACCES on unlink. A second call gives the same error in under 1 ms, with no new copy. After I lift the block, the third call works and the folder is gone. Node 26.11.1 does the same.
Same lock, truncated.db The original error rides in previous_error: "database disk image is malformed". It is still there on the second call.
Folder itself made read-only (chmod 500) The worker fails with EACCES on reply.json. That permission error is kept in previous_error, with the cleanup error on top (EACCES on database.snapshot).
Cancel sent mid-call, block on The cancelled call gets no reply. The next call returns cleanup_incomplete with previous_error code cancelled.
MCP shutdown, lock still on Exit 1. The log says the provider cleanup failed. The folder stays.
CLI, same three locks Exit 1, a JSON error on stdout, nothing on stderr. In the two failed reads, the original error sits inside previous_error. The folder stays, because the process exits.

Not run

  • The full test suite, the CI job on GitHub itself, and npm run check:fast.
  • Main at 1b527f4, which is 2 commits past the base. I tested the head as it stands.
  • Node 24.11 to 24.14. The package accepts them, but the tool needs 24.15. The check is ^24.15.0 || >=26.0.0 in the code; I did not run it on those versions.
  • MCP shutdown after the lock is lifted. I checked that only at a9ce588. Ran at d63d1b1: exit 0, folder gone.
  • Windows and macOS.
  • Encrypted databases. Real app databases.
  • A live writer in WAL mode. I tried one open rollback-journal writer, and it is refused.

Thanks, Y0UW1SH, for the descriptor cleanup work and the BigInt fix.

Odd things I saw
  • On the CLI, primary_error and cleanup_error hold the same cleanup error, so the output prints it twice. The original error is inside both, under previous_error.
  • In the cancel case, the previous_error details say "cleanup": "complete", while the outer error says cleanup is incomplete. I did not trace what the inner word refers to.
  • On shutdown with the block on, the last 2,500 characters of stderr do not name the folder.
  • SQLite stores -0.0 in a REAL column as 0.0. It also rounded my literal -1.5e-300 on the way in. Python's sqlite3 reads back the same values, so the tool reports what is stored.
  • Asking for 1,000 rows of 8 KiB blobs over MCP gives a resource_constraint error about the stdio response budget.
Commands
# Node 22 is the system node; 24 and 26 are under ~/.local/opt/node24 and node26
git archive eed34a6e1 | tar -x -C head; npm ci; npm run build; npm run test:prepare
node scripts/generate-completion-ledger.mjs   # CI runs this too
env -i HOME=<fake> PATH=<node bin>:/usr/bin:/bin TMPDIR=<tmp> \
  node node_modules/vitest/vitest.mjs run \
  src/application/sqlite/SqliteDatabaseService.test.ts \
  tests/acceptance/sqliteDatabaseCli.test.ts \
  tests/boundary/sqlite/sqliteDatabaseCleanup.test.ts \
  tests/boundary/sqlite/sqliteDatabaseDescriptorCleanup.test.ts \
  tests/boundary/sqlite/sqliteDatabaseInspection.test.ts \
  tests/boundary/sqlite/sqliteDatabaseProvider.test.ts \
  tests/boundary/sqlite/sqliteDatabaseSnapshot.test.ts \
  tests/boundary/mcp/serverLifecycleMcp.test.ts \
  --reporter=verbose --reporter=json
rea inspect-sqlite-database <db> [--table T] [--row-limit N] --json
rea capabilities --json; rea doctor --json
# MCP over stdio: tools/list, tools/call binary_session, tools/call inspect_sqlite_database

Fixtures came from Python's sqlite3.

  • A normal database with a 2,002-row table.
  • A WAL database with two rows only in the -wal file.
  • A types database: blobs, REAL, negative zero, big integers, and text that is not UTF-8.
  • A database with an open writer.
  • A truncated file, a file that is not a database, and a 3,000-row table of 8 KiB blobs.

To block cleanup, a small script waited for the snapshot folder. Then it added blocker/f and ran chmod 500 blocker. For the folder case it ran chmod 500 on the folder itself. Lifting the block was chmod 700. For the cancel case a client sent notifications/cancelled as soon as the block was in place.

Raw output
CI files, 8, 91 tests each      Node 22.23.1: 58 passed, 33 skipped, 0 failed
                                Node 24.18.0: 89 passed, 2 skipped, 0 failed
                                Node 26.11.1: 89 passed, 2 skipped, 0 failed

Node 22.23.1, rea capabilities and rea doctor: no SQLite row
Node 22.23.1, MCP binary_session row: available=false, reason=provider_unavailable
Node 24.18.0 and 26.11.1, same row: available=true

MCP, Node 24.18.0, truncated.db with the block on:
call 1 -> cleanup_incomplete, EACCES unlink '<root>/blocker/f'
          previous_error: invalid_request, "database disk image is malformed"
call 2 -> same, no new folder
unblock -> call 3: invalid_request "database disk image is malformed", folder gone

MCP, Node 24.18.0, folder made read-only:
call 1 -> cleanup_incomplete, EACCES unlink '<root>/database.snapshot'
          previous_error: execution_failure, worker stderr
          "Error: EACCES: permission denied, open '<root>/reply.json'"
Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 22.23.1, 24.18.0, 26.11.1
  • Head: eed34a6
  • Base: 60fbb2f
  • The head I tested last time: a9ce588

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

@Y0UW1SH
Y0UW1SH marked this pull request as draft October 11, 2026 00:35
Declare inert Electron imports in preload fixtures so current main can prove API provenance. Preserve option and source-coordinate assertions.

Use the configured catalog startup budget instead of the narrower per-test override under coverage contention.
@Y0UW1SH
Y0UW1SH marked this pull request as ready for review October 11, 2026 01:18
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

Retain upstream Electron imports, matching source ranges, and the catalog timeout. Include SQLite runtime compatibility in the new required CI gate.
Isolate compatibility checks, exercise minimum and rolling runtimes, share test selection, and guard required CI lanes. Merge current main and format its new reference-source files.
@CassieFox23

Copy link
Copy Markdown
Contributor

TL;DR: Fixed: on Node 22.23.1, rea capabilities and rea providers now say SQLite inspection is unavailable, before the tool runs. Still open: rea doctor says nothing about SQLite. Nothing else changed: the tool and the cleanup behave as before.

This follows my retest at eed34a6. I tested d63d1b1. It adds two commits. The first, 7caf4db, adds a SQLite row to capabilities. The second, d63d1b1, fixes test fixtures for Electron. The base is still 60fbb2f. I did not rerun eed34a6, so that column comes from my earlier comment.

Check Last time: eed34a6 Now: d63d1b1
rea capabilities --json, Node 22.23.1 no SQLite row row with available: false, availability_code: "unsupported_version" and the Node 24.15 text
Same command, Node 24.18.0 and 26.11.1 no SQLite row available: true
rea providers --json, Node 22.23.1 no SQLite row same output as rea capabilities --json, apart from the start time
rea doctor --json, Node 22.23.1 no SQLite row still no SQLite row
MCP binary_session, Node 22.23.1 provider_unavailable, with a fix note same words
Tool on 14 CLI cases, Node 22.23.1 refuses all 14, exit 1 refuses all 14, exit 1
Tool on 14 CLI cases, Node 24.18.0 and 26.11.1 14 as expected 14 as expected; Node 24 and 26 match apart from ids and SQLite version
CI test files, Node 22.23.1 8 files: 58 pass, 33 skip, 0 fail 9 files: 67 pass, 33 skip, 0 fail
CI test files, Node 24.18.0 8 files: 89 pass, 2 skip, 0 fail 9 files: 98 pass, 2 skip, 0 fail
CI test files, Node 26.11.1 8 files: 89 pass, 2 skip, 0 fail 9 files: 98 pass, 2 skip, 0 fail

What the command line says now. On Node 22.23.1, rea capabilities lists 19 operations in its first block. The SQLite entry is the fifteenth, at line 185 of 4,089 lines in the plain output. It is the only one marked unsupported_version. The other 10 unavailable ones are unsupported_host. The text names the need: "Node.js 24.x >=24.15 or 26+". The error from the tool itself is unchanged.

rea doctor prints the same on Node 22.23.1 and 24.18.0, apart from the Node version. A one-line row there would finish the job.

The new file has 8 tests of the version check, and the CLI acceptance file has 1 new test. All 9 pass on all three Nodes. The version check gives false for 24.14.9 and true for 24.15.0.

Cleanup checks, Node 24.18.0 (Node 26.11.1 for the first row). The results match my earlier comment.

Case Result at d63d1b1
Locked subfolder, normal read cleanup_incomplete, EACCES. A second call gives the same error with no new copy. After the lock lifts, the third call works and the folder is gone. Node 26 does the same.
Same lock, truncated.db The original "database disk image is malformed" is in previous_error, on both calls.
Folder made read-only The worker's EACCES on reply.json is in previous_error.
Cancel sent mid-call The next call gives cleanup_incomplete with previous_error code cancelled. I ran it twice.
MCP shutdown, lock on Exit 1, the log says cleanup failed, the folder stays.
MCP shutdown after the lock lifts Exit 0, folder gone. I checked this at a9ce588 only before.
CLI, same three locks Exit 1, JSON on stdout, nothing on stderr, folder stays.

Still not run

  • The full test suite, the CI job on GitHub, and npm run check:fast.
  • The 4 test files that d63d1b1 changes. They cover Electron and the catalog startup.
  • The PR head as it stands now, 2d96bf7. It moved after my run, with a merge of main (ceb17b5) and a CI change. I compared it with d63d1b1 file by file. No SQLite source changed. Its docs page for SQLite grew by 22 lines about npm run test:sqlite, which I did not run.
  • Windows and macOS.
  • Encrypted databases. Real app databases.
  • A live writer in WAL mode.

Thanks, Y0UW1SH, for the capabilities row.

Odd things I saw
  • MCP calls the Node 22 state provider_unavailable. The CLI calls it unsupported_version. Both mean the same fact.
  • rea doctor exits 1 on all three Nodes in my clean test home, because Hopper, Ghidra and IDA are not installed. That is not about SQLite.
  • On the CLI, primary_error and cleanup_error still hold the same cleanup error, so it prints twice.
  • Asking for 1,000 rows of 8 KiB blobs over MCP still gives a resource_constraint error about the stdio response budget.
Commands
# Node 22 is the system node; 24 and 26 are under ~/.local/opt/node24 and node26
git archive d63d1b15c | tar -x -C head; npm ci; npm run build; npm run test:prepare
node scripts/generate-mcp-tool-catalog.mjs   # and the skill-metadata, product-catalog
node scripts/generate-completion-ledger.mjs  # and completion-ledger, as the CI job does
rea capabilities --json; rea providers --json; rea doctor --json; rea capabilities
rea inspect-sqlite-database <db> [--table T] [--row-limit N] --json
env -i HOME=<fake> PATH=<node bin>:/usr/bin:/bin TMPDIR=<tmp> \
  node node_modules/vitest/vitest.mjs run \
  src/application/sqlite/SqliteDatabaseCapability.test.ts \
  src/application/sqlite/SqliteDatabaseService.test.ts \
  tests/acceptance/sqliteDatabaseCli.test.ts \
  tests/boundary/sqlite/sqliteDatabaseCleanup.test.ts \
  tests/boundary/sqlite/sqliteDatabaseDescriptorCleanup.test.ts \
  tests/boundary/sqlite/sqliteDatabaseInspection.test.ts \
  tests/boundary/sqlite/sqliteDatabaseProvider.test.ts \
  tests/boundary/sqlite/sqliteDatabaseSnapshot.test.ts \
  tests/boundary/mcp/serverLifecycleMcp.test.ts
# MCP over stdio: tools/list, tools/call binary_session, tools/call inspect_sqlite_database

The fixtures are the same as in my earlier comment. I built them with Python's sqlite3. To block cleanup, a small script waited for the snapshot folder, then added blocker/f and ran chmod 500 blocker. All 8 fixture files kept the same SHA-256 after every run.

Raw output
Node 22.23.1  rea capabilities --json  capabilities[14] (inspect_sqlite_database):
  available: false
  reason: SQLite inspection requires Node.js 24.x >=24.15 or 26+ with the native DatabaseSync.limits API. Other REA features retain their published runtime requirements. The inspection worker verifies the API before querying the snapshot.
  availability_code: unsupported_version
Node 24.18.0 and 26.11.1: available: true, reason: null, availability_code: null

9 test files, 100 tests each
  Node 22.23.1: 67 passed, 33 skipped, 0 failed
  Node 24.18.0: 98 passed, 2 skipped, 0 failed
  Node 26.11.1: 98 passed, 2 skipped, 0 failed
Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 22.23.1, 24.18.0, 26.11.1
  • Head / base: d63d1b1 / 60fbb2f; the head I tested last time: eed34a6
  • Other: SQLite 3.51.2 in Node 24.18.0 and in Python's sqlite3, 3.53.4 in Node 26.11.1 (public domain)

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

@dandgabr dandgabr left a comment

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.

P2 — Bound aggregate SQLite inspection resources. Each inspection can accept up to 256 MiB of database/WAL input (src/sqlite/SqliteDatabaseSnapshot.ts:196-215), while the provider admits concurrent inspections without a provider-wide cap (src/sqlite/SqliteDatabaseProvider.ts:72-88; src/artifacts/ArtifactResourceScope.ts:48-73). Concurrent near-limit requests can multiply buffered memory, worker processes, and temporary disk usage until the host or REA process is exhausted. Please cap concurrent inspections or enforce an aggregate resource budget across active snapshots and workers.

@N0zoM1z0 N0zoM1z0 self-assigned this Oct 12, 2026
@N0zoM1z0 N0zoM1z0 closed this Oct 12, 2026
@morluto morluto added enhancement New feature or request area: native Native analysis and decompilation, including Ghidra, IDA, and Hopper analysis behavior labels Oct 14, 2026
@morluto

morluto commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Thanks @Y0UW1SH for building the SQLite snapshot inspection workflow and preserving exact database values and provenance. Main now carries the CLI/MCP service, DB/WAL snapshot ownership, bounded row sampling, and cleanup-retry coverage (main).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: native Native analysis and decompilation, including Ghidra, IDA, and Hopper analysis behavior enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants