chapterhouse 0.13.1 → 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 (116) 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 +13 -10
  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/package.json +1 -1
  60. package/skills/system/evolve/SKILL.md +131 -0
  61. package/skills/system/foresight/SKILL.md +116 -0
  62. package/skills/system/history/SKILL.md +58 -0
  63. package/skills/system/housekeeping/SKILL.md +185 -0
  64. package/skills/system/reflect/SKILL.md +214 -0
  65. package/skills/system/scenario/SKILL.md +198 -0
  66. package/skills/system/setup/SKILL.md +113 -0
  67. package/web/dist/assets/{WikiEdit-CGRxNazp.js → WikiEdit-BTsiBfbC.js} +2 -2
  68. package/web/dist/assets/{WikiEdit-CGRxNazp.js.map → WikiEdit-BTsiBfbC.js.map} +1 -1
  69. package/web/dist/assets/{WikiGraph-eVWNhZS3.js → WikiGraph-COOZbUeH.js} +2 -2
  70. package/web/dist/assets/{WikiGraph-eVWNhZS3.js.map → WikiGraph-COOZbUeH.js.map} +1 -1
  71. package/web/dist/assets/{index-gAvLNEvJ.js → index-aCcfpaLM.js} +101 -101
  72. package/web/dist/assets/index-aCcfpaLM.js.map +1 -0
  73. package/web/dist/index.html +1 -1
  74. package/dist/api/routes/memory.js +0 -475
  75. package/dist/api/routes/memory.test.js +0 -108
  76. package/dist/copilot/tools/memory.js +0 -678
  77. package/dist/copilot/tools.memory.test.js +0 -590
  78. package/dist/memory/action-items.js +0 -100
  79. package/dist/memory/action-items.test.js +0 -83
  80. package/dist/memory/active-scope.js +0 -78
  81. package/dist/memory/active-scope.test.js +0 -80
  82. package/dist/memory/checkpoint-prompt.js +0 -71
  83. package/dist/memory/checkpoint.js +0 -274
  84. package/dist/memory/checkpoint.test.js +0 -275
  85. package/dist/memory/decisions.js +0 -54
  86. package/dist/memory/decisions.test.js +0 -92
  87. package/dist/memory/entities.js +0 -70
  88. package/dist/memory/entities.test.js +0 -65
  89. package/dist/memory/eot.js +0 -459
  90. package/dist/memory/eot.test.js +0 -949
  91. package/dist/memory/hooks.js +0 -149
  92. package/dist/memory/hooks.test.js +0 -325
  93. package/dist/memory/hot-tier.js +0 -283
  94. package/dist/memory/hot-tier.test.js +0 -275
  95. package/dist/memory/housekeeping-scheduler.js +0 -187
  96. package/dist/memory/housekeeping-scheduler.test.js +0 -236
  97. package/dist/memory/housekeeping.js +0 -497
  98. package/dist/memory/housekeeping.test.js +0 -410
  99. package/dist/memory/inbox.js +0 -83
  100. package/dist/memory/inbox.test.js +0 -178
  101. package/dist/memory/migration.js +0 -244
  102. package/dist/memory/migration.test.js +0 -108
  103. package/dist/memory/observations.js +0 -46
  104. package/dist/memory/observations.test.js +0 -86
  105. package/dist/memory/recall.js +0 -269
  106. package/dist/memory/recall.test.js +0 -265
  107. package/dist/memory/reflect.js +0 -273
  108. package/dist/memory/reflect.test.js +0 -256
  109. package/dist/memory/scope-lock.js +0 -26
  110. package/dist/memory/scope-lock.test.js +0 -118
  111. package/dist/memory/scopes.js +0 -89
  112. package/dist/memory/scopes.test.js +0 -176
  113. package/dist/memory/tiering.js +0 -223
  114. package/dist/memory/tiering.test.js +0 -323
  115. package/dist/memory/types.js +0 -2
  116. package/web/dist/assets/index-gAvLNEvJ.js.map +0 -1
