Repository navigation
v0.1.63 — one answer per decision, durable ledger mirrors
v0.1.63 ships the 15 PRs merged on main since v0.1.62.
What ships
One answer per decision (#464, closes #460; #484).
- Second resolutions rejected: resolving a decision a second time used to silently overwrite the first answer and return 200. Now a different pick, or a pick on a decision closed elsewhere, gets a 409
verdict_already_finalthat carries the recorded winner. The same pick is a true no-op. Both the public and internal resolve routes go through the same guard. - Atomic check-and-resolve (#484): Astra's review of #464 found the stale check wasn't atomic with the write, so two concurrent picks could both write (statuses
[400, 200]). Classify-and-write is now one store operation,resolveDecisionAtomic; N concurrent different picks give exactly one write, and every 409 names the same winner. - Durable before success: a resolve reports success only after a durable flush. If the flush lock is busy, you get a 503 and the write is rolled back in memory, so
check_feedbacknever delivers an answer that wasn't saved. A retry after that is an ordinary first write. - Announced once: the first successful save publishes
decision_resolvedexactly once, with the recorded winner. - Stale card: it shows the winning pick with no Select buttons, and the toast says only what's true.
- Sibling change signal: a per-session
revisioncounter (with a restart epoch) moves on status changes and comments, so a decision resolved in another tab clears, and a sibling's new question appears in Waiting. Quiet siblings cost nothing. Older daemons fall back to the artifact count. - Not in this release: two LOW follow-ups are tracked in #490 / #491, which is still in review.
Ledger mirrors survive a busy lock (#488, closes #486).
- Queued, not dropped: when the cross-project ledger lock is busy, a rejection, approval or retire mirror used to fail with
ELOCKEDand only be logged. It is now queued in.deeppairing/ledger-mirror-pending.jsonand replayed on backoff, after the next successful mirror, and when the project's store next starts (for example after a daemon restart). The local record still commits first. - Exactly once: the ledger append is deduplicated on
(project, sessionId, verdict, at), so a replay that already landed, or several processes replaying at once, never adds a duplicate. - No resurrection:
deeppairing philosophy removewrites a removal tombstone under the ledger lock, and a queued mirror from before the removal is skipped. Retiring a rejection cancels its queued mirror. - Consent under the lock: the publish flag, the local row and the approved pattern are re-read from disk inside the ledger lock right before each append. Withdrawn consent drops the queue. A refused write (for example, a corrupt ledger) stays queued instead of being dequeued.
- Bounds: the queue is capped at 200 entries and 30 days.
Honest offline state (#467, refs #430).
- Act buttons: disabled while the tab is offline, with the reason shown, and drafts are kept.
- No false flash on load: a 3s first-connect grace means no "Disconnected" banner on every load. With the Next-up bar on, it shows "Checking what needs you…" until hydration settles.
- Clearer text: an item from another session gets its session label (N1). The copy says this tab lost its connection (N3). 92s now reads "1 min" (N4).
- Remaining offline gaps are tracked in #477 / #487. They are not fixed in this release.
Decision search and failed session opens (#475, closes #469). The project decisions search now matches the recorded reasoning. Opening a past session that fails (HTTP, network or malformed response) shows an alert with Retry, instead of failing silently, and leaves the live view untouched.
Annotation reads no longer create sessions (#479, closes #472). GET /api/sessions/:id/annotations used to create an empty session directory for an unknown id and return 200. It now returns 404 for an absent session, 200 for a real one, and 500 for a genuine read failure.
Authenticated daemon recovery notifications (#480, closes #468). After a daemon loses its session map, the client's recovery notification now carries the bearer token and project header. Failures stay logged and non-fatal.
Isolated sample demo (#481, closes #471). A new claude-plugin/server/demo.mjs runs a scripted sample of a first review from the installed plugin with plain node, no build. It runs in a throwaway temp HOME and sample project on its own port window (41000-41063), and cleans up on exit. It is labelled as scripted: no AI model is called.
Node 20 deprecated, removal planned (#466, closes #461). Node 20 still works, but it's deprecated, with removal no earlier than v0.2.0 and not before January 2027. Node 22 or 24 is recommended. The plugin prints a one-line deprecation notice to stderr only, so stdout stays clean for MCP.
Upgrade preservation test (#482). A new offline test boots the released v0.1.57 runtime, creates sessions, then checks that this candidate reads them, keeps rejection memory blocking, and survives a restart. It also documents backup/restore and the downgrade boundary.
Test reliability (#485, #489). The cross-process ledger race tests re-submit documented ELOCKED refusals instead of treating them as crashes, and the lock-hog case now detects a silently dropped write. Test-only.
- #465: the #430 attention walkthrough rerun after #458/#459 (the findings #467 fixes).
- #476 (closes #473): Plan Mode comparisons re-verified against current sources, positioned on decision continuity.
- #435: protocol preparation for the consent-gated external pairing pilot (#434). It does not start the pilot; Mitch's approval is still required.
Not in this release: #487, #490 / #491 and #439.
Review provenance
- Claude-side adversarial review: #464, #467, #466, #484 and #488, with independent Opus reviewers. Every round is recorded on its PR.
- Codex review and integration: #475, #476, #479 and #481 (Sol/Astra). #485 was reviewed by Luna and integrated by Astra; a Claude review found a MEDIUM problem after merge, which #489 fixed. #435 was reviewed by Terra and Sol, plus a Claude review.
- Independent Claude approval, Astra integration: #480 and #482.
- #489: signed off by an independent agent; the reviewer isn't named in the record.
- #484 and #488 were merged by Opus under Mitch's explicit authorization, after independent Claude reviews verified every Codex finding fixed. The Codex re-review of their final heads was still pending at merge.
Verification
Measured on a fresh native clone, at the merge of main 927d25f5 into this branch (head 54537b3f):
- Version sources: all four read 0.1.63.
- Diff vs
main: 6 files, 6 insertions and 6 deletions (the four version sources plus thedaemon.js/standalone.jsstamps). - Cold build:
pnpm install --frozen-lockfile, thenpnpm build:clean;git status --porcelainis empty, so the committed bundle matches. - Typecheck: 3 of 3 tasks clean.
- Lint: 0 errors; mcp-server 227 warnings (cap 240), shared 3 (cap 5).
- Tests: full
pnpm testpasses, 369 files and 5,640 tests (mcp-server 354 / 5,319, shared 15 / 321). - Checks:
version-lockstepandplugin-bundle-bootpass (2 files, 5 tests). - Rebuild: a second cold
pnpm build:cleanleaves the tree clean, and no0.1.62string remains inclaude-plugin/server(the literalgrep -r "0.1.62"regex matches one unrelated KaTeX number,0,1062;grep -rFreturns nothing). - Conflict markers: none.