@intx/hub-sessions 0.1.2 → 0.2.2

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 (87) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +84 -1
  3. package/dist/agent-repo.d.ts +89 -0
  4. package/dist/agent-repo.js +109 -0
  5. package/dist/agent-state-kind.d.ts +12 -0
  6. package/dist/agent-state-kind.js +185 -0
  7. package/dist/asset-service.d.ts +123 -0
  8. package/dist/asset-service.js +349 -0
  9. package/dist/available-skills-stanza.d.ts +21 -0
  10. package/dist/available-skills-stanza.js +32 -0
  11. package/dist/credential-push.d.ts +32 -0
  12. package/dist/credential-push.js +85 -0
  13. package/dist/event-collector-registry.d.ts +20 -0
  14. package/dist/event-collector-registry.js +115 -0
  15. package/dist/event-collector.d.ts +39 -0
  16. package/dist/event-collector.js +357 -0
  17. package/dist/hub-session-lookups.d.ts +17 -0
  18. package/dist/hub-session-lookups.js +204 -0
  19. package/dist/hub-session-orchestrator.d.ts +25 -0
  20. package/dist/hub-session-orchestrator.js +122 -0
  21. package/dist/index.d.ts +18 -0
  22. package/dist/index.js +16 -0
  23. package/dist/package-registry-kind.d.ts +70 -0
  24. package/dist/package-registry-kind.js +260 -0
  25. package/dist/repo-store/index.d.ts +4 -0
  26. package/dist/repo-store/index.js +3 -0
  27. package/dist/repo-store/store.d.ts +41 -0
  28. package/dist/repo-store/store.js +1692 -0
  29. package/dist/repo-store/subscribe-kind.d.ts +53 -0
  30. package/dist/repo-store/subscribe-kind.js +179 -0
  31. package/dist/repo-store/types.d.ts +483 -0
  32. package/dist/repo-store/types.js +42 -0
  33. package/dist/session-service.d.ts +235 -0
  34. package/dist/session-service.js +997 -0
  35. package/dist/skill-kind.d.ts +41 -0
  36. package/dist/skill-kind.js +288 -0
  37. package/dist/substrate.d.ts +8 -0
  38. package/dist/substrate.js +21 -0
  39. package/dist/workflow-kind.d.ts +21 -0
  40. package/dist/workflow-kind.js +263 -0
  41. package/dist/workflow-run-event-log.d.ts +21 -0
  42. package/dist/workflow-run-event-log.js +51 -0
  43. package/dist/workflow-run-kind.d.ts +326 -0
  44. package/dist/workflow-run-kind.js +2646 -0
  45. package/dist/workflow-run-reader.d.ts +47 -0
  46. package/dist/workflow-run-reader.js +157 -0
  47. package/dist/ws/index.d.ts +3 -0
  48. package/dist/ws/index.js +3 -0
  49. package/dist/ws/sidecar-events.d.ts +134 -0
  50. package/dist/ws/sidecar-events.js +70 -0
  51. package/dist/ws/sidecar-handler.d.ts +184 -0
  52. package/dist/ws/sidecar-handler.js +1603 -0
  53. package/dist/ws/sidecar-token-authenticator.d.ts +15 -0
  54. package/dist/ws/sidecar-token-authenticator.js +24 -0
  55. package/package.json +34 -12
  56. package/src/agent-repo.test.ts +0 -310
  57. package/src/agent-repo.ts +0 -165
  58. package/src/agent-state-kind.test.ts +0 -247
  59. package/src/agent-state-kind.ts +0 -204
  60. package/src/asset-service.test.ts +0 -540
  61. package/src/asset-service.ts +0 -378
  62. package/src/available-skills-stanza.test.ts +0 -87
  63. package/src/available-skills-stanza.ts +0 -47
  64. package/src/credential-push.ts +0 -65
  65. package/src/event-collector-registry.test.ts +0 -73
  66. package/src/event-collector-registry.ts +0 -171
  67. package/src/event-collector.test.ts +0 -1387
  68. package/src/event-collector.ts +0 -424
  69. package/src/hub-session-lookups.ts +0 -206
  70. package/src/hub-session-orchestrator.test.ts +0 -510
  71. package/src/hub-session-orchestrator.ts +0 -213
  72. package/src/index.ts +0 -78
  73. package/src/repo-store/index.ts +0 -15
  74. package/src/repo-store/store.test.ts +0 -1169
  75. package/src/repo-store/store.ts +0 -428
  76. package/src/repo-store/types.ts +0 -253
  77. package/src/session-service.test.ts +0 -895
  78. package/src/session-service.ts +0 -464
  79. package/src/skill-kind.test.ts +0 -599
  80. package/src/skill-kind.ts +0 -350
  81. package/src/ws/index.ts +0 -18
  82. package/src/ws/sidecar-events.test.ts +0 -96
  83. package/src/ws/sidecar-events.ts +0 -231
  84. package/src/ws/sidecar-handler.test.ts +0 -2217
  85. package/src/ws/sidecar-handler.ts +0 -1574
  86. package/tsconfig.json +0 -4
  87. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,51 @@