@@ -1,323 +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-tiering-${process.pid}`);
7
- const chapterhouseHome = join(sandboxRoot, ".chapterhouse");
8
- const DAY_MS = 24 * 60 * 60 * 1000;
9
- process.env.CHAPTERHOUSE_HOME = sandboxRoot;
10
- process.env.CHAPTERHOUSE_MEMORY_HOT_AGE_DAYS = "30";
11
- process.env.CHAPTERHOUSE_MEMORY_TIERING_ENABLED = "1";
12
- function resetSandbox() {
13
- mkdirSync(join(repoRoot, ".test-work"), { recursive: true });
14
- rmSync(sandboxRoot, { recursive: true, force: true });
15
- mkdirSync(chapterhouseHome, { recursive: true });
16
- }
17
- async function loadModules(cacheBust = `${Date.now()}-${Math.random()}`) {
18
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
19
- const memoryModule = await import(new URL(`./index.js?case=${cacheBust}`, import.meta.url).href);
20
- const tieringModule = await import(new URL(`./tiering.js?case=${cacheBust}`, import.meta.url).href);
21
- return { dbModule, memoryModule, tieringModule };
22
- }
23
- function getFunction(module, name) {
24
- const value = module[name];
25
- assert.equal(typeof value, "function", `expected ${name} to be exported`);
26
- return value;
27
- }
28
- function createTestScope(memoryModule, slug) {
29
- const createScope = getFunction(memoryModule, "createScope");
30
- return createScope({
31
- slug,
32
- title: slug.split("-").map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" "),
33
- description: `${slug} test scope`,
34
- keywords: [slug],
35
- });
36
- }
37
- function isoAt(offsetMs) {
38
- return new Date(Date.now() + offsetMs).toISOString();
39
- }
40
- function sqlAt(offsetMs) {
41
- return isoAt(offsetMs).replace("T", " ").slice(0, 19);
42
- }
43
- test.beforeEach(async () => {
44
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
45
- dbModule.closeDb();
46
- resetSandbox();
47
- });
48
- test.after(async () => {
49
- delete process.env.CHAPTERHOUSE_MEMORY_HOT_AGE_DAYS;
50
- delete process.env.CHAPTERHOUSE_MEMORY_TIERING_ENABLED;
51
- const dbModule = await import(new URL("../store/db.js", import.meta.url).href);
52
- dbModule.closeDb();
53
- rmSync(sandboxRoot, { recursive: true, force: true });
54
- });
55
- test("inferTierFromSignals maps archival, confidence, and 30-day recency boundaries to the expected tier", async () => {
56
- const { tieringModule } = await loadModules("infer-boundaries");
57
- const originalNow = Date.now;
58
- const fixedNow = Date.parse("2026-05-14T15:00:00.000Z");
59
- Date.now = () => fixedNow;
60
- try {
61
- assert.equal(tieringModule.inferTierFromSignals({}), "warm");
62
- assert.equal(tieringModule.inferTierFromSignals({ archived_at: "2026-05-01 12:00:00" }), "cold");
63
- assert.equal(tieringModule.inferTierFromSignals({ superseded_by: 42, tier: "hot" }), "cold");
64
- assert.equal(tieringModule.inferTierFromSignals({ tier: "glacier" }), "cold");
65
- assert.equal(tieringModule.inferTierFromSignals({
66
- confidence: 0.71,
67
- created_at: new Date(fixedNow - 30 * DAY_MS).toISOString(),
68
- }), "hot");
69
- assert.equal(tieringModule.inferTierFromSignals({
70
- confidence: 0.71,
71
- created_at: new Date(fixedNow - 30 * DAY_MS - 1).toISOString(),
72
- }), "warm");
73
- assert.equal(tieringModule.inferTierFromSignals({
74
- confidence: 0.71,
75
- decided_at: new Date(fixedNow - DAY_MS).toISOString(),
76
- }), "hot");
77
- assert.equal(tieringModule.inferTierFromSignals({
78
- confidence: 0.71,
79
- updated_at: new Date(fixedNow - DAY_MS).toISOString(),
80
- }), "hot");
81
- assert.equal(tieringModule.inferTierFromSignals({
82
- confidence: 0.7,
83
- created_at: new Date(fixedNow - DAY_MS).toISOString(),
84
- tier: "hot",
85
- }), "hot");
86
- assert.equal(tieringModule.inferTierFromSignals({
87
- confidence: 0.2,
88
- created_at: new Date(fixedNow - 90 * DAY_MS).toISOString(),
89
- }), "warm");
90
- assert.equal(tieringModule.inferTierFromSignals({ tier: "cold" }), "cold");
91
- }
92
- finally {
93
- Date.now = originalNow;
94
- }
95
- });
96
- test("tieringPass reports empty scopes without changes", async () => {
97
- const { dbModule, memoryModule, tieringModule } = await loadModules("empty-scope");
98
- dbModule.getDb();
99
- const scope = createTestScope(memoryModule, "tiering-empty");
100
- assert.deepEqual(tieringModule.tieringPass(scope.id), {
101
- pass: "tieringPass",
102
- examined: 0,
103
- modified: 0,
104
- errors: [],
105
- });
106
- });
107
- test("tieringPass promotes recent observations, decisions, entities, and due actions while aging stale hot rows", async () => {
108
- const { dbModule, memoryModule, tieringModule } = await loadModules("promotions-and-aging");
109
- const db = dbModule.getDb();
110
- const scope = createTestScope(memoryModule, "tiering-promotions");
111
- const upsertEntity = getFunction(memoryModule, "upsertEntity");
112
- const recordObservation = getFunction(memoryModule, "recordObservation");
113
- const recordDecision = getFunction(memoryModule, "recordDecision");
114
- const recordActionItem = getFunction(memoryModule, "recordActionItem");
115
- const completeActionItem = getFunction(memoryModule, "completeActionItem");
116
- const entity = upsertEntity({
117
- scope_id: scope.id,
118
- kind: "component",
119
- name: "memory-router",
120
- tier: "warm",
121
- confidence: 0.95,
122
- });
123
- const linkedObservation = recordObservation({
124
- scope_id: scope.id,
125
- entity_id: entity.id,
126
- content: "Recent observation that should follow a fresh decision into hot tier.",
127
- source: "test",
128
- tier: "warm",
129
- confidence: 0.9,
130
- });
131
- const supportingObservationTwo = recordObservation({
132
- scope_id: scope.id,
133
- entity_id: entity.id,
134
- content: "Second recent observation keeps the entity active.",
135
- source: "test",
136
- tier: "warm",
137
- confidence: 0.9,
138
- });
139
- const supportingObservationThree = recordObservation({
140
- scope_id: scope.id,
141
- entity_id: entity.id,
142
- content: "Third recent observation pushes the entity over the hot threshold.",
143
- source: "test",
144
- tier: "warm",
145
- confidence: 0.9,
146
- });
147
- const staleObservation = recordObservation({
148
- scope_id: scope.id,
149
- content: "Old hot observation with no recall should cool down.",
150
- source: "test",
151
- tier: "hot",
152
- confidence: 0.8,
153
- });
154
- const boundaryObservation = recordObservation({
155
- scope_id: scope.id,
156
- content: "Hot observation inside the age window should stay hot.",
157
- source: "test",
158
- tier: "hot",
159
- confidence: 0.8,
160
- });
161
- const recentDecision = recordDecision({
162
- scope_id: scope.id,
163
- entity_id: entity.id,
164
- title: "Recent decision keeps related memories hot",
165
- rationale: "Fresh decision activity should promote related observations.",
166
- decided_at: sqlAt(-DAY_MS),
167
- tier: "warm",
168
- });
169
- const staleDecision = recordDecision({
170
- scope_id: scope.id,
171
- title: "Old hot decision without recall cools off",
172
- rationale: "No one has looked at it recently.",
173
- decided_at: sqlAt(-31 * DAY_MS),
174
- tier: "hot",
175
- });
176
- const boundaryDecision = recordDecision({
177
- scope_id: scope.id,
178
- title: "Boundary decision remains hot",
179
- rationale: "Still inside the configured hot age.",
180
- decided_at: sqlAt(-29 * DAY_MS),
181
- tier: "hot",
182
- });
183
- const dueSoonAction = recordActionItem({
184
- scope_id: scope.id,
185
- title: "Due soon action item becomes hot",
186
- due_at: sqlAt(6 * DAY_MS),
187
- source: "test",
188
- tier: "warm",
189
- });
190
- const dueLaterAction = recordActionItem({
191
- scope_id: scope.id,
192
- title: "Far future action item stays warm",
193
- due_at: sqlAt(8 * DAY_MS),
194
- source: "test",
195
- tier: "warm",
196
- });
197
- const staleHotAction = recordActionItem({
198
- scope_id: scope.id,
199
- title: "Old hot action item cools without recall",
200
- source: "test",
201
- tier: "hot",
202
- });
203
- const resolvedAction = recordActionItem({
204
- scope_id: scope.id,
205
- title: "Resolved action item becomes cold",
206
- source: "test",
207
- tier: "warm",
208
- });
209
- completeActionItem(resolvedAction.id, "Shipped");
210
- for (const id of [linkedObservation.id, supportingObservationTwo.id, supportingObservationThree.id]) {
211
- db.prepare(`UPDATE mem_observations SET created_at = ? WHERE id = ?`).run(sqlAt(-2 * DAY_MS), id);
212
- }
213
- db.prepare(`UPDATE mem_observations SET created_at = ?, last_recalled_at = NULL WHERE id = ?`).run(sqlAt(-31 * DAY_MS), staleObservation.id);
214
- db.prepare(`UPDATE mem_observations SET created_at = ?, last_recalled_at = NULL WHERE id = ?`).run(sqlAt(-29 * DAY_MS), boundaryObservation.id);
215
- db.prepare(`UPDATE mem_action_items SET created_at = ?, last_recalled_at = NULL WHERE id = ?`).run(sqlAt(-31 * DAY_MS), staleHotAction.id);
216
- const summary = tieringModule.tieringPass(scope.id);
217
- assert.equal(summary.pass, "tieringPass");
218
- assert.equal(summary.examined, 13);
219
- assert.equal(summary.modified, 10);
220
- assert.deepEqual(summary.errors, []);
221
- for (const id of [linkedObservation.id, supportingObservationTwo.id, supportingObservationThree.id]) {
222
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(id), { tier: "hot", tier_reason: "referenced by recent entity decision" });
223
- }
224
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(linkedObservation.id), { tier: "hot", tier_reason: "referenced by recent entity decision" });
225
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(staleObservation.id), { tier: "warm", tier_reason: "hot age threshold without recall" });
226
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(boundaryObservation.id), { tier: "hot", tier_reason: null });
227
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_entities WHERE id = ?`).get(entity.id), { tier: "hot", tier_reason: "referenced by three recent observations" });
228
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_decisions WHERE id = ?`).get(recentDecision.id), { tier: "hot", tier_reason: "recent decision restatement" });
229
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_decisions WHERE id = ?`).get(staleDecision.id), { tier: "warm", tier_reason: "hot age threshold without recall" });
230
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_decisions WHERE id = ?`).get(boundaryDecision.id), { tier: "hot", tier_reason: null });
231
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_action_items WHERE id = ?`).get(dueSoonAction.id), { tier: "hot", tier_reason: "open action item due soon" });
232
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_action_items WHERE id = ?`).get(dueLaterAction.id), { tier: "warm", tier_reason: null });
233
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_action_items WHERE id = ?`).get(staleHotAction.id), { tier: "warm", tier_reason: "hot age threshold without recall" });
234
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_action_items WHERE id = ?`).get(resolvedAction.id), { tier: "cold", tier_reason: "resolved action item" });
235
- });
236
- test("tieringPass drops archived, superseded, and stale low-confidence rows to cold", async () => {
237
- const { dbModule, memoryModule, tieringModule } = await loadModules("archival-and-stale");
238
- const db = dbModule.getDb();
239
- const scope = createTestScope(memoryModule, "tiering-archival");
240
- const upsertEntity = getFunction(memoryModule, "upsertEntity");
241
- const recordObservation = getFunction(memoryModule, "recordObservation");
242
- const recordDecision = getFunction(memoryModule, "recordDecision");
243
- const archivedObservation = recordObservation({
244
- scope_id: scope.id,
245
- content: "Archived observation should be cold.",
246
- source: "test",
247
- tier: "hot",
248
- confidence: 0.9,
249
- });
250
- const keeperDecision = recordDecision({
251
- scope_id: scope.id,
252
- title: "Current decision",
253
- rationale: "Used as the superseding target.",
254
- decided_at: sqlAt(-DAY_MS),
255
- tier: "warm",
256
- });
257
- const supersededDecision = recordDecision({
258
- scope_id: scope.id,
259
- title: "Old decision",
260
- rationale: "Should become cold once superseded.",
261
- decided_at: sqlAt(-10 * DAY_MS),
262
- tier: "hot",
263
- });
264
- const staleObservation = recordObservation({
265
- scope_id: scope.id,
266
- content: "Low-confidence warm observation should eventually archive.",
267
- source: "test",
268
- tier: "warm",
269
- confidence: 0.2,
270
- });
271
- const staleEntity = upsertEntity({
272
- scope_id: scope.id,
273
- kind: "doc",
274
- name: "stale-entity",
275
- tier: "warm",
276
- confidence: 0.2,
277
- });
278
- db.prepare(`UPDATE mem_observations SET archived_at = ? WHERE id = ?`).run(sqlAt(-DAY_MS), archivedObservation.id);
279
- db.prepare(`UPDATE mem_decisions SET superseded_by = ? WHERE id = ?`).run(keeperDecision.id, supersededDecision.id);
280
- db.prepare(`UPDATE mem_observations SET created_at = ? WHERE id = ?`).run(sqlAt(-61 * DAY_MS), staleObservation.id);
281
- db.prepare(`UPDATE mem_entities SET updated_at = ? WHERE id = ?`).run(sqlAt(-61 * DAY_MS), staleEntity.id);
282
- const summary = tieringModule.tieringPass(scope.id);
283
- assert.equal(summary.examined, 5);
284
- assert.equal(summary.modified, 5);
285
- assert.deepEqual(summary.errors, []);
286
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(archivedObservation.id), { tier: "cold", tier_reason: "archived or superseded" });
287
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_decisions WHERE id = ?`).get(keeperDecision.id), { tier: "hot", tier_reason: "recent decision restatement" });
288
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_decisions WHERE id = ?`).get(supersededDecision.id), { tier: "cold", tier_reason: "archived or superseded" });
289
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(staleObservation.id), { tier: "cold", tier_reason: "stale low confidence" });
290
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_entities WHERE id = ?`).get(staleEntity.id), { tier: "cold", tier_reason: "stale low confidence" });
291
- });
292
- test("tieringPass follows a single observation through creation, recall, aging, and archival", async () => {
293
- const { dbModule, memoryModule, tieringModule } = await loadModules("observation-lifecycle");
294
- const db = dbModule.getDb();
295
- const scope = createTestScope(memoryModule, "tiering-lifecycle");
296
- const recordObservation = getFunction(memoryModule, "recordObservation");
297
- const created = recordObservation({
298
- scope_id: scope.id,
299
- content: "A durable observation should start hot, stay hot when recalled, then cool and archive.",
300
- source: "test",
301
- tier: "hot",
302
- confidence: 0.95,
303
- });
304
- const createdRow = db.prepare(`
305
- SELECT tier, confidence, archived_at, superseded_by, created_at
306
- FROM mem_observations
307
- WHERE id = ?
308
- `).get(created.id);
309
- assert.equal(tieringModule.inferTierFromSignals(createdRow), "hot");
310
- db.prepare(`UPDATE mem_observations SET created_at = ?, last_recalled_at = ? WHERE id = ?`).run(sqlAt(-45 * DAY_MS), sqlAt(-DAY_MS), created.id);
311
- let summary = tieringModule.tieringPass(scope.id);
312
- assert.equal(summary.modified, 0);
313
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(created.id), { tier: "hot", tier_reason: null });
314
- db.prepare(`UPDATE mem_observations SET last_recalled_at = NULL WHERE id = ?`).run(created.id);
315
- summary = tieringModule.tieringPass(scope.id);
316
- assert.equal(summary.modified, 1);
317
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(created.id), { tier: "warm", tier_reason: "hot age threshold without recall" });
318
- db.prepare(`UPDATE mem_observations SET archived_at = ? WHERE id = ?`).run(sqlAt(0), created.id);
319
- summary = tieringModule.tieringPass(scope.id);
320
- assert.equal(summary.modified, 1);
321
- assert.deepEqual(db.prepare(`SELECT tier, tier_reason FROM mem_observations WHERE id = ?`).get(created.id), { tier: "cold", tier_reason: "archived or superseded" });
322
- });
323
- //# sourceMappingURL=tiering.test.js.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map