doxum 0.1.7 → 0.1.9

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 (70) hide show
  1. package/README.md +217 -296
  2. package/dist/contract-BNStLbSE.d.ts +441 -0
  3. package/dist/contract-CIU5FCC1.d.cts +441 -0
  4. package/dist/driver-BlR81Dqg.js +200 -0
  5. package/dist/driver-BlR81Dqg.js.map +1 -0
  6. package/dist/driver-xOIkwrB8.cjs +241 -0
  7. package/dist/driver-xOIkwrB8.cjs.map +1 -0
  8. package/dist/index.cjs +666 -2222
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +10 -20
  11. package/dist/index.d.ts +10 -18
  12. package/dist/index.js +634 -2189
  13. package/dist/index.js.map +1 -1
  14. package/dist/{integration-CZwCwFBS.cjs → integration-C87tjRop.cjs} +4 -9
  15. package/dist/integration-C87tjRop.cjs.map +1 -0
  16. package/dist/{integration-B56u1l9V.js → integration-D5XCBLJ8.js} +2 -7
  17. package/dist/integration-D5XCBLJ8.js.map +1 -0
  18. package/dist/integration.cjs +11 -11
  19. package/dist/integration.d.cts +10 -4
  20. package/dist/integration.d.ts +10 -4
  21. package/dist/integration.js +4 -3
  22. package/dist/issue-DVaGQGeP.js +576 -0
  23. package/dist/issue-DVaGQGeP.js.map +1 -0
  24. package/dist/issue-DhrNdQNg.cjs +797 -0
  25. package/dist/issue-DhrNdQNg.cjs.map +1 -0
  26. package/dist/local-sync.cjs +67 -39
  27. package/dist/local-sync.cjs.map +1 -1
  28. package/dist/local-sync.d.cts +10 -10
  29. package/dist/local-sync.d.ts +10 -10
  30. package/dist/local-sync.js +66 -38
  31. package/dist/local-sync.js.map +1 -1
  32. package/dist/react.cjs +23 -4
  33. package/dist/react.cjs.map +1 -1
  34. package/dist/react.d.cts +8 -3
  35. package/dist/react.d.ts +8 -3
  36. package/dist/react.js +21 -6
  37. package/dist/react.js.map +1 -1
  38. package/dist/store-1Uob0Ghk.cjs +2750 -0
  39. package/dist/store-1Uob0Ghk.cjs.map +1 -0
  40. package/dist/store-CD0KdGsq.d.cts +262 -0
  41. package/dist/store-D7QH6Rzw.js +2511 -0
  42. package/dist/store-D7QH6Rzw.js.map +1 -0
  43. package/dist/store-cp5CpfCy.d.ts +262 -0
  44. package/package.json +1 -1
  45. package/skills/doxum-runtime/SKILL.md +26 -44
  46. package/skills/doxum-runtime/references/guide.en.md +95 -359
  47. package/skills/doxum-runtime/references/guide.zh-CN.md +80 -285
  48. package/skills/doxum-runtime/references/invariants.en.md +42 -165
  49. package/skills/doxum-runtime/references/invariants.zh-CN.md +34 -97
  50. package/skills/doxum-runtime/references/patterns.en.md +73 -225
  51. package/skills/doxum-runtime/references/patterns.zh-CN.md +73 -179
  52. package/dist/chunk-pbuEa-1d.js +0 -13
  53. package/dist/contract-DNZ4D53r.d.ts +0 -563
  54. package/dist/contract-j3SLGAwh.d.cts +0 -563
  55. package/dist/driver-CNxqMVFH.cjs +0 -69
  56. package/dist/driver-CNxqMVFH.cjs.map +0 -1
  57. package/dist/driver-CbzfW5MR.js +0 -46
  58. package/dist/driver-CbzfW5MR.js.map +0 -1
  59. package/dist/integration-B56u1l9V.js.map +0 -1
  60. package/dist/integration-CZwCwFBS.cjs.map +0 -1
  61. package/dist/ownership-CY0nPXGF.cjs +0 -304
  62. package/dist/ownership-CY0nPXGF.cjs.map +0 -1
  63. package/dist/ownership-CduRygE7.js +0 -245
  64. package/dist/ownership-CduRygE7.js.map +0 -1
  65. package/dist/runtime-0mOFbe_H.cjs +0 -2439
  66. package/dist/runtime-0mOFbe_H.cjs.map +0 -1
  67. package/dist/runtime-B22tuj9A.d.cts +0 -150
  68. package/dist/runtime-BFmhzPpZ.d.ts +0 -150
  69. package/dist/runtime-DF1q9Gje.js +0 -2129
  70. package/dist/runtime-DF1q9Gje.js.map +0 -1
