fix(lanes): expire stale stage detections, cover raw test runs in ship-feature gates

withDetected() rendered lane.detected_stage forever once written — the TTL in
recordDetection only stops future writes from advancing past a stale floor, it
never clears the row, so a lane gone quiet kept painting amber nodes from
activity that was no longer current. Also add the shared test-runner regex to
the ship-feature pipeline's `gates` node: Stage 1b's independent-test subagent
runs the repo's test command directly, not through `ccam`, and had no
detection fallback if `ccam stage tests` was skipped.
This commit is contained in:
2026-08-24 10:43:43 +07:00
parent 8bcc30fad6
commit d279af85d5
4 changed files with 35 additions and 0 deletions
+20
View File
@@ -901,6 +901,26 @@ describe("stage detection", () => {
}
}
});
it("a stale detection stops rendering as `detected` in pipeline_nodes, even though the DB row still holds it", () => {
const { db } = require("../db");
const l = lanes.createLane({ cwd: "/tmp/wt-detect-stale-render" });
lanes.recordDetection(l.id, { nodeId: "tests" });
const oldTime = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
db.prepare("UPDATE lanes SET detected_at = ? WHERE id = ?").run(oldTime, l.id);
const lane = lanes.getLane(l.id);
// The TTL only gates future writes; the stale row is still there until a
// fresh detection or a real stage transition overwrites it.
assert.equal(lane.detected_stage, "tests");
const nodes = lanes.lanePayload(lane).pipeline_nodes;
assert.ok(
!nodes.some((n) => n.detected),
"a detection older than the TTL must not paint any node amber — it is no longer current information"
);
lanes.deleteLane(l.id);
});
});
describe("the forward-only hold is short enough for one work session", () => {
+4
View File
@@ -521,6 +521,10 @@ test.describe("ship-feature pipeline template", () => {
["implementing", "Write", { file_path: "server/lib/app.js" }],
["gates", "Bash", { command: "ccam lanes hook ci-gate" }],
["gates", "Bash", { command: "ccam lanes sync-base --check feat/foo" }],
// Stage 1b's independent-test subagent runs the repo's raw test command
// directly, not through `ccam` — without this rule that pass has no
// detection fallback if the agent skips `ccam stage tests`.
["gates", "Bash", { command: "npm run test:server" }],
["e2e-feature", "Bash", { command: "ccam lanes up --qc" }],
["e2e-feature", "Bash", { command: "ccam lanes hook e2e" }],
["review", "Skill", { skill: "code-review" }],