Phase 14: split kept-window filter from registry gate — defer planning stage
filterSkillsNeedingReinjectByKept tracks absent skills without registeredNames; immediate path keeps the combined filter. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+17
-7
@@ -56,17 +56,27 @@ export function skillsPresentInKeptWindow(
|
|||||||
return present;
|
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>,
|
||||||
|
): 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). */
|
/** Tracked skills missing from kept window but still registered (SPEC §5.2, §6.4). */
|
||||||
export function filterSkillsNeedingReinject(
|
export function filterSkillsNeedingReinject(
|
||||||
tracked: readonly TrackedSkill[],
|
tracked: readonly TrackedSkill[],
|
||||||
keptPresent: ReadonlySet<string>,
|
keptPresent: ReadonlySet<string>,
|
||||||
registeredNames: ReadonlySet<string>,
|
registeredNames: ReadonlySet<string>,
|
||||||
): string[] {
|
): string[] {
|
||||||
const needing: string[] = [];
|
return filterSkillsNeedingReinjectByKept(tracked, keptPresent).filter((name) =>
|
||||||
for (const skill of tracked) {
|
registeredNames.has(name),
|
||||||
if (registeredNames.has(skill.name) && !keptPresent.has(skill.name)) {
|
);
|
||||||
needing.push(skill.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return needing;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { SessionEntry } from "@earendil-works/pi-coding-agent";
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
filterSkillsNeedingReinject,
|
filterSkillsNeedingReinject,
|
||||||
|
filterSkillsNeedingReinjectByKept,
|
||||||
getKeptEntries,
|
getKeptEntries,
|
||||||
skillsPresentInKeptWindow,
|
skillsPresentInKeptWindow,
|
||||||
} from "../src/kept";
|
} 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<string>();
|
||||||
|
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", () => {
|
describe("filterSkillsNeedingReinject", () => {
|
||||||
it("returns registered tracked skills absent from kept window", () => {
|
it("returns registered tracked skills absent from kept window", () => {
|
||||||
const keptPresent = new Set(["alpha"]);
|
const keptPresent = new Set(["alpha"]);
|
||||||
|
|||||||
Reference in New Issue
Block a user