@manifesto-ai/core 1.0.0 → 1.3.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 (104) hide show
  1. package/README.md +33 -13
  2. package/dist/__tests__/apply.test.d.ts +2 -0
  3. package/dist/__tests__/apply.test.d.ts.map +1 -0
  4. package/dist/__tests__/apply.test.js +144 -0
  5. package/dist/__tests__/apply.test.js.map +1 -0
  6. package/dist/__tests__/jcs.test.d.ts +2 -0
  7. package/dist/__tests__/jcs.test.d.ts.map +1 -0
  8. package/dist/__tests__/jcs.test.js +45 -0
  9. package/dist/__tests__/jcs.test.js.map +1 -0
  10. package/dist/core/apply.d.ts +2 -1
  11. package/dist/core/apply.d.ts.map +1 -1
  12. package/dist/core/apply.js +92 -14
  13. package/dist/core/apply.js.map +1 -1
  14. package/dist/core/compute.d.ts.map +1 -1
  15. package/dist/core/compute.js +95 -5
  16. package/dist/core/compute.js.map +1 -1
  17. package/dist/core/compute.test.js +291 -58
  18. package/dist/core/compute.test.js.map +1 -1
  19. package/dist/core/explain.d.ts.map +1 -1
  20. package/dist/core/explain.js +14 -10
  21. package/dist/core/explain.js.map +1 -1
  22. package/dist/core/validate.d.ts +2 -1
  23. package/dist/core/validate.d.ts.map +1 -1
  24. package/dist/core/validate.js +219 -1
  25. package/dist/core/validate.js.map +1 -1
  26. package/dist/core/validate.test.js +196 -8
  27. package/dist/core/validate.test.js.map +1 -1
  28. package/dist/core/validation-utils.d.ts +20 -0
  29. package/dist/core/validation-utils.d.ts.map +1 -0
  30. package/dist/core/validation-utils.js +289 -0
  31. package/dist/core/validation-utils.js.map +1 -0
  32. package/dist/errors.d.ts +1 -1
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +2 -2
  35. package/dist/errors.js.map +1 -1
  36. package/dist/evaluator/computed.d.ts.map +1 -1
  37. package/dist/evaluator/computed.js +7 -4
  38. package/dist/evaluator/computed.js.map +1 -1
  39. package/dist/evaluator/context.d.ts +14 -1
  40. package/dist/evaluator/context.d.ts.map +1 -1
  41. package/dist/evaluator/context.js +7 -1
  42. package/dist/evaluator/context.js.map +1 -1
  43. package/dist/evaluator/expr.d.ts.map +1 -1
  44. package/dist/evaluator/expr.js +155 -4
  45. package/dist/evaluator/expr.js.map +1 -1
  46. package/dist/evaluator/expr.test.js +27 -4
  47. package/dist/evaluator/expr.test.js.map +1 -1
  48. package/dist/evaluator/flow.d.ts.map +1 -1
  49. package/dist/evaluator/flow.js +175 -22
  50. package/dist/evaluator/flow.js.map +1 -1
  51. package/dist/evaluator/flow.test.js +59 -6
  52. package/dist/evaluator/flow.test.js.map +1 -1
  53. package/dist/factories.d.ts +4 -2
  54. package/dist/factories.d.ts.map +1 -1
  55. package/dist/factories.js +20 -19
  56. package/dist/factories.js.map +1 -1
  57. package/dist/index.d.ts +3 -2
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/schema/domain.d.ts +4 -0
  61. package/dist/schema/domain.d.ts.map +1 -1
  62. package/dist/schema/domain.js +6 -0
  63. package/dist/schema/domain.js.map +1 -1
  64. package/dist/schema/expr.d.ts +44 -1
  65. package/dist/schema/expr.d.ts.map +1 -1
  66. package/dist/schema/expr.js +40 -4
  67. package/dist/schema/expr.js.map +1 -1
  68. package/dist/schema/host-context.d.ts +12 -0
  69. package/dist/schema/host-context.d.ts.map +1 -0
  70. package/dist/schema/host-context.js +23 -0
  71. package/dist/schema/host-context.js.map +1 -0
  72. package/dist/schema/index.d.ts +2 -0
  73. package/dist/schema/index.d.ts.map +1 -1
  74. package/dist/schema/index.js +3 -0
  75. package/dist/schema/index.js.map +1 -1
  76. package/dist/schema/result.d.ts +12 -0
  77. package/dist/schema/result.d.ts.map +1 -1
  78. package/dist/schema/result.js +5 -1
  79. package/dist/schema/result.js.map +1 -1
  80. package/dist/schema/snapshot.d.ts +2 -0
  81. package/dist/schema/snapshot.d.ts.map +1 -1
  82. package/dist/schema/snapshot.js +4 -0
  83. package/dist/schema/snapshot.js.map +1 -1
  84. package/dist/schema/trace.d.ts +12 -1
  85. package/dist/schema/trace.d.ts.map +1 -1
  86. package/dist/schema/trace.js +14 -3
  87. package/dist/schema/trace.js.map +1 -1
  88. package/dist/schema/type-spec.d.ts +34 -0
  89. package/dist/schema/type-spec.d.ts.map +1 -0
  90. package/dist/schema/type-spec.js +40 -0
  91. package/dist/schema/type-spec.js.map +1 -0
  92. package/dist/utils/canonical.d.ts +8 -0
  93. package/dist/utils/canonical.d.ts.map +1 -1
  94. package/dist/utils/canonical.js +66 -0
  95. package/dist/utils/canonical.js.map +1 -1
  96. package/dist/utils/canonical.test.js +31 -1
  97. package/dist/utils/canonical.test.js.map +1 -1
  98. package/dist/utils/hash.d.ts +9 -1
  99. package/dist/utils/hash.d.ts.map +1 -1
  100. package/dist/utils/hash.js +116 -2
  101. package/dist/utils/hash.js.map +1 -1
  102. package/dist/utils/hash.test.js +44 -20
  103. package/dist/utils/hash.test.js.map +1 -1
  104. package/package.json +7 -6
