From 3d17d148558853f7a0aa1b75c57a6915cbbf71ac Mon Sep 17 00:00:00 2001 From: warren Date: Tue, 16 Jun 2026 03:12:58 +0000 Subject: [PATCH 1/2] chore(warren): plot state --- .plot/plot-b11c5999.events.jsonl | 1 + .plot/plot-fbe17883.events.jsonl | 1 + 2 files changed, 2 insertions(+) diff --git a/.plot/plot-b11c5999.events.jsonl b/.plot/plot-b11c5999.events.jsonl index 39d685db..009f3873 100644 --- a/.plot/plot-b11c5999.events.jsonl +++ b/.plot/plot-b11c5999.events.jsonl @@ -13,3 +13,4 @@ {"type":"run_dispatched","actor":"user:operator","at":"2026-06-16T02:47:02.972Z","data":{"run_id":"run_mqpjexh9zf3c","agent":"pi","model":"claude-opus-4-8","project":"prj_z07y6ssfjfpk"}} {"type":"run_dispatched","actor":"user:operator","at":"2026-06-16T02:57:44.243Z","data":{"run_id":"run_90fqekdeztrt","agent":"pi","model":"claude-opus-4-8","project":"prj_z07y6ssfjfpk"}} {"type":"run_dispatched","actor":"user:operator","at":"2026-06-16T03:05:13.368Z","data":{"run_id":"run_jq3fqgwcs8bb","agent":"pi","model":"claude-opus-4-8","project":"prj_z07y6ssfjfpk"}} +{"type":"run_dispatched","actor":"user:operator","at":"2026-06-16T03:10:33.438Z","data":{"run_id":"run_gky38mc6b49z","agent":"pi","model":"claude-opus-4-8","project":"prj_z07y6ssfjfpk"}} diff --git a/.plot/plot-fbe17883.events.jsonl b/.plot/plot-fbe17883.events.jsonl index b15b3aa5..8f8e9e87 100644 --- a/.plot/plot-fbe17883.events.jsonl +++ b/.plot/plot-fbe17883.events.jsonl @@ -5,3 +5,4 @@ {"type":"intent_edited","actor":"user:leveret","at":"2026-06-16T02:52:41.441Z","data":{"field":"success_criteria","value":["Every page is reviewed for mobile readiness; no unintended horizontal scrolling at common mobile viewport widths","Modals/popups are dismissible on mobile (no state where the user must refresh or re-navigate to exit)"]}} {"type":"intent_edited","actor":"user:leveret","at":"2026-06-16T02:54:03.254Z","data":{"field":"constraints","value":["Prefer a single shared sortable-table primitive over per-page sort logic — minimize duplicated/maintained code"]}} {"type":"intent_edited","actor":"user:leveret","at":"2026-06-16T02:54:03.254Z","data":{"field":"success_criteria","value":["Sortable tables are driven by one shared primitive/hook; per-page bespoke sort logic (e.g. Runs.tsx SortHeader/toggleSort) is removed"]}} +{"type":"run_dispatched","actor":"user:operator","at":"2026-06-16T03:08:14.607Z","data":{"run_id":"run_17e27315wd04","agent":"planner","model":"claude-opus-4-8","project":"prj_z07y6ssfjfpk"}} From b1f56cb1db039fb04f84dc43c82666c1bcb6e5e6 Mon Sep 17 00:00:00 2001 From: warren Date: Tue, 16 Jun 2026 03:12:58 +0000 Subject: [PATCH 2/2] chore(warren): seeds state --- .seeds/issues.jsonl | 11 +++++++++-- .seeds/plans.jsonl | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index a13ab01c..e91b261f 100644 --- a/.seeds/issues.jsonl +++ b/.seeds/issues.jsonl @@ -688,7 +688,7 @@ {"id":"warren-8db7","title":"Harmonize WARREN_SCHEDULER_DISABLED parser to its documented allow-list","status":"closed","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-aff2.\n\nParent seed: warren-2e01 — nightwatch patrol: 2026-06-13\nPlan template: refactor\nPlan approach: Replace the deny-list body of `parseBoolFlag` in both files with the allow-list form already used by `parseTrueEnv` (`src/server/main/utils.ts:80`): `const t = raw.trim().toLowerCase(); return t === '1' || t === 'true' || t === 'yes' || t…\n\nRun `sd plan show pl-aff2` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-13T09:05:19.018Z","updatedAt":"2026-06-13T09:11:00.507Z","labels":["nightwatch"],"requires_plan":true,"blocks":["warren-b79f","warren-2e01"],"extensions":{"role":"pi","lastRunId":"run_91q6gk5yrazh","lastRunAt":"2026-06-13T09:07:06.508Z"},"closedAt":"2026-06-13T09:11:00.507Z"} {"id":"warren-b4ba","title":"Harmonize WARREN_PLAN_RUN_DISABLED parser to its documented allow-list","status":"closed","type":"task","priority":3,"plan_step_index":1,"description":"\nStep 2 of plan pl-aff2.\n\nParent seed: warren-2e01 — nightwatch patrol: 2026-06-13\nPlan template: refactor\nPlan approach: Replace the deny-list body of `parseBoolFlag` in both files with the allow-list form already used by `parseTrueEnv` (`src/server/main/utils.ts:80`): `const t = raw.trim().toLowerCase(); return t === '1' || t === 'true' || t === 'yes' || t…\n\nRun `sd plan show pl-aff2` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-13T09:05:19.018Z","updatedAt":"2026-06-13T09:16:28.571Z","labels":["nightwatch"],"plan_id":"pl-aff2","blocks":["warren-b79f","warren-2e01"],"extensions":{"role":"pi","lastRunId":"run_gx887x6svtnc","lastRunAt":"2026-06-13T09:12:26.810Z"},"closedAt":"2026-06-13T09:16:28.571Z"} {"id":"warren-b79f","title":"Release: run /release per .claude/commands/release.md","status":"closed","type":"task","priority":3,"plan_step_index":2,"description":"\nStep 3 of plan pl-aff2.\n\nParent seed: warren-2e01 — nightwatch patrol: 2026-06-13\nPlan template: refactor\nPlan approach: Replace the deny-list body of `parseBoolFlag` in both files with the allow-list form already used by `parseTrueEnv` (`src/server/main/utils.ts:80`): `const t = raw.trim().toLowerCase(); return t === '1' || t === 'true' || t === 'yes' || t…\n\nRun `sd plan show pl-aff2` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-13T09:05:19.018Z","updatedAt":"2026-06-13T09:23:44.338Z","labels":["nightwatch"],"plan_id":"pl-aff2","blocks":["warren-2e01"],"extensions":{"role":"pi","lastRunId":"run_fjg0nefmk4xm","lastRunAt":"2026-06-13T09:17:56.832Z"},"closedAt":"2026-06-13T09:23:44.338Z"} -{"id":"warren-4c8d","title":"gatewatch: PR #340 commits stray .pi/sessions agent transcript not named in its title","status":"open","type":"task","priority":2,"createdAt":"2026-06-13T10:11:52.904Z","updatedAt":"2026-06-16T03:03:49.017Z","description":"Article I (Merges are truthful): a PR's title describes its diff. Commit d7d0002d (#340) 'Harmonize app-side truthy env parsers on 1/true/yes/on' is titled and scoped as an env-parser change (src/server/config.ts, probe.ts, main/utils.ts + tests). The diff ALSO adds an undisclosed 57-line agent session transcript: .pi/sessions/2026-06-12T09-08-20-735Z_019ebb16-e67f-7a77-ba58-2dfff553a845.jsonl . This file is a leaked pi run log (full prompt + thinking + tool calls), unrelated to the stated work and unmentioned in the subject/body. No gate caught the inclusion and the title hid it. Evidence: SHA d7d0002d (#340); file .pi/sessions/2026-06-12T09-08-20-735Z_019ebb16-e67f-7a77-ba58-2dfff553a845.jsonl (57 lines added). Article I requires the diff to match the title; an unrelated artifact rode in silently. No open seed covers this (sd search '.pi/sessions' / 'session log' returned only unrelated closed seeds).","labels":["gatewatch"]} +{"id":"warren-4c8d","title":"gatewatch: PR #340 commits stray .pi/sessions agent transcript not named in its title","status":"closed","type":"task","priority":2,"createdAt":"2026-06-13T10:11:52.904Z","updatedAt":"2026-06-16T03:08:54.916Z","description":"Article I (Merges are truthful): a PR's title describes its diff. Commit d7d0002d (#340) 'Harmonize app-side truthy env parsers on 1/true/yes/on' is titled and scoped as an env-parser change (src/server/config.ts, probe.ts, main/utils.ts + tests). The diff ALSO adds an undisclosed 57-line agent session transcript: .pi/sessions/2026-06-12T09-08-20-735Z_019ebb16-e67f-7a77-ba58-2dfff553a845.jsonl . This file is a leaked pi run log (full prompt + thinking + tool calls), unrelated to the stated work and unmentioned in the subject/body. No gate caught the inclusion and the title hid it. Evidence: SHA d7d0002d (#340); file .pi/sessions/2026-06-12T09-08-20-735Z_019ebb16-e67f-7a77-ba58-2dfff553a845.jsonl (57 lines added). Article I requires the diff to match the title; an unrelated artifact rode in silently. No open seed covers this (sd search '.pi/sessions' / 'session log' returned only unrelated closed seeds).","labels":["gatewatch"],"closedAt":"2026-06-16T03:08:54.916Z"} {"id":"warren-400d","title":"ratchetwatch tightening: 2026-06-13","status":"closed","type":"task","priority":3,"createdAt":"2026-06-13T10:42:51.801Z","updatedAt":"2026-06-13T18:19:10.128Z","description":"ratchetwatch patrol 2026-06-13. Measured ratchet slack per docs/CONSTITUTION.md Article II.\n\nMeasurement table (floor / actual / slack / action):\n- Coverage functions: floor 88.60% / actual 88.87% / slack 0.27pt / none (< 0.75pt). NOTE: env had zod uninstalled, faking 87.49% — fixed with bun install before measuring; real actuals above.\n- Coverage lines: floor 91.54% / actual 91.83% / slack 0.29pt / none (< 0.75pt).\n- File-size grandfather list: 24 entries, none now under the global 500-line limit, so no removals. Minor sub-budget slack (1-6 lines) on client.ts(565/569), coordinator.completion.test.ts(612/613), main/index.ts(546/548), projects.settings.test.ts(679/685), server.test.ts(531/536) — not in scope for removal (still > 500).\n- Decomposition target: src/server/handlers/projects.settings.test.ts = 679 lines (179 over), furthest-over file not covered by an open seed (warren-c65d covers the four 2026-06-06 birth files; warren-8e04 already decomposed plots.list.test.ts). One plan step adds the decomposition.\n- Bundle creep: gzip js 297562 -> 304567 over trailing 7d = +7005 B (~6.8KB); gzip css +93 B. Under the ~20KB threshold and tied to visible UI features (#272/#273/#276/#282/#283/#284/#290/#292/#316). No action.\n- Debt-marker allowlist: empty. Tight.\n- Grandfather-at-birth (last 24h): none. Only file-size budget change in window (84e339fe / #345) REMOVED plots.list.test.ts; no additions.\n\nPrior patrol (warren-1339, 2026-06-12) plan steps both merged: coverage floor raise (#344) and plots.list.test.ts decomposition (#345).\n\nPlan attached. No release step (Article III).","labels":["audit","ratchetwatch"],"plan_id":"pl-47c0","blockedBy":["warren-6d84"],"closedAt":"2026-06-13T18:19:10.128Z","closeReason":"Ratchetwatch anchor complete: plan pl-47c0 status=done, both children closed (projects.settings.test.ts split #353); sole blocker warren-6d84 closed."} {"id":"warren-a715","title":"Split src/server/handlers/projects.settings.test.ts into sibling files along its four describe seams. Keep the GET /projects/:id/warren-config block (warren-435b) in projects.warren-config.test.ts; move the GET /projects/:id/triggers block (warren-99c3) to projects.triggers.test.ts; move the POST /projects/:id/triggers/:triggerId/run block (warren-99c3) to projects.triggers-run.test.ts; move the GET /projects/:id/seeds/:seedId block (warren-4015) to projects.seed-status.test.ts. Each new file imports shared fixtures from ./projects.test-helpers.ts (no copy-pasted setup). Confirm every resulting file is < 500 lines: `for f in src/server/handlers/projects.warren-config.test.ts src/server/handlers/projects.triggers.test.ts src/server/handlers/projects.triggers-run.test.ts src/server/handlers/projects.seed-status.test.ts; do wc -l \"$f\"; done` — each < 500. Verify same test count green: `bun test src/server/handlers/projects.warren-config.test.ts src/server/handlers/projects.triggers.test.ts src/server/handlers/projects.triggers-run.test.ts src/server/handlers/projects.seed-status.test.ts` passes with the same total number of tests (21) as the original file ran.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-47c0.\n\nParent seed: warren-400d — ratchetwatch tightening: 2026-06-13\nPlan template: refactor\nPlan approach: Split src/server/handlers/projects.settings.test.ts along its four existing top-level describe seams into sibling files under src/server/handlers/, each importing the shared fixtures from the existing ./projects.test-helpers.ts (depsFor,…\n\nRun `sd plan show pl-47c0` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-13T10:43:28.052Z","updatedAt":"2026-06-13T10:50:23.603Z","labels":["ratchetwatch"],"plan_id":"pl-47c0","blocks":["warren-6d84","warren-400d"],"closedAt":"2026-06-13T10:50:23.603Z"} {"id":"warren-6d84","title":"Remove the \"src/server/handlers/projects.settings.test.ts\": 685 entry from scripts/file-size-budgets.json (delete that single line). Do NOT add budget entries for the new sibling files — they default-pass under the 500-line threshold. Per Constitution Article VI, before declaring done run a repo-wide search for the old path across ALL file types — `rg -n \"projects.settings.test\" --hidden -g '!node_modules'` plus an explicit sweep of Dockerfile, .github/workflows/*.yml, supervisor/config strings, and docs/ — and fix any reference (file moves have broken production here before; encode the check, do not assume it). Verify: `bun run check:file-sizes` exits 0 AND `bun test src/server/handlers/` is green.","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-47c0.\n\nParent seed: warren-400d — ratchetwatch tightening: 2026-06-13\nPlan template: refactor\nPlan approach: Split src/server/handlers/projects.settings.test.ts along its four existing top-level describe seams into sibling files under src/server/handlers/, each importing the shared fixtures from the existing ./projects.test-helpers.ts (depsFor,…\n\nRun `sd plan show pl-47c0` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-13T10:43:28.052Z","updatedAt":"2026-06-13T10:50:23.603Z","labels":["ratchetwatch"],"plan_id":"pl-47c0","blocks":["warren-400d"],"closedAt":"2026-06-13T10:50:12.755Z"} @@ -725,7 +725,7 @@ {"id":"warren-faab","title":"Cleanup batch → 0.9.1: logging hardening (pl-f700) + workspace chat fixes + leaked transcript removal + version bump","status":"open","type":"epic","priority":1,"createdAt":"2026-06-14T05:53:53.355Z","updatedAt":"2026-06-16T03:03:49.017Z","description":"Umbrella seed for Plot plot-b11c5999 (\"Workspaces Testing\"). Low-risk cleanup batch capped by a 0.9.1 patch bump. Logging/traceability hardening is the already-approved plan pl-f700 (6 seeds: warren-c686 → warren-fc6e → warren-af76 → warren-26c2 → warren-9f06 → warren-b2dd) — adopted as a contiguous sub-sequence, NOT re-authored. This seed's plan covers the net-new tail: workspace chat ordering/dedup fix, workspace chat unbounded-growth fix, leaked .pi/sessions transcript removal (warren-4c8d), and the 0.9.1 version bump. Each seed lands as its own PR, walked serially, gated on the prior PR merging; version bump lands last after every logging + chat + transcript PR merges. All work passes 'bun run check:all'.","plan_id":"pl-2e59","blockedBy":["warren-4c8d","warren-fade"]} {"id":"warren-f4b8","title":"Fix workspace chat ordering + dedup in src/ui/src/components/chat-messages.ts: merge transcript + stream bubbles on a single unified ordering key (chronological across the transcript/stream boundary) instead of concatenating the two seq-sorted groups, and tighten buildChatMessages dedupe so a streamed assistant turn and its persisted transcript copy collapse to one bubble; add regression tests to chat-messages.test.ts","status":"closed","type":"bug","priority":1,"plan_step_index":0,"description":"\nStep 1 of plan pl-2e59.\n\nParent seed: warren-faab — Cleanup batch → 0.9.1: logging hardening (pl-f700) + workspace chat fixes + leaked transcript removal + version bump\nPlan template: feature\nPlan approach: Walk the net-new tail serially — one seed per PR, each gated on the prior PR merging — mirroring the polish-pass convention and the Plot's stated constraint. Order: chat ordering/dedup fix → chat unbounded-growth fix → leaked-transcript…\n\nRun `sd plan show pl-2e59` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-14T05:54:42.639Z","updatedAt":"2026-06-16T02:52:31.503Z","plan_id":"pl-2e59","blocks":["warren-5755","warren-faab"],"closedAt":"2026-06-16T02:52:31.503Z"} {"id":"warren-5755","title":"Fix unbounded /workspaces growth: bound the conversation card's ancestor height in src/ui/src/pages/conversation-detail/conversation-surface.tsx (min-h-[60vh] → a bounded height) so Chat.tsx's existing internal flex-1 min-h-0 overflow-y-auto engages and the transcript scrolls internally instead of growing the page; no new scroll container","status":"closed","type":"bug","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-2e59.\n\nParent seed: warren-faab — Cleanup batch → 0.9.1: logging hardening (pl-f700) + workspace chat fixes + leaked transcript removal + version bump\nPlan template: feature\nPlan approach: Walk the net-new tail serially — one seed per PR, each gated on the prior PR merging — mirroring the polish-pass convention and the Plot's stated constraint. Order: chat ordering/dedup fix → chat unbounded-growth fix → leaked-transcript…\n\nRun `sd plan show pl-2e59` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-14T05:54:42.639Z","updatedAt":"2026-06-16T03:03:49.017Z","plan_id":"pl-2e59","blocks":["warren-4c8d","warren-faab"],"extensions":{"role":"pi","lastRunId":"run_90fqekdeztrt","lastRunAt":"2026-06-16T02:57:44.047Z"},"closedAt":"2026-06-16T03:03:49.017Z"} -{"id":"warren-fade","title":"Bump version to 0.9.1: set package.json \"version\" and src/index.ts VERSION to 0.9.1 in sync (release workflow fails on drift) and add a matching CHANGELOG.md 0.9.1 section summarizing the logging hardening (pl-f700), workspace chat fixes, and leaked-transcript removal; land last, after every pl-f700 logging PR plus the chat + transcript PRs merge","status":"open","type":"task","priority":1,"plan_step_index":3,"description":"\nStep 4 of plan pl-2e59.\n\nParent seed: warren-faab — Cleanup batch → 0.9.1: logging hardening (pl-f700) + workspace chat fixes + leaked transcript removal + version bump\nPlan template: feature\nPlan approach: Walk the net-new tail serially — one seed per PR, each gated on the prior PR merging — mirroring the polish-pass convention and the Plot's stated constraint. Order: chat ordering/dedup fix → chat unbounded-growth fix → leaked-transcript…\n\nRun `sd plan show pl-2e59` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-14T05:54:42.639Z","updatedAt":"2026-06-14T05:54:42.639Z","plan_id":"pl-2e59","blockedBy":["warren-4c8d"],"blocks":["warren-faab"]} +{"id":"warren-fade","title":"Bump version to 0.9.1: set package.json \"version\" and src/index.ts VERSION to 0.9.1 in sync (release workflow fails on drift) and add a matching CHANGELOG.md 0.9.1 section summarizing the logging hardening (pl-f700), workspace chat fixes, and leaked-transcript removal; land last, after every pl-f700 logging PR plus the chat + transcript PRs merge","status":"open","type":"task","priority":1,"plan_step_index":3,"description":"\nStep 4 of plan pl-2e59.\n\nParent seed: warren-faab — Cleanup batch → 0.9.1: logging hardening (pl-f700) + workspace chat fixes + leaked transcript removal + version bump\nPlan template: feature\nPlan approach: Walk the net-new tail serially — one seed per PR, each gated on the prior PR merging — mirroring the polish-pass convention and the Plot's stated constraint. Order: chat ordering/dedup fix → chat unbounded-growth fix → leaked-transcript…\n\nRun `sd plan show pl-2e59` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-14T05:54:42.639Z","updatedAt":"2026-06-16T03:10:33.416Z","plan_id":"pl-2e59","blockedBy":["warren-4c8d"],"blocks":["warren-faab"],"extensions":{"role":"pi","lastRunId":"run_gky38mc6b49z","lastRunAt":"2026-06-16T03:10:33.250Z"}} {"id":"warren-d426","title":"gatewatch: 4 Article IX-protected merges in window lack human sign-off record","status":"open","type":"task","priority":1,"createdAt":"2026-06-14T10:15:36.224Z","updatedAt":"2026-06-14T10:15:36.224Z","description":"Constitution Article IX requires that any merged change to docs/CONSTITUTION.md, the gatewatch/ratchetwatch/tastewatch entries in .canopy/, or audit entries in .warren/triggers.yaml carry EXPLICIT human review, recorded in the seed tracker (the warren-ea20 ratification-record pattern: 'explicitly human-reviewed and human-merged by the operator... This seed is the sign-off evidence gatewatch's Article IX check looks for'). Four PRs merged in the last 36h touch protected paths and NONE has a corresponding ratification/sign-off seed. The auto-merge.yml Article IX gate (intact, untouched in window) would have BLOCKED auto-merge on these, implying a human merge occurred — but with no recorded ratification, gatewatch cannot verify the gate was honest. Per gatewatch mandate item 6, file priority 1.\n\nEVIDENCE (each modifies its own mandate / the constitution):\n- SHA 7d3cf95e (PR #364): docs/CONSTITUTION.md — adds the 'Audit Warden boundary' section (ingestion rule, digest cadence, meta-Plot, autonomy-promotion constraints). Closes warren-05ef (a WORK seed, not a sign-off record).\n- SHA e2d88409 (PR #362): .warren/triggers.yaml — adds the 'warden-digest' cron audit entry (0 5 * * 0). The constitution explicitly names warden-digest as Article IX-protected. Closes warren-4240 (work seed).\n- SHA f8ead2ff (PR #361): .canopy/prompts.jsonl — bumps gatewatch (v2), ratchetwatch (v2), tastewatch (v3) auditor system prompts to add warden-delivery instructions; ALSO edits the three audit prompt entries in .warren/triggers.yaml. This is the audit population editing its own running mandate (including this very gatewatch prompt). Work seed warren-7f62, not a ratification record.\n- SHA 5f41fef5 (PR #338): .canopy/prompts.jsonl — repins the tastewatch agent model claude-fable-5 -> claude-opus-4-8 (tastewatch entry v1 -> v2). Modifies a protected auditor .canopy entry. No ratification record. (Same PR also adds a biome.json formatter-exempt override carrying tracker pl-cf2a — Article II satisfied there; the Article IX gap is the .canopy auditor change.)\n\nWHAT ARTICLE IX REQUIRES: a recorded human sign-off (warren-ea20-style) per protected-path merge, OR revert. The gate forcing human-merge is necessary but not sufficient — the constitution treats the recorded ratification seed as the audit evidence.\n\nREMEDIATION IS NON-MECHANICAL (no plan attached): the fix is a human decision — file a ratification record for each PR (#364, #362, #361, #338) attesting the operator reviewed and merged it, or revert. A mechanical plan-run cannot self-grant this, and any plan touching these protected paths would itself re-trigger Article IX. Routed to the warden for human triage.\n\nDedupe: not covered by warren-d5e5 (PR #270), warren-4c8d (PR #340), or warren-ea20 (PR #337 only). warden delivery: undeliverable this patrol (WARREN_API_TOKEN unset -> /conversations 401); seed is the durable record.","labels":["audit","gatewatch"]} {"id":"warren-60ee","title":"ratchetwatch tightening: 2026-06-14","status":"open","type":"task","priority":3,"createdAt":"2026-06-14T10:45:24.898Z","updatedAt":"2026-06-14T10:46:18.235Z","description":"Mechanical ratchet tightening for the 2026-06-14 patrol (Constitution Article II — ratchets only tighten).\n\nMeasurements (clean env; node_modules repaired via bun install --frozen-lockfile):\n- Coverage: functions 88.90% vs floor 88.60% (slack 0.30pt); lines 91.65% vs floor 91.54% (slack 0.11pt). Both < 0.75pt → no floor raise this patrol.\n- File-size: no grandfathered entry has dropped below the 500-line global limit (smallest = src/plots/aggregate.ts at 506), so no satisfied entries to remove.\n- Bundle: 7-day net gzip-js -221 B (re-baseline-down in #384); raises sum ~1.9 KB << 20 KB → no finding.\n- Debt allowlist: empty → no finding.\n\nThe single mechanical tightening this patrol is the one-file-per-patrol grandfather decomposition: src/runs/pr.ts (659 lines, furthest over the 500 limit, not covered by any open seed). See the attached refactor plan. Per Article III no release step is included — this hygiene batches into the next real release.","labels":["audit","ratchetwatch"],"plan_id":"pl-88bb","blockedBy":["warren-db9a","warren-70d7"]} {"id":"warren-889a","title":"Grandfather-at-birth: src/runs/stream/bridge.test.ts pushed to 521 lines and exempted in be18ba73 (within 24h)","status":"open","type":"task","priority":3,"createdAt":"2026-06-14T10:45:36.305Z","updatedAt":"2026-06-14T10:45:36.305Z","description":"Constitution Article II finding (ratchets only tighten / nothing grandfathered at birth).\n\nEvidence (Article VIII):\n- File: src/runs/stream/bridge.test.ts — current 521 lines (limit 500).\n- Budget entry \"src/runs/stream/bridge.test.ts\": 521 ADDED in commit be18ba73e20fd4f3beee5cdb7e0563ef6b90cb6a (Jaymin West, 2026-06-13 11:51:08 -0700 = 18:51 UTC; tracker warren-df71, 'feat(runs): keep conversation runs alive...'), i.e. within the trailing 24h of this 2026-06-14 10:42 UTC patrol.\n- The file pre-existed (created 2026-05-27 in 22d16f5d) and was previously UNDER budget; warren-df71 grew it past 500 and added a fresh grandfather exception in the same diff rather than keeping the test under the limit (Article II: 'a new file written over the size limit is decomposed before merge, not exempted at write time' — same spirit applies to pushing a compliant file over the line).\n\nSeverity is low: only 21 lines over. Remedy is a small split/trim of bridge.test.ts back under 500 and removal of its budget entry — NOT planned by ratchetwatch this patrol because the one-decomposition-per-patrol slot went to the furthest-over file (src/runs/pr.ts, 659). Filed for human/gatewatch attention.\n\nDedupe: no existing seed matches 'bridge.test' or 'df71' (searched). Coordinate with gatewatch on be18ba73/warren-df71 rather than double-filing.","labels":["audit","ratchetwatch"]} @@ -738,3 +738,10 @@ {"id":"warren-fa85","title":"ratchetwatch tightening: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:45:30.233Z","updatedAt":"2026-06-15T10:58:43.131Z","description":"Mechanical ratchet tightening for the 2026-06-15 patrol (Constitution Article II — ratchets only tighten).\n\nMeasurements (clean env; node_modules repaired via `bun install --frozen-lockfile` before measuring — local checkout shipped without zod/@os-eco/burrow-cli, which depresses coverage if not repaired):\n- Coverage (`bun run check:coverage`): functions 88.90% vs floor 88.60% (slack 0.30pt); lines 91.65% vs floor 91.54% (slack 0.11pt). Both < 0.75pt → NO floor raise this patrol.\n- File-size grandfather list: no entry has dropped below the 500-line global limit (smallest = src/plots/aggregate.ts at 506), so no satisfied entries to remove. No file-size-budgets.json change in the last 24h → no grandfather-at-birth finding.\n- Bundle creep: 7-day gzip-js raises sum ~1.7KB (525+569+580 B across #380/#381 Plan/Run/Activity tabs), net NEGATIVE after the #384 re-baseline-down (304059 < 304567 start-of-week). << 20KB → no finding.\n- Debt-marker allowlist: empty → no finding.\n\nThe single mechanical tightening this patrol is the one-file-per-patrol grandfather decomposition: scripts/acceptance/scenarios/20-preview.ts (658 lines). src/runs/pr.ts (659, furthest over) is already covered by open plan pl-88bb (warren-db9a/warren-70d7), so 20-preview.ts is the furthest-over file NOT covered by an open seed. See the attached refactor plan. Per Article III no release step is included — hygiene batches into the next real release.\n\nwarden: undeliverable (WARREN_API_TOKEN unset; conversation 'Audit Warden' could not be authenticated/resolved). Seed/plan is the durable record.","labels":["audit","ratchetwatch"],"plan_id":"pl-ef08"} {"id":"warren-65f6","title":"Create scripts/acceptance/scenarios/20-preview.helpers.ts and move the file-local helper group into it. Move buildPreviewProjectFixture, commitInSource, runGit, ensureProject, waitForRunTerminal, waitForPreviewState, fetchEvents, proxyRequest, loginAndIssueCookie, parseSetCookie, sleep, plus their helper-local types (BuildFixtureInput, BuiltPreviewFixture, ProxyRequestInput, ProxyResponse, LoginInput) and the shared row types they need (ProjectRow, EventRow), out of scripts/acceptance/scenarios/20-preview.ts into the new sibling file, exporting each symbol the scenario body still references. Carry the imports those helpers need (node:crypto/node:fs/promises/node:os/node:path, ../lib/assert.ts, ../lib/http.ts WarrenHttp, ../lib/inproc.ts) into the helpers file; if a private utility is needed by both files keep ONE copy and import it (do NOT duplicate, or jscpd check:dups will flag it). Import the moved symbols back into 20-preview.ts. Keep the `scenario` export, runVariantA, runVariantB, and the header comment in 20-preview.ts unchanged. Mirror the existing precedent scripts/acceptance/scenarios/32-plot-workbench-loop.helpers.ts. Verify: `wc -l scripts/acceptance/scenarios/20-preview.ts` shows < 500 AND `wc -l scripts/acceptance/scenarios/20-preview.helpers.ts` shows < 500 AND `bun run typecheck` is clean (run.ts still resolves the unchanged `scenario as scenario20` import).","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-ef08.\n\nParent seed: warren-fa85 — ratchetwatch tightening: 2026-06-15\nPlan template: refactor\nPlan approach: Mirror the established precedent scripts/acceptance/scenarios/32-plot-workbench-loop.helpers.ts: extract the file-local test-helper group into a sibling `scripts/acceptance/scenarios/20-preview.helpers.ts` and import it back. Move the…\n\nRun `sd plan show pl-ef08` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:46:06.270Z","updatedAt":"2026-06-15T10:53:39.566Z","labels":["ratchetwatch"],"plan_id":"pl-ef08","blocks":["warren-fa85"],"extensions":{"role":"pi","lastRunId":"run_b2q7z3p7131f","lastRunAt":"2026-06-15T10:48:09.609Z"},"closedAt":"2026-06-15T10:53:39.566Z"} {"id":"warren-0e37","title":"Remove the \"scripts/acceptance/scenarios/20-preview.ts\": 658 entry from scripts/file-size-budgets.json (delete that one line). Do NOT add a budget entry for scripts/acceptance/scenarios/20-preview.helpers.ts — it must default-pass under the 500 threshold (confirm `wc -l scripts/acceptance/scenarios/20-preview.helpers.ts` < 500). Per Constitution Article VI, before declaring done run a repo-wide search for any reference to the old single-file assumption and the new path across ALL file types — `rg -n \"20-preview\\\\.ts|20-preview\\\\.helpers|scenarios/20-preview\" --hidden -g '!node_modules'` plus an explicit sweep of scripts/acceptance/run.ts, Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, 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:dups` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves both 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-ef08.\n\nParent seed: warren-fa85 — ratchetwatch tightening: 2026-06-15\nPlan template: refactor\nPlan approach: Mirror the established precedent scripts/acceptance/scenarios/32-plot-workbench-loop.helpers.ts: extract the file-local test-helper group into a sibling `scripts/acceptance/scenarios/20-preview.helpers.ts` and import it back. Move the…\n\nRun `sd plan show pl-ef08` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:46:06.270Z","updatedAt":"2026-06-15T10:58:43.131Z","labels":["ratchetwatch"],"plan_id":"pl-ef08","blocks":["warren-fa85"],"closedAt":"2026-06-15T10:58:43.131Z","closeReason":"Removed the 658-line grandfather entry for scripts/acceptance/scenarios/20-preview.ts from scripts/file-size-budgets.json. Both resulting files default-pass under 500 (20-preview.ts=368, 20-preview.helpers.ts=320). Repo-wide sweep (run.ts, Dockerfile, docker-compose.yml, workflows, src/supervisor, docs) found no stale single-file references; run.ts still resolves scenario20. check:size, check:dups, and full check:all (12/12) all green."} +{"id":"warren-832d","title":"UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)","status":"open","type":"epic","priority":2,"createdAt":"2026-06-16T03:11:27.813Z","updatedAt":"2026-06-16T03:12:35.503Z","description":"Plot plot-fbe17883 'UI Nits'. Goal: eliminate a batch of warren UI papercuts so tables and run-launch flows behave consistently and reduce manual operator steps. Constraint: single shared sortable-table primitive over per-page sort logic. Success criteria: (1) consistent sort affordances across pages; (2) plan_id auto-populated after a planner finishes, mirroring plot_id prefill; (3) bespoke sort logic (Runs SortHeader/toggleSort, Workspace handleSort/sortIndicator) removed in favor of one shared primitive; (4) no unintended horizontal scroll at mobile widths; (5) modals/popups dismissible on mobile.","labels":["ui","papercuts"],"plan_id":"pl-3346","blockedBy":["warren-2728","warren-c869","warren-3c6f","warren-ae9f","warren-4734","warren-6f43"]} +{"id":"warren-2728","title":"Add shared sortable-table primitive: useSortableTable hook + SortableHeader component (server-driven and client-side modes) with unit tests","status":"open","type":"feature","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","tables"],"plan_id":"pl-3346","blocks":["warren-c869","warren-3c6f","warren-832d"]} +{"id":"warren-c869","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","status":"open","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","tables"],"requires_plan":true,"blockedBy":["warren-2728"],"blocks":["warren-832d"]} +{"id":"warren-3c6f","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","status":"open","type":"task","priority":2,"plan_step_index":2,"description":"\nStep 3 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","tables"],"requires_plan":true,"blockedBy":["warren-2728"],"blocks":["warren-832d"]} +{"id":"warren-ae9f","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","status":"open","type":"feature","priority":2,"plan_step_index":3,"description":"\nStep 4 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","plan-runs"],"plan_id":"pl-3346","blocks":["warren-832d"]} +{"id":"warren-4734","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)","status":"open","type":"feature","priority":2,"plan_step_index":4,"description":"\nStep 5 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","mobile"],"plan_id":"pl-3346","blocks":["warren-832d"]} +{"id":"warren-6f43","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","status":"open","type":"feature","priority":2,"plan_step_index":5,"description":"\nStep 6 of plan pl-3346.\n\nParent seed: warren-832d — UI Nits: consistent sortable tables, plan_id auto-populate, mobile readiness (plot-fbe17883)\nPlan template: feature\nPlan 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…\n\nRun `sd plan show pl-3346` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-16T03:12:35.503Z","updatedAt":"2026-06-16T03:12:35.503Z","labels":["ui","mobile"],"plan_id":"pl-3346","blocks":["warren-832d"]} diff --git a/.seeds/plans.jsonl b/.seeds/plans.jsonl index 584f2249..8ef83134 100644 --- a/.seeds/plans.jsonl +++ b/.seeds/plans.jsonl @@ -68,3 +68,4 @@ {"id":"pl-2e59","seed":"warren-faab","template":"feature","status":"approved","revision":1,"sections":{"context":"Plot plot-b11c5999 (\"Workspaces Testing\") finalized a low-risk cleanup batch capped by a 0.9.1 patch bump. Its goal names four deliverable areas: (1) the full logging/traceability hardening set, (2) workspace chat surface fixes — out-of-order turns, duplicated assistant messages, and unbounded page growth, (3) removal of the leaked .pi/sessions agent transcript from PR #340, and (4) the version bump. Area (1) is already an approved, decomposed plan: pl-f700 (parent warren-3679) with six child seeds c686 → fc6e → af76 → 26c2 → 9f06 → b2dd. A seed can only belong to one plan (plan_id is single-valued), so this plan does NOT re-adopt those six — that would re-parent them out of pl-f700 and gut the approved logging plan. Instead pl-f700 stands as the logging sub-sequence under the same Plot, and this plan covers only the net-new tail. The chat ordering/dedup defect lives in src/ui/src/components/chat-messages.ts: buildChatMessages concatenates two seq-sorted groups (transcript first, then stream) instead of merging on a single unified ordering key, so turns render transcript-first-then-stream rather than chronologically, and the (kind, content) dedupe is loose enough that a streamed assistant turn and its persisted copy can both render. The unbounded-growth defect is in src/ui/src/pages/conversation-detail/conversation-surface.tsx: the conversation Card uses min-h-[60vh] with no upper bound, so Chat.tsx's existing internal `flex-1 min-h-0 overflow-y-auto` (Chat.tsx:152/157) never engages and the /workspaces page grows with the transcript. warren-4c8d (gatewatch) documents the exact leaked file from PR #340 and is currently unplanned, so it is adopted here. The version lives in two synced places (package.json + src/index.ts VERSION) plus a CHANGELOG.md section; the release workflow fails on drift.","approach":"Walk the net-new tail serially — one seed per PR, each gated on the prior PR merging — mirroring the polish-pass convention and the Plot's stated constraint. Order: chat ordering/dedup fix → chat unbounded-growth fix → leaked-transcript removal → 0.9.1 version bump (last, capping the batch). The whole Plot batch is gated behind pl-f700: the six logging PRs land first, then this tail, so the 0.9.1 bump is the final PR after every logging + chat + transcript PR merges (the version-bump seed records that ordering since a hard cross-plan block edge to warren-b2dd would mutate a seed this run did not create). Chat fixes are split into two seeds because they touch independent files (the pure merge logic vs. the page layout) and are independently reviewable: the ordering/dedup fix is pure, unit-testable logic with a regression test added to chat-messages.test.ts; the growth fix is a layout-only change that bounds the conversation card's ancestor height to engage the existing overflow-y-auto rather than introducing a new scroll container. Transcript removal is adopted from the existing warren-4c8d rather than re-authored. All seeds pass `bun run check:all` before merge.","alternatives":[{"name":"Re-adopt the six pl-f700 logging seeds into this umbrella plan as a literal contiguous step sub-sequence","rejected_because":"A seed's plan_id is single-valued; adopting c686/fc6e/af76/26c2/9f06/b2dd here would re-parent them off the approved pl-f700, gutting that plan and its review state. The Plot already owns the logging sub-sequence via pl-f700; this plan references it for ordering instead of destroying it."},{"name":"Fix chat ordering and dedup in one seed with the unbounded-growth fix","rejected_because":"They touch different files (pure merge logic in chat-messages.ts vs. layout height in conversation-surface.tsx) and have different review surfaces and test strategies. Splitting keeps each PR small, single-concern, and serially reviewable per the batch convention."},{"name":"Introduce a new fixed-height scroll container for the workspace chat","rejected_because":"Chat.tsx already has a working internal overflow-y-auto; the page grows only because no ancestor bounds its height. Bounding the existing ancestor is the minimal fix and avoids a second competing scroll region."}],"steps":[{"title":"Fix workspace chat ordering + dedup in src/ui/src/components/chat-messages.ts: merge transcript + stream bubbles on a single unified ordering key (chronological across the transcript/stream boundary) instead of concatenating the two seq-sorted groups, and tighten buildChatMessages dedupe so a streamed assistant turn and its persisted transcript copy collapse to one bubble; add regression tests to chat-messages.test.ts","type":"bug","priority":1,"blocks":[2]},{"title":"Fix unbounded /workspaces growth: bound the conversation card's ancestor height in src/ui/src/pages/conversation-detail/conversation-surface.tsx (min-h-[60vh] → a bounded height) so Chat.tsx's existing internal flex-1 min-h-0 overflow-y-auto engages and the transcript scrolls internally instead of growing the page; no new scroll container","type":"bug","priority":2,"blocks":[3]},{"existing_seed":"warren-4c8d","blocks":[4]},{"title":"Bump version to 0.9.1: set package.json \"version\" and src/index.ts VERSION to 0.9.1 in sync (release workflow fails on drift) and add a matching CHANGELOG.md 0.9.1 section summarizing the logging hardening (pl-f700), workspace chat fixes, and leaked-transcript removal; land last, after every pl-f700 logging PR plus the chat + transcript PRs merge","type":"task","priority":1,"blocks":[]}],"risks":["The unified ordering key must be stable when transcript rows and stream events share a seq space or use disjoint seq ranges — verify the merge against a never-started anchoring run (transcript only) and an active run (both present) so neither regresses; the existing chat-messages.test.ts cases must stay green.","Tightening dedupe must not collapse legitimately repeated tool/thinking rows (they intentionally key on event id, not content) — keep that behavior while making user/agent turns collapse across transcript+stream.","Bounding the conversation card height must not clip the input row or the plot-intent column on small viewports; verify both the conversation pane and the sibling intent pane in the lg:grid-cols-2 layout.","Version-bump drift: package.json and src/index.ts must match exactly or the release workflow fails; the CHANGELOG section header must match the X.Y.Z the release job greps for.","Serial gating across two plans (pl-f700 + this one) is advisory, not a hard block edge, since wiring warren-b2dd → step 1 would mutate a seed not created in this run; the version-bump seed and umbrella seed document the ordering so dispatch respects it."],"acceptance":["On the workspace conversation surface, user and agent turns render in correct chronological order across the transcript/stream boundary (no transcript-first-then-stream reordering).","No assistant message is duplicated when a streamed turn and its persisted transcript copy both exist; the buildChatMessages dedupe is covered by a new regression test in chat-messages.test.ts.","The workspace conversation transcript scrolls internally and the /workspaces page no longer grows unbounded, using Chat.tsx's existing overflow-y-auto via a bounded ancestor height (no new scroll container).","The leaked .pi/sessions agent transcript from PR #340 is removed from the repo (warren-4c8d).","VERSION in src/index.ts and \"version\" in package.json are both 0.9.1 and in sync, with a matching CHANGELOG.md 0.9.1 section.","Every seed in this plan passes `bun run check:all` (lint, typecheck, size, debt, dups, coverage, etc.) before merge."]},"children":["warren-f4b8","warren-5755","warren-4c8d","warren-fade"],"createdAt":"2026-06-14T05:54:42.639Z","updatedAt":"2026-06-14T05:54:42.639Z","name":"Cleanup batch → 0.9.1 (net-new tail of pl-f700 logging)","adoptedChildren":["warren-4c8d"]} {"id":"pl-88bb","seed":"warren-60ee","template":"refactor","status":"approved","revision":1,"sections":{"context":"Constitution Article II ratchet tightening (2026-06-14 ratchetwatch patrol). src/runs/pr.ts is 659 lines — the grandfathered file furthest over the 500-line global limit (scripts/file-size-budgets.json: \"src/runs/pr.ts\": 659) and not covered by any open seed. Grandfather entries are silent debt; the one-decomposition-per-patrol slot retires this one so the budget entry can be removed (ratchet only goes down).","behavior_invariant":"Every symbol src/runs/pr.ts exports today keeps the same name, signature, and runtime behavior, importable from the same module path src/runs/pr.ts (re-export from pr.ts if a symbol physically moves to a sibling). Current importers — src/server/main/index.ts, src/server/handlers/plots/attachments.ts, src/plots/sync.ts, src/plots/pr-merger.ts, src/plan-runs/pr-merge.ts, src/runs/pr-annotate.ts, src/runs/index.ts, src/runs/reap/run.ts, src/runs/reap/pr-open.ts, src/runs/reap/types.ts, src/runs/pr-template.ts — compile and pass unchanged. The full src/runs/pr.test.ts suite stays green with the same test count.","approach":"Split along the existing seam: move the PR-merge / URL-parsing group (checkPullRequestMerged, parsePullRequestUrl, parsePullRequestRef, mergePullRequest, isRateLimited, plus their CheckPullRequestMergedInput/CheckPrMergedResult/MergePullRequestInput/MergePullRequestResult types and PR_URL_RE/PR_SHORT_RE regexes — roughly lines 403-659) into a new sibling module src/runs/pr-checks.ts (do NOT reuse the name pr-merge.ts; src/plan-runs/pr-merge.ts already exists). Re-export the moved public symbols from src/runs/pr.ts so the module path is unchanged for every importer. That cut removes ~250 lines, landing pr.ts near ~405 lines — comfortably under 500. Keep openPullRequest, buildPrContent, loadAutoOpenPrConfigFromEnv and friends in pr.ts.","steps":[{"title":"Create src/runs/pr-checks.ts and move the PR-merge/URL-parse group into it. Move checkPullRequestMerged, mergePullRequest, parsePullRequestUrl, parsePullRequestRef, isRateLimited and their associated exported types/regexes (CheckPullRequestMergedInput, CheckPrMergedResult, MergePullRequestInput, MergePullRequestResult, PR_URL_RE, PR_SHORT_RE) out of src/runs/pr.ts into the new src/runs/pr-checks.ts, carrying any private helpers they need (buildHeaders/readJson/readText/truncate may need to be shared — if so, keep one copy and import it, do NOT duplicate, or jscpd check:dups will flag it). Re-export every moved PUBLIC symbol from src/runs/pr.ts (export { ... } from \"./pr-checks.ts\") so the path src/runs/pr.ts still resolves all of them. Verify: `wc -l src/runs/pr.ts` shows < 500 AND `bun run typecheck` is clean AND `bun test src/runs/pr.test.ts` is green with the same test count as before the split.","labels":["ratchetwatch"]},{"title":"Remove the \"src/runs/pr.ts\": 659 entry from scripts/file-size-budgets.json (delete that one line). Do NOT add a budget entry for src/runs/pr-checks.ts — it must default-pass under the 500 threshold (confirm `wc -l src/runs/pr-checks.ts` < 500). Per Constitution Article VI, before declaring done run a repo-wide search for any reference to the old single-file assumption and the new path across ALL file types — `rg -n \"runs/pr\\\\.ts|runs/pr-checks\" --hidden -g '!node_modules'` plus an explicit sweep of Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, 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:dups` exits 0 AND `bun run check:all` is fully green (every gate stays green, the raised-tightness budget still passes against current actuals).","labels":["ratchetwatch"],"blocks":[]}],"acceptance":["src/runs/pr.ts is < 500 lines and its budget entry is gone from scripts/file-size-budgets.json; src/runs/pr-checks.ts is < 500 lines with no budget entry.","All prior importers compile unchanged and `bun run typecheck` is clean — every public symbol is still importable from src/runs/pr.ts.","`bun test src/runs/pr.test.ts` passes with the same test count as before the split (behavior invariant preserved).","Article VI repo-wide old-path/new-path search (rg + Dockerfile/compose/workflow YAML/supervisor strings/docs) shows no stale or broken references.","`bun run check:all` is fully green — no gate regresses and no release step is added (Article III: hygiene batches into the next real release)."]},"children":["warren-db9a","warren-70d7"],"createdAt":"2026-06-14T10:46:18.235Z","updatedAt":"2026-06-14T10:46:18.235Z","name":"Decompose src/runs/pr.ts below the 500-line limit"} {"id":"pl-ef08","seed":"warren-fa85","template":"refactor","status":"done","revision":1,"sections":{"context":"Constitution Article II ratchet tightening (2026-06-15 ratchetwatch patrol). scripts/acceptance/scenarios/20-preview.ts is 658 lines — grandfathered at \"scripts/acceptance/scenarios/20-preview.ts\": 658 in scripts/file-size-budgets.json. src/runs/pr.ts (659, furthest over the 500-line limit) is already covered by open plan pl-88bb (warren-db9a/warren-70d7), so 20-preview.ts is the furthest-over grandfathered file NOT covered by an open seed and takes this patrol's single one-decomposition-per-patrol slot. Retiring it lets the budget entry be removed (ratchet only goes down).","behavior_invariant":"The acceptance scenario keeps the exact same `scenario` export (id 20, both variants A happy-path + B idle-TTL eviction) importable from the unchanged path scripts/acceptance/scenarios/20-preview.ts. scripts/acceptance/run.ts line `import { scenario as scenario20 } from \"./scenarios/20-preview.ts\";` stays byte-identical and resolves. runVariantA/runVariantB behavior is unchanged. Scenario 20 still passes (or skips with its documented non-Linux guard) exactly as before. No other scenario imports these helpers (20-preview-path.ts does NOT import from 20-preview.ts — verified), so the move is file-local.","approach":"Mirror the established precedent scripts/acceptance/scenarios/32-plot-workbench-loop.helpers.ts: extract the file-local test-helper group into a sibling `scripts/acceptance/scenarios/20-preview.helpers.ts` and import it back. Move the contiguous helper block (roughly lines 390-658): buildPreviewProjectFixture, commitInSource, runGit, ensureProject, waitForRunTerminal, waitForPreviewState, fetchEvents, proxyRequest, loginAndIssueCookie, parseSetCookie, sleep, plus their helper-local types BuildFixtureInput, BuiltPreviewFixture, ProxyRequestInput, ProxyResponse, LoginInput. The shared row types used by BOTH the scenario body and the helpers (ProjectRow used by ensureProject, EventRow used by fetchEvents) move to the helpers file and are re-imported into 20-preview.ts (same pattern as RunRow in 32's helpers) — do NOT duplicate a type in both files or jscpd check:dups will flag it. Keep `scenario`, runVariantA, runVariantB, and the file header comment in 20-preview.ts. Removing ~268 lines lands 20-preview.ts near ~390 lines; the new helpers file is ~270 lines — both comfortably under 500. Discovery is import-by-name in run.ts (no glob), so a `.helpers.ts` sibling is never auto-loaded as a scenario.","steps":[{"title":"Create scripts/acceptance/scenarios/20-preview.helpers.ts and move the file-local helper group into it. Move buildPreviewProjectFixture, commitInSource, runGit, ensureProject, waitForRunTerminal, waitForPreviewState, fetchEvents, proxyRequest, loginAndIssueCookie, parseSetCookie, sleep, plus their helper-local types (BuildFixtureInput, BuiltPreviewFixture, ProxyRequestInput, ProxyResponse, LoginInput) and the shared row types they need (ProjectRow, EventRow), out of scripts/acceptance/scenarios/20-preview.ts into the new sibling file, exporting each symbol the scenario body still references. Carry the imports those helpers need (node:crypto/node:fs/promises/node:os/node:path, ../lib/assert.ts, ../lib/http.ts WarrenHttp, ../lib/inproc.ts) into the helpers file; if a private utility is needed by both files keep ONE copy and import it (do NOT duplicate, or jscpd check:dups will flag it). Import the moved symbols back into 20-preview.ts. Keep the `scenario` export, runVariantA, runVariantB, and the header comment in 20-preview.ts unchanged. Mirror the existing precedent scripts/acceptance/scenarios/32-plot-workbench-loop.helpers.ts. Verify: `wc -l scripts/acceptance/scenarios/20-preview.ts` shows < 500 AND `wc -l scripts/acceptance/scenarios/20-preview.helpers.ts` shows < 500 AND `bun run typecheck` is clean (run.ts still resolves the unchanged `scenario as scenario20` import).","labels":["ratchetwatch"]},{"title":"Remove the \"scripts/acceptance/scenarios/20-preview.ts\": 658 entry from scripts/file-size-budgets.json (delete that one line). Do NOT add a budget entry for scripts/acceptance/scenarios/20-preview.helpers.ts — it must default-pass under the 500 threshold (confirm `wc -l scripts/acceptance/scenarios/20-preview.helpers.ts` < 500). Per Constitution Article VI, before declaring done run a repo-wide search for any reference to the old single-file assumption and the new path across ALL file types — `rg -n \"20-preview\\\\.ts|20-preview\\\\.helpers|scenarios/20-preview\" --hidden -g '!node_modules'` plus an explicit sweep of scripts/acceptance/run.ts, Dockerfile, docker-compose.yml, .github/workflows/*.yml, src/supervisor/ spawn/config strings, 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:dups` exits 0 AND `bun run check:all` is fully green (every gate stays green; the removed entry leaves both resulting files default-passing under the 500-line threshold).","labels":["ratchetwatch"],"blocks":[]}],"acceptance":["scripts/acceptance/scenarios/20-preview.ts is < 500 lines and its 658-line budget entry is gone from scripts/file-size-budgets.json; scripts/acceptance/scenarios/20-preview.helpers.ts is < 500 lines with NO budget entry (default-passes under threshold).","The `scenario` export and scripts/acceptance/run.ts `import { scenario as scenario20 } from \"./scenarios/20-preview.ts\"` are unchanged and resolve; `bun run typecheck` is clean.","No other scenario or file references a stale path — the Article VI repo-wide rg sweep (plus Dockerfile/compose/workflow YAML/supervisor strings/docs) shows no broken or stale reference.","`bun run check:size` and `bun run check:dups` exit 0 (no duplicated helper/type across the two files).","`bun run check:all` is fully green — no gate regresses and no release step is added (Article III: hygiene batches into the next real release)."]},"children":["warren-65f6","warren-0e37"],"createdAt":"2026-06-15T10:46:06.270Z","updatedAt":"2026-06-15T10:58:43.131Z","name":"Decompose scripts/acceptance/scenarios/20-preview.ts below the 500-line limit"} +{"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"}