1
+ // The sealed-form event log for a terminated run. Compaction folds a run's
2
+ // per-event `runs/<runId>/events/<seq>.json` blobs into a single combined
3
+ // file, `runs/<runId>/events.jsonl`, once the run reaches a terminal event.
4
+ // Each line of the combined file is the verbatim text of the per-event blob
5
+ // it replaced, in seq order, so the fold is a byte-for-byte transition that
6
+ // the workflow-run kind handler can validate against the prior per-event
7
+ // tree. Readers handle both shapes: per-event files for in-flight runs, the
8
+ // combined file for sealed (terminal) runs.
9
+ /** Filename of a run's combined event log, a sibling of its `events/` dir. */
10
+ export const WORKFLOW_RUN_EVENTS_FILE = "events.jsonl";
11
+ /**
12
+ * Split a combined event-log file's content into the per-event JSON texts it
13
+ * holds, in file order. Each non-empty line is the verbatim text of what was
14
+ * an `events/<seq>.json` blob; the trailing newline yields no extra entry.
15
+ * Event JSON never contains a literal newline (JSON escapes them), so a line
16
+ * split is a faithful inverse of the encode side.
17
+ */
18
+ export function splitCombinedEventLog(content) {
19
+ const out = [];
20
+ for (const line of content.split("\n")) {
21
+ if (line.length === 0)
22
+ continue;
23
+ out.push(line);
24
+ }
25
+ return out;
26
+ }
27
+ /**
28
+ * Join per-event blobs (in seq order) into a combined event-log file: each
29
+ * blob's exact bytes followed by a newline. Operating on bytes -- not
30
+ * decoded strings -- keeps the sealed file a *verbatim* concatenation of
31
+ * the per-event blobs, which matters because each event is signed over its
32
+ * own bytes; a decode/re-encode round-trip could alter them. This is the
33
+ * single source of the combined-file byte layout shared by the compaction
34
+ * writer and the validator's byte-equality bridge, so the two cannot
35
+ * drift. An empty input yields an empty file.
36
+ */
37
+ export function encodeCombinedEventLog(perEventBlobs) {
38
+ const NEWLINE = 0x0a;
39
+ let total = 0;
40
+ for (const blob of perEventBlobs)
41
+ total += blob.byteLength + 1;
42
+ const out = new Uint8Array(total);
43
+ let offset = 0;
44
+ for (const blob of perEventBlobs) {
45
+ out.set(blob, offset);
46
+ offset += blob.byteLength;
47
+ out[offset] = NEWLINE;
48
+ offset += 1;
49
+ }
50
+ return out;
51
+ }
@@ -0,0 +1,326 @@
1
+ import { type AuthorizeFn, type KindHandler, type Principal, type RepoId, type RepoStore } from "./repo-store/index.js";
2
+ export type WorkflowRunHubPrincipal = {
3
+ readonly kind: "hub";
4
+ };
5
+ export type WorkflowRunSidecarPrincipal = {
6
+ readonly kind: "sidecar";
7
+ readonly agentId: string;
8
+ };
9
+ export type WorkflowRunWorkflowProcessPrincipal = {
10
+ readonly kind: "workflow-process";
11
+ readonly deploymentId: string;
12
+ readonly runId?: string;
13
+ };
14
+ export type WorkflowRunSupervisorPrincipal = {
15
+ readonly kind: "supervisor";
16
+ readonly deploymentId: string;
17
+ };
18
+ export type WorkflowRunPrincipal = WorkflowRunHubPrincipal | WorkflowRunSidecarPrincipal | WorkflowRunWorkflowProcessPrincipal | WorkflowRunSupervisorPrincipal;
19
+ export declare const WORKFLOW_RUN_GITIGNORE_PATH = ".gitignore";
20
+ export declare const WORKFLOW_RUN_RUNS_PREFIX = "runs";
21
+ export declare const WORKFLOW_RUN_EVENTS_DIR = "events";
22
+ export declare const WORKFLOW_RUN_BLOBS_DIR = "blobs";
23
+ export declare const WORKFLOW_RUN_ADDRESSES_PREFIX = "addresses";
24
+ export declare const WORKFLOW_RUN_CONTROL_PREFIX = "control";
25
+ export declare const WORKFLOW_RUN_INBOX_DIR = "inbox";
26
+ export declare const WORKFLOW_RUN_PROCESSING_DIR = "processing";
27
+ export declare const WORKFLOW_RUN_CONSUMED_DIR = "consumed";
28
+ /**
29
+ * Filename of the per-address retention watermark blob, a direct child
30
+ * of `addresses/<urlEncoded>/` (a file, not a directory). Carries the
31
+ * monotonic `receivedAt`-horizon below which consumed entries may be
32
+ * pruned and at-or-below which inbound enqueues are refused as stale.
33
+ */
34
+ export declare const WORKFLOW_RUN_WATERMARK_FILE = "watermark.json";
35
+ /**
36
+ * Default retention horizon for the consumed dedup index, in
37
+ * milliseconds. The boot edge resolves the operator's
38
+ * `CONSUMED_RETENTION_MS` config to a concrete value and threads it
39
+ * into `markConsumed`; this default applies only when no operator
40
+ * value is supplied. 24 hours is the conservative default: long enough
41
+ * that a duplicate from a retrying upstream within a day is still
42
+ * deduped by a retained consumed entry, short enough that `consumed/`
43
+ * reaches a bounded steady state of one day's message volume.
44
+ *
45
+ * INVARIANT (operator-owned): the horizon must be >= the longest
46
+ * window in which the same `messageId` could legitimately be
47
+ * re-submitted and still must be caught as a duplicate. There is no
48
+ * automatic internal mail redelivery in the system today, so this is
49
+ * the external re-submission window. If an at-least-once redelivery
50
+ * source is ever added, the horizon must be >= its maximum redelivery
51
+ * window or dedup breaks; a breach surfaces LOUDLY (a too-late
52
+ * re-submission carrying an old `receivedAt` is refused at enqueue,
53
+ * not silently reprocessed) rather than as silent double-processing.
54
+ */
55
+ export declare const DEFAULT_CONSUMED_RETENTION_MS: number;
56
+ /**
57
+ * Per-agent durable conversation-state subtree (design §3c). A
58
+ * long-lived single-step agent's multi-turn conversation context is
59
+ * committed under `agent-state/<agentKey>/...` so it survives child
60
+ * respawn: on respawn the rebuilt warm agent reads its prior
61
+ * conversation back from here before the resumed run replays.
62
+ *
63
+ * Unlike `runs/` (append-only events, immutable blobs) this subtree is
64
+ * MUTABLE: each run boundary overwrites the agent's conversation
65
+ * snapshot with the latest turns. It is therefore exempt from the
66
+ * append-only / deletion-direction walks `runs/` is subject to; the
67
+ * only push-time constraint is segment shape (a single round-trip-safe
68
+ * `<agentKey>` directory layer below the prefix).
69
+ */
70
+ export declare const WORKFLOW_RUN_AGENT_STATE_PREFIX = "agent-state";
71
+ /**
72
+ * JSON envelope carried by inbox and processing entries. Keys:
73
+ * - `messageId`: dedup key for the inbound message.
74
+ * - `receivedAt`: epoch-ms timestamp the reactor accepted the
75
+ * message; sortable FIFO key prefix.
76
+ * - `address`: decoded canonical address (not URL-encoded).
77
+ * - `mailAuditRef`: pointer to the raw mail bytes in the mail-audit
78
+ * store. For the in-process single-agent path a separate
79
+ * `MailAuditStore` holds the authoritative bytes and this ref joins
80
+ * onto it.
81
+ * - `rawMessage`: base64 of the inbound mail's raw MIME bytes,
82
+ * inlined so the workflow-process child can read its step input by
83
+ * messageId at `trigger.fired` time. The supervisor is the sole
84
+ * mail owner under the unified-execution host (§3a); it has no
85
+ * separate durable byte store the child can read, so the bytes ride
86
+ * the claim-check envelope itself. Present whenever the supervisor
87
+ * enqueued the entry; omitted by callers that only stamp the audit
88
+ * ref. The bytes survive the inbox→processing transition verbatim
89
+ * (the dequeue copies the entry bytes), so a `trigger.fired` for a
90
+ * processing entry can always recover the input.
91
+ */
92
+ declare const ClaimCheckEnvelope: import("arktype/internal/variants/object.ts").ObjectType<{
93
+ messageId: string;
94
+ receivedAt: number;
95
+ address: string;
96
+ mailAuditRef: {
97
+ store: string;
98
+ path: string;
99
+ };
100
+ rawMessage?: string;
101
+ }, {}>;
102
+ /**
103
+ * JSON envelope carried by consumed entries. The consumed entry is the
104
+ * canonical dedup index keyed by messageId; the envelope preserves
105
+ * the originating receivedAt for audit and carries the runId that
106
+ * consumed the message.
107
+ */
108
+ declare const ConsumedEnvelope: import("arktype/internal/variants/object.ts").ObjectType<{
109
+ messageId: string;
110
+ receivedAt: number;
111
+ address: string;
112
+ runId: string;
113
+ consumedAt: number;
114
+ mailAuditRef: {
115
+ store: string;
116
+ path: string;
117
+ };
118
+ }, {}>;
119
+ /**
120
+ * JSON envelope carried by the per-address `watermark.json` blob. The
121
+ * `watermark` is a `receivedAt` horizon (epoch ms): the oldest
122
+ * `receivedAt` a consumed entry may still retain. It only ever
123
+ * advances. A retention prune drops consumed entries strictly below
124
+ * it; `enqueueInbox` refuses any inbound strictly below it.
125
+ */
126
+ declare const WatermarkEnvelope: import("arktype/internal/variants/object.ts").ObjectType<{
127
+ watermark: number;
128
+ }, {}>;
129
+ export type ClaimCheckEnvelope = typeof ClaimCheckEnvelope.infer;
130
+ export type ConsumedEnvelope = typeof ConsumedEnvelope.infer;
131
+ export type WatermarkEnvelope = typeof WatermarkEnvelope.infer;
132
+ export declare const workflowRunKindHandler: KindHandler;
133
+ export declare const workflowRunAuthorize: AuthorizeFn;
134
+ export type EnqueueInboxArgs = {
135
+ address: string;
136
+ messageId: string;
137
+ receivedAt: number;
138
+ mailAuditRef: {
139
+ store: string;
140
+ path: string;
141
+ };
142
+ /**
143
+ * Base64 of the inbound mail's raw MIME bytes. Inlined on the
144
+ * claim-check envelope so the workflow-process child can recover its
145
+ * step input by messageId at `trigger.fired` time (§3a -- the
146
+ * supervisor is the sole mail owner and has no separate durable byte
147
+ * store the child reads). Omit to stamp only the audit ref.
148
+ */
149
+ rawMessage?: string;
150
+ };
151
+ export type EnqueueInboxResult = {
152
+ commitSha: string;
153
+ inboxKey: string;
154
+ envelope: ClaimCheckEnvelope;
155
+ };
156
+ /**
157
+ * Append a new inbox entry for `address`. The merge callback reads
158
+ * the address subtree under the per-repo lock, augments the inbox
159
+ * with the new entry, and returns the full set of address files. The
160
+ * substrate replaces the address subtree wholesale.
161
+ *
162
+ * Rejects if a same-messageId entry already exists in any queue
163
+ * state at the address — including a prior inbox entry at a
164
+ * different `receivedAt`. The caller is expected to consult the
165
+ * dedup index (consumed/) before calling, but enforcing the
166
+ * invariant here also catches the concurrent-enqueue race that the
167
+ * per-repo lock alone cannot surface.
168
+ */
169
+ export declare function enqueueInbox(store: RepoStore, principal: Principal, repoId: RepoId, args: EnqueueInboxArgs): Promise<EnqueueInboxResult>;
170
+ export type DequeueToProcessingResult = {
171
+ commitSha: string;
172
+ key: string;
173
+ envelope: ClaimCheckEnvelope;
174
+ } | null;
175
+ /**
176
+ * Move the FIFO-first inbox entry for `address` to processing.
177
+ * Returns `null` when the inbox is empty so the caller can
178
+ * distinguish "nothing to do" from "operation failed".
179
+ *
180
+ * FIFO is keyed on the parsed numeric `receivedAt` prefix of the
181
+ * inbox filename, with a lexicographic messageId tiebreak. The
182
+ * substrate does NOT rely on uniform digit widths — sorting raw
183
+ * filenames would put `"100-…"` ahead of `"99-…"` since `'1' < '9'`,
184
+ * which violates the FIFO invariant.
185
+ */
186
+ export declare function dequeueToProcessing(store: RepoStore, principal: Principal, repoId: RepoId, address: string): Promise<DequeueToProcessingResult>;
187
+ export type ReadProcessingEntryResult = {
188
+ envelope: ClaimCheckEnvelope;
189
+ } | null;
190
+ /**
191
+ * Read the processing-queue entry for `messageId` at `address` without
192
+ * mutating the tree. Returns the decoded claim-check envelope (carrying
193
+ * `mailAuditRef` and, when the enqueuer inlined them, the base64
194
+ * `rawMessage` bytes) or `null` when no processing entry exists for the
195
+ * messageId.
196
+ *
197
+ * This is the read half of mailbox ownership (§3a): the supervisor's
198
+ * dispatch loop moves an inbox entry to processing and forwards a
199
+ * `trigger.fired{messageId}` to the workflow-process child; the child
200
+ * calls this to recover the inbound message bytes that become its step
201
+ * input.
202
+ *
203
+ * The read is a flat working-tree read of
204
+ * `addresses/<seg>/processing/`. The substrate materializes each
205
+ * claim-check commit's touched paths into the repo's working tree (the
206
+ * delta write removes each deleted path and writes each put after
207
+ * validation passes), so a read issued after `dequeueToProcessing`
208
+ * committed -- which is exactly when the supervisor forwards
209
+ * `trigger.fired` -- observes the processing entry. Reading the working tree (rather than walking the
210
+ * committed git tree) matches the workflow-process child's sibling
211
+ * reads of `workflow.json` and `runs/<runId>/events/`. Because the
212
+ * read issues no commit it cannot race the supervisor's `markConsumed`
213
+ * write; it returns a point-in-time snapshot of the directory.
214
+ */
215
+ export declare function readProcessingEntry(store: RepoStore, _principal: Principal, repoId: RepoId, address: string, messageId: string): Promise<ReadProcessingEntryResult>;
216
+ export type MarkConsumedArgs = {
217
+ address: string;
218
+ messageId: string;
219
+ runId: string;
220
+ consumedAt: number;
221
+ /**
222
+ * Retention horizon for the consumed dedup index, in milliseconds.
223
+ * The commit advances the per-address watermark to
224
+ * `consumedAt - retentionHorizonMs` (never backward, never past the
225
+ * entry being written) and prunes consumed entries below it. The
226
+ * boot edge resolves the operator's `CONSUMED_RETENTION_MS` config
227
+ * to a concrete value and threads it here. Omit to apply
228
+ * `DEFAULT_CONSUMED_RETENTION_MS` (24h).
229
+ */
230
+ retentionHorizonMs?: number;
231
+ };
232
+ export type MarkConsumedResult = {
233
+ commitSha: string;
234
+ envelope: ConsumedEnvelope;
235
+ /** Watermark the commit advanced to (epoch-ms `receivedAt` horizon). */
236
+ watermark: number;
237
+ /** messageIds whose consumed entries this commit pruned. */
238
+ prunedMessageIds: string[];
239
+ };
240
+ /**
241
+ * Atomically remove the processing entry for `messageId` at `address`,
242
+ * write the canonical `consumed/<messageId>.json` dedup index entry,
243
+ * advance the per-address retention watermark, and prune consumed
244
+ * entries the watermark has passed. The caller is expected to have
245
+ * called `dequeueToProcessing` for this messageId; calling
246
+ * `markConsumed` without a matching processing entry throws.
247
+ *
248
+ * The consumed envelope preserves the original `receivedAt` and
249
+ * `mailAuditRef` from the processing entry so the dedup index doubles
250
+ * as an audit record.
251
+ *
252
+ * Retention (the bounded-`consumed/` contract): the watermark advances
253
+ * to `max(priorWatermark, min(consumedAt - retentionHorizonMs,
254
+ * thisEntry.receivedAt))` -- monotonic, and never past the entry being
255
+ * written so the new entry is always retained. Every consumed entry
256
+ * whose `receivedAt` is strictly below the new watermark is dropped
257
+ * (the oldest age-ordered tail). `consumed/` therefore reaches a
258
+ * bounded steady state of roughly one horizon's worth of entries
259
+ * instead of growing one entry per message forever.
260
+ */
261
+ export declare function markConsumed(store: RepoStore, principal: Principal, repoId: RepoId, args: MarkConsumedArgs): Promise<MarkConsumedResult>;
262
+ export type ReplayProcessingToInboxResult = {
263
+ commitSha: string;
264
+ replayedKeys: string[];
265
+ };
266
+ /**
267
+ * Read the run event logs under `runs/` and return the set of
268
+ * `consumedMessageId`s belonging to NON-terminal runs -- the messages a
269
+ * live run still owns. The caller (the supervisor's spawn-time replay)
270
+ * feeds this into `replayProcessingToInbox`'s `ownedMessageIds` so a
271
+ * parked run's message is not re-admitted to inbox and dispatched a
272
+ * second time while the run is recovered by re-driving its durable log.
273
+ * Without this, the re-drive AND the re-triggered fresh run both re-park
274
+ * the same awaitSignal gate on the same runId, and the two concurrent
275
+ * runtime bodies race to a corrupt terminal.
276
+ *
277
+ * Reads the substrate's working tree via `getRepoDir`, mirroring the
278
+ * child's `discoverInFlightRuns`. The working tree tracks the run-event
279
+ * ref (`refs/heads/main`); the claim-check ref (`refs/heads/events`)
280
+ * cannot see it, which is why this lives at the caller rather than inside
281
+ * `replayProcessingToInbox`'s single-ref delta. A run whose log is sealed
282
+ * (combined `events.json`, only permitted for a terminated run) or
283
+ * carries a terminal event is excluded; an absent `runs/` directory
284
+ * yields an empty set.
285
+ */
286
+ export declare function readOwnedMessageIds(store: RepoStore, repoId: RepoId): Promise<Set<string>>;
287
+ export type ReplayProcessingToInboxOpts = {
288
+ /**
289
+ * MessageIds whose run is still LIVE (non-terminal) and therefore owns
290
+ * its inbound message: recovery re-drives that run against the durable
291
+ * log, so re-admitting the message to `inbox/` would dispatch a SECOND
292
+ * run for it, colliding with the re-drive on the shared runId. Entries
293
+ * in this set are left in `processing/` untouched; the run's eventual
294
+ * `markConsumed` clears them. The caller computes this by reading the
295
+ * run event logs, which live on a DIFFERENT ref (`refs/heads/main`)
296
+ * than the claim-check subtree this operation commits to
297
+ * (`refs/heads/events`). Empty/absent means replay every processing
298
+ * entry (the pre-existing behaviour: recover all orphans).
299
+ */
300
+ ownedMessageIds?: ReadonlySet<string>;
301
+ };
302
+ /**
303
+ * Recovery path: move every processing entry at `address` back to
304
+ * inbox preserving the original `<receivedAt>-<messageId>` filename
305
+ * key so FIFO ordering survives a workflow-process crash. Returns
306
+ * the set of keys that were moved; when nothing was in processing
307
+ * the returned `replayedKeys` is empty (and the commit is a no-op
308
+ * rewrite of the same tree).
309
+ *
310
+ * The replay is atomic across all processing entries — a partial
311
+ * replay that left some entries in processing would corrupt the
312
+ * FIFO discipline (the next dequeue would pull the wrong entry).
313
+ *
314
+ * Watermark carve-out (load-bearing — do NOT "tighten" this): the
315
+ * replay deliberately does NOT apply the `receivedAt < watermark`
316
+ * stale-reject that `enqueueInbox` applies. A `processing/` entry was
317
+ * already dequeued past the dedup index, so re-admitting it to
318
+ * `inbox/` even when its `receivedAt` has fallen below an advanced
319
+ * watermark is correct — the message is a legitimately in-flight one
320
+ * recovered after a crash, not a fresh inbound that could be a
321
+ * duplicate. Applying the stale-reject here would silently LOSE that
322
+ * message. The watermark only ever gates fresh inbound at the enqueue
323
+ * boundary; the recovery replay is exempt by design.
324
+ */
325
+ export declare function replayProcessingToInbox(store: RepoStore, principal: Principal, repoId: RepoId, address: string, opts?: ReplayProcessingToInboxOpts): Promise<ReplayProcessingToInboxResult>;
326
+ export {};