package/README.md CHANGED
@@ -63,32 +63,52 @@ const core = createCore();
63
63
 
64
64
  // Define a simple schema (usually from @manifesto-ai/builder)
65
65
  const schema: DomainSchema = {
66
+ id: "example:counter",
66
67
  version: "1.0.0",
68
+ hash: "example-hash",
69
+ types: {},
67
70
  state: {
68
- count: { type: "number", default: 0 },
71
+ fields: {
72
+ count: { type: "number", required: true, default: 0 },
73
+ },
74
+ },
75
+ computed: {
76
+ fields: {
77
+ "computed.count": {
78
+ deps: ["count"],
79
+ expr: { kind: "get", path: "count" },
80
+ },
81
+ },
69
82
  },
70
83
  actions: {
71
84
  increment: {
72
85
  flow: {
73
86
  kind: "patch",
74
87
  op: "set",
75
- path: "/data/count",
76
- value: { kind: "add", left: { kind: "get", path: "/data/count" }, right: 1 },
88
+ path: "count",
89
+ value: {
90
+ kind: "add",
91
+ left: { kind: "get", path: "count" },
92
+ right: { kind: "lit", value: 1 },
93
+ },
77
94
  },
78
95
  },
79
96
  },
80
97
  };
81
98
 
99
+ // Create host context (deterministic inputs)
100
+ const context = { now: 0, randomSeed: "seed" };
101
+
82
102
  // Create initial snapshot
83
- const snapshot = createSnapshot(schema);
103
+ const snapshot = createSnapshot({ count: 0 }, schema.hash, context);
84
104
 
85
105
  // Create intent
86
- const intent = createIntent("increment");
106
+ const intent = createIntent("increment", "intent-1");
87
107
 
88
108
  // Compute result (pure, deterministic)
89
- const result = await core.compute(schema, snapshot, intent);
109
+ const result = await core.compute(schema, snapshot, intent, context);
90
110
 
91
- console.log(result.status); // → "completed"
111
+ console.log(result.status); // → "complete"
92
112
  console.log(result.snapshot.data.count); // → 1
