chapterhouse 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/api/route-coverage.test.js +1 -3
  2. package/dist/api/server.js +0 -2
  3. package/dist/api/server.test.js +0 -281
  4. package/dist/config.js +3 -85
  5. package/dist/config.test.js +5 -123
  6. package/dist/copilot/agents.js +25 -13
  7. package/dist/copilot/agents.test.js +10 -11
  8. package/dist/copilot/memory-coordinator.js +12 -227
  9. package/dist/copilot/memory-coordinator.test.js +31 -250
  10. package/dist/copilot/orchestrator.js +8 -66
  11. package/dist/copilot/orchestrator.test.js +9 -467
  12. package/dist/copilot/skills.js +15 -1
  13. package/dist/copilot/system-message.js +9 -15
  14. package/dist/copilot/system-message.test.js +9 -22
  15. package/dist/copilot/tools/index.js +3 -3
  16. package/dist/copilot/tools-deps.js +1 -1
  17. package/dist/copilot/tools.agent.test.js +6 -0
  18. package/dist/copilot/tools.inventory.test.js +1 -14
  19. package/dist/daemon.js +7 -9
  20. package/dist/memory/assets.js +33 -0
  21. package/dist/memory/domains.js +58 -0
  22. package/dist/memory/domains.test.js +47 -0
  23. package/dist/memory/git.js +66 -0
  24. package/dist/memory/git.test.js +32 -0
  25. package/dist/memory/history.js +19 -0
  26. package/dist/memory/hottier.js +32 -0
  27. package/dist/memory/hottier.test.js +33 -0
  28. package/dist/memory/index.js +5 -13
  29. package/dist/memory/instructions.js +17 -0
  30. package/dist/memory/manager.js +84 -0
  31. package/dist/memory/markdown.js +78 -0
  32. package/dist/memory/markdown.test.js +42 -0
  33. package/dist/memory/mutex.js +18 -0
  34. package/dist/memory/path-guard.js +26 -0
  35. package/dist/memory/path-guard.test.js +27 -0
  36. package/dist/memory/paths.js +12 -0
  37. package/dist/memory/reconcile.js +75 -0
  38. package/dist/memory/reconcile.test.js +50 -0
  39. package/dist/memory/scaffold.js +37 -0
  40. package/dist/memory/scaffold.test.js +52 -0
  41. package/dist/memory/tools/commit-wrapper.js +32 -0
  42. package/dist/memory/tools/domains.js +73 -0
  43. package/dist/memory/tools/domains.test.js +66 -0
  44. package/dist/memory/tools/git.js +52 -0
  45. package/dist/memory/tools/index.js +25 -0
  46. package/dist/memory/tools/read.js +101 -0
  47. package/dist/memory/tools/read.test.js +69 -0
  48. package/dist/memory/tools/search.js +103 -0
  49. package/dist/memory/tools/search.test.js +63 -0
  50. package/dist/memory/tools/sessions.js +45 -0
  51. package/dist/memory/tools/sessions.test.js +74 -0
  52. package/dist/memory/tools/shared.js +7 -0
  53. package/dist/memory/tools/write.js +116 -0
  54. package/dist/memory/tools/write.test.js +107 -0
  55. package/dist/memory/walk.js +39 -0
  56. package/dist/store/repositories/sessions.js +40 -0
  57. package/dist/wiki/consolidation.js +3 -31
  58. package/dist/wiki/consolidation.test.js +0 -19
  59. package/dist/wiki/frontmatter.js +18 -6
  60. package/dist/wiki/frontmatter.test.js +40 -0
  61. package/package.json +1 -1
  62. package/skills/system/evolve/SKILL.md +131 -0
  63. package/skills/system/foresight/SKILL.md +116 -0
  64. package/skills/system/history/SKILL.md +58 -0
  65. package/skills/system/housekeeping/SKILL.md +185 -0
  66. package/skills/system/reflect/SKILL.md +214 -0
  67. package/skills/system/scenario/SKILL.md +198 -0
  68. package/skills/system/setup/SKILL.md +113 -0
  69. package/web/dist/assets/{WikiEdit-CGRxNazp.js → WikiEdit-BTsiBfbC.js} +2 -2
  70. package/web/dist/assets/{WikiEdit-CGRxNazp.js.map → WikiEdit-BTsiBfbC.js.map} +1 -1
  71. package/web/dist/assets/{WikiGraph-eVWNhZS3.js → WikiGraph-COOZbUeH.js} +2 -2
  72. package/web/dist/assets/{WikiGraph-eVWNhZS3.js.map → WikiGraph-COOZbUeH.js.map} +1 -1
  73. package/web/dist/assets/{index-gAvLNEvJ.js → index-aCcfpaLM.js} +101 -101
  74. package/web/dist/assets/index-aCcfpaLM.js.map +1 -0
  75. package/web/dist/index.html +1 -1
  76. package/dist/api/routes/memory.js +0 -475
  77. package/dist/api/routes/memory.test.js +0 -108
  78. package/dist/copilot/tools/memory.js +0 -678
  79. package/dist/copilot/tools.memory.test.js +0 -590
  80. package/dist/memory/action-items.js +0 -100
  81. package/dist/memory/action-items.test.js +0 -83
  82. package/dist/memory/active-scope.js +0 -78
  83. package/dist/memory/active-scope.test.js +0 -80
  84. package/dist/memory/checkpoint-prompt.js +0 -71
  85. package/dist/memory/checkpoint.js +0 -274
  86. package/dist/memory/checkpoint.test.js +0 -275
  87. package/dist/memory/decisions.js +0 -54
  88. package/dist/memory/decisions.test.js +0 -92
  89. package/dist/memory/entities.js +0 -70
  90. package/dist/memory/entities.test.js +0 -65
  91. package/dist/memory/eot.js +0 -459
  92. package/dist/memory/eot.test.js +0 -949
  93. package/dist/memory/hooks.js +0 -149
  94. package/dist/memory/hooks.test.js +0 -325
  95. package/dist/memory/hot-tier.js +0 -283
  96. package/dist/memory/hot-tier.test.js +0 -275
  97. package/dist/memory/housekeeping-scheduler.js +0 -187
  98. package/dist/memory/housekeeping-scheduler.test.js +0 -236
  99. package/dist/memory/housekeeping.js +0 -497
  100. package/dist/memory/housekeeping.test.js +0 -410
  101. package/dist/memory/inbox.js +0 -83
  102. package/dist/memory/inbox.test.js +0 -178
  103. package/dist/memory/migration.js +0 -244
  104. package/dist/memory/migration.test.js +0 -108
  105. package/dist/memory/observations.js +0 -46
  106. package/dist/memory/observations.test.js +0 -86
  107. package/dist/memory/recall.js +0 -269
  108. package/dist/memory/recall.test.js +0 -265
  109. package/dist/memory/reflect.js +0 -273
  110. package/dist/memory/reflect.test.js +0 -256
  111. package/dist/memory/scope-lock.js +0 -26
  112. package/dist/memory/scope-lock.test.js +0 -118
  113. package/dist/memory/scopes.js +0 -89
  114. package/dist/memory/scopes.test.js +0 -176
  115. package/dist/memory/tiering.js +0 -223
  116. package/dist/memory/tiering.test.js +0 -323
  117. package/dist/memory/types.js +0 -2
  118. package/web/dist/assets/index-gAvLNEvJ.js.map +0 -1
