@microdelta/history 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +30 -4
  2. package/dist/api/history.alpha.d.ts +3 -0
  3. package/dist/api/history.beta.d.ts +3 -0
  4. package/dist/api/history.conformance.store.alpha.d.ts +3 -0
  5. package/dist/api/history.conformance.store.beta.d.ts +3 -0
  6. package/dist/api/history.conformance.store.public.d.ts +3 -0
  7. package/dist/api/history.conformance.store.raw.alpha.d.ts +215 -0
  8. package/dist/api/history.conformance.store.raw.beta.d.ts +215 -0
  9. package/dist/api/history.conformance.store.raw.public.d.ts +215 -0
  10. package/dist/api/history.conformance.store.raw.untrimmed.d.ts +215 -0
  11. package/dist/api/history.conformance.store.untrimmed.d.ts +3 -0
  12. package/dist/api/history.public.d.ts +3 -0
  13. package/dist/api/history.root.raw.alpha.d.ts +1371 -0
  14. package/dist/api/history.root.raw.beta.d.ts +425 -0
  15. package/dist/api/history.root.raw.public.d.ts +425 -0
  16. package/dist/api/history.root.raw.untrimmed.d.ts +1372 -0
  17. package/dist/api/history.shared.alpha.d.ts +1402 -0
  18. package/dist/api/history.shared.beta.d.ts +456 -0
  19. package/dist/api/history.shared.public.d.ts +456 -0
  20. package/dist/api/history.shared.untrimmed.d.ts +1403 -0
  21. package/dist/api/history.untrimmed.d.ts +3 -0
  22. package/dist/api/tsdoc-metadata.json +11 -0
  23. package/dist/src/completed-results.d.ts +99 -0
  24. package/dist/src/completed-results.d.ts.map +1 -0
  25. package/dist/src/completed-results.js +2 -0
  26. package/dist/src/completed-results.js.map +1 -0
  27. package/dist/src/durable/contracts.d.ts +612 -0
  28. package/dist/src/durable/contracts.d.ts.map +1 -0
  29. package/dist/src/durable/contracts.js +2 -0
  30. package/dist/src/durable/contracts.js.map +1 -0
  31. package/dist/src/durable/errors.d.ts +94 -0
  32. package/dist/src/durable/errors.d.ts.map +1 -0
  33. package/dist/src/durable/errors.js +118 -0
  34. package/dist/src/durable/errors.js.map +1 -0
  35. package/dist/src/durable/index.d.ts +9 -0
  36. package/dist/src/durable/index.d.ts.map +1 -0
  37. package/dist/src/durable/index.js +770 -0
  38. package/dist/src/durable/index.js.map +1 -0
  39. package/dist/src/durable/journal.d.ts +53 -0
  40. package/dist/src/durable/journal.d.ts.map +1 -0
  41. package/dist/src/durable/journal.js +174 -0
  42. package/dist/src/durable/journal.js.map +1 -0
  43. package/dist/src/durable/locator.d.ts +31 -0
  44. package/dist/src/durable/locator.d.ts.map +1 -0
  45. package/dist/src/durable/locator.js +50 -0
  46. package/dist/src/durable/locator.js.map +1 -0
  47. package/dist/src/durable/records.d.ts +40 -0
  48. package/dist/src/durable/records.d.ts.map +1 -0
  49. package/dist/src/durable/records.js +74 -0
  50. package/dist/src/durable/records.js.map +1 -0
  51. package/dist/src/durable/schema.d.ts +37 -0
  52. package/dist/src/durable/schema.d.ts.map +1 -0
  53. package/dist/src/durable/schema.js +335 -0
  54. package/dist/src/durable/schema.js.map +1 -0
  55. package/dist/src/durable/selected-index.d.ts +94 -0
  56. package/dist/src/durable/selected-index.d.ts.map +1 -0
  57. package/dist/src/durable/selected-index.js +594 -0
  58. package/dist/src/durable/selected-index.js.map +1 -0
  59. package/dist/src/index.d.ts +28 -0
  60. package/dist/src/index.d.ts.map +1 -0
  61. package/dist/src/index.js +15 -0
  62. package/dist/src/index.js.map +1 -0
  63. package/dist/src/store/index.d.ts +128 -0
  64. package/dist/src/store/index.d.ts.map +1 -0
  65. package/dist/src/store/index.js +33 -0
  66. package/dist/src/store/index.js.map +1 -0
  67. package/dist/src/store/memory/index.d.ts +24 -0
  68. package/dist/src/store/memory/index.d.ts.map +1 -0
  69. package/dist/src/store/memory/index.js +162 -0
  70. package/dist/src/store/memory/index.js.map +1 -0
  71. package/dist/src/types.d.ts +100 -0
  72. package/dist/src/types.d.ts.map +1 -0
  73. package/dist/src/types.js +2 -0
  74. package/dist/src/types.js.map +1 -0
  75. package/dist/test/conformance/store/index.d.ts +34 -0
  76. package/dist/test/conformance/store/index.d.ts.map +1 -0
  77. package/dist/test/conformance/store/index.js +368 -0
  78. package/dist/test/conformance/store/index.js.map +1 -0
  79. package/package.json +48 -8
