fix: use Pi user auth and handle startup failures

This commit is contained in:
2026-07-21 14:01:47 +02:00
parent 2ff63d371f
commit 801f847ec4
12 changed files with 311 additions and 6 deletions
@@ -0,0 +1,87 @@
# Pi User Authentication and Startup Error Handling Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make Dockerized Pi consume the configured user auth store, expose four approved models, fail session startup cleanly, and remove three incomplete attempts.
**Architecture:** Compose mounts only the host Pi `auth.json` into the container while repository-owned Pi settings define the model policy. The backend validates the persisted model before creating a session and converts post-persistence runtime-construction errors into a failed session plus a sanitized 503.
**Tech Stack:** Docker Compose, Pi 0.80.3, Fastify/TypeScript, Vitest, shell deployment-contract tests.
## Global Constraints
- Never copy or log provider keys.
- Mount the auth file read-only.
- Enabled model order is ZAI, DeepSeek Flash, DeepSeek Pro, local Qwen.
- UI error strings remain English.
- Preserve the question in the frontend retry composer.
- Delete only the three explicitly approved incomplete session IDs.
---
### Task 1: Container Pi auth and model policy
**Files:**
- Modify: `compose.yaml`
- Modify: `.env.example`
- Modify: `deploy/pi/settings.json`
- Modify: `docker/core.Dockerfile`
- Test: `scripts/test-default-compose.sh`
- Test: `scripts/test-container-deployment.sh`
**Interfaces:**
- Consumes: `PI_AUTH_FILE`, an absolute readable host path.
- Produces: `/home/thoth/.pi/agent/auth.json` read-only and a four-entry `enabledModels` policy.
- [ ] Add failing deployment-contract assertions for the auth mount, four enabled models, and Pi 0.80.3.
- [ ] Run the focused shell tests and confirm the expected failures.
- [ ] Add the configurable auth mount, model policy, environment documentation, and Pi version alignment.
- [ ] Re-run the focused shell tests and confirm they pass.
### Task 2: Pre-persistence model availability guard
**Files:**
- Modify: `backend/src/app.ts`
- Modify: `backend/src/routes/sessions.ts`
- Test: `backend/test/routes-sessions.test.ts`
**Interfaces:**
- Consumes: the existing `ListModelsFn` used by model/settings routes.
- Produces: a sanitized 503 before `sessionNew` when saved settings are unavailable.
- [ ] Add a failing route test proving an unavailable model returns 503 and never calls `sessionNew`.
- [ ] Run the single Vitest test and confirm the expected failure.
- [ ] Inject the model-list dependency into session routes and implement the minimal guard.
- [ ] Re-run the focused test and confirm it passes.
### Task 3: Post-persistence runtime-construction failure
**Files:**
- Modify: `backend/src/routes/sessions.ts`
- Test: `backend/test/routes-sessions.test.ts`
**Interfaces:**
- Consumes: `ThtRunner.failSession(id, workspace)` and `PiProcessManager.createFor`.
- Produces: failed persisted state plus sanitized 503 when runtime construction throws.
- [ ] Add a failing route test for a throwing `createFor` after `sessionNew`.
- [ ] Run the single test and confirm it fails because the route currently returns 500 and leaves the session open.
- [ ] Catch runtime construction/binding failures, persist `failed`, and return the startup error.
- [ ] Re-run the focused test and confirm it passes.
### Task 4: Cleanup and full verification
**Files:**
- Modify: external PSD session store only through `tht session delete`.
**Interfaces:**
- Consumes: the three approved session IDs.
- Produces: no corresponding directories or API rows.
- [ ] Run backend Vitest and TypeScript typecheck.
- [ ] Run deployment-contract tests and render Compose with the real auth path.
- [ ] Rebuild/recreate the core container and verify health.
- [ ] Verify `/models` returns all four enabled models in order.
- [ ] Start a uniquely named DeepSeek smoke and observe the first reviewer gate; clean up only the smoke.
- [ ] Delete the three approved incomplete sessions and verify they are absent.
- [ ] Run `git diff --check` and inspect the final diff for secret leakage.
@@ -0,0 +1,46 @@
# Pi User Authentication and Startup Error Handling
## Goal
Make the Dockerized ThothII runtime use the same provider authentication that Pi stores for
the host user, expose only the explicitly enabled model set (including DeepSeek V4 Pro), and
avoid leaving apparently healthy `open` sessions when model startup cannot begin.
## Runtime configuration
- Keep the container user `thoth` and `HOME=/home/thoth`; those are valid container-local
identities and must not be changed to a macOS path.
- Bind-mount a configurable host Pi auth file, `PI_AUTH_FILE`, to
`/home/thoth/.pi/agent/auth.json` read-only. The default local value is
`${HOME}/.pi/agent/auth.json`; deployments may override it with another absolute path.
- Keep `deploy/pi/settings.json` as the non-secret runtime policy. It must enable, in order:
`zai/glm-5.2`, `deepseek/deepseek-v4-flash`, `deepseek/deepseek-v4-pro`, and
`aritmolab/qwen3.6-35b-a3b`.
- Keep `deploy/pi/models.json` for custom provider definitions only. Provider credentials stay
exclusively in Pi's user auth file and are never copied into the repository.
- Run Pi 0.80.3 in the core image, matching the audited backend provider contract.
## Session-start behavior
The settings write endpoint remains the main model-validation boundary. Session creation adds a
defense-in-depth availability check before persistence: if the saved provider/model is absent
from Pi's current enabled and authenticated model list, return a sanitized 503 and do not call
`tht session new`.
If runtime construction fails after persistence despite that check (for example a race or local
process limit), catch the error, mark the just-created session failed, and return the same
sanitized startup error. Never expose provider credentials or raw Pi errors to the browser.
Asynchronous bootstrap failures continue to emit `session_failed` and persist failed state.
## Cleanup and verification
Delete only these incomplete sessions:
- `a390c8b8-0a91-4a37-967b-ce7ff9be9797`
- `a2f974b2-4c48-4967-b4b6-afdbc2b2d541`
- `f66e1959-3c71-4b10-8aa1-606992046b7e`
Verify configuration contracts, backend tests and typecheck, rendered Compose mounts, `/models`
containing all four configured models, and a live DeepSeek startup reaching its first reviewer
gate. The auth file must remain read-only and no secret value may appear in rendered Compose,
logs, tests, or source control.