@sema-agent/core 7.14.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 (136) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/core/ask-origin.d.ts +2 -2
  3. package/dist/core/checkpoint-store.d.ts +14 -15
  4. package/dist/core/governance-codes.js +2 -0
  5. package/dist/core/hooks.d.ts +4 -3
  6. package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
  7. package/dist/core/memory-engine/delegation-settlement.js +128 -39
  8. package/dist/core/memory-engine/engine.d.ts +9 -8
  9. package/dist/core/memory-engine/engine.js +115 -120
  10. package/dist/core/memory-engine/file-backend.d.ts +17 -5
  11. package/dist/core/memory-engine/file-backend.js +78 -34
  12. package/dist/core/memory-engine/index.d.ts +2 -2
  13. package/dist/core/memory-engine/index.js +2 -2
  14. package/dist/core/memory-engine/layout.d.ts +152 -54
  15. package/dist/core/memory-engine/layout.js +441 -104
  16. package/dist/core/memory-engine/types.d.ts +8 -3
  17. package/dist/core/memory-engine/types.js +5 -0
  18. package/dist/core/runner/abort-race.d.ts +3 -3
  19. package/dist/core/runner/active-skill-scope.d.ts +2 -2
  20. package/dist/core/runner/assemble-result.d.ts +29 -29
  21. package/dist/core/runner/checkpoint-scope.d.ts +4 -4
  22. package/dist/core/runner/clock-and-limits.d.ts +3 -3
  23. package/dist/core/runner/compaction-call-options.d.ts +11 -11
  24. package/dist/core/runner/compaction-knobs.d.ts +4 -4
  25. package/dist/core/runner/compaction-seams.d.ts +5 -5
  26. package/dist/core/runner/contracts.d.ts +224 -226
  27. package/dist/core/runner/decide-continuation.d.ts +6 -6
  28. package/dist/core/runner/denial-limit-arms.d.ts +8 -8
  29. package/dist/core/runner/derived-route-fallback.d.ts +2 -2
  30. package/dist/core/runner/gate-exit.d.ts +6 -6
  31. package/dist/core/runner/git-status-frame.d.ts +7 -7
  32. package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
  33. package/dist/core/runner/memory-capture-optout.d.ts +1 -1
  34. package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
  35. package/dist/core/runner/memory-consolidation.d.ts +6 -6
  36. package/dist/core/runner/park-commit.d.ts +6 -6
  37. package/dist/core/runner/permission-rule-lanes.d.ts +22 -20
  38. package/dist/core/runner/permission-rule-lanes.js +1 -1
  39. package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
  40. package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
  41. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
  42. package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -5
  43. package/dist/core/runner/prepare-config-doors.d.ts +21 -21
  44. package/dist/core/runner/prepare-context-lane.d.ts +6 -6
  45. package/dist/core/runner/prepare-defer-classify.d.ts +3 -3
  46. package/dist/core/runner/prepare-defer-classify.js +12 -10
  47. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  48. package/dist/core/runner/prepare-file-history.d.ts +2 -2
  49. package/dist/core/runner/prepare-gate-stations.d.ts +8 -9
  50. package/dist/core/runner/prepare-gate-stations.js +2 -2
  51. package/dist/core/runner/prepare-hands-readface.d.ts +41 -41
  52. package/dist/core/runner/prepare-hands-readface.js +27 -29
  53. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -6
  54. package/dist/core/runner/prepare-listings.d.ts +3 -3
  55. package/dist/core/runner/prepare-lsp.d.ts +3 -3
  56. package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
  57. package/dist/core/runner/prepare-memory.js +6 -7
  58. package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
  59. package/dist/core/runner/prepare-park-ask.d.ts +11 -12
  60. package/dist/core/runner/prepare-park-ask.js +3 -3
  61. package/dist/core/runner/prepare-policy-chain.d.ts +6 -6
  62. package/dist/core/runner/prepare-policy-chain.js +2 -2
  63. package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
  64. package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
  65. package/dist/core/runner/prepare-question-face.d.ts +4 -4
  66. package/dist/core/runner/prepare-run-refs.d.ts +11 -11
  67. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  68. package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
  69. package/dist/core/runner/prepare-task.d.ts +12 -12
  70. package/dist/core/runner/prepare-task.js +5 -7
  71. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
  72. package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
  73. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
  74. package/dist/core/runner/remote-env-retry.d.ts +3 -3
  75. package/dist/core/runner/resume-admission.d.ts +1 -1
  76. package/dist/core/runner/resume-claim.d.ts +1 -1
  77. package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
  78. package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
  79. package/dist/core/runner/resume-preflight.d.ts +1 -1
  80. package/dist/core/runner/resume-review-outcome.d.ts +1 -1
  81. package/dist/core/runner/run-brain-sinks.d.ts +1 -1
  82. package/dist/core/runner/run-clock-and-content.d.ts +4 -4
  83. package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
  84. package/dist/core/runner/run-git-lane.d.ts +1 -1
  85. package/dist/core/runner/run-harness-handlers.d.ts +2 -2
  86. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  87. package/dist/core/runner/run-leg.d.ts +3 -3
  88. package/dist/core/runner/run-notification-lane.d.ts +2 -2
  89. package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
  90. package/dist/core/runner/run-settle-and-teardown.d.ts +4 -4
  91. package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
  92. package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
  93. package/dist/core/runner/runtask.d.ts +14 -14
  94. package/dist/core/runner/session-file-state-replay.d.ts +3 -3
  95. package/dist/core/runner/session-rule-policy.d.ts +2 -2
  96. package/dist/core/runner/steer-admission.d.ts +2 -2
  97. package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
  98. package/dist/core/runner/stream-reap.d.ts +1 -1
  99. package/dist/core/runner/synthetic-tools.d.ts +8 -8
  100. package/dist/core/runner/teardown-bounded.d.ts +2 -2
  101. package/dist/core/runner/tool-defer-gate.d.ts +86 -0
  102. package/dist/core/runner/tool-defer-gate.js +57 -0
  103. package/dist/core/runner/tool-disclosure.d.ts +33 -69
  104. package/dist/core/runner/tool-disclosure.js +0 -43
  105. package/dist/core/runner/tool-end-body.d.ts +3 -3
  106. package/dist/core/runner/tool-face-overlay.d.ts +2 -2
  107. package/dist/core/runner/tool-output-projection.d.ts +2 -2
  108. package/dist/core/runner/turn-attachments.d.ts +53 -53
  109. package/dist/core/runner/usage-accounting.d.ts +4 -4
  110. package/dist/core/runner/workspace-path.d.ts +1 -1
  111. package/dist/core/runner-deps.d.ts +16 -9
  112. package/dist/core/task-spec.d.ts +8 -2
  113. package/dist/core/tool-spec.d.ts +7 -4
  114. package/dist/core/types.d.ts +1 -1
  115. package/dist/engine/llm/types.d.ts +1 -1
  116. package/dist/index.d.ts +4 -4
  117. package/dist/index.js +3 -3
  118. package/dist/tools/fs/bash-readonly-classifier.d.ts +40 -40
  119. package/dist/tools/fs/encoding.d.ts +31 -40
  120. package/dist/tools/fs/fs-bash.d.ts +76 -35
  121. package/dist/tools/fs/fs-bash.js +86 -29
  122. package/dist/tools/fs/fs-pdf.d.ts +8 -8
  123. package/dist/tools/fs/fs-search-tools.d.ts +4 -4
  124. package/dist/tools/fs/fs-shared.d.ts +144 -158
  125. package/dist/tools/fs/fs-write.d.ts +8 -8
  126. package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
  127. package/dist/tools/fs/index.d.ts +74 -78
  128. package/dist/tools/fs/notebook.d.ts +24 -25
  129. package/dist/tools/fs/pdf.d.ts +3 -3
  130. package/dist/tools/fs/read-deny.d.ts +22 -22
  131. package/dist/tools/fs/read-face.d.ts +21 -24
  132. package/dist/tools/fs/repo-map.d.ts +8 -8
  133. package/dist/tools/fs/safety.d.ts +116 -129
  134. package/dist/tools/fs/search.d.ts +63 -71
  135. package/package.json +5 -2
  136. package/test/export-surface.snapshot.json +9 -1
