diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index 81bc9410..13720ad2 100644 --- a/.seeds/issues.jsonl +++ b/.seeds/issues.jsonl @@ -757,7 +757,7 @@ {"id":"warren-882e","title":"ratchetwatch tightening: 2026-06-16","status":"open","type":"task","priority":3,"createdAt":"2026-06-16T10:44:01.390Z","updatedAt":"2026-06-16T10:56:50.995Z","labels":["audit","ratchetwatch"],"plan_id":"pl-2b5e"} {"id":"warren-7a15","title":"Decompose src/diagnostics/checks.test.ts (653 lines) below the 500-line global limit. Extract the shared helper captureSpawnCalls plus the imports it needs (SpawnFn from ../projects/clone.ts) into a new sibling src/diagnostics/checks.test-helpers.ts and export it; import it from each resulting test file (keep ONE copy — do NOT duplicate, or jscpd check:dups will flag it). Split the 10 top-level describe blocks along their existing seams into sibling files under src/diagnostics/ so every resulting file is < 500 lines: keep checks.test.ts for checkBwrap/checkCanopyClone/checkCanopyClean; create checks.config.test.ts for checkWarrenConfig/checkWarrenConfigDeprecations/checkWarrenDb/checkDatabaseReachable; create checks.preview.test.ts for checkPreviewPortAllocator/checkPreviewMaxLive/checkPreviewAuthStrength. Each file imports the checks under test from ./checks.ts and the shared helper from ./checks.test-helpers.ts. Do not alter any test body or assertion. Verify: each of `wc -l src/diagnostics/checks.test.ts src/diagnostics/checks.config.test.ts src/diagnostics/checks.preview.test.ts src/diagnostics/checks.test-helpers.ts` shows < 500 AND `bun test src/diagnostics/checks.test.ts src/diagnostics/checks.config.test.ts src/diagnostics/checks.preview.test.ts` reports 53 pass / 0 fail (same total as before) AND `bun run typecheck` is clean AND `bun run check:dups` exits 0.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-2b5e.\n\nParent seed: warren-882e — ratchetwatch tightening: 2026-06-16\nPlan template: refactor\nPlan approach: Split src/diagnostics/checks.test.ts (653 lines, 10 top-level describe blocks, 53 tests) along its existing describe seams into sibling test files under src/diagnostics/, each comfortably under the 500-line threshold. Hoist the single…\n\nRun `sd plan show pl-2b5e` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T10:44:38.043Z","updatedAt":"2026-06-16T10:52:14.841Z","labels":["ratchetwatch"],"plan_id":"pl-2b5e","blocks":["warren-2c73","warren-882e"],"extensions":{"role":"pi","lastRunId":"run_h8cb2nadsngr","lastRunAt":"2026-06-16T10:46:58.027Z"},"closedAt":"2026-06-16T10:52:14.841Z"} {"id":"warren-2c73","title":"Remove the \"src/diagnostics/checks.test.ts\": 653 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (checks.config.test.ts, checks.preview.test.ts, checks.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `grep -rn \"diagnostics/checks.test\" --include='*' . | grep -v node_modules` (or `git grep -n \"diagnostics/checks.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-2b5e.\n\nParent seed: warren-882e — ratchetwatch tightening: 2026-06-16\nPlan template: refactor\nPlan approach: Split src/diagnostics/checks.test.ts (653 lines, 10 top-level describe blocks, 53 tests) along its existing describe seams into sibling test files under src/diagnostics/, each comfortably under the 500-line threshold. Hoist the single…\n\nRun `sd plan show pl-2b5e` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T10:44:38.043Z","updatedAt":"2026-06-16T10:56:50.995Z","labels":["ratchetwatch"],"plan_id":"pl-2b5e","blocks":["warren-882e"],"closedAt":"2026-06-16T10:56:50.995Z"} -{"id":"warren-1c0d","title":"ratchetwatch tightening: 2026-06-17","status":"open","type":"task","priority":3,"createdAt":"2026-06-17T10:45:50.559Z","updatedAt":"2026-06-17T10:54:35.710Z","description":"Per docs/CONSTITUTION.md Article II (ratchets only tighten). Patrol 2026-06-17 measurements:\n- Coverage: functions 88.96% (floor 88.60%, slack 0.36pt), lines 91.74% (floor 91.54%, slack 0.20pt) — both under the 0.75pt threshold; no floor raise.\n- Bundle: net +460 B gzip JS over trailing 7d (raises summed ~2.6KB); under ~20KB; no finding.\n- Debt-marker allowlist: empty (last touched 2026-05-27); no finding.\n- File-size grandfather list: no entry has dropped below the 500-line global limit (no removals); no new entry in last 24h (only removal of checks.test.ts in 4e157b16). bridge.test.ts grandfather-at-birth already tracked (warren-889a).\n- Decomposition (one per patrol): src/server/handlers/plot-plan-runs.test.ts at 640 lines is the furthest-over grandfathered file NOT already covered by an open seed (pr.ts 659 is covered by warren-db9a/warren-70d7). Plan below decomposes it and removes its budget entry.","labels":["audit","ratchetwatch"],"plan_id":"pl-7c4f","blockedBy":["warren-e304"]} +{"id":"warren-1c0d","title":"ratchetwatch tightening: 2026-06-17","status":"open","type":"task","priority":3,"createdAt":"2026-06-17T10:45:50.559Z","updatedAt":"2026-06-17T10:59:24.445Z","description":"Per docs/CONSTITUTION.md Article II (ratchets only tighten). Patrol 2026-06-17 measurements:\n- Coverage: functions 88.96% (floor 88.60%, slack 0.36pt), lines 91.74% (floor 91.54%, slack 0.20pt) — both under the 0.75pt threshold; no floor raise.\n- Bundle: net +460 B gzip JS over trailing 7d (raises summed ~2.6KB); under ~20KB; no finding.\n- Debt-marker allowlist: empty (last touched 2026-05-27); no finding.\n- File-size grandfather list: no entry has dropped below the 500-line global limit (no removals); no new entry in last 24h (only removal of checks.test.ts in 4e157b16). bridge.test.ts grandfather-at-birth already tracked (warren-889a).\n- Decomposition (one per patrol): src/server/handlers/plot-plan-runs.test.ts at 640 lines is the furthest-over grandfathered file NOT already covered by an open seed (pr.ts 659 is covered by warren-db9a/warren-70d7). Plan below decomposes it and removes its budget entry.","labels":["audit","ratchetwatch"],"plan_id":"pl-7c4f"} {"id":"warren-59db","title":"Decompose src/server/handlers/plot-plan-runs.test.ts (640 lines, furthest-over grandfathered file not under an open seed) below the 500-line global limit. Extract the file-local helper/fixture group into a new sibling src/server/handlers/plot-plan-runs.test-helpers.ts and export each symbol: silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor, tcpUrl, plus their helper-local types (SdCall, SynthesizeCall, BuildDepsInput). Carry the imports those helpers need into the helpers file (Attachment from @os-eco/plot-cli, BurrowClient/BurrowClientPool, openDatabase/WarrenDb, createRepos/Repos, ProjectRow, the plan-run/plot/synthesizer types, SpawnFn/SpawnOptions/SpawnResult, RunEventBroker, NO_AUTH, createBridgeRegistry, startServer, server types). Keep ONE copy of every helper and import it — do NOT duplicate, or jscpd check:dups will flag it. Split the 9 tests in the single describe(\"POST /plot-plan-runs\") block along theme seams into two sibling test files, each importing from ./plot-plan-runs.test-helpers.ts: keep plot-plan-runs.test.ts for the happy-path + filter tests ('happy path: synthesizes plan + persists plan-run + emits Plot dispatch event' and 'filters closed seeds + sd_plan attachments before synthesis'); create plot-plan-runs.validation.test.ts for the 7 validation/error tests (malformed plot_id 400, no .plot/ 400, no .seeds/ 400, plot_id not in project 400, zero dispatchable attachments 400, 404 project missing, synthesizer error 500). Do not alter any test body, assertion, stub, or fixture. Mirror the precedent of src/diagnostics/checks.test-helpers.ts (warren-7a15) and src/server/handlers/projects.test-helpers.ts (warren-a715). Verify: each of `wc -l src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts src/server/handlers/plot-plan-runs.test-helpers.ts` shows < 500 AND `bun test src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts` reports 9 pass / 0 fail (same total as before) AND `bun run typecheck` is clean AND `bun run check:dups` exits 0.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-7c4f.\n\nParent seed: warren-1c0d — ratchetwatch tightening: 2026-06-17\nPlan template: refactor\nPlan approach: Extract the file-local helper/fixture block (the ~16 helpers spanning silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor,…\n\nRun `sd plan show pl-7c4f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-17T10:46:21.709Z","updatedAt":"2026-06-17T10:54:35.710Z","labels":["ratchetwatch"],"plan_id":"pl-7c4f","blocks":["warren-e304","warren-1c0d"],"extensions":{"role":"pi","lastRunId":"run_gwekz26ek6vm","lastRunAt":"2026-06-17T10:49:16.505Z"},"closedAt":"2026-06-17T10:54:35.710Z"} -{"id":"warren-e304","title":"Remove the \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (plot-plan-runs.validation.test.ts, plot-plan-runs.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `rg -n \"plot-plan-runs.test\" --hidden -g '!node_modules' .` (or `git grep -n \"plot-plan-runs.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","status":"open","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-7c4f.\n\nParent seed: warren-1c0d — ratchetwatch tightening: 2026-06-17\nPlan template: refactor\nPlan approach: Extract the file-local helper/fixture block (the ~16 helpers spanning silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor,…\n\nRun `sd plan show pl-7c4f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-17T10:46:21.709Z","updatedAt":"2026-06-17T10:54:35.710Z","labels":["ratchetwatch"],"plan_id":"pl-7c4f","blocks":["warren-1c0d"]} +{"id":"warren-e304","title":"Remove the \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (plot-plan-runs.validation.test.ts, plot-plan-runs.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `rg -n \"plot-plan-runs.test\" --hidden -g '!node_modules' .` (or `git grep -n \"plot-plan-runs.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-7c4f.\n\nParent seed: warren-1c0d — ratchetwatch tightening: 2026-06-17\nPlan template: refactor\nPlan approach: Extract the file-local helper/fixture block (the ~16 helpers spanning silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor,…\n\nRun `sd plan show pl-7c4f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-17T10:46:21.709Z","updatedAt":"2026-06-17T10:59:24.445Z","labels":["ratchetwatch"],"plan_id":"pl-7c4f","blocks":["warren-1c0d"],"closedAt":"2026-06-17T10:59:24.445Z"} {"id":"warren-f248","title":"Auditor sandboxes lack WARREN_API_TOKEN — warden-conversation delivery (POST /conversations/:id/messages) returns 401 for gatewatch/ratchetwatch/tastewatch","status":"open","type":"bug","priority":2,"createdAt":"2026-06-17T10:47:09.663Z","updatedAt":"2026-06-17T10:47:09.663Z","description":"Evidence (ratchetwatch patrol 2026-06-17):\n- The warren API is reachable from the auditor burrow at http://localhost:8080 (e.g. GET/POST /conversations responds), but every request returns: {\"error\":{\"code\":\"unauthorized\",\"message\":\"missing Authorization header\"}}.\n- src/server/auth.ts requires a bearer token from WARREN_API_TOKEN; that env var is NOT present in the auditor sandbox (env shows only ANTHROPIC_API_KEY and WARREN_QUALITY_GATE). No token file is mounted (~/.warren absent; /data unreadable; no *.token anywhere outside node_modules).\n- Result: the operating contract added by warren-7f62 (post each finding to the standing 'Audit Warden' conversation over POST /conversations/:id/messages, 202 steering channel) cannot be fulfilled by ANY auditor — gatewatch, ratchetwatch, tastewatch — because they cannot authenticate or even resolve the conversation id (GET /conversations is also 401-gated).\n- This is a runtime/provisioning gap, not a prompt gap: warren-7f62 wired the prompts but the auditor runs are not given a credential (or a loopback no-auth exemption, or a pre-resolved conversation id) to reach the channel.\nSuggested fix directions (for a human/operator to choose): inject a scoped WARREN_API_TOKEN into auditor burrow env via composeRunEnv, OR expose a loopback no-auth path for the conversation-message endpoint, OR pass the resolved warden conversation id + token through the rendered agent context. Until then, auditors file seeds/plans correctly (this patrol filed warren-1c0d + plan pl-7c4f) but the warden transcript stays empty.","labels":["audit","warden"]} diff --git a/.seeds/plans.jsonl b/.seeds/plans.jsonl index cde773e1..7ec328b1 100644 --- a/.seeds/plans.jsonl +++ b/.seeds/plans.jsonl @@ -71,4 +71,4 @@ {"id":"pl-3346","seed":"warren-832d","template":"feature","status":"approved","revision":1,"sections":{"context":"Plot plot-fbe17883 ('UI Nits') collects a batch of warren UI papercuts. Today sort behavior is inconsistent and duplicated: Runs.tsx ships a bespoke server-driven SortHeader/toggleSort with chevron icons and a 3-state cycle, while Workspace.tsx hand-rolls a client-side .sort() with handleSort/sortIndicator and text ↑↓ arrows and a 2-state toggle. Launching a plan-run is also a manual step: dispatch-plan-dialog.tsx and NewPlanRun.tsx both start planId as useState(\"\") and force the operator to paste the plan id by hand, even though NewRun.tsx already prefills plot_id from location.state. Several pages also have not been reviewed for mobile: wide tables and modals can produce horizontal scroll or trap the user with no way to dismiss. This plan eliminates the duplication and the manual steps so tables and run-launch flows behave consistently.","approach":"Land one shared sortable-table primitive (a useSortableTable hook plus a SortableHeader component under src/ui/src/components/ui/) that owns sort key/dir state, the click-to-cycle decision, and a single consistent chevron affordance, with a mode for server-driven sorting (Runs passes sort/dir to the API) and client-side sorting (Workspace sorts in memory). Migrate the existing pages onto it, deleting the per-page bespoke logic so common columns (date/started, status) read and behave identically everywhere. Separately, close the plan-run launch gap by reading the planner's emitted plan id (surfaced via the Plot's sd_plan attachment / planner run) and prefilling the planId field, mirroring NewRun's route-state plot_id prefill. Finally, do a mobile-readiness pass: audit every page for unintended horizontal scroll (the flex-main min-w-0 pattern, mx-a8a1df, plus the Table overflow-auto wrapper) and ensure every modal/popup is dismissible on a touch viewport. Keeping the primitive first lets the two table migrations land as small independent PRs.","alternatives":[{"name":"Per-page sort tidy-up without a shared primitive","rejected_because":"Violates the Plot constraint to prefer a single shared sortable-table primitive; leaves two divergent affordances (chevrons vs text arrows) and duplicated maintenance."},{"name":"Introduce a full data-grid/table library (e.g. TanStack Table)","rejected_because":"Heavy new dependency for a handful of small tables; would blow the bundle-size ratchet (check:bundle-size) and over-solves the papercut."}],"steps":[{"title":"Add shared sortable-table primitive: useSortableTable hook + SortableHeader component (server-driven and client-side modes) with unit tests","type":"feature","priority":2,"blocks":[2,3],"labels":["ui","tables"]},{"title":"Migrate Runs.tsx to the shared sortable-table primitive (server-driven mode): remove bespoke SortHeader/toggleSort, keep sort/dir API wiring and the 3-state cycle behavior","type":"task","plan_template":"refactor","priority":2,"labels":["ui","tables"]},{"title":"Migrate Workspace.tsx (and any other sortable tables) to the shared primitive: remove handleSort/sortIndicator text-arrow logic, standardize common columns (date/started, status) on the shared chevron affordance","type":"task","plan_template":"refactor","priority":2,"labels":["ui","tables"]},{"title":"Auto-populate plan_id after a planner finishes: read the planner run's emitted plan id (Plot sd_plan attachment) and prefill planId in dispatch-plan-dialog.tsx + NewPlanRun.tsx, mirroring NewRun's location.state plot_id prefill","type":"feature","priority":2,"labels":["ui","plan-runs"]},{"title":"Mobile readiness: audit every page at common mobile viewport widths and eliminate unintended horizontal scroll (flex min-w-0, table overflow wrappers, fixed-width layouts)","type":"feature","priority":2,"labels":["ui","mobile"]},{"title":"Mobile dismissibility: audit all modals/popups (dialog primitive, mobile nav drawer) so each is dismissible on touch — no state requiring refresh or re-navigation to exit","type":"feature","priority":2,"labels":["ui","mobile"]}],"risks":["tsc -b inside src/ui/ can fail with duplicate bun-types declarations from the parent node_modules (mx-ef8eab) — keep the primitive's types self-contained and run bun run build:ui before declaring done.","Server-driven (Runs) vs client-side (Workspace) sorting have different data flows; a single primitive must support both modes without forcing one page into the wrong one.","Discovering the planner-emitted plan id depends on the sd_plan attachment shape; if the attachment is absent the prefill must degrade gracefully to the current manual paste.","Mobile fixes touch shared layout (Layout main wrapper, Table) and can regress desktop — verify both viewports."],"acceptance":["Sortable tables across pages are driven by one shared primitive/hook; Runs.tsx SortHeader/toggleSort and Workspace.tsx handleSort/sortIndicator are removed.","Common columns (date/started, status) share identical sort affordances and behavior on every page that has them.","Triggering a plan run after a planner finishes auto-populates the plan_id field (mirroring plot_id prefill), with graceful fallback to manual entry when no plan id is available.","Every page is reviewed at common mobile viewport widths with no unintended horizontal scrolling.","Every modal/popup is dismissible on a mobile/touch viewport with no state requiring refresh or re-navigation to exit.","bun run check:all is green (lint, typecheck, check:dups, check:size, check:bundle-size, tests)."]},"children":["warren-2728","warren-c869","warren-3c6f","warren-ae9f","warren-4734","warren-6f43"],"createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","name":"UI Nits: shared sortable tables, plan_id auto-populate, mobile readiness"} {"id":"pl-dfb5","seed":"warren-1551","template":"feature","status":"done","revision":1,"sections":{"context":"Warren's UI has accumulated three concrete papercuts that this Plot (plot-9f03348c) targets. (1) Table sorting is inconsistent: Runs.tsx sorts server-side via a local SortHeader component, Workspace.tsx sorts client-side with inline ↑/↓ glyphs and its own SortKey/SortDir state, while Projects, PlanRuns, and Agents tables are not sortable at all. (2) The plan-run dispatch form (NewPlanRun.tsx) forces the operator to hand-type the plan id (`pl-a258`) into a free-text Input with no list to pick from — error-prone and undiscoverable. (3) Several pages (notably Runs.tsx and Workspace.tsx with zero responsive prefixes) break on phone-width viewports because their wide tables overflow and there is no standardized responsive pattern. This is responsive-web polish plus consistency work — no redesign, no native/PWA.","approach":"Tackle the three papercuts as independent, parallelizable workstreams that converge on a final release seed. SORTING: extract one canonical sortable column-header primitive into src/ui/src/components/ui/ that consolidates the two existing ad-hoc implementations (Workspace inline glyphs + Runs SortHeader), then wire it into every list table so sort affordances, glyphs, and toggle behaviour are identical everywhere. PLAN_ID PREFILL: add a read-side server endpoint that lists the available seeds plans for a project (shelling out through the existing src/seeds-cli/ helpers, mirroring `sd plan show`/`sd plan list`), expose it through the api client + types, then replace the free-text Plan ID Input in NewPlanRun.tsx with a populated selector that still allows a manual fallback. MOBILE: first standardize the responsive contract (canonical breakpoints targeting ~393px iPhone logical width degrading to ~360px, plus a reusable wide-table-on-mobile pattern — horizontal scroll / stacked), then apply it page-by-page so every page is usable on phones. Finish with the mandatory patch version bump via the .claude/commands/release.md flow. Chosen over a single monolithic 'fix the UI' seed because each papercut touches different modules, reviews independently, and the Plot constraint explicitly permits chunked mobile execution.","alternatives":[{"name":"One monolithic UI-polish seed","rejected_because":"Too large to review as a single PR and conflates three unrelated surfaces (table component, server endpoint + form, responsive CSS); the Plot intent explicitly allows the mobile work to be chunked."},{"name":"Client-side-only plan_id autocomplete (no new endpoint)","rejected_because":"The UI has no existing way to enumerate a project's plans; the plan list lives in `.seeds/plans.jsonl` inside the clone, only reachable server-side via the seeds-cli helpers, so a read endpoint is required to populate any selector."}],"steps":[{"title":"Extract a shared sortable table-head component into components/ui","type":"task","priority":2,"blocks":[2],"labels":["ui","sorting"]},{"title":"Apply the shared sortable header across all list tables (Runs, Workspace, Projects, PlanRuns, Agents)","type":"feature","priority":2,"blocks":[7],"labels":["ui","sorting"]},{"title":"Add a read endpoint + api client to list a project's seeds plans","type":"feature","priority":2,"blocks":[4],"labels":["server","plan-runs"]},{"title":"Replace free-text Plan ID input with a populated selector (manual fallback) on the plan-run form","type":"feature","priority":2,"blocks":[7],"labels":["ui","plan-runs"]},{"title":"Standardize the responsive contract: canonical breakpoints (~393px down to ~360px) and a reusable wide-table-on-mobile pattern","type":"feature","priority":2,"blocks":[6],"labels":["ui","mobile"]},{"title":"Apply the standardized mobile pattern across all pages so every page works on phones","type":"feature","priority":2,"blocks":[7],"labels":["ui","mobile"]},{"title":"Patch version bump via the .claude/commands/release.md flow (package.json + src/index.ts in sync, CHANGELOG.md, commit)","type":"task","priority":2,"labels":["release"]}],"risks":["Consolidating two sort implementations may regress Runs' server-side sort params vs Workspace's client-side sort — preserve each table's existing data source, change only the header affordance.","The plans-list endpoint shells out to the seeds CLI; handle projects without `.seeds/` (hasSeeds=false) and slow/erroring shell-outs gracefully, mirroring the existing hasSeeds gating.","Mobile table reflow can hide columns operators rely on; the standardized pattern must keep all data reachable (scroll or stack), not drop columns silently.","Bundle-size and per-file line-count ratchets (check:bundle-size, check:size) can trip on new components — keep additions lean and re-baseline only when legitimately grown."],"acceptance":["Every list table (Runs, Workspace, Projects, PlanRuns, Agents) uses the same sortable-header component with identical sort affordance, glyphs, and toggle behaviour.","The plan-run dispatch form lets the operator pick a plan id from a list of the selected project's plans, with a manual-entry fallback, and no longer requires hand-typing `pl-XXXX`.","All pages render and are usable at ~393px and degrade gracefully down to ~360px, with no horizontal overflow that hides data; wide tables follow the standardized responsive pattern.","A patch version bump is committed via the release.md flow with package.json and src/index.ts in sync and CHANGELOG.md updated.","bun run check:all passes (lint, typecheck, size, bundle-size, coverage, etc.) on the merged result."]},"children":["warren-9440","warren-5562","warren-9b49","warren-c030","warren-3315","warren-42ba","warren-1c81"],"createdAt":"2026-06-16T07:18:51.397Z","updatedAt":"2026-06-16T22:48:22.022Z","name":"UI Nits Redux"} {"id":"pl-2b5e","seed":"warren-882e","template":"refactor","status":"done","revision":1,"sections":{"context":"ratchetwatch patrol 2026-06-16, docs/CONSTITUTION.md Article II (ratchets only tighten). The file-size grandfather list (scripts/file-size-budgets.json, threshold 500) holds 23 entries, all still over the 500-line global limit, so none are removable this patrol. Coverage slack is tight (functions 88.97% vs floor 88.60% = 0.37pt; lines 91.70% vs floor 91.54% = 0.16pt; both under the 0.75pt threshold). Bundle creep is tight (~1.7KB summed gzip-js raises over the trailing 7 days, far under 20KB; an autoheal re-baseline at 9da86f5 dropped totals back down). Debt-marker allowlist is empty. The single warranted mechanical tightening is the one-per-patrol decomposition: src/diagnostics/checks.test.ts at 653 lines is the grandfathered file furthest over the limit (over by 153) that is NOT already covered by an open seed. The absolute furthest-over file, src/runs/pr.ts (659), is already covered by open seeds warren-db9a + warren-70d7, so it is skipped per the dedupe rule.","behavior_invariant":"All 53 tests currently in src/diagnostics/checks.test.ts must still exist and pass after the decomposition, with the same total count (53) across the resulting sibling files. The checks under test (checkBwrap, checkCanopyClone, checkCanopyClean, checkWarrenConfig, checkWarrenConfigDeprecations, checkWarrenDb, checkDatabaseReachable, checkPreviewPortAllocator, checkPreviewMaxLive, checkPreviewAuthStrength) and their assertions remain unchanged in meaning; only file boundaries move. No production source under src/diagnostics/ is modified. Every check:all gate stays green.","approach":"Split src/diagnostics/checks.test.ts (653 lines, 10 top-level describe blocks, 53 tests) along its existing describe seams into sibling test files under src/diagnostics/, each comfortably under the 500-line threshold. Hoist the single shared helper captureSpawnCalls (and the imports it needs: SpawnFn type from ../projects/clone.ts) into a new sibling src/diagnostics/checks.test-helpers.ts and import it from each split file rather than copy-pasting it (jscpd check:dups will flag a duplicate). Suggested grouping (executor may adjust as long as every file is < 500 lines and the shared helper lives in ONE place): keep checks.test.ts for the sandbox/clone group (checkBwrap, checkCanopyClone, checkCanopyClean); new checks.config.test.ts for the config group (checkWarrenConfig, checkWarrenConfigDeprecations, checkWarrenDb, checkDatabaseReachable); new checks.preview.test.ts for the preview group (checkPreviewPortAllocator, checkPreviewMaxLive, checkPreviewAuthStrength). Then remove the grandfather entry for checks.test.ts from scripts/file-size-budgets.json; do NOT add budget entries for the new siblings (they must default-pass under 500).","steps":[{"title":"Decompose src/diagnostics/checks.test.ts (653 lines) below the 500-line global limit. Extract the shared helper captureSpawnCalls plus the imports it needs (SpawnFn from ../projects/clone.ts) into a new sibling src/diagnostics/checks.test-helpers.ts and export it; import it from each resulting test file (keep ONE copy — do NOT duplicate, or jscpd check:dups will flag it). Split the 10 top-level describe blocks along their existing seams into sibling files under src/diagnostics/ so every resulting file is < 500 lines: keep checks.test.ts for checkBwrap/checkCanopyClone/checkCanopyClean; create checks.config.test.ts for checkWarrenConfig/checkWarrenConfigDeprecations/checkWarrenDb/checkDatabaseReachable; create checks.preview.test.ts for checkPreviewPortAllocator/checkPreviewMaxLive/checkPreviewAuthStrength. Each file imports the checks under test from ./checks.ts and the shared helper from ./checks.test-helpers.ts. Do not alter any test body or assertion. Verify: each of `wc -l src/diagnostics/checks.test.ts src/diagnostics/checks.config.test.ts src/diagnostics/checks.preview.test.ts src/diagnostics/checks.test-helpers.ts` shows < 500 AND `bun test src/diagnostics/checks.test.ts src/diagnostics/checks.config.test.ts src/diagnostics/checks.preview.test.ts` reports 53 pass / 0 fail (same total as before) AND `bun run typecheck` is clean AND `bun run check:dups` exits 0.","labels":["ratchetwatch"],"blocks":[2]},{"title":"Remove the \"src/diagnostics/checks.test.ts\": 653 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (checks.config.test.ts, checks.preview.test.ts, checks.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `grep -rn \"diagnostics/checks.test\" --include='*' . | grep -v node_modules` (or `git grep -n \"diagnostics/checks.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","labels":["ratchetwatch"]}],"acceptance":["src/diagnostics/checks.test.ts and every new sibling (checks.config.test.ts, checks.preview.test.ts, checks.test-helpers.ts) are each < 500 lines (wc -l).","bun test over the resulting diagnostics check files reports 53 pass / 0 fail — the same total test count as the pre-split checks.test.ts.","scripts/file-size-budgets.json no longer lists src/diagnostics/checks.test.ts and adds NO entry for any new sibling file.","A repo-wide search for the old path 'diagnostics/checks.test' (incl. Dockerfile, workflow YAML, supervisor/config strings, scripts/acceptance, docs) finds no stale reference, per Article VI.","bun run check:all is fully green (check:size, check:dups, typecheck, coverage, all gates)."]},"children":["warren-7a15","warren-2c73"],"createdAt":"2026-06-16T10:44:38.043Z","updatedAt":"2026-06-16T10:56:50.995Z","name":"ratchetwatch tightening 2026-06-16: decompose checks.test.ts"} -{"id":"pl-7c4f","seed":"warren-1c0d","template":"refactor","status":"approved","revision":1,"sections":{"context":"Article II of docs/CONSTITUTION.md requires grandfather lists to burn down, not just hold. src/server/handlers/plot-plan-runs.test.ts is grandfathered in scripts/file-size-budgets.json at 640 lines (140 over the 500-line global limit) and is the furthest-over entry not already covered by an open seed (src/runs/pr.ts at 659 is covered by warren-db9a / warren-70d7). ratchetwatch decomposes at most one file per patrol; this is that file for 2026-06-17. No other mechanical tightening is warranted this patrol: coverage slack is under 0.75pt, bundle creep is under 20KB/7d, the debt allowlist is empty, and no other entry has fallen under the global limit.","behavior_invariant":"The same set of tests for POST /plot-plan-runs must continue to run and pass with the identical total count (9 tests across the original single describe block). No test body, assertion, stub, or fixture may change behavior — this is a pure file split, not a rewrite. bun run check:all must stay fully green.","approach":"Extract the file-local helper/fixture block (the ~16 helpers spanning silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor, tcpUrl plus their helper-local types SdCall/SynthesizeCall/BuildDepsInput) into a new sibling src/server/handlers/plot-plan-runs.test-helpers.ts and export each symbol, carrying the imports those helpers need. Then split the 9 tests in the single `describe(\"POST /plot-plan-runs\")` block along theme seams into two sibling files, each importing the shared helpers (keep ONE copy of every helper — do NOT duplicate, or jscpd check:dups will flag it). Mirror the established precedent in this repo (warren-7a15 checks.test-helpers.ts, warren-a715 projects.test-helpers.ts). Finally remove the grandfather entry. Both budget changes leave every gate green: the resulting files all default-pass under the 500-line threshold.","steps":[{"title":"Decompose src/server/handlers/plot-plan-runs.test.ts (640 lines, furthest-over grandfathered file not under an open seed) below the 500-line global limit. Extract the file-local helper/fixture group into a new sibling src/server/handlers/plot-plan-runs.test-helpers.ts and export each symbol: silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor, tcpUrl, plus their helper-local types (SdCall, SynthesizeCall, BuildDepsInput). Carry the imports those helpers need into the helpers file (Attachment from @os-eco/plot-cli, BurrowClient/BurrowClientPool, openDatabase/WarrenDb, createRepos/Repos, ProjectRow, the plan-run/plot/synthesizer types, SpawnFn/SpawnOptions/SpawnResult, RunEventBroker, NO_AUTH, createBridgeRegistry, startServer, server types). Keep ONE copy of every helper and import it — do NOT duplicate, or jscpd check:dups will flag it. Split the 9 tests in the single describe(\"POST /plot-plan-runs\") block along theme seams into two sibling test files, each importing from ./plot-plan-runs.test-helpers.ts: keep plot-plan-runs.test.ts for the happy-path + filter tests ('happy path: synthesizes plan + persists plan-run + emits Plot dispatch event' and 'filters closed seeds + sd_plan attachments before synthesis'); create plot-plan-runs.validation.test.ts for the 7 validation/error tests (malformed plot_id 400, no .plot/ 400, no .seeds/ 400, plot_id not in project 400, zero dispatchable attachments 400, 404 project missing, synthesizer error 500). Do not alter any test body, assertion, stub, or fixture. Mirror the precedent of src/diagnostics/checks.test-helpers.ts (warren-7a15) and src/server/handlers/projects.test-helpers.ts (warren-a715). Verify: each of `wc -l src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts src/server/handlers/plot-plan-runs.test-helpers.ts` shows < 500 AND `bun test src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts` reports 9 pass / 0 fail (same total as before) AND `bun run typecheck` is clean AND `bun run check:dups` exits 0.","labels":["ratchetwatch"],"blocks":[2]},{"title":"Remove the \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (plot-plan-runs.validation.test.ts, plot-plan-runs.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `rg -n \"plot-plan-runs.test\" --hidden -g '!node_modules' .` (or `git grep -n \"plot-plan-runs.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","labels":["ratchetwatch"]}],"acceptance":["src/server/handlers/plot-plan-runs.test.ts, plot-plan-runs.validation.test.ts, and plot-plan-runs.test-helpers.ts are each < 500 lines (wc -l).","bun test src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts reports 9 pass / 0 fail — same total as the original file.","The \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry is removed from scripts/file-size-budgets.json with no new entries added for the sibling files.","A repo-wide search (rg/git grep across all file types plus Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/, scripts/acceptance/, docs/) finds no stale reference to the old single-file layout.","bun run check:all is fully green (check:size, check:dups, typecheck, and all other gates pass)."]},"children":["warren-59db","warren-e304"],"createdAt":"2026-06-17T10:46:21.709Z","updatedAt":"2026-06-17T10:46:21.709Z","name":"ratchetwatch tightening: 2026-06-17 (decompose plot-plan-runs.test.ts)"} +{"id":"pl-7c4f","seed":"warren-1c0d","template":"refactor","status":"done","revision":1,"sections":{"context":"Article II of docs/CONSTITUTION.md requires grandfather lists to burn down, not just hold. src/server/handlers/plot-plan-runs.test.ts is grandfathered in scripts/file-size-budgets.json at 640 lines (140 over the 500-line global limit) and is the furthest-over entry not already covered by an open seed (src/runs/pr.ts at 659 is covered by warren-db9a / warren-70d7). ratchetwatch decomposes at most one file per patrol; this is that file for 2026-06-17. No other mechanical tightening is warranted this patrol: coverage slack is under 0.75pt, bundle creep is under 20KB/7d, the debt allowlist is empty, and no other entry has fallen under the global limit.","behavior_invariant":"The same set of tests for POST /plot-plan-runs must continue to run and pass with the identical total count (9 tests across the original single describe block). No test body, assertion, stub, or fixture may change behavior — this is a pure file split, not a rewrite. bun run check:all must stay fully green.","approach":"Extract the file-local helper/fixture block (the ~16 helpers spanning silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor, tcpUrl plus their helper-local types SdCall/SynthesizeCall/BuildDepsInput) into a new sibling src/server/handlers/plot-plan-runs.test-helpers.ts and export each symbol, carrying the imports those helpers need. Then split the 9 tests in the single `describe(\"POST /plot-plan-runs\")` block along theme seams into two sibling files, each importing the shared helpers (keep ONE copy of every helper — do NOT duplicate, or jscpd check:dups will flag it). Mirror the established precedent in this repo (warren-7a15 checks.test-helpers.ts, warren-a715 projects.test-helpers.ts). Finally remove the grandfather entry. Both budget changes leave every gate green: the resulting files all default-pass under the 500-line threshold.","steps":[{"title":"Decompose src/server/handlers/plot-plan-runs.test.ts (640 lines, furthest-over grandfathered file not under an open seed) below the 500-line global limit. Extract the file-local helper/fixture group into a new sibling src/server/handlers/plot-plan-runs.test-helpers.ts and export each symbol: silentLogger, stubFetch, jsonRes, poolFor, makeSdSpawn, planShowResult, seedShowResult, makeAttachment, makePlotReader, makePlotResolver, makeSynthesizer, depsFor, tcpUrl, plus their helper-local types (SdCall, SynthesizeCall, BuildDepsInput). Carry the imports those helpers need into the helpers file (Attachment from @os-eco/plot-cli, BurrowClient/BurrowClientPool, openDatabase/WarrenDb, createRepos/Repos, ProjectRow, the plan-run/plot/synthesizer types, SpawnFn/SpawnOptions/SpawnResult, RunEventBroker, NO_AUTH, createBridgeRegistry, startServer, server types). Keep ONE copy of every helper and import it — do NOT duplicate, or jscpd check:dups will flag it. Split the 9 tests in the single describe(\"POST /plot-plan-runs\") block along theme seams into two sibling test files, each importing from ./plot-plan-runs.test-helpers.ts: keep plot-plan-runs.test.ts for the happy-path + filter tests ('happy path: synthesizes plan + persists plan-run + emits Plot dispatch event' and 'filters closed seeds + sd_plan attachments before synthesis'); create plot-plan-runs.validation.test.ts for the 7 validation/error tests (malformed plot_id 400, no .plot/ 400, no .seeds/ 400, plot_id not in project 400, zero dispatchable attachments 400, 404 project missing, synthesizer error 500). Do not alter any test body, assertion, stub, or fixture. Mirror the precedent of src/diagnostics/checks.test-helpers.ts (warren-7a15) and src/server/handlers/projects.test-helpers.ts (warren-a715). Verify: each of `wc -l src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts src/server/handlers/plot-plan-runs.test-helpers.ts` shows < 500 AND `bun test src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts` reports 9 pass / 0 fail (same total as before) AND `bun run typecheck` is clean AND `bun run check:dups` exits 0.","labels":["ratchetwatch"],"blocks":[2]},{"title":"Remove the \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files (plot-plan-runs.validation.test.ts, plot-plan-runs.test-helpers.ts) — they must default-pass under the 500-line threshold (confirm `wc -l` for each shows < 500). Per docs/CONSTITUTION.md Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `rg -n \"plot-plan-runs.test\" --hidden -g '!node_modules' .` (or `git grep -n \"plot-plan-runs.test\"`) PLUS an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, scripts/acceptance/, and docs/ — and fix any stale reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:size` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves all resulting files default-passing under the 500-line threshold).","labels":["ratchetwatch"]}],"acceptance":["src/server/handlers/plot-plan-runs.test.ts, plot-plan-runs.validation.test.ts, and plot-plan-runs.test-helpers.ts are each < 500 lines (wc -l).","bun test src/server/handlers/plot-plan-runs.test.ts src/server/handlers/plot-plan-runs.validation.test.ts reports 9 pass / 0 fail — same total as the original file.","The \"src/server/handlers/plot-plan-runs.test.ts\": 640 entry is removed from scripts/file-size-budgets.json with no new entries added for the sibling files.","A repo-wide search (rg/git grep across all file types plus Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/, scripts/acceptance/, docs/) finds no stale reference to the old single-file layout.","bun run check:all is fully green (check:size, check:dups, typecheck, and all other gates pass)."]},"children":["warren-59db","warren-e304"],"createdAt":"2026-06-17T10:46:21.709Z","updatedAt":"2026-06-17T10:59:24.445Z","name":"ratchetwatch tightening: 2026-06-17 (decompose plot-plan-runs.test.ts)"} diff --git a/scripts/acceptance/scenarios/31-plot-plan-run-synthesis.ts b/scripts/acceptance/scenarios/31-plot-plan-run-synthesis.ts index 0a2dae8a..4715f9ee 100644 --- a/scripts/acceptance/scenarios/31-plot-plan-run-synthesis.ts +++ b/scripts/acceptance/scenarios/31-plot-plan-run-synthesis.ts @@ -29,7 +29,7 @@ * * The `project_lacks_seeds` arm is unit-test-only here: a project with * `.plot/` but no `.seeds/` requires a third fixture clone for one - * assertion already covered by `handlers.plot-plan-runs.test.ts`. + * assertion already covered by `plot-plan-runs.validation.test.ts`. * * Topology: in-proc only, per-scenario stack so the * `WARREN_GH_FETCH_OVERRIDE=merged` / `WARREN_STUB_NO_COMMIT_SEEDS` diff --git a/scripts/file-size-budgets.json b/scripts/file-size-budgets.json index da4a4996..a54cdd5f 100644 --- a/scripts/file-size-budgets.json +++ b/scripts/file-size-budgets.json @@ -21,7 +21,6 @@ "src/server/bridges.test.ts": 557, "src/server/handlers/agents.test.ts": 533, "src/server/main/index.ts": 548, - "src/server/handlers/plot-plan-runs.test.ts": 640, "src/server/integration.multi-worker.test.ts": 553, "src/server/server.test.ts": 536 }