perf(storage): bound artifact point reads and revisions - #4874
Conversation
Replace full-store reloads with indexed ID and Session queries. Preserve Session revisions and select conversation copy metadata within one read snapshot. Keep the explicit global purge safety scan. Add bounded-read, concurrent snapshot, metadata validation, and cross-process visibility regression coverage. Refs apache#4037 Generated-by: Codex
Updated test summaryVerified implementation Local checks: Storage 1,132 passed, 8 skipped, 0 failed; related Runtime Host suites 67 passed, 0 failed. Repository lint/format and storage/runtime-host typechecks passed. The 17 new revision tests cover both growth axes, bounded writes, atomic snapshots, cross-process visibility and migration. Negative controls fail as expected: six growth tests with the previous read implementation, two snapshot tests without read transactions. Target Session growth — previous PR
Each current get additionally reads one persisted revision row. The revision is maintained transactionally without a full-Session scan/hash on writes. At 50,000 target records, creation P50 was 3.272 → 3.896 ms (19.1% slower); this overhead is reported, not excluded. Other Session growth — original baseline Apple M2 / Node 22.22.2 / runtime SQLite 3.53.0. Three fresh-process rounds, with at least 30 calls AND 1 second of API execution before sampling each operation. Both comparisons use version-specific schemas; 2,700 measured samples overall. These are prewarmed storage API measurements, not startup/UI results. Session listing/copy still process the target Session, and physical purge retains its global safety scan. Full-application/full-repository verification was not run. Schema v4 and the switch from content hashes to opaque revision markers are documented in the PR. Full report, scripts, raw samples, environment details, and negative controls. Earlier results for Updated with Codex assistance. |
Astro-Han
left a comment
There was a problem hiding this comment.
Reviewed current head 46b131dfe8012249a4367266136e0859932ff182 (OPEN, MERGEABLE/BLOCKED awaiting human review). NO-GO — one P2 below. Checks green on this head (test, label, windows_recovery); base 7370f07a94cf, merge-tree clean, diff check green.
P2 — the "scoped" single-record read still scales with the target session
getInSession() (artifact-store.ts:535-543) still reads and decodes the target session's full record set via sessionSnapshot(); :807-815 then sorts and revisions over the complete array. So target-session growth linearly increases one single-record get's SQL, JSON decode, sort, and hash cost. The ordinary Runtime Host artifact get uses this path (artifact-coordinator.ts:388-400), and attachment validation (:108-139) calls it per attachment. The new test (artifact-scoped-reads.test.ts:186-190) expects a get to read the target session's 10 rows and does not cover boundedness under target-session growth — failing issue #4037's acceptance that single-record reads and their revisions must not grow with the target session. Fix: maintain a per-session revision/digest (or equivalent constant-time token) in the same metadata mutation transaction so getInSession() reads by ID and queries the token; if target-session scanning is accepted, narrow the acceptance explicitly and add a scale-growth benchmark. No new P0/P1 correctness, permission, concurrency, or lifecycle issues found (the retained global scan on the purge-safety path is declared and not counted; copy-payload lifetime interleaving not graded as this PR's regression).
Scope and limits
Full 5-file diff (+584/-95): SQLite projection queries/identity checks, read snapshots, mutation queue/writer lock, create/get/list/copy/purge/delete, Runtime Host attachment and query call sites, new regression tests. Local TypeScript build/test could not run independently (incomplete worktree dependencies).
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
简体中文
评审结论来自自动化审查流程;发布者没有读这份 diff,核的是当前 head 有没有漂移、以及 exact-head 的门禁状态。当前 head 是 46b131d,未关闭。一条 P2:号称收敛的单记录读取仍随目标会话线性增长,不满足验收条件。修好再合。
Maintain opaque Session change tokens with indexed SQLite triggers in schema v4. Fetch an Artifact and its revision from one read snapshot without decoding the Session. Preserve no-op replay, rollback, reopen and empty-Session behavior; retain explicit Session-wide listing and purge costs. Add target/other Session growth checks, bounded write auditing, concurrent record/revision snapshots, cross-process visibility and migration rollback coverage. Revision tokens now represent changes rather than the digest of the current record set. Refs apache#4037 Generated-by: Codex
Keep one 12,000-record case per growth axis; retain scale comparisons in the benchmark harness. Refs apache#4037 Generated-by: Codex
Keep the acceptance, transaction, snapshot, and migration cases while removing redundant functional branches. Refs apache#4037 Generated-by: Codex
Preserve the v1 upgrade residue recovery alongside indexed Artifact reads and transactional Session revisions. Refs apache#4037 Generated-by: Codex
Astro-Han
left a comment
There was a problem hiding this comment.
Reviewed current head b6c34f6266b553e171b1587fdb6afe364b6a4d9c (OPEN). Technical GO — the previous P2 is fixed, no new P0–P3 correctness, permission, concurrency, or lifecycle issues. Prior conclusions were re-verified against this head, not carried over. Exact-head test and windows_recovery SUCCESS; merge-tree against latest origin/main=c66791bc clean, diff check clean. (Last GitHub state query showed mergeability UNKNOWN — integration state pending confirmation, not a correctness finding.)
What fixed the P2
sqlite-artifact-metadata.ts:48-98 now does bounded reads by artifact ID and reads the persisted session revision token in the same snapshot; artifact-store.ts:576-585 no longer scans the target session. The listPage target-session enumeration remains a separate path required for paging, sorting, and totals. Schema v4's revision table, migration backfill, and insert/update/delete triggers (sqlite-artifact-schema.ts:26-170) checked; purge's global scan confirmed used only for cross-session file-alias safety.
Scope and limits
Hosted test completed build/typecheck, affected workspace and Runtime Host tests, and forward-roll qualification. Local build/test not independently re-run (missing tsc/Storage dist in this worktree).
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
简体中文
评审结论来自自动化审查流程;发布者没有读这份 diff,核的是当前 head 有没有漂移、以及 exact-head 的门禁状态。当前 head 是 b6c34f6,未关闭,检查绿。旧 P2 修掉了(按 ID 有界读加 revision token),无新问题。合并由人类定。
Summary
Replace full-store Artifact metadata reloads with indexed ID and Session queries, preserving the delta writes introduced by #4716 and following the indexed-row direction in #4030.
The first implementation (
46b131dfe) still scanned the target Session to compute a single-record read's revision. Commit99ac97bc6addresses that P2:getInSession()reads by Artifact ID and looks up a persisted Session revision in the same read snapshot. It no longer loads, sorts, or hashes the target Session's record set.Both growth acceptance checks are covered:
getInSession()still returns one Artifact row and one revision row, decoding only the Artifact. A missing ID decodes zero Artifacts. Revision lookup does not scan the Session.SQLite triggers maintain revision tokens in the same metadata mutation transaction, using indexed operations rather than moving the Session scan to writes. These are bounded row/decode counts, not a claim that SQLite index traversal or wall-clock latency is mathematically constant.
Preserve no-op replay, rollback, cross-process visibility, common empty-Session revisions, locale-aware listing order, copy snapshot consistency, writer locks, and physical deletion safeguards. Indexed reads reject malformed metadata and inconsistent identity/Session/time/path projections.
Refs #4037
Verification
Implementation and benchmark baseline:
99ac97bc6625d14f044f8ed7be41d29231e629da. Test-only follow-upsb099cd28band70568f709reduce the revision suite from 17 to 8 cases and remove redundant scoped-read branches; production code is unchanged.@maka/core,@maka/storage,@maka/mcp,@maka/runtime, and@maka/runtime-host.99ac97bc6(before the test-only follow-up):testandwindows_recoverypassed.Prewarmed target-growth benchmark, previous PR implementation
46b131dfe→99ac97bc6:Each new get also reads one revision row. Every case warmed up for at least 30 calls AND 1 second of API execution, with three fresh-process rounds per revision/size. The target-growth and separate other-Session-growth comparisons contain 2,700 timed samples in total.
Write overhead is not zero: at 50,000 target records, creation P50 was 3.272 → 3.896 ms (19.1% slower). These local measurements are not a latency guarantee.
Full test report, reproduction scripts, raw samples, and negative controls. The linked report records the original 17-test run on
99ac97bc6; the updated 8-test/full-suite results are above. It supersedes the earlier fixed-10-record-Session report for the current implementation; that earlier comparison did not establish boundedness under target-Session growth.Not run locally: full-application build, full-repository typecheck/tests, opt-in process-lock stress, Windows execution, Electron/UI/packaged-app verification, or UI/Desktop knip checks. No startup/UI performance claim is made.
Migration and revision semantics
Artifact schema v3 → v4 adds a Session revision table and transaction-owned triggers. A one-time covering-index backfill enumerates existing Session keys without decoding Artifact JSON; migration cost still scales with existing index entries. Older builds reject the newer schema.
Session revisions become opaque committed-change markers, not hashes of the current record set. The
sha256:<64 hex>wire shape stays unchanged, but revision values now hash a fixed-size persisted change token. Metadata changed and later restored does not reuse an earlier nonempty revision. Unchanged writes keep their revision; malformed-row edits may conservatively invalidate pagination.Review focus
listPagestill validates/sorts the target Session for filtering, totals and locale ordering; only its revision lookup is bounded. Turn listing and copy selection remain Session-scoped. Physical purge retains the explicit global path-alias safety scan. This PR does not claim to remove all startup/deletion work or close the entire issue.AI use
Tool(s) and scope: Codex contributed implementation, regression tests, benchmark harnesses, and PR/test-report drafting. All five PR commits include
Generated-by: Codex; retain the trailer in the final squash commit. Human review and submission ownership remain with the contributor.Checklist
Does this PR entail a change in behavior?