Skip to content

feat(limb): persist pairing & access-policy state across API restarts#332

Open
xu75 wants to merge 4 commits intozts212653:mainfrom
xu75:feat/limb-persistence
Open

feat(limb): persist pairing & access-policy state across API restarts#332
xu75 wants to merge 4 commits intozts212653:mainfrom
xu75:feat/limb-persistence

Conversation

@xu75
Copy link
Copy Markdown
Contributor

@xu75 xu75 commented Mar 31, 2026

PR Type

  • 🐛 Patch
  • Feature — New capability or behavior change (requires Feature Doc)
  • 📋 Protocol

Related Issue

Closes #331

What

SQLite-backed persistence for the limb domain so approved pairings and access policies survive API restarts.

Changes

  1. SqliteLimbPersistence (new) — WAL-mode SQLite layer with two tables (limb_pairings, limb_access_policies), versioned migrations following the existing SqliteEvidenceStore pattern.
  2. LimbPairingStore — optional persistence constructor param; write-through on createRequest(), approve(), reject(); initialize() loads persisted state. No persistence = pure in-memory (backward compat).
  3. LimbAccessPolicy — same write-through pattern for setPolicy(); initialize() loads persisted policies.
  4. index.ts startup recovery — on boot: open limb.sqlite → load approved pairings → create offline RemoteLimbNode stubs → heartbeat flips them online. LIMB_DB env var overrides default path.

Tests (12 new)

  • sqlite-limb-persistence.test.js — 6 tests for raw SQLite CRUD
  • limb-pairing-store-persistence.test.js — 3 tests for PairingStore round-trip
  • limb-access-policy-persistence.test.js — 2 tests for AccessPolicy round-trip
  • limb-persistence-integration.test.js — 1 full lifecycle test (register → approve → policy → teardown → reload → offline stub → heartbeat → online)

Why

Every API restart wipes all limb registrations. Users must re-approve pairings each time, making limb integrations fragile for production use.

Tradeoff

Option Pros Cons
SQLite (chosen) Already in project, ACID, low friction Extra DB tables
Redis Fast, shared state Heavier dependency for small dataset
JSON file dump Simplest No ACID, concurrent write risk

Test Evidence

All 102 existing + new tests pass (pnpm --filter @cat-cafe/api test).

AC Checklist

  • Approved pairings persist across restart
  • Access policies persist across restart
  • Offline stubs created on startup for approved nodes
  • Heartbeat flips offline → online
  • Backward compatible (no persistence = in-memory only)
  • No any types, biome clean

xu75 and others added 4 commits April 2, 2026 16:00
…d access policies

Implements the SQLite persistence layer for zts212653#331. Two tables:
limb_pairings and limb_access_policies, with WAL mode and
versioned migrations following the SqliteEvidenceStore pattern.

[宪宪/Opus-46🐾]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Write-through to SqliteLimbPersistence on every mutation. Optional
constructor param — no persistence = pure in-memory (backward compat).
initialize() loads persisted state into Map on startup.

[宪宪/Opus-46🐾]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On startup: open limb.sqlite → load approved pairings → create
offline RemoteLimbNode stubs. Heartbeat flips them online.
Env: LIMB_DB overrides default path.

Closes zts212653#331

[宪宪/Opus-46🐾]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies: register → approve → set policy → teardown → reload
from SQLite → offline stub → heartbeat → online. Full zts212653#331 cycle.

[宪宪/Opus-46🐾]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@xu75 xu75 force-pushed the feat/limb-persistence branch from bbdaddd to e3a8ec9 Compare April 2, 2026 08:04
@xu75 xu75 changed the title Feature: Persist limb node registrations across API restarts feat(limb): persist pairing & access-policy state across API restarts Apr 2, 2026
@xu75 xu75 marked this pull request as ready for review April 2, 2026 08:11
@xu75 xu75 requested a review from zts212653 as a code owner April 2, 2026 08:11
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3a8ec9d4f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

};

this.requests.set(request.requestId, request);
this.persistence?.upsertPairing(request);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Persist approved-pairing reconnect updates

Ensure reconnect-time mutations are written through to SQLite: createRequest() only persists when a new request is created, but the reconnect flow in registerLimbNodeRoutes mutates existing approved requests (notably endpointUrl) in place. With this commit’s restart recovery, those in-memory changes are lost on process restart, so recovered stubs can point to stale endpoints and route invokes to the wrong/unreachable host until another full re-register occurs.

Useful? React with 👍 / 👎.

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.

Feature: Persist limb node registrations and pairing approvals across API restarts

1 participant