# TESS-M2-002 — Durable Tess State - **Issue:** #708 - **Task:** `TESS-M2-002` / `TESS-STA-001`, `TESS-SEC-007..008` - **Branch:** `feat/tess-durable-state` - **Base:** fresh `origin/main` at `e3b5113be21e51d015fa1ae54572929b2a4acd9f` - **Budget assumption:** 38K task estimate; no explicit cap. Use focused TDD plus workspace validation. ## Objective Persist a Tess session's immutable identity, inbox/outbox idempotency state, checkpoints, handoffs, and approval bindings so a new service instance can recover it after a process restart or context compaction without replaying a completed message or applied side effect. ## Plan 1. Write recovery/idempotency tests first in `packages/agent/src/tess-durable-session.test.ts`. 2. Add transport-neutral durable-state contracts/state machine in `packages/agent`. 3. Add canonical PostgreSQL schema/migration and a gateway Drizzle repository adapter. 4. Wire gateway service/module and reuse `tess:command-approval:*` durable approval semantics for exact, actor/tenant/action-bound approval consumption. 5. Test PGlite restart recovery with separate service instances sharing the same durable DB. 6. Document the recovery/compaction operation and update Tess architecture evidence. 7. Run focused, cold-cache, workspace, migration, review, commit, push, and open PR to `main`. ## Required Evidence | Requirement | Primary evidence | | --- | --- | | Restart recovery | Test creates a second coordinator over unchanged durable store after simulated process death. | | No duplicate side effects | Duplicate ingress and post-restart dispatch assert one handler/effect invocation. | | Compaction survival | Checkpoint/handoff/reconstructed state preserve the same session identity and pending records. | | Durable approvals | Existing `tess:command-approval` record is consumed only once and survives a new authorization service instance. | | Handoff | Stored handoff is portable and reconstructed without live process state. | ## Progress - Intake complete: PRD AC-TESS-06, threat TM-07/TM-08, and verification matrix reviewed. - Affected surfaces: `packages/agent`, `apps/gateway`, `packages/db`; auth/authorization and DB migration tests required. - TDD is required (security authorization and critical state mutation). ## Risks - An external provider action cannot be atomically committed with the database. The outbox gives the receiver a stable idempotency key; generic recovery never replays an ambiguous `processing` effect, and completed effects are never redispatched. - PostgreSQL is canonical; PGlite is the local/restart test implementation. ## Verification - TDD red: `pnpm --filter @mosaicstack/agent test src/tess-durable-session.test.ts` initially failed because the durable-state module did not exist. - Focused green: 7 agent state-machine tests; 6 PGlite repository tests (including close/reopen recovery and encrypted-at-rest redaction); 5 durable-approval tests; DB migration tests. - Full cold-cache green: `pnpm turbo run typecheck lint test --force` completed 88 tasks with zero cache hits; `pnpm format:check` and `git diff --check` passed. - Fresh worktree dependency install passed with `pnpm install --frozen-lockfile --store-dir /home/jarvis/.local/share/pnpm/store`. The default pnpm store path was inaccessible to this harness, so the explicit user-owned store path was required. - Codex review identified plaintext durable payload risk; resolved by AES-256-GCM sealing after redaction, with an at-rest ciphertext assertion in the PGlite suite. - Pending final clean review, commit, and PR.