feat(tess): persist durable session state #729

Merged
jason.woltje merged 3 commits from feat/tess-durable-state into main 2026-07-13 05:14:12 +00:00
Owner

Summary

  • add transport-neutral durable session identity, inbox/outbox idempotency, immutable checkpoints, and portable handoffs
  • persist canonical state through the gateway PostgreSQL adapter with restart recovery and encrypted/redacted durable payloads
  • reuse exact one-time command approvals for runtime termination and scope provider outbox dispatch

Verification

  • pnpm turbo run typecheck lint test --force (88 tasks, zero cache hits)
  • pnpm format:check
  • focused PGlite close/reopen, duplicate-effect, idempotency-conflict, approval, and migration suites
  • Codex code and security reviews completed; findings remediated

Refs #708

## Summary - add transport-neutral durable session identity, inbox/outbox idempotency, immutable checkpoints, and portable handoffs - persist canonical state through the gateway PostgreSQL adapter with restart recovery and encrypted/redacted durable payloads - reuse exact one-time command approvals for runtime termination and scope provider outbox dispatch ## Verification - `pnpm turbo run typecheck lint test --force` (88 tasks, zero cache hits) - `pnpm format:check` - focused PGlite close/reopen, duplicate-effect, idempotency-conflict, approval, and migration suites - Codex code and security reviews completed; findings remediated Refs #708
jason.woltje added 1 commit 2026-07-13 04:11:21 +00:00
feat(tess): persist durable session state
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
102a7b606b
Author
Owner

REQUEST CHANGES — ROR for PR #729 at exact head 102a7b606bd492201e3d731a86397a9cfe4eb998.

Findings:

  1. CI is red at the reviewed head. Woodpecker PR pipeline 1730 failed in test: @mosaicstack/gateway#test timed out in src/agent/tess-durable-session.repository.test.ts on TessDurableSessionRepository > survives a full PGlite close/reopen mid-session without duplicate inbox or outbox side effects after 30s. This is the primary recovery/idempotency proof for AC-TESS-06, so I cannot approve while it is failing.

  2. Idempotency conflict checks run after redaction, allowing distinct sensitive payloads to collapse into the same durable record. In apps/gateway/src/agent/tess-durable-session.repository.ts lines 94-120 and 170-199, record.content is redacted before insert and before sameInbox / sameOutbox conflict comparison. Two different payloads like api_key=secret-one and api_key=secret-two with the same sessionId + idempotencyKey both normalize to the same redacted content, so the second write is treated as an accepted duplicate instead of an idempotency conflict. Same pattern exists for checkpoint cursor/summary at lines 267-286. The durable store needs a secret-safe exactness check, e.g. a sealed/HMAC digest of the original payload fields, while still only persisting redacted/sealed content for recovery.

  3. Name-as-config invariant is not preserved. New durable schema and approval storage are hardcoded to Tess-specific identifiers: packages/db/src/schema.ts lines 494-594 define tess_* enums/tables/indexes, packages/db/drizzle/0012_tess_durable_state.sql creates tess_* DB objects, and apps/gateway/src/commands/command-authorization.service.ts line 252 stores approvals under tess:command-approval:${approvalId}. This makes the durable state and approval namespace Tess-specific instead of agent/runtime-name config data, which conflicts with the M2 name-as-config requirement and the requested no-hardcoded-tess review scope.

No approval posted. Re-ROR needed after a new head with terminal-green PR CI and fixes for the above.

Marker: ROR-729-REQUEST-CHANGES-102a7b60