93
113
  ```
94
114
 
@@ -106,18 +126,18 @@ function createCore(): ManifestoCore;
106
126
 
107
127
  // Core interface
108
128
  interface ManifestoCore {
109
- compute(schema, snapshot, intent): Promise<ComputeResult>;
110
- apply(schema, snapshot, patches): Snapshot;
129
+ compute(schema, snapshot, intent, context): Promise<ComputeResult>;
130
+ apply(schema, snapshot, patches, context): Snapshot;
111
131
  validate(schema): ValidationResult;
112
132
  explain(schema, snapshot, path): ExplainResult;
113
133
  }
114
134
 
115
135
  // Key types
116
- type DomainSchema = { version, state, computed?, actions?, flows?, meta? };
136
+ type DomainSchema = { id, version, hash, types, state, computed, actions, meta? };
117
137
  type Snapshot = { data, computed, system, input, meta };
118
138
  type Intent = { type, input?, intentId };
119
139
  type Patch = { op: "set" | "unset" | "merge", path, value? };
120
- type ComputeResult = { status, snapshot, patches, requirements, trace };
140
+ type ComputeResult = { status, snapshot, requirements, trace };
121
141
  ```
122
142
 
123
143
  > See [SPEC.md](../../docs/packages/core/SPEC.md) for complete API reference.
