dotmem 0.0.8 → 0.1.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.
package/index.cjs CHANGED
@@ -22,6 +22,18 @@ var __export = (target, all) => {
22
22
  __defProp(target, name, { get: all[name], enumerable: true });
23
23
  };
24
24
 
25
+ // suppress-idb-warning.ts
26
+ var orig;
27
+ var init_suppress_idb_warning = __esm({
28
+ "suppress-idb-warning.ts"() {
29
+ orig = console.warn.bind(console);
30
+ console.warn = (...args) => {
31
+ if (typeof args[0] === "string" && args[0].includes("IndexedDB is not available")) return;
32
+ orig(...args);
33
+ };
34
+ }
35
+ });
36
+
25
37
  // core/env.ts
26
38
  var DEV;
27
39
  var init_env = __esm({
@@ -674,7 +686,7 @@ var init_detection_events = __esm({
674
686
  });
675
687
 
676
688
  // core/knowledge/policy.ts
677
- var ENFORCEMENT_TIERS, POLICY_DIR_NAME, PolicyAuthorityError, validatePolicyAuthority, TIER_ENFORCEMENT, TIER_ACTION, CONVERSATIONAL_OVERRIDE_KEYS, ConversationalOverrideRejectedError, PolicyPreconditionViolationError, assertNoConversationalOverride, findPolicyBypassKey, canonicalEvent, findFieldValue, evaluateCondition, validatePolicyAuditAuthority, authorityRelaxationPermitted, authorityRevocationPermitted, canonicalPolicyFingerprint, resolveOverrideState, resolveEffectivePolicies, evaluatePolicies, applyOverrideOverlay, stripNonAuthoritativeTierFields;
689
+ var ENFORCEMENT_TIERS, POLICY_DIR_NAME, PolicyAuthorityError; exports.validateGovernanceAuthority = void 0; var TIER_ENFORCEMENT, TIER_ACTION, CONVERSATIONAL_OVERRIDE_KEYS, ConversationalOverrideRejectedError, PolicyPreconditionViolationError, assertNoConversationalOverride, findPolicyBypassKey, canonicalEvent, findFieldValue, evaluateCondition, validatePolicyAuditAuthority, authorityRelaxationPermitted, authorityRevocationPermitted, canonicalPolicyFingerprint, resolveOverrideState, resolveEffectivePolicies, evaluatePolicies, applyOverrideOverlay, stripNonAuthoritativeTierFields;
678
690
  var init_policy = __esm({
679
691
  "core/knowledge/policy.ts"() {
680
692
  init_canonical_hash();
@@ -690,7 +702,7 @@ var init_policy = __esm({
690
702
  this.name = "PolicyAuthorityError";
691
703
  }
692
704
  };
693
- validatePolicyAuthority = /* @__PURE__ */ __name((value) => {
705
+ exports.validateGovernanceAuthority = /* @__PURE__ */ __name((value) => {
694
706
  if (!value || typeof value !== "object" || Array.isArray(value)) {
695
707
  throw new PolicyAuthorityError("Policy authority requires an authority object");
696
708
  }
@@ -825,17 +837,17 @@ var init_policy = __esm({
825
837
  if (candidate.kind === "system") {
826
838
  return { kind: "system", source: candidate.source.trim() };
827
839
  }
828
- return validatePolicyAuthority(candidate);
840
+ return exports.validateGovernanceAuthority(candidate);
829
841
  }, "validatePolicyAuditAuthority");
830
842
  authorityRelaxationPermitted = /* @__PURE__ */ __name((targetAuthority, actorAuthority) => {
831
- validatePolicyAuthority(targetAuthority);
832
- validatePolicyAuthority(actorAuthority);
843
+ exports.validateGovernanceAuthority(targetAuthority);
844
+ exports.validateGovernanceAuthority(actorAuthority);
833
845
  if (targetAuthority.kind === "HI") return actorAuthority.kind === "HI";
834
846
  return actorAuthority.kind === "HI" || actorAuthority.kind === "operator";
835
847
  }, "authorityRelaxationPermitted");
836
848
  authorityRevocationPermitted = /* @__PURE__ */ __name((overrideAuthority, actorAuthority) => {
837
- validatePolicyAuthority(overrideAuthority);
838
- validatePolicyAuthority(actorAuthority);
849
+ exports.validateGovernanceAuthority(overrideAuthority);
850
+ exports.validateGovernanceAuthority(actorAuthority);
839
851
  if (actorAuthority.kind === "HI") return true;
840
852
  return overrideAuthority.kind === "operator";
841
853
  }, "authorityRevocationPermitted");
@@ -2238,7 +2250,7 @@ var init_policy_store = __esm({
2238
2250
  resolveUserPolicyFilePath = /* @__PURE__ */ __name((namespace2) => joinPath(resolveUserPolicyDir2(), `${namespace2}.policy.json`), "resolveUserPolicyFilePath");
2239
2251
  validatePolicyAuthority2 = /* @__PURE__ */ __name((value) => {
2240
2252
  try {
2241
- return validatePolicyAuthority(value);
2253
+ return exports.validateGovernanceAuthority(value);
2242
2254
  } catch (error) {
2243
2255
  emitPolicyAuthorityDetection(value);
2244
2256
  throw error instanceof PolicyStoreError ? error : new PolicyStoreError(error.message);
@@ -2414,6 +2426,7 @@ var init_policy_store = __esm({
2414
2426
  if (entry.target !== void 0) built.target = entry.target;
2415
2427
  if (entry.reason !== void 0) built.reason = entry.reason;
2416
2428
  if (entry.detail !== void 0) built.detail = entry.detail;
2429
+ if (entry.mandatory !== void 0) built.mandatory = entry.mandatory;
2417
2430
  return built;
2418
2431
  }, "validatePolicyAuditEntry");
2419
2432
  validatePolicyDocument = /* @__PURE__ */ __name((value) => {
@@ -2491,6 +2504,7 @@ var init_policy_store = __esm({
2491
2504
  if (entry.target !== void 0) built.target = entry.target;
2492
2505
  if (entry.reason !== void 0) built.reason = entry.reason;
2493
2506
  if (entry.detail !== void 0) built.detail = entry.detail;
2507
+ if (entry.mandatory !== void 0) built.mandatory = entry.mandatory;
2494
2508
  return built;
2495
2509
  }, "buildAuditEntry");
2496
2510
  boundedAudit = /* @__PURE__ */ __name((entries2, overrides) => {
@@ -2503,9 +2517,10 @@ var init_policy_store = __esm({
2503
2517
  for (let index = entries2.length - 1; index >= 0; index--) {
2504
2518
  const entry = entries2[index];
2505
2519
  const activeLinked = entry.target !== void 0 && activeOverrideIds.has(entry.target) && (entry.action === "override" || entry.action === "revoke");
2506
- if (activeLinked || budget > 0) {
2520
+ const mandatory = entry.mandatory === true;
2521
+ if (activeLinked || mandatory || budget > 0) {
2507
2522
  kept.unshift(entry);
2508
- if (!activeLinked) budget--;
2523
+ if (!activeLinked && !mandatory) budget--;
2509
2524
  }
2510
2525
  }
2511
2526
  return kept;
@@ -2546,6 +2561,12 @@ var init_policy_store = __esm({
2546
2561
  try {
2547
2562
  await fs.writeFile(temporary, `${JSON.stringify(document, null, 2)}
2548
2563
  `, "utf8");
2564
+ const handle = await fs.open(temporary, "r+");
2565
+ try {
2566
+ await handle.sync();
2567
+ } finally {
2568
+ await handle.close();
2569
+ }
2549
2570
  await fs.rename(temporary, filePath);
2550
2571
  } catch (error) {
2551
2572
  await fs.rm(temporary, { force: true }).catch(() => void 0);
@@ -4464,7 +4485,7 @@ function encodeMemFile(stateValue, preserved) {
4464
4485
  function decodeMemDocument(value) {
4465
4486
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid .mem file format");
4466
4487
  const file = value;
4467
- if (file.format !== MEM_FORMAT) throw new Error("Invalid .mem file format");
4488
+ if (file.format !== MEM_FORMAT && file.format !== MEM_FORMAT_LEGACY) throw new Error("Invalid .mem file format");
4468
4489
  if (file.version === MEM_FORMAT_VERSION_V1) {
4469
4490
  if (!file.knowledge) throw new Error("Invalid .mem file format");
4470
4491
  return { state: validateSourceState(file.knowledge) };
@@ -4546,11 +4567,12 @@ function decodeMemDocument(value) {
4546
4567
  preserved: { map: structuredClone(map), data: structuredClone(stateRecord) }
4547
4568
  };
4548
4569
  }
4549
- var MEM_FORMAT, MEM_FORMAT_VERSION, MEM_FORMAT_VERSION_V1, expectedFields, epistemicTypes, revisionKinds, claimKinds, isJsonValue2, createMemInterpretationMap, validateSourceState, trimRecord, fieldIndexes, validateVocabulary, put, get, optionalGet, requireRecord, putOptional;
4570
+ var MEM_FORMAT, MEM_FORMAT_LEGACY, MEM_FORMAT_VERSION, MEM_FORMAT_VERSION_V1, expectedFields, epistemicTypes, revisionKinds, claimKinds, isJsonValue2, createMemInterpretationMap, validateSourceState, trimRecord, fieldIndexes, validateVocabulary, put, get, optionalGet, requireRecord, putOptional;
4550
4571
  var init_mem_codec = __esm({
4551
4572
  "core/knowledge/mem-codec.ts"() {
4552
4573
  init_state();
4553
4574
  MEM_FORMAT = "dotmem.knowledge";
4575
+ MEM_FORMAT_LEGACY = "memorio.knowledge";
4554
4576
  MEM_FORMAT_VERSION = 2;
4555
4577
  MEM_FORMAT_VERSION_V1 = 1;
4556
4578
  expectedFields = {
@@ -4729,12 +4751,13 @@ async function inspectMem(input) {
4729
4751
  return { status: artifactError.code, representation: "unknown", message: artifactError.message, parts: [] };
4730
4752
  }
4731
4753
  }
4732
- var MEM_PACKAGE_FORMAT, MEM_PACKAGE_VERSION, MEM_PACKAGE_LIMITS, MEM_PACKAGE_WRITE_MARGIN_BYTES, MEM_PACKAGE_WRITE_LIMITS, MANIFEST_PATH, MAP_PATH, DATA_PATH, INTEGRITY_PATH, requiredParts, encoder2, decoder, MemArtifactError, stableValue, jsonBytes, sha256, parseJson, validEntryPath, concatenate, readZipParts, createManifest, digestTableIdentity, signaturePayload, base64UrlEncode, base64UrlDecode, keyIdentity, signaturePath, encodePackage, isZip, decodePackage, verifySignature;
4754
+ var MEM_PACKAGE_FORMAT, MEM_PACKAGE_FORMAT_LEGACY, MEM_PACKAGE_VERSION, MEM_PACKAGE_LIMITS, MEM_PACKAGE_WRITE_MARGIN_BYTES, MEM_PACKAGE_WRITE_LIMITS, MANIFEST_PATH, MAP_PATH, DATA_PATH, INTEGRITY_PATH, requiredParts, encoder2, decoder, MemArtifactError, stableValue, jsonBytes, sha256, parseJson, validEntryPath, concatenate, readZipParts, createManifest, digestTableIdentity, signaturePayload, base64UrlEncode, base64UrlDecode, keyIdentity, signaturePath, encodePackage, isZip, decodePackage, verifySignature;
4733
4755
  var init_mem_package = __esm({
4734
4756
  "core/knowledge/mem-package.ts"() {
4735
4757
  init_browser();
4736
4758
  init_mem_codec();
4737
4759
  MEM_PACKAGE_FORMAT = "dotmem.package";
4760
+ MEM_PACKAGE_FORMAT_LEGACY = "memorio.package";
4738
4761
  MEM_PACKAGE_VERSION = 1;
4739
4762
  MEM_PACKAGE_LIMITS = Object.freeze({
4740
4763
  maximumPackageBytes: 10 * 1024 * 1024,
@@ -4925,10 +4948,10 @@ ${contentId}
4925
4948
  if (!parts[path]) throw new MemArtifactError("invalid", `Missing MEM package part: ${path}`);
4926
4949
  }
4927
4950
  const manifest = parseJson(parts[MANIFEST_PATH], MANIFEST_PATH);
4928
- if (manifest.format !== MEM_PACKAGE_FORMAT && manifest.format || manifest.version !== MEM_PACKAGE_VERSION) {
4951
+ if (manifest.format !== MEM_PACKAGE_FORMAT && manifest.format !== MEM_PACKAGE_FORMAT_LEGACY || manifest.version !== MEM_PACKAGE_VERSION) {
4929
4952
  throw new MemArtifactError("unsupported", "Unsupported MEM package format or version");
4930
4953
  }
4931
- if (manifest.memory?.format !== MEM_FORMAT && manifest.memory?.format || manifest.memory.version !== MEM_FORMAT_VERSION || manifest.parts?.map !== MAP_PATH || manifest.parts?.data !== DATA_PATH || manifest.parts?.integrity !== INTEGRITY_PATH) {
4954
+ if (manifest.memory?.format !== MEM_FORMAT && manifest.memory?.format !== MEM_FORMAT_LEGACY || manifest.memory.version !== MEM_FORMAT_VERSION || manifest.parts?.map !== MAP_PATH || manifest.parts?.data !== DATA_PATH || manifest.parts?.integrity !== INTEGRITY_PATH) {
4932
4955
  throw new MemArtifactError("invalid", "Invalid MEM package manifest");
4933
4956
  }
4934
4957
  const integrity = parseJson(parts[INTEGRITY_PATH], INTEGRITY_PATH);
@@ -5040,6 +5063,109 @@ ${contentId}
5040
5063
  }
5041
5064
  });
5042
5065
 
5066
+ // core/storage-coordinator/index.ts
5067
+ var nodeFs4, withStorageLock, readStorageGeneration, writeStorageGeneration;
5068
+ var init_storage_coordinator = __esm({
5069
+ "core/storage-coordinator/index.ts"() {
5070
+ nodeFs4 = /* @__PURE__ */ __name(async () => import('fs/promises'), "nodeFs");
5071
+ withStorageLock = /* @__PURE__ */ __name(async (directoryPath, operationOrOptions, operation, _options = {}) => {
5072
+ const opts = typeof operationOrOptions === "function" ? operation ?? {} : operationOrOptions ?? {};
5073
+ const op = typeof operationOrOptions === "function" ? operationOrOptions : operation;
5074
+ const timeoutMs = opts.timeoutMs ?? 3e4;
5075
+ const staleMs = opts.staleMs ?? 6e4;
5076
+ const lockName = opts.lockName ?? ".storage.lock";
5077
+ const lockPath = `${directoryPath}/${lockName}`;
5078
+ const fs = await nodeFs4();
5079
+ const started = Date.now();
5080
+ await fs.mkdir(directoryPath, { recursive: true });
5081
+ while (true) {
5082
+ try {
5083
+ await fs.mkdir(lockPath);
5084
+ const token2 = `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
5085
+ await fs.writeFile(`${lockPath}/owner.json`, JSON.stringify({ token: token2, pid: process.pid, createdAt: Date.now() }), { flag: "wx" });
5086
+ break;
5087
+ } catch (error) {
5088
+ const code = error.code;
5089
+ if (code !== "EEXIST" && code !== "ENOENT" && code !== "EPERM" && code !== "ENOTEMPTY") throw error;
5090
+ let stale = false;
5091
+ let processDead = false;
5092
+ try {
5093
+ const raw = await fs.readFile(`${lockPath}/owner.json`, "utf8");
5094
+ const parsed = JSON.parse(raw);
5095
+ const ageStale = typeof parsed.createdAt === "number" && Date.now() - parsed.createdAt > staleMs;
5096
+ if (typeof parsed.pid === "number") {
5097
+ try {
5098
+ process.kill(parsed.pid, 0);
5099
+ } catch {
5100
+ processDead = true;
5101
+ }
5102
+ } else {
5103
+ processDead = true;
5104
+ }
5105
+ if (ageStale || processDead) stale = true;
5106
+ } catch {
5107
+ stale = true;
5108
+ }
5109
+ if (stale) {
5110
+ if (processDead) {
5111
+ try {
5112
+ await fs.rm(lockPath, { recursive: true, force: true });
5113
+ continue;
5114
+ } catch {
5115
+ }
5116
+ }
5117
+ try {
5118
+ await fs.rmdir(lockPath);
5119
+ continue;
5120
+ } catch {
5121
+ }
5122
+ }
5123
+ if (Date.now() - started > timeoutMs) {
5124
+ throw new Error(`Storage lock timeout for ${directoryPath}`);
5125
+ }
5126
+ await new Promise((resolve) => setTimeout(resolve, 25));
5127
+ }
5128
+ }
5129
+ let token = "";
5130
+ try {
5131
+ const raw = await fs.readFile(`${lockPath}/owner.json`, "utf8");
5132
+ token = JSON.parse(raw).token ?? "";
5133
+ } catch {
5134
+ token = "";
5135
+ }
5136
+ try {
5137
+ return await op();
5138
+ } finally {
5139
+ try {
5140
+ const raw = await fs.readFile(`${lockPath}/owner.json`, "utf8");
5141
+ const parsed = JSON.parse(raw);
5142
+ if (parsed.token === token && token) {
5143
+ await fs.rm(lockPath, { recursive: true, force: true });
5144
+ }
5145
+ } catch {
5146
+ }
5147
+ }
5148
+ }, "withStorageLock");
5149
+ readStorageGeneration = /* @__PURE__ */ __name(async (directoryPath) => {
5150
+ const fs = await nodeFs4();
5151
+ try {
5152
+ const raw = await fs.readFile(`${directoryPath}/.storage.generation`, "utf8");
5153
+ const value = Number(raw.trim());
5154
+ return Number.isFinite(value) && value >= 0 ? value : 0;
5155
+ } catch {
5156
+ return 0;
5157
+ }
5158
+ }, "readStorageGeneration");
5159
+ writeStorageGeneration = /* @__PURE__ */ __name(async (directoryPath, value) => {
5160
+ const fs = await nodeFs4();
5161
+ await fs.mkdir(directoryPath, { recursive: true });
5162
+ const temp = `${directoryPath}/.storage.generation.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
5163
+ await fs.writeFile(temp, String(value));
5164
+ await fs.rename(temp, `${directoryPath}/.storage.generation`);
5165
+ }, "writeStorageGeneration");
5166
+ }
5167
+ });
5168
+
5043
5169
  // core/knowledge/mem-repository.ts
5044
5170
  function resolveDuplicate(existing, existingSource, current, currentSource) {
5045
5171
  const existingRetracts = existing.revision?.kind === "retracts";
@@ -5080,19 +5206,20 @@ async function parseMemFile(value, sourceId) {
5080
5206
  throw new Error(`${message} in ${sourceId}`);
5081
5207
  }
5082
5208
  }
5083
- var DOTMEM_DIRECTORY, DEFAULT_MEM_FILE, directoryLocks, nodeFs4, separator2, normalizePath, isAbsolutePath, resolvePath, joinPath2, parentPath, uniqueSuffix, withDirectoryLock, isMissingDirectory, sourcePriority, memFilePath, MemDirectoryKnowledgeRepository;
5209
+ var DOTMEM_DIRECTORY, DEFAULT_MEM_FILE, nodeFs5, repositoryLoadCaches, separator2, normalizePath, isAbsolutePath, resolvePath, joinPath2, parentPath, uniqueSuffix, isMissingDirectory, sourcePriority, memFilePath, MemDirectoryKnowledgeRepository;
5084
5210
  var init_mem_repository = __esm({
5085
5211
  "core/knowledge/mem-repository.ts"() {
5086
5212
  init_mem_codec();
5087
5213
  init_mem_package();
5088
5214
  init_state();
5089
5215
  init_acquisition_limits();
5216
+ init_storage_coordinator();
5090
5217
  DOTMEM_DIRECTORY = ".dotmem";
5091
5218
  DEFAULT_MEM_FILE = "project.mem";
5092
- directoryLocks = /* @__PURE__ */ new Map();
5093
- nodeFs4 = /* @__PURE__ */ __name(async () => {
5219
+ nodeFs5 = /* @__PURE__ */ __name(async () => {
5094
5220
  return import('fs/promises');
5095
5221
  }, "nodeFs");
5222
+ repositoryLoadCaches = /* @__PURE__ */ new Map();
5096
5223
  separator2 = /* @__PURE__ */ __name(() => process.platform === "win32" ? "\\" : "/", "separator");
5097
5224
  normalizePath = /* @__PURE__ */ __name((value) => value.replace(/[\\/]+/g, separator2()), "normalizePath");
5098
5225
  isAbsolutePath = /* @__PURE__ */ __name((value) => /^(?:[A-Za-z]:[\\/]|[\\/])/.test(value), "isAbsolutePath");
@@ -5104,25 +5231,8 @@ var init_mem_repository = __esm({
5104
5231
  return index <= 0 ? "." : normalized.slice(0, index);
5105
5232
  }, "parentPath");
5106
5233
  uniqueSuffix = /* @__PURE__ */ __name(() => globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`, "uniqueSuffix");
5107
- withDirectoryLock = /* @__PURE__ */ __name(async (directoryPath, operation) => {
5108
- const previous = directoryLocks.get(directoryPath) ?? Promise.resolve();
5109
- let release = /* @__PURE__ */ __name(() => void 0, "release");
5110
- const gate = new Promise((resolveGate) => {
5111
- release = resolveGate;
5112
- });
5113
- const queued = previous.then(() => gate);
5114
- directoryLocks.set(directoryPath, queued);
5115
- await previous;
5116
- try {
5117
- return await operation();
5118
- } finally {
5119
- release();
5120
- if (directoryLocks.get(directoryPath) === queued) directoryLocks.delete(directoryPath);
5121
- }
5122
- }, "withDirectoryLock");
5123
5234
  isMissingDirectory = /* @__PURE__ */ __name((error) => error.code === "ENOENT", "isMissingDirectory");
5124
5235
  sourcePriority = /* @__PURE__ */ __name((sourceId, scope) => {
5125
- if (sourceId.endsWith(".mem") && sourceId !== "project.mem" && sourceId !== "user.mem" && sourceId !== "agent.mem") return 0;
5126
5236
  if (scope === "project" || sourceId === "project.mem") return 4;
5127
5237
  if (scope === "user" || sourceId === "user.mem") return 3;
5128
5238
  if (sourceId === "agent.mem" || sourceId === "agent") return 2;
@@ -5150,7 +5260,7 @@ var init_mem_repository = __esm({
5150
5260
  this.loadWritableOnly = loadWritableOnly;
5151
5261
  }
5152
5262
  async discover() {
5153
- const { readdir } = await nodeFs4();
5263
+ const { readdir } = await nodeFs5();
5154
5264
  try {
5155
5265
  const entries2 = await readdir(this.directoryPath, { withFileTypes: true });
5156
5266
  return entries2.filter((entry) => entry.isFile() && entry.name.endsWith(".mem") && entry.name !== "@brain.mem").map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
@@ -5165,7 +5275,7 @@ var init_mem_repository = __esm({
5165
5275
  * receive a clear failure instead of discovering corruption on first use.
5166
5276
  */
5167
5277
  async initialize() {
5168
- const { mkdir } = await nodeFs4();
5278
+ const { mkdir } = await nodeFs5();
5169
5279
  await mkdir(this.directoryPath, { recursive: true });
5170
5280
  await this.load();
5171
5281
  }
@@ -5180,7 +5290,7 @@ var init_mem_repository = __esm({
5180
5290
  * that does not delete is not a delete.
5181
5291
  */
5182
5292
  async clearWritable() {
5183
- const { rm, readdir } = await nodeFs4();
5293
+ const { rm, readdir } = await nodeFs5();
5184
5294
  const filePath = memFilePath(this.directoryPath, this.writableSourceId);
5185
5295
  await rm(filePath, { force: true });
5186
5296
  await rm(`${filePath}.bak`, { force: true });
@@ -5197,15 +5307,28 @@ var init_mem_repository = __esm({
5197
5307
  }
5198
5308
  }
5199
5309
  async load() {
5200
- const loaded = this.loadWritableOnly ? await this.loadSources([this.writableSourceId]) : await this.loadSources();
5201
- return this.combine(loaded);
5310
+ const cacheKey = `${this.directoryPath}:${this.writableSourceId}:${this.loadWritableOnly}`;
5311
+ for (let attempt = 0; attempt < 5; attempt += 1) {
5312
+ const generationBefore = await readStorageGeneration(this.directoryPath);
5313
+ const cached = repositoryLoadCaches.get(cacheKey);
5314
+ if (cached && cached.signature === String(generationBefore)) {
5315
+ return structuredClone(cached.state);
5316
+ }
5317
+ const loaded = this.loadWritableOnly ? await this.loadSources([this.writableSourceId]) : await this.loadSources();
5318
+ const state3 = this.combine(loaded);
5319
+ const generationAfter = await readStorageGeneration(this.directoryPath);
5320
+ if (generationBefore !== generationAfter && attempt < 4) continue;
5321
+ repositoryLoadCaches.set(cacheKey, { signature: String(generationAfter), state: structuredClone(state3) });
5322
+ return state3;
5323
+ }
5324
+ throw new Error("Unable to load stable repository state");
5202
5325
  }
5203
- async save(state3, expectedVersion) {
5326
+ async save(state3, expectedVersion, locked = false) {
5204
5327
  const validated = validateKnowledgeState(state3);
5205
5328
  if (!Number.isInteger(expectedVersion) || expectedVersion < 0 || validated.version !== expectedVersion + 1) {
5206
5329
  throw new Error("Invalid expected persisted version");
5207
5330
  }
5208
- await withDirectoryLock(this.directoryPath, async () => {
5331
+ const doWrite = /* @__PURE__ */ __name(async () => {
5209
5332
  const loaded = await this.loadSources();
5210
5333
  const writable = loaded.find((source) => source.id === this.writableSourceId) ?? {
5211
5334
  id: this.writableSourceId,
@@ -5227,10 +5350,16 @@ var init_mem_repository = __esm({
5227
5350
  claims: [...writable.state.claims, ...newClaims]
5228
5351
  };
5229
5352
  await this.writeSource(writable.filePath, nextWritable, writable.preserved, writable.package);
5230
- });
5353
+ await writeStorageGeneration(this.directoryPath, await readStorageGeneration(this.directoryPath) + 1);
5354
+ }, "doWrite");
5355
+ if (locked) {
5356
+ await doWrite();
5357
+ } else {
5358
+ await withStorageLock(this.directoryPath, doWrite);
5359
+ }
5231
5360
  }
5232
5361
  async loadSources(sourceIds) {
5233
- const { readFile: readFile5 } = await nodeFs4();
5362
+ const { readFile: readFile5 } = await nodeFs5();
5234
5363
  const ids = sourceIds ?? await this.discover();
5235
5364
  const sources = [];
5236
5365
  for (const sourceId of ids) {
@@ -5320,7 +5449,7 @@ var init_mem_repository = __esm({
5320
5449
  * valid package, so the backup is always a version this library can read.
5321
5450
  */
5322
5451
  async keepLastValidVersion(filePath) {
5323
- const { readFile: readFile5, copyFile, rename, rm } = await nodeFs4();
5452
+ const { readFile: readFile5, copyFile, rename, rm } = await nodeFs5();
5324
5453
  let current;
5325
5454
  try {
5326
5455
  current = await readFile5(filePath);
@@ -5344,7 +5473,7 @@ var init_mem_repository = __esm({
5344
5473
  }
5345
5474
  /** Best-effort directory sync: the rename is durable once the directory is. */
5346
5475
  async syncDirectory(directoryPath) {
5347
- const { open } = await nodeFs4();
5476
+ const { open } = await nodeFs5();
5348
5477
  try {
5349
5478
  const handle = await open(directoryPath, "r");
5350
5479
  try {
@@ -5356,7 +5485,7 @@ var init_mem_repository = __esm({
5356
5485
  }
5357
5486
  }
5358
5487
  async writeSource(filePath, state3, preserved, preservedPackage) {
5359
- const { mkdir, rename, rm, open, readFile: readFile5 } = await nodeFs4();
5488
+ const { mkdir, rename, rm, open, readFile: readFile5 } = await nodeFs5();
5360
5489
  if (!Number.isInteger(state3.version) || state3.version < 0) throw new Error("Invalid writable .mem knowledge version");
5361
5490
  for (const claim of state3.claims) validateClaim(claim);
5362
5491
  await mkdir(parentPath(filePath), { recursive: true });
@@ -5884,7 +6013,7 @@ var init_project_identity = __esm({
5884
6013
  });
5885
6014
 
5886
6015
  // core/knowledge/staging.ts
5887
- var DOTMEM_STAGE_FORMAT, DOTMEM_STAGE_VERSION, StageFileError, generateRequestId, nodeCwd, resolveStagingDirectory, stagePathFor, nodeFs5, normalizeClaimIds, revisionFromOptions, writeStageFile, readStageFile, validateStageFile, commitStageFile, cleanupStageFile;
6016
+ var DOTMEM_STAGE_FORMAT, DOTMEM_STAGE_VERSION, StageFileError, generateRequestId, nodeCwd, resolveStagingDirectory, stagePathFor, nodeFs6, normalizeClaimIds, revisionFromOptions, writeStageFile, readStageFile, validateStageFile, commitStageFile, cleanupStageFile;
5888
6017
  var init_staging = __esm({
5889
6018
  "core/knowledge/staging.ts"() {
5890
6019
  init_claim_record();
@@ -5919,7 +6048,7 @@ var init_staging = __esm({
5919
6048
  return `${base}/dotmem`;
5920
6049
  }, "resolveStagingDirectory");
5921
6050
  stagePathFor = /* @__PURE__ */ __name((requestId) => `${resolveStagingDirectory()}/${requestId}.stage`, "stagePathFor");
5922
- nodeFs5 = /* @__PURE__ */ __name(async () => import('fs/promises'), "nodeFs");
6051
+ nodeFs6 = /* @__PURE__ */ __name(async () => import('fs/promises'), "nodeFs");
5923
6052
  normalizeClaimIds = /* @__PURE__ */ __name((value) => {
5924
6053
  if (!value) return [];
5925
6054
  return Array.isArray(value) ? value : [value];
@@ -5944,7 +6073,7 @@ var init_staging = __esm({
5944
6073
  };
5945
6074
  const requestId = generateRequestId();
5946
6075
  const stagePath = stagePathFor(requestId);
5947
- const fs = await nodeFs5();
6076
+ const fs = await nodeFs6();
5948
6077
  await fs.mkdir(resolveStagingDirectory(), { recursive: true });
5949
6078
  const stageFile = {
5950
6079
  format: DOTMEM_STAGE_FORMAT,
@@ -5964,7 +6093,7 @@ var init_staging = __esm({
5964
6093
  }, "writeStageFile");
5965
6094
  readStageFile = /* @__PURE__ */ __name(async (requestId) => {
5966
6095
  const stagePath = stagePathFor(requestId);
5967
- const fs = await nodeFs5();
6096
+ const fs = await nodeFs6();
5968
6097
  try {
5969
6098
  const content = await fs.readFile(stagePath, "utf8");
5970
6099
  return JSON.parse(content);
@@ -6075,7 +6204,7 @@ var init_staging = __esm({
6075
6204
  }, "commitStageFile");
6076
6205
  cleanupStageFile = /* @__PURE__ */ __name(async (requestId) => {
6077
6206
  const stagePath = stagePathFor(requestId);
6078
- const fs = await nodeFs5();
6207
+ const fs = await nodeFs6();
6079
6208
  try {
6080
6209
  await fs.unlink(stagePath);
6081
6210
  } catch (error) {
@@ -6846,6 +6975,7 @@ function _inferConfidence(claim) {
6846
6975
  var LOGIC_MEM_FILE, nodeCwd2, cachedRuntime, LogicEngine, logic, logic_default;
6847
6976
  var init_logic = __esm({
6848
6977
  "core/logic/index.ts"() {
6978
+ init_suppress_idb_warning();
6849
6979
  init_knowledge();
6850
6980
  init_mem_repository();
6851
6981
  init_acquisition_boundary();
@@ -7113,6 +7243,9 @@ Do not store secrets unless dotmem explicitly supports secure secret storage.
7113
7243
  }
7114
7244
  });
7115
7245
 
7246
+ // index.ts
7247
+ init_suppress_idb_warning();
7248
+
7116
7249
  // core/idb.ts
7117
7250
  var idb = {
7118
7251
  db: {},
@@ -7452,7 +7585,11 @@ var security = {
7452
7585
  createSanitizer
7453
7586
  };
7454
7587
 
7588
+ // core/memory/index.ts
7589
+ init_suppress_idb_warning();
7590
+
7455
7591
  // core/memory/journal.ts
7592
+ init_suppress_idb_warning();
7456
7593
  init_env();
7457
7594
  var g = globalThis;
7458
7595
  function namespace() {
@@ -7659,6 +7796,7 @@ var journal_default = journal;
7659
7796
  init_brain();
7660
7797
 
7661
7798
  // core/memory/knowledge-runtime.ts
7799
+ init_suppress_idb_warning();
7662
7800
  init_knowledge();
7663
7801
  init_project_identity();
7664
7802
  init_user_paths();
@@ -8007,6 +8145,7 @@ var policy = {
8007
8145
  };
8008
8146
 
8009
8147
  // core/memory/entries.ts
8148
+ init_suppress_idb_warning();
8010
8149
  init_env();
8011
8150
  var MEMORY_INDEX_KEY = "__dotmem_memory_index__";
8012
8151
  var SUPERSEDED_PREFIX = "__dotmem_superseded__";
@@ -8551,15 +8690,18 @@ var context = {
8551
8690
  };
8552
8691
 
8553
8692
  // core/memory/acquire.ts
8693
+ init_suppress_idb_warning();
8554
8694
  init_env();
8555
8695
  init_project_identity();
8556
8696
  init_project_anchor();
8557
8697
  init_acquisition_boundary();
8558
8698
  init_claim_record();
8699
+ init_state();
8559
8700
  init_router();
8560
8701
  init_store_queue();
8561
8702
  init_staging();
8562
8703
  init_user_paths();
8704
+ init_storage_coordinator();
8563
8705
  init_mem_repository();
8564
8706
  function normalizeClaimIds3(value) {
8565
8707
  if (!value) return [];
@@ -8637,23 +8779,27 @@ var acquire = {
8637
8779
  );
8638
8780
  }
8639
8781
  const revision = revisionFromAcquire2(opts);
8782
+ const repository = target.repository;
8640
8783
  await withStoreQueue(acquisitionStoreKey(kind, scope, sourceProject), async () => {
8641
- const state3 = await target.runtime.select([]);
8642
- await target.runtime.update({
8643
- basedOnVersion: state3.context.knowledgeVersion,
8644
- claims: [buildClaimRecord({
8645
- id: opts.id,
8646
- knowledge: boundary.knowledge,
8647
- applicability: opts.applicability,
8648
- evidence: opts.evidence,
8649
- epistemicType: opts.epistemicType,
8650
- provenance: opts.provenance,
8651
- acquiredAt: opts.acquiredAt,
8652
- revision,
8653
- scope,
8654
- sourceProject,
8655
- kind
8656
- })]
8784
+ await withStorageLock(repository.directoryPath, async () => {
8785
+ const state3 = await repository.load();
8786
+ const next = updateKnowledge(state3, {
8787
+ basedOnVersion: state3.version,
8788
+ claims: [buildClaimRecord({
8789
+ id: opts.id,
8790
+ knowledge: boundary.knowledge,
8791
+ applicability: opts.applicability,
8792
+ evidence: opts.evidence,
8793
+ epistemicType: opts.epistemicType,
8794
+ provenance: opts.provenance,
8795
+ acquiredAt: opts.acquiredAt,
8796
+ revision,
8797
+ scope,
8798
+ sourceProject,
8799
+ kind
8800
+ })]
8801
+ });
8802
+ await repository.save(next, state3.version, true);
8657
8803
  });
8658
8804
  });
8659
8805
  const verification = await target.repository.load();
@@ -10194,6 +10340,442 @@ var saveContinuityDocument = /* @__PURE__ */ __name(async (path, document) => {
10194
10340
  }
10195
10341
  }, "saveContinuityDocument");
10196
10342
 
10343
+ // core/continuity-ledger/index.ts
10344
+ var EVENT_ID_PREFIX = "evt.";
10345
+ var LEDGER_APPLICABILITY = { area: "continuity", baseline: false };
10346
+ var EVENT_TYPES = /* @__PURE__ */ new Set([
10347
+ "decision",
10348
+ "discovery",
10349
+ "correction",
10350
+ "conversation",
10351
+ "commitment",
10352
+ "open-loop",
10353
+ "project-change",
10354
+ "activity"
10355
+ ]);
10356
+ var MEMORY_DOMAINS = /* @__PURE__ */ new Set(["environmental", "professional", "conversational", "activity"]);
10357
+ var EPITEMIC_STATUSES = /* @__PURE__ */ new Set([
10358
+ "verified-fact",
10359
+ "user-statement",
10360
+ "ai-inference",
10361
+ "hypothesis",
10362
+ "proposal",
10363
+ "decision",
10364
+ "verified-result"
10365
+ ]);
10366
+ var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["high", "medium", "low", "unknown"]);
10367
+ var AUTHORS = /* @__PURE__ */ new Set(["human", "ai", "system"]);
10368
+ var CHANNELS = /* @__PURE__ */ new Set(["conversation", "acquisition", "tool", "migration"]);
10369
+ var SOURCE_KINDS = /* @__PURE__ */ new Set(["claim", "file", "commit", "tool-output", "conversation"]);
10370
+ var RELATIONSHIP_KEYS = [
10371
+ "refines",
10372
+ "supersedes",
10373
+ "retracts",
10374
+ "dependsOn",
10375
+ "resolves",
10376
+ "relatedTo"
10377
+ ];
10378
+ var isRecord = /* @__PURE__ */ __name((value) => !!value && typeof value === "object" && !Array.isArray(value), "isRecord");
10379
+ var normalizeRelationships = /* @__PURE__ */ __name((value) => {
10380
+ const result = {
10381
+ refines: [],
10382
+ supersedes: [],
10383
+ retracts: [],
10384
+ dependsOn: [],
10385
+ resolves: [],
10386
+ relatedTo: []
10387
+ };
10388
+ if (!isRecord(value)) return result;
10389
+ for (const key of RELATIONSHIP_KEYS) {
10390
+ const raw = value[key];
10391
+ if (Array.isArray(raw)) {
10392
+ result[key] = raw.filter((item) => typeof item === "string");
10393
+ }
10394
+ }
10395
+ return result;
10396
+ }, "normalizeRelationships");
10397
+ var validateEvent = /* @__PURE__ */ __name((event) => {
10398
+ if (!isRecord(event)) throw new Error("Continuity event must be an object");
10399
+ if (event.schemaVersion !== 1) throw new Error("Unsupported continuity event schemaVersion");
10400
+ if (typeof event.eventId !== "string" || !event.eventId.startsWith(EVENT_ID_PREFIX)) {
10401
+ throw new Error("Continuity event requires a valid eventId");
10402
+ }
10403
+ if (typeof event.eventType !== "string" || !EVENT_TYPES.has(event.eventType)) {
10404
+ throw new Error("Continuity event requires a valid eventType");
10405
+ }
10406
+ if (typeof event.memoryDomain !== "string" || !MEMORY_DOMAINS.has(event.memoryDomain)) {
10407
+ throw new Error("Continuity event requires a valid memoryDomain");
10408
+ }
10409
+ if (typeof event.epistemicStatus !== "string" || !EPITEMIC_STATUSES.has(event.epistemicStatus)) {
10410
+ throw new Error("Continuity event requires a valid epistemicStatus");
10411
+ }
10412
+ if (typeof event.confidence !== "string" || !CONFIDENCE_VALUES.has(event.confidence)) {
10413
+ throw new Error("Continuity event requires a valid confidence");
10414
+ }
10415
+ if (typeof event.createdAt !== "string") throw new Error("Continuity event requires createdAt");
10416
+ if (typeof event.sessionId !== "string") throw new Error("Continuity event requires sessionId");
10417
+ if (event.projectId !== null && typeof event.projectId !== "string") {
10418
+ throw new Error("Continuity event requires projectId to be string or null");
10419
+ }
10420
+ if (typeof event.subject !== "string") throw new Error("Continuity event requires subject");
10421
+ if (!isRecord(event.content)) throw new Error("Continuity event requires content object");
10422
+ if (!Array.isArray(event.sourceRefs)) throw new Error("Continuity event requires sourceRefs array");
10423
+ for (const ref of event.sourceRefs) {
10424
+ if (!isRecord(ref) || typeof ref.kind !== "string" || !SOURCE_KINDS.has(ref.kind) || typeof ref.id !== "string") {
10425
+ throw new Error("Continuity event contains an invalid sourceRef");
10426
+ }
10427
+ }
10428
+ if (!isRecord(event.relationships)) throw new Error("Continuity event requires relationships object");
10429
+ if (!isRecord(event.provenance)) throw new Error("Continuity event requires provenance object");
10430
+ const provenance = event.provenance;
10431
+ if (typeof provenance.author !== "string" || !AUTHORS.has(provenance.author)) {
10432
+ throw new Error("Continuity event requires a valid provenance.author");
10433
+ }
10434
+ if (typeof provenance.origin !== "string") throw new Error("Continuity event requires provenance.origin");
10435
+ if (typeof provenance.channel !== "string" || !CHANNELS.has(provenance.channel)) {
10436
+ throw new Error("Continuity event requires a valid provenance.channel");
10437
+ }
10438
+ if (typeof provenance.recordedAt !== "string") throw new Error("Continuity event requires provenance.recordedAt");
10439
+ return {
10440
+ schemaVersion: 1,
10441
+ eventId: event.eventId,
10442
+ eventType: event.eventType,
10443
+ memoryDomain: event.memoryDomain,
10444
+ epistemicStatus: event.epistemicStatus,
10445
+ confidence: event.confidence,
10446
+ createdAt: event.createdAt,
10447
+ sessionId: event.sessionId,
10448
+ projectId: event.projectId,
10449
+ subject: event.subject,
10450
+ content: event.content,
10451
+ sourceRefs: event.sourceRefs,
10452
+ relationships: normalizeRelationships(event.relationships),
10453
+ provenance
10454
+ };
10455
+ }, "validateEvent");
10456
+ var isLedgerEvent = /* @__PURE__ */ __name((claim) => {
10457
+ return isRecord(claim.knowledge) && claim.knowledge.schemaVersion === 1 && typeof claim.knowledge.eventId === "string";
10458
+ }, "isLedgerEvent");
10459
+ var loadEvents = /* @__PURE__ */ __name(async () => {
10460
+ const state3 = await loadCombinedKnowledgeState();
10461
+ const events = [];
10462
+ for (const claim of state3.claims) {
10463
+ if (isLedgerEvent(claim)) {
10464
+ try {
10465
+ events.push(validateEvent(claim.knowledge));
10466
+ } catch {
10467
+ }
10468
+ }
10469
+ }
10470
+ return events.sort((left, right) => left.eventId.localeCompare(right.eventId));
10471
+ }, "loadEvents");
10472
+ var findEvent = /* @__PURE__ */ __name((events, eventId) => events.find((event) => event.eventId === eventId), "findEvent");
10473
+ var epistemicTypeFor = /* @__PURE__ */ __name((status) => {
10474
+ if (status === "verified-fact" || status === "verified-result" || status === "decision") return "verified";
10475
+ if (status === "user-statement") return "human-stated";
10476
+ return "inferred";
10477
+ }, "epistemicTypeFor");
10478
+ var EVENT_ID_PATTERN = /^evt\.[A-Za-z0-9][A-Za-z0-9._-]*$/;
10479
+ var validateEventId = /* @__PURE__ */ __name((eventId) => {
10480
+ if (!EVENT_ID_PATTERN.test(eventId)) throw new Error(`Invalid continuity event ID: ${eventId}`);
10481
+ }, "validateEventId");
10482
+ var hasRelationshipPath = /* @__PURE__ */ __name((events, startId, targetId, relationKey) => {
10483
+ const visited = /* @__PURE__ */ new Set();
10484
+ const stack = [startId];
10485
+ while (stack.length > 0) {
10486
+ const current = stack.pop();
10487
+ if (current === targetId) return true;
10488
+ if (visited.has(current)) continue;
10489
+ visited.add(current);
10490
+ const event = findEvent(events, current);
10491
+ if (!event) continue;
10492
+ for (const next of event.relationships[relationKey]) {
10493
+ if (!visited.has(next)) stack.push(next);
10494
+ }
10495
+ }
10496
+ return false;
10497
+ }, "hasRelationshipPath");
10498
+ var CYCLIC_RELATIONSHIP_KEYS = /* @__PURE__ */ new Set([
10499
+ "refines",
10500
+ "supersedes",
10501
+ "retracts",
10502
+ "dependsOn",
10503
+ "resolves",
10504
+ "relatedTo"
10505
+ ]);
10506
+ var validateRelationshipTargets = /* @__PURE__ */ __name(async (event, existing) => {
10507
+ validateEventId(event.eventId);
10508
+ for (const key of RELATIONSHIP_KEYS) {
10509
+ for (const targetId of event.relationships[key]) {
10510
+ validateEventId(targetId);
10511
+ if (targetId === event.eventId) throw new Error(`Continuity event cannot reference itself: ${targetId}`);
10512
+ const target = findEvent(existing, targetId);
10513
+ if (!target) throw new Error(`Continuity relationship references a nonexistent event: ${targetId}`);
10514
+ if (target.projectId !== event.projectId) {
10515
+ throw new Error(`Cross-scope continuity relationship is not allowed: ${event.eventId} -> ${targetId}`);
10516
+ }
10517
+ if (CYCLIC_RELATIONSHIP_KEYS.has(key) && hasRelationshipPath(existing, targetId, event.eventId, key)) {
10518
+ throw new Error(`Continuity relationship would create a cycle: ${event.eventId} -> ${targetId}`);
10519
+ }
10520
+ }
10521
+ }
10522
+ }, "validateRelationshipTargets");
10523
+ var validateResolutionRequest = /* @__PURE__ */ __name(async (resolution, existing) => {
10524
+ validateEventId(resolution.resolutionEventId);
10525
+ if (!Array.isArray(resolution.conflictingEventIds) || resolution.conflictingEventIds.length === 0) {
10526
+ throw new Error("Conflict resolution requires at least one conflicting event");
10527
+ }
10528
+ if (typeof resolution.selectedEventId !== "string" || !resolution.selectedEventId) {
10529
+ throw new Error("Conflict resolution requires a selected event");
10530
+ }
10531
+ if (typeof resolution.reason !== "string" || !resolution.reason.trim()) {
10532
+ throw new Error("Conflict resolution requires a reason");
10533
+ }
10534
+ const conflicting = resolution.conflictingEventIds.map((id) => {
10535
+ validateEventId(id);
10536
+ const event = findEvent(existing, id);
10537
+ if (!event) throw new Error(`Conflict resolution references a nonexistent event: ${id}`);
10538
+ if (event.relationships.supersedes.length !== 1) {
10539
+ throw new Error(`Conflict resolution references a non-supersession event: ${id}`);
10540
+ }
10541
+ return event;
10542
+ });
10543
+ const targets = new Set(conflicting.map((event) => event.relationships.supersedes[0]));
10544
+ if (targets.size !== 1) {
10545
+ throw new Error("Conflict resolution references supersession events targeting different decisions");
10546
+ }
10547
+ const targetId = [...targets][0];
10548
+ const knownCompeting = supersedingEvents(existing, targetId).map((event) => event.eventId).sort();
10549
+ const requested = [...resolution.conflictingEventIds].sort();
10550
+ if (requested.length !== knownCompeting.length || requested.some((id, index) => id !== knownCompeting[index])) {
10551
+ throw new Error("Conflict resolution must include every competing supersession event");
10552
+ }
10553
+ if (!resolution.conflictingEventIds.includes(resolution.selectedEventId)) {
10554
+ throw new Error("Conflict resolution selectedEventId must be one of the conflicting events");
10555
+ }
10556
+ const existingResolutions = existing.filter(
10557
+ (event) => event.relationships.resolves.includes(targetId) || resolution.conflictingEventIds.some((id) => event.relationships.resolves.includes(id))
10558
+ );
10559
+ if (existingResolutions.length > 0) {
10560
+ const selectedOutcomes = new Set(existingResolutions.map((event) => {
10561
+ const content = isRecord(event.content) ? event.content : {};
10562
+ return typeof content.selectedEventId === "string" ? content.selectedEventId : null;
10563
+ }).filter((value) => value !== null));
10564
+ if (existingResolutions.some((event) => event.eventId === resolution.resolutionEventId)) {
10565
+ throw new Error(`Duplicate continuity resolution event: ${resolution.resolutionEventId}`);
10566
+ }
10567
+ if (selectedOutcomes.size > 0 && !selectedOutcomes.has(resolution.selectedEventId)) {
10568
+ throw new Error("Incompatible continuity conflict resolution");
10569
+ }
10570
+ throw new Error("Continuity conflict is already resolved");
10571
+ }
10572
+ const resolutionEventId = resolution.resolutionEventId;
10573
+ for (const conflictingId of resolution.conflictingEventIds) {
10574
+ const event = findEvent(existing, conflictingId);
10575
+ if (event && hasRelationshipPath(existing, conflictingId, resolutionEventId, "resolves")) {
10576
+ throw new Error(`Continuity resolution would create a cycle: ${resolutionEventId}`);
10577
+ }
10578
+ }
10579
+ }, "validateResolutionRequest");
10580
+ var recordEventOnce = /* @__PURE__ */ __name(async (event) => {
10581
+ const validated = validateEvent(event);
10582
+ const existing = await loadEvents();
10583
+ await validateRelationshipTargets(validated, existing);
10584
+ if (existing.some((item) => item.eventId === validated.eventId)) {
10585
+ throw new Error(`Continuity event already exists: ${validated.eventId}`);
10586
+ }
10587
+ const scope = validated.projectId ? "project" : "user";
10588
+ const evidence = validated.sourceRefs.length > 0 ? validated.sourceRefs.map((ref) => ({
10589
+ id: ref.id,
10590
+ source: ref.kind,
10591
+ observedAt: validated.createdAt,
10592
+ supports: validated.eventId
10593
+ })) : [{ id: validated.eventId, source: "continuity-ledger", observedAt: validated.createdAt, supports: validated.eventId }];
10594
+ await memory.acquire({
10595
+ id: validated.eventId,
10596
+ knowledge: validated,
10597
+ applicability: { ...LEDGER_APPLICABILITY, topic: validated.eventType },
10598
+ evidence,
10599
+ epistemicType: epistemicTypeFor(validated.epistemicStatus),
10600
+ provenance: {
10601
+ source: validated.provenance.origin,
10602
+ detail: validated.provenance.channel
10603
+ },
10604
+ scope,
10605
+ sourceProject: validated.projectId ?? void 0,
10606
+ kind: "experience"
10607
+ });
10608
+ }, "recordEventOnce");
10609
+ var recordEvent = /* @__PURE__ */ __name(async (event) => {
10610
+ let lastError;
10611
+ for (let attempt = 0; attempt < 10; attempt += 1) {
10612
+ try {
10613
+ await recordEventOnce(event);
10614
+ return;
10615
+ } catch (error) {
10616
+ lastError = error;
10617
+ if (error instanceof Error && /Stale update/i.test(error.message) && attempt < 9) {
10618
+ await new Promise((resolve) => setTimeout(resolve, 20));
10619
+ continue;
10620
+ }
10621
+ throw error;
10622
+ }
10623
+ }
10624
+ throw lastError instanceof Error ? lastError : new Error("Continuity event recording failed");
10625
+ }, "recordEvent");
10626
+ var getEvent = /* @__PURE__ */ __name(async (eventId) => {
10627
+ const events = await loadEvents();
10628
+ return findEvent(events, eventId) ?? null;
10629
+ }, "getEvent");
10630
+ var listEvents = /* @__PURE__ */ __name(async (filter = {}) => {
10631
+ const events = await loadEvents();
10632
+ return events.filter((event) => {
10633
+ if (filter.eventId && event.eventId !== filter.eventId) return false;
10634
+ if (filter.eventType && event.eventType !== filter.eventType) return false;
10635
+ if (filter.memoryDomain && event.memoryDomain !== filter.memoryDomain) return false;
10636
+ if (filter.sessionId && event.sessionId !== filter.sessionId) return false;
10637
+ if (filter.projectId !== void 0 && event.projectId !== filter.projectId) return false;
10638
+ if (filter.epistemicStatus && event.epistemicStatus !== filter.epistemicStatus) return false;
10639
+ return true;
10640
+ });
10641
+ }, "listEvents");
10642
+ var supersedingEvents = /* @__PURE__ */ __name((events, eventId) => events.filter((event) => event.relationships.supersedes.includes(eventId)), "supersedingEvents");
10643
+ var retractingEvents = /* @__PURE__ */ __name((events, eventId) => events.filter((event) => event.relationships.retracts.includes(eventId)), "retractingEvents");
10644
+ var resolutionEventsFor = /* @__PURE__ */ __name((events, eventId, conflictingIds) => events.filter(
10645
+ (event) => event.relationships.resolves.includes(eventId) || conflictingIds.some((id) => event.relationships.resolves.includes(id))
10646
+ ), "resolutionEventsFor");
10647
+ var deriveValidity = /* @__PURE__ */ __name(async (eventId) => {
10648
+ let events = await loadEvents();
10649
+ for (let stabilityAttempt = 0; stabilityAttempt < 5; stabilityAttempt += 1) {
10650
+ const nextEvents = await loadEvents();
10651
+ if (nextEvents.length === events.length) break;
10652
+ events = nextEvents;
10653
+ await new Promise((resolve) => setTimeout(resolve, 25));
10654
+ }
10655
+ const supersededBy = supersedingEvents(events, eventId).map((event) => event.eventId);
10656
+ const retractedBy = retractingEvents(events, eventId).map((event) => event.eventId);
10657
+ const contestedBy = supersededBy.length > 1 ? supersededBy : [];
10658
+ const resolvedBy = resolutionEventsFor(events, eventId, contestedBy).map((event) => event.eventId);
10659
+ let state3 = "current";
10660
+ if (retractedBy.length > 0) state3 = "retracted";
10661
+ else if (supersededBy.length > 0) state3 = supersededBy.length > 1 && resolvedBy.length === 0 ? "contested" : "superseded";
10662
+ else if (events.some((event) => event.eventId === eventId && event.eventType === "decision") === false) state3 = "current";
10663
+ if (supersededBy.length > 1 && resolvedBy.length === 0) state3 = "contested";
10664
+ return {
10665
+ eventId,
10666
+ state: state3,
10667
+ supersededBy,
10668
+ retractedBy,
10669
+ contestedBy,
10670
+ resolvedBy
10671
+ };
10672
+ }, "deriveValidity");
10673
+ var listContested = /* @__PURE__ */ __name(async () => {
10674
+ const events = await loadEvents();
10675
+ const targets = /* @__PURE__ */ new Set();
10676
+ for (const event of events) {
10677
+ for (const target of event.relationships.supersedes) targets.add(target);
10678
+ }
10679
+ const contested = [];
10680
+ for (const target of targets) {
10681
+ const supersededBy = supersedingEvents(events, target);
10682
+ if (supersededBy.length <= 1) continue;
10683
+ const conflictingIds = supersededBy.map((event) => event.eventId);
10684
+ const resolvedBy = resolutionEventsFor(events, target, conflictingIds);
10685
+ if (resolvedBy.length === 0) contested.push(target);
10686
+ }
10687
+ return contested.sort();
10688
+ }, "listContested");
10689
+ var resolveConflictOnce = /* @__PURE__ */ __name(async (resolution) => {
10690
+ const existing = await loadEvents();
10691
+ await validateResolutionRequest(resolution, existing);
10692
+ const resolutionEvent = {
10693
+ schemaVersion: 1,
10694
+ eventId: resolution.resolutionEventId,
10695
+ eventType: "correction",
10696
+ memoryDomain: "professional",
10697
+ epistemicStatus: "decision",
10698
+ confidence: "high",
10699
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
10700
+ sessionId: "resolution",
10701
+ projectId: null,
10702
+ subject: "Continuity conflict resolution",
10703
+ content: {
10704
+ selectedEventId: resolution.selectedEventId,
10705
+ reason: resolution.reason
10706
+ },
10707
+ sourceRefs: resolution.conflictingEventIds.map((id) => ({ kind: "claim", id })),
10708
+ relationships: {
10709
+ refines: [],
10710
+ supersedes: [],
10711
+ retracts: [],
10712
+ dependsOn: [],
10713
+ resolves: [...resolution.conflictingEventIds],
10714
+ relatedTo: [resolution.selectedEventId]
10715
+ },
10716
+ provenance: {
10717
+ author: "system",
10718
+ origin: "continuity-ledger",
10719
+ channel: "acquisition",
10720
+ recordedAt: (/* @__PURE__ */ new Date()).toISOString()
10721
+ }
10722
+ };
10723
+ await recordEvent(resolutionEvent);
10724
+ }, "resolveConflictOnce");
10725
+ var reconstructValidity = /* @__PURE__ */ __name(async () => {
10726
+ const events = await loadEvents();
10727
+ const result = [];
10728
+ const targets = new Set(events.map((event) => event.eventId));
10729
+ for (const event of events) {
10730
+ for (const target of event.relationships.supersedes) targets.add(target);
10731
+ for (const target of event.relationships.retracts) targets.add(target);
10732
+ }
10733
+ for (const target of targets) {
10734
+ result.push(await deriveValidity(target));
10735
+ }
10736
+ return result.sort((left, right) => left.eventId.localeCompare(right.eventId));
10737
+ }, "reconstructValidity");
10738
+ var resolveConflict = /* @__PURE__ */ __name(async (resolution) => {
10739
+ let lastError;
10740
+ for (let attempt = 0; attempt < 3; attempt += 1) {
10741
+ try {
10742
+ await resolveConflictOnce(resolution);
10743
+ return;
10744
+ } catch (error) {
10745
+ lastError = error;
10746
+ if (error instanceof Error && /Stale update/i.test(error.message) && attempt < 9) {
10747
+ await new Promise((resolve) => setTimeout(resolve, 20));
10748
+ continue;
10749
+ }
10750
+ throw error;
10751
+ }
10752
+ }
10753
+ throw lastError instanceof Error ? lastError : new Error("Continuity conflict resolution failed");
10754
+ }, "resolveConflict");
10755
+ var validateRelationships = validateRelationshipTargets;
10756
+ var continuityLedger = {
10757
+ recordEvent,
10758
+ record: recordEvent,
10759
+ append: recordEvent,
10760
+ add: recordEvent,
10761
+ getEvent,
10762
+ get: getEvent,
10763
+ find: getEvent,
10764
+ listEvents,
10765
+ list: listEvents,
10766
+ query: listEvents,
10767
+ deriveValidity,
10768
+ validity: deriveValidity,
10769
+ listContested,
10770
+ contested: listContested,
10771
+ resolveConflict,
10772
+ resolve: resolveConflict,
10773
+ reconstructValidity,
10774
+ validateRelationships,
10775
+ validateRelationshipTargets,
10776
+ validateResolution: validateResolutionRequest
10777
+ };
10778
+
10197
10779
  // core/continuity/index.ts
10198
10780
  var continuity = {
10199
10781
  async context(options) {
@@ -12022,6 +12604,1232 @@ var createCompactionEngine = /* @__PURE__ */ __name((options) => new CompactionE
12022
12604
  // index.ts
12023
12605
  init_user_identity();
12024
12606
  init_user_paths();
12607
+
12608
+ // core/governance/index.ts
12609
+ init_user_paths();
12610
+ init_policy();
12611
+ init_policy_namespace_lock();
12612
+ init_detection_events();
12613
+ init_policy();
12614
+ var GOVERNANCE_FILE_NAME = "governance.policy.json";
12615
+ var GOVERNANCE_FORMAT = "dotmem.governance-policy";
12616
+ var GOVERNANCE_VERSION = 1;
12617
+ var GOVERNANCE_AUDIT_RETENTION = 200;
12618
+ var GovernancePolicyError = class extends Error {
12619
+ static {
12620
+ __name(this, "GovernancePolicyError");
12621
+ }
12622
+ constructor(message) {
12623
+ super(message);
12624
+ this.name = "GovernancePolicyError";
12625
+ }
12626
+ };
12627
+ var requiredText3 = /* @__PURE__ */ __name((v) => typeof v === "string" && v.trim().length > 0, "requiredText");
12628
+ var nowIso2 = /* @__PURE__ */ __name(() => (/* @__PURE__ */ new Date()).toISOString(), "nowIso");
12629
+ var joinPath7 = /* @__PURE__ */ __name((base, child) => {
12630
+ const sep = process.platform === "win32" ? "\\" : "/";
12631
+ return `${base.replace(/[\\/]+/g, sep)}${sep}${child}`;
12632
+ }, "joinPath");
12633
+ var resolveGovernanceDir = /* @__PURE__ */ __name((directory) => directory ?? joinPath7(resolveUserDotMemPath(), "policy"), "resolveGovernanceDir");
12634
+ var resolveGovernanceFilePath = /* @__PURE__ */ __name((directory) => joinPath7(resolveGovernanceDir(directory), GOVERNANCE_FILE_NAME), "resolveGovernanceFilePath");
12635
+ var ROLE_CAPABILITIES = {
12636
+ "human-owner": /* @__PURE__ */ new Set(["policy.propose", "policy.review", "policy.approve", "policy.reject", "policy.activate", "policy.suspend", "policy.retire", "role.bind", "governance.read", "governance.audit.read", "agent.execute", "guardrail.stop.activate", "guardrail.stop.release"]),
12637
+ "human-approver": /* @__PURE__ */ new Set(["policy.review", "policy.approve", "policy.reject", "governance.read", "governance.audit.read", "guardrail.stop.activate", "guardrail.stop.release"]),
12638
+ "coordinator-jo": /* @__PURE__ */ new Set(["policy.propose", "policy.review", "policy.activate", "governance.read", "governance.audit.read", "agent.execute"]),
12639
+ "specialist-agent": /* @__PURE__ */ new Set(["policy.propose", "governance.read"]),
12640
+ "policy-authority": /* @__PURE__ */ new Set(["policy.propose", "policy.review", "policy.activate", "governance.read", "governance.audit.read", "agent.execute"]),
12641
+ "auditor-reviewer": /* @__PURE__ */ new Set(["governance.read", "governance.audit.read"])
12642
+ };
12643
+ var defaultRoleBindings = /* @__PURE__ */ __name(() => [
12644
+ { principalId: "hi", role: "human-owner", scope: "*", grantedBy: "system", grantedAt: (/* @__PURE__ */ new Date(0)).toISOString() },
12645
+ { principalId: "human-owner", role: "human-owner", scope: "*", grantedBy: "system", grantedAt: (/* @__PURE__ */ new Date(0)).toISOString() },
12646
+ { principalId: "jo", role: "coordinator-jo", scope: "*", grantedBy: "system", grantedAt: (/* @__PURE__ */ new Date(0)).toISOString() }
12647
+ ], "defaultRoleBindings");
12648
+ var emptyDocument2 = /* @__PURE__ */ __name(() => ({
12649
+ format: GOVERNANCE_FORMAT,
12650
+ version: GOVERNANCE_VERSION,
12651
+ revision: 0,
12652
+ policies: [],
12653
+ roleBindings: defaultRoleBindings(),
12654
+ audit: []
12655
+ }), "emptyDocument");
12656
+ var validateAuthority = /* @__PURE__ */ __name((value) => {
12657
+ try {
12658
+ return exports.validateGovernanceAuthority(value);
12659
+ } catch (err2) {
12660
+ void detectAuthorityEscalationAttempt({ claimed: "invalid governance authority", channel: "governance" }).catch(() => void 0);
12661
+ throw err2 instanceof GovernancePolicyError ? err2 : new GovernancePolicyError(err2.message);
12662
+ }
12663
+ }, "validateAuthority");
12664
+ var buildAudit = /* @__PURE__ */ __name((entry) => ({
12665
+ id: entry.id ?? `gov-audit.${entry.action}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`,
12666
+ action: entry.action,
12667
+ at: entry.at,
12668
+ ...entry.actorPrincipal !== void 0 ? { actorPrincipal: entry.actorPrincipal } : {},
12669
+ ...entry.actorRole !== void 0 ? { actorRole: entry.actorRole } : {},
12670
+ ...entry.targetPolicyId !== void 0 ? { targetPolicyId: entry.targetPolicyId } : {},
12671
+ ...entry.targetVersion !== void 0 ? { targetVersion: entry.targetVersion } : {},
12672
+ ...entry.scope !== void 0 ? { scope: entry.scope } : {},
12673
+ outcome: entry.outcome,
12674
+ ...entry.reason !== void 0 ? { reason: entry.reason } : {},
12675
+ ...entry.detail !== void 0 ? { detail: entry.detail } : {},
12676
+ ...entry.correlationId !== void 0 ? { correlationId: entry.correlationId } : {},
12677
+ ...entry.mandatory !== void 0 ? { mandatory: entry.mandatory } : {}
12678
+ }), "buildAudit");
12679
+ var boundedAudit2 = /* @__PURE__ */ __name((entries2) => {
12680
+ if (entries2.length <= GOVERNANCE_AUDIT_RETENTION) return [...entries2];
12681
+ const kept = [];
12682
+ let budget = GOVERNANCE_AUDIT_RETENTION;
12683
+ for (let i2 = entries2.length - 1; i2 >= 0; i2--) {
12684
+ const e = entries2[i2];
12685
+ const mandatory = e.mandatory === true;
12686
+ if (mandatory || budget > 0) {
12687
+ kept.unshift(e);
12688
+ if (!mandatory) budget--;
12689
+ }
12690
+ }
12691
+ return kept;
12692
+ }, "boundedAudit");
12693
+ var validatePolicy = /* @__PURE__ */ __name((p) => {
12694
+ if (!p || typeof p !== "object" || Array.isArray(p)) throw new GovernancePolicyError("Governance policy must be an object");
12695
+ const r = p;
12696
+ if (!requiredText3(r.policyId)) throw new GovernancePolicyError("policyId is required");
12697
+ if (typeof r.version !== "number" || !Number.isInteger(r.version) || r.version < 1) throw new GovernancePolicyError("version must be a positive integer");
12698
+ if (!requiredText3(r.scope)) throw new GovernancePolicyError("scope is required");
12699
+ if (!requiredText3(r.rationale)) throw new GovernancePolicyError("rationale is required");
12700
+ if (!requiredText3(r.proposedBy)) throw new GovernancePolicyError("proposedBy is required");
12701
+ if (!requiredText3(r.proposedAt)) throw new GovernancePolicyError("proposedAt is required");
12702
+ if (typeof r.status !== "string" || !["proposed", "under_review", "approved", "active", "rejected", "suspended", "retired"].includes(r.status)) {
12703
+ throw new GovernancePolicyError("invalid status");
12704
+ }
12705
+ if (typeof r.revision !== "number" || !Number.isInteger(r.revision) || r.revision < 0) throw new GovernancePolicyError("revision must be a non-negative integer");
12706
+ if (!Array.isArray(r.applicablePrincipals)) throw new GovernancePolicyError("applicablePrincipals must be an array");
12707
+ if (!Array.isArray(r.applicableResources)) throw new GovernancePolicyError("applicableResources must be an array");
12708
+ const authority = validateAuthority(r.ownerAuthority);
12709
+ return {
12710
+ policyId: r.policyId,
12711
+ version: r.version,
12712
+ ...requiredText3(r.title) ? { title: r.title } : {},
12713
+ ...requiredText3(r.description) ? { description: r.description } : {},
12714
+ scope: r.scope,
12715
+ applicablePrincipals: r.applicablePrincipals,
12716
+ applicableResources: r.applicableResources,
12717
+ ...requiredText3(r.effectiveAt) ? { effectiveAt: r.effectiveAt } : {},
12718
+ ...requiredText3(r.expiresAt) ? { expiresAt: r.expiresAt } : {},
12719
+ rationale: r.rationale,
12720
+ status: r.status,
12721
+ ownerAuthority: authority,
12722
+ proposedBy: r.proposedBy,
12723
+ proposedAt: r.proposedAt,
12724
+ ...requiredText3(r.reviewedBy) ? { reviewedBy: r.reviewedBy } : {},
12725
+ ...requiredText3(r.reviewedAt) ? { reviewedAt: r.reviewedAt } : {},
12726
+ ...r.approval && typeof r.approval === "object" ? { approval: r.approval } : {},
12727
+ ...requiredText3(r.activatedBy) ? { activatedBy: r.activatedBy } : {},
12728
+ ...requiredText3(r.activatedAt) ? { activatedAt: r.activatedAt } : {},
12729
+ ...requiredText3(r.suspendedBy) ? { suspendedBy: r.suspendedBy } : {},
12730
+ ...requiredText3(r.suspendedAt) ? { suspendedAt: r.suspendedAt } : {},
12731
+ ...requiredText3(r.retiredBy) ? { retiredBy: r.retiredBy } : {},
12732
+ ...requiredText3(r.retiredAt) ? { retiredAt: r.retiredAt } : {},
12733
+ ...requiredText3(r.supersedes) ? { supersedes: r.supersedes } : {},
12734
+ ...requiredText3(r.supersededBy) ? { supersededBy: r.supersededBy } : {},
12735
+ ...requiredText3(r.correlationId) ? { correlationId: r.correlationId } : {},
12736
+ revision: r.revision,
12737
+ ...requiredText3(r.fingerprint) ? { fingerprint: r.fingerprint } : {}
12738
+ };
12739
+ }, "validatePolicy");
12740
+ var validateRoleBinding = /* @__PURE__ */ __name((rb) => {
12741
+ if (!rb || typeof rb !== "object" || Array.isArray(rb)) throw new GovernancePolicyError("role binding must be an object");
12742
+ const r = rb;
12743
+ if (!requiredText3(r.principalId)) throw new GovernancePolicyError("principalId is required");
12744
+ if (typeof r.role !== "string" || !["human-owner", "human-approver", "coordinator-jo", "specialist-agent", "policy-authority", "auditor-reviewer"].includes(r.role)) {
12745
+ throw new GovernancePolicyError("invalid role");
12746
+ }
12747
+ if (!requiredText3(r.scope)) throw new GovernancePolicyError("scope is required");
12748
+ return {
12749
+ principalId: r.principalId,
12750
+ role: r.role,
12751
+ scope: r.scope,
12752
+ ...requiredText3(r.grantedBy) ? { grantedBy: r.grantedBy } : {},
12753
+ ...requiredText3(r.grantedAt) ? { grantedAt: r.grantedAt } : {}
12754
+ };
12755
+ }, "validateRoleBinding");
12756
+ var validateDocument2 = /* @__PURE__ */ __name((value) => {
12757
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new GovernancePolicyError("document must be an object");
12758
+ const d = value;
12759
+ if (d.format !== GOVERNANCE_FORMAT) throw new GovernancePolicyError("invalid format");
12760
+ if (d.version !== GOVERNANCE_VERSION) throw new GovernancePolicyError("invalid version");
12761
+ if (typeof d.revision !== "number" || !Number.isInteger(d.revision) || d.revision < 0) throw new GovernancePolicyError("invalid revision");
12762
+ if (!Array.isArray(d.policies)) throw new GovernancePolicyError("policies must be an array");
12763
+ if (!Array.isArray(d.roleBindings)) throw new GovernancePolicyError("roleBindings must be an array");
12764
+ if (!Array.isArray(d.audit)) throw new GovernancePolicyError("audit must be an array");
12765
+ const policies = d.policies.map(validatePolicy);
12766
+ const roleBindings = d.roleBindings.map(validateRoleBinding);
12767
+ const audit = d.audit.map((e) => {
12768
+ if (!e || typeof e !== "object" || Array.isArray(e)) throw new GovernancePolicyError("audit entry must be an object");
12769
+ const r = e;
12770
+ if (!requiredText3(r.id)) throw new GovernancePolicyError("audit id required");
12771
+ if (!requiredText3(r.action)) throw new GovernancePolicyError("audit action required");
12772
+ if (!requiredText3(r.at)) throw new GovernancePolicyError("audit at required");
12773
+ if (r.outcome !== "applied" && r.outcome !== "rejected") throw new GovernancePolicyError("audit outcome invalid");
12774
+ return r;
12775
+ });
12776
+ return { format: GOVERNANCE_FORMAT, version: GOVERNANCE_VERSION, revision: d.revision, policies, roleBindings, audit };
12777
+ }, "validateDocument");
12778
+ var scopeCovers = /* @__PURE__ */ __name((bindingScope, targetScope) => {
12779
+ if (bindingScope === "*") return true;
12780
+ if (bindingScope === targetScope) return true;
12781
+ return targetScope.startsWith(bindingScope.endsWith("/") ? bindingScope : bindingScope + "/");
12782
+ }, "scopeCovers");
12783
+ var GovernancePolicyStore = class {
12784
+ constructor(directory) {
12785
+ this.directory = directory;
12786
+ }
12787
+ directory;
12788
+ static {
12789
+ __name(this, "GovernancePolicyStore");
12790
+ }
12791
+ dir() {
12792
+ return resolveGovernanceDir(this.directory);
12793
+ }
12794
+ filePath() {
12795
+ return resolveGovernanceFilePath(this.directory);
12796
+ }
12797
+ async load() {
12798
+ const fs = await import('fs/promises');
12799
+ let raw;
12800
+ try {
12801
+ raw = await fs.readFile(this.filePath(), "utf8");
12802
+ } catch (err2) {
12803
+ if (err2.code === "ENOENT") return emptyDocument2();
12804
+ throw err2;
12805
+ }
12806
+ return validateDocument2(JSON.parse(raw));
12807
+ }
12808
+ async readDoc(fs) {
12809
+ try {
12810
+ const raw = await fs.readFile(this.filePath(), "utf8");
12811
+ return validateDocument2(JSON.parse(raw));
12812
+ } catch (err2) {
12813
+ if (err2.code === "ENOENT") return emptyDocument2();
12814
+ throw err2;
12815
+ }
12816
+ }
12817
+ async writeDoc(fs, doc) {
12818
+ await fs.mkdir(this.dir(), { recursive: true });
12819
+ const fp = this.filePath();
12820
+ const tmp = `${fp}.${process.pid}.${Date.now().toString(36)}.tmp`;
12821
+ try {
12822
+ await fs.writeFile(tmp, `${JSON.stringify(doc, null, 2)}
12823
+ `, "utf8");
12824
+ const handle = await fs.open(tmp, "r+");
12825
+ try {
12826
+ await handle.sync();
12827
+ } finally {
12828
+ await handle.close();
12829
+ }
12830
+ await fs.rename(tmp, fp);
12831
+ } catch (err2) {
12832
+ await fs.rm(tmp, { force: true }).catch(() => void 0);
12833
+ throw err2;
12834
+ }
12835
+ }
12836
+ async mutate(operation, options = {}) {
12837
+ const directory = this.dir();
12838
+ return withPolicyNamespaceLock(async (session3) => {
12839
+ const fs = await import('fs/promises');
12840
+ const doc = await this.readDoc(fs);
12841
+ if (options.basedOnRevision !== void 0 && options.basedOnRevision !== doc.revision) {
12842
+ throw new GovernancePolicyError(`Stale governance revision: expected ${options.basedOnRevision}, current ${doc.revision}`);
12843
+ }
12844
+ const outcome = operation(doc);
12845
+ let next = outcome.document;
12846
+ validateDocument2(next);
12847
+ await session3.assertOwnership();
12848
+ await this.writeDoc(fs, next);
12849
+ return outcome.result;
12850
+ }, { directory });
12851
+ }
12852
+ // --- role helpers ---
12853
+ findRoleBinding(doc, principalId, scope) {
12854
+ const candidates = doc.roleBindings.filter((rb) => rb.principalId === principalId && scopeCovers(rb.scope, scope));
12855
+ if (candidates.length === 0) return null;
12856
+ return candidates.sort((a, b) => b.scope.length - a.scope.length)[0];
12857
+ }
12858
+ resolveRole(principalId, scope = "*") {
12859
+ return { principalId, role: null, scope, reason: "use resolveRoleAsync" };
12860
+ }
12861
+ async resolveRoleAsync(principalId, scope = "*") {
12862
+ const doc = await this.load();
12863
+ const rb = this.findRoleBinding(doc, principalId, scope);
12864
+ if (!rb) return { principalId, role: null, scope, reason: "no role binding for principal in scope" };
12865
+ return { principalId, role: rb.role, scope, reason: `bound role ${rb.role} (scope ${rb.scope})` };
12866
+ }
12867
+ async hasPermission(principalId, action, scope) {
12868
+ const res = await this.resolveRoleAsync(principalId, scope);
12869
+ if (!res.role) return false;
12870
+ return ROLE_CAPABILITIES[res.role].has(action);
12871
+ }
12872
+ // --- role binding governed ---
12873
+ async bindRole(input, basedOnRevision) {
12874
+ const authority = validateAuthority(input.authority);
12875
+ if (!requiredText3(input.principalId)) throw new GovernancePolicyError("principalId is required");
12876
+ if (!requiredText3(input.grantedBy)) throw new GovernancePolicyError("grantedBy is required");
12877
+ if (input.principalId === input.grantedBy && (input.role === "human-owner" || input.role === "human-approver" || input.role === "policy-authority")) {
12878
+ void detectSelfPromoted({ claim: `self-grant ${input.role}`, channel: "governance.role.bind" }).catch(() => void 0);
12879
+ throw new GovernancePolicyError("self-grant of elevated role denied");
12880
+ }
12881
+ const doc0 = await this.load();
12882
+ const grantedByRole = this.findRoleBinding(doc0, input.grantedBy, input.scope ?? "*");
12883
+ if (!grantedByRole || !ROLE_CAPABILITIES[grantedByRole.role].has("role.bind")) {
12884
+ throw new GovernancePolicyError("grantedBy lacks role.bind authority");
12885
+ }
12886
+ if (authority.kind !== "HI" && authority.kind !== "operator") {
12887
+ throw new GovernancePolicyError("invalid authority for role binding");
12888
+ }
12889
+ const binding = {
12890
+ principalId: input.principalId,
12891
+ role: input.role,
12892
+ scope: input.scope || "*",
12893
+ grantedBy: input.grantedBy,
12894
+ grantedAt: nowIso2()
12895
+ };
12896
+ return this.mutate((doc) => {
12897
+ const nextBindings = [...doc.roleBindings.filter((rb) => !(rb.principalId === binding.principalId && rb.scope === binding.scope)), binding];
12898
+ const revision = doc.revision + 1;
12899
+ const audit = boundedAudit2([...doc.audit, buildAudit({
12900
+ action: "role.bind",
12901
+ at: binding.grantedAt,
12902
+ actorPrincipal: input.grantedBy,
12903
+ actorRole: grantedByRole.role,
12904
+ scope: binding.scope,
12905
+ outcome: "applied",
12906
+ detail: `bound ${binding.principalId} to ${binding.role} in scope ${binding.scope}`,
12907
+ correlationId: void 0
12908
+ })]);
12909
+ return { document: { ...doc, revision, roleBindings: nextBindings, audit }, result: binding };
12910
+ }, { basedOnRevision });
12911
+ }
12912
+ // --- propose ---
12913
+ async propose(input, basedOnRevision) {
12914
+ if (!input || typeof input !== "object") throw new GovernancePolicyError("proposal input required");
12915
+ if (!requiredText3(input.scope)) throw new GovernancePolicyError("scope is required");
12916
+ if (!requiredText3(input.rationale)) throw new GovernancePolicyError("rationale is required");
12917
+ if (!requiredText3(input.proposedBy)) throw new GovernancePolicyError("proposedBy is required");
12918
+ const authority = validateAuthority(input.authority);
12919
+ const doc0 = await this.load();
12920
+ if (!await this.hasPermission(input.proposedBy, "policy.propose", input.scope)) {
12921
+ void detectAuthorityEscalationAttempt({ claimed: `${input.proposedBy} propose without permission`, channel: "governance.propose" }).catch(() => void 0);
12922
+ await this.recordDenial(doc0, "policy.propose", input.proposedBy, input.scope, "permission denied");
12923
+ throw new GovernancePolicyError("proposer lacks policy.propose permission");
12924
+ }
12925
+ const policyId = requiredText3(input.policyId) ? input.policyId : `gov-policy.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
12926
+ const existing = doc0.policies.filter((p) => p.policyId === policyId);
12927
+ const version = existing.length > 0 ? Math.max(...existing.map((p) => p.version)) + 1 : 1;
12928
+ const supersedes = input.supersedes;
12929
+ const policy2 = {
12930
+ policyId,
12931
+ version,
12932
+ ...requiredText3(input.title) ? { title: input.title } : {},
12933
+ ...requiredText3(input.description) ? { description: input.description } : {},
12934
+ scope: input.scope,
12935
+ applicablePrincipals: input.applicablePrincipals ?? [],
12936
+ applicableResources: input.applicableResources ?? [],
12937
+ ...requiredText3(input.effectiveAt) ? { effectiveAt: input.effectiveAt } : {},
12938
+ ...requiredText3(input.expiresAt) ? { expiresAt: input.expiresAt } : {},
12939
+ rationale: input.rationale,
12940
+ status: "proposed",
12941
+ ownerAuthority: authority,
12942
+ proposedBy: input.proposedBy,
12943
+ proposedAt: nowIso2(),
12944
+ ...requiredText3(supersedes) ? { supersedes } : {},
12945
+ ...requiredText3(input.correlationId) ? { correlationId: input.correlationId } : {},
12946
+ revision: 0
12947
+ };
12948
+ return this.mutate((doc) => {
12949
+ const revision = doc.revision + 1;
12950
+ const fingerprint = `${policy2.policyId}@v${policy2.version}`;
12951
+ const stored = { ...policy2, revision, fingerprint };
12952
+ const policies = [...doc.policies, stored];
12953
+ const audit = boundedAudit2([...doc.audit, buildAudit({
12954
+ action: "policy.proposed",
12955
+ at: stored.proposedAt,
12956
+ actorPrincipal: input.proposedBy,
12957
+ targetPolicyId: stored.policyId,
12958
+ targetVersion: stored.version,
12959
+ scope: stored.scope,
12960
+ outcome: "applied",
12961
+ detail: `policy ${stored.policyId} v${stored.version} proposed`,
12962
+ correlationId: input.correlationId
12963
+ })]);
12964
+ return { document: { ...doc, revision, policies, audit }, result: stored };
12965
+ }, { basedOnRevision });
12966
+ }
12967
+ async recordDenial(doc, action, actor, scope, reason) {
12968
+ try {
12969
+ await this.mutate((d) => {
12970
+ const revision = d.revision + 1;
12971
+ const audit = boundedAudit2([...d.audit, buildAudit({
12972
+ action: `${action}.denied`,
12973
+ at: nowIso2(),
12974
+ actorPrincipal: actor,
12975
+ scope,
12976
+ outcome: "rejected",
12977
+ reason
12978
+ })]);
12979
+ return { document: { ...d, revision, audit }, result: void 0 };
12980
+ });
12981
+ } catch {
12982
+ }
12983
+ }
12984
+ // --- review ---
12985
+ async review(input) {
12986
+ if (!input || !requiredText3(input.policyId)) throw new GovernancePolicyError("policyId is required");
12987
+ if (typeof input.version !== "number") throw new GovernancePolicyError("version is required");
12988
+ if (!requiredText3(input.reviewerPrincipal)) throw new GovernancePolicyError("reviewerPrincipal is required");
12989
+ const doc0 = await this.load();
12990
+ if (!await this.hasPermission(input.reviewerPrincipal, "policy.review", "*")) {
12991
+ const pol = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
12992
+ const scope = pol?.scope ?? "*";
12993
+ if (!await this.hasPermission(input.reviewerPrincipal, "policy.review", scope)) {
12994
+ await this.recordDenial(doc0, "policy.review", input.reviewerPrincipal, scope, "permission denied");
12995
+ throw new GovernancePolicyError("reviewer lacks policy.review permission");
12996
+ }
12997
+ }
12998
+ const policy2 = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
12999
+ if (!policy2) throw new GovernancePolicyError("policy not found");
13000
+ if (policy2.status !== "proposed") throw new GovernancePolicyError(`cannot review policy in status ${policy2.status}`);
13001
+ return this.mutate((doc) => {
13002
+ const idx = doc.policies.findIndex((p) => p.policyId === input.policyId && p.version === input.version);
13003
+ if (idx < 0) throw new GovernancePolicyError("policy not found");
13004
+ const updated = {
13005
+ ...doc.policies[idx],
13006
+ status: "under_review",
13007
+ reviewedBy: input.reviewerPrincipal,
13008
+ reviewedAt: nowIso2()
13009
+ };
13010
+ const policies = [...doc.policies];
13011
+ policies[idx] = updated;
13012
+ const revision = doc.revision + 1;
13013
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13014
+ action: "policy.reviewed",
13015
+ at: updated.reviewedAt,
13016
+ actorPrincipal: input.reviewerPrincipal,
13017
+ targetPolicyId: updated.policyId,
13018
+ targetVersion: updated.version,
13019
+ scope: updated.scope,
13020
+ outcome: "applied",
13021
+ correlationId: input.correlationId
13022
+ })]);
13023
+ return { document: { ...doc, revision, policies, audit }, result: updated };
13024
+ });
13025
+ }
13026
+ // --- decide (approve/reject) ---
13027
+ async decide(input) {
13028
+ if (!input || !requiredText3(input.policyId)) throw new GovernancePolicyError("policyId is required");
13029
+ if (typeof input.version !== "number") throw new GovernancePolicyError("version is required");
13030
+ if (!requiredText3(input.approverPrincipal)) throw new GovernancePolicyError("approverPrincipal is required");
13031
+ if (input.decision !== "approved" && input.decision !== "rejected") throw new GovernancePolicyError("decision must be approved or rejected");
13032
+ const doc0 = await this.load();
13033
+ const policy2 = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
13034
+ if (!policy2) throw new GovernancePolicyError("policy not found");
13035
+ const scope = policy2.scope;
13036
+ const action = input.decision === "approved" ? "policy.approve" : "policy.reject";
13037
+ if (!await this.hasPermission(input.approverPrincipal, "policy.approve", scope) && !await this.hasPermission(input.approverPrincipal, "policy.reject", scope)) {
13038
+ if (!await this.hasPermission(input.approverPrincipal, "policy.approve", scope)) {
13039
+ await this.recordDenial(doc0, action, input.approverPrincipal, scope, "permission denied");
13040
+ throw new GovernancePolicyError("approver lacks approval permission");
13041
+ }
13042
+ }
13043
+ if (input.approverPrincipal === policy2.proposedBy) {
13044
+ void detectSelfPromoted({ claim: `self-approval ${policy2.policyId}`, channel: "governance.approve" }).catch(() => void 0);
13045
+ await this.recordDenial(doc0, action, input.approverPrincipal, scope, "self-approval denied");
13046
+ throw new GovernancePolicyError("self-approval denied: proposer cannot be sole approver");
13047
+ }
13048
+ if (policy2.status !== "under_review" && policy2.status !== "proposed") {
13049
+ throw new GovernancePolicyError(`cannot decide policy in status ${policy2.status}`);
13050
+ }
13051
+ return this.mutate((doc) => {
13052
+ const idx = doc.policies.findIndex((p) => p.policyId === input.policyId && p.version === input.version);
13053
+ if (idx < 0) throw new GovernancePolicyError("policy not found");
13054
+ const current = doc.policies[idx];
13055
+ const newStatus = input.decision === "approved" ? "approved" : "rejected";
13056
+ const updated = {
13057
+ ...current,
13058
+ status: newStatus,
13059
+ approval: {
13060
+ approverPrincipal: input.approverPrincipal,
13061
+ decision: input.decision,
13062
+ ...requiredText3(input.reason) ? { reason: input.reason } : {},
13063
+ at: nowIso2()
13064
+ }
13065
+ };
13066
+ const policies = [...doc.policies];
13067
+ policies[idx] = updated;
13068
+ const revision = doc.revision + 1;
13069
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13070
+ action: input.decision === "approved" ? "policy.approved" : "policy.rejected",
13071
+ at: updated.approval.at,
13072
+ actorPrincipal: input.approverPrincipal,
13073
+ targetPolicyId: updated.policyId,
13074
+ targetVersion: updated.version,
13075
+ scope: updated.scope,
13076
+ outcome: "applied",
13077
+ reason: input.reason,
13078
+ correlationId: input.correlationId
13079
+ })]);
13080
+ return { document: { ...doc, revision, policies, audit }, result: updated };
13081
+ });
13082
+ }
13083
+ // --- activate ---
13084
+ async activate(input) {
13085
+ if (!input || !requiredText3(input.policyId)) throw new GovernancePolicyError("policyId is required");
13086
+ if (typeof input.version !== "number") throw new GovernancePolicyError("version is required");
13087
+ if (!requiredText3(input.activatorPrincipal)) throw new GovernancePolicyError("activatorPrincipal is required");
13088
+ const doc0 = await this.load();
13089
+ const policy2 = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
13090
+ if (!policy2) throw new GovernancePolicyError("policy not found");
13091
+ if (policy2.status !== "approved") throw new GovernancePolicyError(`cannot activate policy in status ${policy2.status}`);
13092
+ const scope = policy2.scope;
13093
+ if (!await this.hasPermission(input.activatorPrincipal, "policy.activate", scope)) {
13094
+ await this.recordDenial(doc0, "policy.activate", input.activatorPrincipal, scope, "permission denied");
13095
+ throw new GovernancePolicyError("activator lacks policy.activate permission");
13096
+ }
13097
+ const now3 = /* @__PURE__ */ new Date();
13098
+ if (policy2.effectiveAt && Date.parse(policy2.effectiveAt) > now3.getTime()) {
13099
+ throw new GovernancePolicyError("policy not yet effective");
13100
+ }
13101
+ if (policy2.expiresAt && Date.parse(policy2.expiresAt) <= now3.getTime()) {
13102
+ throw new GovernancePolicyError("policy expired");
13103
+ }
13104
+ return this.mutate((doc) => {
13105
+ const idx = doc.policies.findIndex((p) => p.policyId === input.policyId && p.version === input.version);
13106
+ if (idx < 0) throw new GovernancePolicyError("policy not found");
13107
+ const current = doc.policies[idx];
13108
+ if (current.status !== "approved") throw new GovernancePolicyError(`cannot activate policy in status ${current.status}`);
13109
+ const policies = doc.policies.map((p) => {
13110
+ if (p.policyId === current.policyId && p.version !== current.version && p.status === "active") {
13111
+ return { ...p, status: "retired", retiredBy: input.activatorPrincipal, retiredAt: nowIso2(), supersededBy: `${current.policyId}@v${current.version}` };
13112
+ }
13113
+ return p;
13114
+ });
13115
+ const nowStr = nowIso2();
13116
+ policies[idx] = {
13117
+ ...current,
13118
+ status: "active",
13119
+ activatedBy: input.activatorPrincipal,
13120
+ activatedAt: nowStr
13121
+ };
13122
+ const updated = policies[idx];
13123
+ const revision = doc.revision + 1;
13124
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13125
+ action: "policy.activated",
13126
+ at: nowStr,
13127
+ actorPrincipal: input.activatorPrincipal,
13128
+ targetPolicyId: updated.policyId,
13129
+ targetVersion: updated.version,
13130
+ scope: updated.scope,
13131
+ outcome: "applied",
13132
+ correlationId: input.correlationId
13133
+ })]);
13134
+ return { document: { ...doc, revision, policies, audit }, result: updated };
13135
+ });
13136
+ }
13137
+ async suspend(input) {
13138
+ if (!input || !requiredText3(input.policyId)) throw new GovernancePolicyError("policyId is required");
13139
+ if (typeof input.version !== "number") throw new GovernancePolicyError("version is required");
13140
+ if (!requiredText3(input.actorPrincipal)) throw new GovernancePolicyError("actorPrincipal is required");
13141
+ const doc0 = await this.load();
13142
+ const policy2 = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
13143
+ if (!policy2) throw new GovernancePolicyError("policy not found");
13144
+ const scope = policy2.scope;
13145
+ if (!await this.hasPermission(input.actorPrincipal, "policy.suspend", scope)) {
13146
+ const role = await this.resolveRoleAsync(input.actorPrincipal, scope);
13147
+ if (role.role !== "human-owner" && role.role !== "human-approver") {
13148
+ await this.recordDenial(doc0, "policy.suspend", input.actorPrincipal, scope, "permission denied");
13149
+ throw new GovernancePolicyError("actor lacks suspend permission");
13150
+ }
13151
+ }
13152
+ return this.mutate((doc) => {
13153
+ const idx = doc.policies.findIndex((p) => p.policyId === input.policyId && p.version === input.version);
13154
+ if (idx < 0) throw new GovernancePolicyError("policy not found");
13155
+ const current = doc.policies[idx];
13156
+ if (current.status !== "active" && current.status !== "approved") throw new GovernancePolicyError(`cannot suspend policy in status ${current.status}`);
13157
+ const updated = {
13158
+ ...current,
13159
+ status: "suspended",
13160
+ suspendedBy: input.actorPrincipal,
13161
+ suspendedAt: nowIso2()
13162
+ };
13163
+ const policies = [...doc.policies];
13164
+ policies[idx] = updated;
13165
+ const revision = doc.revision + 1;
13166
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13167
+ action: "policy.suspended",
13168
+ at: updated.suspendedAt,
13169
+ actorPrincipal: input.actorPrincipal,
13170
+ targetPolicyId: updated.policyId,
13171
+ targetVersion: updated.version,
13172
+ scope: updated.scope,
13173
+ outcome: "applied",
13174
+ reason: input.reason,
13175
+ correlationId: input.correlationId
13176
+ })]);
13177
+ return { document: { ...doc, revision, policies, audit }, result: updated };
13178
+ });
13179
+ }
13180
+ async retire(input) {
13181
+ if (!input || !requiredText3(input.policyId)) throw new GovernancePolicyError("policyId is required");
13182
+ if (typeof input.version !== "number") throw new GovernancePolicyError("version is required");
13183
+ if (!requiredText3(input.actorPrincipal)) throw new GovernancePolicyError("actorPrincipal is required");
13184
+ const doc0 = await this.load();
13185
+ const policy2 = doc0.policies.find((p) => p.policyId === input.policyId && p.version === input.version);
13186
+ if (!policy2) throw new GovernancePolicyError("policy not found");
13187
+ const scope = policy2.scope;
13188
+ const role = await this.resolveRoleAsync(input.actorPrincipal, scope);
13189
+ if (role.role !== "human-owner" && role.role !== "human-approver") {
13190
+ await this.recordDenial(doc0, "policy.retire", input.actorPrincipal, scope, "permission denied");
13191
+ throw new GovernancePolicyError("actor lacks retire permission");
13192
+ }
13193
+ return this.mutate((doc) => {
13194
+ const idx = doc.policies.findIndex((p) => p.policyId === input.policyId && p.version === input.version);
13195
+ if (idx < 0) throw new GovernancePolicyError("policy not found");
13196
+ const current = doc.policies[idx];
13197
+ const updated = {
13198
+ ...current,
13199
+ status: "retired",
13200
+ retiredBy: input.actorPrincipal,
13201
+ retiredAt: nowIso2()
13202
+ };
13203
+ const policies = [...doc.policies];
13204
+ policies[idx] = updated;
13205
+ const revision = doc.revision + 1;
13206
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13207
+ action: "policy.retired",
13208
+ at: updated.retiredAt,
13209
+ actorPrincipal: input.actorPrincipal,
13210
+ targetPolicyId: updated.policyId,
13211
+ targetVersion: updated.version,
13212
+ scope: updated.scope,
13213
+ outcome: "applied",
13214
+ reason: input.reason,
13215
+ correlationId: input.correlationId
13216
+ })]);
13217
+ return { document: { ...doc, revision, policies, audit }, result: updated };
13218
+ });
13219
+ }
13220
+ // --- resolution (fail-closed) ---
13221
+ async resolvePolicy(policyId, version, requestedScope, now3 = /* @__PURE__ */ new Date()) {
13222
+ const doc = await this.load();
13223
+ const policy2 = doc.policies.find((p) => p.policyId === policyId && p.version === version);
13224
+ if (!policy2) {
13225
+ return { outcome: "none", policy: null, reason: "no applicable policy" };
13226
+ }
13227
+ if (!scopeCovers(policy2.scope, requestedScope)) {
13228
+ return { outcome: "insufficient-scope", policy: null, reason: "policy scope does not cover requested scope" };
13229
+ }
13230
+ if (!policy2.ownerAuthority || policy2.ownerAuthority.kind !== "HI" && policy2.ownerAuthority.kind !== "operator") {
13231
+ return { outcome: "unresolved-authority", policy: null, reason: "unresolved or invalid authority" };
13232
+ }
13233
+ if (policy2.effectiveAt && Date.parse(policy2.effectiveAt) > now3.getTime()) {
13234
+ return { outcome: "not-yet-effective", policy: null, reason: "policy not yet effective" };
13235
+ }
13236
+ if (policy2.expiresAt && Date.parse(policy2.expiresAt) <= now3.getTime()) {
13237
+ return { outcome: "expired", policy: null, reason: "policy expired" };
13238
+ }
13239
+ if (policy2.status !== "active") {
13240
+ return { outcome: "none", policy: null, reason: `policy status ${policy2.status} is not active` };
13241
+ }
13242
+ if (policy2.fingerprint && policy2.fingerprint !== `${policy2.policyId}@v${policy2.version}`) {
13243
+ return { outcome: "invalid-provenance", policy: null, reason: "fingerprint mismatch" };
13244
+ }
13245
+ return { outcome: "applicable", policy: policy2, reason: "applicable and valid" };
13246
+ }
13247
+ async resolveActivePolicies(scope, now3 = /* @__PURE__ */ new Date()) {
13248
+ const doc = await this.load();
13249
+ const active = doc.policies.filter((p) => p.status === "active" && scopeCovers(p.scope, scope));
13250
+ return active.filter((p) => {
13251
+ if (p.effectiveAt && Date.parse(p.effectiveAt) > now3.getTime()) return false;
13252
+ if (p.expiresAt && Date.parse(p.expiresAt) <= now3.getTime()) return false;
13253
+ return true;
13254
+ });
13255
+ }
13256
+ async checkConflicts(scope, now3 = /* @__PURE__ */ new Date()) {
13257
+ const actives = await this.resolveActivePolicies(scope, now3);
13258
+ const conflicting = actives.length > 1;
13259
+ return { conflicting, policies: actives };
13260
+ }
13261
+ async failClosedResolve(scope, now3 = /* @__PURE__ */ new Date()) {
13262
+ const actives = await this.resolveActivePolicies(scope, now3);
13263
+ if (actives.length === 0) {
13264
+ return { outcome: "none", policy: null, reason: "no applicable policy" };
13265
+ }
13266
+ if (actives.length > 1) {
13267
+ return { outcome: "conflicting", policy: null, reason: "conflicting active policies" };
13268
+ }
13269
+ const p = actives[0];
13270
+ if (!p.ownerAuthority || p.ownerAuthority.kind !== "HI" && p.ownerAuthority.kind !== "operator") {
13271
+ return { outcome: "unresolved-authority", policy: null, reason: "unresolved authority" };
13272
+ }
13273
+ return { outcome: "applicable", policy: p, reason: "applicable and valid" };
13274
+ }
13275
+ // --- authorization granted/denied audit ---
13276
+ async recordAuthorization(decision) {
13277
+ await this.mutate((doc) => {
13278
+ const revision = doc.revision + 1;
13279
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13280
+ action: decision.allowed ? "authorization.granted" : "authorization.denied",
13281
+ at: nowIso2(),
13282
+ actorPrincipal: decision.principalId,
13283
+ scope: decision.scope ?? decision.resource,
13284
+ outcome: decision.allowed ? "applied" : "rejected",
13285
+ reason: decision.reason,
13286
+ detail: `${decision.action} on ${decision.resource}`,
13287
+ correlationId: decision.correlationId
13288
+ })]);
13289
+ return { document: { ...doc, revision, audit }, result: void 0 };
13290
+ });
13291
+ }
13292
+ // --- list ---
13293
+ async listPolicies() {
13294
+ const doc = await this.load();
13295
+ return [...doc.policies].sort((a, b) => a.policyId.localeCompare(b.policyId) || a.version - b.version);
13296
+ }
13297
+ async listRoleBindings() {
13298
+ const doc = await this.load();
13299
+ return [...doc.roleBindings];
13300
+ }
13301
+ async auditTrail() {
13302
+ const doc = await this.load();
13303
+ return [...doc.audit];
13304
+ }
13305
+ async recordAuditEvent(input) {
13306
+ await this.mutate((doc) => {
13307
+ const revision = doc.revision + 1;
13308
+ const audit = boundedAudit2([...doc.audit, buildAudit({
13309
+ action: input.action,
13310
+ at: input.at ?? nowIso2(),
13311
+ ...input.actorPrincipal !== void 0 ? { actorPrincipal: input.actorPrincipal } : {},
13312
+ ...input.actorRole !== void 0 ? { actorRole: input.actorRole } : {},
13313
+ ...input.targetPolicyId !== void 0 ? { targetPolicyId: input.targetPolicyId } : {},
13314
+ ...input.targetVersion !== void 0 ? { targetVersion: input.targetVersion } : {},
13315
+ ...input.scope !== void 0 ? { scope: input.scope } : {},
13316
+ outcome: input.outcome,
13317
+ ...input.reason !== void 0 ? { reason: input.reason } : {},
13318
+ ...input.detail !== void 0 ? { detail: input.detail } : {},
13319
+ ...input.correlationId !== void 0 ? { correlationId: input.correlationId } : {},
13320
+ ...input.mandatory !== void 0 ? { mandatory: input.mandatory } : {}
13321
+ })]);
13322
+ return { document: { ...doc, revision, audit }, result: void 0 };
13323
+ });
13324
+ }
13325
+ };
13326
+ var roleHasPermission = /* @__PURE__ */ __name((role, action) => ROLE_CAPABILITIES[role].has(action), "roleHasPermission");
13327
+ var GOVERNANCE_ROLES = [
13328
+ "human-owner",
13329
+ "human-approver",
13330
+ "coordinator-jo",
13331
+ "specialist-agent",
13332
+ "policy-authority",
13333
+ "auditor-reviewer"
13334
+ ];
13335
+ var GOVERNANCE_POLICY_STATUSES = [
13336
+ "proposed",
13337
+ "under_review",
13338
+ "approved",
13339
+ "active",
13340
+ "rejected",
13341
+ "suspended",
13342
+ "retired"
13343
+ ];
13344
+
13345
+ // core/guardrails/index.ts
13346
+ init_user_paths();
13347
+ init_policy_namespace_lock();
13348
+ var STOP_FILE_NAME = "guardrails.stop.json";
13349
+ var STOP_FORMAT = "dotmem.guardrails-stop";
13350
+ var STOP_VERSION = 1;
13351
+ var GuardrailError = class extends Error {
13352
+ static {
13353
+ __name(this, "GuardrailError");
13354
+ }
13355
+ constructor(message) {
13356
+ super(message);
13357
+ this.name = "GuardrailError";
13358
+ }
13359
+ };
13360
+ var requiredText4 = /* @__PURE__ */ __name((v) => typeof v === "string" && v.trim().length > 0, "requiredText");
13361
+ var nowIso3 = /* @__PURE__ */ __name(() => (/* @__PURE__ */ new Date()).toISOString(), "nowIso");
13362
+ var joinPath8 = /* @__PURE__ */ __name((base, child) => {
13363
+ const sep = process.platform === "win32" ? "\\" : "/";
13364
+ return `${base.replace(/[\\/]+/g, sep)}${sep}${child}`;
13365
+ }, "joinPath");
13366
+ var resolveGuardrailDir = /* @__PURE__ */ __name((directory) => directory ?? joinPath8(resolveUserDotMemPath(), "policy"), "resolveGuardrailDir");
13367
+ var resolveStopFilePath = /* @__PURE__ */ __name((directory) => joinPath8(resolveGuardrailDir(directory), STOP_FILE_NAME), "resolveStopFilePath");
13368
+ var ACTIONS_REQUIRING_TRUSTED_IDENTITY = /* @__PURE__ */ new Set([
13369
+ "agent.execute",
13370
+ "guardrail.stop.activate",
13371
+ "guardrail.stop.release"
13372
+ ]);
13373
+ var GuardrailService = class {
13374
+ static {
13375
+ __name(this, "GuardrailService");
13376
+ }
13377
+ directory;
13378
+ governance;
13379
+ constructor(directory, governance) {
13380
+ this.directory = directory;
13381
+ this.governance = governance ?? new GovernancePolicyStore(directory);
13382
+ }
13383
+ dir() {
13384
+ return resolveGuardrailDir(this.directory);
13385
+ }
13386
+ // --- stop controller persistence ---
13387
+ async readStopState() {
13388
+ const fs = await import('fs/promises');
13389
+ let raw;
13390
+ try {
13391
+ raw = await fs.readFile(resolveStopFilePath(this.directory), "utf8");
13392
+ } catch (err2) {
13393
+ if (err2.code === "ENOENT") {
13394
+ return { stopped: false, revision: 0 };
13395
+ }
13396
+ throw err2;
13397
+ }
13398
+ const parsed = JSON.parse(raw);
13399
+ if (parsed.format !== STOP_FORMAT || parsed.version !== STOP_VERSION) {
13400
+ throw new GuardrailError("invalid stop state document");
13401
+ }
13402
+ return {
13403
+ stopped: parsed.stopped === true,
13404
+ ...requiredText4(parsed.activatedBy) ? { activatedBy: parsed.activatedBy } : {},
13405
+ ...requiredText4(parsed.activatedAt) ? { activatedAt: parsed.activatedAt } : {},
13406
+ ...requiredText4(parsed.reason) ? { reason: parsed.reason } : {},
13407
+ ...requiredText4(parsed.releasedBy) ? { releasedBy: parsed.releasedBy } : {},
13408
+ ...requiredText4(parsed.releasedAt) ? { releasedAt: parsed.releasedAt } : {},
13409
+ revision: typeof parsed.revision === "number" ? parsed.revision : 0
13410
+ };
13411
+ }
13412
+ async writeStopState(state3) {
13413
+ const fs = await import('fs/promises');
13414
+ const dir = this.dir();
13415
+ await fs.mkdir(dir, { recursive: true });
13416
+ const fp = resolveStopFilePath(this.directory);
13417
+ const tmp = `${fp}.${process.pid}.${Date.now().toString(36)}.tmp`;
13418
+ const doc = { format: STOP_FORMAT, version: STOP_VERSION, ...state3 };
13419
+ try {
13420
+ await fs.writeFile(tmp, `${JSON.stringify(doc, null, 2)}
13421
+ `, "utf8");
13422
+ const handle = await fs.open(tmp, "r+");
13423
+ try {
13424
+ await handle.sync();
13425
+ } finally {
13426
+ await handle.close();
13427
+ }
13428
+ await fs.rename(tmp, fp);
13429
+ } catch (err2) {
13430
+ await fs.rm(tmp, { force: true }).catch(() => void 0);
13431
+ throw err2;
13432
+ }
13433
+ }
13434
+ async getStopState() {
13435
+ return this.readStopState();
13436
+ }
13437
+ async isStopped() {
13438
+ const s = await this.readStopState();
13439
+ return s.stopped;
13440
+ }
13441
+ async activateStop(input) {
13442
+ if (!requiredText4(input.actorPrincipal)) throw new GuardrailError("actorPrincipal is required");
13443
+ const role = await this.governance.resolveRoleAsync(input.actorPrincipal, "*");
13444
+ if (role.role !== "human-owner" && role.role !== "human-approver") {
13445
+ await this.governance.recordAuditEvent({
13446
+ action: "guardrail.stop.activate.denied",
13447
+ actorPrincipal: input.actorPrincipal,
13448
+ actorRole: role.role ?? void 0,
13449
+ outcome: "rejected",
13450
+ reason: "insufficient authority to activate stop",
13451
+ correlationId: input.correlationId
13452
+ }).catch(() => void 0);
13453
+ throw new GuardrailError("unauthorized stop activation");
13454
+ }
13455
+ const current = await this.readStopState();
13456
+ if (current.stopped) {
13457
+ await this.governance.recordAuditEvent({
13458
+ action: "guardrail.stop.activate",
13459
+ actorPrincipal: input.actorPrincipal,
13460
+ actorRole: role.role ?? void 0,
13461
+ outcome: "applied",
13462
+ reason: "already stopped (idempotent)",
13463
+ correlationId: input.correlationId
13464
+ }).catch(() => void 0);
13465
+ return current;
13466
+ }
13467
+ const now3 = nowIso3();
13468
+ const next = {
13469
+ stopped: true,
13470
+ activatedBy: input.actorPrincipal,
13471
+ activatedAt: now3,
13472
+ ...requiredText4(input.reason) ? { reason: input.reason } : {},
13473
+ revision: current.revision + 1
13474
+ };
13475
+ await this.governance.recordAuditEvent({
13476
+ action: "guardrail.stop.activated",
13477
+ actorPrincipal: input.actorPrincipal,
13478
+ actorRole: role.role ?? void 0,
13479
+ outcome: "applied",
13480
+ reason: input.reason,
13481
+ correlationId: input.correlationId
13482
+ });
13483
+ await withPolicyNamespaceLock(async (session3) => {
13484
+ await this.writeStopState(next);
13485
+ await session3.assertOwnership();
13486
+ }, { directory: this.dir() });
13487
+ return next;
13488
+ }
13489
+ async releaseStop(input) {
13490
+ if (!requiredText4(input.actorPrincipal)) throw new GuardrailError("actorPrincipal is required");
13491
+ const role = await this.governance.resolveRoleAsync(input.actorPrincipal, "*");
13492
+ if (role.role !== "human-owner" && role.role !== "human-approver") {
13493
+ await this.governance.recordAuditEvent({
13494
+ action: "guardrail.stop.release.denied",
13495
+ actorPrincipal: input.actorPrincipal,
13496
+ actorRole: role.role ?? void 0,
13497
+ outcome: "rejected",
13498
+ reason: "insufficient authority to release stop",
13499
+ correlationId: input.correlationId
13500
+ }).catch(() => void 0);
13501
+ throw new GuardrailError("unauthorized stop release");
13502
+ }
13503
+ const current = await this.readStopState();
13504
+ if (!current.stopped) {
13505
+ await this.governance.recordAuditEvent({
13506
+ action: "guardrail.stop.release",
13507
+ actorPrincipal: input.actorPrincipal,
13508
+ actorRole: role.role ?? void 0,
13509
+ outcome: "applied",
13510
+ reason: "already running (idempotent)",
13511
+ correlationId: input.correlationId
13512
+ }).catch(() => void 0);
13513
+ return current;
13514
+ }
13515
+ const now3 = nowIso3();
13516
+ const next = {
13517
+ stopped: false,
13518
+ activatedBy: current.activatedBy,
13519
+ activatedAt: current.activatedAt,
13520
+ reason: current.reason,
13521
+ releasedBy: input.actorPrincipal,
13522
+ releasedAt: now3,
13523
+ revision: current.revision + 1
13524
+ };
13525
+ await this.governance.recordAuditEvent({
13526
+ action: "guardrail.stop.released",
13527
+ actorPrincipal: input.actorPrincipal,
13528
+ actorRole: role.role ?? void 0,
13529
+ outcome: "applied",
13530
+ reason: input.reason,
13531
+ correlationId: input.correlationId
13532
+ });
13533
+ await withPolicyNamespaceLock(async (session3) => {
13534
+ await this.writeStopState(next);
13535
+ await session3.assertOwnership();
13536
+ }, { directory: this.dir() });
13537
+ return next;
13538
+ }
13539
+ auditModes = {
13540
+ "agent.execute": "mandatory",
13541
+ "guardrail.stop.activate": "mandatory",
13542
+ "guardrail.stop.release": "mandatory"
13543
+ };
13544
+ auditModeFor(action) {
13545
+ return this.auditModes[action] ?? "best_effort";
13546
+ }
13547
+ async recordAudit(decision, auditMode) {
13548
+ const persisted = await this.auditDecision(decision);
13549
+ decision.auditPersisted = persisted;
13550
+ decision.auditMode = auditMode;
13551
+ if (!persisted && auditMode === "mandatory" && decision.allowed) {
13552
+ decision.outcome = "audit_failure";
13553
+ decision.allowed = false;
13554
+ decision.reason = "mandatory audit persistence failed";
13555
+ }
13556
+ return persisted;
13557
+ }
13558
+ // --- evaluation ---
13559
+ async evaluate(input) {
13560
+ const evaluatedAt = nowIso3();
13561
+ const auditMode = this.auditModeFor(input.action);
13562
+ const principalId = input.principalContext.trusted ? input.principalContext.trustedPrincipalId : input.principalContext.assertedPrincipalId;
13563
+ const stopState = await this.readStopState().catch(() => ({ stopped: false, revision: 0 }));
13564
+ const base = {
13565
+ outcome: "deny",
13566
+ allowed: false,
13567
+ reason: "",
13568
+ evaluatedAt,
13569
+ principalId,
13570
+ action: input.action,
13571
+ resource: input.resource,
13572
+ scope: input.scope,
13573
+ phase: input.phase,
13574
+ stopState: stopState.stopped ? "stopped" : "running",
13575
+ correlationId: input.correlationId,
13576
+ auditMode,
13577
+ auditPersisted: false
13578
+ };
13579
+ if (stopState.stopped && input.action !== "guardrail.stop.release") {
13580
+ const decision2 = { ...base, outcome: "stop_active", reason: "global stop active" };
13581
+ await this.recordAudit(decision2, auditMode);
13582
+ return decision2;
13583
+ }
13584
+ const requiresTrusted = ACTIONS_REQUIRING_TRUSTED_IDENTITY.has(input.action);
13585
+ if (requiresTrusted && !input.principalContext.trusted) {
13586
+ const decision2 = { ...base, outcome: "identity_unverified", reason: "trusted identity required but not verified" };
13587
+ await this.recordAudit(decision2, auditMode);
13588
+ return decision2;
13589
+ }
13590
+ if (!requiredText4(input.action) || !requiredText4(input.resource) || !requiredText4(input.scope)) {
13591
+ const decision2 = { ...base, outcome: "invalid_context", reason: "missing action/resource/scope" };
13592
+ await this.recordAudit(decision2, auditMode);
13593
+ return decision2;
13594
+ }
13595
+ let policyId;
13596
+ let policyVersion;
13597
+ try {
13598
+ const resolution = await this.governance.failClosedResolve(input.scope, input.now ?? /* @__PURE__ */ new Date());
13599
+ if (resolution.outcome !== "applicable" || !resolution.policy) {
13600
+ const decision2 = {
13601
+ ...base,
13602
+ outcome: resolution.outcome === "conflicting" ? "deny" : "policy_unavailable",
13603
+ reason: `policy resolution: ${resolution.outcome} - ${resolution.reason}`
13604
+ };
13605
+ await this.recordAudit(decision2, auditMode);
13606
+ return decision2;
13607
+ }
13608
+ policyId = resolution.policy.policyId;
13609
+ policyVersion = resolution.policy.version;
13610
+ const actorForPermission = principalId ?? "";
13611
+ const allowed = await this.governance.hasPermission(actorForPermission, input.action, input.scope);
13612
+ if (!allowed) {
13613
+ const decision2 = {
13614
+ ...base,
13615
+ outcome: "deny",
13616
+ reason: "permission denied by governance role binding",
13617
+ policyId,
13618
+ policyVersion
13619
+ };
13620
+ await this.recordAudit(decision2, auditMode);
13621
+ return decision2;
13622
+ }
13623
+ } catch (err2) {
13624
+ const decision2 = {
13625
+ ...base,
13626
+ outcome: "policy_unavailable",
13627
+ reason: `governance unavailable: ${err2.message}`
13628
+ };
13629
+ await this.recordAudit(decision2, auditMode);
13630
+ return decision2;
13631
+ }
13632
+ const decision = {
13633
+ ...base,
13634
+ outcome: "allow",
13635
+ allowed: true,
13636
+ reason: "allowed by governance policy",
13637
+ policyId,
13638
+ policyVersion
13639
+ };
13640
+ await this.recordAudit(decision, auditMode);
13641
+ return decision;
13642
+ }
13643
+ async auditDecision(decision) {
13644
+ try {
13645
+ await this.governance.recordAuditEvent({
13646
+ action: decision.allowed ? "guardrail.evaluation.allowed" : "guardrail.evaluation.denied",
13647
+ actorPrincipal: decision.principalId,
13648
+ scope: decision.scope,
13649
+ outcome: decision.allowed ? "applied" : "rejected",
13650
+ reason: decision.reason,
13651
+ detail: `${decision.action} on ${decision.resource} (${decision.outcome})`,
13652
+ correlationId: decision.correlationId,
13653
+ mandatory: decision.auditMode === "mandatory"
13654
+ });
13655
+ return true;
13656
+ } catch {
13657
+ return false;
13658
+ }
13659
+ }
13660
+ async execute(input, operation) {
13661
+ const decision = await this.evaluate(input);
13662
+ if (!decision.allowed) {
13663
+ return { decision, executed: false, error: decision.reason };
13664
+ }
13665
+ await this.governance.recordAuditEvent({
13666
+ action: "guardrail.operation.started",
13667
+ actorPrincipal: decision.principalId,
13668
+ scope: decision.scope,
13669
+ outcome: "applied",
13670
+ detail: `${decision.action} on ${decision.resource}`,
13671
+ correlationId: decision.correlationId
13672
+ }).catch(() => void 0);
13673
+ let result;
13674
+ try {
13675
+ result = await operation();
13676
+ } catch (err2) {
13677
+ await this.governance.recordAuditEvent({
13678
+ action: "guardrail.operation.failed",
13679
+ actorPrincipal: decision.principalId,
13680
+ scope: decision.scope,
13681
+ outcome: "rejected",
13682
+ reason: err2.message,
13683
+ detail: `${decision.action} on ${decision.resource}`,
13684
+ correlationId: decision.correlationId
13685
+ }).catch(() => void 0);
13686
+ return { decision, executed: true, error: err2.message };
13687
+ }
13688
+ await this.governance.recordAuditEvent({
13689
+ action: "guardrail.operation.completed",
13690
+ actorPrincipal: decision.principalId,
13691
+ scope: decision.scope,
13692
+ outcome: "applied",
13693
+ detail: `${decision.action} on ${decision.resource}`,
13694
+ correlationId: decision.correlationId
13695
+ }).catch(() => void 0);
13696
+ return { decision, executed: true, result };
13697
+ }
13698
+ };
13699
+ function createGuardrailService(directory, governance) {
13700
+ return new GuardrailService(directory, governance);
13701
+ }
13702
+ __name(createGuardrailService, "createGuardrailService");
13703
+
13704
+ // core/memory-anthology/index.ts
13705
+ var VALID_TRANSITIONS = {
13706
+ unassessed: ["asserted", "corroborated", "reviewed", "disputed", "refuted", "superseded"],
13707
+ asserted: ["corroborated", "reviewed", "disputed", "refuted", "superseded"],
13708
+ corroborated: ["reviewed", "disputed", "refuted", "superseded"],
13709
+ reviewed: ["disputed", "refuted", "superseded"],
13710
+ disputed: ["corroborated", "reviewed", "refuted", "superseded"],
13711
+ refuted: ["superseded"],
13712
+ superseded: []
13713
+ };
13714
+ function canTransitionEpistemic(from, to) {
13715
+ if (from === to) return true;
13716
+ return (VALID_TRANSITIONS[from] ?? []).includes(to);
13717
+ }
13718
+ __name(canTransitionEpistemic, "canTransitionEpistemic");
13719
+ function validateEpistemicTransition(from, to, reason) {
13720
+ if (from === to) return { allowed: true, reason: "no change" };
13721
+ if (!canTransitionEpistemic(from, to)) {
13722
+ return { allowed: false, reason: `invalid transition ${from} -> ${to}` };
13723
+ }
13724
+ if (to === "corroborated" && !reason) {
13725
+ return { allowed: false, reason: "corroborated requires explanation of independent sources" };
13726
+ }
13727
+ if (to === "reviewed" && !reason) {
13728
+ return { allowed: false, reason: "reviewed requires reviewer identity and scope" };
13729
+ }
13730
+ return { allowed: true, reason: reason ?? "ok" };
13731
+ }
13732
+ __name(validateEpistemicTransition, "validateEpistemicTransition");
13733
+ function validateProvenance(p) {
13734
+ const errors = [];
13735
+ if (!p || typeof p !== "object") {
13736
+ errors.push("provenance must be an object");
13737
+ return { valid: false, errors };
13738
+ }
13739
+ const kinds = ["user-statement", "system-observation", "imported-document", "external-source", "agent-inference", "model-summary", "human-correction", "system-event", "unknown"];
13740
+ if (!kinds.includes(p.kind)) errors.push("invalid provenance kind");
13741
+ if (p.observedAt !== void 0 && (typeof p.observedAt !== "string" || isNaN(Date.parse(p.observedAt)))) {
13742
+ errors.push("observedAt must be valid ISO timestamp if provided");
13743
+ }
13744
+ return { valid: errors.length === 0, errors };
13745
+ }
13746
+ __name(validateProvenance, "validateProvenance");
13747
+ function validateMemoryItem(item) {
13748
+ const errors = [];
13749
+ if (!item || typeof item !== "object") {
13750
+ errors.push("item must be an object");
13751
+ return { valid: false, errors };
13752
+ }
13753
+ if (typeof item.itemId !== "string" || !item.itemId.trim()) errors.push("itemId is required");
13754
+ if (typeof item.schemaVersion !== "number" || !Number.isInteger(item.schemaVersion) || item.schemaVersion < 1) errors.push("schemaVersion must be positive integer");
13755
+ if (typeof item.scope !== "string" || !item.scope.trim()) errors.push("scope is required");
13756
+ if (!item.temporal || typeof item.temporal !== "object") errors.push("temporal is required");
13757
+ else if (typeof item.temporal.recordedAt !== "string" || isNaN(Date.parse(item.temporal.recordedAt))) errors.push("recordedAt must be valid ISO timestamp");
13758
+ if (!item.provenance) errors.push("provenance is required");
13759
+ else {
13760
+ const pv = validateProvenance(item.provenance);
13761
+ if (!pv.valid) errors.push(...pv.errors);
13762
+ }
13763
+ if (!item.revision || typeof item.revision !== "object") errors.push("revision is required");
13764
+ else if (typeof item.revision.revision !== "number" || item.revision.revision < 0) errors.push("revision.revision must be non-negative integer");
13765
+ if (item.category === "derived-summary") {
13766
+ if (!item.derivedLineage) errors.push("derived summary requires lineage");
13767
+ }
13768
+ return { valid: errors.length === 0, errors };
13769
+ }
13770
+ __name(validateMemoryItem, "validateMemoryItem");
13771
+ function validateDerivedLineage(lineage, _sourceStatuses) {
13772
+ const errors = [];
13773
+ if (!lineage || typeof lineage !== "object") {
13774
+ errors.push("lineage required");
13775
+ return { valid: false, errors };
13776
+ }
13777
+ if (!Array.isArray(lineage.sourceItemIds) || lineage.sourceItemIds.length === 0) errors.push("sourceItemIds required");
13778
+ if (!Array.isArray(lineage.sourceRevisions) || lineage.sourceRevisions.length !== lineage.sourceItemIds.length) errors.push("sourceRevisions must match sourceItemIds length");
13779
+ if (typeof lineage.derivedAt !== "string" || isNaN(Date.parse(lineage.derivedAt))) errors.push("derivedAt invalid");
13780
+ if (typeof lineage.producingComponent !== "string" || !lineage.producingComponent.trim()) errors.push("producingComponent required");
13781
+ return { valid: errors.length === 0, errors };
13782
+ }
13783
+ __name(validateDerivedLineage, "validateDerivedLineage");
13784
+ function markDerivedStale(lineage) {
13785
+ return { ...lineage, stale: true };
13786
+ }
13787
+ __name(markDerivedStale, "markDerivedStale");
13788
+ function isLegacyRecord(item) {
13789
+ return !item || typeof item !== "object" || !item.provenance || !item.temporal || !item.revision;
13790
+ }
13791
+ __name(isLegacyRecord, "isLegacyRecord");
13792
+ function normalizeLegacyRecord(item) {
13793
+ return {
13794
+ itemId: item?.id ?? item?.itemId ?? `legacy-${Math.random().toString(36).slice(2, 10)}`,
13795
+ schemaVersion: 0,
13796
+ category: "legacy",
13797
+ payload: item,
13798
+ scope: item?.scope ?? "unknown",
13799
+ provenance: { kind: "unknown" },
13800
+ epistemicStatus: "unassessed",
13801
+ sensitivity: "unknown",
13802
+ temporal: { recordedAt: item?.createdAt ? new Date(item.createdAt).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString() },
13803
+ revision: { revision: 0 }
13804
+ };
13805
+ }
13806
+ __name(normalizeLegacyRecord, "normalizeLegacyRecord");
13807
+ var MEMORY_CATEGORIES = [
13808
+ "observation",
13809
+ "claim",
13810
+ "fact-candidate",
13811
+ "hypothesis",
13812
+ "decision",
13813
+ "preference",
13814
+ "instruction",
13815
+ "experience",
13816
+ "goal",
13817
+ "relationship",
13818
+ "derived-summary",
13819
+ "unknown-disputed",
13820
+ "legacy"
13821
+ ];
13822
+ var EPITEMIC_STATUSES2 = [
13823
+ "unassessed",
13824
+ "asserted",
13825
+ "corroborated",
13826
+ "reviewed",
13827
+ "disputed",
13828
+ "refuted",
13829
+ "superseded"
13830
+ ];
13831
+
13832
+ // index.ts
12025
13833
  var dotmem = {
12026
13834
  version: "0.0.8",
12027
13835
  isBrowser,
@@ -12056,18 +13864,29 @@ Object.defineProperty(exports, "store", {
12056
13864
  exports.CompactionEngine = CompactionEngine;
12057
13865
  exports.ContextCompiler = ContextCompiler;
12058
13866
  exports.ContextLifecycleOrchestrator = ContextLifecycleOrchestrator;
13867
+ exports.EPITEMIC_STATUSES = EPITEMIC_STATUSES2;
13868
+ exports.GOVERNANCE_POLICY_STATUSES = GOVERNANCE_POLICY_STATUSES;
13869
+ exports.GOVERNANCE_ROLES = GOVERNANCE_ROLES;
13870
+ exports.GovernancePolicyError = GovernancePolicyError;
13871
+ exports.GovernancePolicyStore = GovernancePolicyStore;
13872
+ exports.GuardrailError = GuardrailError;
13873
+ exports.GuardrailService = GuardrailService;
13874
+ exports.MEMORY_CATEGORIES = MEMORY_CATEGORIES;
12059
13875
  exports.RecoveryService = RecoveryService;
12060
13876
  exports.addDecision = addDecision;
12061
13877
  exports.addOpenLoopRef = addOpenLoopRef;
12062
13878
  exports.addRejectedApproach = addRejectedApproach;
12063
13879
  exports.addUnresolvedQuestion = addUnresolvedQuestion;
12064
13880
  exports.appendReasoningStep = appendReasoningStep;
13881
+ exports.canTransitionEpistemic = canTransitionEpistemic;
12065
13882
  exports.clearUserIdentity = clearUserIdentity;
12066
13883
  exports.closeConversationalState = closeConversationalState;
12067
13884
  exports.compileContext = compileContext;
12068
13885
  exports.continuity = continuity;
13886
+ exports.continuityLedger = continuityLedger;
12069
13887
  exports.createCompactionEngine = createCompactionEngine;
12070
13888
  exports.createConversationalState = createConversationalState;
13889
+ exports.createGuardrailService = createGuardrailService;
12071
13890
  exports.createNoOpHost = createNoOpHost;
12072
13891
  exports.createRecoveryService = createRecoveryService;
12073
13892
  exports.default = index_default;
@@ -12082,11 +13901,14 @@ exports.isBrowser = isBrowser;
12082
13901
  exports.isBun = isBun;
12083
13902
  exports.isDeno = isDeno;
12084
13903
  exports.isEdge = isEdge;
13904
+ exports.isLegacyRecord = isLegacyRecord;
12085
13905
  exports.isNode = isNode;
12086
13906
  exports.listUnfinishedConversations = listUnfinishedConversations;
12087
13907
  exports.loadAllConversationalStates = loadAllConversationalStates;
12088
13908
  exports.loadConversationalStateById = loadConversationalStateById;
13909
+ exports.markDerivedStale = markDerivedStale;
12089
13910
  exports.memory = memory;
13911
+ exports.normalizeLegacyRecord = normalizeLegacyRecord;
12090
13912
  exports.recoverConversation = recoverConversation;
12091
13913
  exports.resolveUserAgentMemoryPath = resolveUserAgentMemoryPath;
12092
13914
  exports.resolveUserBrainPath = resolveUserBrainPath;
@@ -12096,8 +13918,15 @@ exports.resolveUserExperiencePath = resolveUserExperiencePath;
12096
13918
  exports.resolveUserIdentity = resolveUserIdentity;
12097
13919
  exports.resolveUserProjectMemoryPath = resolveUserProjectMemoryPath;
12098
13920
  exports.resolveUserReadmePath = resolveUserReadmePath;
13921
+ exports.roleHasPermission = roleHasPermission;
12099
13922
  exports.saveConversationalState = saveConversationalState;
12100
13923
  exports.security = security;
12101
13924
  exports.setUserIdentity = setUserIdentity;
12102
13925
  exports.signMemPackage = signMemPackage;
12103
13926
  exports.updateConversationalState = updateConversationalState;
13927
+ exports.validateDerivedLineage = validateDerivedLineage;
13928
+ exports.validateEpistemicTransition = validateEpistemicTransition;
13929
+ exports.validateMemoryItem = validateMemoryItem;
13930
+ exports.validateProvenance = validateProvenance;
13931
+ exports.validateRelationshipTargets = validateRelationshipTargets;
13932
+ exports.validateResolutionRequest = validateResolutionRequest;