diff --git a/server/__tests__/lanes-lib.test.js b/server/__tests__/lanes-lib.test.js index 893b599..ca85369 100644 --- a/server/__tests__/lanes-lib.test.js +++ b/server/__tests__/lanes-lib.test.js @@ -86,6 +86,7 @@ describe("pipelines", () => { }); const lanes = require("../lib/lanes"); +const features = require("../lib/lane-features"); describe("lanes lib", () => { it("creates, lists, updates and deletes a lane", () => { @@ -586,6 +587,32 @@ describe("stage detection", () => { assert.equal(lanes.getLane(l.id).detected_stage, "implement"); lanes.deleteLane(l.id); }); + describe("clearLane archives the active feature first", () => { + it("archives the active feature with its final stage before resetting the live row", () => { + const l = lanes.createLane({ title: "t", cwd: "/tmp/wt-archive-active" }); + features.activateFeature(l.id, "one"); + lanes.setStage(l.id, { stage: "review", evidence: "e" }); + + lanes.clearLane(l.id); + + const archived = features.getFeature(l.id, "one"); + assert.notEqual(archived.archived_at, null); + assert.equal(archived.stage, "review"); + const cleared = lanes.getLane(l.id); + assert.equal(cleared.stage, "idle"); + assert.equal(cleared.active_feature_id, null); + lanes.deleteLane(l.id); + }); + + it("is unchanged for a lane that never activated a feature (no archive row created)", () => { + const l = lanes.createLane({ title: "t2", cwd: "/tmp/wt-archive-none" }); + lanes.setStage(l.id, { stage: "review" }); + lanes.clearLane(l.id); + const cleared = lanes.getLane(l.id); + assert.equal(cleared.stage, "idle"); + lanes.deleteLane(l.id); + }); + }); it("a real stage transition clears a stale detection and unblocks a fresh one behind it", () => { const l = lanes.createLane({ cwd: "/tmp/wt-detect-stale-cross-task" }); diff --git a/server/lib/lanes.js b/server/lib/lanes.js index 05218d6..d137760 100644 --- a/server/lib/lanes.js +++ b/server/lib/lanes.js @@ -334,10 +334,16 @@ function recordDetection(id, { nodeId, signal } = {}) { * never be advanced past. */ function clearLane(id) { + // Opt-in: only a lane that has activated a feature has anything to archive. + // Requiring the module here (not at file top) avoids a require cycle — + // lane-features.js itself requires this file for lanesLib.getLane/setStage. + require("./lane-features").archiveActiveFeature(id); + db.prepare( `UPDATE lanes SET stage = 'idle', stage_since = ?, status = 'idle', gate_decision = NULL, ci_status = NULL, needs_action = NULL, stages = '{}', notes = NULL, run_id = NULL, detected_stage = NULL, detected_signal = NULL, detected_at = NULL, + active_feature_id = NULL, updated_at = ? WHERE id = ?` ).run(nowIso(), nowIso(), id); return getLane(id);