Skip to content

perf: read only the lifecycle payload fields the check uses - #216

Merged
bompus merged 1 commit into
mainfrom
perf/lifecycle-payload-fields-20261029
Oct 30, 2026
Merged

bompus merged 1 commit into
mainfrom
perf/lifecycle-payload-fields-20261029

Conversation

@bompus

@bompus bompus commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

The lifecycle check runs on every wait renewal by a lifecycle-bound session. Its snapshot read parsed the whole stored payload of every bound thread to reach two fields. It now asks SQLite for just those fields, and json_valid keeps one malformed row from failing the whole query.

This is issue #169's option 1b. It does not change how fresh the check is: it still reads the source and checks the watermark on every call. A thread's state comes from the same fields, and an unreadable row still holds only its own identity.

Evidence

  • test/lifecycle.test.ts compares each payload shape with the former JSON.parse result: missing and null fields, every other JSON type, invalid text, arrays, scalars, BLOBs, escaped keys and surrounding whitespace. 69 tests pass in the file. The invalid-JSON cases also fail if the guard is removed: a bare json_extract would make one unverified row return unavailable for the whole profile.
  • On a private copy of T3 Code's real thread projection (3287 rows), both revisions recorded the same state for every readable row: 1010 archived, 177 settled, 38 deleted, 2061 active. With one payload replaced by { or [], both revisions returned ready and skipped only that unverified thread; after the threads were verified, both returned unavailable and kept the previous states.
  • Reconcile over 200 calls on the same private copy, 3 runs each: 8.27 to 7.35 ms wall and 8.74 to 7.45 ms CPU per call.
  • Copy server with 20 stand-in clients renewing a 3 s wait and one reconcile every 2 s, 5 x 30 s windows: 0.1293 to 0.0952 cores (about 26% less).

Limits

  • Measured on the unbundled source (bun) on a private copy, not the release binary and not the live server. The live server was not restarted or attached to.
  • Parser differences on hand-edited rows. On a hand-edited row, a NUL inside one of the two keys, a raw NUL after the JSON, a repeated key, or nesting past SQLite's ~1,000-level limit can read differently from JSON.parse. Every T3-written payload and every row in the real database behaves identically; the real-database check above found no row where the two revisions differ.
  • A row too deep for SQLite does not fail the reconcile query. json_valid returns 0, the guarded SELECT returns the row with a NULL type instead of raising, and the per-row handling holds only that row when it is unverified. A verified row still fails the profile closed, as any invalid verified row does.
  • A full fallback to JSON.parse for the four shapes measured 17.7 ms per query against 4.6 ms for this one and 5.4 ms for the old parse, so it is not part of this change.

No live install is part of this change.

The lifecycle snapshot parsed every bound thread's whole stored payload to reach settledAt and settledOverride. SQLite now returns those two fields, and json_valid keeps one malformed row from failing the whole query.

Reconcile over 200 calls on a copy: 8.27 -> 7.35 ms wall, 8.74 -> 7.45 ms CPU. A copy server with 20 clients renewing a 3 s wait: 0.1293 -> 0.0952 cores.

Refs #169
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Walkthrough

Lifecycle snapshots now project the settlement fields they use from SQLite JSON instead of parsing each thread’s full payload in JavaScript. Tests compare lifecycle reconciliation with a reference parser across valid and invalid payloads.

Changes: Lifecycle field projection

Layer / File(s) Summary
Project fields and derive lifecycle state
src/lifecycle.ts, CHANGELOG.md
readSnapshot selects settlement fields through SQLite JSON projections. stateOf uses the projected values while preserving lifecycle validation and precedence. The changelog reports an approximately 25% CPU reduction in a copy-server measurement.
Verify lifecycle reconciliation
test/lifecycle.test.ts
A reference parser and table-driven tests compare lifecycle reconciliation across valid, malformed, missing, and unusual payload values, including verified and unverified records.

Possibly related PRs

  • bompus/swarmail#194: Adds refusal rules for agents with different lifecycle identity fields, which are also used by lifecycle reconciliation.

Priority: Low

Merge Risk: Minimal · up to 1e91a

The lifecycle query reads fewer payload fields, with no established merge-blocking issue.

Pre-merge checks: Passed 5 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Description check Inconclusive The description states the purpose (the lifecycle check parsed each bound thread's full payload to read two fields; it now queries only those fields via SQLite with json_valid as a guard) and gives de… Tick or explicitly confirm the template checkboxes. Confirm that the README Development section checks pass. Confirm that the description, commits, and CHANGELOG entry contain no private project or repository names, local paths, home direct…
Passed Passed checks: 5 passed
Check name Status Explanation
Title check Passed The title is concise and directly identifies the main change: limiting lifecycle payload reads to the fields used by the check.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Suppressions Explained Passed The pull request changes only CHANGELOG.md, src/lifecycle.ts, and test/lifecycle.test.ts. The diff adds no lint, type-check, or formatter suppression directive, and it adds no ignore entry in a tool c…
Interface Changes Documented Passed PASS. The pull request changes lifecycle projection logic, tests, and adds a CHANGELOG.md entry under ## Unreleased. The reviewed diff adds no MCP tool or argument, swarmail command or flag, or …
Full details: Suppressions Explained

Explanation

The pull request changes only CHANGELOG.md, src/lifecycle.ts, and test/lifecycle.test.ts. The diff adds no lint, type-check, or formatter suppression directive, and it adds no ignore entry in a tool configuration file.

Full details: Interface Changes Documented

Explanation

PASS. The pull request changes lifecycle projection logic, tests, and adds a CHANGELOG.md entry under ## Unreleased. The reviewed diff adds no MCP tool or argument, swarmail command or flag, or environment variable. Therefore the documentation condition is not triggered.

Full details: Description check

Explanation

The description states the purpose (the lifecycle check parsed each bound thread's full payload to read two fields; it now queries only those fields via SQLite with json_valid as a guard) and gives detailed validation evidence: test results, private-copy row-level comparisons, timing and CPU measurements, and explicit limits. It also explains the freshness guarantee and the parser-difference caveats. Against the template, the description does not check or confirm the first item (README Development section checks pass) or the third item (no private project names, local paths, home directories, or credentials). It does mention a 'private copy' and 'private' repository without naming it, but the template asks the author to confirm this explicitly. The second item (CHANGELOG entry under Unreleased) is satisfied by the changed CHANGELOG.md per the raw summary, though the description does not mention it. The template checkboxes are not ticked, so the template is not fully followed, though the substantive content is strong.

Resolution

Tick or explicitly confirm the template checkboxes. Confirm that the README Development section checks pass. Confirm that the description, commits, and CHANGELOG entry contain no private project or repository names, local paths, home directories, or credentials. The description refers to 'a private copy of T3 Code' and to 'issue #169'; state that these references are safe to publish, or remove any private detail. Optionally mention the CHANGELOG.md entry in the description.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

❤️ Share

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

@bompus

bompus commented Oct 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@bompus-ai-review bompus-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bompus AI Review (GPT-6.1 Sol, xhigh reasoning): 1 finding(s).

Comment thread src/lifecycle.ts Resolved
@bompus
bompus merged commit 487eae9 into main Oct 30, 2026
3 checks passed
@bompus
bompus deleted the perf/lifecycle-payload-fields-20261029 branch October 30, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant