@sema-agent/core 5.46.0 → 5.48.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/CHANGELOG.md +93 -0
- package/dist/agents/agent-transcript-tool.d.ts +4 -0
- package/dist/agents/agent-transcript-tool.js +10 -3
- package/dist/agents/send-message-tool.d.ts +43 -1
- package/dist/agents/send-message-tool.js +50 -11
- package/dist/agents/subagent.d.ts +18 -0
- package/dist/agents/subagent.js +231 -4
- package/dist/config/defaults.d.ts +20 -0
- package/dist/config/defaults.js +5 -0
- package/dist/core/background-agent-store.d.ts +1 -0
- package/dist/core/background-agent-store.js +13 -0
- package/dist/core/governance-codes.d.ts +13 -0
- package/dist/core/governance-codes.js +33 -0
- package/dist/core/mcp.d.ts +6 -1
- package/dist/core/mcp.js +34 -7
- package/dist/core/memory-engine/delegation-settlement.d.ts +318 -0
- package/dist/core/memory-engine/delegation-settlement.js +661 -0
- package/dist/core/memory-engine/engine.d.ts +159 -1
- package/dist/core/memory-engine/engine.js +699 -15
- package/dist/core/memory-engine/file-backend.d.ts +1 -0
- package/dist/core/memory-engine/file-backend.js +3 -1
- package/dist/core/memory-engine/frontmatter.d.ts +46 -19
- package/dist/core/memory-engine/frontmatter.js +91 -77
- package/dist/core/memory-engine/index.d.ts +4 -3
- package/dist/core/memory-engine/index.js +3 -2
- package/dist/core/memory-engine/layout.d.ts +14 -0
- package/dist/core/memory-engine/layout.js +2 -2
- package/dist/core/memory-engine/memory-backend-contract.js +43 -0
- package/dist/core/memory-engine/origin-clearance.d.ts +66 -0
- package/dist/core/memory-engine/origin-clearance.js +84 -0
- package/dist/core/memory-engine/provenance-wording.d.ts +50 -0
- package/dist/core/memory-engine/provenance-wording.js +15 -0
- package/dist/core/memory-engine/tools.d.ts +61 -7
- package/dist/core/memory-engine/tools.js +34 -9
- package/dist/core/memory-engine/types.d.ts +70 -2
- package/dist/core/reminder-disclosure.d.ts +90 -0
- package/dist/core/reminder-disclosure.js +64 -0
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +6 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +1 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -0
- package/dist/core/runner/prepare-hands-readface.js +1 -0
- package/dist/core/runner/prepare-memory.js +50 -15
- package/dist/core/runner/prepare-task.d.ts +39 -0
- package/dist/core/runner/prepare-task.js +128 -40
- package/dist/core/runner/runtask.js +3 -1
- package/dist/core/session-reconcile.js +3 -2
- package/dist/core/session-store.d.ts +59 -1
- package/dist/core/session-store.js +82 -14
- package/dist/core/session.d.ts +83 -1
- package/dist/core/task-registry-agent.d.ts +28 -0
- package/dist/core/task-registry-agent.js +63 -2
- package/dist/core/task-registry.d.ts +21 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/types.d.ts +98 -3
- package/dist/core/types.js +3 -0
- package/dist/core/untrusted-text.d.ts +63 -0
- package/dist/core/untrusted-text.js +48 -0
- package/dist/core/wiring-manifest.d.ts +35 -0
- package/dist/core/wiring-manifest.js +21 -1
- package/dist/engine/harness/types.d.ts +36 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +6 -4
- package/dist/internal/harness-types.d.ts +1 -0
- package/dist/stores/file/index.d.ts +19 -3
- package/dist/stores/file/index.js +24 -1
- package/dist/stores/file/session-store.d.ts +18 -4
- package/dist/stores/file/session-store.js +73 -12
- package/dist/tools/fs/fs-pdf.d.ts +12 -1
- package/dist/tools/fs/fs-pdf.js +17 -3
- package/dist/tools/fs/fs-read.d.ts +2 -1
- package/dist/tools/fs/fs-read.js +33 -5
- package/dist/tools/fs/fs-shared.d.ts +6 -2
- package/dist/tools/fs/index.d.ts +7 -0
- package/dist/tools/fs/index.js +1 -1
- package/dist/tools/task-list.d.ts +5 -1
- package/dist/tools/web.js +21 -2
- package/package.json +3 -2
- package/test/export-surface.snapshot.json +24 -2
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import type { MemoryOriginCause } from "./types.js";
|
|
2
|
+
export declare const DELEGATION_SETTLEMENT_FILE = "delegation-settlement.json";
|
|
3
|
+
/** A row's FIRST-WRITE status. Rows are immutable after their first write — every later transition
|
|
4
|
+
* is an append-only event ({@link SettlementEvent}); the effective status is the fold. */
|
|
5
|
+
export type SettlementRowStatus = "pending" | "unattestable";
|
|
6
|
+
/** The effective (folded) status vocabulary. */
|
|
7
|
+
export type SettlementStatus = "pending" | "clean" | "external" | "expired" | "void" | "unattestable";
|
|
8
|
+
/** One delegation's launch fact (write-ahead: this row lands BEFORE the delegation registers or
|
|
9
|
+
* invokes — a launch that cannot be accounted must not run). */
|
|
10
|
+
export interface DelegationSettlementRow {
|
|
11
|
+
/** Background lane: minted at the write-ahead point (the launch site holds it thereafter).
|
|
12
|
+
* Sync lane: the injective `(sessionId, toolCallId)` encoding ({@link syncSettleId}). */
|
|
13
|
+
settleId: string;
|
|
14
|
+
sessionId: string;
|
|
15
|
+
launchedAt: number;
|
|
16
|
+
lane: "background" | "sync";
|
|
17
|
+
status: SettlementRowStatus;
|
|
18
|
+
/** The delegation TOOL CALL that launched this row (background lane) — the receipt-exemption
|
|
19
|
+
* anchor: a sync delivery claiming to be a background launch receipt is honored only when a
|
|
20
|
+
* write-ahead row for ITS OWN toolUseId exists (a status string alone must not buy the
|
|
21
|
+
* exemption — adversarial round 2's forged-receipt vehicle). */
|
|
22
|
+
toolUseId?: string;
|
|
23
|
+
}
|
|
24
|
+
/** One append-only transition/annotation event. Idempotent per eventId. */
|
|
25
|
+
export interface SettlementEvent {
|
|
26
|
+
settleId: string;
|
|
27
|
+
eventId: string;
|
|
28
|
+
at: number;
|
|
29
|
+
kind: "settle" | "admin-resolve" | "annotation";
|
|
30
|
+
/** For `settle`: the observed terminal (`"unattestable"` = the delegation terminated but its
|
|
31
|
+
* conduct is permanently unprovable — a recorder-less or incomplete chain). For `admin-resolve`:
|
|
32
|
+
* the host's ruling ("clean"|"external"). */
|
|
33
|
+
status?: "clean" | "external" | "expired" | "void" | "unattestable";
|
|
34
|
+
/** Audit attribution for `admin-resolve` (who asked — required there, refused absent). */
|
|
35
|
+
requestId?: string;
|
|
36
|
+
note?: string;
|
|
37
|
+
}
|
|
38
|
+
/** The injective sync-lane settleId: `encodeURIComponent` on both members keeps the separator
|
|
39
|
+
* unambiguous (neither side can smuggle a `:`), so `(sessionId, toolCallId)` is one-to-one. */
|
|
40
|
+
export declare function syncSettleId(sessionId: string, toolCallId: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* §3.3 write-ahead — land the pending row for a BACKGROUND delegation, before registration and
|
|
43
|
+
* before invoke (行→注册→invoke). Idempotent per settleId (a revive cycle re-registers under a
|
|
44
|
+
* fresh settleId; a crash-retry of the same launch replays the same row). Throws on an unwritable
|
|
45
|
+
* or corrupt ledger — the launch site fails the launch loudly (a delegation that cannot be
|
|
46
|
+
* accounted must not run: the whole point is that no child exists outside the account).
|
|
47
|
+
*/
|
|
48
|
+
export declare function registerDelegationLaunch(controlDir: string, input: {
|
|
49
|
+
settleId: string;
|
|
50
|
+
sessionId: string;
|
|
51
|
+
now: () => number;
|
|
52
|
+
toolUseId?: string;
|
|
53
|
+
}): void;
|
|
54
|
+
/**
|
|
55
|
+
* §3.5 (r5-3) — the SYNC lane's unattestable row: a synchronous delegation delivered with a
|
|
56
|
+
* missing/unknown attestation under the "attested-only" evidence standard. The row is a durable
|
|
57
|
+
* TERMINAL at first write (there is nothing left to settle — the window is already closed
|
|
58
|
+
* unprovable), and it must commit BEFORE the result enters the transcript: the caller treats a
|
|
59
|
+
* throw here as "deliver an error instead" (fail-closed — unattested content must not ride into
|
|
60
|
+
* the transcript of a session whose account could not record the fact).
|
|
61
|
+
*/
|
|
62
|
+
export declare function recordSyncUnattestable(controlDir: string, input: {
|
|
63
|
+
sessionId: string;
|
|
64
|
+
toolCallId: string;
|
|
65
|
+
now: () => number;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* §3.3 settle — append one observed terminal (idempotent per eventId; the default eventId keys on
|
|
69
|
+
* (settleId, status) so an at-least-once observer replays into one event). Transition legality is
|
|
70
|
+
* the FOLD's question, not the append's: an event that the fold rules out (e.g. `clean` arriving
|
|
71
|
+
* after `expired`) still lands — as an event row the fold reads as an annotation-grade fact — so
|
|
72
|
+
* the account never loses an observation (事件不丢), it just doesn't let it rewrite history.
|
|
73
|
+
*/
|
|
74
|
+
export declare function settleDelegation(controlDir: string, input: {
|
|
75
|
+
settleId: string;
|
|
76
|
+
status: "clean" | "external" | "expired" | "void" | "unattestable";
|
|
77
|
+
now: () => number;
|
|
78
|
+
eventId?: string;
|
|
79
|
+
note?: string;
|
|
80
|
+
}): void;
|
|
81
|
+
/**
|
|
82
|
+
* §3.3 host valve — `resolveSettlement(settleId, "clean"|"external", requestId)`. Advisory, same
|
|
83
|
+
* trust plane as the host API family; `requestId` is the audit anchor and is REQUIRED (a
|
|
84
|
+
* settlement resolution without attribution is refused loudly, #123 posture). Effective-state
|
|
85
|
+
* semantics live in the fold: an admin `clean` flips the EFFECTIVE state (releases post-expiry)
|
|
86
|
+
* but never the history bit, and a LATER observed `external` overrides it (观测证据>admin 裁决).
|
|
87
|
+
*/
|
|
88
|
+
export declare function resolveSettlementRecord(controlDir: string, input: {
|
|
89
|
+
settleId: string;
|
|
90
|
+
to: "clean" | "external";
|
|
91
|
+
requestId: string;
|
|
92
|
+
now: () => number;
|
|
93
|
+
}): void;
|
|
94
|
+
/** One settlement's folded (effective) view. */
|
|
95
|
+
export interface EffectiveSettlement {
|
|
96
|
+
row: DelegationSettlementRow;
|
|
97
|
+
/** The effective status after the fold (终局序: clean/external 互斥首达胜; external 可覆写
|
|
98
|
+
* expired; admin clean 翻 effective 不翻史; admin 之后的 observed external 再覆写). */
|
|
99
|
+
effective: SettlementStatus;
|
|
100
|
+
/** Monotonic history bit: an `external` was EVER observed (never cleared, admin included not —
|
|
101
|
+
* admin resolves are rulings, not observations). */
|
|
102
|
+
everExternal: boolean;
|
|
103
|
+
/** The terminal event whose identity keys the external-effects replay (undefined while pending). */
|
|
104
|
+
terminalEventId?: string;
|
|
105
|
+
}
|
|
106
|
+
/** Lock-less folded read of the whole ledger (journal-aware, fail-closed on corruption). */
|
|
107
|
+
export declare function effectiveSettlements(controlDir: string): EffectiveSettlement[];
|
|
108
|
+
/** One session's folded rows (the harvest classifier's input). */
|
|
109
|
+
export declare function sessionSettlements(controlDir: string, sessionId: string): EffectiveSettlement[];
|
|
110
|
+
/**
|
|
111
|
+
* §3.1 — the session exposure classifier over the settlement account (the durable pollution marker
|
|
112
|
+
* is the OTHER input; the caller ORs them). `exposed` ⇔ any {external, unattestable, expired}
|
|
113
|
+
* effective row; `pending` ⇔ not exposed ∧ any pending row. The mint cause follows the strongest
|
|
114
|
+
* evidence: an external row is an observed fact; unattestable/expired are evidence windows that
|
|
115
|
+
* closed unprovable (the static-standard cause).
|
|
116
|
+
*/
|
|
117
|
+
export declare function classifySessionSettlements(rows: readonly EffectiveSettlement[]): {
|
|
118
|
+
state: "clean" | "pending" | "exposed";
|
|
119
|
+
cause?: MemoryOriginCause;
|
|
120
|
+
reason?: string;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* §3.3-4 — expire overdue pending rows (reconciliation's first leg). Every expiry is an event
|
|
124
|
+
* (idempotent by (settleId, "expired") key); returns the settleIds newly expired this pass.
|
|
125
|
+
*/
|
|
126
|
+
export declare function expireOverdueSettlements(controlDir: string, input: {
|
|
127
|
+
timeoutMs: number;
|
|
128
|
+
now: () => number;
|
|
129
|
+
}): string[];
|
|
130
|
+
/**
|
|
131
|
+
* §3.3-2 — replay the EXTERNAL rows' side effects (账先落、副作用可重放): ensure the durable
|
|
132
|
+
* pollution marker is in place (wx, first-write-wins) and the retroaction challenge sweep has
|
|
133
|
+
* covered the session's unmarked committed contributions (eventId keyed to the terminal event —
|
|
134
|
+
* a replay lands the SAME generation, a later terminal re-arms). Also enqueues the next-session
|
|
135
|
+
* announcement once per terminal event. Idempotent throughout; the watermark only skips work.
|
|
136
|
+
* `carry` scopes the sweep domain exactly like the engine's own sweeps (marked rows carry their
|
|
137
|
+
* account under "carry"; the "off" width challenges everything).
|
|
138
|
+
*/
|
|
139
|
+
export declare function replayExternalSettlementEffects(controlDir: string, input: {
|
|
140
|
+
carry: boolean;
|
|
141
|
+
now: () => number;
|
|
142
|
+
}): Array<{
|
|
143
|
+
settleId: string;
|
|
144
|
+
sessionId: string;
|
|
145
|
+
}>;
|
|
146
|
+
export declare const SESSION_ACCOUNTS_FILE = "session-accounts.json";
|
|
147
|
+
export interface SessionAccountRow {
|
|
148
|
+
sessionId: string;
|
|
149
|
+
openedAt: number;
|
|
150
|
+
/** The STICKY unattributed set (rel paths), frozen at materialize (§3.6 归属判据): pre-existing,
|
|
151
|
+
* uncommitted files seen while a FOREIGN dangling open row stood. Membership never shrinks on
|
|
152
|
+
* later writes (the r3-5 sticky law); it clears only when the row is re-opened with a fresh
|
|
153
|
+
* classification (the residue was adjudicated by an intervening harvest). */
|
|
154
|
+
unattributed: string[];
|
|
155
|
+
closedAt?: number;
|
|
156
|
+
/** r7-3 — the host valve closed this row WITHOUT adjudication: it stops dangling but keeps
|
|
157
|
+
* triggering the residue arm until the next FULL-domain harvest closes an account normally
|
|
158
|
+
* (an unadjudicated close must not launder the residue window it covered). */
|
|
159
|
+
unadjudicated?: true;
|
|
160
|
+
}
|
|
161
|
+
/** The dangling-trigger read: open rows (and unadjudicated closes) belonging to OTHER sessions.
|
|
162
|
+
* These are what arm the unattributed residue classification at a session's materialize. */
|
|
163
|
+
export declare function foreignDanglingSessionAccounts(controlDir: string, selfSessionId: string): SessionAccountRow[];
|
|
164
|
+
/** Open (or re-open, on a same-session resume) the session's account row, persisting the sticky
|
|
165
|
+
* unattributed classification frozen at THIS materialize. */
|
|
166
|
+
export declare function openSessionAccount(controlDir: string, input: {
|
|
167
|
+
sessionId: string;
|
|
168
|
+
now: () => number;
|
|
169
|
+
unattributed: readonly string[];
|
|
170
|
+
}): void;
|
|
171
|
+
/** The current session's sticky unattributed set (the harvest's residue-arm input). */
|
|
172
|
+
export declare function sessionUnattributedSet(controlDir: string, sessionId: string): Set<string>;
|
|
173
|
+
/** Close the session's account row — called ONLY after a FULL-domain harvest (zero deferred
|
|
174
|
+
* files): a partial harvest's close would launder the deferred residue window (§3.6 序则②).
|
|
175
|
+
* A normal full close also clears every standing `unadjudicated` flag (r7-3: the valve's
|
|
176
|
+
* conservative window ends when a full harvest has adjudicated the plane). */
|
|
177
|
+
export declare function closeSessionAccount(controlDir: string, input: {
|
|
178
|
+
sessionId: string;
|
|
179
|
+
now: () => number;
|
|
180
|
+
}): void;
|
|
181
|
+
/** The host valve for a dangling row (advisory; §3.6 — dangling rows never auto-expire). The
|
|
182
|
+
* close is `closed-unadjudicated` (r7-3): it stops the row dangling but the residue arm keeps
|
|
183
|
+
* firing until a full-domain harvest closes normally. `requestId` required (audit, #123). */
|
|
184
|
+
export declare function resolveSessionAccountRecord(controlDir: string, input: {
|
|
185
|
+
sessionId: string;
|
|
186
|
+
requestId: string;
|
|
187
|
+
now: () => number;
|
|
188
|
+
}): void;
|
|
189
|
+
export declare const HOLDS_FILE = "holds.json";
|
|
190
|
+
export declare const HOLD_DIR = "hold";
|
|
191
|
+
export type HoldStatus = "capturing" | "held" | "released" | "disposed";
|
|
192
|
+
export type HoldTerminal = "dirty" | "expired" | "conflict" | "discarded" | "capture_lost";
|
|
193
|
+
export interface HoldRow {
|
|
194
|
+
holdId: string;
|
|
195
|
+
/** The WRITER session (lineage attribution on release records this id — the true author). */
|
|
196
|
+
sessionId: string;
|
|
197
|
+
/** The committed entry this hold's file addressed, when it addressed one (update form). */
|
|
198
|
+
entryId?: string;
|
|
199
|
+
op: "add" | "update";
|
|
200
|
+
/** CAS anchor at capture time (update form): release refuses to blind-write over a later edit. */
|
|
201
|
+
baseRev?: string;
|
|
202
|
+
/** Path relative to the memory dir (the plane seat the file was removed from). */
|
|
203
|
+
relPath: string;
|
|
204
|
+
/** The entry slug (path relative to the scope dir, sans `.md`) — the release leg's projection
|
|
205
|
+
* identity and its filename-scan input. */
|
|
206
|
+
slug: string;
|
|
207
|
+
/** The write scope the capture belonged to — the release commits into it. */
|
|
208
|
+
scope: string;
|
|
209
|
+
/** The custody file name under `hold/`. */
|
|
210
|
+
captureName: string;
|
|
211
|
+
/** sha256 over the captured bytes (minted from the ONE read buffer — the same buffer writes the
|
|
212
|
+
* custody file and, verified, is what release commits: no verify-reread window). */
|
|
213
|
+
contentDigest: string;
|
|
214
|
+
capturedAt: number;
|
|
215
|
+
/** The settlement rows whose outcome this hold waits on (the session's pending set at capture). */
|
|
216
|
+
settleIds: string[];
|
|
217
|
+
status: HoldStatus;
|
|
218
|
+
disposition?: {
|
|
219
|
+
terminal: HoldTerminal;
|
|
220
|
+
quarantineName?: string;
|
|
221
|
+
};
|
|
222
|
+
/** Host valve verdict awaiting the next harvest ("release" commits with cause "static"). */
|
|
223
|
+
resolved?: "release" | "discard";
|
|
224
|
+
}
|
|
225
|
+
export declare function readHolds(controlDir: string): HoldRow[];
|
|
226
|
+
/** ATOMIC no-replace restore of a staged file onto a plane path (adversarial round 2: an
|
|
227
|
+
* existsSync-then-rename pair is a TOCTOU — POSIX rename REPLACES a destination created between
|
|
228
|
+
* the check and the call, clobbering a third writer's newer bytes). `link` refuses EEXIST
|
|
229
|
+
* atomically: on success the staging name is dropped (one inode, two names → one); on EEXIST the
|
|
230
|
+
* staging file is KEPT (custody — never overwrite the plane's newer legal bytes). */
|
|
231
|
+
export declare function noReplaceRestore(stagingPath: string, destPath: string): "restored" | "kept" | "stranded";
|
|
232
|
+
/**
|
|
233
|
+
* §4.2 — open one hold over an instruction-form file: the two-stage journal.
|
|
234
|
+
* ① append row `status:"capturing"` (deterministic captureName + contentDigest minted from the
|
|
235
|
+
* one read buffer) — the account exists before any byte moves;
|
|
236
|
+
* ② write the custody file FROM THE SAME BUFFER, read it back, verify the digest;
|
|
237
|
+
* ③ remove the plane file RENAME-FIRST (atomic move into `hold/<staging>`), then hash what
|
|
238
|
+
* actually moved: equal ⇒ the staging duplicate is dropped (custody already holds verified
|
|
239
|
+
* bytes); unequal ⇒ a third writer replaced the file between read and rename — NO-CLOBBER
|
|
240
|
+
* rollback (the newer bytes go back ONLY if the plane path is still absent; a re-created path
|
|
241
|
+
* keeps both copies, staging stays in custody and the caller hears "conflict" — never an
|
|
242
|
+
* overwrite of newer legal bytes);
|
|
243
|
+
* ④ flip the row to `"held"`.
|
|
244
|
+
* Every failure path returns a structured outcome (never throws past the row append): the caller
|
|
245
|
+
* fail-closes the file through the ordinary quarantine containment instead — an instruction file
|
|
246
|
+
* must never stay on the plane because its hold failed. EXDEV on the rename is one such refusal
|
|
247
|
+
* (cross-filesystem staging gives up rename atomicity — refused, not degraded to copy+delete).
|
|
248
|
+
*/
|
|
249
|
+
export declare function openInstructionHold(controlDir: string, input: {
|
|
250
|
+
sessionId: string;
|
|
251
|
+
relPath: string;
|
|
252
|
+
absPath: string;
|
|
253
|
+
content: string;
|
|
254
|
+
entryId?: string;
|
|
255
|
+
op: "add" | "update";
|
|
256
|
+
baseRev?: string;
|
|
257
|
+
slug: string;
|
|
258
|
+
scope: string;
|
|
259
|
+
settleIds: readonly string[];
|
|
260
|
+
now: () => number;
|
|
261
|
+
}): {
|
|
262
|
+
ok: true;
|
|
263
|
+
holdId: string;
|
|
264
|
+
thirdWriterStranded?: string;
|
|
265
|
+
} | {
|
|
266
|
+
ok: false;
|
|
267
|
+
holdId?: string;
|
|
268
|
+
reason: string;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* §4.2 reconciliation — converge half-way holds (a crash between the journal stages):
|
|
272
|
+
* - `capturing` + custody file present & digest-equal ⇒ flip held (the crash was after ②);
|
|
273
|
+
* - `capturing` + custody absent + plane file present & digest-equal ⇒ complete the capture and
|
|
274
|
+
* continue the two-stage walk; digest-UNEQUAL ⇒ the bytes were replaced — `capture_lost`
|
|
275
|
+
* (the file stays on the plane and walks the ordinary/§3.6 arms; never "capture whatever is
|
|
276
|
+
* there now" — that would hold a third writer's bytes under the first writer's account);
|
|
277
|
+
* - `capturing` + custody absent + plane file gone ⇒ `capture_lost` (nothing to hold).
|
|
278
|
+
* - `held` + plane file REAPPEARED at the relPath ⇒ left alone (a fresh write is a fresh file —
|
|
279
|
+
* the next harvest judges it on its own; the hold's custody bytes stay the hold's).
|
|
280
|
+
*/
|
|
281
|
+
export declare function reconcileHolds(controlDir: string, input: {
|
|
282
|
+
memoryDir: string;
|
|
283
|
+
now: () => number;
|
|
284
|
+
}): void;
|
|
285
|
+
/** Dispose one held row: custody bytes move to the quarantine directory (host-auditable), the row
|
|
286
|
+
* records its terminal + quarantineName (from-row-to-bytes addressing survives every terminal). */
|
|
287
|
+
export declare function disposeHold(controlDir: string, input: {
|
|
288
|
+
holdId: string;
|
|
289
|
+
terminal: HoldTerminal;
|
|
290
|
+
now: () => number;
|
|
291
|
+
}): {
|
|
292
|
+
ok: boolean;
|
|
293
|
+
quarantineName?: string;
|
|
294
|
+
};
|
|
295
|
+
/** Flip one row to released (the caller — the harvest release leg — has already committed the
|
|
296
|
+
* custody bytes through the full gate set; the custody file is dropped after the flip). */
|
|
297
|
+
export declare function markHoldReleased(controlDir: string, input: {
|
|
298
|
+
holdId: string;
|
|
299
|
+
now: () => number;
|
|
300
|
+
}): void;
|
|
301
|
+
/** The host valve — `resolveHold(holdId, "release"|"discard", requestId)`: records the verdict on
|
|
302
|
+
* the row; the NEXT harvest reconciliation executes it ("release" re-walks the full gates and
|
|
303
|
+
* commits WITH cause "static" — a timeout release is not proof of cleanliness; "discard"
|
|
304
|
+
* disposes to quarantine). requestId required (audit, #123). */
|
|
305
|
+
export declare function resolveHoldRecord(controlDir: string, input: {
|
|
306
|
+
holdId: string;
|
|
307
|
+
action: "release" | "discard";
|
|
308
|
+
requestId: string;
|
|
309
|
+
now: () => number;
|
|
310
|
+
}): void;
|
|
311
|
+
/** Read one hold's custody bytes (release leg + expired-release valve). Returns undefined when
|
|
312
|
+
* the custody file is gone or fails its digest — the caller records capture_lost, never commits
|
|
313
|
+
* unverified bytes. For an expired-released row the bytes may already sit in quarantine
|
|
314
|
+
* (disposition.quarantineName) — both seats are tried, digest-verified either way. */
|
|
315
|
+
export declare function readHoldCustody(controlDir: string, row: HoldRow): string | undefined;
|
|
316
|
+
/** True ⇔ the session's pollution marker or any non-clean settlement row blocks a clean release
|
|
317
|
+
* (§4.2-1: any non-clean row in the session's account keeps the hold held/disposed). */
|
|
318
|
+
export declare function sessionBlocksCleanRelease(controlDir: string, sessionId: string): boolean;
|