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,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