@kairos-es/codec 1.0.0-alpha.0 → 1.0.0-alpha.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.
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.recordQuery = exports.makeReadLedger = exports.deriveLayeredCondition = exports.assertServableAddition = exports.ambientLayeredCondition = exports.TaglessSliceInLedger = exports.ReadLedger = exports.NoReadsRecorded = void 0;
7
+ var _core = require("@kairos-es/core");
8
+ var _effect = require("effect");
9
+ /**
10
+ * The ambient ledger, present only inside a bracket.
11
+ *
12
+ * ⚠ A RECORDING path reads it with `Effect.serviceOption` and never
13
+ * `yield* ReadLedger`: its absence is the normal case there, and costing the
14
+ * requirement channel nothing is exactly what makes this change additive.
15
+ * `modelAtHead` is that path and is why the rule exists.
16
+ *
17
+ * A BRACKET-ONLY function is the opposite case and yields the tag deliberately.
18
+ * `decideOnly` does, and naming the requirement is what turns *"call me inside a
19
+ * bracket"* from a runtime defect into a compile error — presence being the one
20
+ * direction the type system can decide here. So the test is what the function
21
+ * means outside a bracket: nothing (record ambiently), or nothing sensible
22
+ * (require it).
23
+ *
24
+ * Recording is two-phase, and `record`'s own doc below owns why and what shape the
25
+ * second phase takes.
26
+ */
27
+ class ReadLedger extends /*#__PURE__*/_effect.Context.Tag('@kairos-es/codec/ReadLedger')() {}
28
+ /**
29
+ * Raised when a bracket closes having recorded no read at all.
30
+ *
31
+ * On the ERROR channel and deliberately split from the nested-append DEFECT,
32
+ * because the two are different mistakes. An empty bracket can arise from a
33
+ * data-dependent branch that produces events without reading — a genuinely
34
+ * unconditional creation, written inside a bracket by mistake — where a nested
35
+ * append is always a wiring fault. An error-channel value lets a caller decide
36
+ * which it is.
37
+ *
38
+ * Its job is narrower than it looks, and the narrowing is worth stating because
39
+ * the wider reading is the tempting one. Once a bracket's guard is itself a fold,
40
+ * a body that reads nothing still has a hop, so this cannot fire — it is the guard
41
+ * against an unguarded UNCONDITIONAL bracket, not against an unguarded bracket. A
42
+ * bracket that looks guarded and is not is NOT what this catches and never was,
43
+ * and nothing else catches it either — `precondition.ts` owns that gap and the
44
+ * rule a reader has to keep in its place. A refusal taken BEFORE reading is not
45
+ * this case either: it short-circuits and surfaces as the refusal.
46
+ */
47
+ exports.ReadLedger = ReadLedger;
48
+ class NoReadsRecorded extends /*#__PURE__*/_effect.Data.TaggedError('NoReadsRecorded') {
49
+ /**
50
+ * The sentence, as the `Error` field that says why — so the fault renders
51
+ * ITSELF, exactly as this package's other two errors do (`errors.ts` owns the
52
+ * argument for the mechanism and it is not restated here).
53
+ *
54
+ * A getter over a constant rather than a constructor field, because there is no
55
+ * datum to vary: every raise of this error means one thing.
56
+ */
57
+ get message() {
58
+ return 'the bracket closed having recorded no read, so there is no append condition ' + 'to derive. A decision that reads nothing is unconditional — say so with the ' + 'escape hatch, which takes a reason, rather than by opening a bracket.';
59
+ }
60
+ }
61
+ /**
62
+ * Raised when recording a hop would leave the bracket's accumulated union
63
+ * unservable.
64
+ *
65
+ * The store refuses a multi-item query in which any item is tagless, and it
66
+ * refuses it by THROWING inside the append decorator, which becomes a defect:
67
+ * uncatchable, one call and one layer away from the `build()` that chose no tags.
68
+ * A slice built without tags defaults to none, so it is perfectly servable alone
69
+ * and kills the append the moment it is unioned. This moves that failure onto the
70
+ * error channel, to the read that caused it, naming the record entry to fix.
71
+ *
72
+ * It refuses an unservable UNION and not every tagless hop, which is the easy
73
+ * mistake to make in the other direction: one tagless slice read on its own is
74
+ * servable and must keep working. Two cases reach it — a tagless hop unioned with
75
+ * another, and a single hop whose own RECORD holds two tagless slices, which
76
+ * composes to a multi-item query with no second hop needed.
77
+ */
78
+ exports.NoReadsRecorded = NoReadsRecorded;
79
+ class TaglessSliceInLedger extends /*#__PURE__*/_effect.Data.TaggedError('TaglessSliceInLedger') {
80
+ /** The offending slice and the remedy, in one sentence. */
81
+ get message() {
82
+ return `slice '${this.sliceKey}' was built with no tags, and this bracket now reads ` + 'more than one slice. A layered append condition unions every query it ' + 'recorded, and the store refuses a multi-item query if any item is tagless. ' + 'Pass `build({ tags: [...] })` for this slice.';
83
+ }
84
+ }
85
+ /**
86
+ * The ONE derivation: the union of every query walked, at the earliest head
87
+ * observed. Package-internal, for the reason the module doc gives.
88
+ *
89
+ * The union goes through core's own `unionQueries` — the merge
90
+ * `composeProjections` folds a record through, reached without one — and never a
91
+ * spread of `items`, because a wildcard hop (`items: []`) is ABSORBING under OR
92
+ * while a spread of an empty list contributes nothing, so hand-rolling the union
93
+ * narrows a match-everything hop to its sibling, silently and in the unsafe
94
+ * direction. A
95
+ * repeated or overlapping hop is harmless because this derives ONCE from a merged
96
+ * set and matching is idempotent over an OR; that property belongs to deriving
97
+ * once and would be lost by a refactor to per-hop evaluation.
98
+ *
99
+ * ## When any hop is headless the floor is `ORIGIN`, and the alternative is unsound
100
+ *
101
+ * The earliest head that actually ARRIVED is refused, and is named here as refused
102
+ * rather than merely not chosen, because it is what a reader writes by accident
103
+ * when told to take the earliest head. With one headless hop among completed hops
104
+ * the union looks right and the floor betrays it, sitting already above the
105
+ * invalidating event.
106
+ *
107
+ * `ORIGIN`'s cost is measured rather than described: it refuses every append to
108
+ * any identity that already has history, so it is not a conservative default but a
109
+ * hard stop. It is affordable only because conflict retry wraps the bracket from
110
+ * OUTSIDE and re-reads, which is the rule the whole shape depends on.
111
+ */
112
+ exports.TaglessSliceInLedger = TaglessSliceInLedger;
113
+ const deriveLayeredCondition = hops => {
114
+ if (hops.length === 0) {
115
+ return undefined;
116
+ }
117
+ const merged = (0, _core.unionQueries)(hops.map(hop => hop.query));
118
+ const arrived = hops.flatMap(hop => hop.head === undefined ? [] : [hop.head]);
119
+ // A headless hop widens the guard to the whole log. Unioning its query is the
120
+ // half that is not in dispute; the floor is where the two readings diverge.
121
+ const after = arrived.length === hops.length ? arrived.reduce((a, b) => b < a ? b : a) : _core.ORIGIN;
122
+ return {
123
+ failIfEventsMatch: merged,
124
+ after
125
+ };
126
+ };
127
+ /**
128
+ * A fresh ledger and the `Layer` providing it: a `Ref` of hops behind the two-phase
129
+ * `record` the service declares.
130
+ *
131
+ * The hops effect is handed back beside the layer because the bracket reads them
132
+ * AFTER the body has run and the layer is out of scope, which is the same moment it
133
+ * stops being able to reach the service.
134
+ */
135
+ exports.deriveLayeredCondition = deriveLayeredCondition;
136
+ const makeReadLedger = exports.makeReadLedger = /*#__PURE__*/_effect.Effect.gen(function* () {
137
+ const ref = yield* _effect.Ref.make([]);
138
+ return {
139
+ layer: _effect.Layer.succeed(ReadLedger, {
140
+ record: query => _effect.Ref.modify(ref, hops => [
141
+ // The close effect closes over the slot this hop just took, so the slot
142
+ // never becomes a value anything else has to carry or interpret.
143
+ head => _effect.Ref.update(ref, current => current.map((hop, index) => index === hops.length ? {
144
+ query: hop.query,
145
+ head
146
+ } : hop)), [...hops, {
147
+ query
148
+ }]]),
149
+ hops: _effect.Ref.get(ref)
150
+ }),
151
+ // The same effect the service exposes, reachable AFTER the layer is out of
152
+ // scope — which is exactly when the bracket derives.
153
+ hops: _effect.Ref.get(ref)
154
+ };
155
+ });
156
+ /**
157
+ * Run `f` against the ambient ledger, or answer `absent` when there is none.
158
+ *
159
+ * "Outside a bracket this is a no-op" is ONE fact stated once, rather than one
160
+ * per consumer free to drift from the others. Every ambient lookup in this module
161
+ * goes through here, which is also what keeps `Effect.serviceOption` — the reason
162
+ * nothing enters the requirement channel — from being a detail each caller has to
163
+ * remember.
164
+ */
165
+ const withLedger = (absent, f) => _effect.Effect.flatMap(_effect.Effect.serviceOption(ReadLedger), ledger => _effect.Option.isNone(ledger) ? _effect.Effect.succeed(absent) : f(ledger.value));
166
+ /** A close effect that does nothing: what a read outside a bracket gets back. */
167
+ const NO_CLOSE = () => _effect.Effect.void;
168
+ /**
169
+ * File a query into the ambient ledger if there is one, and hand back the effect
170
+ * that completes it. Outside a bracket the whole thing is a no-op, and the caller
171
+ * still writes one line rather than a conditional.
172
+ */
173
+ const recordQuery = query => withLedger(NO_CLOSE, ledger => ledger.record(query));
174
+ /** The tagless slice keys in a record, in declaration order. */
175
+ exports.recordQuery = recordQuery;
176
+ const taglessKeys = projections => Object.entries(projections).filter(([, projection]) => projection.query.items.some(item => item.tags.length === 0)).map(([key]) => key);
177
+ /** Would recording this record's query leave the accumulated union unservable? */
178
+ const unionWouldBeUnservable = (existing, incoming) => (0, _core.servableQueryFault)((0, _core.unionQueries)([...existing.map(h => h.query), incoming])) !== undefined;
179
+ /**
180
+ * Refuse a read that would leave the bracket's accumulated union unservable,
181
+ * BEFORE the read is paid for.
182
+ *
183
+ * Servability is answerable from the queries alone, so the check runs when a hop is
184
+ * recorded rather than at append time — the eager half of the eager/lazy split doing
185
+ * one more job. Outside a bracket nothing is unioned and nothing is unservable, so
186
+ * the ordinary single-hop caller is untaxed.
187
+ *
188
+ * It judges the PROSPECTIVE UNION and asks core for the verdict, which is what makes
189
+ * both failing shapes one case rather than two. An earlier version tested each
190
+ * recorded query separately and treated a FIRST hop as unconditionally fine — but a
191
+ * hop is a RECORD, and a record of two tagless slices composes to a multi-item query
192
+ * that is unservable on its own. That read died at the store, uncatchably, on the
193
+ * exact path this error exists to keep off the defect channel. A grammar with two
194
+ * homes drifts at the shapes neither author had in mind, so there is one home and it
195
+ * is `servableQueryFault`'s.
196
+ *
197
+ * Where the OFFENDING slice is THIS record's the ledger can name its key; where it
198
+ * belongs to an earlier hop it can only say so, a recorded hop keeping its query
199
+ * rather than the key it was composed from. That asymmetry is diagnostic-only and is
200
+ * why the message is built from a key that may be a placeholder.
201
+ */
202
+ const assertServableAddition = projections => withLedger(undefined, ledger => _effect.Effect.flatMap(ledger.hops, existing => {
203
+ const incoming = (0, _core.composeProjections)(projections).query;
204
+ if (!unionWouldBeUnservable(existing, incoming)) {
205
+ return _effect.Effect.void;
206
+ }
207
+ // The offending key where the tagless slice is THIS record's, and a
208
+ // placeholder where it belongs to an earlier hop — a recorded hop keeps its
209
+ // query rather than the key it was composed from.
210
+ const offending = taglessKeys(projections)[0] ?? '<an earlier hop>';
211
+ return new TaglessSliceInLedger({
212
+ sliceKey: offending
213
+ });
214
+ }));
215
+ /**
216
+ * The condition the ambient ledger derives right now, or `None` outside a bracket.
217
+ *
218
+ * This is what makes `buildDecisionModel` correct inside a bracket: the call whose
219
+ * current behaviour is the hazard derives from every hop the bracket walked rather
220
+ * than from its own single read.
221
+ */
222
+ exports.assertServableAddition = assertServableAddition;
223
+ const ambientLayeredCondition = exports.ambientLayeredCondition = /*#__PURE__*/withLedger(/*#__PURE__*/_effect.Option.none(), ledger => _effect.Effect.map(ledger.hops, hops => _effect.Option.fromNullable(deriveLayeredCondition(hops))));
224
+ //# sourceMappingURL=readLedger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readLedger.js","names":["_core","require","_effect","ReadLedger","Context","Tag","exports","NoReadsRecorded","Data","TaggedError","message","TaglessSliceInLedger","sliceKey","deriveLayeredCondition","hops","length","undefined","merged","unionQueries","map","hop","query","arrived","flatMap","head","after","reduce","a","b","ORIGIN","failIfEventsMatch","makeReadLedger","Effect","gen","ref","Ref","make","layer","Layer","succeed","record","modify","update","current","index","get","withLedger","absent","f","serviceOption","ledger","Option","isNone","value","NO_CLOSE","void","recordQuery","taglessKeys","projections","Object","entries","filter","projection","items","some","item","tags","key","unionWouldBeUnservable","existing","incoming","servableQueryFault","h","assertServableAddition","composeProjections","offending","ambientLayeredCondition","none","fromNullable"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -60,6 +60,7 @@ import { Effect } from 'effect';
60
60
  import { type RequirementOf } from './decisionModel.js';