package/README.md CHANGED
@@ -1,7 +1,33 @@
1
- # @microdelta/history
1
+ # Result History & Publication
2
2
 
3
- This package reserves the name for microdelta trusted-publishing setup.
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
- This bootstrap version contains no runtime implementation, dependencies, or install scripts. It is not a usable library release.
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
- Development: https://github.com/mike-north/microdelta
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, namespaced by the explicitly named environment that recorded them;
18
+ - environment namespaces within one store, so a trial run's attempts, heads,
19
+ candidates, acceptances and journal records never satisfy production;
20
+ - recorded, fenced promotions that admit named exact results of one environment
21
+ into another of the same analysis, without moving or rewriting either one's history;
22
+ - Run Supervision's operation journal: opaque versioned records per environment,
23
+ owner-named collection and key, committed atomically by compare-and-set under
24
+ writer fencing, with undeclared record formats and versions refused.
25
+
26
+ It stores Resolution's provenance and Supervision's journal records as
27
+ versioned opaque records and never decides reuse eligibility, freshness or
28
+ operation meaning. The durable schema is at version 2. Files at any other
29
+ version, including version 1 files written before environment-scoped
30
+ acceptances, promotions and the journal existed, are rejected by version; stored
31
+ data is never migrated by guessing. See the
32
+ [package map](../../docs/package-map.md) and the
33
+ [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, JournalConflictError, JournalVersionError, 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, IJournalAddress, IJournalCommit, IJournalDeclaration, IJournalFormat, IJournalQuery, IJournalRecord, IJournalWrite, IOperation, IOperationJournal, IPromotionQuery, IPromotionRecord, IPromotionRequest, 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, IWriterContention, IWriterLease, IWriterRenewal, 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,3 @@
1
+ /** Entry-specific exports preserve one History type identity per release tier. */
2
+ export { storeConformance } from './history.shared.alpha.js';
3
+ export type { StoreConformanceOptions, ValueReadProbe } from './history.shared.alpha.js';
@@ -0,0 +1,3 @@
1
+ /** Entry-specific exports preserve one History type identity per release tier. */
2
+ export { storeConformance } from './history.shared.beta.js';
3
+ export type { StoreConformanceOptions, ValueReadProbe } from './history.shared.beta.js';
@@ -0,0 +1,3 @@
1
+ /** Entry-specific exports preserve one History type identity per release tier. */
2
+ export { storeConformance } from './history.shared.public.js';
3
+ export type { StoreConformanceOptions, ValueReadProbe } from './history.shared.public.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 { }