@remnic/core 9.25.7 → 9.27.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 (238) hide show
  1. package/dist/access-admin-ops-surface.d.ts +5 -5
  2. package/dist/access-admin-ops-surface.js +41 -41
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +5 -5
  5. package/dist/access-authorization-probe.js +42 -42
  6. package/dist/access-boundary.d.ts +5 -5
  7. package/dist/access-boundary.js +41 -41
  8. package/dist/access-cli.js +98 -97
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-http-lcm-compaction.d.ts +130 -0
  11. package/dist/access-http-lcm-compaction.js +10 -0
  12. package/dist/access-http.d.ts +5 -5
  13. package/dist/access-http.js +53 -52
  14. package/dist/access-identity-continuity-surface.d.ts +4 -4
  15. package/dist/access-identity-continuity-surface.js +41 -41
  16. package/dist/access-lcm-surface.d.ts +5 -5
  17. package/dist/access-lcm-surface.js +41 -41
  18. package/dist/access-mcp.d.ts +5 -5
  19. package/dist/access-mcp.js +47 -47
  20. package/dist/access-namespace-preflight.js +41 -41
  21. package/dist/access-observe-write-surface.d.ts +5 -5
  22. package/dist/access-observe-write-surface.js +41 -41
  23. package/dist/access-operations-batch.js +43 -43
  24. package/dist/access-operations.d.ts +8 -8
  25. package/dist/access-operations.js +45 -45
  26. package/dist/access-recall-concurrency.d.ts +5 -5
  27. package/dist/access-recall-concurrency.js +41 -41
  28. package/dist/access-recall-response.d.ts +5 -5
  29. package/dist/access-recall-response.js +41 -41
  30. package/dist/access-recall-surface.d.ts +5 -5
  31. package/dist/access-recall-surface.js +41 -41
  32. package/dist/access-schema.d.ts +92 -77
  33. package/dist/access-schema.js +8 -8
  34. package/dist/{access-service-CIdWkP6J.d.ts → access-service-B4-Fu9x2.d.ts} +4 -4
  35. package/dist/access-service.d.ts +5 -5
  36. package/dist/access-service.js +41 -41
  37. package/dist/access-surface-catalog.d.ts +5 -5
  38. package/dist/access-wearables-meetings-surface.d.ts +2 -2
  39. package/dist/adapters/index.js +7 -7
  40. package/dist/adapters/registry.js +3 -3
  41. package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +3 -3
  42. package/dist/bootstrap.d.ts +4 -4
  43. package/dist/briefing.d.ts +1 -1
  44. package/dist/briefing.js +5 -5
  45. package/dist/buffer.d.ts +1 -1
  46. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  47. package/dist/capsule-crypto-YO5QJ6L3.js.map +1 -0
  48. package/dist/causal-behavior.js +2 -2
  49. package/dist/causal-chain.js +2 -2
  50. package/dist/causal-consolidation.js +11 -11
  51. package/dist/causal-retrieval.js +2 -2
  52. package/dist/causal-trajectory.js +1 -1
  53. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  54. package/dist/{chunk-UMFLAACL.js → chunk-2RAC4JIG.js} +9 -9
  55. package/dist/{chunk-OIE242WM.js → chunk-4MJZTF42.js} +3 -3
  56. package/dist/chunk-4Z4XNEWZ.js +86 -0
  57. package/dist/chunk-4Z4XNEWZ.js.map +1 -0
  58. package/dist/{chunk-IR4LGIH6.js → chunk-5BRT4Z2I.js} +2 -2
  59. package/dist/{chunk-2PHX3I5C.js → chunk-6NNNURLK.js} +8 -8
  60. package/dist/{chunk-BLAKS3CP.js → chunk-77CNV7DY.js} +4 -4
  61. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  62. package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
  63. package/dist/{chunk-7CPOZH6Y.js → chunk-AJ7QCSIS.js} +2 -2
  64. package/dist/{chunk-TPYZ727G.js → chunk-BHLN7L7M.js} +6 -6
  65. package/dist/{chunk-WIGBTWXA.js → chunk-BNGPHGVZ.js} +2 -2
  66. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  67. package/dist/{chunk-PS5OG75R.js → chunk-CI26JDZA.js} +2 -2
  68. package/dist/{chunk-K4DP5KZA.js → chunk-CIQXI47W.js} +684 -22
  69. package/dist/chunk-CIQXI47W.js.map +1 -0
  70. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  71. package/dist/{chunk-W33DEUKR.js → chunk-EOLC6EXV.js} +2 -2
  72. package/dist/{chunk-UOURUMBN.js → chunk-EUSLKI4X.js} +2 -2
  73. package/dist/{chunk-ZPUFQGUF.js → chunk-EYJSW2RV.js} +5 -5
  74. package/dist/{chunk-3CHQZVAL.js → chunk-FRVTCCGD.js} +5 -5
  75. package/dist/{chunk-AQ2ZQYDI.js → chunk-HEXSNYJD.js} +6 -6
  76. package/dist/{chunk-E5A6C4A5.js → chunk-HORJVJ6K.js} +48 -48
  77. package/dist/{chunk-3UOSVTFR.js → chunk-JCVQV6QX.js} +11 -11
  78. package/dist/{chunk-37VPMR4E.js → chunk-JDOJZTFF.js} +6 -6
  79. package/dist/{chunk-P25IPRXP.js → chunk-KGTD2KZJ.js} +28 -8
  80. package/dist/chunk-KGTD2KZJ.js.map +1 -0
  81. package/dist/{chunk-WSEA52RI.js → chunk-MEBQFQ26.js} +2 -2
  82. package/dist/{chunk-G6MGAE36.js → chunk-MG6MNSP4.js} +5 -5
  83. package/dist/{chunk-BL4JHZSO.js → chunk-NUWMZIYZ.js} +40 -40
  84. package/dist/{chunk-ES36HTSC.js → chunk-PTN6UAUA.js} +4 -4
  85. package/dist/{chunk-KZVPTJNZ.js → chunk-RGJBM7Z3.js} +75 -75
  86. package/dist/{chunk-7IGWPXVC.js → chunk-RNY3BO35.js} +2 -2
  87. package/dist/{chunk-JA4HEXV7.js → chunk-RPA2RX5P.js} +2 -2
  88. package/dist/{chunk-32XTXKIA.js → chunk-RSYJV25N.js} +22 -14
  89. package/dist/chunk-RSYJV25N.js.map +1 -0
  90. package/dist/{chunk-S2BBISHU.js → chunk-RYHWZ52A.js} +4 -4
  91. package/dist/{chunk-ZN4UZWMT.js → chunk-SK3EYPKC.js} +2 -2
  92. package/dist/{chunk-BUK2FXOL.js → chunk-TKBDJTXG.js} +4 -4
  93. package/dist/{chunk-D7MAWMMK.js → chunk-U3TH5Q2Q.js} +2 -2
  94. package/dist/{chunk-SSYBI43M.js → chunk-UT3OQPFA.js} +6 -6
  95. package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
  96. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  97. package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
  98. package/dist/{chunk-5J7HJ7RT.js → chunk-WEAO45M4.js} +2 -2
  99. package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
  100. package/dist/{chunk-NY6W6CJW.js → chunk-XKO7BM2C.js} +2 -2
  101. package/dist/{chunk-7KXQ44PA.js → chunk-XQ4EH6DI.js} +5 -5
  102. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  103. package/dist/{chunk-VPSAVXHM.js → chunk-YSGBD3QN.js} +7 -7
  104. package/dist/{cli-Da5kesWC.d.ts → cli-Bz7X7dGx.d.ts} +3 -3
  105. package/dist/cli.d.ts +6 -6
  106. package/dist/cli.js +75 -74
  107. package/dist/compounding/engine.d.ts +1 -1
  108. package/dist/compounding/engine.js +5 -5
  109. package/dist/connectors/codex-materialize-runner.js +5 -5
  110. package/dist/connectors/index.js +5 -5
  111. package/dist/consolidation-provenance-check.d.ts +1 -1
  112. package/dist/consolidation-undo.d.ts +1 -1
  113. package/dist/contradiction/index.d.ts +1 -1
  114. package/dist/conversation-index/backend.js +2 -2
  115. package/dist/corpus-watermark.js +16 -16
  116. package/dist/dashboard-runtime.js +2 -2
  117. package/dist/entity-retrieval.d.ts +1 -1
  118. package/dist/entity-retrieval.js +5 -5
  119. package/dist/explicit-capture.d.ts +4 -4
  120. package/dist/extraction.js +3 -3
  121. package/dist/{first-start-migration-BKNGOFED.js → first-start-migration-LEXL3XYL.js} +4 -4
  122. package/dist/index.d.ts +398 -398
  123. package/dist/index.js +177 -176
  124. package/dist/lcm/engine.js +3 -3
  125. package/dist/lcm/index.js +9 -9
  126. package/dist/maintenance/memory-governance.js +6 -6
  127. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +1 -1
  128. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  129. package/dist/maintenance/rebuild-memory-projection.d.ts +1 -1
  130. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  131. package/dist/{maintenance-DD22oIx9.d.ts → maintenance-DgnD2z8S.d.ts} +1 -1
  132. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  133. package/dist/memory-worth-outcomes.d.ts +1 -1
  134. package/dist/namespaces/migrate.d.ts +1 -1
  135. package/dist/namespaces/migrate.js +15 -15
  136. package/dist/namespaces/search.js +9 -9
  137. package/dist/namespaces/storage.d.ts +1 -1
  138. package/dist/namespaces/storage.js +5 -5
  139. package/dist/operator-doctor-corpus.js +17 -17
  140. package/dist/operator-toolkit.d.ts +1 -1
  141. package/dist/operator-toolkit.js +28 -28
  142. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  143. package/dist/orchestration/maintenance.d.ts +2 -2
  144. package/dist/orchestration/maintenance.js +11 -11
  145. package/dist/{orchestrator-CFJ_TG6D.d.ts → orchestrator-rIHmHpv1.d.ts} +3 -3
  146. package/dist/orchestrator.d.ts +4 -4
  147. package/dist/orchestrator.js +98 -97
  148. package/dist/resume-bundles.js +1 -1
  149. package/dist/schemas.d.ts +76 -76
  150. package/dist/search/factory.js +8 -8
  151. package/dist/search/index.js +13 -13
  152. package/dist/search/lancedb-backend.js +2 -2
  153. package/dist/search/meilisearch-backend.js +2 -2
  154. package/dist/search/orama-backend.js +2 -2
  155. package/dist/semantic-consolidation.js +7 -7
  156. package/dist/semantic-rule-promotion.js +5 -5
  157. package/dist/semantic-rule-verifier.js +6 -6
  158. package/dist/{service-Z8uzoAST.d.ts → service-cTvil7D_.d.ts} +1 -1
  159. package/dist/session-namespace-bindings.d.ts +27 -0
  160. package/dist/session-namespace-bindings.js +243 -0
  161. package/dist/session-namespace-bindings.js.map +1 -0
  162. package/dist/shared-context/manager.d.ts +8 -8
  163. package/dist/{storage-BZVMn8yJ.d.ts → storage-C9ibpTme.d.ts} +0 -3
  164. package/dist/storage.d.ts +1 -1
  165. package/dist/storage.js +4 -4
  166. package/dist/temporal-supersession.d.ts +1 -1
  167. package/dist/testing/lifecycle-matrix.d.ts +100 -0
  168. package/dist/testing/lifecycle-matrix.js +149 -0
  169. package/dist/testing/lifecycle-matrix.js.map +1 -0
  170. package/dist/tier-migration.d.ts +1 -1
  171. package/dist/transfer/backup.js +4 -4
  172. package/dist/transfer/capsule-export.js +4 -4
  173. package/dist/transfer/capsule-import.js +3 -3
  174. package/dist/transfer/types.d.ts +66 -66
  175. package/dist/verified-recall.js +6 -6
  176. package/package.json +22 -2
  177. package/src/access-http-lcm-compaction.ts +116 -0
  178. package/src/access-http.test.ts +218 -0
  179. package/src/access-http.ts +8 -8
  180. package/src/access-schema-pi.test.ts +9 -0
  181. package/src/access-schema.ts +29 -4
  182. package/src/access-surface-catalog.test.ts +1 -0
  183. package/src/session-namespace-bindings.test.ts +358 -0
  184. package/src/session-namespace-bindings.ts +301 -0
  185. package/src/storage/profile-header.ts +897 -0
  186. package/src/storage-profile-timestamp.test.ts +3290 -0
  187. package/src/storage.ts +5 -8
  188. package/src/testing/lifecycle-matrix.ts +17 -7
  189. package/src/testing/subjects/profile-header-write.test.ts +71 -0
  190. package/dist/chunk-32XTXKIA.js.map +0 -1
  191. package/dist/chunk-K4DP5KZA.js.map +0 -1
  192. package/dist/chunk-P25IPRXP.js.map +0 -1
  193. /package/dist/{capsule-crypto-7FJQINUR.js.map → access-http-lcm-compaction.js.map} +0 -0
  194. /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
  195. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  196. /package/dist/{chunk-UMFLAACL.js.map → chunk-2RAC4JIG.js.map} +0 -0
  197. /package/dist/{chunk-OIE242WM.js.map → chunk-4MJZTF42.js.map} +0 -0
  198. /package/dist/{chunk-IR4LGIH6.js.map → chunk-5BRT4Z2I.js.map} +0 -0
  199. /package/dist/{chunk-2PHX3I5C.js.map → chunk-6NNNURLK.js.map} +0 -0
  200. /package/dist/{chunk-BLAKS3CP.js.map → chunk-77CNV7DY.js.map} +0 -0
  201. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  202. /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
  203. /package/dist/{chunk-7CPOZH6Y.js.map → chunk-AJ7QCSIS.js.map} +0 -0
  204. /package/dist/{chunk-TPYZ727G.js.map → chunk-BHLN7L7M.js.map} +0 -0
  205. /package/dist/{chunk-WIGBTWXA.js.map → chunk-BNGPHGVZ.js.map} +0 -0
  206. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  207. /package/dist/{chunk-PS5OG75R.js.map → chunk-CI26JDZA.js.map} +0 -0
  208. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  209. /package/dist/{chunk-W33DEUKR.js.map → chunk-EOLC6EXV.js.map} +0 -0
  210. /package/dist/{chunk-UOURUMBN.js.map → chunk-EUSLKI4X.js.map} +0 -0
  211. /package/dist/{chunk-ZPUFQGUF.js.map → chunk-EYJSW2RV.js.map} +0 -0
  212. /package/dist/{chunk-3CHQZVAL.js.map → chunk-FRVTCCGD.js.map} +0 -0
  213. /package/dist/{chunk-AQ2ZQYDI.js.map → chunk-HEXSNYJD.js.map} +0 -0
  214. /package/dist/{chunk-E5A6C4A5.js.map → chunk-HORJVJ6K.js.map} +0 -0
  215. /package/dist/{chunk-3UOSVTFR.js.map → chunk-JCVQV6QX.js.map} +0 -0
  216. /package/dist/{chunk-37VPMR4E.js.map → chunk-JDOJZTFF.js.map} +0 -0
  217. /package/dist/{chunk-WSEA52RI.js.map → chunk-MEBQFQ26.js.map} +0 -0
  218. /package/dist/{chunk-G6MGAE36.js.map → chunk-MG6MNSP4.js.map} +0 -0
  219. /package/dist/{chunk-BL4JHZSO.js.map → chunk-NUWMZIYZ.js.map} +0 -0
  220. /package/dist/{chunk-ES36HTSC.js.map → chunk-PTN6UAUA.js.map} +0 -0
  221. /package/dist/{chunk-KZVPTJNZ.js.map → chunk-RGJBM7Z3.js.map} +0 -0
  222. /package/dist/{chunk-7IGWPXVC.js.map → chunk-RNY3BO35.js.map} +0 -0
  223. /package/dist/{chunk-JA4HEXV7.js.map → chunk-RPA2RX5P.js.map} +0 -0
  224. /package/dist/{chunk-S2BBISHU.js.map → chunk-RYHWZ52A.js.map} +0 -0
  225. /package/dist/{chunk-ZN4UZWMT.js.map → chunk-SK3EYPKC.js.map} +0 -0
  226. /package/dist/{chunk-BUK2FXOL.js.map → chunk-TKBDJTXG.js.map} +0 -0
  227. /package/dist/{chunk-D7MAWMMK.js.map → chunk-U3TH5Q2Q.js.map} +0 -0
  228. /package/dist/{chunk-SSYBI43M.js.map → chunk-UT3OQPFA.js.map} +0 -0
  229. /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
  230. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  231. /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
  232. /package/dist/{chunk-5J7HJ7RT.js.map → chunk-WEAO45M4.js.map} +0 -0
  233. /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
  234. /package/dist/{chunk-NY6W6CJW.js.map → chunk-XKO7BM2C.js.map} +0 -0
  235. /package/dist/{chunk-7KXQ44PA.js.map → chunk-XQ4EH6DI.js.map} +0 -0
  236. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  237. /package/dist/{chunk-VPSAVXHM.js.map → chunk-YSGBD3QN.js.map} +0 -0
  238. /package/dist/{first-start-migration-BKNGOFED.js.map → first-start-migration-LEXL3XYL.js.map} +0 -0