@@ -0,0 +1,262 @@
1
+ import { B as CollectionPath, C as CollectionAccess, Q as ObjectNode, R as CollectionId, T as Read, _ as Unsubscribe, m as Synchronous, ot as ValueSchemaNode, r as DocumentCommit, rt as SchemaPath, s as DocumentReadable, tt as PathPick, v as Readable, x as CollectionImpact, z as CollectionNode } from "./contract-BNStLbSE.js";
2
+
3
+ //#region core/src/projection/contract.d.ts
4
+ declare const sourceContext: unique symbol;
5
+ type EngineSource<T> = {
6
+ readonly [sourceContext]: T;
7
+ };
8
+ type EngineSources = Readonly<Record<string, EngineSource<unknown>>>;
9
+ type EngineInputs<S extends EngineSources> = { readonly [K in keyof S]: S[K] extends EngineSource<infer T> ? T : never };
10
+ type DocumentInput<S extends ObjectNode> = {
11
+ readonly read: Read<S>;
12
+ readonly revision: number;
13
+ readonly commits: readonly DocumentCommit<S>[];
14
+ readonly reset: boolean;
15
+ };
16
+ type DocumentCollectionInput<S extends ObjectNode, N extends ValueSchemaNode, K extends string = string> = {
17
+ readonly read: CollectionAccess<K, N>;
18
+ readonly revision: number;
19
+ readonly commits: readonly DocumentCommit<S>[];
20
+ readonly reset: boolean;
21
+ readonly candidates: {
22
+ readonly keys: readonly K[];
23
+ readonly orderDirty: boolean;
24
+ };
25
+ };
26
+ type DocumentSource<S extends ObjectNode> = EngineSource<DocumentInput<S>> & {
27
+ collection<P extends CollectionPath>(pick: (path: SchemaPath<S['shape']>) => P): DocumentCollectionSource<S, CollectionNode<P>, CollectionId<P>>;
28
+ targets(...targets: readonly [PathPick<S>, ...PathPick<S>[]]): EngineSource<DocumentInput<S>>;
29
+ };
30
+ type DocumentCollectionSource<S extends ObjectNode, N extends ValueSchemaNode, K extends string = string> = EngineSource<DocumentCollectionInput<S, N, K>>;
31
+ type ValueInput<T> = {
32
+ readonly value: T;
33
+ readonly previous: T;
34
+ readonly changed: boolean;
35
+ readonly revision: number;
36
+ readonly reset: boolean;
37
+ };
38
+ type EngineInput<T> = {
39
+ readonly source: EngineSource<ValueInput<T>>;
40
+ set(value: T): void;
41
+ };
42
+ type ValueUpdate<T> = {
43
+ readonly kind: 'unchanged';
44
+ } | {
45
+ readonly kind: 'changed';
46
+ readonly value: T;
47
+ } | {
48
+ readonly kind: 'rebuild';
49
+ };
50
+ type EngineValueSpec<S extends EngineSources, T> = {
51
+ readonly name?: string;
52
+ readonly sources: S;
53
+ readonly build: (sources: EngineInputs<S>) => {
54
+ readonly value: T;
55
+ readonly update: (sources: EngineInputs<S>) => ValueUpdate<NoInfer<T>>;
56
+ };
57
+ };
58
+ type MaterializedValue<T> = Readable<T> & EngineSource<ValueInput<T>> & {
59
+ rebuild(): void;
60
+ dispose(): void;
61
+ };
62
+ type CollectionRead<K extends string, V> = {
63
+ get(key: K): V | undefined;
64
+ has(key: K): boolean;
65
+ ids(): readonly K[];
66
+ };
67
+ type CollectionInput<K extends string, V> = CollectionRead<K, V> & {
68
+ readonly change: CollectionImpact<K> | undefined;
69
+ readonly revision: number;
70
+ readonly reset: boolean;
71
+ };
72
+ type MaterializedCollection<K extends string, V> = EngineSource<CollectionInput<K, V>> & {
73
+ current(): CollectionRead<K, V>;
74
+ readonly ids: Readable<readonly K[]>;
75
+ readonly all: Readable<readonly V[]>;
76
+ item(key: K): Readable<V | undefined>;
77
+ revision(): number;
78
+ subscribe(listener: (change: CollectionImpact<K>) => void): Unsubscribe;
79
+ rebuild(): void;
80
+ dispose(): void;
81
+ };
82
+ type MaterializedCollectionWriter<K extends string, V> = {
83
+ set(key: K, value: V): void;
84
+ remove(key: K): void;
85
+ order(ids: readonly K[]): void;
86
+ replace(entries: readonly (readonly [K, V])[]): void;
87
+ };
88
+ type EngineCollectionProcess<S extends EngineSources, K extends string, V> = {
89
+ readonly sources: EngineInputs<S>;
90
+ readonly previous: CollectionRead<K, V>;
91
+ readonly next: CollectionRead<K, V>;
92
+ readonly writer: MaterializedCollectionWriter<K, V>;
93
+ };
94
+ type EngineCollectionSpec<S extends EngineSources, K extends string, V> = {
95
+ readonly name?: string;
96
+ readonly sources: S;
97
+ readonly isEqual?: (previous: V, next: V) => boolean;
98
+ readonly build: (input: EngineCollectionProcess<S, K, V>) => {
99
+ readonly update: (input: EngineCollectionProcess<S, K, V>) => void | {
100
+ readonly kind: 'rebuild';
101
+ };
102
+ };
103
+ };
104
+ declare class ProjectionError extends Error {
105
+ readonly phase: 'processor' | 'listener' | 'source' | 'blocked';
106
+ readonly identity: string;
107
+ readonly revisions: readonly number[];
108
+ constructor(phase: 'processor' | 'listener' | 'source' | 'blocked', identity: string, revisions: readonly number[], cause: unknown);
109
+ }
110
+ declare class ProjectionDisposedError extends Error {
111
+ constructor();
112
+ }
113
+ type ProjectionEngine = {
114
+ document<S extends ObjectNode>(runtime: DocumentReadable<S>): DocumentSource<S>;
115
+ fromReadable<T>(readable: Readable<T>, options?: {
116
+ readonly isEqual?: (a: T, b: T) => boolean;
117
+ }): EngineSource<ValueInput<T>>;
118
+ input<T>(initial: T, options?: {
119
+ readonly isEqual?: (a: T, b: T) => boolean;
120
+ }): EngineInput<T>;
121
+ value<S extends EngineSources, T>(sources: S, compute: (sources: EngineInputs<S>) => Synchronous<T>, options?: {
122
+ readonly isEqual?: (a: NoInfer<T>, b: NoInfer<T>) => boolean;
123
+ }): MaterializedValue<T>;
124
+ value<S extends EngineSources, T>(spec: EngineValueSpec<S, T>, options?: {
125
+ readonly isEqual?: (a: NoInfer<T>, b: NoInfer<T>) => boolean;
126
+ }): MaterializedValue<T>;
127
+ collection<V, K extends string = string>(): <S extends EngineSources>(spec: EngineCollectionSpec<S, K, V>) => MaterializedCollection<K, V>;
128
+ map<S extends ObjectNode, N extends ValueSchemaNode, K extends string, V>(source: DocumentCollectionSource<S, N, K>, mapper: (id: K, entry: Read<N>) => Synchronous<V>, options?: {
129
+ readonly isEqual?: (a: V, b: V) => boolean;
130
+ }): MaterializedCollection<K, V>;
131
+ map<K extends string, V, R>(source: MaterializedCollection<K, V>, mapper: (id: K, entry: V) => Synchronous<R>, options?: {
132
+ readonly isEqual?: (a: NoInfer<R>, b: NoInfer<R>) => boolean;
133
+ }): MaterializedCollection<K, R>;
134
+ batch<T>(run: () => Synchronous<T>): T;
135
+ dispose(): void;
136
+ };
137
+ //#endregion
138
+ //#region core/src/projection/definition.d.ts
139
+ declare const projectionDefinition: unique symbol;
140
+ declare const writableInput: unique symbol;
141
+ type Projection<T, E = T, K extends 'source' | 'value' | 'collection' = 'source' | 'value' | 'collection'> = {
142
+ readonly [projectionDefinition]: {
143
+ readonly value: T;
144
+ readonly event: E;
145
+ readonly kind: K;
146
+ };
147
+ };
148
+ type ProjectionSources = Readonly<Record<string, Projection<unknown, unknown, 'source' | 'value' | 'collection'>>>;
149
+ type ProjectionValues<S extends ProjectionSources> = { readonly [K in keyof S]: S[K] extends Projection<infer T, unknown, 'source' | 'value' | 'collection'> ? T : never };
150
+ type ProjectionEvents<S extends ProjectionSources> = { readonly [K in keyof S]: S[K] extends Projection<unknown, infer E, 'source' | 'value' | 'collection'> ? E : never };
151
+ type ValueProjection<T, E = ValueEvent<T>> = Projection<T, E, 'value'>;
152
+ type InputProjection<T> = ValueProjection<T> & {
153
+ readonly [writableInput]: true;
154
+ };
155
+ type CollectionProjection<K extends string, V, E = CollectionEvent<K, V>> = Projection<CollectionRead<K, V>, E, 'collection'>;
156
+ type CollectionSource<K extends string, V, E> = Projection<CollectionRead<K, V>, E, 'source'>;
157
+ type DocumentProjection<S extends ObjectNode> = Projection<Read<S>, DocumentEvent<S>, 'source'>;
158
+ type DocumentCollectionProjection<S extends ObjectNode, N extends ValueSchemaNode, K extends string = string> = CollectionSource<K, Read<N>, DocumentCollectionEvent<S, N, K>>;
159
+ type ValueEvent<T> = {
160
+ readonly value: T;
161
+ readonly previous: T;
162
+ readonly changed: boolean;
163
+ readonly revision: number;
164
+ readonly reset: boolean;
165
+ };
166
+ type DocumentEvent<S extends ObjectNode> = {
167
+ readonly read: Read<S>;
168
+ readonly revision: number;
169
+ readonly commits: readonly DocumentCommit<S>[];
170
+ readonly reset: boolean;
171
+ };
172
+ type DocumentCollectionEvent<S extends ObjectNode, N extends ValueSchemaNode, K extends string = string> = {
173
+ readonly read: CollectionAccess<K, N>;
174
+ readonly revision: number;
175
+ readonly commits: readonly DocumentCommit<S>[];
176
+ readonly reset: boolean;
177
+ readonly candidates: {
178
+ readonly keys: readonly K[];
179
+ readonly orderDirty: boolean;
180
+ };
181
+ };
182
+ type CollectionEvent<K extends string, V> = CollectionRead<K, V> & {
183
+ readonly change: CollectionImpact<K> | undefined;
184
+ readonly revision: number;
185
+ readonly reset: boolean;
186
+ };
187
+ declare const input: <T>(initial: T, options?: {
188
+ readonly isEqual?: (a: T, b: T) => boolean;
189
+ }) => InputProjection<T>;
190
+ type AdvancedValueSpec<S extends ProjectionSources, T> = {
191
+ readonly kind: 'value';
192
+ readonly name?: string;
193
+ readonly sources: S;
194
+ readonly build: (sources: ProjectionEvents<S>) => {
195
+ readonly value: T;
196
+ readonly update: (sources: ProjectionEvents<S>) => ValueUpdate<NoInfer<T>>;
197
+ };
198
+ readonly isEqual?: (previous: T, next: T) => boolean;
199
+ };
200
+ type AdvancedCollectionSpec<S extends ProjectionSources, K extends string, V> = {
201
+ readonly kind: 'collection';
202
+ readonly name?: string;
203
+ readonly sources: S;
204
+ readonly build: (input: AdvancedCollectionProcess<S, K, V>) => {
205
+ readonly update: (input: AdvancedCollectionProcess<S, K, V>) => void | {
206
+ readonly kind: 'rebuild';
207
+ };
208
+ };
209
+ readonly isEqual?: (previous: V, next: V) => boolean;
210
+ };
211
+ type AdvancedCollectionProcess<S extends ProjectionSources, K extends string, V> = {
212
+ readonly sources: ProjectionEvents<S>;
213
+ readonly previous: CollectionRead<K, V>;
214
+ readonly next: CollectionRead<K, V>;
215
+ readonly writer: MaterializedCollectionWriter<K, V>;
216
+ };
217
+ declare function project<T>(readable: Readable<T>): ValueProjection<T>;
218
+ declare function project<S extends ObjectNode>(document: DocumentReadable<S>): DocumentProjection<S>;
219
+ declare function project<S extends ObjectNode>(document: DocumentReadable<S>, targets: readonly [PathPick<S>, ...PathPick<S>[]]): DocumentProjection<S>;
220
+ declare function project<S extends ObjectNode, P extends CollectionPath>(document: DocumentReadable<S>, pick: (path: SchemaPath<S['shape']>) => P): DocumentCollectionProjection<S, CollectionNode<P>, CollectionId<P>>;
221
+ declare function project<S extends ObjectNode, P extends CollectionPath, V>(document: DocumentReadable<S>, pick: (path: SchemaPath<S['shape']>) => P, mapper: (id: CollectionId<P>, entry: Read<CollectionNode<P>>) => Synchronous<V>, options?: {
222
+ readonly isEqual?: (a: V, b: V) => boolean;
223
+ }): CollectionProjection<CollectionId<P>, V>;
224
+ declare function project<K extends string, V, E, R>(source: Projection<CollectionRead<K, V>, E, 'source' | 'collection'>, mapper: (id: K, entry: V) => Synchronous<R>, options?: {
225
+ readonly isEqual?: (a: R, b: R) => boolean;
226
+ }): CollectionProjection<K, R>;
227
+ declare function project<S extends ProjectionSources, T>(sources: S, compute: (sources: ProjectionValues<S>) => Synchronous<T>, options?: {
228
+ readonly isEqual?: (a: T, b: T) => boolean;
229
+ }): ValueProjection<T>;
230
+ declare function project<S extends ProjectionSources, T>(spec: AdvancedValueSpec<S, T>): ValueProjection<T>;
231
+ declare function project<V, K extends string = string, S extends ProjectionSources = ProjectionSources>(spec: AdvancedCollectionSpec<S, K, V>): CollectionProjection<K, V>;
232
+ //#endregion
233
+ //#region core/src/projection/runtime.d.ts
234
+ declare const createProjectionEngine: (options: {
235
+ readonly onError: (error: ProjectionError) => void;
236
+ }) => ProjectionEngine;
237
+ //#endregion
238
+ //#region core/src/projection/store.d.ts
239
+ type ProjectionStore = {
240
+ get<K extends string, V>(projection: CollectionProjection<K, V>): CollectionRead<K, V>;
241
+ get<T>(projection: ValueProjection<T>): T;
242
+ set<T>(projection: InputProjection<T>, value: T): void;
243
+ subscribe<K extends string, V>(projection: CollectionProjection<K, V>, listener: (change: CollectionImpact<K>) => void): Unsubscribe;
244
+ subscribe<T>(projection: ValueProjection<T>, listener: () => void): Unsubscribe;
245
+ revision(projection: ValueProjection<unknown> | CollectionProjection<string, unknown>): number;
246
+ rebuild(projection: ValueProjection<unknown> | CollectionProjection<string, unknown>): void;
247
+ release(projection: ValueProjection<unknown> | CollectionProjection<string, unknown>): void;
248
+ batch<T>(run: () => T): T;
249
+ dispose(): void;
250
+ };
251
+ declare const projectionStoreDebug: (store: ProjectionStore) => Readonly<{
252
+ nodes: number;
253
+ sources: number;
254
+ subscriptions: number;
255
+ pending: number;
256
+ }>;
257
+ declare const createProjectionStore: (options: {
258
+ readonly onError: Parameters<typeof createProjectionEngine>[0]["onError"];
259
+ }) => ProjectionStore;
260
+ //#endregion
261
+ export { ProjectionDisposedError as C, project as S, ProjectionSources as _, AdvancedCollectionSpec as a, ValueProjection as b, CollectionProjection as c, DocumentCollectionProjection as d, DocumentEvent as f, ProjectionEvents as g, Projection as h, AdvancedCollectionProcess as i, CollectionSource as l, InputProjection as m, createProjectionStore as n, AdvancedValueSpec as o, DocumentProjection as p, projectionStoreDebug as r, CollectionEvent as s, ProjectionStore as t, DocumentCollectionEvent as u, ProjectionValues as v, ProjectionError as w, input as x, ValueEvent as y };
262
+ //# sourceMappingURL=store-cp5CpfCy.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doxum",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "Doxum is a typed runtime for complex mutable documents.",
@@ -1,52 +1,34 @@
1
1
  ---
