diff --git a/src/kept.ts b/src/kept.ts index 6855872..be72a9f 100644 --- a/src/kept.ts +++ b/src/kept.ts @@ -56,17 +56,27 @@ export function skillsPresentInKeptWindow( return present; } +/** Tracked skills absent from kept window — defer planning stage without registry filter (Phase 14 / B-002). */ +export function filterSkillsNeedingReinjectByKept( + tracked: readonly TrackedSkill[], + keptPresent: ReadonlySet, +): string[] { + const needing: string[] = []; + for (const skill of tracked) { + if (!keptPresent.has(skill.name)) { + needing.push(skill.name); + } + } + return needing; +} + /** Tracked skills missing from kept window but still registered (SPEC §5.2, §6.4). */ export function filterSkillsNeedingReinject( tracked: readonly TrackedSkill[], keptPresent: ReadonlySet, registeredNames: ReadonlySet, ): string[] { - const needing: string[] = []; - for (const skill of tracked) { - if (registeredNames.has(skill.name) && !keptPresent.has(skill.name)) { - needing.push(skill.name); - } - } - return needing; + return filterSkillsNeedingReinjectByKept(tracked, keptPresent).filter((name) => + registeredNames.has(name), + ); } diff --git a/test/kept-window.test.ts b/test/kept-window.test.ts index 72633dd..431e05b 100644 --- a/test/kept-window.test.ts +++ b/test/kept-window.test.ts @@ -2,6 +2,7 @@ import type { SessionEntry } from "@earendil-works/pi-coding-agent"; import { describe, expect, it } from "vitest"; import { filterSkillsNeedingReinject, + filterSkillsNeedingReinjectByKept, getKeptEntries, skillsPresentInKeptWindow, } from "../src/kept"; @@ -95,6 +96,23 @@ describe("skillsPresentInKeptWindow", () => { }); }); +describe("filterSkillsNeedingReinjectByKept", () => { + it("returns tracked skills absent from kept window regardless of registration", () => { + const keptPresent = new Set(["alpha"]); + expect(filterSkillsNeedingReinjectByKept(trackedSkills, keptPresent)).toEqual(["beta"]); + }); + + it("preserves tracked order including unregistered names", () => { + const keptPresent = new Set(); + expect(filterSkillsNeedingReinjectByKept(trackedSkills, keptPresent)).toEqual(["alpha", "beta"]); + }); + + it("returns empty when all tracked skills are in kept window", () => { + const keptPresent = new Set(["alpha", "beta"]); + expect(filterSkillsNeedingReinjectByKept(trackedSkills, keptPresent)).toEqual([]); + }); +}); + describe("filterSkillsNeedingReinject", () => { it("returns registered tracked skills absent from kept window", () => { const keptPresent = new Set(["alpha"]);