@ecsia/scheduler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/commands/apply.d.ts +49 -0
  4. package/dist/commands/apply.d.ts.map +1 -0
  5. package/dist/commands/apply.js +211 -0
  6. package/dist/commands/apply.js.map +1 -0
  7. package/dist/commands/buffer.d.ts +53 -0
  8. package/dist/commands/buffer.d.ts.map +1 -0
  9. package/dist/commands/buffer.js +66 -0
  10. package/dist/commands/buffer.js.map +1 -0
  11. package/dist/commands/encode.d.ts +30 -0
  12. package/dist/commands/encode.d.ts.map +1 -0
  13. package/dist/commands/encode.js +108 -0
  14. package/dist/commands/encode.js.map +1 -0
  15. package/dist/commands/fields.d.ts +22 -0
  16. package/dist/commands/fields.d.ts.map +1 -0
  17. package/dist/commands/fields.js +123 -0
  18. package/dist/commands/fields.js.map +1 -0
  19. package/dist/commands/index.d.ts +10 -0
  20. package/dist/commands/index.d.ts.map +1 -0
  21. package/dist/commands/index.js +6 -0
  22. package/dist/commands/index.js.map +1 -0
  23. package/dist/commands/op.d.ts +16 -0
  24. package/dist/commands/op.d.ts.map +1 -0
  25. package/dist/commands/op.js +43 -0
  26. package/dist/commands/op.js.map +1 -0
  27. package/dist/executor/guards.d.ts +8 -0
  28. package/dist/executor/guards.d.ts.map +1 -0
  29. package/dist/executor/guards.js +61 -0
  30. package/dist/executor/guards.js.map +1 -0
  31. package/dist/executor/index.d.ts +9 -0
  32. package/dist/executor/index.d.ts.map +1 -0
  33. package/dist/executor/index.js +6 -0
  34. package/dist/executor/index.js.map +1 -0
  35. package/dist/executor/run-wave.d.ts +19 -0
  36. package/dist/executor/run-wave.d.ts.map +1 -0
  37. package/dist/executor/run-wave.js +38 -0
  38. package/dist/executor/run-wave.js.map +1 -0
  39. package/dist/executor/scheduler.d.ts +41 -0
  40. package/dist/executor/scheduler.d.ts.map +1 -0
  41. package/dist/executor/scheduler.js +71 -0
  42. package/dist/executor/scheduler.js.map +1 -0
  43. package/dist/executor/seams.d.ts +38 -0
  44. package/dist/executor/seams.d.ts.map +1 -0
  45. package/dist/executor/seams.js +16 -0
  46. package/dist/executor/seams.js.map +1 -0
  47. package/dist/executor/update-threaded.d.ts +17 -0
  48. package/dist/executor/update-threaded.d.ts.map +1 -0
  49. package/dist/executor/update-threaded.js +67 -0
  50. package/dist/executor/update-threaded.js.map +1 -0
  51. package/dist/executor/update.d.ts +4 -0
  52. package/dist/executor/update.d.ts.map +1 -0
  53. package/dist/executor/update.js +23 -0
  54. package/dist/executor/update.js.map +1 -0
  55. package/dist/graph/dag.d.ts +16 -0
  56. package/dist/graph/dag.d.ts.map +1 -0
  57. package/dist/graph/dag.js +118 -0
  58. package/dist/graph/dag.js.map +1 -0
  59. package/dist/graph/edges.d.ts +20 -0
  60. package/dist/graph/edges.d.ts.map +1 -0
  61. package/dist/graph/edges.js +181 -0
  62. package/dist/graph/edges.js.map +1 -0
  63. package/dist/graph/index.d.ts +8 -0
  64. package/dist/graph/index.d.ts.map +1 -0
  65. package/dist/graph/index.js +5 -0
  66. package/dist/graph/index.js.map +1 -0
  67. package/dist/graph/waves.d.ts +30 -0
  68. package/dist/graph/waves.d.ts.map +1 -0
  69. package/dist/graph/waves.js +133 -0
  70. package/dist/graph/waves.js.map +1 -0
  71. package/dist/graph/weights.d.ts +7 -0
  72. package/dist/graph/weights.d.ts.map +1 -0
  73. package/dist/graph/weights.js +10 -0
  74. package/dist/graph/weights.js.map +1 -0
  75. package/dist/index.d.ts +9 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +21 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/internal.d.ts +13 -0
  80. package/dist/internal.d.ts.map +1 -0
  81. package/dist/internal.js +12 -0
  82. package/dist/internal.js.map +1 -0
  83. package/dist/planner/access.d.ts +18 -0
  84. package/dist/planner/access.d.ts.map +1 -0
  85. package/dist/planner/access.js +92 -0
  86. package/dist/planner/access.js.map +1 -0
  87. package/dist/planner/define-system.d.ts +14 -0
  88. package/dist/planner/define-system.d.ts.map +1 -0
  89. package/dist/planner/define-system.js +30 -0
  90. package/dist/planner/define-system.js.map +1 -0
  91. package/dist/planner/index.d.ts +6 -0
  92. package/dist/planner/index.d.ts.map +1 -0
  93. package/dist/planner/index.js +4 -0
  94. package/dist/planner/index.js.map +1 -0
  95. package/dist/planner/types.d.ts +74 -0
  96. package/dist/planner/types.d.ts.map +1 -0
  97. package/dist/planner/types.js +6 -0
  98. package/dist/planner/types.js.map +1 -0
  99. package/dist/workers/atomics-shim.d.ts +8 -0
  100. package/dist/workers/atomics-shim.d.ts.map +1 -0
  101. package/dist/workers/atomics-shim.js +14 -0
  102. package/dist/workers/atomics-shim.js.map +1 -0
  103. package/dist/workers/index.d.ts +13 -0
  104. package/dist/workers/index.d.ts.map +1 -0
  105. package/dist/workers/index.js +10 -0
  106. package/dist/workers/index.js.map +1 -0
  107. package/dist/workers/manifest.d.ts +67 -0
  108. package/dist/workers/manifest.d.ts.map +1 -0
  109. package/dist/workers/manifest.js +5 -0
  110. package/dist/workers/manifest.js.map +1 -0
  111. package/dist/workers/pool.d.ts +60 -0
  112. package/dist/workers/pool.d.ts.map +1 -0
  113. package/dist/workers/pool.js +313 -0
  114. package/dist/workers/pool.js.map +1 -0
  115. package/dist/workers/reservation.d.ts +18 -0
  116. package/dist/workers/reservation.d.ts.map +1 -0
  117. package/dist/workers/reservation.js +41 -0
  118. package/dist/workers/reservation.js.map +1 -0
  119. package/dist/workers/wave-sync.d.ts +18 -0
  120. package/dist/workers/wave-sync.d.ts.map +1 -0
  121. package/dist/workers/wave-sync.js +88 -0
  122. package/dist/workers/wave-sync.js.map +1 -0
  123. package/dist/workers/worker-entry.d.ts +2 -0
  124. package/dist/workers/worker-entry.d.ts.map +1 -0
  125. package/dist/workers/worker-entry.js +187 -0
  126. package/dist/workers/worker-entry.js.map +1 -0
  127. package/dist/workers/worker-system.d.ts +31 -0
  128. package/dist/workers/worker-system.d.ts.map +1 -0
  129. package/dist/workers/worker-system.js +20 -0
  130. package/dist/workers/worker-system.js.map +1 -0
  131. package/dist/workers/world-view.d.ts +39 -0
  132. package/dist/workers/world-view.d.ts.map +1 -0
  133. package/dist/workers/world-view.js +85 -0
  134. package/dist/workers/world-view.js.map +1 -0
  135. package/package.json +53 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/commands/fields.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,EAAE,MAAM,eAAe,CAAA;AAU1E,UAAU,UAAU;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvE,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;CAC7D;AAED,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,2FAA2F;IAC3F,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACvF,sFAAsF;IACtF,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChE;AA8ED,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,mBAAmB,CA0B9E"}