61
61
  import type { CodecError } from './errors.js';
62
62
  import type { SliceProjection } from './projection.js';
63
+ import type { TaglessSliceInLedger } from './readLedger.js';
63
64
  import type { Serializer } from './Serializer.js';
64
65
  import type { Uuid } from './Uuid.js';
65
66
  /**
@@ -150,8 +151,15 @@ export declare const decider: <P extends Record<string, SliceProjection>, Comman
150
151
  * (`buildDecisionModel`) and produce (`toEvent`) sides, `Uuid` through produce,
151
152
  * the slices' `RequirementOf<P>` through decode, and `R` through produce. (For a
152
153
  * def whose `Schema` carries a requirement, `RequirementOf<P>` and `R` are the
153
- * same tag.) Any `decide` failure, a decode `CodecError`, or an
154
- * `AppendConditionFailed` propagates on the error channel unchanged.
154
+ * same tag.) Any `decide` failure, a decode `CodecError`, an
155
+ * `AppendConditionFailed`, or the read's own `TaglessSliceInLedger` propagates on
156
+ * the error channel unchanged.
157
+ *
158
+ * ⚠ INSIDE a bracket this function is REFUSED, as a defect, at the store's shared
159
+ * append decorator, and `decideOnly` is what a body reaches for instead.
160
+ * `index.ts` states that pair, why each refuses exactly where the other is the
161
+ * answer, and why neither can be expressed over the other. Read it before
162
+ * changing either signature; this file does not restate the argument.
155
163
  */
