@sema-agent/core 7.15.0 → 7.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/core/governance-codes.js +2 -0
  3. package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
  4. package/dist/core/memory-engine/delegation-settlement.js +128 -39
  5. package/dist/core/memory-engine/engine.d.ts +9 -8
  6. package/dist/core/memory-engine/engine.js +115 -120
  7. package/dist/core/memory-engine/file-backend.d.ts +17 -5
  8. package/dist/core/memory-engine/file-backend.js +78 -34
  9. package/dist/core/memory-engine/index.d.ts +2 -2
  10. package/dist/core/memory-engine/index.js +2 -2
  11. package/dist/core/memory-engine/layout.d.ts +152 -54
  12. package/dist/core/memory-engine/layout.js +441 -104
  13. package/dist/core/memory-engine/types.d.ts +8 -3
  14. package/dist/core/memory-engine/types.js +5 -0
  15. package/dist/core/runner/abort-race.d.ts +3 -3
  16. package/dist/core/runner/active-skill-scope.d.ts +2 -2
  17. package/dist/core/runner/assemble-result.d.ts +29 -29
  18. package/dist/core/runner/checkpoint-scope.d.ts +4 -4
  19. package/dist/core/runner/clock-and-limits.d.ts +3 -3
  20. package/dist/core/runner/compaction-call-options.d.ts +11 -11
  21. package/dist/core/runner/compaction-knobs.d.ts +4 -4
  22. package/dist/core/runner/compaction-seams.d.ts +5 -5
  23. package/dist/core/runner/contracts.d.ts +222 -224
  24. package/dist/core/runner/decide-continuation.d.ts +6 -6
  25. package/dist/core/runner/denial-limit-arms.d.ts +8 -8
  26. package/dist/core/runner/derived-route-fallback.d.ts +2 -2
  27. package/dist/core/runner/gate-exit.d.ts +6 -6
  28. package/dist/core/runner/git-status-frame.d.ts +7 -7
  29. package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
  30. package/dist/core/runner/memory-capture-optout.d.ts +1 -1
  31. package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
  32. package/dist/core/runner/memory-consolidation.d.ts +6 -6
  33. package/dist/core/runner/park-commit.d.ts +6 -6
  34. package/dist/core/runner/permission-rule-lanes.d.ts +19 -19
  35. package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
  36. package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
  37. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
  38. package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -5
  39. package/dist/core/runner/prepare-config-doors.d.ts +21 -21
  40. package/dist/core/runner/prepare-context-lane.d.ts +6 -6
  41. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  42. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  43. package/dist/core/runner/prepare-file-history.d.ts +2 -2
  44. package/dist/core/runner/prepare-gate-stations.d.ts +5 -5
  45. package/dist/core/runner/prepare-hands-readface.d.ts +33 -33
  46. package/dist/core/runner/prepare-inherited-gate.d.ts +4 -4
  47. package/dist/core/runner/prepare-listings.d.ts +3 -3
  48. package/dist/core/runner/prepare-lsp.d.ts +3 -3
  49. package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
  50. package/dist/core/runner/prepare-memory.js +6 -7
  51. package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
  52. package/dist/core/runner/prepare-park-ask.d.ts +6 -6
  53. package/dist/core/runner/prepare-policy-chain.d.ts +4 -4
  54. package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
  55. package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
  56. package/dist/core/runner/prepare-question-face.d.ts +4 -4
  57. package/dist/core/runner/prepare-run-refs.d.ts +11 -11
  58. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  59. package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
  60. package/dist/core/runner/prepare-task.d.ts +12 -12
  61. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
  62. package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
  63. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
  64. package/dist/core/runner/remote-env-retry.d.ts +3 -3
  65. package/dist/core/runner/resume-admission.d.ts +1 -1
  66. package/dist/core/runner/resume-claim.d.ts +1 -1
  67. package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
  68. package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
  69. package/dist/core/runner/resume-preflight.d.ts +1 -1
  70. package/dist/core/runner/resume-review-outcome.d.ts +1 -1
  71. package/dist/core/runner/run-brain-sinks.d.ts +1 -1
  72. package/dist/core/runner/run-clock-and-content.d.ts +4 -4
  73. package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
  74. package/dist/core/runner/run-git-lane.d.ts +1 -1
  75. package/dist/core/runner/run-harness-handlers.d.ts +2 -2
  76. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  77. package/dist/core/runner/run-leg.d.ts +3 -3
  78. package/dist/core/runner/run-notification-lane.d.ts +2 -2
  79. package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
  80. package/dist/core/runner/run-settle-and-teardown.d.ts +4 -4
  81. package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
  82. package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
  83. package/dist/core/runner/runtask.d.ts +14 -14
  84. package/dist/core/runner/session-file-state-replay.d.ts +3 -3
  85. package/dist/core/runner/session-rule-policy.d.ts +2 -2
  86. package/dist/core/runner/steer-admission.d.ts +2 -2
  87. package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
  88. package/dist/core/runner/stream-reap.d.ts +1 -1
  89. package/dist/core/runner/synthetic-tools.d.ts +8 -8
  90. package/dist/core/runner/teardown-bounded.d.ts +2 -2
  91. package/dist/core/runner/tool-defer-gate.d.ts +1 -1
  92. package/dist/core/runner/tool-disclosure.d.ts +33 -33
  93. package/dist/core/runner/tool-end-body.d.ts +3 -3
  94. package/dist/core/runner/tool-face-overlay.d.ts +2 -2
  95. package/dist/core/runner/tool-output-projection.d.ts +2 -2
  96. package/dist/core/runner/turn-attachments.d.ts +53 -53
  97. package/dist/core/runner/usage-accounting.d.ts +4 -4
  98. package/dist/core/runner/workspace-path.d.ts +1 -1
  99. package/dist/engine/llm/types.d.ts +1 -1
  100. package/dist/index.d.ts +2 -2
  101. package/dist/index.js +2 -2
  102. package/dist/tools/fs/bash-readonly-classifier.d.ts +40 -40
  103. package/dist/tools/fs/encoding.d.ts +31 -40
  104. package/dist/tools/fs/fs-bash.d.ts +35 -35
  105. package/dist/tools/fs/fs-pdf.d.ts +8 -8
  106. package/dist/tools/fs/fs-search-tools.d.ts +4 -4
  107. package/dist/tools/fs/fs-shared.d.ts +144 -158
  108. package/dist/tools/fs/fs-write.d.ts +8 -8
  109. package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
  110. package/dist/tools/fs/index.d.ts +74 -78
  111. package/dist/tools/fs/notebook.d.ts +24 -25
  112. package/dist/tools/fs/pdf.d.ts +3 -3
  113. package/dist/tools/fs/read-deny.d.ts +22 -22
  114. package/dist/tools/fs/read-face.d.ts +21 -24
  115. package/dist/tools/fs/repo-map.d.ts +8 -8
  116. package/dist/tools/fs/safety.d.ts +116 -129
  117. package/dist/tools/fs/search.d.ts +63 -71
  118. package/package.json +5 -2
  119. package/test/export-surface.snapshot.json +5 -1