REQUEST CHANGES — ROR for PR #729 at exact head `102a7b606bd492201e3d731a86397a9cfe4eb998`. Findings: 1. **CI is red at the reviewed head.** Woodpecker PR pipeline `1730` failed in `test`: `@mosaicstack/gateway#test` timed out in `src/agent/tess-durable-session.repository.test.ts` on `TessDurableSessionRepository > survives a full PGlite close/reopen mid-session without duplicate inbox or outbox side effects` after 30s. This is the primary recovery/idempotency proof for AC-TESS-06, so I cannot approve while it is failing. 2. **Idempotency conflict checks run after redaction, allowing distinct sensitive payloads to collapse into the same durable record.** In `apps/gateway/src/agent/tess-durable-session.repository.ts` lines 94-120 and 170-199, `record.content` is redacted before insert and before `sameInbox` / `sameOutbox` conflict comparison. Two different payloads like `api_key=secret-one` and `api_key=secret-two` with the same `sessionId + idempotencyKey` both normalize to the same redacted content, so the second write is treated as an accepted duplicate instead of an idempotency conflict. Same pattern exists for checkpoint cursor/summary at lines 267-286. The durable store needs a secret-safe exactness check, e.g. a sealed/HMAC digest of the original payload fields, while still only persisting redacted/sealed content for recovery. 3. **Name-as-config invariant is not preserved.** New durable schema and approval storage are hardcoded to Tess-specific identifiers: `packages/db/src/schema.ts` lines 494-594 define `tess_*` enums/tables/indexes, `packages/db/drizzle/0012_tess_durable_state.sql` creates `tess_*` DB objects, and `apps/gateway/src/commands/command-authorization.service.ts` line 252 stores approvals under `tess:command-approval:${approvalId}`. This makes the durable state and approval namespace Tess-specific instead of agent/runtime-name config data, which conflicts with the M2 name-as-config requirement and the requested no-hardcoded-`tess` review scope. No approval posted. Re-ROR needed after a new head with terminal-green PR CI and fixes for the above. Marker: ROR-729-REQUEST-CHANGES-102a7b60
jason.woltje added 1 commit 2026-07-13 04:37:16 +00:00
fix(tess): harden durable recovery namespaces
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
444988d23b
Author
Owner

REQUEST CHANGES — re-ROR for PR #729 at exact head 444988d23bada28d3cc9ce7e588e18e052f058ff.

CI verification: Woodpecker PR pipeline 1731 is green at this head, and the previously failing recovery test now passes rather than being skipped: src/agent/tess-durable-session.repository.test.ts ran 6 tests, including survives a full PGlite close/reopen mid-session without duplicate inbox or outbox side effects in 1515ms.

Remaining blocker:

  1. Checkpoint idempotency still compares redacted values, so distinct sensitive checkpoint payloads can collapse. apps/gateway/src/agent/tess-durable-session.repository.ts lines 288-307 redact cursor and summary before insert and before the sameCheckpoint(existing, checkpoint) conflict comparison, but unlike inbox/outbox there is no pre-redaction digest for checkpoint fields in packages/db/src/schema.ts lines 566-583. Scenario: write checkpoint (sessionId=S, checkpointId=C, cursor="bearer secret-one", summary="email a@example.test", compactionEpoch=1), then replay the same checkpointId with cursor="bearer secret-two" and summary="email b@example.test". Both normalize to the same redacted values, so the second write is accepted as an idempotent duplicate instead of an immutable-state conflict. This leaves the prior checkpoint portion of the idempotency finding unresolved and fails the requested checkpoint conflict detection bar.

Also worth tightening with the same fix: the new inbox/outbox digest is createHash('sha256').update(content) at apps/gateway/src/agent/tess-durable-session.repository.ts lines 386-388. That proves exactness for high-entropy payloads, but it is unkeyed and stored in plaintext; for low-entropy PII/secret-shaped values, a keyed HMAC or sealed digest would better satisfy the “secret-safe digest / no live credential material at rest” contract.

No approval posted. Re-ROR needed after a new head fixes checkpoint pre-redaction exactness and keeps CI terminal green.

Marker: ROR-729-REQUEST-CHANGES-444988d2

