Adds the Phase B paliad-side migration: a thin HTTP client of the
centralized aichat backend shipped in m/mAi#207 Phase A (darwin's
mai/darwin/issue-207-aichat branch). Implements the same services.Paliadin
interface as LocalPaliadinService / RemotePaliadinService — handler
plumbing is unchanged, the cutover is a single env-var flip.
internal/services/aichat_paliadin.go (~530 LoC):
- POST /chat/turn + POST /chat/reset + GET /chat/health via the aichat
JSON envelope (mirrors m/mAi internal/aichat/api/types.go verbatim;
no module import to keep paliad self-contained).
- Per-turn HS256 JWT mint (uses paliadin_jwt.go from the prior commit)
when SUPABASE_JWT_SECRET is configured. Aichat owns file write +
cleanup; we just sign and ship.
- Service-wide health-gate cache (10 s success window, no failure
cache — failures re-probe so recovery surfaces immediately).
- Per-user-window primer cache. Pulls up to MaxPrimerTurns prior
exchanges from paliad.paliadin_turns and ships them in TurnRequest.
Primer so a pane respawn (pane_spawned=true in response) doesn't
strand the user with a cold claude. Cleared on ResetSession +
pane_spawned response.
- Username from email_localpart per m's §13 Q2 pick (sanitized inside
aichat). Nil-DB fallback: "user-<uuid8>".
- Maps aichat's typed wire errors (auth_failed, persona_unknown,
mriver_unreachable, bootstrap_failed, timeout, shim_error) onto
paliad's existing audit-row codes — preserves the German i18n table
in paliadin.ts unchanged (no new strings needed per design §11).
cmd/server/main.go:
- PALIADIN_BACKEND env: "aichat" → AichatPaliadinService, anything
else → existing remote/local/disabled tree. Default = legacy, so
every existing deploy is byte-identical until flipped.
- buildAichatPaliadinConfig validates AICHAT_URL + AICHAT_TOKEN at
boot; AICHAT_PERSONA defaults to "paliadin". JWT secret threaded
in so per-user RLS is on by default.
Tests cover constructor defaults, health-gate caching + retry +
expiry, ResetSession wiring, error-envelope decoding + classifier,
HTTP-layer auth/JSON wiring via a roundTripper, JWT mint integration,
TurnContext → meta packing, and the env-gate helper. go test ./...
green. NOT self-merged — head owns the merge per task instructions.