@microdelta/history 0.0.0 → 0.1.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/README.md +19 -4
- package/dist/api/history.alpha.d.ts +3 -0
- package/dist/api/history.beta.d.ts +3 -0
- package/dist/api/history.conformance.store.alpha.d.ts +3 -0
- package/dist/api/history.conformance.store.beta.d.ts +3 -0
- package/dist/api/history.conformance.store.public.d.ts +3 -0
- package/dist/api/history.conformance.store.raw.alpha.d.ts +215 -0
- package/dist/api/history.conformance.store.raw.beta.d.ts +215 -0
- package/dist/api/history.conformance.store.raw.public.d.ts +215 -0
- package/dist/api/history.conformance.store.raw.untrimmed.d.ts +215 -0
- package/dist/api/history.conformance.store.untrimmed.d.ts +3 -0
- package/dist/api/history.public.d.ts +3 -0
- package/dist/api/history.root.raw.alpha.d.ts +1058 -0
- package/dist/api/history.root.raw.beta.d.ts +393 -0
- package/dist/api/history.root.raw.public.d.ts +393 -0
- package/dist/api/history.root.raw.untrimmed.d.ts +1059 -0
- package/dist/api/history.shared.alpha.d.ts +1091 -0
- package/dist/api/history.shared.beta.d.ts +426 -0
- package/dist/api/history.shared.public.d.ts +426 -0
- package/dist/api/history.shared.untrimmed.d.ts +1092 -0
- package/dist/api/history.untrimmed.d.ts +3 -0
- package/dist/api/tsdoc-metadata.json +11 -0
- package/dist/src/completed-results.d.ts +99 -0
- package/dist/src/completed-results.d.ts.map +1 -0
- package/dist/src/completed-results.js +2 -0
- package/dist/src/completed-results.js.map +1 -0
- package/dist/src/durable/contracts.d.ts +339 -0
- package/dist/src/durable/contracts.d.ts.map +1 -0
- package/dist/src/durable/contracts.js +2 -0
- package/dist/src/durable/contracts.js.map +1 -0
- package/dist/src/durable/errors.d.ts +69 -0
- package/dist/src/durable/errors.d.ts.map +1 -0
- package/dist/src/durable/errors.js +87 -0
- package/dist/src/durable/errors.js.map +1 -0
- package/dist/src/durable/index.d.ts +9 -0
- package/dist/src/durable/index.d.ts.map +1 -0
- package/dist/src/durable/index.js +590 -0
- package/dist/src/durable/index.js.map +1 -0
- package/dist/src/durable/locator.d.ts +31 -0
- package/dist/src/durable/locator.d.ts.map +1 -0
- package/dist/src/durable/locator.js +50 -0
- package/dist/src/durable/locator.js.map +1 -0
- package/dist/src/durable/schema.d.ts +28 -0
- package/dist/src/durable/schema.d.ts.map +1 -0
- package/dist/src/durable/schema.js +266 -0
- package/dist/src/durable/schema.js.map +1 -0
- package/dist/src/durable/selected-index.d.ts +94 -0
- package/dist/src/durable/selected-index.d.ts.map +1 -0
- package/dist/src/durable/selected-index.js +592 -0
- package/dist/src/durable/selected-index.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/store/index.d.ts +128 -0
- package/dist/src/store/index.d.ts.map +1 -0
- package/dist/src/store/index.js +33 -0
- package/dist/src/store/index.js.map +1 -0
- package/dist/src/store/memory/index.d.ts +24 -0
- package/dist/src/store/memory/index.d.ts.map +1 -0
- package/dist/src/store/memory/index.js +162 -0
- package/dist/src/store/memory/index.js.map +1 -0
- package/dist/src/types.d.ts +100 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/test/conformance/store/index.d.ts +34 -0
- package/dist/test/conformance/store/index.d.ts.map +1 -0
- package/dist/test/conformance/store/index.js +368 -0
- package/dist/test/conformance/store/index.js.map +1 -0
- package/package.json +48 -8
package/README.md
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Result History & Publication
|
|
2
2
|
|
|
3
|
-
This package
|
|
3
|
+
This package owns the scaffold's row Store, memory backend, legacy compatibility
|
|
4
|
+
schema, and backend conformance suite. Its public declarations preserve the
|
|
5
|
+
existing `microdelta` facade contract. `Path` is a row-storage address, not the
|
|
6
|
+
future Value Semantics path. The memory backend proves single-row behavior only;
|
|
7
|
+
it has no durable or cross-row publication guarantee.
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
It also owns the project-private alpha durable authority, `openDurableHistory`.
|
|
10
|
+
Over injected Machine SQLite, clock and SHA-256 capabilities it owns a versioned
|
|
11
|
+
single-file schema, distinct from the legacy Store, with:
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
- the single logical writer lease, fence and clock high-water;
|
|
14
|
+
- never-reused attempt identities with stable keys and intent digests;
|
|
15
|
+
- staging and one-commit atomic publication with a current pointer per scoped subject;
|
|
16
|
+
- immutable completed results with an exact scoped selected reader generated from their canonical payload;
|
|
17
|
+
- separate acceptance records.
|
|
18
|
+
|
|
19
|
+
It stores Resolution's provenance as a versioned opaque record and never decides
|
|
20
|
+
reuse eligibility or freshness. See the
|
|
21
|
+
[package map](../../docs/package-map.md) and the
|
|
22
|
+
[durable History evidence record](../../docs/validation/m3-durable-history-2026-09-27.md).
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Entry-specific exports preserve one History type identity per release tier. */
|
|
2
|
+
export { AttemptConflictError, AttemptStateError, DuplicateRowError, FingerprintAlgorithmMismatchError, HistoryClockError, HistoryIntegrityError, HistorySchemaError, InvalidStorePatchError, MissingRowError, StaleWriterError, createMemoryStore, openDurableHistory } from './history.shared.alpha.js';
|
|
3
|
+
export type { Divergence, FieldRow, Fingerprint, GenerationPatch, GenerationRow, GenerationState, IAbandonRequest, IAcceptanceRecord, IAcceptanceRequest, IAddressSegment, IAttemptRecord, IAttemptRequest, IAttemptState, IClockCapability, ICompletedEnvelope, ICompletedNavigationReader, ICompletedProjectionReader, ICompletedResultReader, ICompletedResultReference, IDurableHistory, IDurableHistoryOptions, IHistoryScope, IOperation, IRecoveryOutcome, IResultVerification, IScopedSubject, ISelectedFact, ISelectedFingerprintRequest, ISelectedFingerprintResolution, ISelectedNode, ISelectedReadRequest, ISha256Capability, ISqliteCapability, ISqliteConnection, ISqliteRow, ISqliteRunResult, ISqliteStatement, ISqliteSynchronousResult, ISqliteValue, IStageRequest, IValueProjectionDescriptor, IValueProjectionFact, IValueProjectionMember, IValueProjectionTraversal, IVersionedRecord, IVersionedSubject, IWriterAcquisition, IWriterAcquisitionRequest, IWriterLease, Identity, MemoryStoreOptions, Outcome, Path, RecordedRead, ResultKey, Store, StoreMetadata, Subject, SubjectPatch, SubjectRow } from './history.shared.alpha.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Entry-specific exports preserve one History type identity per release tier. */
|
|
2
|
+
export { DuplicateRowError, FingerprintAlgorithmMismatchError, InvalidStorePatchError, MissingRowError, createMemoryStore } from './history.shared.beta.js';
|
|
3
|
+
export type { Divergence, FieldRow, Fingerprint, GenerationPatch, GenerationRow, GenerationState, Identity, MemoryStoreOptions, Outcome, Path, RecordedRead, ResultKey, Store, StoreMetadata, Subject, SubjectPatch, SubjectRow } from './history.shared.beta.js';
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** An immutable value node and its caller-computed fingerprint. @public */
|
|
2
|
+
declare interface FieldRow {
|
|
3
|
+
key: ResultKey;
|
|
4
|
+
generation: number;
|
|
5
|
+
path: Path;
|
|
6
|
+
fingerprint: Fingerprint;
|
|
7
|
+
value: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Compatibility shapes for the scaffold row Store. Their names and string paths
|
|
12
|
+
* describe that storage port, not the target Value Semantics or identity model.
|
|
13
|
+
*/
|
|
14
|
+
/** Opaque, stable, hex-encoded content digest; equality is string equality. @public */
|
|
15
|
+
declare type Fingerprint = string & {
|
|
16
|
+
readonly __fp: unique symbol;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Writable generation columns; tuple identity cannot change after insertion. @public */
|
|
20
|
+
declare type GenerationPatch = Partial<Omit<GenerationRow, 'key' | 'generation'>>;
|
|
21
|
+
|
|
22
|
+
/** A retained attempt, with lifecycle and numbering supplied by its caller. @public */
|
|
23
|
+
declare interface GenerationRow {
|
|
24
|
+
key: ResultKey;
|
|
25
|
+
generation: number;
|
|
26
|
+
state: GenerationState;
|
|
27
|
+
reads: RecordedRead[];
|
|
28
|
+
identity: Identity | undefined;
|
|
29
|
+
startedAt: number;
|
|
30
|
+
endedAt: number | null;
|
|
31
|
+
cost: Record<string, number>;
|
|
32
|
+
arrival: string;
|
|
33
|
+
abandonReason?: 'error' | 'lease-expired' | 'refused';
|
|
34
|
+
error?: {
|
|
35
|
+
message: string;
|
|
36
|
+
stack?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Retained lifecycle states interpreted by repository and claim, not by storage. @public */
|
|
41
|
+
declare type GenerationState = 'claimed' | 'current' | 'superseded' | 'abandoned';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Compatibility identity shape stored in scaffold rows. It does not establish
|
|
45
|
+
* target subject identity, binding correspondence, or collection semantics.
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
declare type Identity = {
|
|
49
|
+
kind: 'type';
|
|
50
|
+
type: string;
|
|
51
|
+
key: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'step';
|
|
54
|
+
name: string;
|
|
55
|
+
inputs: readonly Identity[];
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'member';
|
|
58
|
+
of: Identity;
|
|
59
|
+
path: Path;
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'collection';
|
|
62
|
+
step: string;
|
|
63
|
+
source: Identity;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** A legacy row-storage address, not the future structured semantic path. @public */
|
|
67
|
+
declare type Path = string;
|
|
68
|
+
|
|
69
|
+
/** Legacy persisted read rows; target observation encoding remains undecided. @public */
|
|
70
|
+
declare type RecordedRead = {
|
|
71
|
+
kind: 'field';
|
|
72
|
+
arg: number;
|
|
73
|
+
path: Path;
|
|
74
|
+
fingerprint: Fingerprint;
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'whole';
|
|
77
|
+
arg: number;
|
|
78
|
+
fingerprint: Fingerprint;
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'memo';
|
|
81
|
+
key: ResultKey;
|
|
82
|
+
generation: number;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Complete storage tuple. Backends must preserve boundaries between all three parts. @public */
|
|
86
|
+
declare type ResultKey = {
|
|
87
|
+
step: string;
|
|
88
|
+
revision: number;
|
|
89
|
+
subjectHash: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Storage mechanism for independent rows, with linearizable subject CAS.
|
|
94
|
+
* All inputs and returned rows are detached snapshots: caller mutation cannot
|
|
95
|
+
* alter persisted data. Values may only change by inserting another generation.
|
|
96
|
+
* There is no transaction spanning these methods; callers must not infer atomic
|
|
97
|
+
* claim/generation publication from the per-row CAS guarantee.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
declare interface Store {
|
|
101
|
+
/** Return detached format metadata; opening code must reject algorithm mismatches. */
|
|
102
|
+
meta(): Promise<StoreMetadata>;
|
|
103
|
+
/** Read a detached subject snapshot, or undefined for an absent tuple. */
|
|
104
|
+
getSubject(key: ResultKey): Promise<SubjectRow | undefined>;
|
|
105
|
+
/** Insert only; duplicate tuples reject, as do versions outside safe integers. */
|
|
106
|
+
putSubject(row: SubjectRow): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Atomically apply a shallow column patch only when the stored version matches.
|
|
109
|
+
* Success increments that version once, even for an empty patch; a missing or
|
|
110
|
+
* stale row returns false without changes. Key/version properties reject at
|
|
111
|
+
* runtime, including extras passed from untyped JavaScript callers.
|
|
112
|
+
* An exhausted MAX_SAFE_INTEGER version rejects rather than reporting success
|
|
113
|
+
* without advancing the token. Neither rejection changes the stored row.
|
|
114
|
+
*/
|
|
115
|
+
casSubject(key: ResultKey, expectedVersion: number, patch: SubjectPatch): Promise<boolean>;
|
|
116
|
+
/** Read a detached generation, or undefined for an absent tuple. */
|
|
117
|
+
getGeneration(key: ResultKey, generation: number): Promise<GenerationRow | undefined>;
|
|
118
|
+
/** Return detached rows for exactly this complete key; ordering is unspecified. */
|
|
119
|
+
listGenerations(key: ResultKey): Promise<GenerationRow[]>;
|
|
120
|
+
/** Insert only; generation numbers are supplied, never allocated by storage. */
|
|
121
|
+
putGeneration(row: GenerationRow): Promise<void>;
|
|
122
|
+
/** Patch an existing row; missing tuples and attempts to change its key reject. */
|
|
123
|
+
updateGeneration(key: ResultKey, generation: number, patch: GenerationPatch): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Insert an atomic batch of immutable fields. Duplicate addresses, within the
|
|
126
|
+
* batch or already stored, reject the whole batch without inserting anything.
|
|
127
|
+
* This proposed storage refinement enforces retained-value immutability.
|
|
128
|
+
*/
|
|
129
|
+
putFields(rows: FieldRow[]): Promise<void>;
|
|
130
|
+
/** Return requested field snapshots; absent paths are omitted. */
|
|
131
|
+
getFields(key: ResultKey, generation: number, paths: Path[]): Promise<FieldRow[]>;
|
|
132
|
+
/** Return requested fingerprints without reading/deserializing any field value. */
|
|
133
|
+
getFingerprints(key: ResultKey, generation: number, paths: Path[]): Promise<Map<Path, Fingerprint>>;
|
|
134
|
+
/**
|
|
135
|
+
* Query leases strictly less than now, oldest first, with at most limit rows.
|
|
136
|
+
* Zero limit returns no rows. This query never sweeps or changes a claim.
|
|
137
|
+
*/
|
|
138
|
+
expiredClaims(now: number, limit: number): Promise<SubjectRow[]>;
|
|
139
|
+
/** Release resources owned by this store. */
|
|
140
|
+
close(): Promise<void>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Register reusable backend qualification tests for SA-1 through SA-7.
|
|
145
|
+
* Register this from a Jest test module; the suite imports no concrete backend.
|
|
146
|
+
* Mutation tests enforce rev 9's retained-value isolation at the storage seam.
|
|
147
|
+
* This suite does not assert atomicity across subject, generation, and field rows:
|
|
148
|
+
* the supplied Store contract does not provide that operation.
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
151
|
+
export declare function storeConformance(name: string, options: StoreConformanceOptions): void;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Opens a fresh store for each test. The optional algorithm models persisted metadata
|
|
155
|
+
* at open time; factories must reject a mismatch with their runtime algorithm.
|
|
156
|
+
* Instrumentation is optional for third-party backends, but both shipped backends
|
|
157
|
+
* must provide it to qualify SA-3 without relying on wall-clock timing.
|
|
158
|
+
* @public
|
|
159
|
+
*/
|
|
160
|
+
export declare interface StoreConformanceOptions {
|
|
161
|
+
create(options?: {
|
|
162
|
+
fingerprintAlgorithm?: string;
|
|
163
|
+
}): Store | Promise<Store>;
|
|
164
|
+
fingerprintAlgorithm: string;
|
|
165
|
+
probeValueReads?(store: Store): ValueReadProbe;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Persisted format identifiers, checked before using a store's fingerprints. @public */
|
|
169
|
+
declare interface StoreMetadata {
|
|
170
|
+
schemaVersion: number;
|
|
171
|
+
fingerprintAlgorithm: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Legacy row subject shape; future author-supplied subject identity is separate. @public */
|
|
175
|
+
declare type Subject = Extract<Identity, {
|
|
176
|
+
kind: 'step';
|
|
177
|
+
}>;
|
|
178
|
+
|
|
179
|
+
/** Writable subject columns; the complete key and CAS token cannot be patched. @public */
|
|
180
|
+
declare type SubjectPatch = Partial<Omit<SubjectRow, 'key' | 'version'>>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* One compare-and-set row per complete result key. Repository owns generation
|
|
184
|
+
* meaning; claim owns lease meaning. Storage only preserves and patches columns.
|
|
185
|
+
* @public
|
|
186
|
+
*/
|
|
187
|
+
declare interface SubjectRow {
|
|
188
|
+
key: ResultKey;
|
|
189
|
+
subject: Subject;
|
|
190
|
+
/** Nonnegative safe-integer CAS token, incremented once per successful CAS. */
|
|
191
|
+
version: number;
|
|
192
|
+
currentGeneration: number | null;
|
|
193
|
+
claim: null | {
|
|
194
|
+
generation: number;
|
|
195
|
+
holder: string;
|
|
196
|
+
leaseUntil: number;
|
|
197
|
+
progress: {
|
|
198
|
+
fingerprint: Fingerprint;
|
|
199
|
+
value: unknown;
|
|
200
|
+
} | null;
|
|
201
|
+
};
|
|
202
|
+
durations: number[];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* A backend's test-only counter at its actual value-read/deserialization boundary.
|
|
207
|
+
* The suite resets it after insertion and verifies a positive control with getFields.
|
|
208
|
+
* @public
|
|
209
|
+
*/
|
|
210
|
+
export declare interface ValueReadProbe {
|
|
211
|
+
reset(): void;
|
|
212
|
+
count(): number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export { }
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** An immutable value node and its caller-computed fingerprint. @public */
|
|
2
|
+
declare interface FieldRow {
|
|
3
|
+
key: ResultKey;
|
|
4
|
+
generation: number;
|
|
5
|
+
path: Path;
|
|
6
|
+
fingerprint: Fingerprint;
|
|
7
|
+
value: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Compatibility shapes for the scaffold row Store. Their names and string paths
|
|
12
|
+
* describe that storage port, not the target Value Semantics or identity model.
|
|
13
|
+
*/
|
|
14
|
+
/** Opaque, stable, hex-encoded content digest; equality is string equality. @public */
|
|
15
|
+
declare type Fingerprint = string & {
|
|
16
|
+
readonly __fp: unique symbol;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Writable generation columns; tuple identity cannot change after insertion. @public */
|
|
20
|
+
declare type GenerationPatch = Partial<Omit<GenerationRow, 'key' | 'generation'>>;
|
|
21
|
+
|
|
22
|
+
/** A retained attempt, with lifecycle and numbering supplied by its caller. @public */
|
|
23
|
+
declare interface GenerationRow {
|
|
24
|
+
key: ResultKey;
|
|
25
|
+
generation: number;
|
|
26
|
+
state: GenerationState;
|
|
27
|
+
reads: RecordedRead[];
|
|
28
|
+
identity: Identity | undefined;
|
|
29
|
+
startedAt: number;
|
|
30
|
+
endedAt: number | null;
|
|
31
|
+
cost: Record<string, number>;
|
|
32
|
+
arrival: string;
|
|
33
|
+
abandonReason?: 'error' | 'lease-expired' | 'refused';
|
|
34
|
+
error?: {
|
|
35
|
+
message: string;
|
|
36
|
+
stack?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Retained lifecycle states interpreted by repository and claim, not by storage. @public */
|
|
41
|
+
declare type GenerationState = 'claimed' | 'current' | 'superseded' | 'abandoned';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Compatibility identity shape stored in scaffold rows. It does not establish
|
|
45
|
+
* target subject identity, binding correspondence, or collection semantics.
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
declare type Identity = {
|
|
49
|
+
kind: 'type';
|
|
50
|
+
type: string;
|
|
51
|
+
key: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'step';
|
|
54
|
+
name: string;
|
|
55
|
+
inputs: readonly Identity[];
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'member';
|
|
58
|
+
of: Identity;
|
|
59
|
+
path: Path;
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'collection';
|
|
62
|
+
step: string;
|
|
63
|
+
source: Identity;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** A legacy row-storage address, not the future structured semantic path. @public */
|
|
67
|
+
declare type Path = string;
|
|
68
|
+
|
|
69
|
+
/** Legacy persisted read rows; target observation encoding remains undecided. @public */
|
|
70
|
+
declare type RecordedRead = {
|
|
71
|
+
kind: 'field';
|
|
72
|
+
arg: number;
|
|
73
|
+
path: Path;
|
|
74
|
+
fingerprint: Fingerprint;
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'whole';
|
|
77
|
+
arg: number;
|
|
78
|
+
fingerprint: Fingerprint;
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'memo';
|
|
81
|
+
key: ResultKey;
|
|
82
|
+
generation: number;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Complete storage tuple. Backends must preserve boundaries between all three parts. @public */
|
|
86
|
+
declare type ResultKey = {
|
|
87
|
+
step: string;
|
|
88
|
+
revision: number;
|
|
89
|
+
subjectHash: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Storage mechanism for independent rows, with linearizable subject CAS.
|
|
94
|
+
* All inputs and returned rows are detached snapshots: caller mutation cannot
|
|
95
|
+
* alter persisted data. Values may only change by inserting another generation.
|
|
96
|
+
* There is no transaction spanning these methods; callers must not infer atomic
|
|
97
|
+
* claim/generation publication from the per-row CAS guarantee.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
declare interface Store {
|
|
101
|
+
/** Return detached format metadata; opening code must reject algorithm mismatches. */
|
|
102
|
+
meta(): Promise<StoreMetadata>;
|
|
103
|
+
/** Read a detached subject snapshot, or undefined for an absent tuple. */
|
|
104
|
+
getSubject(key: ResultKey): Promise<SubjectRow | undefined>;
|
|
105
|
+
/** Insert only; duplicate tuples reject, as do versions outside safe integers. */
|
|
106
|
+
putSubject(row: SubjectRow): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Atomically apply a shallow column patch only when the stored version matches.
|
|
109
|
+
* Success increments that version once, even for an empty patch; a missing or
|
|
110
|
+
* stale row returns false without changes. Key/version properties reject at
|
|
111
|
+
* runtime, including extras passed from untyped JavaScript callers.
|
|
112
|
+
* An exhausted MAX_SAFE_INTEGER version rejects rather than reporting success
|
|
113
|
+
* without advancing the token. Neither rejection changes the stored row.
|
|
114
|
+
*/
|
|
115
|
+
casSubject(key: ResultKey, expectedVersion: number, patch: SubjectPatch): Promise<boolean>;
|
|
116
|
+
/** Read a detached generation, or undefined for an absent tuple. */
|
|
117
|
+
getGeneration(key: ResultKey, generation: number): Promise<GenerationRow | undefined>;
|
|
118
|
+
/** Return detached rows for exactly this complete key; ordering is unspecified. */
|
|
119
|
+
listGenerations(key: ResultKey): Promise<GenerationRow[]>;
|
|
120
|
+
/** Insert only; generation numbers are supplied, never allocated by storage. */
|
|
121
|
+
putGeneration(row: GenerationRow): Promise<void>;
|
|
122
|
+
/** Patch an existing row; missing tuples and attempts to change its key reject. */
|
|
123
|
+
updateGeneration(key: ResultKey, generation: number, patch: GenerationPatch): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Insert an atomic batch of immutable fields. Duplicate addresses, within the
|
|
126
|
+
* batch or already stored, reject the whole batch without inserting anything.
|
|
127
|
+
* This proposed storage refinement enforces retained-value immutability.
|
|
128
|
+
*/
|
|
129
|
+
putFields(rows: FieldRow[]): Promise<void>;
|
|
130
|
+
/** Return requested field snapshots; absent paths are omitted. */
|
|
131
|
+
getFields(key: ResultKey, generation: number, paths: Path[]): Promise<FieldRow[]>;
|
|
132
|
+
/** Return requested fingerprints without reading/deserializing any field value. */
|
|
133
|
+
getFingerprints(key: ResultKey, generation: number, paths: Path[]): Promise<Map<Path, Fingerprint>>;
|
|
134
|
+
/**
|
|
135
|
+
* Query leases strictly less than now, oldest first, with at most limit rows.
|
|
136
|
+
* Zero limit returns no rows. This query never sweeps or changes a claim.
|
|
137
|
+
*/
|
|
138
|
+
expiredClaims(now: number, limit: number): Promise<SubjectRow[]>;
|
|
139
|
+
/** Release resources owned by this store. */
|
|
140
|
+
close(): Promise<void>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Register reusable backend qualification tests for SA-1 through SA-7.
|
|
145
|
+
* Register this from a Jest test module; the suite imports no concrete backend.
|
|
146
|
+
* Mutation tests enforce rev 9's retained-value isolation at the storage seam.
|
|
147
|
+
* This suite does not assert atomicity across subject, generation, and field rows:
|
|
148
|
+
* the supplied Store contract does not provide that operation.
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
151
|
+
export declare function storeConformance(name: string, options: StoreConformanceOptions): void;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Opens a fresh store for each test. The optional algorithm models persisted metadata
|
|
155
|
+
* at open time; factories must reject a mismatch with their runtime algorithm.
|
|
156
|
+
* Instrumentation is optional for third-party backends, but both shipped backends
|
|
157
|
+
* must provide it to qualify SA-3 without relying on wall-clock timing.
|
|
158
|
+
* @public
|
|
159
|
+
*/
|
|
160
|
+
export declare interface StoreConformanceOptions {
|
|
161
|
+
create(options?: {
|
|
162
|
+
fingerprintAlgorithm?: string;
|
|
163
|
+
}): Store | Promise<Store>;
|
|
164
|
+
fingerprintAlgorithm: string;
|
|
165
|
+
probeValueReads?(store: Store): ValueReadProbe;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Persisted format identifiers, checked before using a store's fingerprints. @public */
|
|
169
|
+
declare interface StoreMetadata {
|
|
170
|
+
schemaVersion: number;
|
|
171
|
+
fingerprintAlgorithm: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Legacy row subject shape; future author-supplied subject identity is separate. @public */
|
|
175
|
+
declare type Subject = Extract<Identity, {
|
|
176
|
+
kind: 'step';
|
|
177
|
+
}>;
|
|
178
|
+
|
|
179
|
+
/** Writable subject columns; the complete key and CAS token cannot be patched. @public */
|
|
180
|
+
declare type SubjectPatch = Partial<Omit<SubjectRow, 'key' | 'version'>>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* One compare-and-set row per complete result key. Repository owns generation
|
|
184
|
+
* meaning; claim owns lease meaning. Storage only preserves and patches columns.
|
|
185
|
+
* @public
|
|
186
|
+
*/
|
|
187
|
+
declare interface SubjectRow {
|
|
188
|
+
key: ResultKey;
|
|
189
|
+
subject: Subject;
|
|
190
|
+
/** Nonnegative safe-integer CAS token, incremented once per successful CAS. */
|
|
191
|
+
version: number;
|
|
192
|
+
currentGeneration: number | null;
|
|
193
|
+
claim: null | {
|
|
194
|
+
generation: number;
|
|
195
|
+
holder: string;
|
|
196
|
+
leaseUntil: number;
|
|
197
|
+
progress: {
|
|
198
|
+
fingerprint: Fingerprint;
|
|
199
|
+
value: unknown;
|
|
200
|
+
} | null;
|
|
201
|
+
};
|
|
202
|
+
durations: number[];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* A backend's test-only counter at its actual value-read/deserialization boundary.
|
|
207
|
+
* The suite resets it after insertion and verifies a positive control with getFields.
|
|
208
|
+
* @public
|
|
209
|
+
*/
|
|
210
|
+
export declare interface ValueReadProbe {
|
|
211
|
+
reset(): void;
|
|
212
|
+
count(): number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export { }
|