@@ -1,89 +0,0 @@
1
- import { getDb } from "../store/db.js";
2
- function parseKeywords(raw, scopeSlug) {
3
- const parsed = JSON.parse(raw);
4
- if (!Array.isArray(parsed) || parsed.some((value) => typeof value !== "string")) {
5
- throw new Error(`Invalid mem_scopes.keywords payload for scope '${scopeSlug}'.`);
6
- }
7
- return parsed;
8
- }
9
- function serializeKeywords(keywords) {
10
- if (!Array.isArray(keywords) || keywords.some((keyword) => typeof keyword !== "string")) {
11
- throw new Error("Scope keywords must be an array of strings.");
12
- }
13
- return JSON.stringify(keywords);
14
- }
15
- function toScope(row) {
16
- return {
17
- id: row.id,
18
- slug: row.slug,
19
- title: row.title,
20
- description: row.description,
21
- keywords: parseKeywords(row.keywords, row.slug),
22
- active: row.active === 1,
23
- createdAt: row.created_at,
24
- updatedAt: row.updated_at,
25
- };
26
- }
27
- function getScopeRow(idOrSlug) {
28
- const db = getDb();
29
- if (typeof idOrSlug === "number") {
30
- return db.prepare(`
31
- SELECT id, slug, title, description, keywords, active, created_at, updated_at
32
- FROM mem_scopes
33
- WHERE id = ?
34
- `).get(idOrSlug);
35
- }
36
- return db.prepare(`
37
- SELECT id, slug, title, description, keywords, active, created_at, updated_at
38
- FROM mem_scopes
39
- WHERE slug = ?
40
- `).get(idOrSlug);
41
- }
42
- export function listScopes() {
43
- const db = getDb();
44
- const rows = db.prepare(`
45
- SELECT id, slug, title, description, keywords, active, created_at, updated_at
46
- FROM mem_scopes
47
- ORDER BY slug
48
- `).all();
49
- return rows.map(toScope);
50
- }
51
- export function getScope(idOrSlug) {
52
- const row = getScopeRow(idOrSlug);
53
- return row ? toScope(row) : undefined;
54
- }
55
- export function createScope(input) {
56
- const db = getDb();
57
- const result = db.prepare(`
58
- INSERT INTO mem_scopes (slug, title, description, keywords, active, created_at, updated_at)
59
- VALUES (?, ?, ?, ?, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
60
- `).run(input.slug, input.title, input.description, serializeKeywords(input.keywords));
61
- return getScope(Number(result.lastInsertRowid));
62
- }
63
- export function updateScope(id, patch) {
64
- const existing = getScope(id);
65
- if (!existing) {
66
- throw new Error(`Unknown scope id '${id}'.`);
67
- }
68
- const nextTitle = patch.title ?? existing.title;
69
- const nextDescription = patch.description ?? existing.description;
70
- const nextKeywords = patch.keywords ?? existing.keywords;
71
- getDb().prepare(`
72
- UPDATE mem_scopes
73
- SET title = ?, description = ?, keywords = ?, updated_at = CURRENT_TIMESTAMP
74
- WHERE id = ?
75
- `).run(nextTitle, nextDescription, serializeKeywords(nextKeywords), id);
76
- return getScope(id);
77
- }
78
- export function deactivateScope(id) {
79
- const result = getDb().prepare(`
80
- UPDATE mem_scopes
81
- SET active = 0, updated_at = CURRENT_TIMESTAMP
82
- WHERE id = ?
83
- `).run(id);
84
- if (result.changes === 0) {
85
- throw new Error(`Unknown scope id '${id}'.`);
86
- }
87
- return getScope(id);
88
- }
89
- //# sourceMappingURL=scopes.js.map
@@ -1,176 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { mkdirSync, rmSync } from "node:fs";
3
- import { join } from "node:path";
4
- import test from "node:test";
5
- const repoRoot = process.cwd();
6
- const sandboxRoot = join(repoRoot, ".test-work", `memory-scopes-${process.pid}`);
7
- const chapterhouseHome = join(sandboxRoot, ".chapterhouse");
8
- process.env.CHAPTERHOUSE_HOME = sandboxRoot;
9
- async function loadModules() {
10
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
11
- const memoryModule = await import(new URL("./scopes.js", import.meta.url).href);
12
- return { dbModule, memoryModule };
13
- }
14
- function resetSandbox() {
15
- mkdirSync(join(repoRoot, ".test-work"), { recursive: true });
16
- rmSync(sandboxRoot, { recursive: true, force: true });
17
- mkdirSync(chapterhouseHome, { recursive: true });
18
- }
19
- test.beforeEach(async () => {
20
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
21
- dbModule.closeDb();
22
- resetSandbox();
23
- });
24
- test.after(async () => {
25
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
26
- dbModule.closeDb();
27
- rmSync(sandboxRoot, { recursive: true, force: true });
28
- });
29
- test("getDb creates memory tables and indexes", async () => {
30
- const { dbModule } = await loadModules();
31
- try {
32
- const db = dbModule.getDb();
33
- const tables = new Set(db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'mem_%'`).all()
34
- .map((row) => row.name));
35
- const indexes = new Set(db.prepare(`SELECT name FROM sqlite_master WHERE type = 'index' AND name LIKE 'mem_%'`).all()
36
- .map((row) => row.name));
37
- for (const name of [
38
- "mem_scopes",
39
- "mem_entities",
40
- "mem_observations",
41
- "mem_decisions",
42
- "mem_inbox",
43
- ]) {
44
- assert.equal(tables.has(name), true, `expected memory table ${name}`);
45
- }
46
- for (const name of [
47
- "mem_scopes_slug_idx",
48
- "mem_entities_scope_kind_idx",
49
- "mem_observations_scope_idx",
50
- "mem_decisions_scope_idx",
51
- "mem_inbox_status_idx",
52
- ]) {
53
- assert.equal(indexes.has(name), true, `expected memory index ${name}`);
54
- }
55
- }
56
- finally {
57
- dbModule.closeDb();
58
- }
59
- });
60
- test("getDb seeds canonical memory scopes on first run", async () => {
61
- const { dbModule } = await loadModules();
62
- try {
63
- const db = dbModule.getDb();
64
- const rows = db.prepare(`
65
- SELECT slug, title, description, keywords, active
66
- FROM mem_scopes
67
- ORDER BY slug
68
- `).all();
69
- assert.deepEqual(rows, [
70
- {
71
- slug: "chapterhouse",
72
- title: "Chapterhouse",
73
- description: "Chapterhouse codebase, conventions, decisions, gotchas",
74
- keywords: JSON.stringify(["chapterhouse", "this repo", "this project", "the daemon"]),
75
- active: 1,
76
- },
77
- {
78
- slug: "global",
79
- title: "Global",
80
- description: "Cross-cutting facts that apply everywhere",
81
- keywords: JSON.stringify(["everywhere", "general"]),
82
- active: 1,
83
- },
84
- ]);
85
- }
86
- finally {
87
- dbModule.closeDb();
88
- }
89
- });
90
- test("memory schema initialization is idempotent", async () => {
91
- const { dbModule } = await loadModules();
92
- try {
93
- dbModule.getDb();
94
- dbModule.closeDb();
95
- const reopened = await loadModules();
96
- const db = reopened.dbModule.getDb();
97
- const counts = db.prepare(`
98
- SELECT slug, COUNT(*) AS count
99
- FROM mem_scopes
100
- GROUP BY slug
101
- ORDER BY slug
102
- `).all();
103
- assert.deepEqual(counts, [
104
- { slug: "chapterhouse", count: 1 },
105
- { slug: "global", count: 1 },
106
- ]);
107
- reopened.dbModule.closeDb();
108
- }
109
- finally {
110
- dbModule.closeDb();
111
- }
112
- });
113
- test("scope CRUD creates, reads, lists, updates, deactivates, and preserves keywords", async () => {
114
- const { dbModule, memoryModule } = await loadModules();
115
- try {
116
- const created = memoryModule.createScope({
117
- slug: "docs-site",
118
- title: "Docs Site",
119
- description: "Documentation publishing and content workflows",
120
- keywords: ["docs", "content", "publish"],
121
- });
122
- assert.equal(created.slug, "docs-site");
123
- assert.equal(created.title, "Docs Site");
124
- assert.equal(created.description, "Documentation publishing and content workflows");
125
- assert.deepEqual(created.keywords, ["docs", "content", "publish"]);
126
- assert.equal(created.active, true);
127
- assert.deepEqual(memoryModule.getScope("docs-site"), created);
128
- assert.deepEqual(memoryModule.getScope(created.id), created);
129
- const listed = memoryModule.listScopes();
130
- assert.equal(listed.some((scope) => scope.slug === "docs-site"), true);
131
- await new Promise((resolve) => setTimeout(resolve, 1_100));
132
- const updated = memoryModule.updateScope(created.id, {
133
- title: "Docs Platform",
134
- description: "Docs platform and release content",
135
- keywords: ["docs", "release", "guides"],
136
- });
137
- assert.equal(updated.id, created.id);
138
- assert.equal(updated.slug, "docs-site");
139
- assert.equal(updated.title, "Docs Platform");
140
- assert.equal(updated.description, "Docs platform and release content");
141
- assert.deepEqual(updated.keywords, ["docs", "release", "guides"]);
142
- assert.notEqual(updated.updatedAt, created.updatedAt);
143
- const inactive = memoryModule.deactivateScope(created.id);
144
- assert.equal(inactive.active, false);
145
- assert.deepEqual(inactive.keywords, ["docs", "release", "guides"]);
146
- assert.deepEqual(memoryModule.getScope(created.id), inactive);
147
- const storedKeywords = dbModule.getDb()
148
- .prepare(`SELECT keywords FROM mem_scopes WHERE id = ?`)
149
- .get(created.id).keywords;
150
- assert.deepEqual(JSON.parse(storedKeywords), ["docs", "release", "guides"]);
151
- }
152
- finally {
153
- dbModule.closeDb();
154
- }
155
- });
156
- test("createScope enforces unique slugs", async () => {
157
- const { dbModule, memoryModule } = await loadModules();
158
- try {
159
- memoryModule.createScope({
160
- slug: "shared",
161
- title: "Shared",
162
- description: "Shared scope",
163
- keywords: ["shared"],
164
- });
165
- assert.throws(() => memoryModule.createScope({
166
- slug: "shared",
167
- title: "Shared Again",
168
- description: "Duplicate scope",
169
- keywords: ["duplicate"],
170
- }), /UNIQUE|constraint/i);
171
- }
172
- finally {
173
- dbModule.closeDb();
174
- }
175
- });
176
- //# sourceMappingURL=scopes.test.js.map
@@ -1,223 +0,0 @@
1
- import { config } from "../config.js";
2
- import { getDb } from "../store/db.js";
3
- import { childLogger } from "../util/logger.js";
4
- const log = childLogger("memory.tiering");
5
- const TABLES = {
6
- observation: "mem_observations",
7
- decision: "mem_decisions",
8
- entity: "mem_entities",
9
- action_item: "mem_action_items",
10
- };
11
- function dbTable(table) {
12
- return TABLES[table];
13
- }
14
- function passSummary(pass, examined = 0, modified = 0, errors = []) {
15
- return { pass, examined, modified, errors };
16
- }
17
- function isRecent(value, days) {
18
- if (!value) {
19
- return false;
20
- }
21
- const parsed = new Date(value.includes("T") ? value : value.replace(" ", "T"));
22
- if (Number.isNaN(parsed.getTime())) {
23
- return false;
24
- }
25
- return parsed.getTime() >= Date.now() - days * 24 * 60 * 60 * 1000;
26
- }
27
- export function inferTierFromSignals(row) {
28
- if (row.archived_at || row.superseded_by) {
29
- return "cold";
30
- }
31
- if (row.tier === "glacier") {
32
- return "cold";
33
- }
34
- if (row.confidence !== undefined && row.confidence !== null && row.confidence > 0.7) {
35
- const timestamp = row.created_at ?? row.decided_at ?? row.updated_at;
36
- if (isRecent(timestamp, 30)) {
37
- return "hot";
38
- }
39
- }
40
- return row.tier === "hot" || row.tier === "cold" ? row.tier : "warm";
41
- }
42
- function setTier(table, id, tier, reason, manual) {
43
- const result = getDb().prepare(`
44
- UPDATE ${dbTable(table)}
45
- SET tier = ?, tier_reason = ?, tier_pinned_at = ${manual ? "CURRENT_TIMESTAMP" : "tier_pinned_at"}
46
- WHERE id = ?
47
- `).run(tier, reason, id);
48
- if (result.changes === 0) {
49
- throw new Error(`Unknown memory ${table} id '${id}'.`);
50
- }
51
- log.info({ table, id, tier, reason, manual }, "memory.tier.set");
52
- }
53
- export function promoteToHot(table, id, reason) {
54
- setTier(table, id, "hot", reason, true);
55
- }
56
- export function demoteToWarm(table, id, reason) {
57
- setTier(table, id, "warm", reason, true);
58
- }
59
- export function demoteToCold(table, id, reason) {
60
- setTier(table, id, "cold", reason, true);
61
- }
62
- function updateTier(sql, params) {
63
- return getDb().prepare(sql).run(...params).changes;
64
- }
65
- export function tieringPass(scopeId) {
66
- if (!config.memoryTieringEnabled) {
67
- return passSummary("tieringPass");
68
- }
69
- try {
70
- const db = getDb();
71
- const counts = db.prepare(`
72
- SELECT
73
- (SELECT COUNT(*) FROM mem_observations WHERE scope_id = ?) AS observations,
74
- (SELECT COUNT(*) FROM mem_decisions WHERE scope_id = ?) AS decisions,
75
- (SELECT COUNT(*) FROM mem_entities WHERE scope_id = ?) AS entities,
76
- (SELECT COUNT(*) FROM mem_action_items WHERE scope_id = ?) AS action_items
77
- `).get(scopeId, scopeId, scopeId, scopeId);
78
- let modified = 0;
79
- const tx = db.transaction(() => {
80
- modified += updateTier(`
81
- UPDATE mem_observations
82
- SET tier = 'cold', tier_reason = 'archived or superseded'
83
- WHERE scope_id = ?
84
- AND tier != 'cold'
85
- AND tier_pinned_at IS NULL
86
- AND (archived_at IS NOT NULL OR superseded_by IS NOT NULL)
87
- `, [scopeId]);
88
- modified += updateTier(`
89
- UPDATE mem_decisions
90
- SET tier = 'cold', tier_reason = 'archived or superseded'
91
- WHERE scope_id = ?
92
- AND tier != 'cold'
93
- AND tier_pinned_at IS NULL
94
- AND (archived_at IS NOT NULL OR superseded_by IS NOT NULL)
95
- `, [scopeId]);
96
- modified += updateTier(`
97
- UPDATE mem_observations
98
- SET tier = 'hot', tier_reason = 'referenced by recent entity decision'
99
- WHERE scope_id = ?
100
- AND tier != 'hot'
101
- AND tier_pinned_at IS NULL
102
- AND archived_at IS NULL
103
- AND superseded_by IS NULL
104
- AND entity_id IS NOT NULL
105
- AND EXISTS (
106
- SELECT 1
107
- FROM mem_decisions d
108
- WHERE d.scope_id = mem_observations.scope_id
109
- AND d.entity_id = mem_observations.entity_id
110
- AND d.archived_at IS NULL
111
- AND d.superseded_by IS NULL
112
- AND datetime(d.decided_at) >= datetime('now', '-7 days')
113
- )
114
- `, [scopeId]);
115
- modified += updateTier(`
116
- UPDATE mem_decisions
117
- SET tier = 'hot', tier_reason = 'recent decision restatement'
118
- WHERE scope_id = ?
119
- AND tier != 'hot'
120
- AND tier_pinned_at IS NULL
121
- AND archived_at IS NULL
122
- AND (
123
- datetime(decided_at) >= datetime('now', '-7 days')
124
- OR EXISTS (
125
- SELECT 1
126
- FROM mem_decisions old
127
- WHERE old.superseded_by = mem_decisions.id
128
- AND datetime(mem_decisions.decided_at) >= datetime('now', '-7 days')
129
- )
130
- )
131
- `, [scopeId]);
132
- modified += updateTier(`
133
- UPDATE mem_entities
134
- SET tier = 'hot', tier_reason = 'referenced by three recent observations'
135
- WHERE scope_id = ?
136
- AND tier != 'hot'
137
- AND tier_pinned_at IS NULL
138
- AND (
139
- SELECT COUNT(*)
140
- FROM mem_observations o
141
- WHERE o.entity_id = mem_entities.id
142
- AND o.archived_at IS NULL
143
- AND o.superseded_by IS NULL
144
- AND datetime(o.created_at) >= datetime('now', '-7 days')
145
- ) >= 3
146
- `, [scopeId]);
147
- modified += updateTier(`
148
- UPDATE mem_observations
149
- SET tier = 'warm', tier_reason = 'hot age threshold without recall'
150
- WHERE scope_id = ?
151
- AND tier = 'hot'
152
- AND tier_pinned_at IS NULL
153
- AND archived_at IS NULL
154
- AND superseded_by IS NULL
155
- AND last_recalled_at IS NULL
156
- AND datetime(created_at) < datetime('now', ?)
157
- `, [scopeId, `-${config.memoryHotAgeDays} days`]);
158
- modified += updateTier(`
159
- UPDATE mem_decisions
160
- SET tier = 'warm', tier_reason = 'hot age threshold without recall'
161
- WHERE scope_id = ?
162
- AND tier = 'hot'
163
- AND tier_pinned_at IS NULL
164
- AND archived_at IS NULL
165
- AND superseded_by IS NULL
166
- AND last_recalled_at IS NULL
167
- AND datetime(decided_at) < datetime('now', ?)
168
- `, [scopeId, `-${config.memoryHotAgeDays} days`]);
169
- modified += updateTier(`
170
- UPDATE mem_action_items
171
- SET tier = 'cold', tier_reason = 'resolved action item'
172
- WHERE scope_id = ?
173
- AND tier != 'cold'
174
- AND tier_pinned_at IS NULL
175
- AND status IN ('done', 'dropped')
176
- `, [scopeId]);
177
- modified += updateTier(`
178
- UPDATE mem_action_items
179
- SET tier = 'hot', tier_reason = 'open action item due soon'
180
- WHERE scope_id = ?
181
- AND tier != 'hot'
182
- AND tier_pinned_at IS NULL
183
- AND status = 'open'
184
- AND due_at IS NOT NULL
185
- AND datetime(due_at) <= datetime('now', '+7 days')
186
- `, [scopeId]);
187
- modified += updateTier(`
188
- UPDATE mem_action_items
189
- SET tier = 'warm', tier_reason = 'hot age threshold without recall'
190
- WHERE scope_id = ?
191
- AND tier = 'hot'
192
- AND tier_pinned_at IS NULL
193
- AND status = 'open'
194
- AND last_recalled_at IS NULL
195
- AND datetime(created_at) < datetime('now', ?)
196
- `, [scopeId, `-${config.memoryHotAgeDays} days`]);
197
- modified += updateTier(`
198
- UPDATE mem_observations
199
- SET tier = 'cold', tier_reason = 'stale low confidence'
200
- WHERE scope_id = ?
201
- AND tier = 'warm'
202
- AND tier_pinned_at IS NULL
203
- AND confidence < 0.3
204
- AND datetime(created_at) < datetime('now', '-60 days')
205
- `, [scopeId]);
206
- modified += updateTier(`
207
- UPDATE mem_entities
208
- SET tier = 'cold', tier_reason = 'stale low confidence'
209
- WHERE scope_id = ?
210
- AND tier = 'warm'
211
- AND tier_pinned_at IS NULL
212
- AND confidence < 0.3
213
- AND datetime(updated_at) < datetime('now', '-60 days')
214
- `, [scopeId]);
215
- });
216
- tx();
217
- return passSummary("tieringPass", counts.observations + counts.decisions + counts.entities + counts.action_items, modified);
218
- }
219
- catch (error) {
220
- return passSummary("tieringPass", 0, 0, [error instanceof Error ? error.message : String(error)]);
221
- }
222
- }
223
- //# sourceMappingURL=tiering.js.map