# 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.
