@loomwork/plugin-content 0.0.0-stage → 0.1.1
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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +92 -2
- package/dist/CachingContentStore.d.ts +54 -0
- package/dist/CachingContentStore.d.ts.map +1 -0
- package/dist/CachingContentStore.js +171 -0
- package/dist/CachingContentStore.js.map +1 -0
- package/dist/ContentResolvingEventStore.d.ts +70 -0
- package/dist/ContentResolvingEventStore.d.ts.map +1 -0
- package/dist/ContentResolvingEventStore.js +245 -0
- package/dist/ContentResolvingEventStore.js.map +1 -0
- package/dist/ContentStore.d.ts +186 -0
- package/dist/ContentStore.d.ts.map +1 -0
- package/dist/ContentStore.js +177 -0
- package/dist/ContentStore.js.map +1 -0
- package/dist/ContentTouchingSnapshotStore.d.ts +56 -0
- package/dist/ContentTouchingSnapshotStore.d.ts.map +1 -0
- package/dist/ContentTouchingSnapshotStore.js +85 -0
- package/dist/ContentTouchingSnapshotStore.js.map +1 -0
- package/dist/citations.d.ts +40 -0
- package/dist/citations.d.ts.map +1 -0
- package/dist/citations.js +118 -0
- package/dist/citations.js.map +1 -0
- package/dist/content.bench.d.ts +2 -0
- package/dist/content.bench.d.ts.map +1 -0
- package/dist/content.bench.js +75 -0
- package/dist/content.bench.js.map +1 -0
- package/dist/content.d.ts +40 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +177 -0
- package/dist/content.js.map +1 -0
- package/dist/derive.d.ts +9 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +40 -0
- package/dist/derive.js.map +1 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -0
- package/dist/executionEnd.d.ts +22 -0
- package/dist/executionEnd.d.ts.map +1 -0
- package/dist/executionEnd.js +66 -0
- package/dist/executionEnd.js.map +1 -0
- package/dist/gc.d.ts +470 -0
- package/dist/gc.d.ts.map +1 -0
- package/dist/gc.js +819 -0
- package/dist/gc.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/touchAround.d.ts +46 -0
- package/dist/touchAround.d.ts.map +1 -0
- package/dist/touchAround.js +98 -0
- package/dist/touchAround.js.map +1 -0
- package/package.json +58 -3
- package/src/CachingContentStore.ts +184 -0
- package/src/ContentResolvingEventStore.ts +325 -0
- package/src/ContentStore.ts +317 -0
- package/src/ContentTouchingSnapshotStore.ts +109 -0
- package/src/citations.ts +117 -0
- package/src/content.bench.ts +84 -0
- package/src/content.ts +191 -0
- package/src/derive.ts +40 -0
- package/src/errors.ts +19 -0
- package/src/executionEnd.ts +64 -0
- package/src/gc.ts +1213 -0
- package/src/index.ts +54 -0
- package/src/touchAround.ts +131 -0
package/dist/gc.d.ts
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import type { ArchiveStore, EventStore, ExecutionEnumerable } from "@loomwork/event-runtime";
|
|
2
|
+
import type { ContentStore } from "./ContentStore";
|
|
3
|
+
/**
|
|
4
|
+
* A {@link PinPredicate} for `LogLifecycle` (K10.6): pin any execution whose log
|
|
5
|
+
* carries at least one event of the designated kinds — e.g. the app's finding
|
|
6
|
+
* events. Use when no archive is configured and reclaiming the run would destroy
|
|
7
|
+
* the only copy of its durable conclusions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pinByEventKinds(eventStore: Pick<EventStore, "read">, kinds: Iterable<string>): (executionId: string) => Promise<boolean>;
|
|
10
|
+
/** Everything but the `dryRun` / `reclaimOrphans` pair, which {@link ContentSweepOptions} ties together. */
|
|
11
|
+
export interface ContentSweepBase {
|
|
12
|
+
/**
|
|
13
|
+
* Every log store whose events may cite content — the live store AND any
|
|
14
|
+
* archive stores. All must be enumerable (`listExecutionsPage()` preferred —
|
|
15
|
+
* SP-2, bounded memory — or `listExecutions()`): a store that cannot be
|
|
16
|
+
* enumerated cannot be swept safely (its pins would be invisible), so the
|
|
17
|
+
* sweep refuses rather than silently under-pinning.
|
|
18
|
+
*
|
|
19
|
+
* List the LIVE store BEFORE its archive. Retention copies an execution to the archive and
|
|
20
|
+
* then deletes it from the live store. Scanned live-first, an execution that moves during
|
|
21
|
+
* the sweep is seen in one store or the other. Scanned archive-first, it can be missed by
|
|
22
|
+
* both, and its blobs then look like orphans.
|
|
23
|
+
*/
|
|
24
|
+
eventStores: readonly (Pick<EventStore, "read"> & ExecutionEnumerable)[];
|
|
25
|
+
/**
|
|
26
|
+
* ADR 0055 D6 — where compaction checkpoints live: the live snapshot store AND EACH
|
|
27
|
+
* ARCHIVE'S snapshot store. `LogLifecycle.compact` checkpoints the fold and truncates the
|
|
28
|
+
* prefix, so a ref the prefix cited survives only in snapshot state.
|
|
29
|
+
*
|
|
30
|
+
* Which logs were compacted (ADR 0106, superseding "no sequence-1 event"): compaction
|
|
31
|
+
* removes its checkpoint's slot and, when it keeps pinned-kind events, never the tip. So a
|
|
32
|
+
* gap-free log with more than the bootstrap was never compacted (no snapshot read); a
|
|
33
|
+
* gapped log's checkpoint sits at its highest missing sequence `gap`; a bootstrap-only log
|
|
34
|
+
* was compacted through its tip. For each compacted execution the sweep pins every ref in:
|
|
35
|
+
* - the COMPACTION CHECKPOINT: the lowest snapshot in `[gap, tip]` — exactly `gap` for a
|
|
36
|
+
* compaction's own, the fork seed (`metadata.forkSequence`, one `loadAt`) for a child
|
|
37
|
+
* forked from a compacted parent — or, for a bootstrap-only log, its latest snapshot.
|
|
38
|
+
* ANY snapshot at or above `gap` covers a lost checkpoint, matching `LogLifecycle.compact`,
|
|
39
|
+
* which accepts a base at or above the gap; below `gap` nothing does. `fork()` from any point after it loads that
|
|
40
|
+
* checkpoint, so its refs stay reachable even after a later snapshot overwrote them.
|
|
41
|
+
* - the LATEST snapshot, which resume loads.
|
|
42
|
+
*
|
|
43
|
+
* Snapshots in between hold only checkpoint- or suffix-derived refs, and the suffix is
|
|
44
|
+
* scanned as log. Anything below the checkpoint is unreachable. The refs are PINNED because
|
|
45
|
+
* compaction folded away the event kinds, so the sweep cannot tell telemetry from evidence.
|
|
46
|
+
* They are released when retention deletes the execution, which deletes its snapshots too.
|
|
47
|
+
*
|
|
48
|
+
* `reclaimOrphans` REFUSES, before erasing anything:
|
|
49
|
+
* - without this option, when any scanned store can `truncatePrefix`;
|
|
50
|
+
* - when an execution looks compacted but no checkpoint is found. That covers a gap with no
|
|
51
|
+
* snapshot in `[gap, tip]`, and a sequence-0-only log with no snapshot, which is either
|
|
52
|
+
* compacted at its tip or a run that never got past its bootstrap. The two are
|
|
53
|
+
* indistinguishable, so both refuse.
|
|
54
|
+
*/
|
|
55
|
+
snapshotStores?: readonly SnapshotLookup[];
|
|
56
|
+
/**
|
|
57
|
+
* ADR 0138 - the compaction archives (`LogLifecycle.compactionArchive`). Compaction MOVES the events
|
|
58
|
+
* it removes into the archive, so a ref only an archived event cites (a step input the fold no
|
|
59
|
+
* longer keeps, an old finding) is cited THERE and nowhere else. Every ref cited by an archived
|
|
60
|
+
* envelope is PINNED for as long as the archive holds it: the sweep never reclaims a blob the
|
|
61
|
+
* recoverable history still names. Not scanning them is the hazard: an erasing orphan pass without
|
|
62
|
+
* the archive of a compacted log erases blobs its audit trail still cites. Read through the same
|
|
63
|
+
* sealing store the lifecycle uses (an `EncryptingArchiveStore` yields plaintext; a crypto-shredded
|
|
64
|
+
* subject's archive is unreadable and cites nothing). The archive itself is never swept or pruned.
|
|
65
|
+
*
|
|
66
|
+
* REQUIRED (fail closed) by an ERASING `reclaimOrphans` pass whenever any scanned log is compacted
|
|
67
|
+
* (a gap below its tip, or only its bootstrap left): {@link ArchiveStoresRequiredError} otherwise,
|
|
68
|
+
* before anything is erased. Coverage is CHECKED for EVERY compacted log, whatever its checkpoint
|
|
69
|
+
* is called (the `ckpt-0138-` id mark is only used to label reports - it can be lost to pruning, so
|
|
70
|
+
* it never gates an erase): the log's removed range must be covered by the given archives' headers
|
|
71
|
+
* (legacy-checkpoint segments included), else {@link ArchiveStoresRequiredError} (`reason:
|
|
72
|
+
* "uncovered"`). `[]` alone therefore no longer passes a gapped log. The only way past it, for logs
|
|
73
|
+
* compacted before ADR 0138 (no archive exists), is {@link acknowledgeUnarchivedLogs}.
|
|
74
|
+
* The archive is ENUMERATED (`listExecutions`), so segments whose log is gone are scanned
|
|
75
|
+
* too. A segment that is still sealed (count > 0 with no envelopes: the RAW inner store of an
|
|
76
|
+
* `EncryptingArchiveStore`) throws {@link SealedArchiveScanError} on an erasing pass.
|
|
77
|
+
*/
|
|
78
|
+
archiveStores?: readonly Pick<ArchiveStore, "read" | "listExecutions" | "headers">[];
|
|
79
|
+
/**
|
|
80
|
+
* Explicit opt-in for an erasing `reclaimOrphans` pass over compacted logs the given
|
|
81
|
+
* `archiveStores` do not cover: "these logs' compacted history is already gone (compacted before
|
|
82
|
+
* ADR 0138 and never re-compacted, or a fork child whose parent's archive is not keyed to it);
|
|
83
|
+
* erasing their orphan blobs is accepted." The affected executions are reported in
|
|
84
|
+
* `unarchivedAcknowledged`. Never a substitute for passing the real archive.
|
|
85
|
+
*/
|
|
86
|
+
acknowledgeUnarchivedLogs?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The blob store. With `deleteIfUntouchedSince` (SPI 1.3.0) every erase is conditional on
|
|
89
|
+
* the blob's touch time, which closes the re-cite race for a re-cite THROUGH `put` (ADR 0055
|
|
90
|
+
* D5); without it the sweep falls back to `delete` and reports `raceSafe: false`. A citation
|
|
91
|
+
* copied WITHOUT a `put` (a fork's `copyPrefix`, a ref an `append` keeps) is protected by SPI
|
|
92
|
+
* 1.4.0 `touch`, which `reclaimOrphans` requires; see `reclaimOrphans`. `listPage` enables it.
|
|
93
|
+
*/
|
|
94
|
+
contentStore: Pick<ContentStore, "delete" | "deleteIfUntouchedSince" | "listPage" | "touchClock" | "touch">;
|
|
95
|
+
/** Event kinds whose cited refs are pinned — retained as long as the citing fact exists. */
|
|
96
|
+
pinnedEventTypes: Iterable<string>;
|
|
97
|
+
/**
|
|
98
|
+
* Reclaim an unpinned ref only when its effective citation time is older than this (ADR 0146:
|
|
99
|
+
* its latest citation, or, for a ref cited by an execution that has ENDED, that execution's end
|
|
100
|
+
* if later). EXACTLY ONE of `olderThanMs` / `policy` must be given.
|
|
101
|
+
*/
|
|
102
|
+
olderThanMs?: number;
|
|
103
|
+
/**
|
|
104
|
+
* ADR 0145 - an app-owned retention policy (`retentionPolicy()` from `@loomwork/workflow-runtime`;
|
|
105
|
+
* typed structurally here so this package takes no dependency on it). `content.unpinnedAfterMs`
|
|
106
|
+
* is used as `olderThanMs`. A policy without a `content` section is an error, not a silent no-op.
|
|
107
|
+
* Re-validated structurally (see `resolvePolicyTtl`): unknown keys are refused, and
|
|
108
|
+
* `unpinnedAfterMs >= terminalTtlMs` when the policy carries one (an advisory consistency rule,
|
|
109
|
+
* ADR 0145 D2).
|
|
110
|
+
*/
|
|
111
|
+
policy?: {
|
|
112
|
+
terminalTtlMs?: number;
|
|
113
|
+
snapshots?: unknown;
|
|
114
|
+
content?: {
|
|
115
|
+
unpinnedAfterMs: number;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* LOG time, in epoch ms: the instant the TTL is measured back from, compared against event
|
|
120
|
+
* `timestamp`s (`now − effective citation time ≥ olderThanMs`, ADR 0146). It is NOT the store's clock. A
|
|
121
|
+
* simulated or replayed log may run far from the store's wall clock; the race guard uses
|
|
122
|
+
* `touchedBefore` for that reason.
|
|
123
|
+
*/
|
|
124
|
+
now: number;
|
|
125
|
+
/**
|
|
126
|
+
* STORE time, in epoch ms, on the clock the content store stamps touch times with: the
|
|
127
|
+
* cutoff for the conditional delete and for orphan eligibility (ADR 0055 D5). Default: the
|
|
128
|
+
* store's `touchClock()` read ONCE at the sweep's start, minus `olderThanMs`. A store with
|
|
129
|
+
* `deleteIfUntouchedSince` but no `touchClock` requires it explicitly.
|
|
130
|
+
*/
|
|
131
|
+
touchedBefore?: number;
|
|
132
|
+
/**
|
|
133
|
+
* DX-2 — report what WOULD be reclaimed without deleting anything (the
|
|
134
|
+
* `loom sweep content` operator default; `--apply` turns it off).
|
|
135
|
+
*/
|
|
136
|
+
dryRun?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* ADR 0055 D7 — external root sets: content addresses held OUTSIDE the scanned logs (an app
|
|
139
|
+
* table such as a Postgres `experience_refs`). Every yielded address is pinned through both
|
|
140
|
+
* passes. Read once per sweep, after the mark phase. An app that records a new root for
|
|
141
|
+
* bytes the store already holds must `put` them (the put is the touch the conditional
|
|
142
|
+
* delete sees), exactly as a flow does.
|
|
143
|
+
*/
|
|
144
|
+
roots?: () => AsyncIterable<string>;
|
|
145
|
+
/**
|
|
146
|
+
* ADR 0055 D6 — also reclaim ORPHANS: blobs no scanned event and no root cites (their
|
|
147
|
+
* execution was deleted with no archive, a crash between `put` and the append, a truncated
|
|
148
|
+
* prefix), once untouched for the TTL. Requires the store's `listPage` and
|
|
149
|
+
* `deleteIfUntouchedSince`; refuses otherwise.
|
|
150
|
+
*
|
|
151
|
+
* ACKNOWLEDGEMENT REQUIRED (ADR 0055 amendment, fail-closed): to ERASE, pass
|
|
152
|
+
* `{ completeScan: true }` (plus `snapshotsTouchContent: true` when `snapshotStores` is given, below). A bare `true` (or any other value) throws
|
|
153
|
+
* {@link ReclaimOrphansAckError} before anything is read or erased. A `dryRun` erases nothing
|
|
154
|
+
* and is how you check completeness, so under `dryRun: true` any truthy value (`true` included)
|
|
155
|
+
* is accepted; see {@link ContentSweepOptions} for the typing. The acknowledgement is your
|
|
156
|
+
* assertion that `eventStores`, `snapshotStores` and `roots` together cover EVERY place that
|
|
157
|
+
* cites content, scanned in the right ORDER: each live store BEFORE its archive (ADR 0055
|
|
158
|
+
* "Scan order"). `[archive, live]` can miss an execution that retention moves mid-sweep, and
|
|
159
|
+
* its blobs then look like orphans.
|
|
160
|
+
*
|
|
161
|
+
* HAZARD the sweep cannot detect, which is why the assertion exists: a citing store that was
|
|
162
|
+
* NOT passed in `eventStores` or `snapshotStores`. Every blob only that store cites is an
|
|
163
|
+
* orphan to this pass, and it is erased while still cited. Pass every archive
|
|
164
|
+
* (`retention.archive`) and each archive's snapshot store, and every app table through `roots`.
|
|
165
|
+
* Run with `dryRun: true` first and read the list.
|
|
166
|
+
*
|
|
167
|
+
* CONCURRENCY (ADR 0055 D6 amendment 2): D5's conditional delete only sees a touch. A `put`
|
|
168
|
+
* touches; a citation that enters a log WITHOUT one does not by itself:
|
|
169
|
+
* `ContentResolvingEventStore.copyPrefix` (a fork) copies refs verbatim, and an `append`
|
|
170
|
+
* keeps refs already inside its payload (recalled memory, `scriptRef`, refs passed between
|
|
171
|
+
* steps). SPI 1.4.0 `touch` closes that: those two paths touch the refs they carry, so a fork
|
|
172
|
+
* made mid-sweep makes `deleteIfUntouchedSince` refuse. To ERASE, the content store MUST
|
|
173
|
+
* implement `touch` or the sweep throws {@link ReclaimOrphansTouchError} (a `dryRun` need not).
|
|
174
|
+
* The log must be written through a `ContentResolvingEventStore` over that store: a writer
|
|
175
|
+
* that copies refs some other way is outside the guarantee.
|
|
176
|
+
*
|
|
177
|
+
* SNAPSHOTS (second path): a fork of a COMPACTED parent saves a seed snapshot whose state
|
|
178
|
+
* cites refs that exist nowhere else (the prefix was truncated). `ContentResolvingEventStore`
|
|
179
|
+
* cannot see it; only a snapshot store wrapped in `ContentTouchingSnapshotStore`
|
|
180
|
+
* (outside any `EncryptingSnapshotStore`, over the same content store) touches those refs.
|
|
181
|
+
* loom never builds either store for the host, so the wrapping is the host's and is not PROVEN
|
|
182
|
+
* from here (a sweep, and the CLI, read a RAW store over the tables a wrapped one wrote, so an
|
|
183
|
+
* unbranded store is no evidence the writer was unwrapped): an ERASING pass given `snapshotStores` must also pass
|
|
184
|
+
* `{ completeScan: true, snapshotsTouchContent: true }` or it throws
|
|
185
|
+
* {@link ReclaimOrphansSnapshotAckError}. Without `snapshotStores` it is not needed (such a
|
|
186
|
+
* pass already refuses a store that can `truncatePrefix`, and a fork of an uncompacted parent
|
|
187
|
+
* copies every event, so its seed cites nothing the copied events do not). A `dryRun` is exempt.
|
|
188
|
+
* The flag stays an assertion about the WRITER and is ALWAYS required, even when every store
|
|
189
|
+
* passed is a `ContentTouchingSnapshotStore` (it vouches for itself, not for the other stores the
|
|
190
|
+
* runtime saves to). Best-effort detection only WARNS: the report counts branded and unbranded
|
|
191
|
+
* stores (`snapshotStoresTouching` / `snapshotStoresUnbranded`), and a pass that is handed a MIX
|
|
192
|
+
* (some branded, some not: a host wrapped some writers and likely forgot others) emits one
|
|
193
|
+
* `LOOM_CONTENT_SNAPSHOT_UNWRAPPED` process warning. It never refuses, so the CLI's raw SQLite
|
|
194
|
+
* stores are not rejected; it never relaxes the flag either (fail-closed).
|
|
195
|
+
*
|
|
196
|
+
* THE GUARANTEE IS D5'S, NOT THE TOUCH'S. The cutoff is `touchClock() - olderThanMs`. The
|
|
197
|
+
* touch BEFORE a write is what makes a sweep whose cutoff is later refuse; so the race is
|
|
198
|
+
* closed while a write's touch-to-commit window is shorter than the margin
|
|
199
|
+
* `store-now - cutoff` (the TTL, or the distance of an explicit `touchedBefore` from the
|
|
200
|
+
* store's clock). The touch AFTER the write is a best-effort extension of that window (it
|
|
201
|
+
* is not retried and an error is reported through `onTouchError`, not raised); do not
|
|
202
|
+
* count on it. With a zero or tiny margin the window is unbounded: a fork whose before-touch
|
|
203
|
+
* is older than the cutoff and which commits after the scan has passed the child is erased
|
|
204
|
+
* under. So an ERASING orphan pass refuses `olderThanMs <= 0` and any cutoff closer to the
|
|
205
|
+
* store's clock than {@link MIN_ORPHAN_ERASE_MARGIN_MS} with {@link ReclaimOrphansMarginError},
|
|
206
|
+
* and a store with no `touchClock()` (the margin cannot be measured) with
|
|
207
|
+
* {@link ReclaimOrphansClockError}; a `dryRun` is unaffected. Pick a margin well above your longest write (a fork's copy of a
|
|
208
|
+
* long prefix included).
|
|
209
|
+
*/
|
|
210
|
+
reclaimOrphans?: ReclaimOrphansAck | boolean;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Sweep options. `reclaimOrphans` and `dryRun` are tied by a union so the type says what the
|
|
214
|
+
* runtime enforces: a sweep that can ERASE (`dryRun` absent or `false`) accepts only the
|
|
215
|
+
* acknowledgement object (or `false`), so a bare `true` is a compile error there; a
|
|
216
|
+
* `dryRun: true` sweep also accepts a plain `true`, because it erases nothing and is how a host
|
|
217
|
+
* checks completeness. (A `dryRun` typed as a plain `boolean` falls in the first arm, which is
|
|
218
|
+
* the safe one.)
|
|
219
|
+
*/
|
|
220
|
+
export type ContentSweepOptions = Omit<ContentSweepBase, "dryRun" | "reclaimOrphans"> & ({
|
|
221
|
+
dryRun?: false;
|
|
222
|
+
reclaimOrphans?: ReclaimOrphansAck | false;
|
|
223
|
+
} | {
|
|
224
|
+
dryRun: true;
|
|
225
|
+
reclaimOrphans?: ReclaimOrphansAck | boolean;
|
|
226
|
+
});
|
|
227
|
+
/**
|
|
228
|
+
* The caller's assertion that a `reclaimOrphans` sweep sees every citing store. The literal
|
|
229
|
+
* `true` type makes `{ completeScan: false }` a compile error; the runtime check also refuses
|
|
230
|
+
* untyped callers.
|
|
231
|
+
*/
|
|
232
|
+
export interface ReclaimOrphansAck {
|
|
233
|
+
completeScan: true;
|
|
234
|
+
/**
|
|
235
|
+
* Required (checked at runtime) whenever an ERASING pass is given `snapshotStores`: the
|
|
236
|
+
* caller's assertion that every snapshot store the runtime SAVES to is wrapped in
|
|
237
|
+
* `ContentTouchingSnapshotStore` (outside any `EncryptingSnapshotStore`). Without it a
|
|
238
|
+
* fork of a compacted parent saves a seed snapshot citing refs that live nowhere else, and
|
|
239
|
+
* a sweep can erase them under the live child. See {@link ReclaimOrphansSnapshotAckError}.
|
|
240
|
+
*/
|
|
241
|
+
snapshotsTouchContent?: true;
|
|
242
|
+
}
|
|
243
|
+
/** `reclaimOrphans` was set without `{ completeScan: true }`. Nothing was read or erased. */
|
|
244
|
+
export declare class ReclaimOrphansAckError extends TypeError {
|
|
245
|
+
constructor(received: unknown);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* An ERASING `reclaimOrphans` pass was given `snapshotStores` without
|
|
249
|
+
* `{ snapshotsTouchContent: true }`. Nothing was read or erased. A compacted parent's prefix refs
|
|
250
|
+
* live only in snapshot state, and a fork copies that state into its seed snapshot with no `put`
|
|
251
|
+
* and no event; only a snapshot store wrapped in `ContentTouchingSnapshotStore` touches them.
|
|
252
|
+
* The sweep cannot see how the writing runtime's snapshot store was built, so, like D6's
|
|
253
|
+
* archive assertion, the host states it. A `dryRun` is exempt. With no `snapshotStores` the
|
|
254
|
+
* acknowledgement is not needed: the pass then refuses any store that can `truncatePrefix`, and
|
|
255
|
+
* a fork of an UNcompacted parent copies every event (refs touched by `copyPrefix`), so its seed
|
|
256
|
+
* state cites nothing the copied events do not.
|
|
257
|
+
*/
|
|
258
|
+
export declare class ReclaimOrphansSnapshotAckError extends TypeError {
|
|
259
|
+
constructor();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* `reclaimOrphans` was asked to ERASE through a content store without SPI 1.4.0 `touch`.
|
|
263
|
+
* Nothing was read or erased. Without `touch`, a citation that enters a log with no `put` (a
|
|
264
|
+
* fork's `copyPrefix`, a ref an `append` carries) cannot make the conditional delete refuse, so
|
|
265
|
+
* an orphan sweep concurrent with a fork or a delete can erase a blob a live log still cites
|
|
266
|
+
* (replay then throws `ContentMissingError`). This is a deletion safety boundary: it refuses
|
|
267
|
+
* rather than documenting the hazard. A `dryRun` is unaffected.
|
|
268
|
+
*/
|
|
269
|
+
export declare class ReclaimOrphansTouchError extends TypeError {
|
|
270
|
+
constructor();
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The smallest margin, in ms, between the content store's clock and the guard cutoff that an
|
|
274
|
+
* ERASING orphan pass accepts (ADR 0055 D6 amendment 2). A write's touch-to-commit window must
|
|
275
|
+
* be shorter than the margin for the touch to protect it; 60 s is far above an append and
|
|
276
|
+
* above a fork's prefix copy at any realistic size, and an operator who needs a bigger one
|
|
277
|
+
* simply passes a larger TTL.
|
|
278
|
+
*/
|
|
279
|
+
export declare const MIN_ORPHAN_ERASE_MARGIN_MS = 60000;
|
|
280
|
+
/**
|
|
281
|
+
* An ERASING `reclaimOrphans` pass was configured with a zero/negative `olderThanMs`, or a
|
|
282
|
+
* cutoff (`touchedBefore`) closer to the content store's clock than
|
|
283
|
+
* {@link MIN_ORPHAN_ERASE_MARGIN_MS}. Nothing was read or erased. With no margin the
|
|
284
|
+
* touch-before-write has no window to protect: a write can touch, the sweep read a later cutoff,
|
|
285
|
+
* and the write commit after the scan, so a blob a live log cites is erased.
|
|
286
|
+
*/
|
|
287
|
+
export declare class ReclaimOrphansMarginError extends TypeError {
|
|
288
|
+
readonly marginMs: number;
|
|
289
|
+
constructor(marginMs: number);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* An ERASING `reclaimOrphans` pass over a content store with `deleteIfUntouchedSince` but no
|
|
293
|
+
* `touchClock()`. Nothing was read or erased. Without the store's clock the sweep cannot measure
|
|
294
|
+
* the margin between "now" and the cutoff (`touchedBefore` is an unchecked caller value, so
|
|
295
|
+
* `touchedBefore: Date.now()` would pass any `olderThanMs`), and the touch-to-commit window is
|
|
296
|
+
* then unbounded. A `dryRun` is exempt.
|
|
297
|
+
*/
|
|
298
|
+
export declare class ReclaimOrphansClockError extends TypeError {
|
|
299
|
+
constructor();
|
|
300
|
+
}
|
|
301
|
+
/** Structural view of a snapshot store: just `loadLatest` (no snapshot-runtime dependency). */
|
|
302
|
+
export interface SnapshotLookup {
|
|
303
|
+
loadLatest(executionId: string): Promise<{
|
|
304
|
+
id?: string;
|
|
305
|
+
sequence: number;
|
|
306
|
+
state: unknown;
|
|
307
|
+
} | null>;
|
|
308
|
+
/** Exact-sequence load; used for a forked child's seed (optional — falls back to a walk). */
|
|
309
|
+
loadAt?(executionId: string, sequence: number): Promise<{
|
|
310
|
+
id?: string;
|
|
311
|
+
sequence: number;
|
|
312
|
+
state: unknown;
|
|
313
|
+
} | null>;
|
|
314
|
+
loadLatestBefore(executionId: string, sequence: number): Promise<{
|
|
315
|
+
id?: string;
|
|
316
|
+
sequence: number;
|
|
317
|
+
state: unknown;
|
|
318
|
+
} | null>;
|
|
319
|
+
}
|
|
320
|
+
/** Test-only: re-arm the once-per-process warning below. Not exported from the package index. */
|
|
321
|
+
export declare function resetSnapshotUnwrappedWarning(): void;
|
|
322
|
+
export interface ContentSweepReport {
|
|
323
|
+
executionsScanned: number;
|
|
324
|
+
refsSeen: number;
|
|
325
|
+
refsPinned: number;
|
|
326
|
+
/**
|
|
327
|
+
* ADR 0055 D4 - refs cited at least once anywhere but as a RECLAIMABLE claim-check envelope's
|
|
328
|
+
* `ref` (a digest counts as anywhere). Since ADR 0140 that includes a `retain: true` envelope
|
|
329
|
+
* whose ref sits at a trusted root (the top-level `output` of a STEP_COMPLETED, through a taint
|
|
330
|
+
* wrapper), and a R5 media source `{ kind: "ref", ref: { address } }`. Every address cited by an
|
|
331
|
+
* `archiveStores` segment is counted unconditionally. These are never reclaimed while any scanned
|
|
332
|
+
* event cites them. The set OVERLAPS `refsPinned` (a ref can be in both): the two are not disjoint
|
|
333
|
+
* partitions of `refsSeen`.
|
|
334
|
+
*/
|
|
335
|
+
refsLoadBearing: number;
|
|
336
|
+
/**
|
|
337
|
+
* ADR 0146 - unpinned refs whose age clock came from a citing execution's END rather than from the
|
|
338
|
+
* citation: a ref cited by an execution that ended after the citation ages from the end. Counted
|
|
339
|
+
* on every sweep.
|
|
340
|
+
*/
|
|
341
|
+
refsAgedByEnd: number;
|
|
342
|
+
/**
|
|
343
|
+
* ADR 0146 - DRY RUN ONLY (absent on an erasing sweep, which keeps no second map): refs the old
|
|
344
|
+
* citation clock would have reclaimed that the end clock keeps. Never reclaimed by the end clock
|
|
345
|
+
* that would not also have been by the old one, so this is the whole delta.
|
|
346
|
+
*/
|
|
347
|
+
heldByEndClock?: string[];
|
|
348
|
+
/**
|
|
349
|
+
* Unpinned refs whose age clock stayed on the CITATION because the newest citing execution was
|
|
350
|
+
* RE-OPENED after a terminal event (`resumeAs` onto an ended run, ADR 0104 D1; ADR 0146's exception):
|
|
351
|
+
* they can be reclaimed while that execution's log is still live. Counted on every sweep. A plain
|
|
352
|
+
* running or parked execution that never ended is NOT counted. Decisions are unchanged: visibility only.
|
|
353
|
+
*/
|
|
354
|
+
refsOfReopened: number;
|
|
355
|
+
/**
|
|
356
|
+
* DRY RUN ONLY (absent on an erasing sweep, which keeps no second list): of `reclaimed`, the addresses
|
|
357
|
+
* counted in `refsOfReopened`, so an operator sees them before `--apply`.
|
|
358
|
+
*/
|
|
359
|
+
reclaimedWhileReopened?: string[];
|
|
360
|
+
/** Content addresses erased this sweep — or, under `dryRun`, that WOULD be. */
|
|
361
|
+
reclaimed: string[];
|
|
362
|
+
/**
|
|
363
|
+
* Eligible addresses (refs and orphans) whose conditional erase was REFUSED by the touch/race guard:
|
|
364
|
+
* `deleteIfUntouchedSince` returned false because the blob was touched after `touchCutoff` (a
|
|
365
|
+
* concurrent re-cite, or a content-store clock that is not the one the log's `now` runs on).
|
|
366
|
+
* ALWAYS 0 on a dry run, which never calls the store: a dry run can list N in `reclaimed` while the
|
|
367
|
+
* apply reports `reclaimed: []` and `keptByTouch: N`; when it does, compare `touchCutoff` with the
|
|
368
|
+
* store's touch stamps (see `touchedBefore`). Also 0 when the store is not `raceSafe` (plain delete).
|
|
369
|
+
*/
|
|
370
|
+
keptByTouch: number;
|
|
371
|
+
/**
|
|
372
|
+
* The cutoff the guard compared touch stamps with, on the CONTENT STORE's clock (resolved from
|
|
373
|
+
* `touchedBefore`, else `touchClock() - olderThanMs`). Present on a dry run too (where it was not
|
|
374
|
+
* enforced); `undefined` when the store is not `raceSafe`.
|
|
375
|
+
*/
|
|
376
|
+
touchCutoff?: number;
|
|
377
|
+
/**
|
|
378
|
+
* ADR 0055 D5 — every erase was conditional on the blob's touch time
|
|
379
|
+
* (`deleteIfUntouchedSince`), so a `put` that re-cited a blob during the sweep kept it.
|
|
380
|
+
* `false` = the store lacks it and the sweep used plain `delete`: such a re-cite is lost.
|
|
381
|
+
*/
|
|
382
|
+
raceSafe: boolean;
|
|
383
|
+
/** ADR 0055 D6 — orphans erased (or, under `dryRun`, that WOULD be); `[]` unless `reclaimOrphans`. */
|
|
384
|
+
orphansReclaimed: string[];
|
|
385
|
+
/**
|
|
386
|
+
* Of `snapshotStores`, how many are a `ContentTouchingSnapshotStore` (branded). Informational:
|
|
387
|
+
* an unbranded store may be a raw reader over tables a wrapped writer filled.
|
|
388
|
+
*/
|
|
389
|
+
snapshotStoresTouching: number;
|
|
390
|
+
/** Of `snapshotStores`, how many are NOT branded. See `snapshotStoresTouching`. */
|
|
391
|
+
snapshotStoresUnbranded: number;
|
|
392
|
+
/**
|
|
393
|
+
* Executions whose scanned snapshot `state` is a top-level `__loomEnc` envelope (an
|
|
394
|
+
* `EncryptingSnapshotStore({ sealState })` read RAW): the refs it cites are invisible to this
|
|
395
|
+
* scan. An erasing pass throws {@link SealedSnapshotScanError} instead; a `dryRun` lists them.
|
|
396
|
+
* The check looks at the TOP-LEVEL `__loomEnc` key of `state` only, not a nested envelope.
|
|
397
|
+
*/
|
|
398
|
+
sealedSnapshots: string[];
|
|
399
|
+
/**
|
|
400
|
+
* Executions whose snapshot load threw `PayloadShreddedError` (their subject was crypto-shredded
|
|
401
|
+
* under a `sealState` store): the snapshot is erased, so it cites no readable refs and is skipped.
|
|
402
|
+
* Blobs another live owner cites stay pinned by it. Any OTHER load error still aborts the pass.
|
|
403
|
+
*/
|
|
404
|
+
shreddedSnapshots: string[];
|
|
405
|
+
/**
|
|
406
|
+
* Executions whose compacted history is NOT (fully) in the given archives and whose orphan blobs
|
|
407
|
+
* this erasing pass erased anyway because `acknowledgeUnarchivedLogs: true` accepted it. Empty
|
|
408
|
+
* otherwise (and on a dry run).
|
|
409
|
+
*/
|
|
410
|
+
unarchivedAcknowledged: string[];
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* An ERASING `reclaimOrphans` pass found compacted logs but was given no `archiveStores`: the events
|
|
414
|
+
* a compaction moved are cited only by the archive, so their blobs would look like orphans and be
|
|
415
|
+
* erased (ADR 0138). Nothing was erased.
|
|
416
|
+
*/
|
|
417
|
+
export declare class ArchiveStoresRequiredError extends TypeError {
|
|
418
|
+
readonly executionIds: readonly string[];
|
|
419
|
+
/** `"none"`: no archiveStores given. `"uncovered"`: given, but they do not hold what was archived. */
|
|
420
|
+
readonly reason: "none" | "uncovered";
|
|
421
|
+
constructor(executionIds: readonly string[],
|
|
422
|
+
/** `"none"`: no archiveStores given. `"uncovered"`: given, but they do not hold what was archived. */
|
|
423
|
+
reason?: "none" | "uncovered");
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* An erasing sweep read an archive segment that is still sealed (count > 0, no envelopes): the RAW
|
|
427
|
+
* inner store of an `EncryptingArchiveStore`. The refs inside are invisible, so live blobs would
|
|
428
|
+
* look unreferenced. Pass the sealing store itself. Nothing was erased.
|
|
429
|
+
*/
|
|
430
|
+
export declare class SealedArchiveScanError extends TypeError {
|
|
431
|
+
readonly executionIds: readonly string[];
|
|
432
|
+
constructor(executionIds: readonly string[]);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* An erasing sweep read a snapshot whose `state` is one sealed envelope (a `sealState`
|
|
436
|
+
* `EncryptingSnapshotStore` given as its RAW inner store). The scan cannot see the refs inside, so
|
|
437
|
+
* it would treat live blobs as unreferenced and erase them. Nothing was erased.
|
|
438
|
+
*/
|
|
439
|
+
export declare class SealedSnapshotScanError extends TypeError {
|
|
440
|
+
readonly executionIds: readonly string[];
|
|
441
|
+
constructor(executionIds: readonly string[]);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Mark: walk every event of every execution across the given stores, collecting
|
|
445
|
+
* each ref's latest citation timestamp, pinning refs cited from events of the
|
|
446
|
+
* designated kinds, and marking refs cited anywhere other than as a
|
|
447
|
+
* claim-check envelope's `ref` (a `digest` included) as load-bearing. Sweep:
|
|
448
|
+
* physically erase refs that are neither pinned nor load-bearing and whose
|
|
449
|
+
* effective citation time is older than the TTL — i.e. only refs cited solely as an
|
|
450
|
+
* envelope's `ref`. ADR 0146: a citing execution that has ENDED (newest kernel terminal event, not
|
|
451
|
+
* re-opened) ages its citations from `max(citation, end)`, so with a content TTL at least the log TTL a blob is
|
|
452
|
+
* never reclaimable before retention could delete the log citing it (exceptions: ADR 0146); a
|
|
453
|
+
* running execution (or a reserved stream) keeps the citation clock. Never earlier than the citation. Their erasure is invisible to replay by the claim-check
|
|
454
|
+
* contract (ADR 0054 — the fold never resolves); `resolveClaimCheck` readers get
|
|
455
|
+
* `null`. A bare ref is never reclaimed while cited (ADR 0055 D4): the resolving
|
|
456
|
+
* store would throw `ContentMissingError` on the next read. Idempotent:
|
|
457
|
+
* `ContentStore.delete` is idempotent and a reclaimed ref simply no longer
|
|
458
|
+
* resolves on the next sweep.
|
|
459
|
+
*
|
|
460
|
+
* Race-safe (ADR 0055 D5) when the store has `deleteIfUntouchedSince`: every erase is
|
|
461
|
+
* conditional on the blob being untouched since `now − olderThanMs`, so a `put` that re-cites
|
|
462
|
+
* old bytes between the scan and its own append keeps the blob. That holds while a flow's
|
|
463
|
+
* put→append window is shorter than the TTL. A citation copied without a `put` (a fork's
|
|
464
|
+
* `copyPrefix`, a ref kept inside an `append` payload) is covered by SPI 1.4.0 `touch`, which
|
|
465
|
+
* `reclaimOrphans` requires; see `reclaimOrphans`. `roots` (D7) pins addresses held outside the
|
|
466
|
+
* log; `reclaimOrphans` (D6) also erases stored blobs nothing scanned cites. Cost:
|
|
467
|
+
* O(events + blobs), all membership tests are Set/Map lookups.
|
|
468
|
+
*/
|
|
469
|
+
export declare function sweepUnpinnedContent(given: ContentSweepOptions): Promise<ContentSweepReport>;
|
|
470
|
+
//# sourceMappingURL=gc.d.ts.map
|
package/dist/gc.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gc.d.ts","sourceRoot":"","sources":["../src/gc.ts"],"names":[],"mappings":"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"}
|