The plan recorded false history after a re-plan and the activity panel showed fabricated, churning timestamps. Two bugs compounding on one event stream. Plan drift (P0.1): - proposePlan seq is now 1..N per generation; (session,generation,seq) is the addressing key. The model's 1-based update_plan_step calls always map to the CURRENT plan after a re-plan, instead of resurrecting a superseded `replaced` row as done while the live work went unrecorded. - updatePlanStep resolves against MAX(generation); a stale/out-of-range seq returns errPlanStepNotFound (never touches a superseded generation). - getPlanSteps returns only the current generation by default; ?all=true keeps the audit/eval view (plan_generations assertion). - completeTask auto-close scopes to the current gen, stamps started_at, and emits one plan.step.finished per closed step so the panel converges instead of freezing on "running" after completion (P1.1). - propose_plan result enumerates step seqs; writeback detector matches "write back"/"writeback"/"upsert_knowledge" so a natural-language final step isn't doubled (P1.2). - migration 029 renumbers existing seq per generation + unique index. Activity panel (P0.2 / P1.1, web): - computeActivityLog uses the real message created_at for tool calls; live entries fall back to wall-clock frozen on first sight, killing the 3s poll churn. Steps use real started_at. - dropped plan-step events warn + count instead of a silent no-op. Tests: TestProposePlan updated; + generation-relative-seq and auto-close event-emission regression tests; + web activity purity/timestamp tests. VERSION: 0.14.0 -> 0.14.1
34 lines
1.5 KiB
SQL
34 lines
1.5 KiB
SQL
-- 029_plan_generation_relative_seq.up.sql
|
|
-- Make plan-step seq generation-relative: 1..N within each
|
|
-- (session_id, generation). Before this, seq was globally increasing across
|
|
-- generations (gen1: 1..6, gen2: 7..12), so the model's 1-based
|
|
-- update_plan_step calls — which the prompt and schema explicitly tell it to
|
|
-- use — landed on superseded gen-1 rows after a re-plan while the live gen-2
|
|
-- work went unrecorded (or, worse, resurrected a `replaced` row as `done`).
|
|
-- The addressing key is now (session_id, generation, seq); updatePlanStep
|
|
-- resolves against MAX(generation), so a 1-based seq always maps to the
|
|
-- CURRENT plan. See plans/2026-07-30-session-review-plan-drift-and-dead-
|
|
-- activity-panel.md P0.1.
|
|
|
|
-- Renumber existing rows so seq resets to 1..N per (session, generation),
|
|
-- preserving each generation's step order.
|
|
WITH ranked AS (
|
|
SELECT id,
|
|
ROW_NUMBER() OVER (
|
|
PARTITION BY session_id, generation
|
|
ORDER BY seq, created_at
|
|
) AS new_seq
|
|
FROM session_plan_steps
|
|
)
|
|
UPDATE session_plan_steps s
|
|
SET seq = ranked.new_seq
|
|
FROM ranked
|
|
WHERE s.id = ranked.id AND s.seq <> ranked.new_seq;
|
|
|
|
-- (session_id, seq) is no longer unique once seq resets per generation; the
|
|
-- store resolves via (session_id, generation, seq). Drop the old composite
|
|
-- index (it now collides on seq) and add the generation-scoped unique index.
|
|
DROP INDEX IF EXISTS idx_plan_steps_session;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_plan_steps_session_gen_seq
|
|
ON session_plan_steps (session_id, generation, seq);
|