dag-ml-wasm 0.2.6 → 0.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.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Browser-friendly bindings for DAG-ML JSON contracts.
4
4
 
5
- The WASM package exposes validation, DSL compilation and execution-plan
6
- construction over UTF-8 JSON strings. It intentionally excludes host controller
7
- execution, artifacts and data-buffer ownership.
5
+ The WASM package exposes validation, DSL compilation, execution-plan
6
+ construction and synchronous host-controller execution over UTF-8 JSON strings.
7
+ Artifacts and data-buffer ownership remain outside the binding.
8
8
 
9
9
  `contract_manifest_json()` returns a stable JSON manifest with the package
10
10
  version, supported contract ids, exported Python/WASM function names and shared
@@ -27,7 +27,9 @@ node scripts/smoke_wasm_web_bindings.mjs "$web_out_dir"
27
27
 
28
28
  ```js
29
29
  import init, {
30
+ LocalImplementationRegistry,
30
31
  contract_manifest_json,
32
+ loss_execution_attestation_json,
31
33
  validate_pipeline_dsl_json,
32
34
  compile_pipeline_dsl_artifact_json,
33
35
  } from "./pkg/dag_ml_wasm.js";
@@ -38,6 +40,84 @@ validate_pipeline_dsl_json(JSON.stringify(dsl));
38
40
  const artifact = JSON.parse(compile_pipeline_dsl_artifact_json(JSON.stringify(dsl)));
39
41
  ```
40
42
 
43
+ Local JavaScript losses and metrics are retained by a WASM registry and never
44
+ serialized into DAG-ML contracts:
45
+
46
+ ```js
47
+ const implementations = new LocalImplementationRegistry();
48
+ implementations.register_loss(JSON.stringify(lossReference), weightedLoss);
49
+
50
+ const loss = implementations.resolve_training_loss(
51
+ JSON.stringify(trainingLossRole),
52
+ "FIT_CV",
53
+ );
54
+ const value = loss(target, prediction);
55
+ const attestation = JSON.parse(
56
+ loss_execution_attestation_json(JSON.stringify(trainingLossRole), "FIT_CV"),
57
+ );
58
+ ```
59
+
60
+ Controllers should bind from the native `NodeTask` rather than resolving a
61
+ role and constructing lineage independently:
62
+
63
+ ```js
64
+ const binding = implementations.bind_training_loss(
65
+ JSON.stringify(nodeTask),
66
+ 0,
67
+ );
68
+ const loss = binding.invoke;
69
+ const value = loss(target, prediction);
70
+ const requiredAttestation = JSON.parse(binding.required_attestation_json);
71
+ binding.free();
72
+ ```
73
+
74
+ The role index is zero-based. Binding validates that the task's ordered loss
75
+ requirements exactly match its active roles. A controller may copy the returned
76
+ attestation into `NodeResult.lineage.loss_attestations` only after `loss(...)`
77
+ returns successfully.
78
+
79
+ For scheduler execution, lower the roles into the native plan and execute that
80
+ plan rather than rebuilding a loss-free campaign plan:
81
+
82
+ ```js
83
+ const planJson = build_execution_plan_with_training_losses_json(
84
+ planId,
85
+ JSON.stringify(graph),
86
+ JSON.stringify(campaign),
87
+ JSON.stringify(controllerManifests),
88
+ JSON.stringify(trainingLossRoles),
89
+ );
90
+
91
+ const resultsJson = execute_execution_plan_phase_json(
92
+ planJson,
93
+ JSON.stringify(controllerManifests),
94
+ runId,
95
+ rootSeed,
96
+ "FIT_CV",
97
+ (controllerId, taskJson, exactSeed) =>
98
+ controller.invoke(controllerId, taskJson, exactSeed),
99
+ );
100
+ ```
101
+
102
+ The native lowerer replaces all plan loss roles, groups them by node and sorts
103
+ them canonically before validating controller capabilities. At execution, every
104
+ manifest embedded in the plan must exactly match the independently supplied
105
+ trusted controller registry before any callback runs. The scheduler then checks
106
+ that each callback result contains exactly the task's required loss attestations
107
+ in the same order.
108
+
109
+ The callback's `exactSeed` argument is a decimal string (or `null`), avoiding
110
+ precision loss for native `u64` seeds beyond JavaScript's safe-integer range.
111
+ The callback may set `NodeResult.lineage.seed` to `null`; the WASM bridge then
112
+ injects the authoritative native seed before scheduler validation. The returned
113
+ `resultsJson` still contains native numeric `u64` values; use a lossless JSON
114
+ integer parser, or preserve the raw JSON, when inspecting lineage seeds exactly.
115
+
116
+ JavaScript-local descriptors use `binding:javascript` and a `host_local` or
117
+ `portable_registered` lifecycle. A Web Worker must populate its own registry;
118
+ functions are not cloned, posted, or embedded in replay artifacts. Resolution
119
+ is rejected when the exact descriptor or phase does not match.
120
+
41
121
  Rust-side validation failures are returned as JSON strings with the ADR-11