156
- export declare const runDecider: <P extends Record<string, SliceProjection>, Command, E, R>(decider: Decider<P, Command, E, R>, command: Command) => Effect.Effect<Position, E | CodecError | AppendConditionFailed, DcbEventStore | Serializer | Uuid | R | RequirementOf<P>>;
164
+ export declare const runDecider: <P extends Record<string, SliceProjection>, Command, E, R>(decider: Decider<P, Command, E, R>, command: Command) => Effect.Effect<Position, E | CodecError | AppendConditionFailed | TaglessSliceInLedger, DcbEventStore | Serializer | Uuid | R | RequirementOf<P>>;
157
165
  //# sourceMappingURL=decider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decider.d.ts","sourceRoot":"","sources":["../../src/decider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,QAAQ,EACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAElC;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO,CACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,CAAC,GAAG,KAAK,EACT,CAAC,GAAG,KAAK;IAET,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,CAAA;IAC7C,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAChB,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EACnC,CAAC,EACD,UAAU,GAAG,IAAI,GAAG,CAAC,CACtB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,eAAO,MAAM,OAAO,GAClB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,GAAG,SAAS,MAAM,CAAC,MAAM,CACvB,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EACnC,OAAO,EACP,OAAO,CACR,EAED,aAAa,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,EACpC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,GAAG,KAC1D,OAAO,CACR,CAAC,EACD,OAAO,EACP,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC,CAOrD,CAAA;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,GACrB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,CAAC,EACD,CAAC,EAED,SAAS,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,EAClC,SAAS,OAAO,KACf,MAAM,CAAC,MAAM,CACd,QAAQ,EACR,CAAC,GAAG,UAAU,GAAG,qBAAqB,EACtC,aAAa,GAAG,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAStD,CAAA"}
