diff options
Diffstat (limited to 'docs/plans/local-oss-runner.md')
| -rw-r--r-- | docs/plans/local-oss-runner.md | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/docs/plans/local-oss-runner.md b/docs/plans/local-oss-runner.md index de16e05..108495b 100644 --- a/docs/plans/local-oss-runner.md +++ b/docs/plans/local-oss-runner.md @@ -183,3 +183,67 @@ This is the only phase we execute in this pass. Phases 2–4 will get their own - Branch pushed to remote After Phase 1 lands, we stop and decide whether to begin Phase 2 (elaboration). At that point we'll write a Phase 2 focused plan in `docs/plans/local-oss-runner.md`. + +--- + +# Post-epic follow-up: deep cleanup + +After all four phases land, plan and execute a deep cleanup pass. Things noticed in flight that we deliberately did not chase mid-epic: + +- **Sandbox/git tests fail in this environment** because `git commit` invokes a signing server that returns 400 ("missing source"). Affected: `TestSandboxCloneSource_*`, `TestSetupSandbox_*`, `TestTeardownSandbox_*`, `TestBlockedError_IncludesSandboxDir`, `TestClaudeRunner_Run_StaleSandboxDir_ClonesAfresh`. Fix: set `commit.gpgsign=false` in test setup so sandbox tests run hermetically. +- **`TestParseGeminiStream_ParsesStructuredOutput` is currently `t.Skip`** as a pre-existing gemini-stub gap. Either implement result-error/cost parsing in `parseGeminiStream` or delete the test until the stub is finished. +- **`TestPool_ActivePerAgent_DeletesZeroEntries` flakes** under `-race` when run with the full suite (passes in isolation and on `-count=3`). Likely goroutine-ordering in the `activePerAgent` map cleanup path. Audit dispatch/finish ordering. +- **`setupSandbox` test signature drift** was just fixed; audit other tests for similar staleness from prior refactors. +- **Pre-existing `executor` tests didn't compile on trunk** until the setupSandbox fix landed. Verify CI reality — is it green via something we're missing, or quietly broken? +- **GeminiRunner is still simulated** (`gemini.go:107-116`). Decide: finish it (real subprocess + cost parsing + sandbox) or delete it and leave only Claude + Local. +- **Frontend "Local" agent option** — UI dropdown still says "Auto / Claude / Gemini". Add Local once token telemetry has a place to render. +- **Audit `*_test.go` for `t.Skip` and other dormant breakage** before shipping more code on top. +- **`TestGeminiLogs_ParsedCorrectly`** in `internal/api` returns 404 from `GET /log` for a gemini execution — pre-existing on Phase 1 baseline. Some routing or log-path resolution mismatch specific to gemini executions. Likely related to the GeminiRunner stub status above. + +Goal: clean `go test -race ./...` with zero skips and zero environmental failures on whatever platform CI runs on. + +--- + +# Phase 2 — Focused Plan (Elaboration) + +## Phase 2 scope + +`internal/api/elaborate.go` currently has two paths: Claude and Gemini. Add a third (local) and make it the preferred path when local model is configured. Try-order: local → claude → gemini, with each next attempt only on hard failure of the prior. + +Second-cheapest, second-highest-volume LLM call after classification (one per task creation, sub-second target). Routing through local removes another cost line and lets elaboration work offline. + +## What ships + +- `Server` (`internal/api/server.go`) gains `llm *llm.Client` threaded through `NewServer` +- `internal/api/elaborate.go` gains `elaborateWithLocal(ctx, *llm.Client, input string) (string, error)` +- Dispatch in `Server.elaborate` reorders to: local → claude → gemini, gated by `PreferLocalForElaborate` +- `Config` gains `PreferLocalForElaborate bool`, defaulted true when `LocalModel.Endpoint != ""` +- Wiring in `internal/cli/serve.go` passes the LLM client into `NewServer` + +## Explicit non-goals + +- No prompt rework — reuse existing elaboration prompt template verbatim +- No streaming the response into SSE/WebSocket (one-shot RPC) +- No changes to webhook (Phase 3) or summary (Phase 4) +- No UI changes — `/elaborate` endpoint signature stays the same + +## Task list + +1. Read `internal/api/elaborate.go` end-to-end: dispatch site, Claude path, Gemini path, prompt template +2. Read `internal/api/server.go` `NewServer` signature and `Server` fields +3. Thread `llm *llm.Client` through `NewServer` and update callers (`internal/cli/serve.go`) +4. Implement `elaborateWithLocal` using the same prompt template as Claude/Gemini, returning `(string, error)` +5. Add `PreferLocalForElaborate bool` to `config.Config`, default true when local endpoint configured +6. Reorder dispatch: `if s.llm != nil && cfg.PreferLocalForElaborate { try local; else fall through }` then existing claude → gemini chain +7. httptest-based unit test for `elaborateWithLocal` +8. Dispatch fallback test: local fails → claude attempted +9. `go build ./... && go test -race ./...` +10. Commit Phase 2 on the same branch +11. Push + +## Stop conditions + +- Tests green under `-race` +- `prefer_local_for_elaborate=false` short-circuits to Claude path (preserves current behavior when user opts out) +- Local-failure fallback to Claude verified by test +- Branch pushed |