@@ -1,4 +1,5 @@
1
1
  import { type MemoryAnnouncement } from "./types.js";
2
+ import type { AssertAllKeysHandled } from "../ask-origin.js";
2
3
  /** Cursor sidecar for the design/84 Seam B pair on the FileBackend (`{ [scope]: cursor }`). B3: control plane. */
3
4
  export declare const CURSORS_FILE = "cursors.json";
4
5
  /** The control-plane subdir name under a key dir — ONE spelling for every derivation and for the
@@ -127,41 +128,126 @@ export declare function scopeDirName(scope: string): string;
127
128
  * Exported for the layout pins; not part of the package surface.
128
129
  */
129
130
  export declare function dirCaseFolds(dir: string): boolean | undefined;
130
- /** Which scope owns the memory dir ROOT (undefined = unclaimed). */
131
- export declare function rootScopeOf(controlDir: string): string | undefined;
132
- /**
133
- * Claim the memory dir root for `scope` iff unclaimed (idempotent, first-writer-wins, durable).
134
- * Returns the (possibly pre-existing) root owner. Lock-serialized (独立轨 F5): two first-users of a
135
- * shared mount race the claim under the sidecar lock — exactly one wins, the other SEES the winner.
136
- */
137
- export declare function claimRootScope(controlDir: string, scope: string): string;
138
- /** Register `scope` in the durable registry (idempotent) and return its home dir under `memoryDir`.
139
- * H5 fail-closed: a dir-name collision with a DIFFERENT registered scope throws — two scopes must
140
- * never share one directory (silent cross-scope merge). The collision test has TWO arms:
141
- * - exact: two scopes whose labels are the SAME string (hash collision / caller-declared registry);
142
- * - case-fold (2026-08-12): two labels differing ONLY in letter case are distinct strings to this
143
- * registry yet ONE physical directory on a case-folding volume cross-scope bleed the exact arm
144
- * cannot see. The fold arm compares the FINAL dir labels (ASCII by construction, so toLowerCase
145
- * is an exact fold) and only fires when the volume actually folds — probed lazily on a fold-equal
146
- * candidate ({@link dirCaseFolds}), so the no-collision path never pays the probe and a
147
- * case-SENSITIVE volume keeps hosting case-differing scope pairs as the genuinely distinct
148
- * directories they are there. An UNPROBEABLE volume (neither probe leg answers) refuses the
149
- * fold-equal pair too — an unresolved semantics guess would fail open exactly where the guard
150
- * is needed. `opts.caseFoldingFs` overrides the probe for callers (and pins) that already
151
- * measured the volume's semantics. The scope→dir MAPPING itself is unchanged on purpose:
152
- * folding scopeDirName would re-home every existing mixed-case scope's directory.
153
- * Both arms compare the scope's EFFECTIVE label — the registered one when present (a registered
154
- * scope's home NEVER moves; entries live there), the formula only for a never-registered scope —
155
- * so a registry whose stored labels drifted from the current formula is judged by the directories
156
- * it actually serves, not by labels nobody uses. Lock-serialized (独立轨 F5). */
131
+ /** The closure of every label {@link scopeDirName} can mint: a safe-form scope verbatim, or the
132
+ * folded form (leading `.`/`-` stripped) plus a hash suffix. One non-hidden path segment — never
133
+ * empty, never `.`/`..`, never a separator — so two labels are two distinct directory entries. */
134
+ export declare const SCOPE_DIR_LABEL_RE: RegExp;
135
+ /** Prefix of the case-fold probe files the layout leaves (briefly) at a memory root. One spelling
136
+ * for the probe writer and for the migration's residue removal. */
137
+ export declare const CASEFOLD_PROBE_PREFIX = ".casefold-probe-";
138
+ /** The four shapes a scope registry read can take. */
139
+ export declare const SCOPE_REGISTRY_SHAPES: readonly ["absent", "v1", "v2", "migrating"];
140
+ export type ScopeRegistryShape = (typeof SCOPE_REGISTRY_SHAPES)[number];
141
+ /** Which shapes the path-deriving read faces (`registerScope` / `scopeDirFor` / `registeredScopes`)
142
+ * may serve. `v1` (the pre-v2 file: a root-owning scope, `""` labels) and `migrating` (a v2 file
143
+ * carrying an unfinished move marker) are refused fail-closed: the registry then does not describe
144
+ * where entries physically live until {@link adoptRootScopeLayout} has run to completion. */
145
+ export declare const REGISTRY_SHAPE_DERIVES_PATHS: {
146
+ readonly absent: true;
147
+ readonly v1: false;
148
+ readonly v2: true;
149
+ readonly migrating: false;
150
+ };
151
+ export type DerivesPathsTableCoversEveryRegistryShape = AssertAllKeysHandled<Exclude<ScopeRegistryShape, keyof typeof REGISTRY_SHAPE_DERIVES_PATHS>>;
152
+ /** The unfinished-move marker: the physical root whose loose content is being moved into
153
+ * `<root>/<label>` for `owner`. Durable across crashes; whoever holds the registry lock next
154
+ * finishes it before doing anything else. */
155
+ export interface ScopeLayoutMigratingMarker {
156
+ root: string;
157
+ owner: string;
158
+ label: string;
159
+ }
160
+ /** The v2 registry record. `rootOwner` is the scope that historically owned the memory root; it is
161
+ * consulted only to attribute loose root content during adoption and never derives a path. */
162
+ export interface ScopesRecordV2 {
163
+ v: 2;
164
+ scopes: Record<string, string>;
165
+ rootOwner?: string;
166
+ migrating?: ScopeLayoutMigratingMarker;
167
+ }
168
+ /** A parsed registry, tagged by shape. `v1` keeps the pre-v2 fields for the one-time conversion. */
169
+ export type ScopeRegistryRead = {
170
+ shape: "absent";
171
+ rec: ScopesRecordV2;
172
+ } | {
173
+ shape: "v1";
174
+ rootScope?: string;
175
+ scopes: Record<string, string>;
176
+ } | {
177
+ shape: "v2";
178
+ rec: ScopesRecordV2;
179
+ } | {
180
+ shape: "migrating";
181
+ rec: ScopesRecordV2 & {
182
+ migrating: ScopeLayoutMigratingMarker;
183
+ };
184
+ };
185
+ /** Register `scope` in the durable registry (idempotent) and return its home `<memoryDir>/<label>`.
186
+ * The registered label is the truth for a scope that has one (a home never moves); the
187
+ * {@link scopeDirName} formula mints the label for a never-registered scope. Both collision arms
188
+ * run over the effective labels; the home is created on first registration and its physical form
189
+ * is proven on every call. Lock-serialized; a `v1`/`migrating` registry is refused. */
157
190
  export declare function registerScope(memoryDir: string, controlDir: string, scope: string, opts?: {
158
191
  caseFoldingFs?: boolean;
159
192
  }): string;
