feat(FN-1146): add configurable AI session cleanup lifecycle

- Add aiSessionTtlMs and aiSessionCleanupIntervalMs project settings with defaults and bounds for cleanup scheduling
- Extend AiSessionStore cleanup to expire stale in-progress sessions, emit deletion events, and support start/stop scheduled cleanup loops
- Wire server startup/shutdown to load cleanup settings and manage the scheduled ai_sessions sweep lifecycle
- Align planning, subtask breakdown, and mission interview in-memory session retention to a 7-day TTL with shared deletion-driven cleanup
- Update schema/tests/docs for migration v15 ai_sessions indexing and end-to-end cleanup/TTL behavior stability
This commit is contained in:
gsxdsm
2026-04-08 06:44:09 -07:00
parent e3acec2019
commit 5f4bd9c4d2
12 changed files with 506 additions and 144 deletions

View File

@@ -96,7 +96,7 @@ describe("Database", () => {
});
it("seeds schema version", () => {
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
});
it("seeds lastModified", () => {
@@ -119,7 +119,7 @@ describe("Database", () => {
it("is idempotent - calling init() twice does not fail", () => {
expect(() => db.init()).not.toThrow();
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
});
it("does not overwrite existing config on re-init", () => {
@@ -726,7 +726,7 @@ describe("schema migrations", () => {
db.init();
// Verify version bumped to 5 (includes v1→v2, v2→v3, v3→v4, and v4→v5 migrations)
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
// Verify new columns exist and existing data is intact
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
@@ -751,16 +751,16 @@ describe("schema migrations", () => {
const db = new Database(kbDir);
db.init();
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
// Re-init should not fail
db.init();
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
db.close();
});
it("applies migration 14 by creating agentRatings table and indexes", () => {
it("applies migration 14+15 by creating agentRatings and ai_sessions indexes", () => {
tmpDir = makeTmpDir();
const kbDir = join(tmpDir, ".fusion");
@@ -771,7 +771,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = 'agentRatings'").all() as Array<{ name: string }>;
expect(tables).toEqual([{ name: "agentRatings" }]);
@@ -874,7 +874,7 @@ describe("schema migrations", () => {
db.init();
// Verify version bumped to 5
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
// Verify new columns exist and existing data is intact
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
@@ -1084,7 +1084,7 @@ describe("createDatabase factory", () => {
const db = createDatabase(kbDir);
db.init();
expect(db.getSchemaVersion()).toBe(14);
expect(db.getSchemaVersion()).toBe(15);
expect(db.getLastModified()).toBeGreaterThan(0);
db.close();