42
122
  descriptor fields `category`, `code`, `severity`, `message`,
43
123
  `remediation_hint` and `context`.
package/dag_ml_wasm.d.ts CHANGED
@@ -1,8 +1,40 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
 
4
+ export class LocalImplementationRegistry {
5
+ free(): void;
6
+ [Symbol.dispose](): void;
7
+ bind_training_loss(node_task_json: string, role_index: number): TrainingLossBinding;
8
+ clear(): void;
9
+ descriptors_json(): string;
10
+ constructor();
11
+ register_loss(loss_reference_json: string, implementation: Function): void;
12
+ register_metric(metric_reference_json: string, implementation: Function): void;
13
+ resolve_loss(loss_reference_json: string): Function;
14
+ resolve_metric(metric_reference_json: string): Function;
15
+ resolve_training_loss(training_loss_role_json: string, phase: string): Function;
16
+ toJSON(): any;
17
+ unregister_loss(loss_reference_json: string): Function;
18
+ unregister_metric(metric_reference_json: string): Function;
19
+ readonly size: number;
20
+ }
21
+
22
+ export class TrainingLossBinding {
23
+ private constructor();
24
+ free(): void;
25
+ [Symbol.dispose](): void;
26
+ readonly invoke: Function;
27
+ readonly required_attestation_json: string;
28
+ }
29
+
4
30
  export function build_execution_plan_json(plan_id: string, graph_json: string, campaign_json: string, controller_manifests_json: string): string;
5
31
 
32
+ /**
33
+ * Build an execution plan and lower an explicit set of native training-loss
34
+ * roles into its node plans. The supplied set replaces every node's roles.
35
+ */
36
+ export function build_execution_plan_with_training_losses_json(plan_id: string, graph_json: string, campaign_json: string, controller_manifests_json: string, training_loss_roles_json: string): string;
37
+
6
38
  export function compile_pipeline_dsl_artifact_json(json: string): string;
7
39
 
8
40
  export function compile_pipeline_dsl_artifact_with_controllers_json(dsl_json: string, controller_manifests_json: string): string;