160
- /** All registered scopes → home dir name (`""` = the root). */
193
+ /** All registered scopes → label. A `v1`/`migrating` registry is refused. */
161
194
  export declare function registeredScopes(controlDir: string): Record<string, string>;
162
- /** The stable home directory of `scope`'s entry files: the root when it owns the root, else the
163
- * REGISTERED subdir (falls back to the {@link scopeDirName} formula for a never-registered scope). */
195
+ /** The stable home directory of `scope`'s entry files: `<memoryDir>/<label>`, the REGISTERED label
196
+ * when there is one, the formula otherwise. Registers nothing. A `v1`/`migrating` registry is refused. */
164
197
  export declare function scopeDirFor(memoryDir: string, controlDir: string, scope: string): string;
198
+ /** The scope registry's shape as it stands on disk (lock-free, journal-aware). Exported for the
199
+ * backend's cheap pre-check and for the layout pins; not part of the package surface. */
200
+ export declare function scopeRegistryShape(controlDir: string): ScopeRegistryShape;
201
+ /** The v1 path-key resolver (design A6): maps a memory-dir-relative persistent key written under the
202
+ * root-owning layout onto the ledger form `(scope, rel)`. The first segment names a registered
203
+ * non-owner label ⇒ that scope's home; otherwise the key belonged to the root owner. `undefined`
204
+ * when the row cannot be attributed (no root owner on record) — the caller keeps the row in its
205
+ * old form and refuses the operations that depend on it. Reads any registry shape (the conversion
206
+ * is independent of the physical move). */
207
+ export declare function v1MemoryPathKeyResolver(controlDir: string): (relPath: string) => {
208
+ scope: string;
209
+ rel: string;
210
+ } | undefined;
211
+ /** Options of {@link adoptRootScopeLayout}. `ownerCandidate` attributes loose root content when the
212
+ * registry records no root owner (the mount's write scope / a standalone batch's first add scope).
213
+ * `renew` is the caller's outer-lock heartbeat (the backend's transaction lock) — called before
214
+ * every filesystem action and every sidecar write, together with the registry lock's own. */
215
+ export interface AdoptRootScopeLayoutOptions {
216
+ ownerCandidate?: string | null;
217
+ onIncident?: MemoryPartitionIncidentSink;
218
+ renew?: () => void;
219
+ /** The one-time v1 sidecar key conversions, run in the adoption (before any later scope
220
+ * registration can change what a v1 key's first segment names). Each conversion is idempotent
221
+ * and takes its own sidecar lock. */
222
+ convertSidecars?: (controlDir: string) => void;
223
+ }
224
+ /** The lock-free pre-check the backend's public faces ask before a registry-derived path: does the
225
+ * tree at `root` still need the adoption (a v1/migrating registry, or loose content at the root)?
226
+ * One journal-aware registry read plus one readdir; the adoption re-enumerates under the locks. */
227
+ export declare function layoutNeedsAdoption(root: string, controlDir: string): boolean;
228
+ /**
229
+ * Adopt the per-scope layout for the physical tree at `root` (the engine's memory dir, or the
230
+ * backend's directory root; both when they differ — they share one control plane, so the registry
231
+ * conversion happens once). Runs under the registry lock; the caller holds any outer lock. Every
232
+ * step is idempotent and the two-phase marker makes an interrupted move resumable by whoever holds
233
+ * the lock next:
234
+ * 0. registry shape: `absent` ⇒ an empty v2 record; `v1` ⇒ v2 with `rootOwner` = the old
235
+ * `rootScope` (the root owner is also given its label); `migrating` ⇒ that move is finished
236
+ * FIRST, whichever tree it names. The root's loose content is enumerated on every call — a v2
237
+ * registry proves nothing about THIS tree.
238
+ * 1. loose content ⇒ owner = `rootOwner ?? ownerCandidate`; neither ⇒ `memory.layout_unowned_root_content`
239
+ * (names capped), registry converted, nothing moved.
240
+ * 2. pre-checks, zero writes: the control plane inside the root; the owner's home a link/file, or
241
+ * a real non-empty directory without a marker for it; any loose name already present in the
242
+ * home — each refuses with {@link ControlPlaneCorruptError}.
243
+ * 3. commit A: the v2 record with the owner registered, `rootOwner`, and the `migrating` marker.
244
+ * 4. move: per entry, lstat the destination (absent ⇒ rename; present ⇒ refuse; source gone ⇒
245
+ * already moved); probe residue removed. No sidecar key and no index text is rewritten (the
246
+ * ledger form keys are location-free; the index heals through its rebuild law).
247
+ * 5. `index-revs.json` cleared (fail-open snapshot; the next rebuild keeps model wording once).
248
+ * 6. commit B: the marker removed; `memory.layout_migrated` disclosed.
249
+ */
250
+ export declare function adoptRootScopeLayout(rootPath: string, controlDir: string, opts?: AdoptRootScopeLayoutOptions): void;
165
251
  /** Canonicalize a path for containment checks (resolves symlinks on the EXISTING prefix). */