1
+ {"version":3,"file":"decider.d.ts","sourceRoot":"","sources":["../../src/decider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,QAAQ,EACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAElC;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO,CACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,CAAC,GAAG,KAAK,EACT,CAAC,GAAG,KAAK;IAET,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,CAAA;IAC7C,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAChB,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EACnC,CAAC,EACD,UAAU,GAAG,IAAI,GAAG,CAAC,CACtB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,eAAO,MAAM,OAAO,GAClB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,GAAG,SAAS,MAAM,CAAC,MAAM,CACvB,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EACnC,OAAO,EACP,OAAO,CACR,EAED,aAAa,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,EACpC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,GAAG,KAC1D,OAAO,CACR,CAAC,EACD,OAAO,EACP,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC,CAOrD,CAAA;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,UAAU,GACrB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACzC,OAAO,EACP,CAAC,EACD,CAAC,EAED,SAAS,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,EAClC,SAAS,OAAO,KACf,MAAM,CAAC,MAAM,CACd,QAAQ,EACR,CAAC,GAAG,UAAU,GAAG,qBAAqB,GAAG,oBAAoB,EAC7D,aAAa,GAAG,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAStD,CAAA"}
@@ -7,11 +7,18 @@
7
7
  * `modelAtHead` stops where the fold does, at `{ state, head }` — a
8
8
  * materialisation of the record with no table, no checkpoint and no runner.
9
9
  * `buildDecisionModel` adds the only part that is genuinely decision-specific:
10
- * the `AppendCondition` derived from the same query and that same head (the DCB
11
- * optimistic-concurrency contract). It is core's old
12
- * `buildDecisionModel(Record<string, AnyProjection>)` surface, moved here
10
+ * the `AppendCondition` (the DCB optimistic-concurrency contract). It is core's
11
+ * old `buildDecisionModel(Record<string, AnyProjection>)` surface, moved here
13
12
  * because decode needs `Schema` + the `Serializer`.
14
13
  *
14
+ * BOTH exports also record into the ambient read ledger when one is in context,
15
+ * which is what makes a decision that walks a chain of identifiers guard on every
16
+ * hop rather than on its last. Recording is `modelAtHead`'s, so it happens
17
+ * whatever symbol performed the read; outside a bracket there is no ledger,
18
+ * nothing is recorded and no behaviour changes. `readLedger.ts` owns the whole
19
+ * argument, including why the recorder is this module rather than a
20
+ * layered-only entry point of its own.
21
+ *
15
22
  * The fold stays pure and in core; only the decode stage is effectful, and that
16
23
  * stage lives in `decode.ts` — `decodeSlices` — so the read side folds a live
17
24
  * `subscribe` stream through the *same* decode this module folds a bounded
@@ -28,6 +35,7 @@ import { type AppendCondition, type CompositeState, DcbEventStore, type Position
28
35
  import { Effect } from 'effect';
29
36
  import type { CodecError } from './errors.js';
30
37
  import type { SliceProjection } from './projection.js';
38
+ import { type TaglessSliceInLedger } from './readLedger.js';
31
39
  import type { Serializer } from './Serializer.js';
32
40
  /** The union of requirements `R` carried by a record of `SliceProjection`s. */
33
41
  export type RequirementOf<T extends Record<string, SliceProjection>> = T[keyof T] extends SliceProjection<infer _S, infer R> ? R : never;
@@ -55,6 +63,16 @@ export type RequirementOf<T extends Record<string, SliceProjection>> = T[keyof T
55
63
  * single fold cannot serve — across many identities, ordered, joined, paginated
56
64
  * — and never because it is fresher, because it is not.
57
65
  *
66
+ * ⚠ AND INSIDE A BRACKET IT IS NOT THE FLOOR THE APPEND WILL USE. Everything
67
+ * above is a statement about THIS read, and it stays true; what changes is that a
68
+ * bracket guards on the EARLIEST head across every hop it walked, which on any hop
69
+ * after the first is a strictly lower number than the one returned here. So a
70
+ * caller who reads `head` inside a bracket and reasons about what the append will
71
+ * refuse is reasoning from the wrong figure — the guard is wider than this head
72
+ * says. Nothing here is wrong; the trap is assuming the two are the same number,
73
+ * and it is named because it is exactly the assumption that holds outside a
74
+ * bracket and quietly stops holding inside one. `readLedger.ts` owns the floor.
75
+ *
58
76
  * `head` is LOG-GLOBAL: it is the head the store's `read` returned, so it moves
59
77
  * for an event no slice here selects. `test/decisionModel.test.ts` pins that
60
78
  * behaviour EXPLICITLY, over four appended events one of which the composed query
@@ -81,7 +99,7 @@ export type RequirementOf<T extends Record<string, SliceProjection>> = T[keyof T
81
99
  export declare const modelAtHead: <T extends Record<string, SliceProjection>>(projections: T) => Effect.Effect<{
82
100
  readonly state: CompositeState<T>;
83
101
  readonly head: Position;
84
- }, CodecError, DcbEventStore | Serializer | RequirementOf<T>>;
102
+ }, CodecError | TaglessSliceInLedger, DcbEventStore | Serializer | RequirementOf<T>>;
85
103
  /**
86
104
  * The write side's decision model: `modelAtHead` plus the `AppendCondition` that
87
105
  * reuses the read query as `failIfEventsMatch` and the read head as `after` (the
@@ -95,17 +113,19 @@ export declare const modelAtHead: <T extends Record<string, SliceProjection>>(pr
95
113
  * of a near-duplicate: `modelAtHead` is the shared part, this function is the
96
114
  * condition and nothing else, and each is shorter than the one function was.
97
115
  *
98
- * `composeProjections` therefore runs TWICE for one command — once inside
99
- * `modelAtHead` for the read, once here for `failIfEventsMatch` — and that is
100
- * deliberate rather than waste. It is a pure derivation of the record, so the two
101
- * queries cannot disagree however either call site changes. The alternative,
102
- * returning the query from `modelAtHead`, would put a third field on a READ-TIME
103
- * API that no read-time caller wants, to save one pure merge over a handful of
104
- * slices; a surface paying for a body's convenience is the worse trade.
116
+ * Outside a bracket `composeProjections` therefore runs twice for one command —
117
+ * once inside `modelAtHead` for the read, once here for `failIfEventsMatch` — and
118
+ * that is deliberate rather than waste. It is a pure derivation of the record, so
119
+ * the two queries cannot disagree however either call site changes. The
120
+ * alternative, returning the query from `modelAtHead`, would put a third field on
121
+ * a READ-TIME API that no read-time caller wants, to save one pure merge over a
122
+ * handful of slices; a surface paying for a body's convenience is the worse
123
+ * trade. Inside a bracket the second merge is not reached at all: the ledger's
124
+ * own derivation composes every recorded hop instead.
105
125
  *
106
126
  * ## How to attribute the read, the decode and the fold — the rule, stated once
107
127
  *
108
- * Because this function is `Effect.map` over `modelAtHead`, prose about the codec
128
+ * Because this function is expressed OVER `modelAtHead`, prose about the codec
109
129
  * splits into two kinds and only one of them may name this symbol:
110
130
  *
111
131
  * - Naming this function as the ENTRY POINT a caller invokes, or as the path
@@ -125,5 +145,5 @@ export declare const modelAtHead: <T extends Record<string, SliceProjection>>(pr
125
145
  export declare const buildDecisionModel: <T extends Record<string, SliceProjection>>(projections: T) => Effect.Effect<{
126
146
  readonly state: CompositeState<T>;
127
147
  readonly appendCondition: AppendCondition;
128
- }, CodecError, DcbEventStore | Serializer | RequirementOf<T>>;
148
+ }, CodecError | TaglessSliceInLedger, DcbEventStore | Serializer | RequirementOf<T>>;
129
149
  //# sourceMappingURL=decisionModel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decisionModel.d.ts","sourceRoot":"","sources":["../../src/decisionModel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,aAAa,EACb,KAAK,QAAQ,EACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,+EAA+E;AAC/E,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,IACjE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,eAAe,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACnE,aAAa,CAAC,KACb,MAAM,CAAC,MAAM,CACd;IAAE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,EAC9D,UAAU,EACV,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAyB3C,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAC1E,aAAa,CAAC,KACb,MAAM,CAAC,MAAM,CACd;IACE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAA;CAC1C,EACD,UAAU,EACV,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAU1C,CAAA"}
1
+ {"version":3,"file":"decisionModel.d.ts","sourceRoot":"","sources":["../../src/decisionModel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,aAAa,EACb,KAAK,QAAQ,EACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,MAAM,EAAkB,MAAM,QAAQ,CAAA;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,+EAA+E;AAC/E,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,IACjE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,eAAe,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACnE,aAAa,CAAC,KACb,MAAM,CAAC,MAAM,CACd;IAAE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,EAC9D,UAAU,GAAG,oBAAoB,EACjC,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CA6C3C,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAC1E,aAAa,CAAC,KACb,MAAM,CAAC,MAAM,CACd;IACE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAA;CAC1C,EACD,UAAU,GAAG,oBAAoB,EACjC,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CA6B3C,CAAA"}
@@ -34,6 +34,55 @@
34
34
  * error union are written once, in the two function bodies, rather than restated
35
35
  * as an annotation above them.
36
36
  *
37
+ * `transact(precondition)(body)` is the layered write path, for a decision whose
38
+ * second query cannot be written until an earlier read has been folded. It opens
39
+ * an ambient read ledger, evaluates the precondition inside it, hands that
40
+ * precondition's output to the body as a service, and appends what the body
41
+ * returned under the union of every query either of them read, at the earliest
42
+ * head observed. No condition reaches the caller. `unsafeAppend(events, reason)`
43
+ * is the one sanctioned way out. `precondition.ts` owns the argument for the
44
+ * bracket and everything on it, and `readLedger.ts` for the ledger the seam rests
45
+ * on — including why the derivation itself is deliberately not on this surface.
46
+ *
47
+ * ## ⚠ `runDecider` and `decideOnly` are TWO DISPOSITIONS OF ONE CYCLE
48
+ *
49
+ * They are read as a pair or not at all, because each refuses exactly where the
50
+ * other is the answer:
51
+ *
52
+ * | | outside a bracket | inside a bracket |
53
+ * | ------------ | ---------------------------------------- | ----------------------------------- |
54
+ * | `runDecider` | ✅ the ordinary single-hop case | ⛔ a DEFECT, refused at the store |
55
+ * | `decideOnly` | ⛔ unrunnable, and `tsc` says so | ✅ the layered case |
56
+ *
57
+ * ⚠ *Unrunnable* rather than *unwritable*, and the difference is measured. A bare
58
+ * `decideOnly(d, cmd)` outside a bracket COMPILES, and so does an exported helper
59
+ * over it: its `ReadLedger` requirement simply propagates, as any unmet requirement
60
+ * does. The refusal lands where the context is DISCHARGED — an `Effect.provide`, a
61
+ * `runPromise`, an annotation asking for `R = never` — which may be another file.
62
+ * So `pnpm check` catches it without anything running, which is the whole gain over
63
+ * the runtime defect this replaced; what it does not do is underline the call.
64
+ *
65
+ * Neither is expressed over the other, and that is forced rather than chosen: a
66
+ * definition of `runDecider` as *"`decideOnly`, then append"* would have to call
67
+ * `decideOnly` outside a bracket, which does not typecheck, and the append it then
68
+ * made inside one would be refused. The two refusals are the same fact seen from
69
+ * either side — an append inside a bracket belongs to the bracket — so any
70
+ * expression of one over the other has to defeat one of them.
71
+ *
72
+ * ⚠ The two refusals arrive at DIFFERENT MOMENTS, which is the part a caller acts
73
+ * on. `runDecider` inside a bracket is refused when it RUNS, at core's shared append
74
+ * decorator — so the same refusal also meets a raw `store.append` and a runner one
75
+ * call away in a helper. `decideOnly` outside a bracket is refused by `tsc`, at the
76
+ * discharge point above, by naming `ReadLedger` in its requirement channel. Why each
77
+ * was given the instrument it was is a DECISION and belongs to the record that took
78
+ * it: ADR-0014's `Status`. A lint rule reaches the first case earlier still, while it
79
+ * is being written; `biome-plugins/README.md` in the source repository owns what a
80
+ * rule there can and cannot see.
81
+ *
82
+ * The remedy is one identifier away in each direction, which is the whole reason a
83
+ * refusal is affordable at all. `decider.ts` and `precondition.ts` carry the two
84
+ * halves.
85
+ *
37
86
  * `modelAtHead(slices)` is that same read-decode-fold WITHOUT the
38
87
  * `AppendCondition`: `{ state, head }`, one slice record materialised at read
39
88
  * time with no table, no checkpoint and no runner, current as of the `head` its
@@ -55,7 +104,9 @@ export { buildDecisionModel, modelAtHead, type RequirementOf, } from './decision
55
104
  export { decodeSlices } from './decode.js';
56
105
  export { CodecError, UnknownEventType } from './errors.js';
57
106
  export { type EventDef, type EventDefAny, event, type TagsFor } from './event.js';
107
+ export { decideOnly, type Precondition, transact, unsafeAppend, } from './precondition.js';
58
108
  export { type ProjectionBuilder, projection, type SliceProjection, } from './projection.js';
109
+ export { type CloseHop, type Hop, NoReadsRecorded, ReadLedger, TaglessSliceInLedger, } from './readLedger.js';
59
110
  export { makeRegistry, type Registry } from './registry.js';
60
111
  export { Serializer, SerializerDefault } from './Serializer.js';
61
112
  export { toEvent } from './toEvent.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoGG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,EACL,UAAU,EACV,KAAK,YAAY,EACjB,QAAQ,EACR,YAAY,GACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,GAAG,EACR,eAAe,EACf,UAAU,EACV,oBAAoB,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA"}