@@ -15,12 +15,12 @@ export interface ScannedEntryFile {
15
15
  }
16
16
  /**
17
17
  * Enumerate a scope dir's entry files (depth-capped, symlinks skipped, dotfiles/index/non-`.md`
18
- * ignored, `exclude` dirs sibling scope homes under the root skipped). Shared by the backend
19
- * and the engine's harvest scan so the two can never disagree on what counts as an entry file.
18
+ * ignored). Shared by the backend and the engine's harvest scan so the two can never disagree on
19
+ * what counts as an entry file. A scope dir is that scope's home and nothing else no other
20
+ * scope's directory can lie under it, so there is nothing to exclude.
20
21
  */
21
22
  export declare function scanEntryFiles(dir: string, opts?: {
22
23
  maxDepth?: number;
23
- exclude?: ReadonlySet<string>;
24
24
  /** Harvest gate hook: called for every path the scan SKIPS, with why (backend scans ignore it). */
25
25
  onSkip?: (path: string, kind: "symlink" | "depth" | "nonmd" | "dotfile" | "unreadable") => void;
26
26
  }): ScannedEntryFile[];
@@ -377,6 +377,8 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
377
377
  readonly controlPlaneRoot: string;
378
378
  /** Injected clock (opus 1.258 LOW: match the engine's `this.now` determinism discipline). */
379
379
  private readonly now;
380
+ /** The construction-time incident sink (partition adoption, layout adoption on the standalone faces). */
381
+ private readonly onIncident;
380
382
  /**
381
383
  * The COMMITTED-rev ledger (`revs.json`, id → row; design/186 schema v2). Zero-copy makes it
382
384
  * load-bearing for CAS: the entry files are the SAME files the session edits, so "read the current
@@ -448,6 +450,18 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
448
450
  * loop, cleared before EXECUTE mutates the disk. Never caches `sync:true` reads. */
449
451
  private batchScan;
450
452
  constructor(dir: string, opts?: FileMemoryEngineBackendOptions);