166
252
  export declare function canonicalize(p: string): string;
167
253
  /** True iff `child` (canonicalized) is `root` or inside it. */
@@ -297,7 +383,10 @@ export declare function enqueueMemoryAnnouncement(controlDir: string, ann: Memor
297
383
  export declare function drainMemoryAnnouncements(controlDir: string): AnnouncementsRecord;
298
384
  /** Test/observability peek (journal-aware, non-destructive). */
299
385
  export declare function peekMemoryAnnouncements(controlDir: string): AnnouncementsRecord;
300
- /** S2-C record one write-time scan rejection for `key` (canonical file path); returns the count
386
+ /** The fuse key for a memory file: the ledger form `(scope, rel)` (`rel` relative to the scope's
387
+ * home, `/`-separated) — location-free, so a home move never re-keys a count. */
388
+ export declare function scanFuseKey(scope: string, rel: string): string;
389
+ /** S2-C — record one write-time scan rejection for `key` ({@link scanFuseKey}); returns the count
301
390
  * BEFORE this bump (callers mute the feedback when it is already ≥ {@link SCAN_FUSE_THRESHOLD}). */
302
391
  export declare function bumpScanFuse(controlDir: string, key: string): number;
303
392
  export declare function readIndexRevs(controlDir: string): Record<string, string>;
@@ -816,48 +905,57 @@ export declare function recordChallengedHistory(controlDir: string, rows: Readon
816
905
  /** Journal-aware read (observability/tests only — no engine consumer exists, on purpose). */
817
906
  export declare function readChallengedHistory(controlDir: string): Record<string, ChallengedHistoryRow>;
818
907
  export declare const PROJECTION_DEBTS_FILE = "projection-debts.json";
819
- /** One standing debt: the plane file at `relPath` (memory-dir-relative, canonical base) belongs to
820
- * committed entry `entryId`, whose id write-back has not landed; `rev` is the rev the projection
821
- * was staged against (the CAS baseline a reconciling harvest hands its update). */
908
+ /** One standing debt: the plane file at `(scope, rel)` — `rel` relative to the scope's home,
909
+ * `/`-separated — belongs to committed entry `entryId`, whose id write-back has not landed; `rev`
910
+ * is the rev the projection was staged against (the CAS baseline a reconciling harvest hands its
911
+ * update). The key is the ledger form: location-free, so a home move never re-keys a row. */
822
912
  export interface ProjectionDebtRow {
823
- relPath: string;
913
+ scope: string;
914
+ rel: string;
824
915
  entryId: string;
825
916
  rev: string;
826
917
  at: number;
827
918
  }
828
- /** WRITE-AHEAD staging. Upsert discipline (adversarial round 2): a stage lands only when the seat
829
- * has NO standing row, the standing row is the stager's OWN entry (a rev refresh), or the
830
- * standing row is the entry the stager itself just judged stale (`replaces` — the same-harvest
831
- * stale-then-remint lane). It never blindly replaces ANOTHER writer's protection: a lagging
832
- * process that validated an old row before pausing must not overwrite the row a faster sibling
833
- * staged at the same path (its own commit then CAS-conflicts and its tuple-keyed clear misses
834
- * the survivor the account converges instead of emptying). Called before the backend
835
- * transaction; the caller degrades LOUDLY (report warning) on a refused stage rather than
836
- * refusing the harvest — the ledger is duplicate-admission protection, not the commit's
837
- * integrity. */
919
+ /** WRITE-AHEAD staging. Upsert discipline: a stage lands only when the seat has NO standing row,
920
+ * the standing row is the stager's OWN entry (a rev refresh), or the standing row is the entry the
921
+ * stager itself just judged stale (`replaces` — the same-harvest stale-then-remint lane). It never
922
+ * blindly replaces ANOTHER writer's protection: a lagging process that validated an old row before
923
+ * pausing must not overwrite the row a faster sibling staged at the same seat (its own commit then
924
+ * CAS-conflicts and its tuple-keyed clear misses the survivor — the account converges instead of
925
+ * emptying). Called before the backend transaction; the caller degrades LOUDLY (report warning)
926
+ * on a refused stage rather than refusing the harvest the ledger is duplicate-admission
927
+ * protection, not the commit's integrity. */
838
928
  export declare function stageProjectionDebts(controlDir: string, rows: ReadonlyArray<{
839
- relPath: string;
929
+ scope: string;
930
+ rel: string;
840
931
  entryId: string;
841
932
  rev: string;
842
933
  replaces?: string;
843
934
  }>, now: () => number): {
844
935
  refused: Array<{
845
- relPath: string;
936
+ scope: string;
937
+ rel: string;
846
938
  entryId: string;
847
939
  }>;
848
940
  };
849
- /** Settle (remove) rows by ROW IDENTITY — (relPath, entryId), never the bare path: the write-back
941
+ /** Settle (remove) rows by ROW IDENTITY — (scope, rel, entryId), never the bare seat: the write-back
850
942
  * landed, the staged claim turned out stale, or a materialize re-projected the seat. Identity
851
- * matters (adversarial review F1): a stale-clear judged against an OLD row must not delete the
852
- * NEWER row a later staging upserted at the same path (same harvest: stale X cleared while fresh
853
- * Y's write-back failed — a path-keyed drop would erase Y and re-open the duplicate window; same
854
- * shape across processes for a lagging sibling's clear). Missing rows are a no-op (idempotent). */
943
+ * matters: a stale-clear judged against an OLD row must not delete the NEWER row a later staging
944
+ * upserted at the same seat. Missing rows are a no-op (idempotent). */
855
945
  export declare function settleProjectionDebts(controlDir: string, rows: ReadonlyArray<{
856
- relPath: string;
946
+ scope: string;
947
+ rel: string;
857
948
  entryId: string;
858
949
  }>): void;
859
- /** Strict read (ENOENT ⇒ empty; corrupt ⇒ throws — the caller's fail-closed arm owns the refusal). */
950
+ /** Strict read (ENOENT ⇒ empty; corrupt ⇒ throws — the caller's fail-closed arm owns the refusal).
951
+ * A v1 record is converted in the ledger's lock on this first read. Rows the registry
952
+ * could not attribute stay on the record's `unresolved` seat and are not served. */
860
953
  export declare function readProjectionDebts(controlDir: string): ProjectionDebtRow[];
954
+ /** The rows a key-form conversion could not attribute (audit read; empty on a converted ledger). */
955
+ export declare function unresolvedProjectionDebts(controlDir: string): Array<{
956
+ relPath: string;
957
+ entryId: string;
958
+ }>;
861
959
  /**
862
960
  * REF-C6 — write EVERY byte of `data` to `fd`, looping until the OS has taken all of them.
863
961
  *