[shepherding] Durable outbox for Pi adapter: atomic leases + at-least-once + dead-letter isolation

Author: aleronwangCreated Sep 17, 2026Updated Sep 18, 2026
Labelsenhancement

Is this feature related to a problem? | 该功能需求是否与某个问题相关?请描述

Shepherding issue split out of #1070 (see review comment closing that PR). Follow-up PR author: @kbob3687-hub. Targets feat/server_team.

Background

The proxy-first Pi adapter has landed in MemoryProxy/src/agent-adapters/pi.ts via #1126, but that PR only covers the transport layer — it does not provide any durability guarantees. #1070 originally shipped a full durable-delivery layer that we want to reintroduce as an independent, testable PR.

Why this matters: without a durable outbox, memory writes generated during a Pi coding session can be lost on process crash, replayed on network retry, or silently deduplicated against the wrong turn. This is the single largest correctness gap in the current Pi path.

In scope

  • Atomic lease on outbox entries (single-consumer semantics across concurrent Pi sessions on the same host)
  • At-least-once delivery to the gateway with idempotency-key propagation
  • Dead-letter isolation for entries that fail past the retry ceiling, with an operator-visible surface (not just a log line)
  • Crash-window contract test: gateway accept → local ack write is interrupted → restart recover() must not double-deliver
  • Wire-in point: MemoryProxy/src/agent-adapters/pi.ts (post-#1126 layout)

Alignment with #1142

The outbox writes MUST carry idempotency_key: turn.key and the gateway side MUST treat same-key + same-payload as no-op, same-key + different-payload as an explicit error. This is the contract #1142 establishes for retry-safe conversation writes — please read that PR before implementing so we avoid the ack-gap discussion that consumed #978.

Out of scope

  • Any changes to the proxy-first transport layer landed by #1126
  • Cross-branch memory identity (that's the /tree shepherding issue)
  • Gateway-side idempotency implementation itself (owned by #1142)

Acceptance criteria

  • Outbox entries carry idempotency_key on every gateway call
  • Same key + same payload → gateway no-op (unit test)
  • Same key + different payload → gateway error surfaces to DLQ (unit test)
  • Crash-window test: kill process between gateway 202 and local ack, restart, assert no duplicate delivery
  • DLQ entries queryable and re-drivable via a documented operator path
  • No modifications to handler.ts or session/codebuddy/init.ts (per repo contribution guidance)
  • All new tests pass; existing test suite unaffected

Related

  • Closes down the outbox portion of #1070
  • Consumes the contract in #1142
  • See #978 for the earlier ack-gap discussion this design avoids

Suggested branching

Branch name: pi-adapter/durable-outbox against feat/server_team. Please keep this PR to the outbox layer only — the other three follow-ups have their own shepherding issues (linked in the batch comment on #1070).

Describe the solution you'd like | 描述你期望的解决方案

/

Describe alternatives you've considered | 描述你考虑过的其他方案

No response

Additional context | 补充说明

No response

Source: TencentCloud/TencentDB-Agent-Memory