CodeNomad/packages/electron-app/electron/main/serialized-lifecycle.test.ts
Pascal André 0bab9e3438
fix(restore): simplify persistence and harden cross-platform cleanup (#602)
## Summary

- Follow up #578 by consolidating desktop persistence, restore
reconciliation, lifecycle coordination, and regression coverage.
- Preserve active drafts and attachments, request-scoped workspace
ownership, deletion tombstones, renderer authority, and bounded shutdown
behavior.
- Fix the reported macOS cleanup failure with targeted BSD process
queries and random-token-guarded process-group cleanup, without an
unverified PID fallback.

## Platform hardening

- Ignore development renderer origins in packaged Electron builds.
- Preserve staged Tauri navigation authority and handle confirmed
Windows session-end shutdown on the UI thread.
- Bound workspace launch preflight, runtime startup, and health
readiness.
- Retain cleanup ownership after unexpected leaders exit and verify
portable POSIX descendants by immutable identity or inherited launch
token.
- Add real Darwin-only process-group integration tests for macOS CI.

## Scope

- 96 files changed.
- 6,295 additions and 12,167 deletions, a net reduction of 5,872 lines
from the merged implementation.
- Consolidated duplicated tests while retaining focused race,
durability, cleanup, and platform contracts.

## Validation

- pm run typecheck
- pm run typecheck --workspace @neuralnomads/codenomad
- Electron native suite: 60 passed
- Tauri suite: 49 passed
- Focused server lifecycle/identity suite: 31 passed, 2 Darwin-only
skipped on Windows
- Focused UI restore/codec/reconciliation suite: 36 passed
- Broader server suite: 59 passed, 3 platform skips
- Broader UI suite: 97 passed, 1 skip; 2 Node 25 solid-toast loader
failures reproduced on the merged baseline
- git diff --check
- Final limited gatekeeper: PASS for server/macOS, UI restore, and
Electron/Tauri
2026-07-17 22:17:15 +01:00

38 lines
1.3 KiB
TypeScript

import assert from "node:assert/strict"
import test from "node:test"
import { SerializedLifecycle } from "./serialized-lifecycle"
test("serializes operations and exposes shutdown before queued work resumes", async () => {
const lifecycle = new SerializedLifecycle()
let release!: () => void
const gate = new Promise<void>((resolve) => { release = resolve })
let active = 0, maximum = 0
const first = lifecycle.enqueue(async () => {
active += 1; maximum = Math.max(maximum, active)
await gate
active -= 1
if (lifecycle.stopped) throw new Error("stopped")
})
const second = lifecycle.enqueue(async () => {
active += 1; maximum = Math.max(maximum, active); active -= 1
})
const shutdown = lifecycle.stop(async () => {})
release()
await assert.rejects(first, /stopped/)
await second
await shutdown
assert.equal(maximum, 1)
})
test("failed shutdown reopens the lifecycle before queued retries run", async () => {
const lifecycle = new SerializedLifecycle()
const shutdown = lifecycle.stop(async () => { throw new Error("cleanup unconfirmed") })
const retry = lifecycle.enqueue(async () => {
assert.equal(lifecycle.stopped, false)
return "restarted"
})
await assert.rejects(shutdown, /cleanup unconfirmed/)
assert.equal(await retry, "restarted")
assert.equal(lifecycle.stopped, false)
})