453
+ /** The adoption under a held transaction lock (before the ledger migration, whose census derives
454
+ * paths from the registry); the heartbeat refreshes the lock and re-proves it before every action. */
455
+ private adoptLayoutLocked;
456
+ /** The seat at the head of every lock-free public face: adopt under a NON-BLOCKING try-acquire. A live
457
+ * holder stands this caller down (its locked faces, or the next mount, adopt); the read that follows
458
+ * refuses fail-closed on a v1 registry rather than serving a layout it cannot describe. */
459
+ private ensureLayout;
460
+ /** The engine's mount seat: adopt under the transaction lock (`ownerCandidate` = the write scope; `onIncident` = this call's sink). */
461
+ adoptRootScopeLayout(opts?: {
462
+ ownerCandidate?: string | null;
463
+ onIncident?: MemoryPartitionIncidentSink;
464
+ }): Promise<void>;
451
465
  /** B3 fail-closed preflight (engine harvest duck-types this): force-reload every load-bearing
452
466
  * sidecar from disk; throws {@link ControlPlaneCorruptError} when one is corrupt. Also completes
453
467
  * any interrupted transaction (H4 recovery). */
@@ -690,8 +704,6 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
690
704
  /** Remove orphaned `.stage-*` files (a crash BEFORE the journal rename = clean rollback: nothing
691
705
  * was committed, the staged tmps are litter). Dotfiles are invisible to entry scans regardless. */
692
706
  private sweepStagedFiles;
693
- /** The names of sibling scope subdirs to exclude when scanning the ROOT scope's own nested content. */
694
- private excludedSubdirNames;
695
707
  private scopeDir;