@@ -186,8 +206,8 @@ For typical usage, see [`@manifesto-ai/react`](../react/) or [`@manifesto-ai/hos
186
206
  | Document | Purpose |
187
207
  |----------|---------|
188
208
  | [GUIDE.md](../../docs/packages/core/GUIDE.md) | Step-by-step usage guide |
189
- | [SPEC.md](../../docs/packages/core/SPEC.md) | Complete specification |
190
- | [FDR.md](../../docs/packages/core/FDR.md) | Design rationale |
209
+ | [SPEC.md](docs/SPEC.md) | Complete specification |
210
+ | [FDR.md](docs/FDR.md) | Design rationale |
191
211
 
192
212
  ---
193
213
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=apply.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/apply.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,144 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { apply } from "../core/apply.js";
3
+ import { createSnapshot } from "../factories.js";
4
+ const HOST_CONTEXT = { now: 0, randomSeed: "seed" };
5
+ describe("apply", () => {
6
+ it("should surface computed evaluation errors as values", () => {
7
+ const schema = {
8
+ id: "manifesto:test",
9
+ version: "1.0.0",
10
+ hash: "test-hash",
11
+ types: {},
12
+ state: {
13
+ fields: {
14
+ dummy: { type: "string", required: true },
15
+ },
16
+ },
17
+ computed: {
18
+ fields: {
19
+ "computed.a": {
20
+ expr: { kind: "get", path: "computed.b" },
21
+ deps: ["computed.b"],
22
+ },
23
+ "computed.b": {
24
+ expr: { kind: "get", path: "computed.a" },
25
+ deps: ["computed.a"],
26
+ },
27
+ },
28
+ },
29
+ actions: {
30
+ noop: { flow: { kind: "halt", reason: "noop" } },
31
+ },
32
+ };
33
+ const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
34
+ const result = apply(schema, snapshot, [{ op: "set", path: "dummy", value: "updated" }], HOST_CONTEXT);
35
+ expect(result.data).toEqual({ dummy: "updated" });
36
+ expect(result.system.status).toBe("error");
37
+ expect(result.system.lastError?.code).toBe("CYCLIC_DEPENDENCY");
38
+ expect(result.computed).toEqual({});
39
+ });
40
+ it("should record errors for unknown patch paths", () => {
41
+ const schema = {
42
+ id: "manifesto:test",
43
+ version: "1.0.0",
44
+ hash: "test-hash",
45
+ types: {},
46
+ state: {
47
+ fields: {
48
+ dummy: { type: "string", required: true },
49
+ },
50
+ },
51
+ computed: { fields: {} },
52
+ actions: {
53
+ noop: { flow: { kind: "halt", reason: "noop" } },
54
+ },
55
+ };
56
+ const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
57
+ const result = apply(schema, snapshot, [{ op: "set", path: "missing", value: "value" }], HOST_CONTEXT);
58
+ expect(result.data).toEqual({ dummy: "initial" });
59
+ expect(result.system.status).toBe("error");
60
+ expect(result.system.lastError?.code).toBe("PATH_NOT_FOUND");
61
+ });
62
+ it("should record errors for invalid patch value types", () => {
63
+ const schema = {
64
+ id: "manifesto:test",
65
+ version: "1.0.0",
66
+ hash: "test-hash",
67
+ types: {},
68
+ state: {
69
+ fields: {
70
+ dummy: { type: "string", required: true },
71
+ },
72
+ },
73
+ computed: { fields: {} },
74
+ actions: {
75
+ noop: { flow: { kind: "halt", reason: "noop" } },
76
+ },
77
+ };
78
+ const snapshot = createSnapshot({ dummy: "initial" }, schema.hash, HOST_CONTEXT);
79
+ const result = apply(schema, snapshot, [{ op: "set", path: "dummy", value: 42 }], HOST_CONTEXT);
80
+ expect(result.data).toEqual({ dummy: "initial" });
81
+ expect(result.system.status).toBe("error");
82
+ expect(result.system.lastError?.code).toBe("TYPE_MISMATCH");
83
+ });
84
+ it("should ignore patches to computed and meta", () => {
85
+ const schema = {
86
+ id: "manifesto:test",
87
+ version: "1.0.0",
88
+ hash: "test-hash",
89
+ types: {},
90
+ state: {
91
+ fields: {
92
+ count: { type: "number", required: true },
93
+ },
94
+ },
95
+ computed: {
96
+ fields: {
97
+ "computed.double": {
98
+ expr: {
99
+ kind: "mul",
100
+ left: { kind: "get", path: "count" },
101
+ right: { kind: "lit", value: 2 },
102
+ },
103
+ deps: ["count"],
104
+ },
105
+ },
106
+ },
107
+ actions: {
108
+ noop: { flow: { kind: "halt", reason: "noop" } },
109
+ },
110
+ };
111
+ const snapshot = createSnapshot({ count: 2 }, schema.hash, HOST_CONTEXT);
112
+ const result = apply(schema, snapshot, [
113
+ { op: "set", path: "computed.double", value: 999 },
114
+ { op: "set", path: "meta.version", value: 999 },
115
+ { op: "set", path: "count", value: 3 },
116
+ ], HOST_CONTEXT);
117
+ expect(result.data).toEqual({ count: 3 });
118
+ expect(result.computed["computed.double"]).toBe(6);
119
+ expect(result.meta.version).toBe(snapshot.meta.version + 1);
120
+ });
121
+ it("should record errors for merge patches on non-object fields", () => {
122
+ const schema = {
123
+ id: "manifesto:test",
124
+ version: "1.0.0",
125
+ hash: "test-hash",
126
+ types: {},
127
+ state: {
128
+ fields: {
129
+ name: { type: "string", required: true },
130
+ },
131
+ },
132
+ computed: { fields: {} },
133
+ actions: {
134
+ noop: { flow: { kind: "halt", reason: "noop" } },
135
+ },
136
+ };
137
+ const snapshot = createSnapshot({ name: "initial" }, schema.hash, HOST_CONTEXT);
138
+ const result = apply(schema, snapshot, [{ op: "merge", path: "name", value: { extra: "value" } }], HOST_CONTEXT);
139
+ expect(result.data).toEqual({ name: "initial" });
140
+ expect(result.system.status).toBe("error");
141
+ expect(result.system.lastError?.code).toBe("TYPE_MISMATCH");
142
+ });
143
+ });
144
+ //# sourceMappingURL=apply.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.test.js","sourceRoot":"","sources":["../../src/__tests__/apply.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jcs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jcs.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/jcs.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { toJcs } from "../utils/canonical.js";
3
+ describe("toJcs", () => {
4
+ it("should serialize -0 as 0", () => {
5
+ expect(toJcs(-0)).toBe("0");
6
+ });
7
+ it("should use exponent form for large and small numbers", () => {
8
+ expect(toJcs(1e21)).toBe("1e+21");
9
+ expect(toJcs(1e-7)).toBe("1e-7");
10
+ });
11
+ it("should omit undefined and symbol object properties", () => {
12
+ const sym = Symbol("x");
13
+ const value = { b: 1, a: undefined, c: sym, d: null };
14
+ expect(toJcs(value)).toBe('{"b":1,"d":null}');
15
+ });
16
+ it("should convert non-serializable array items to null", () => {
17
+ const sym = Symbol("x");
18
+ const fn = () => { };
19
+ expect(toJcs([1, undefined, fn, sym, 2])).toBe("[1,null,null,null,2]");
20
+ });
21
+ it("should escape control characters in strings", () => {
22
+ const value = { text: "line\nbreak\tend" };
23
+ expect(toJcs(value)).toBe("{\"text\":\"line\\nbreak\\tend\"}");
24
+ });
25
+ it("should order keys by code point, including surrogate pairs", () => {
26
+ const keyA = "\uD834\uDD1E";
27
+ const keyB = "\uD834\uDD1F";
28
+ const value = {
29
+ [keyB]: 2,
30
+ a: 3,
31
+ [keyA]: 1,
32
+ };
33
+ const expected = `{"a":3,${JSON.stringify(keyA)}:1,${JSON.stringify(keyB)}:2}`;
34
+ expect(toJcs(value)).toBe(expected);
35
+ });
36
+ it("should escape quotes and backslashes", () => {
37
+ const value = { text: "quote\"slash\\end" };
38
+ expect(toJcs(value)).toBe("{\"text\":\"quote\\\"slash\\\\end\"}");
39
+ });
40
+ it("should escape null character", () => {
41
+ const value = { text: "nul\u0000end" };
42
+ expect(toJcs(value)).toBe("{\"text\":\"nul\\u0000end\"}");
43
+ });
44
+ });
45
+ //# sourceMappingURL=jcs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jcs.test.js","sourceRoot":"","sources":["../../src/__tests__/jcs.test.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { DomainSchema } from "../schema/domain.js";
2
2
  import type { Snapshot } from "../schema/snapshot.js";
3
3
  import type { Patch } from "../schema/patch.js";
4
+ import type { HostContext } from "../schema/host-context.js";
4
5
  /**
5
6
  * Apply patches to a snapshot
6
7
  *
@@ -12,5 +13,5 @@ import type { Patch } from "../schema/patch.js";
12
13
  *
13
14
  * Note: Version and timestamp are Core-owned - Host MUST NOT modify these directly.
14
15
  */
15
- export declare function apply(schema: DomainSchema, snapshot: Snapshot, patches: readonly Patch[]): Snapshot;
16
+ export declare function apply(schema: DomainSchema, snapshot: Snapshot, patches: readonly Patch[], context: HostContext): Snapshot;
16
17
  //# sourceMappingURL=apply.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAKhD;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,QAAQ,CAwCV"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAS7D;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,OAAO,EAAE,WAAW,GACnB,QAAQ,CA2GV"}
@@ -1,6 +1,8 @@
1
1
  import { setByPath, unsetByPath, mergeAtPath } from "../utils/path.js";
2
2
  import { evaluateComputed } from "../evaluator/computed.js";
3
- import { isOk } from "../schema/common.js";
3
+ import { isOk, isErr } from "../schema/common.js";
4
+ import { createError } from "../errors.js";
5
+ import { getFieldSpecAtPath, validateValueAgainstFieldSpec } from "./validation-utils.js";
4
6
  /**
5
7
  * Apply patches to a snapshot
6
8
  *
@@ -12,41 +14,117 @@ import { isOk } from "../schema/common.js";
12
14
  *
13
15
  * Note: Version and timestamp are Core-owned - Host MUST NOT modify these directly.
14
16
  */
15
- export function apply(schema, snapshot, patches) {
16
- // 1. Apply patches to data
17
+ export function apply(schema, snapshot, patches, context) {
18
+ // 1. Apply patches to data/system/input (data is default root)
17
19
  let newData = snapshot.data;
20
+ let newSystem = snapshot.system;
21
+ let newInput = snapshot.input;
22
+ const validationErrors = [];
23
+ const rootSpec = { type: "object", required: true, fields: schema.state.fields };
18
24
  for (const patch of patches) {
19
- switch (patch.op) {
20
- case "set":
21
- newData = setByPath(newData, patch.path, patch.value);
25
+ const { root, subPath } = splitPatchPath(patch.path);
26
+ switch (root) {
27
+ case "data":
28
+ {
29
+ const fieldSpec = getFieldSpecAtPath(rootSpec, subPath);
30
+ if (!fieldSpec) {
31
+ validationErrors.push(createError("PATH_NOT_FOUND", `Unknown patch path: ${patch.path}`, snapshot.system.currentAction ?? "", patch.path, context.now, { patch }));
32
+ break;
33
+ }
34
+ if (patch.op !== "unset") {
35
+ const result = validateValueAgainstFieldSpec(patch.value, fieldSpec, {
36
+ allowPartial: patch.op === "merge",
37
+ allowUndefined: false,
38
+ });
39
+ if (!result.ok) {
40
+ validationErrors.push(createError("TYPE_MISMATCH", `Invalid patch value at ${patch.path}: ${result.message ?? "type mismatch"}`, snapshot.system.currentAction ?? "", patch.path, context.now, { patch }));
41
+ break;
42
+ }
43
+ }
44
+ newData = applyPatch(newData, patch, subPath);
45
+ }
22
46
  break;
23
- case "unset":
24
- newData = unsetByPath(newData, patch.path);
47
+ case "system":
48
+ newSystem = applyPatch(newSystem, patch, subPath);
25
49
  break;
26
- case "merge":
27
- newData = mergeAtPath(newData, patch.path, patch.value);
50
+ case "input":
51
+ newInput = applyPatch(newInput, patch, subPath);
52
+ break;
53
+ case "computed":
54
+ case "meta":
55
+ // Computed/meta are Core-owned; ignore external patch attempts.
28
56
  break;
29
57
  }
30
58
  }
59
+ if (validationErrors.length > 0) {
60
+ const lastError = validationErrors[validationErrors.length - 1];
61
+ newSystem = {
62
+ ...newSystem,
63
+ status: "error",
64
+ lastError,
65
+ errors: [...newSystem.errors, ...validationErrors],
66
+ };
67
+ }
31
68
  // 2. Create intermediate snapshot with new data
32
69
  const intermediateSnapshot = {
33
70
  ...snapshot,
34
71
  data: newData,
72
+ system: newSystem,
73
+ input: newInput,
35
74
  };
36
75
  // 3. Recompute all computed values
37
76
  const computedResult = evaluateComputed(schema, intermediateSnapshot);
38
- const computed = isOk(computedResult) ? computedResult.value : snapshot.computed;
77
+ let computed = snapshot.computed;
78
+ if (isOk(computedResult)) {
79
+ computed = computedResult.value;
80
+ }
81
+ else if (isErr(computedResult)) {
82
+ const error = computedResult.error;
83
+ computed = {};
84
+ newSystem = {
85
+ ...newSystem,
86
+ status: "error",
87
+ lastError: error,
88
+ errors: [...newSystem.errors, error],
89
+ };
90
+ }
39
91
  // 4. Return new snapshot with updated metadata
40
92
  return {
41
93
  data: newData,
42
94
  computed,
43
- system: snapshot.system,
44
- input: snapshot.input,
95
+ system: newSystem,
96
+ input: newInput,
45
97
  meta: {
46
98
  ...snapshot.meta,
47
99
  version: snapshot.meta.version + 1,
48
- timestamp: Date.now(),
100
+ timestamp: context.now,
101
+ randomSeed: context.randomSeed,
49
102
  },
50
103
  };
51
104
  }
105
+ function splitPatchPath(path) {
106
+ if (path === "system" || path.startsWith("system.")) {
107
+ return { root: "system", subPath: path === "system" ? "" : path.slice(7) };
108
+ }
109
+ if (path === "input" || path.startsWith("input.")) {
110
+ return { root: "input", subPath: path === "input" ? "" : path.slice(6) };
111
+ }
112
+ if (path === "computed" || path.startsWith("computed.")) {
113
+ return { root: "computed", subPath: path === "computed" ? "" : path.slice(9) };
114
+ }
115
+ if (path === "meta" || path.startsWith("meta.")) {
116
+ return { root: "meta", subPath: path === "meta" ? "" : path.slice(5) };
117
+ }
118
+ return { root: "data", subPath: path };
119
+ }
120
+ function applyPatch(value, patch, subPath) {
121
+ switch (patch.op) {
122
+ case "set":
123
+ return setByPath(value, subPath, patch.value);
124
+ case "unset":
125
+ return unsetByPath(value, subPath);
126
+ case "merge":
127
+ return mergeAtPath(value, subPath, patch.value);
128
+ }
129
+ }
52
130
  //# sourceMappingURL=apply.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,KAAK,CACnB,MAAoB,EACpB,QAAkB,EAClB,OAAyB;IAEzB,2BAA2B;IAC3B,IAAI,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,QAAQ,KAAK,CAAC,EAAE,EAAE,CAAC;YACjB,KAAK,KAAK;gBACR,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtD,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3C,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBACxD,MAAM;QACV,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,MAAM,oBAAoB,GAAa;QACrC,GAAG,QAAQ;QACX,IAAI,EAAE,OAAO;KACd,CAAC;IAEF,mCAAmC;IACnC,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAEjF,+CAA+C;IAC/C,OAAO;QACL,IAAI,EAAE,OAAO;QACb,QAAQ;QACR,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,IAAI,EAAE;YACJ,GAAG,QAAQ,CAAC,IAAI;YAChB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC;YAClC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/core/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AASxE;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CA6HxB"}
1
+ {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/core/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAUxE;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAiKxB"}
@@ -31,15 +31,29 @@ export async function compute(schema, snapshot, intent) {
31
31
  if (!action) {
32
32
  return createErrorResult(currentSnapshot, intent, "UNKNOWN_ACTION", `Unknown action: ${intent.type}`, startTime);
33
33
  }
34
+ // 1.5 Validate intentId (must be non-empty)
35
+ if (!intent.intentId || intent.intentId === "") {
36
+ return createErrorResult(currentSnapshot, intent, "INVALID_INPUT", "Intent must have a non-empty intentId", startTime);
37
+ }
38
+ // 1.6 Validate input against action's input schema
39
+ if (action.input) {
40
+ const inputError = validateInput(action.input, intent.input);
41
+ if (inputError) {
42
+ return createErrorResult(currentSnapshot, intent, "INVALID_INPUT", inputError, startTime);
43
+ }
44
+ }
34
45
  // 2. Check availability condition
35
46
  if (action.available) {
36
- const ctx = createContext(currentSnapshot, schema, intent.type, "available");
47
+ const ctx = createContext(currentSnapshot, schema, intent.type, "available", intent.intentId);
37
48
  const availResult = evaluateExpr(action.available, ctx);
38
49
  if (isErr(availResult)) {
39
50
  return createErrorResult(currentSnapshot, intent, "INTERNAL_ERROR", `Error evaluating availability: ${availResult.error.message}`, startTime);
40
51
  }
41
- const isAvailable = availResult.value !== false && availResult.value !== null && availResult.value !== undefined;
42
- if (!isAvailable) {
52
+ // Availability must return a boolean (A28: available conditions must be pure)
53
+ if (typeof availResult.value !== "boolean") {
54
+ return createErrorResult(currentSnapshot, intent, "TYPE_MISMATCH", `Availability condition must return boolean, got ${typeof availResult.value}`, startTime);
55
+ }
56
+ if (!availResult.value) {
43
57
  return createErrorResult(currentSnapshot, intent, "ACTION_UNAVAILABLE", `Action "${intent.type}" is not available`, startTime);
44
58
  }
45
59
  }
@@ -54,7 +68,7 @@ export async function compute(schema, snapshot, intent) {
54
68
  },
55
69
  };
56
70
  // 4. Create evaluation context and flow state
57
- const ctx = createContext(preparedSnapshot, schema, intent.type, `actions.${intent.type}.flow`);
71
+ const ctx = createContext(preparedSnapshot, schema, intent.type, `actions.${intent.type}.flow`, intent.intentId);
58
72
  const flowState = createFlowState(preparedSnapshot);
59
73
  // 5. Evaluate the flow
60
74
  const flowResult = await evaluateFlow(action.flow, ctx, flowState, `actions.${intent.type}.flow`);
@@ -100,6 +114,7 @@ export async function compute(schema, snapshot, intent) {
100
114
  };
101
115
  return {
102
116
  snapshot: finalSnapshot,
117
+ requirements: [...flowResult.state.requirements],
103
118
  trace,
104
119
  status: systemStatus,
105
120
  };
@@ -154,7 +169,7 @@ function collectTraceNodes(root) {
154
169
  * Create an error result
155
170
  */
156
171
  function createErrorResult(snapshot, intent, code, message, startTime) {
157
- const error = createError(code, message, intent.type, "");
172
+ const error = createError(code, message, intent.type, "", Date.now());
158
173
  const errorSnapshot = {
159
174
  ...snapshot,
160
175
  input: intent.input,
@@ -190,8 +205,83 @@ function createErrorResult(snapshot, intent, code, message, startTime) {
190
205
  };
191
206
  return {
192
207
  snapshot: errorSnapshot,
208
+ requirements: [],
193
209
  trace,
194
210
  status: "error",
195
211
  };
196
212
  }
213
+ /**
214
+ * Validate input against action's input schema
215
+ * Returns error message if invalid, null if valid
216
+ */
217
+ function validateInput(inputSpec, input) {
218
+ // Check type
219
+ if (inputSpec.type === "object") {
220
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
221
+ return `Expected object input, got ${typeof input}`;
222
+ }
223
+ const inputObj = input;
224
+ const fields = inputSpec.fields ?? {};
225
+ // Check for required fields
226
+ for (const [fieldName, fieldSpec] of Object.entries(fields)) {
227
+ if (fieldSpec.required && !(fieldName in inputObj)) {
228
+ return `Missing required field: ${fieldName}`;
229
+ }
230
+ }
231
+ // Check for unknown fields
232
+ for (const key of Object.keys(inputObj)) {
233
+ if (!(key in fields)) {
234
+ return `Unknown field: ${key}`;
235
+ }
236
+ }
237
+ // Recursively validate nested fields
238
+ for (const [fieldName, fieldSpec] of Object.entries(fields)) {
239
+ if (fieldName in inputObj) {
240
+ const error = validateFieldValue(fieldSpec, inputObj[fieldName], fieldName);
241
+ if (error)
242
+ return error;
243
+ }
244
+ }
245
+ }
246
+ return null;
247
+ }
248
+ /**
249
+ * Validate a field value against its spec
250
+ */
251
+ function validateFieldValue(spec, value, path) {
252
+ if (value === undefined || value === null) {
253
+ if (spec.required) {
254
+ return `Missing required field: ${path}`;
255
+ }
256
+ return null;
257
+ }
258
+ switch (spec.type) {
259
+ case "string":
260
+ if (typeof value !== "string") {
261
+ return `Expected string for ${path}, got ${typeof value}`;
262
+ }
263
+ break;
264
+ case "number":
265
+ if (typeof value !== "number") {
266
+ return `Expected number for ${path}, got ${typeof value}`;
267
+ }
268
+ break;
269
+ case "boolean":
270
+ if (typeof value !== "boolean") {
271
+ return `Expected boolean for ${path}, got ${typeof value}`;
272
+ }
273
+ break;
274
+ case "array":
275
+ if (!Array.isArray(value)) {
276
+ return `Expected array for ${path}, got ${typeof value}`;
277
+ }
278
+ break;
279
+ case "object":
280
+ if (typeof value !== "object" || Array.isArray(value)) {
281
+ return `Expected object for ${path}, got ${typeof value}`;
282
+ }
283
+ break;
284
+ }
285
+ return null;
286
+ }
197
287
  //# sourceMappingURL=compute.js.map