REQUEST CHANGES — re-ROR for PR #729 at exact head `444988d23bada28d3cc9ce7e588e18e052f058ff`. CI verification: Woodpecker PR pipeline `1731` is green at this head, and the previously failing recovery test now passes rather than being skipped: `src/agent/tess-durable-session.repository.test.ts` ran 6 tests, including `survives a full PGlite close/reopen mid-session without duplicate inbox or outbox side effects` in 1515ms. Remaining blocker: 1. **Checkpoint idempotency still compares redacted values, so distinct sensitive checkpoint payloads can collapse.** `apps/gateway/src/agent/tess-durable-session.repository.ts` lines 288-307 redact `cursor` and `summary` before insert and before the `sameCheckpoint(existing, checkpoint)` conflict comparison, but unlike inbox/outbox there is no pre-redaction digest for checkpoint fields in `packages/db/src/schema.ts` lines 566-583. Scenario: write checkpoint `(sessionId=S, checkpointId=C, cursor="bearer secret-one", summary="email a@example.test", compactionEpoch=1)`, then replay the same `checkpointId` with `cursor="bearer secret-two"` and `summary="email b@example.test"`. Both normalize to the same redacted values, so the second write is accepted as an idempotent duplicate instead of an immutable-state conflict. This leaves the prior checkpoint portion of the idempotency finding unresolved and fails the requested checkpoint conflict detection bar. Also worth tightening with the same fix: the new inbox/outbox digest is `createHash('sha256').update(content)` at `apps/gateway/src/agent/tess-durable-session.repository.ts` lines 386-388. That proves exactness for high-entropy payloads, but it is unkeyed and stored in plaintext; for low-entropy PII/secret-shaped values, a keyed HMAC or sealed digest would better satisfy the “secret-safe digest / no live credential material at rest” contract. No approval posted. Re-ROR needed after a new head fixes checkpoint pre-redaction exactness and keeps CI terminal green. Marker: ROR-729-REQUEST-CHANGES-444988d2
jason.woltje added 1 commit 2026-07-13 05:00:39 +00:00
fix(tess): secure checkpoint idempotency
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
cbdc38af95
Author
Owner

VERIFIED APPROVE reviewer-of-record [W-jarvis:reviewer] head cbdc38af95

Evidence verified at exact head cbdc38af954d49016b5fdc4a6dab0497317b6a1c:

  • Woodpecker PR pipeline 1732 is terminal green on this commit; steps ci-postgres, install, sanitization, typecheck, lint, format, and test succeeded.
  • Recovery/idempotency proof is active, not skipped: src/agent/tess-durable-session.repository.test.ts ran 9 tests; PGlite close/reopen recovery with no duplicate inbox/outbox side effects passed in 2070ms.
  • Checkpoint, inbox, and outbox idempotency now compute pre-redaction hmac:v1 digests from original payload material using config-sourced BETTER_AUTH_SECRET; missing secret fails closed.
  • Distinct sensitive checkpoint and inbox/outbox payload regressions are present; delimiter-collision checkpoint regression is present; legacy checkpoint digest rows fail closed.
  • Durable payloads are redacted then sealed before persistence; scoped dispatch and one-time runtime approval persistence remain covered.
  • Durable DB objects and approval namespace are generic/agent-bound (interaction_*, agent:${agentName}:command-approval:*); no tess:command-approval:* namespace remains.

No merge performed by reviewer.

Marker: ROR-729-APPROVE-cbdc38af

VERIFIED APPROVE reviewer-of-record [W-jarvis:reviewer] head cbdc38af954d49016b5fdc4a6dab0497317b6a1c Evidence verified at exact head `cbdc38af954d49016b5fdc4a6dab0497317b6a1c`: - Woodpecker PR pipeline `1732` is terminal green on this commit; steps `ci-postgres`, `install`, `sanitization`, `typecheck`, `lint`, `format`, and `test` succeeded. - Recovery/idempotency proof is active, not skipped: `src/agent/tess-durable-session.repository.test.ts` ran 9 tests; PGlite close/reopen recovery with no duplicate inbox/outbox side effects passed in 2070ms. - Checkpoint, inbox, and outbox idempotency now compute pre-redaction `hmac:v1` digests from original payload material using config-sourced `BETTER_AUTH_SECRET`; missing secret fails closed. - Distinct sensitive checkpoint and inbox/outbox payload regressions are present; delimiter-collision checkpoint regression is present; legacy checkpoint digest rows fail closed. - Durable payloads are redacted then sealed before persistence; scoped dispatch and one-time runtime approval persistence remain covered. - Durable DB objects and approval namespace are generic/agent-bound (`interaction_*`, `agent:${agentName}:command-approval:*`); no `tess:command-approval:*` namespace remains. No merge performed by reviewer. Marker: ROR-729-APPROVE-cbdc38af
jason.woltje merged commit 99a2d0fc9d into main 2026-07-13 05:14:12 +00:00
jason.woltje deleted branch feat/tess-durable-state 2026-07-13 05:14:12 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#729