2
2
  name: doxum-runtime
3
- description: 'Use doxum and doxum/react to design, build, or review Doxum document runtime code. Apply for schemas, mutations, operations, views, subscriptions, and React integration.'
3
+ description: 'Use doxum and doxum/react for schemas, scoped draft updates, ChangeSets, history, projections, subscriptions and React integration.'
4
4
  ---
5
5
 
6
6
  # Doxum Runtime
7
7
 
8
- Use this skill when a task creates, modifies, reviews, or explains Doxum code.
9
- It applies to `doxum`, `doxum/react`, and application code that uses
10
- Doxum's schema, runtime, transaction, operation, impact, projection, or React
11
- APIs. Do not apply it to unrelated TypeScript or React work merely because the
12
- application happens to contain a Doxum runtime.
8
+ Read the [English guide](references/guide.en.md) or [中文指南](references/guide.zh-CN.md).
9
+ For examples read [patterns](references/patterns.en.md) or [中文模式](references/patterns.zh-CN.md).
10
+ Before runtime changes read [invariants](references/invariants.en.md) or
11
+ [中文不变量](references/invariants.zh-CN.md).
13
12
 
14
- ## Read the right reference
13
+ - Root object defines schema identity; Infer describes readonly data with shared immutable payloads.
14
+ - createDocument owns canonical state. update, apply and replace share one session.
15
+ - Draft and trusted internal readWith scopes are borrowed for synchronous callbacks;
16
+ their proxies must not escape. Public values should use snapshot when they need to
17
+ outlive the callback.
18
+ - Atomic fields are deeply readonly during access and replaced whole.
19
+ - Use assign(scope, key, value) for replacements containing nested collection tools.
20
+ - Expected business failure throws TransactionRejected. Other exceptions roll back
21
+ and rethrow unchanged. Callback returns carry business values and notices.
22
+ - Commits contain final reversible ChangeSets. History and impact share those facts.
23
+ - ChangeSets group member transitions by container, with explicit added/removed/updated
24
+ kinds, optional before/after order in the same group, and a separate root reset.
25
+ Standalone order records and duplicate groups are invalid. Grouping preserves field-level impact.
26
+ - Paths belong in subscription, impact and collection source callbacks.
27
+ - Projection dependencies are explicit; React selectors track actual reads.
28
+ - Observer errors leave commits accepted. Do not retry as if they rolled back.
29
+ - Core stays framework-neutral; adapters use integration capabilities.
30
+ - Local sync owns browser persistence/leadership. Network conflict policy and
31
+ collaborative undo belong at a separate boundary.
15
32
 