package/src/storage.ts CHANGED
@@ -20,6 +20,7 @@ import path from "node:path";
20
20
  import { log } from "./logger.js";
21
21
  import { assertMemoryFrontmatterId, warnProjectionFallback } from "./storage-guards.js";
22
22
  import { MemoryReadStore } from "./storage/memory-read-store.js";
23
+ import { renderProfileWithLastUpdated } from "./storage/profile-header.js";
23
24
  import { readMaybeEncryptedLines, readMemoryActionEventRowsFromLines } from "./storage/secure-line-reader.js";
24
25
  import {
25
26
  appendLifecycleEventsSerialized,
@@ -4251,15 +4252,13 @@ export class StorageManager {
4251
4252
  }
4252
4253
 
4253
4254
  async writeProfile(content: string): Promise<void> {
4255
+ const stampedContent = renderProfileWithLastUpdated(content, new Date().toISOString());
4254
4256
  await this.ensureDirectories();
4255
4257
  await this.snapshotBeforeWrite(this.profilePath, "consolidation");
4256
- await this.writeStorageSecureFile(this.profilePath, content);
4258
+ await this.writeStorageSecureFile(this.profilePath, stampedContent);
4257
4259
  log.debug("updated profile.md");
4258
4260
  }
4259
4261
 
4260
- /**
4261
- * Normalize a string for fuzzy profile dedup: lowercase, strip punctuation, collapse whitespace.
4262
- */
4263
4262
  private static normalizeForDedup(s: string): string {
4264
4263
  if (typeof s !== "string") return "";
4265
4264
  return s
@@ -4308,15 +4307,13 @@ export class StorageManager {
4308
4307
  const content = [
4309
4308
  "# Behavioral Profile",
4310
4309
  "",
4311
- `*Last updated: ${new Date().toISOString()}*`,
4312
- "",
4313
4310
  ...newBullets.map((b) => `- ${b}`),
4314
4311
  "",
4315
4312
  ].join("\n");
4316
4313
  await this.writeProfile(content);
4317
4314
  } else {
4318
- const updatedTimestamp = existing.replace(/\*Last updated:.*\*/, `*Last updated: ${new Date().toISOString()}*`);
4319
- const withBullets = updatedTimestamp.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
4315
+ const withBullets =
4316
+ existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
4320
4317
  await this.writeProfile(withBullets);
4321
4318
  }
4322
4319
  }
@@ -15,13 +15,13 @@
15
15
  * `MATRIX_ROWS` entry. Adding a row here is a one-file change that
16
16
  * automatically extends every adopter — the whole point of the harness.
17
17
  *
18
- * Test-support only: this file lives under `src/testing/` (a subdirectory, so
19
- * tsup which entry-points only top-level `src/*.ts` and the public exports —
20
- * never bundles it) and is intentionally absent from package.json `exports`.
21
- * It imports `node:test` and must NEVER be imported by runtime code.
18
+ * Test-support only: this file lives under `src/testing/` and is exported solely
19
+ * so adapter test subjects can share the canonical matrix across packages.
20
+ * The registrar loads `node:test` through `createRequire` so the built artifact
21
+ * keeps the builtin specifier, and runtime code must never import this module.
22
22
  */
23
23
 
24
- import test from "node:test";
24
+ import { createRequire } from "node:module";
25
25
 
26
26
  /** The nine canonical AGENTS.md session/retrieval/cache matrix rows. */
27
27
  export type MatrixRowId =
@@ -215,13 +215,23 @@ export interface RunLifecycleMatrixOptions {
215
215
  export function lifecycleTestName(subjectName: string, row: MatrixRow): string {
216
216
  return `lifecycle-matrix[${subjectName}] :: ${row.id} — ${row.title}`;
217
217
  }
218
+ type NodeTestRegistrar = {
219
+ (name: string, fn: () => void | Promise<void>): void;
220
+ (name: string, options: { skip: string }, fn: () => void): void;
221
+ };
222
+
223
+ const requiredNodeTest = createRequire(import.meta.url)("node:test") as
224
+ | NodeTestRegistrar
225
+ | { test: NodeTestRegistrar };
226
+ const nodeTest: NodeTestRegistrar =
227
+ typeof requiredNodeTest === "function" ? requiredNodeTest : requiredNodeTest.test;
218
228
 
219
229
  const defaultRegister: MatrixTestRegistrar = (name, fn) => {
220
- test(name, fn);
230
+ nodeTest(name, fn);
221
231
  };
222
232
 
223
233
  const defaultRegisterSkipped: MatrixSkipRegistrar = (name, reason) => {
224
- test(name, { skip: reason }, () => {});
234
+ nodeTest(name, { skip: reason }, () => {});
225
235
  };
226
236
 
227
237
  /**
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Profile-header write-boundary subject for the lifecycle scenario matrix.
3
+ * Profile content is not session state, so only the session-end mutation row
4
+ * applies; the remaining canonical rows are explicit skips rather than false
5
+ * extraction-lifecycle coverage.
6
+ */
7
+
8
+ import assert from "node:assert/strict";
9
+
10
+ import { StorageManager } from "../../storage.js";
11
+ import { type LifecycleSubject, type MatrixRow, runLifecycleMatrix } from "../lifecycle-matrix.js";
12
+ import { cleanupDir, mkTempMemoryDir } from "../orchestrator-lite.js";
13
+
14
+ interface ProfileHeaderState {
15
+ dir: string;
16
+ storage: StorageManager;
17
+ writeStartedAt?: number;
18
+ }
19
+
20
+ const STALE_PROFILE = [
21
+ "# Behavioral Profile",
22
+ "",
23
+ "*Last updated: 2024-01-02T03:04:05.000Z*",
24
+ "",
25
+ "- Profile content survives the write boundary.",
26
+ "",
27
+ ].join("\n");
28
+
29
+ const subject: LifecycleSubject<ProfileHeaderState> = {
30
+ appliesTo(row: MatrixRow): boolean | string {
31
+ return row.id === "session-end"
32
+ ? true
33
+ : "profile writes have no provider, restart, or replay variants; direct profile tests cover those boundaries";
34
+ },
35
+
36
+ async setup(row: MatrixRow): Promise<ProfileHeaderState> {
37
+ const dir = await mkTempMemoryDir(`profile-header-${row.id}`);
38
+ try {
39
+ return { dir, storage: new StorageManager(dir) };
40
+ } catch (error) {
41
+ await cleanupDir(dir);
42
+ throw error;
43
+ }
44
+ },
45
+
46
+ async exercise(state: ProfileHeaderState): Promise<void> {
47
+ state.writeStartedAt = Date.now();
48
+ await state.storage.writeProfile(STALE_PROFILE);
49
+ },
50
+
51
+ async invariants(state: ProfileHeaderState): Promise<void> {
52
+ const profile = await state.storage.readProfile();
53
+ const headers = profile.match(/^\*Last updated: .*\*$/gm) ?? [];
54
+ assert.equal(headers.length, 1, "profile writes leave one canonical Last updated header");
55
+ assert.notEqual(headers[0], "*Last updated: 2024-01-02T03:04:05.000Z*");
56
+ assert.match(profile, /^# Behavioral Profile$/m);
57
+
58
+ const timestamp = headers[0]?.match(/^\*Last updated: ([^*]+)\*$/)?.[1];
59
+ assert.ok(timestamp, "the canonical header contains an ISO timestamp");
60
+ const updatedAt = Date.parse(timestamp);
61
+ assert.ok(Number.isFinite(updatedAt), "the profile header timestamp is parseable");
62
+ assert.ok(updatedAt >= (state.writeStartedAt ?? 0), "the header advances at the write boundary");
63
+ assert.ok(updatedAt <= Date.now(), "the header is not in the future");
64
+ },
65
+
66
+ async teardown(state: ProfileHeaderState): Promise<void> {
67
+ await cleanupDir(state.dir);
68
+ },
69
+ };
70
+
71
+ runLifecycleMatrix("profile-header-write", subject);