@@ -0,0 +1,123 @@
1
+ // Field-word codec for OP_ADD / OP_SET_PAYLOAD / OP_ADD_PAIR payloads.
2
+ // Each component/relation field contributes `stride` u32 words to a record's payload tail; f64
3
+ // contributes two words (low, high). The codec is derived ONCE per component from its FieldDescriptor
4
+ // list (declaration order). Encode widens a JS value to its u32 slot bit-pattern; decode narrows back.
5
+ // Object<T> fields are NOT encodable (restrictedToMainThread) — a component carrying one is
6
+ // worker-ineligible upstream, so this path never sees it.
7
+ // Shared scratch for f32-bit aliasing and f64 two-word split (host-native, consistent within a
8
+ // process; the buffer is transferred not re-serialized in the fallback, so byte order is preserved).
9
+ const scratch = new ArrayBuffer(8);
10
+ const scratchF32 = new Float32Array(scratch);
11
+ const scratchF64 = new Float64Array(scratch);
12
+ const scratchU32 = new Uint32Array(scratch);
13
+ const scratchI32 = new Int32Array(scratch);
14
+ function scalarCodec(token, d) {
15
+ if (token === 'f32') {
16
+ return {
17
+ name: d.name,
18
+ words: 1,
19
+ encode: (v, out, at) => {
20
+ scratchF32[0] = +v;
21
+ out[at] = scratchU32[0];
22
+ },
23
+ decode: (w, at) => {
24
+ scratchU32[0] = w[at];
25
+ return scratchF32[0];
26
+ },
27
+ };
28
+ }
29
+ if (token === 'f64') {
30
+ return {
31
+ name: d.name,
32
+ words: 2,
33
+ encode: (v, out, at) => {
34
+ scratchF64[0] = +v;
35
+ out[at] = scratchU32[0];
36
+ out[at + 1] = scratchU32[1];
37
+ },
38
+ decode: (w, at) => {
39
+ scratchU32[0] = w[at];
40
+ scratchU32[1] = w[at + 1];
41
+ return scratchF64[0];
42
+ },
43
+ };
44
+ }
45
+ // Integer / bool / eid / staticString: one word, the encoded slot value. Round-trip through the
46
+ // descriptor's own encode/decode so the apply path stores exactly what a main-thread setter would.
47
+ return {
48
+ name: d.name,
49
+ words: 1,
50
+ encode: (v, out, at) => {
51
+ out[at] = d.encode(v) >>> 0;
52
+ },
53
+ decode: (w, at) => {
54
+ // i32-class slots must round-trip through a signed reinterpret before the descriptor decode.
55
+ scratchU32[0] = w[at];
56
+ return d.decode(scratchI32[0]);
57
+ },
58
+ };
59
+ }
60
+ function fieldCodec(d) {
61
+ const token = d.token;
62
+ if (typeof token === 'string')
63
+ return scalarCodec(token, d);
64
+ const kind = token.kind;
65
+ if (kind === 'vec') {
66
+ const elem = token.elem;
67
+ const len = token.len;
68
+ const per = scalarCodec(elem, { ...d, stride: 1 });
69
+ const words = per.words * len;
70
+ return {
71
+ name: d.name,
72
+ words,
73
+ encode: (v, out, at) => {
74
+ const arr = v;
75
+ for (let i = 0; i < len; i++)
76
+ per.encode(arr[i], out, at + i * per.words);
77
+ },
78
+ decode: (w, at) => {
79
+ const arr = [];
80
+ for (let i = 0; i < len; i++)
81
+ arr.push(per.decode(w, at + i * per.words));
82
+ return arr;
83
+ },
84
+ };
85
+ }
86
+ if (kind === 'staticString') {
87
+ return scalarCodec('u32', d);
88
+ }
89
+ throw new Error(`command-buffer: field '${d.name}' (object token) is not encodable in a command buffer`);
90
+ }
91
+ export function buildFieldCodec(def) {
92
+ const fields = def.fields.filter((f) => f.shareable).map(fieldCodec);
93
+ let totalWords = 0;
94
+ for (const f of fields)
95
+ totalWords += f.words;
96
+ return {
97
+ totalWords,
98
+ fields,
99
+ encode(init, out, at) {
100
+ let cursor = at;
101
+ for (const f of fields) {
102
+ const value = init?.[f.name] ?? defaultFor(def, f.name);
103
+ f.encode(value, out, cursor);
104
+ cursor += f.words;
105
+ }
106
+ return cursor - at;
107
+ },
108
+ decode(words, at) {
109
+ const obj = {};
110
+ let cursor = at;
111
+ for (const f of fields) {
112
+ obj[f.name] = f.decode(words, cursor);
113
+ cursor += f.words;
114
+ }
115
+ return obj;
116
+ },
117
+ };
118
+ }
119
+ function defaultFor(def, fieldName) {
120
+ const d = def.fields.find((f) => f.name === fieldName);
121
+ return d?.default ?? 0;
122
+ }
123
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/commands/fields.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { Op, recordLen } from './op.js';
2
+ export { directApplySink, flushAll } from './apply.js';
3
+ export type { CommandSink, StructuralIntent, WorldApply } from './apply.js';
4
+ export { makeCommandBuffer, resetBuffer, ensureWords } from './buffer.js';
5
+ export type { CommandBuffer, BufferReservation } from './buffer.js';
6
+ export { makeEncoder } from './encode.js';
7
+ export type { CommandEncoder, ComponentEncodeInfo, EncoderEnv } from './encode.js';
8
+ export { buildFieldCodec } from './fields.js';
9
+ export type { ComponentFieldCodec } from './fields.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACtD,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { Op, recordLen } from './op.js';
2
+ export { directApplySink, flushAll } from './apply.js';
3
+ export { makeCommandBuffer, resetBuffer, ensureWords } from './buffer.js';
4
+ export { makeEncoder } from './encode.js';
5
+ export { buildFieldCodec } from './fields.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEtD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,16 @@
1
+ export declare const enum Op {
2
+ CREATE = 0,// OP_CREATE reservedEid
3
+ DESTROY = 1,// OP_DESTROY eid
4
+ ADD = 2,// OP_ADD eid componentId fieldWordCount [field words...]
5
+ REMOVE = 3,// OP_REMOVE eid componentId
6
+ ADD_PAIR = 4,// OP_ADD_PAIR eid relationId targetEid payloadWordCount [payload words...]
7
+ REMOVE_PAIR = 5,// OP_REMOVE_PAIR eid relationId targetEid
8
+ SET_PAYLOAD = 6
9
+ }
10
+ /**
11
+ * Self-describing record length in u32 words. Every record's length is
12
+ * computable from its first word(s) WITHOUT consulting any schema — the variable-arity ops carry an
13
+ * explicit count word — so the merge loop can skip/iterate records with no schema lookup.
14
+ */
15
+ export declare function recordLen(words: Uint32Array, at: number): number;
16
+ //# sourceMappingURL=op.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"op.d.ts","sourceRoot":"","sources":["../../src/commands/op.ts"],"names":[],"mappings":"AASA,0BAAkB,EAAE;IAClB,MAAM,IAAI,CAAE,wBAAwB;IACpC,OAAO,IAAI,CAAE,iBAAiB;IAC9B,GAAG,IAAI,CAAE,yDAAyD;IAClE,MAAM,IAAI,CAAE,4BAA4B;IACxC,QAAQ,IAAI,CAAE,2EAA2E;IACzF,WAAW,IAAI,CAAE,0CAA0C;IAC3D,WAAW,IAAI;CAChB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAkBhE"}
@@ -0,0 +1,43 @@
1
+ // Command-buffer op ordinals. These numeric
2
+ // values are SHARED across command-buffer `Op`, serialization `DeltaOp`, and reactivity `ShapeKind`
3
+ // — the member names differ per spec but the numeric values are identical. Pinning them here is what
4
+ // lets the apply path be reused across command-buffer and serialization.
5
+ //
6
+ // declares the FORMAT only. The encode methods (CommandEncoder) and the
7
+ // per-worker SAB transport land at; ships the ordinals, the self-describing record-length
8
+ // function, and a direct main-thread apply seam so is purely additive.
9
+ export var Op;
10
+ (function (Op) {
11
+ Op[Op["CREATE"] = 0] = "CREATE";
12
+ Op[Op["DESTROY"] = 1] = "DESTROY";
13
+ Op[Op["ADD"] = 2] = "ADD";
14
+ Op[Op["REMOVE"] = 3] = "REMOVE";
15
+ Op[Op["ADD_PAIR"] = 4] = "ADD_PAIR";
16
+ Op[Op["REMOVE_PAIR"] = 5] = "REMOVE_PAIR";
17
+ Op[Op["SET_PAYLOAD"] = 6] = "SET_PAYLOAD";
18
+ })(Op || (Op = {}));
19
+ /**
20
+ * Self-describing record length in u32 words. Every record's length is
21
+ * computable from its first word(s) WITHOUT consulting any schema — the variable-arity ops carry an
22
+ * explicit count word — so the merge loop can skip/iterate records with no schema lookup.
23
+ */
24
+ export function recordLen(words, at) {
25
+ switch (words[at]) {
26
+ case Op.CREATE:
27
+ return 2;
28
+ case Op.DESTROY:
29
+ return 2;
30
+ case Op.REMOVE:
31
+ return 3;
32
+ case Op.REMOVE_PAIR:
33
+ return 4;
34
+ case Op.ADD:
35
+ case Op.SET_PAYLOAD:
36
+ return 4 + words[at + 3]; // 4 + fieldWordCount
37
+ case Op.ADD_PAIR:
38
+ return 5 + words[at + 4]; // 5 + payloadWordCount
39
+ default:
40
+ throw new Error(`corrupt command buffer: bad opcode ${words[at]} at ${at}`);
41
+ }
42
+ }
43
+ //# sourceMappingURL=op.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"op.js","sourceRoot":"","sources":["../../src/commands/op.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,oGAAoG;AACpG,qGAAqG;AACrG,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,0FAA0F;AAC1F,uEAAuE;AAEvE,MAAM,CAAN,IAAkB,EAQjB;AARD,WAAkB,EAAE;IAClB,+BAAU,CAAA;IACV,iCAAW,CAAA;IACX,yBAAO,CAAA;IACP,+BAAU,CAAA;IACV,mCAAY,CAAA;IACZ,yCAAe,CAAA;IACf,yCAAe,CAAA;AACjB,CAAC,EARiB,EAAE,KAAF,EAAE,QAQnB;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAkB,EAAE,EAAU;IACtD,QAAQ,KAAK,CAAC,EAAE,CAAO,EAAE,CAAC;QACxB,KAAK,EAAE,CAAC,MAAM;YACZ,OAAO,CAAC,CAAA;QACV,KAAK,EAAE,CAAC,OAAO;YACb,OAAO,CAAC,CAAA;QACV,KAAK,EAAE,CAAC,MAAM;YACZ,OAAO,CAAC,CAAA;QACV,KAAK,EAAE,CAAC,WAAW;YACjB,OAAO,CAAC,CAAA;QACV,KAAK,EAAE,CAAC,GAAG,CAAC;QACZ,KAAK,EAAE,CAAC,WAAW;YACjB,OAAO,CAAC,GAAI,KAAK,CAAC,EAAE,GAAG,CAAC,CAAY,CAAA,CAAC,qBAAqB;QAC5D,KAAK,EAAE,CAAC,QAAQ;YACd,OAAO,CAAC,GAAI,KAAK,CAAC,EAAE,GAAG,CAAC,CAAY,CAAA,CAAC,uBAAuB;QAC9D;YACE,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAC/E,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { World } from '@ecsia/core';
2
+ import type { SystemBox } from '../planner/index.js';
3
+ /**
4
+ * Wrap `world.query` so each term's component is asserted against the system's declared access.
5
+ * Returns the world's own query result unchanged; only the dev-mode diagnostic is added.
6
+ */
7
+ export declare function makeScopedQuery(world: World, sb: SystemBox, dev: boolean): World['query'];
8
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/executor/guards.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAwBpD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CA4BzF"}
@@ -0,0 +1,61 @@
1
+ // Dev-mode access guards (declared-intent contract). A system's
2
+ // scoped `query` warns when a term references a component outside the system's declared
3
+ // `read ∪ write`, and when a `write(C)` term names a C absent from `writeIds`. The declaration stays
4
+ // authoritative — an undeclared access is a scheduling BUG the user must fix, not blocked (production
5
+ // silent). Guards compile out when `dev` is false so the hot path is unaffected.
6
+ function defOfTerm(term) {
7
+ const t = term;
8
+ if (t.relation !== undefined)
9
+ return { def: null, role: 'other' }; // Pair term — pair ids checked at
10
+ switch (t.__term) {
11
+ case 'write':
12
+ return { def: t.c ?? null, role: 'write' };
13
+ case 'read':
14
+ case 'optional':
15
+ return { def: t.c ?? null, role: 'read' };
16
+ case 'has':
17
+ case 'without':
18
+ return { def: t.c ?? null, role: 'other' };
19
+ default:
20
+ // bare ComponentDef == read
21
+ return { def: term, role: 'read' };
22
+ }
23
+ }
24
+ function warn(message) {
25
+ if (typeof console !== 'undefined')
26
+ console.warn(`[ecsia:scheduler] ${message}`);
27
+ }
28
+ /**
29
+ * Wrap `world.query` so each term's component is asserted against the system's declared access.
30
+ * Returns the world's own query result unchanged; only the dev-mode diagnostic is added.
31
+ */
32
+ export function makeScopedQuery(world, sb, dev) {
33
+ if (!dev)
34
+ return world.query;
35
+ const readSet = new Set(sb.readIds);
36
+ const writeSet = new Set(sb.writeIds);
37
+ const scoped = (...terms) => {
38
+ for (const term of terms) {
39
+ const { def, role } = defOfTerm(term);
40
+ if (def === null)
41
+ continue;
42
+ const id = def.id;
43
+ if (id < 0)
44
+ continue; // unregistered — the world's compiler reports it
45
+ if (role === 'write') {
46
+ if (!writeSet.has(id)) {
47
+ warn(`system '${sb.name}' issues a write(${def.name}) term but '${def.name}' is not in its declared write set — ` +
48
+ `add it to the system's write access so parallel scheduling can serialize conflicting writers`);
49
+ }
50
+ }
51
+ else if (role === 'read' && !readSet.has(id) && !writeSet.has(id)) {
52
+ // `has`/`without` are presence FILTERS (role 'other'), not data access — declaring the
53
+ // filtered component would be spurious, so only genuine read terms are access-checked.
54
+ warn(`system '${sb.name}' references ${def.name} in a query but it is not in the system's declared read/write set`);
55
+ }
56
+ }
57
+ return world.query(...terms);
58
+ };
59
+ return scoped;
60
+ }
61
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/executor/guards.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,wFAAwF;AACxF,qGAAqG;AACrG,sGAAsG;AACtG,iFAAiF;AAMjF,SAAS,SAAS,CAAC,IAAe;IAChC,MAAM,CAAC,GAAG,IAAyE,CAAA;IACnF,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA,CAAC,kCAAkC;IACpG,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QAC5C,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU;YACb,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAC3C,KAAK,KAAK,CAAC;QACX,KAAK,SAAS;YACZ,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QAC5C;YACE,4BAA4B;YAC5B,OAAO,EAAE,GAAG,EAAE,IAA4B,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAA;AAClF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,EAAa,EAAE,GAAY;IACvE,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC,KAAK,CAAA;IAC5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,EAAE,CAAC,OAA8B,CAAC,CAAA;IAClE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,EAAE,CAAC,QAA+B,CAAC,CAAA;IACpE,MAAM,MAAM,GAAG,CAAC,GAAG,KAAkB,EAAW,EAAE;QAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;YACrC,IAAI,GAAG,KAAK,IAAI;gBAAE,SAAQ;YAC1B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAuB,CAAA;YACtC,IAAI,EAAE,GAAG,CAAC;gBAAE,SAAQ,CAAC,iDAAiD;YACtE,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;oBACtB,IAAI,CACF,WAAW,EAAE,CAAC,IAAI,oBAAoB,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,IAAI,uCAAuC;wBAC1G,8FAA8F,CACjG,CAAA;gBACH,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpE,uFAAuF;gBACvF,uFAAuF;gBACvF,IAAI,CACF,WAAW,EAAE,CAAC,IAAI,gBAAgB,GAAG,CAAC,IAAI,mEAAmE,CAC9G,CAAA;YACH,CAAC;QACH,CAAC;QACD,OAAQ,KAAK,CAAC,KAAwC,CAAC,GAAG,KAAK,CAAC,CAAA;IAClE,CAAC,CAAA;IACD,OAAO,MAAmC,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { createScheduler, buildSchedulePlan } from './scheduler.js';
2
+ export type { SchedulerHandle, CreateSchedulerOptions } from './scheduler.js';
3
+ export { runUpdate } from './update.js';
4
+ export { runUpdateThreaded } from './update-threaded.js';
5
+ export type { RoundDispatcher } from './update-threaded.js';
6
+ export { runWave, buildScopedQueries } from './run-wave.js';
7
+ export type { ExecutorEnv } from './run-wave.js';
8
+ export { makeScopedQuery } from './guards.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACnE,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { createScheduler, buildSchedulePlan } from './scheduler.js';
2
+ export { runUpdate } from './update.js';
3
+ export { runUpdateThreaded } from './update-threaded.js';
4
+ export { runWave, buildScopedQueries } from './run-wave.js';
5
+ export { makeScopedQuery } from './guards.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,19 @@
1
+ import type { World } from '@ecsia/core';
2
+ import type { ScheduleWave } from '../graph/index.js';
3
+ import type { SystemBox } from '../planner/index.js';
4
+ import type { CommandSink } from '../commands/index.js';
5
+ export interface ExecutorEnv {
6
+ readonly world: World;
7
+ readonly dev: boolean;
8
+ readonly commands: CommandSink;
9
+ /** 'per-system' drains observers in every wave's serial slot; 'frame-end' once after the last wave. */
10
+ readonly observerCadence: 'frame-end' | 'per-system';
11
+ /** The plan's SystemBoxes, indexed by SystemId. */
12
+ readonly systems: readonly SystemBox[];
13
+ /** Pre-built per-system scoped queries (dev-guarded). Indexed by SystemId. */
14
+ readonly scopedQueries: readonly World['query'][];
15
+ }
16
+ export declare function buildScopedQueries(world: World, systems: readonly SystemBox[], dev: boolean): World['query'][];
17
+ /** Run one wave, then the serial flush slot after it. */
18
+ export declare function runWave(env: ExecutorEnv, wave: ScheduleWave, dt: number): void;
19
+ //# sourceMappingURL=run-wave.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-wave.d.ts","sourceRoot":"","sources":["../../src/executor/run-wave.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,uGAAuG;IACvG,QAAQ,CAAC,eAAe,EAAE,WAAW,GAAG,YAAY,CAAA;IACpD,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAA;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,aAAa,EAAE,SAAS,KAAK,CAAC,OAAO,CAAC,EAAE,CAAA;CAClD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAE9G;AAYD,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAY9E"}
@@ -0,0 +1,38 @@
1
+ // The single-threaded executor — the NORMATIVE semantics. Runs waves IN ORDER on
2
+ // the main thread; each wave's rounds run sequentially and (single-thread) each round's batches run
3
+ // sequentially in batch-index order. Because batches in a round are conflict-free by construction
4
+ // (WAVE-CONFLICT), the observable result equals the threaded path.
5
+ //
6
+ // Rule PHASE-1: in single-thread mode (workers === 0) runWave does NOT flip world.phase to
7
+ // 'wave'. It stays 'serial' for the entire update, so every structural op a system performs takes the
8
+ // synchronous direct-apply fast path and there are no command buffers to
9
+ // flush. The post-wave serial slot's flushAll/mergeCorrals are no-ops — zero cost single-threaded.
10
+ import { makeScopedQuery } from './guards.js';
11
+ export function buildScopedQueries(world, systems, dev) {
12
+ return systems.map((sb) => makeScopedQuery(world, sb, dev));
13
+ }
14
+ function runSystem(env, sb, dt) {
15
+ const ctx = {
16
+ world: env.world,
17
+ dt,
18
+ tick: env.world.currentTick(),
19
+ query: env.scopedQueries[sb.id],
20
+ };
21
+ sb.run(ctx);
22
+ }
23
+ /** Run one wave, then the serial flush slot after it. */
24
+ export function runWave(env, wave, dt) {
25
+ // ---- WAVE PHASE ---- (single-thread: world.phase stays 'serial', PHASE-1)
26
+ for (const round of wave.rounds) {
27
+ for (const batch of round) {
28
+ runSystem(env, env.systems[batch.systemId], dt);
29
+ }
30
+ }
31
+ // ---- SERIAL SLOT ---- apply staged structural changes + maintain queries + (maybe) observers.
32
+ env.world.mergeCorrals(); // no-op single-thread (no worker corrals)
33
+ env.commands.flushAll(); // no-op single-thread (no worker command buffers)
34
+ env.world.maintainStructural();
35
+ if (env.observerCadence === 'per-system')
36
+ env.world.observerDrain();
37
+ }
38
+ //# sourceMappingURL=run-wave.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-wave.js","sourceRoot":"","sources":["../../src/executor/run-wave.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,oGAAoG;AACpG,kGAAkG;AAClG,mEAAmE;AACnE,EAAE;AACF,2FAA2F;AAC3F,sGAAsG;AACtG,yEAAyE;AACzE,mGAAmG;AAOnG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAc7C,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,OAA6B,EAAE,GAAY;IAC1F,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,SAAS,CAAC,GAAgB,EAAE,EAAa,EAAE,EAAU;IAC5D,MAAM,GAAG,GAAkB;QACzB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,EAAE;QACF,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAqB;QAChD,KAAK,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,EAAuB,CAAE;KACtD,CAAA;IACD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AACb,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,OAAO,CAAC,GAAgB,EAAE,IAAkB,EAAE,EAAU;IACtE,4EAA4E;IAC5E,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,QAA6B,CAAE,EAAE,EAAE,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;IACD,gGAAgG;IAChG,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,CAAA,CAAC,0CAA0C;IACnE,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAA,CAAC,kDAAkD;IAC1E,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAA;IAC9B,IAAI,GAAG,CAAC,eAAe,KAAK,YAAY;QAAE,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,CAAA;AACrE,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { World } from '@ecsia/core';
2
+ import type { SystemBox, SystemDef } from '../planner/index.js';
3
+ import type { SchedulePlan } from '../graph/index.js';
4
+ import type { RoundDispatcher } from './update-threaded.js';
5
+ export interface SchedulerHandle {
6
+ /** The immutable plan (frozen; rebuilt wholesale on re-plan, never patched — ). */
7
+ readonly plan: SchedulePlan;
8
+ /** Run one wave-scheduled tick on the main thread. */
9
+ update(dt?: number): void;
10
+ /**
11
+ * Run one wave-scheduled tick THREADED (PHASE-2): each round's worker batches
12
+ * are dispatched to `pool` (the WorkerPool), the rest run on the main thread. Reproduces the
13
+ * single-thread observable result through the SAME frame loop. The `pool`'s PoolSystem
14
+ * registration order MUST match the plan's SystemId order (the test rig wires this).
15
+ */
16
+ updateThreaded(pool: RoundDispatcher, dt?: number): Promise<void>;
17
+ }
18
+ export interface CreateSchedulerOptions {
19
+ /**
20
+ * registry.nextComponentId after createWorld registration (user components + reserved ids + one
21
+ * presence id per relation); accessStrideWords = ceil(registeredComponentCount / 32). When omitted,
22
+ * the stride is derived from the max declared component id (correct for the type-level disjointness
23
+ * test; widen-only). Pass it to align the access words with the bitmask stride for worker work.
24
+ */
25
+ readonly registeredComponentCount?: number;
26
+ /** Worker pool size for plan shape (matches WorldOptions.scheduler.workers). Default: 0 (single-thread; worker bodies land at ). */
27
+ readonly workers?: number;
28
+ /** Dev guards on/off. Default: NODE_ENV !== 'production'. */
29
+ readonly dev?: boolean;
30
+ }
31
+ /**
32
+ * Build the immutable plan from lowered, ordering-resolved SystemBoxes. The full pipeline:
33
+ * aggregate access → derive weighted conflict edges → cycle-detect + transitively reduce → extract
34
+ * waves + pack batches (WAVE-CONFLICT). Fails fast on a cyclic dependency (CycleError).
35
+ */
36
+ export declare function buildSchedulePlan(systems: readonly SystemBox[], opts: {
37
+ accessStrideWords: number;
38
+ workers: number;
39
+ }): SchedulePlan;
40
+ export declare function createScheduler(world: World, defs: readonly SystemDef[], opts?: CreateSchedulerOptions): SchedulerHandle;
41
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/executor/scheduler.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAG3D,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,sDAAsD;IACtD,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;;OAKG;IACH,cAAc,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClE;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAA;IAC1C,oIAAoI;IACpI,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CACvB;AAaD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,IAAI,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnD,YAAY,CAcd;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,eAAe,CA0BjB"}
@@ -0,0 +1,71 @@
1
+ // The world↔scheduler wiring seam (the locked dependency direction schema ← core ←
2
+ // scheduler). The scheduler DRIVES the world externally: `createScheduler(world, systems).update(dt)`.
3
+ // @ecsia/core NEVER imports @ecsia/scheduler — so rather than a core→scheduler import, the scheduler
4
+ // holds the World and calls its public lifecycle verbs (frameReset / mergeCorrals /
5
+ // maintainStructural / observerDrain / flushLogs / query / phase). A `world.setUpdate(fn)` seam was
6
+ // rejected in favour of this external driver because it keeps the acyclic graph trivially obvious and
7
+ // needs no new core surface.
8
+ import { lowerSystems, aggregateAccess } from '../planner/index.js';
9
+ import { resolveOrdering, buildEdges, buildDAG, buildPlan } from '../graph/index.js';
10
+ import { directApplySink } from '../commands/index.js';
11
+ import { buildScopedQueries } from './run-wave.js';
12
+ import { runUpdate } from './update.js';
13
+ import { runUpdateThreaded } from './update-threaded.js';
14
+ import { IS_DEV } from '@ecsia/core';
15
+ function strideFor(systems, registeredComponentCount) {
16
+ if (registeredComponentCount !== undefined)
17
+ return Math.max(1, Math.ceil(registeredComponentCount / 32));
18
+ let maxId = 0;
19
+ for (const sb of systems) {
20
+ for (const c of [...sb.readIds, ...sb.writeIds]) {
21
+ if (c > maxId)
22
+ maxId = c;
23
+ }
24
+ }
25
+ return Math.max(1, Math.ceil((maxId + 1) / 32));
26
+ }
27
+ /**
28
+ * Build the immutable plan from lowered, ordering-resolved SystemBoxes. The full pipeline:
29
+ * aggregate access → derive weighted conflict edges → cycle-detect + transitively reduce → extract
30
+ * waves + pack batches (WAVE-CONFLICT). Fails fast on a cyclic dependency (CycleError).
31
+ */
32
+ export function buildSchedulePlan(systems, opts) {
33
+ if (systems.length === 0) {
34
+ return Object.freeze({
35
+ waves: [],
36
+ systems,
37
+ accessStrideWords: opts.accessStrideWords,
38
+ workers: opts.workers,
39
+ });
40
+ }
41
+ const defs = systems.map((sb) => sb.def);
42
+ const access = aggregateAccess(systems);
43
+ const edges = buildEdges(systems, defs, access);
44
+ const dag = buildDAG(systems, edges);
45
+ return buildPlan(systems, dag, opts.accessStrideWords, opts.workers);
46
+ }
47
+ export function createScheduler(world, defs, opts) {
48
+ const workers = opts?.workers ?? 0;
49
+ const dev = opts?.dev ?? IS_DEV;
50
+ const accessStrideWords = strideFor(lowerSystems(defs, 1), opts?.registeredComponentCount);
51
+ const systems = resolveOrdering(lowerSystems(defs, accessStrideWords), defs);
52
+ const plan = buildSchedulePlan(systems, { accessStrideWords, workers });
53
+ const env = {
54
+ world,
55
+ dev,
56
+ commands: directApplySink,
57
+ observerCadence: world.options.reactivity.observerCadence,
58
+ systems: plan.systems,
59
+ scopedQueries: buildScopedQueries(world, plan.systems, dev),
60
+ };
61
+ return {
62
+ plan,
63
+ update(dt = 0) {
64
+ runUpdate(env, plan, dt);
65
+ },
66
+ updateThreaded(pool, dt = 0) {
67
+ return runUpdateThreaded(env, plan, pool, dt);
68
+ },
69
+ };
70
+ }
71
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/executor/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { Tick } from '@ecsia/schema';
2
+ import type { SystemBatch } from '../graph/index.js';
3
+ export type WorkerMode = 'single' | 'sab' | 'no-sab';
4
+ /** SAB control block for one round's completion fence. */
5
+ export interface WaveCounter {
6
+ readonly sab: SharedArrayBuffer;
7
+ readonly view: Int32Array;
8
+ }
9
+ export interface WaveSync {
10
+ /** Reset the counter to `batchCount` and bump the epoch. Main thread, before dispatch. */
11
+ begin(c: WaveCounter, batchCount: number): void;
12
+ /** Worker side (body ): Atomics.sub(remaining,1); if 0, Atomics.notify(epoch). */
13
+ complete(c: WaveCounter): void;
14
+ /** Main thread: wait until remaining === 0. Tier chosen by capability probe. */
15
+ await(c: WaveCounter): Promise<void> | void;
16
+ }
17
+ export interface WaveSyncTierProbe {
18
+ readonly waitAsync: boolean;
19
+ readonly waitBlocking: boolean;
20
+ readonly sabAvailable: boolean;
21
+ }
22
+ export type WaveSyncTier = 'waitAsync' | 'coordinator-block' | 'promise-poll' | 'postMessage';
23
+ /**: choose the three-tier wait implementation once at world creation from the capability probe. */
24
+ export declare function selectWaitTier(caps: WaveSyncTierProbe): WaveSyncTier;
25
+ export interface WorkerHandle {
26
+ readonly index: number;
27
+ /** (plain AB, worker-local). Typed loosely until fills the CommandBuffer. */
28
+ readonly commandBuffer: unknown;
29
+ /** (plain AB, worker-local). */
30
+ readonly writeCorral: Uint32Array;
31
+ }
32
+ export interface WorkerDispatch {
33
+ /** Post a batch's systemId + ctx slice to a worker. Worker runs runSystem then WaveSync.complete (body ). */
34
+ dispatch(w: WorkerHandle, batch: SystemBatch, dt: number, tick: Tick): void;
35
+ readonly workers: readonly WorkerHandle[];
36
+ readonly mode: WorkerMode;
37
+ }
38
+ //# sourceMappingURL=seams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seams.d.ts","sourceRoot":"","sources":["../../src/executor/seams.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAA;AAEpD,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAK1B;AAED,MAAM,WAAW,QAAQ;IACvB,0FAA0F;IAC1F,KAAK,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/C,kFAAkF;IAClF,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC9B,gFAAgF;IAChF,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,mBAAmB,GAAG,cAAc,GAAG,aAAa,CAAA;AAE7F,mGAAmG;AACnG,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,YAAY,CAKpE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,gCAAgC;IAChC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,6GAA6G;IAC7G,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IAC3E,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IACzC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAC1B"}
@@ -0,0 +1,16 @@
1
+ // Parallel-ready seams — INTERFACES ONLY. The single-thread executor is the
2
+ // normative semantics; these contracts let the worker layer slot in with no public-API change.
3
+ // This file ships only the type declarations + `selectWaitTier` so the plan already knows the
4
+ // tier; the workers/ layer fills the bodies (WaveSync.complete, WorkerDispatch.dispatch, the
5
+ // coordinator worker). NO Atomics, NO worker bodies here.
6
+ /**: choose the three-tier wait implementation once at world creation from the capability probe. */
7
+ export function selectWaitTier(caps) {
8
+ if (caps.waitAsync)
9
+ return 'waitAsync'; // tier 1: browser main thread, non-blocking
10
+ if (caps.waitBlocking)
11
+ return 'coordinator-block'; // tier 2: blocking Atomics.wait off main thread
12
+ if (caps.sabAvailable)
13
+ return 'promise-poll'; // tier 3: Atomics.load poll on microtask/setTimeout(0)
14
+ return 'postMessage'; // no SAB:
15
+ }
16
+ //# sourceMappingURL=seams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seams.js","sourceRoot":"","sources":["../../src/executor/seams.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+FAA+F;AAC/F,8FAA8F;AAC9F,6FAA6F;AAC7F,0DAA0D;AAkC1D,mGAAmG;AACnG,MAAM,UAAU,cAAc,CAAC,IAAuB;IACpD,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,WAAW,CAAA,CAAC,4CAA4C;IACnF,IAAI,IAAI,CAAC,YAAY;QAAE,OAAO,mBAAmB,CAAA,CAAC,gDAAgD;IAClG,IAAI,IAAI,CAAC,YAAY;QAAE,OAAO,cAAc,CAAA,CAAC,uDAAuD;IACpG,OAAO,aAAa,CAAA,CAAC,UAAU;AACjC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { SchedulePlan } from '../graph/index.js';
2
+ import type { ExecutorEnv } from './run-wave.js';
3
+ /** The slice of WorkerPool the threaded executor drives. Kept structural to avoid a hard dependency
4
+ * cycle on the concrete pool (the workers layer is the deeper sibling). */
5
+ export interface RoundDispatcher {
6
+ runRound(batches: readonly {
7
+ systemId: import('@ecsia/schema').SystemId;
8
+ workerIndex: number;
9
+ }[], dt: number): Promise<void>;
10
+ }
11
+ /**
12
+ * Run one threaded tick: the whole schedule (worker waves) + reactivity flush. The frame order is
13
+ * byte-identical to the single-thread runUpdate (frameReset → waves → observerDrain → flushLogs);
14
+ * the only difference is that each round's worker batches run on workers.
15
+ */
16
+ export declare function runUpdateThreaded(env: ExecutorEnv, plan: SchedulePlan, pool: RoundDispatcher, dt: number): Promise<void>;
17
+ //# sourceMappingURL=update-threaded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-threaded.d.ts","sourceRoot":"","sources":["../../src/executor/update-threaded.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAA6B,MAAM,mBAAmB,CAAA;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAIhD;2EAC2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,EAAE,OAAO,eAAe,EAAE,QAAQ,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7H;AAmCD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc9H"}