696
708
  /** B2/C-F9 — contain one inbound-gate REJECT, shared by the adopting read (`readScope` sync) and
697
709
  * the adoption-restricted committed view (`readScopeCommitted`) so the two doors can never drift:
@@ -1,11 +1,12 @@
1
- import { existsSync, linkSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, openSync, fsyncSync, closeSync } from "node:fs";
1
+ import { existsSync, linkSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, openSync, fsyncSync, closeSync, utimesSync } from "node:fs";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { dirname, join, relative } from "node:path";
4
4
  import { jaccardDistance, termSet } from "../memory-vector.js";
5
5
  import { MAX_MEMORY_BYTES } from "../memory.js";
6
6
  import { inlineUntrusted } from "../untrusted-text.js";
7
7
  import { ambiguousOriginRepresentation, committedDistilledOf, committedOriginOf, computeEntryRev, distilledEquals, entryFromFile, isValidEntryId, originEquals, parseEntryFile, serializeEntryFile } from "./frontmatter.js";
8
- import { ControlPlaneCorruptError, CURSORS_FILE, QUARANTINE_DIR, CHALLENGES_FILE, IMPORT_RECEIPTS_DIR, LINEAGE_FILE, SESSION_POLLUTION_DIR, appendChallengeEvents, atomicWriteFileSync, quarantineAndTombstone, captureAndClearLineageForEntries, claimRootScope, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, importLatchTxnId, importLineageCommitted, importSessionPollution, isContainedIn, lineageContributionsOfSession, listSessionPollution, readChallengeEvents, readLineageRecord, registerScope, registeredScopes, releaseImportLatch, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, stageImportLatch, writeAllSync, } from "./layout.js";
8
+ import { convertV1SidecarKeys } from "./delegation-settlement.js";
9
+ import { ControlPlaneCorruptError, CURSORS_FILE, QUARANTINE_DIR, CHALLENGES_FILE, IMPORT_RECEIPTS_DIR, LINEAGE_FILE, SESSION_POLLUTION_DIR, appendChallengeEvents, atomicWriteFileSync, quarantineAndTombstone, captureAndClearLineageForEntries, adoptRootScopeLayout, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, importLatchTxnId, importLineageCommitted, importSessionPollution, isContainedIn, lineageContributionsOfSession, listSessionPollution, readChallengeEvents, readLineageRecord, registerScope, registeredScopes, releaseImportLatch, layoutNeedsAdoption, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, scopeRegistryShape, stageImportLatch, writeAllSync, } from "./layout.js";
9
10
  import { screenInboundEntries } from "./data-plane.js";
10
11
  import { scanMemoryFileName, scanMemoryWrite } from "./scan.js";
11
12
  export const MEMORY_INDEX_FILENAME = "MEMORY.md";
@@ -43,8 +44,6 @@ export function scanEntryFiles(dir, opts = {}) {
43
44
  continue;
44
45
  }
45
46
  if (st.isDirectory()) {
46
- if (depth === 0 && opts.exclude?.has(name))
47
- continue;
48
47
  if (depth + 1 <= maxDepth)
49
48
  walk(p, depth + 1);
50
49
  else
@@ -534,6 +533,7 @@ export class FileMemoryEngineBackend {
534
533
  directoryRoot;
535
534
  controlPlaneRoot;
536
535
  now;
536
+ onIncident;
537
537
  ledger;
538
538
  envelopeExtras;
539
539
  persistedSchemaVersion;
@@ -549,6 +549,7 @@ export class FileMemoryEngineBackend {
549
549
  batchScan;
550
550
  constructor(dir, opts = {}) {
551
551
  this.now = opts.now ?? Date.now;
552
+ this.onIncident = opts.onIncident;
552
553
  this.directoryRoot = dir;
553
554
  if (opts.controlDir === undefined)
554
555
  adoptCanonicalKeyedControlDir(resolveMemoryEngineRoot(), dir, opts.onIncident);
@@ -561,11 +562,60 @@ export class FileMemoryEngineBackend {
561
562
  }
562
563
  catch {
563
564
  }
564
- if (this.persistedSchemaVersion === "v1" || (this.ledger !== undefined && hasUnboundRows(this.ledger)))
565
- this.tryOpportunisticMigrate();
565
+ if (this.persistedSchemaVersion === "v1" || (this.ledger !== undefined && hasUnboundRows(this.ledger))) {
566
+ let layoutDerivesPaths = false;
567
+ try {
568
+ const shape = scopeRegistryShape(this.controlPlaneRoot);
569
+ layoutDerivesPaths = shape !== "v1" && shape !== "migrating";
570
+ }
571
+ catch {
572
+ }
573
+ if (layoutDerivesPaths)
574
+ this.tryOpportunisticMigrate();
575
+ }
576
+ }
577
+ adoptLayoutLocked(lockToken, ownerCandidate, onIncident) {
578
+ adoptRootScopeLayout(this.directoryRoot, this.controlPlaneRoot, {
579
+ ownerCandidate,
580
+ onIncident: onIncident ?? this.onIncident,
581
+ convertSidecars: convertV1SidecarKeys,
582
+ renew: () => {
583
+ const now = new Date();
584
+ utimesSync(this.txnLockDir(), now, now);
585
+ this.assertTxnLockOwnership(lockToken);
586
+ },
587
+ });
588
+ }
589
+ ensureLayout(ownerCandidate) {
590
+ if (!layoutNeedsAdoption(this.directoryRoot, this.controlPlaneRoot))
591
+ return;
592
+ const lock = this.tryAcquireTxnLockSync();
593
+ if (lock === undefined)
594
+ return;
595
+ try {
596
+ this.recoverJournal({ token: lock.token });
597
+ this.adoptLayoutLocked(lock.token, ownerCandidate);
598
+ }
599
+ finally {
600
+ lock.release();
601
+ }
602
+ }
603
+ async adoptRootScopeLayout(opts = {}) {
604
+ if (!layoutNeedsAdoption(this.directoryRoot, this.controlPlaneRoot))
605
+ return;
606
+ const lock = await this.acquireTxnLock();
607
+ try {
608
+ this.assertTxnLockOwnership(lock.token);
609
+ this.recoverJournal({ token: lock.token });
610
+ this.adoptLayoutLocked(lock.token, opts.ownerCandidate, opts.onIncident);
611
+ }
612
+ finally {
613
+ lock.release();
614
+ }
566
615
  }
567
616
  checkControlPlane() {
568
617
  this.recoverJournal({ unlocked: true });
618
+ this.ensureLayout();
569
619
  this.ledger = undefined;
570
620
  this.loadLedger();
571
621
  registeredScopes(this.controlPlaneRoot);
@@ -658,8 +708,6 @@ export class FileMemoryEngineBackend {
658
708
  const byId = new Map();
659
709
  for (const scope of Object.keys(registeredScopes(this.controlPlaneRoot))) {
660
710
  const dir = this.scopeDir(scope);
661
- const isRoot = dir === this.directoryRoot;
662
- const exclude = isRoot ? this.excludedSubdirNames(scope) : undefined;
663
711
  const walk = (d, depth) => {
664
712
  let names;
665
713
  try {
@@ -686,8 +734,6 @@ export class FileMemoryEngineBackend {
686
734
  if (st.isSymbolicLink())
687
735
  continue;
688
736
  if (st.isDirectory()) {
689
- if (depth === 0 && exclude?.has(name))
690
- continue;
691
737
  if (depth + 1 <= DEFAULT_MAX_ENTRY_DEPTH)
692
738
  walk(p, depth + 1);
693
739
  continue;
@@ -855,6 +901,7 @@ export class FileMemoryEngineBackend {
855
901
  return;
856
902
  try {
857
903
  this.recoverJournal({ token: lock.token });
904
+ this.adoptLayoutLocked(lock.token);
858
905
  this.migrateLockedIfNeeded(lock.token);
859
906
  }
860
907
  finally {
@@ -1482,15 +1529,6 @@ export class FileMemoryEngineBackend {
1482
1529
  };
1483
1530
  walk(this.directoryRoot, 0);
1484
1531
  }
1485
- excludedSubdirNames(forScope) {
1486
- const reg = registeredScopes(this.controlPlaneRoot);
1487
- const names = new Set();
1488
- for (const [scope, dirName] of Object.entries(reg)) {
1489
- if (scope !== forScope && dirName !== "")
1490
- names.add(dirName);
1491
- }
1492
- return names;
1493
- }
1494
1532
  scopeDir(scope) {
1495
1533
  return registerScope(this.directoryRoot, this.controlPlaneRoot, scope);
1496
1534
  }
@@ -1540,8 +1578,7 @@ export class FileMemoryEngineBackend {
1540
1578
  if (this.persistedSchemaVersion === "v1" || this.unboundRowsKnown)
1541
1579
  this.tryOpportunisticMigrate();
1542
1580
  const dir = this.scopeDir(scope);
1543
- const isRoot = dir === this.directoryRoot;
1544
- const files = scanEntryFiles(dir, { exclude: isRoot ? this.excludedSubdirNames(scope) : undefined });
1581
+ const files = scanEntryFiles(dir);
1545
1582
  const entries = [];
1546
1583
  const rows = sync ? this.loadLedger() : undefined;
1547
1584
  const retrievalDeleted = !sync && files.length > 0 ? this.retrievalDeletedIds() : undefined;
@@ -1774,6 +1811,7 @@ export class FileMemoryEngineBackend {
1774
1811
  this.assertTxnLockOwnership(lock.token);
1775
1812
  this.ledger = undefined;
1776
1813
  this.recoverJournal({ token: lock.token });
1814
+ this.adoptLayoutLocked(lock.token);
1777
1815
  this.migrateLockedIfNeeded(lock.token);
1778
1816
  return this.readScope(scope, true, false, lock.token);
1779
1817
  }
@@ -1786,9 +1824,11 @@ export class FileMemoryEngineBackend {
1786
1824
  }
1787
1825
  }
1788
1826
  listScopes() {
1827
+ this.ensureLayout();
1789
1828
  return { supported: true, scopes: Object.keys(registeredScopes(this.controlPlaneRoot)).sort() };
1790
1829
  }
1791
1830
  async listHeaders(scopes) {
1831
+ this.ensureLayout();
1792
1832
  return this.listHeadersFrom(scopes, (s) => this.readScopeAdopting(s));
1793
1833
  }
1794
1834
  async listHeadersFrom(scopes, read) {
@@ -1802,6 +1842,7 @@ export class FileMemoryEngineBackend {
1802
1842
  return out;
1803
1843
  }
1804
1844
  async getByIds(ids) {
1845
+ this.ensureLayout();
1805
1846
  return this.getByIdsFrom(ids, (s) => this.readScopeAdopting(s));
1806
1847
  }
1807
1848
  async getByIdsFrom(ids, read) {
@@ -1820,9 +1861,9 @@ export class FileMemoryEngineBackend {
1820
1861
  throw new Error(`memory retrieval view is read-only — ${op} must go through the backend itself`);
1821
1862
  };
1822
1863
  return {
1823
- listHeaders: async (scopes) => this.listHeadersFrom(scopes, (s) => this.readScope(s, false)),
1824
- getByIds: async (ids) => this.getByIdsFrom(ids, (s) => this.readScope(s, false)),
1825
- search: async (query, scopes, opts) => this.searchFrom(query, scopes, opts, (s) => this.readScope(s, false)),
1864
+ listHeaders: async (scopes) => (this.ensureLayout(), this.listHeadersFrom(scopes, (s) => this.readScope(s, false))),
1865
+ getByIds: async (ids) => (this.ensureLayout(), this.getByIdsFrom(ids, (s) => this.readScope(s, false))),
1866
+ search: async (query, scopes, opts) => (this.ensureLayout(), this.searchFrom(query, scopes, opts, (s) => this.readScope(s, false))),
1826
1867
  applyPatches: async () => refuse("applyPatches"),
1827
1868
  getConsolidationCursor: async (scope) => this.getConsolidationCursor(scope),
1828
1869
  setConsolidationCursor: async () => refuse("setConsolidationCursor"),
@@ -1841,9 +1882,7 @@ export class FileMemoryEngineBackend {
1841
1882
  if (this.persistedSchemaVersion === "v1" || this.unboundRowsKnown)
1842
1883
  this.tryOpportunisticMigrate();
1843
1884
  const dir = this.scopeDir(scope);
1844
- const isRoot = dir === this.directoryRoot;
1845
1885
  const files = scanEntryFiles(dir, {
1846
- exclude: isRoot ? this.excludedSubdirNames(scope) : undefined,
1847
1886
  onSkip: audit
1848
1887
  ? (p, kind) => {
1849
1888
  if (kind !== "unreadable")
@@ -1998,8 +2037,7 @@ export class FileMemoryEngineBackend {
1998
2037
  idProjectionElsewhere(id, excludeAbsPath) {
1999
2038
  for (const scope of Object.keys(registeredScopes(this.controlPlaneRoot))) {
2000
2039
  const dir = this.scopeDir(scope);
2001
- const isRoot = dir === this.directoryRoot;
2002
- for (const f of scanEntryFiles(dir, { exclude: isRoot ? this.excludedSubdirNames(scope) : undefined })) {
2040
+ for (const f of scanEntryFiles(dir)) {
2003
2041
  if (f.path === excludeAbsPath)
2004
2042
  continue;
2005
2043
  const text = readSafe(f.path);
@@ -2022,15 +2060,16 @@ export class FileMemoryEngineBackend {
2022
2060
  throw new Error(`memory adoption-restricted view is read-only — ${op} must go through the backend itself`);
2023
2061
  };
2024
2062
  return {
2025
- listHeaders: async (scopes) => this.listHeadersFrom(scopes, (s) => this.readScopeCommitted(s, audit)),
2026
- getByIds: async (ids) => this.getByIdsFrom(ids, (s) => this.readScopeCommitted(s, audit)),
2027
- search: async (query, scopes, o) => this.searchFrom(query, scopes, o, (s) => this.readScopeCommitted(s, audit)),
2063
+ listHeaders: async (scopes) => (this.ensureLayout(), this.listHeadersFrom(scopes, (s) => this.readScopeCommitted(s, audit))),
2064
+ getByIds: async (ids) => (this.ensureLayout(), this.getByIdsFrom(ids, (s) => this.readScopeCommitted(s, audit))),
2065
+ search: async (query, scopes, o) => (this.ensureLayout(), this.searchFrom(query, scopes, o, (s) => this.readScopeCommitted(s, audit))),
2028
2066
  applyPatches: async () => refuse("applyPatches"),
2029
2067
  getConsolidationCursor: async (scope) => this.getConsolidationCursor(scope),
2030
2068
  setConsolidationCursor: async () => refuse("setConsolidationCursor"),
2031
2069
  };
2032
2070
  }
2033
2071
  auditRestrictedDivergence(scopes, opts) {
2072
+ this.ensureLayout();
2034
2073
  for (const scope of scopes)
2035
2074
  this.readScopeCommitted(scope, true);
2036
2075
  const idlessBaseline = opts?.idlessWriteScope !== undefined && opts.idlessWriteScope === this.restrictedIdlessScope ? this.restrictedIdlessBaseline : undefined;
@@ -2044,9 +2083,7 @@ export class FileMemoryEngineBackend {
2044
2083
  let complete = true;
2045
2084
  for (const scope of Object.keys(registeredScopes(this.controlPlaneRoot))) {
2046
2085
  const dir = this.scopeDir(scope);
2047
- const isRoot = dir === this.directoryRoot;
2048
2086
  const files = scanEntryFiles(dir, {
2049
- exclude: isRoot ? this.excludedSubdirNames(scope) : undefined,
2050
2087
  onSkip: (_p, kind) => {
2051
2088
  if (kind === "unreadable")
2052
2089
  complete = false;
@@ -2121,6 +2158,7 @@ export class FileMemoryEngineBackend {
2121
2158
  }
2122
2159
  }
2123
2160
  async search(query, scopes, opts) {
2161
+ this.ensureLayout();
2124
2162
  return this.searchFrom(query, scopes, opts, (s) => this.readScopeAdopting(s));
2125
2163
  }
2126
2164
  async searchFrom(query, scopes, opts, read) {
@@ -2266,6 +2304,7 @@ export class FileMemoryEngineBackend {
2266
2304
  this.assertTxnLockOwnership(lockToken);
2267
2305
  this.ledger = undefined;
2268
2306
  this.recoverJournal({ token: lockToken });
2307
+ this.adoptLayoutLocked(lockToken, patches.find((p) => p.op === "add" && p.entry !== undefined)?.entry?.scope);
2269
2308
  this.migrateLockedIfNeeded(lockToken);
2270
2309
  const rows = cloneRows(this.loadLedger());
2271
2310
  const report = { applied: [], conflicts: [] };
@@ -2442,7 +2481,6 @@ export class FileMemoryEngineBackend {
2442
2481
  if (existingAnywhere !== undefined && existingAnywhere.entry.slug !== entry.slug) {
2443
2482
  ops.push({ kind: "delete", target: existingAnywhere.path });
2444
2483
  }
2445
- claimRootScope(this.controlPlaneRoot, entry.scope);
2446
2484
  const dir = this.scopeDir(entry.scope);
2447
2485
  let slug = entry.slug;
2448
2486
  let target = join(dir, `${slug}.md`);
@@ -2584,6 +2622,7 @@ export class FileMemoryEngineBackend {
2584
2622
  this.assertTxnLockOwnership(lock.token);
2585
2623
  this.ledger = undefined;
2586
2624
  this.recoverJournal({ token: lock.token });
2625
+ this.adoptLayoutLocked(lock.token);
2587
2626
  this.migrateLockedIfNeeded(lock.token);
2588
2627
  const rows = cloneRows(this.loadLedger());
2589
2628
  const chain = this.readTransferChain(lock.token);
@@ -2924,6 +2963,7 @@ export class FileMemoryEngineBackend {
2924
2963
  return { state: "unavailable", reason: "shadowless-legacy" };
2925
2964
  }
2926
2965
  async committedSnapshotOf(id) {
2966
+ this.ensureLayout();
2927
2967
  return this.auditStable((rows, final) => {
2928
2968
  const row = Object.prototype.hasOwnProperty.call(rows, id) ? rows[id] : undefined;
2929
2969
  if (row === undefined)
@@ -2951,6 +2991,7 @@ export class FileMemoryEngineBackend {
2951
2991
  }
2952
2992
  async committedSnapshotsOfScopes(scopes) {
2953
2993
  const want = new Set(scopes);
2994
+ this.ensureLayout();
2954
2995
  try {
2955
2996
  return await this.auditStable((rows, final) => {
2956
2997
  const out = { complete: true, rows: [], unbound: [] };
@@ -3278,6 +3319,7 @@ export class FileMemoryEngineBackend {
3278
3319
  this.assertTxnLockOwnership(lock.token);
3279
3320
  this.ledger = undefined;
3280
3321
  this.recoverJournal({ token: lock.token });
3322
+ this.adoptLayoutLocked(lock.token);
3281
3323
  const rows = this.loadLedger();
3282
3324
  if (this.persistedSchemaVersion !== "v2") {
3283
3325
  throw erasureCodedError("memory export refused: the committed-rev ledger is still schema v1 (pre-binding) — the store migrates itself at its next write/read entry or checkControlPlane; an export never triggers the migration", FileMemoryEngineBackend.EXPORT_INCOMPLETE);
@@ -3361,6 +3403,7 @@ export class FileMemoryEngineBackend {
3361
3403
  this.assertTxnLockOwnership(lock.token);
3362
3404
  this.ledger = undefined;
3363
3405
  this.recoverJournal({ token: lock.token });
3406
+ this.adoptLayoutLocked(lock.token);
3364
3407
  const rows = this.loadLedger();
3365
3408
  if (this.persistedSchemaVersion !== "v2")
3366
3409
  return { custody: [], unbound: [], complete: false, unsliceableCustody: 0, reason: "the committed-rev ledger is still schema v1 (migrate first)" };
@@ -3465,6 +3508,7 @@ export class FileMemoryEngineBackend {
3465
3508
  this.assertTxnLockOwnership(lock.token);
3466
3509
  this.ledger = undefined;
3467
3510
  this.recoverJournal({ token: lock.token });
3511
+ this.adoptLayoutLocked(lock.token);
3468
3512
  this.migrateLockedIfNeeded(lock.token);
3469
3513
  const ctl = this.controlPlaneRoot;
3470
3514
  const txnId = importLatchTxnId(bundleHash);
@@ -4,7 +4,7 @@ export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_R
4
4
  export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
5
5
  export { FileMemoryEngineBackend, scanEntryFiles, MEMORY_INDEX_FILENAME, DEFAULT_MAX_ENTRY_DEPTH, type ScannedEntryFile, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, type MemoryExportSnapshot, } from "./file-backend.js";
6
6
  export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvalid, type MemoryExportBundle, type MemoryImportReport, type MemoryBundleImportPlan, type BundleChallengeRow, type BundleLineageRow, type BundlePollutedSession, } from "./export-bundle.js";
7
- export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAppendResult, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, type SessionCaptureOptOutRecord, type SessionCaptureOptOutMarkOutcome, type SessionCaptureRecordStore, } from "./layout.js";
7
+ export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, scopeRegistryShape, layoutNeedsAdoption, adoptRootScopeLayout, v1MemoryPathKeyResolver, unresolvedProjectionDebts, scanFuseKey, type AdoptRootScopeLayoutOptions, type ScopeRegistryShape, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAppendResult, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, type SessionCaptureOptOutRecord, type SessionCaptureOptOutMarkOutcome, type SessionCaptureRecordStore, } from "./layout.js";
8
8
  export { readV2HeaderHints, isInstructionEntry, type V2HeaderHints } from "./header-hints.js";
9
9
  export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation, type ParsedEntryFile } from "./frontmatter.js";
10
10
  export { consolidationExposedFrontmatter } from "./frontmatter.js";
@@ -13,7 +13,7 @@ export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERS
13
13
  export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, type CleanArmLeakFinding, type CleanArmLeakVerdict, type MemoryDistillerPurityContract, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanArm, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, } from "./distiller.js";
14
14
  export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, type ConsolidationDriverEngine, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type RunMemoryConsolidationOptions, } from "./consolidation-driver.js";
15
15
  export type { OriginClearanceRow, OriginClearanceEvent, OriginClearanceShadow } from "./origin-clearance.js";
16
- export { MEMORY_ORIGIN_CAUSES } from "./types.js";
16
+ export { MEMORY_ORIGIN_CAUSES, writableRootOf } from "./types.js";
17
17
  export type { MemoryBackend, MemoryEntry, MemoryEntryFrontmatter, MemoryEntryOrigin, MemoryOriginCause, MemoryScopeEnumeration, MemoryEntryDistilled, MemoryEntryDistilledInput, MemoryEntryHeader, ScoredMemoryEntry, NotePatch, PatchReport, MaterializedFile, MemorySessionHandle, HarvestReport, HarvestRejection, HarvestRejectionCode, MemoryAnnouncement, ScanFinding, } from "./types.js";
18
18
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, } from "./memory-backend-contract.js";
19
19
  export { SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, } from "./scope-contract.js";
@@ -4,7 +4,7 @@ export { MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_PROVENANCE_R
4
4
  export { scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE } from "./scan.js";
5
5
  export { FileMemoryEngineBackend, scanEntryFiles, MEMORY_INDEX_FILENAME, DEFAULT_MAX_ENTRY_DEPTH, erasureSelectHash, } from "./file-backend.js";
6
6
  export { computeBundleSectionHashes, computeMemoryBundleHash, memoryBundleInvalid, } from "./export-bundle.js";
7
- export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, claimRootScope, rootScopeOf, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, } from "./layout.js";
7
+ export { ControlPlaneCorruptError, deriveControlPlaneDir, deriveRepoControlPlaneDir, deriveRepoKey, deriveRepoMemoryDir, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, scopeRegistryShape, layoutNeedsAdoption, adoptRootScopeLayout, v1MemoryPathKeyResolver, unresolvedProjectionDebts, scanFuseKey, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, } from "./layout.js";
8
8
  export { readV2HeaderHints, isInstructionEntry } from "./header-hints.js";
9
9
  export { parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, committedOriginOf, originEquals, ambiguousOriginRepresentation } from "./frontmatter.js";
10
10
  export { consolidationExposedFrontmatter } from "./frontmatter.js";
@@ -12,7 +12,7 @@ export { committedDistilledOf, distilledEquals } from "./frontmatter.js";
12
12
  export { CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, CONSOLIDATION_RUN_STOP_REASONS, } from "./consolidation.js";
13
13
  export { DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, } from "./distiller.js";
14
14
  export { CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, } from "./consolidation-driver.js";
15
- export { MEMORY_ORIGIN_CAUSES } from "./types.js";
15
+ export { MEMORY_ORIGIN_CAUSES, writableRootOf } from "./types.js";
16
16
  export { memoryBackendContract, assertMemoryBackendSearchEquivalence, } from "./memory-backend-contract.js";
17
17
  export { SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, } from "./scope-contract.js";
18
18
  export { migrateScope } from "./migrate.js";