@@ -24,13 +56,25 @@ export function derive_controller_manifest_list_json(host_controller_specs_json:
24
56
  * - `graph_json` / `campaign_json` / `controller_manifests_json`: the same
25
57
  * inputs as [`build_execution_plan_json`]. The campaign's
26
58
  * `split_invocation.fold_set` drives the FIT_CV fold loop.
27
- * - `js_invoke`: `(controllerId: string, taskJson: string) => nodeResultJson: string`,
28
- * **synchronous** (no `await` across this boundary).
59
+ * - `js_invoke`: `(controllerId: string, taskJson: string, exactSeed: string | null)
60
+ * => nodeResultJson: string`, **synchronous** (no `await` across this boundary).
61
+ * A callback may return `lineage.seed: null`; the bridge injects the native
62
+ * `u64` from the task before scheduler validation.
29
63
  *
30
64
  * Returns the phase's `Vec<NodeResult>` as JSON (predictions + lineage).
31
65
  */
32
66
  export function execute_campaign_phase_json(plan_id: string, graph_json: string, campaign_json: string, controller_manifests_json: string, run_id: string, root_seed: number, phase: string, js_invoke: Function): string;
33
67
 
68
+ /**
69
+ * Execute one phase from a previously built and validated execution plan.
70
+ *
71
+ * Unlike [`execute_campaign_phase_json`], this preserves native training-loss
72
+ * roles already lowered into `NodePlan.training_losses`. Every embedded
73
+ * controller manifest must exactly match the independently supplied trusted
74
+ * runtime registry before any callback is dispatched.
75
+ */
76
+ export function execute_execution_plan_phase_json(execution_plan_json: string, trusted_controller_manifests_json: string, run_id: string, root_seed: number, phase: string, js_invoke: Function): string;
77
+
34
78
  export function fold_set_fingerprint_json(json: string): string;
35
79
 
36
80
  /**
@@ -39,6 +83,8 @@ export function fold_set_fingerprint_json(json: string): string;
39
83
  */
40
84
  export function kfold_split_json(spec_json: string, sample_ids_json: string, id: string): string;
41
85
 
86
+ export function loss_execution_attestation_json(training_loss_role_json: string, phase: string): string;
87
+
42
88
  /**
43
89
  * Rank candidate variants and return the winner — the SELECT phase for in-browser
44
90
  * generators/finetune. Selection stays in dag-ml (deterministic argmin/argmax +
@@ -75,7 +121,26 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
75
121
 
76
122
  export interface InitOutput {
77
123
  readonly memory: WebAssembly.Memory;
124
+ readonly __wbg_localimplementationregistry_free: (a: number, b: number) => void;
125
+ readonly __wbg_traininglossbinding_free: (a: number, b: number) => void;
126
+ readonly localimplementationregistry_bind_training_loss: (a: number, b: number, c: number, d: any) => [number, number, number];
127
+ readonly localimplementationregistry_clear: (a: number) => void;
128
+ readonly localimplementationregistry_descriptors_json: (a: number) => [number, number, number, number];
129
+ readonly localimplementationregistry_new: () => number;
130
+ readonly localimplementationregistry_register_loss: (a: number, b: number, c: number, d: any) => [number, number];
131
+ readonly localimplementationregistry_register_metric: (a: number, b: number, c: number, d: any) => [number, number];
132
+ readonly localimplementationregistry_resolve_loss: (a: number, b: number, c: number) => [number, number, number];
133
+ readonly localimplementationregistry_resolve_metric: (a: number, b: number, c: number) => [number, number, number];
134
+ readonly localimplementationregistry_resolve_training_loss: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
135
+ readonly localimplementationregistry_size: (a: number) => number;
136
+ readonly localimplementationregistry_toJSON: (a: number) => [number, number, number];
137
+ readonly localimplementationregistry_unregister_loss: (a: number, b: number, c: number) => [number, number, number];
138
+ readonly localimplementationregistry_unregister_metric: (a: number, b: number, c: number) => [number, number, number];
139
+ readonly loss_execution_attestation_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
140
+ readonly traininglossbinding_invoke: (a: number) => any;
141
+ readonly traininglossbinding_required_attestation_json: (a: number) => [number, number];
78
142
  readonly build_execution_plan_json: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number, number, number];
143
+ readonly build_execution_plan_with_training_losses_json: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number, number, number];
79
144
  readonly compile_pipeline_dsl_artifact_json: (a: number, b: number) => [number, number, number, number];
80
145
  readonly compile_pipeline_dsl_artifact_with_controllers_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
81
146
  readonly compile_pipeline_dsl_graph_json: (a: number, b: number) => [number, number, number, number];
@@ -84,6 +149,7 @@ export interface InitOutput {
84
149
  readonly derive_controller_manifest_json: (a: number, b: number) => [number, number, number, number];
85
150
  readonly derive_controller_manifest_list_json: (a: number, b: number) => [number, number, number, number];
86
151
  readonly execute_campaign_phase_json: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: any) => [number, number, number, number];
152
+ readonly execute_execution_plan_phase_json: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: any) => [number, number, number, number];
87
153
  readonly fold_set_fingerprint_json: (a: number, b: number) => [number, number, number, number];
88
154
  readonly kfold_split_json: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
89
155
  readonly select_candidates_json: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
package/dag_ml_wasm.js CHANGED
@@ -1,5 +1,214 @@
1
1
  /* @ts-self-types="./dag_ml_wasm.d.ts" */
2
2
 
3
+ export class LocalImplementationRegistry {
4
+ __destroy_into_raw() {
5
+ const ptr = this.__wbg_ptr;
6
+ this.__wbg_ptr = 0;
7
+ LocalImplementationRegistryFinalization.unregister(this);
8
+ return ptr;
9
+ }
10
+ free() {
11
+ const ptr = this.__destroy_into_raw();
12
+ wasm.__wbg_localimplementationregistry_free(ptr, 0);
13
+ }
14
+ /**
15
+ * @param {string} node_task_json
16
+ * @param {number} role_index
17
+ * @returns {TrainingLossBinding}
18
+ */
19
+ bind_training_loss(node_task_json, role_index) {
20
+ const ptr0 = passStringToWasm0(node_task_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
21
+ const len0 = WASM_VECTOR_LEN;
22
+ const ret = wasm.localimplementationregistry_bind_training_loss(this.__wbg_ptr, ptr0, len0, role_index);
23
+ if (ret[2]) {
24
+ throw takeFromExternrefTable0(ret[1]);
25
+ }
26
+ return TrainingLossBinding.__wrap(ret[0]);
27
+ }
28
+ clear() {
29
+ wasm.localimplementationregistry_clear(this.__wbg_ptr);
30
+ }
31
+ /**
32
+ * @returns {string}
33
+ */
34
+ descriptors_json() {
35
+ let deferred2_0;
36
+ let deferred2_1;
37
+ try {
38
+ const ret = wasm.localimplementationregistry_descriptors_json(this.__wbg_ptr);
39
+ var ptr1 = ret[0];
40
+ var len1 = ret[1];
41
+ if (ret[3]) {
42
+ ptr1 = 0; len1 = 0;
43
+ throw takeFromExternrefTable0(ret[2]);
44
+ }
45
+ deferred2_0 = ptr1;
46
+ deferred2_1 = len1;
47
+ return getStringFromWasm0(ptr1, len1);
48
+ } finally {
49
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
50
+ }
51
+ }
52
+ constructor() {
53
+ const ret = wasm.localimplementationregistry_new();
54
+ this.__wbg_ptr = ret;
55
+ LocalImplementationRegistryFinalization.register(this, this.__wbg_ptr, this);
56
+ return this;
57
+ }
58
+ /**
59
+ * @param {string} loss_reference_json
60
+ * @param {Function} implementation
61
+ */
62
+ register_loss(loss_reference_json, implementation) {
63
+ const ptr0 = passStringToWasm0(loss_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
64
+ const len0 = WASM_VECTOR_LEN;
65
+ const ret = wasm.localimplementationregistry_register_loss(this.__wbg_ptr, ptr0, len0, implementation);
66
+ if (ret[1]) {
67
+ throw takeFromExternrefTable0(ret[0]);
68
+ }
69
+ }
70
+ /**
71
+ * @param {string} metric_reference_json
72
+ * @param {Function} implementation
73
+ */
74
+ register_metric(metric_reference_json, implementation) {
75
+ const ptr0 = passStringToWasm0(metric_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
76
+ const len0 = WASM_VECTOR_LEN;
77
+ const ret = wasm.localimplementationregistry_register_metric(this.__wbg_ptr, ptr0, len0, implementation);
78
+ if (ret[1]) {
79
+ throw takeFromExternrefTable0(ret[0]);
80
+ }
81
+ }
82
+ /**
83
+ * @param {string} loss_reference_json
84
+ * @returns {Function}
85
+ */
86
+ resolve_loss(loss_reference_json) {
87
+ const ptr0 = passStringToWasm0(loss_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
88
+ const len0 = WASM_VECTOR_LEN;
89
+ const ret = wasm.localimplementationregistry_resolve_loss(this.__wbg_ptr, ptr0, len0);
90
+ if (ret[2]) {
91
+ throw takeFromExternrefTable0(ret[1]);
92
+ }
93
+ return takeFromExternrefTable0(ret[0]);
94
+ }
95
+ /**
96
+ * @param {string} metric_reference_json
97
+ * @returns {Function}
98
+ */
99
+ resolve_metric(metric_reference_json) {
100
+ const ptr0 = passStringToWasm0(metric_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
101
+ const len0 = WASM_VECTOR_LEN;
102
+ const ret = wasm.localimplementationregistry_resolve_metric(this.__wbg_ptr, ptr0, len0);
103
+ if (ret[2]) {
104
+ throw takeFromExternrefTable0(ret[1]);
105
+ }
106
+ return takeFromExternrefTable0(ret[0]);
107
+ }
108
+ /**
109
+ * @param {string} training_loss_role_json
110
+ * @param {string} phase
111
+ * @returns {Function}
112
+ */
113
+ resolve_training_loss(training_loss_role_json, phase) {
114
+ const ptr0 = passStringToWasm0(training_loss_role_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
115
+ const len0 = WASM_VECTOR_LEN;
116
+ const ptr1 = passStringToWasm0(phase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
117
+ const len1 = WASM_VECTOR_LEN;
118
+ const ret = wasm.localimplementationregistry_resolve_training_loss(this.__wbg_ptr, ptr0, len0, ptr1, len1);
119
+ if (ret[2]) {
120
+ throw takeFromExternrefTable0(ret[1]);
121
+ }
122
+ return takeFromExternrefTable0(ret[0]);
123
+ }
124
+ /**
125
+ * @returns {number}
126
+ */
127
+ get size() {
128
+ const ret = wasm.localimplementationregistry_size(this.__wbg_ptr);
129
+ return ret >>> 0;
130
+ }
131
+ /**
132
+ * @returns {any}
133
+ */
134
+ toJSON() {
135
+ const ret = wasm.localimplementationregistry_toJSON(this.__wbg_ptr);
136
+ if (ret[2]) {
137
+ throw takeFromExternrefTable0(ret[1]);
138
+ }
139
+ return takeFromExternrefTable0(ret[0]);
140
+ }
141
+ /**
142
+ * @param {string} loss_reference_json
143
+ * @returns {Function}
144
+ */
145
+ unregister_loss(loss_reference_json) {
146
+ const ptr0 = passStringToWasm0(loss_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
147
+ const len0 = WASM_VECTOR_LEN;
148
+ const ret = wasm.localimplementationregistry_unregister_loss(this.__wbg_ptr, ptr0, len0);
149
+ if (ret[2]) {
150
+ throw takeFromExternrefTable0(ret[1]);
151
+ }
152
+ return takeFromExternrefTable0(ret[0]);
153
+ }
154
+ /**
155
+ * @param {string} metric_reference_json
156
+ * @returns {Function}
157
+ */
158
+ unregister_metric(metric_reference_json) {
159
+ const ptr0 = passStringToWasm0(metric_reference_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
160
+ const len0 = WASM_VECTOR_LEN;
161
+ const ret = wasm.localimplementationregistry_unregister_metric(this.__wbg_ptr, ptr0, len0);
162
+ if (ret[2]) {
163
+ throw takeFromExternrefTable0(ret[1]);
164
+ }
165
+ return takeFromExternrefTable0(ret[0]);
166
+ }
167
+ }
168
+ if (Symbol.dispose) LocalImplementationRegistry.prototype[Symbol.dispose] = LocalImplementationRegistry.prototype.free;
169
+
170
+ export class TrainingLossBinding {
171
+ static __wrap(ptr) {
172
+ const obj = Object.create(TrainingLossBinding.prototype);
173
+ obj.__wbg_ptr = ptr;
174
+ TrainingLossBindingFinalization.register(obj, obj.__wbg_ptr, obj);
175
+ return obj;
176
+ }
177
+ __destroy_into_raw() {
178
+ const ptr = this.__wbg_ptr;
179
+ this.__wbg_ptr = 0;
180
+ TrainingLossBindingFinalization.unregister(this);
181
+ return ptr;
182
+ }
183
+ free() {
184
+ const ptr = this.__destroy_into_raw();
185
+ wasm.__wbg_traininglossbinding_free(ptr, 0);
186
+ }
187
+ /**
188
+ * @returns {Function}
189
+ */
190
+ get invoke() {
191
+ const ret = wasm.traininglossbinding_invoke(this.__wbg_ptr);
192
+ return ret;
193
+ }
194
+ /**
195
+ * @returns {string}
196
+ */
197
+ get required_attestation_json() {
198
+ let deferred1_0;
199
+ let deferred1_1;
200
+ try {
201
+ const ret = wasm.traininglossbinding_required_attestation_json(this.__wbg_ptr);
202
+ deferred1_0 = ret[0];
203
+ deferred1_1 = ret[1];
204
+ return getStringFromWasm0(ret[0], ret[1]);
205
+ } finally {
206
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
207
+ }
208
+ }
209
+ }
210
+ if (Symbol.dispose) TrainingLossBinding.prototype[Symbol.dispose] = TrainingLossBinding.prototype.free;
211
+
3
212
  /**
4
213
  * @param {string} plan_id
5
214
  * @param {string} graph_json
@@ -34,6 +243,45 @@ export function build_execution_plan_json(plan_id, graph_json, campaign_json, co
34
243
  }
35
244
  }
36
245
 
246
+ /**
247
+ * Build an execution plan and lower an explicit set of native training-loss
248
+ * roles into its node plans. The supplied set replaces every node's roles.
249
+ * @param {string} plan_id
250
+ * @param {string} graph_json
251
+ * @param {string} campaign_json
252
+ * @param {string} controller_manifests_json
253
+ * @param {string} training_loss_roles_json
254
+ * @returns {string}
255
+ */
256
+ export function build_execution_plan_with_training_losses_json(plan_id, graph_json, campaign_json, controller_manifests_json, training_loss_roles_json) {
257
+ let deferred7_0;
258
+ let deferred7_1;
259
+ try {
260
+ const ptr0 = passStringToWasm0(plan_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
261
+ const len0 = WASM_VECTOR_LEN;
262
+ const ptr1 = passStringToWasm0(graph_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
263
+ const len1 = WASM_VECTOR_LEN;
264
+ const ptr2 = passStringToWasm0(campaign_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
265
+ const len2 = WASM_VECTOR_LEN;
266
+ const ptr3 = passStringToWasm0(controller_manifests_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
267
+ const len3 = WASM_VECTOR_LEN;
268
+ const ptr4 = passStringToWasm0(training_loss_roles_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
269
+ const len4 = WASM_VECTOR_LEN;
270
+ const ret = wasm.build_execution_plan_with_training_losses_json(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
271
+ var ptr6 = ret[0];
272
+ var len6 = ret[1];
273
+ if (ret[3]) {
274
+ ptr6 = 0; len6 = 0;
275
+ throw takeFromExternrefTable0(ret[2]);
276
+ }
277
+ deferred7_0 = ptr6;
278
+ deferred7_1 = len6;
279
+ return getStringFromWasm0(ptr6, len6);
280
+ } finally {
281
+ wasm.__wbindgen_free(deferred7_0, deferred7_1, 1);
282
+ }
283
+ }
284
+
37
285
  /**
38
286
  * @param {string} json
39
287
  * @returns {string}
@@ -207,8 +455,10 @@ export function derive_controller_manifest_list_json(host_controller_specs_json)
207
455
  * - `graph_json` / `campaign_json` / `controller_manifests_json`: the same
208
456
  * inputs as [`build_execution_plan_json`]. The campaign's
209
457
  * `split_invocation.fold_set` drives the FIT_CV fold loop.
210
- * - `js_invoke`: `(controllerId: string, taskJson: string) => nodeResultJson: string`,
211
- * **synchronous** (no `await` across this boundary).
458
+ * - `js_invoke`: `(controllerId: string, taskJson: string, exactSeed: string | null)
459
+ * => nodeResultJson: string`, **synchronous** (no `await` across this boundary).
460
+ * A callback may return `lineage.seed: null`; the bridge injects the native
461
+ * `u64` from the task before scheduler validation.
212
462
  *
213
463
  * Returns the phase's `Vec<NodeResult>` as JSON (predictions + lineage).
214
464
  * @param {string} plan_id
@@ -252,6 +502,48 @@ export function execute_campaign_phase_json(plan_id, graph_json, campaign_json,
252
502
  }
253
503
  }
254
504
 
505
+ /**
506
+ * Execute one phase from a previously built and validated execution plan.
507
+ *
508
+ * Unlike [`execute_campaign_phase_json`], this preserves native training-loss
509
+ * roles already lowered into `NodePlan.training_losses`. Every embedded
510
+ * controller manifest must exactly match the independently supplied trusted
511
+ * runtime registry before any callback is dispatched.
512
+ * @param {string} execution_plan_json
513
+ * @param {string} trusted_controller_manifests_json
514
+ * @param {string} run_id
515
+ * @param {number} root_seed
516
+ * @param {string} phase
517
+ * @param {Function} js_invoke
518
+ * @returns {string}
519
+ */
520
+ export function execute_execution_plan_phase_json(execution_plan_json, trusted_controller_manifests_json, run_id, root_seed, phase, js_invoke) {
521
+ let deferred6_0;
522
+ let deferred6_1;
523
+ try {
524
+ const ptr0 = passStringToWasm0(execution_plan_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
525
+ const len0 = WASM_VECTOR_LEN;
526
+ const ptr1 = passStringToWasm0(trusted_controller_manifests_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
527
+ const len1 = WASM_VECTOR_LEN;
528
+ const ptr2 = passStringToWasm0(run_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
529
+ const len2 = WASM_VECTOR_LEN;
530
+ const ptr3 = passStringToWasm0(phase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
531
+ const len3 = WASM_VECTOR_LEN;
532
+ const ret = wasm.execute_execution_plan_phase_json(ptr0, len0, ptr1, len1, ptr2, len2, root_seed, ptr3, len3, js_invoke);
533
+ var ptr5 = ret[0];
534
+ var len5 = ret[1];
535
+ if (ret[3]) {
536
+ ptr5 = 0; len5 = 0;
537
+ throw takeFromExternrefTable0(ret[2]);
538
+ }
539
+ deferred6_0 = ptr5;
540
+ deferred6_1 = len5;
541
+ return getStringFromWasm0(ptr5, len5);
542
+ } finally {
543
+ wasm.__wbindgen_free(deferred6_0, deferred6_1, 1);
544
+ }
545
+ }
546
+
255
547
  /**
256
548
  * @param {string} json
257
549
  * @returns {string}
@@ -310,6 +602,34 @@ export function kfold_split_json(spec_json, sample_ids_json, id) {
310
602
  }
311
603
  }
312
604
 
605
+ /**
606
+ * @param {string} training_loss_role_json
607
+ * @param {string} phase
608
+ * @returns {string}
609
+ */
610
+ export function loss_execution_attestation_json(training_loss_role_json, phase) {
611
+ let deferred4_0;
612
+ let deferred4_1;
613
+ try {
614
+ const ptr0 = passStringToWasm0(training_loss_role_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
615
+ const len0 = WASM_VECTOR_LEN;
616
+ const ptr1 = passStringToWasm0(phase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
617
+ const len1 = WASM_VECTOR_LEN;
618
+ const ret = wasm.loss_execution_attestation_json(ptr0, len0, ptr1, len1);
619
+ var ptr3 = ret[0];
620
+ var len3 = ret[1];
621
+ if (ret[3]) {
622
+ ptr3 = 0; len3 = 0;
623
+ throw takeFromExternrefTable0(ret[2]);
624
+ }
625
+ deferred4_0 = ptr3;
626
+ deferred4_1 = len3;
627
+ return getStringFromWasm0(ptr3, len3);
628
+ } finally {
629
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
630
+ }
631
+ }
632
+
313
633
  /**
314
634
  * Rank candidate variants and return the winner — the SELECT phase for in-browser
315
635
  * generators/finetune. Selection stays in dag-ml (deterministic argmin/argmax +
@@ -488,6 +808,12 @@ function __wbg_get_imports() {
488
808
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
489
809
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
490
810
  },
811
+ __wbg___wbindgen_number_get_394265ed1e1b84ee: function(arg0, arg1) {
812
+ const obj = arg1;
813
+ const ret = typeof(obj) === 'number' ? obj : undefined;
814
+ getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
815
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
816
+ },
491
817
  __wbg___wbindgen_string_get_b0ca35b86a603356: function(arg0, arg1) {
492
818
  const obj = arg1;
493
819
  const ret = typeof(obj) === 'string' ? obj : undefined;
@@ -499,8 +825,8 @@ function __wbg_get_imports() {
499
825
  __wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
500
826
  throw new Error(getStringFromWasm0(arg0, arg1));
501
827
  },
502
- __wbg_call_e3b662382210db98: function() { return handleError(function (arg0, arg1, arg2, arg3) {
503
- const ret = arg0.call(arg1, arg2, arg3);
828
+ __wbg_call_44b7209e1e252e6a: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
829
+ const ret = arg0.call(arg1, arg2, arg3, arg4);
504
830
  return ret;
505
831
  }, arguments); },
506
832
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
@@ -524,6 +850,13 @@ function __wbg_get_imports() {
524
850
  };
525
851
  }
526
852
 
853
+ const LocalImplementationRegistryFinalization = (typeof FinalizationRegistry === 'undefined')
854
+ ? { register: () => {}, unregister: () => {} }
855
+ : new FinalizationRegistry(ptr => wasm.__wbg_localimplementationregistry_free(ptr, 1));
856
+ const TrainingLossBindingFinalization = (typeof FinalizationRegistry === 'undefined')
857
+ ? { register: () => {}, unregister: () => {} }
858
+ : new FinalizationRegistry(ptr => wasm.__wbg_traininglossbinding_free(ptr, 1));
859
+
527
860
  function addToExternrefTable0(obj) {
528
861
  const idx = wasm.__externref_table_alloc();
529
862
  wasm.__wbindgen_externrefs.set(idx, obj);
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "G. Beurier <beurier@cirad.fr>"
6
6
  ],
7
7
  "description": "WASM bindings for DAG-ML JSON contracts.",
8
- "version": "0.2.6",
8
+ "version": "0.3.0",
9
9
  "license": "CECILL-2.1 OR AGPL-3.0-or-later",
10
10
  "repository": {
11
11
  "type": "git",