16
- - Start with [the English guide](references/guide.en.md) for English requests
17
- or [中文指南](references/guide.zh-CN.md) for Chinese requests. They are
18
- equivalent task-oriented introductions.
19
- - Read [the English patterns](references/patterns.en.md) or
20
- [中文模式参考](references/patterns.zh-CN.md) when implementing schema models,
21
- transactions, replay, selectors, views, or React code.
22
- - Read [the English invariants](references/invariants.en.md) or
23
- [中文不变量](references/invariants.zh-CN.md) before changing mutation,
24
- addressing, impact, notification, history, tree, or derived-view behavior.
25
-
26
- ## Required Doxum decisions
27
-
28
- - Treat `createDocument` as the only write authority for canonical document
29
- state. Application writes use `runtime.update`; replayed external operations
30
- use `runtime.apply`.
31
- - A transaction is synchronous and atomic. Do not retain a transaction reader
32
- or writer after its callback returns, and do not introduce another writable
33
- state cache.
34
- - Use the runtime's schema selectors, anchors, addresses, and `target` APIs.
35
- Do not add local path parsers, duplicate impact-target helpers, or manually
36
- synchronize derived data.
37
- - Handle expected mutation failure from the returned `rejected` result and its
38
- `MutationIssue` values. Use `tx.report` or `tx.reject` with
39
- `{ code, message, address? }` for application validation; runtime adds the
40
- application source to published `DocumentDiagnostic` values. A thrown callback error
41
- rolls back and is rethrown.
42
- - A committed result with `observerErrors` is still committed. Do not retry its
43
- write as if canonical state had been rolled back.
44
- - Keep `core` framework-neutral. React code belongs behind `doxum/react` and
45
- must not make `core` import UI concepts.
46
- - Doxum does not define persistence, synchronization, authorization, or
47
- conflict resolution. Keep those policies in the application boundary before
48
- `apply` or `replace`.
49
-
50
- When public behavior or lifecycle semantics change, update the README and
51
- architecture guide and add focused tests for rollback, inverse history, impact
52
- or subscription behavior, and performance-sensitive collection or tree paths.
33
+ Update examples and tests when behavior changes. Never add compatibility APIs,
34
+ a second path grammar or another writable derived cache.