@animastor/orchestration 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/package.json +51 -0
- package/src/host/host-bindings.js +138 -0
- package/src/index.js +99 -0
- package/src/orchestration/index.js +40 -0
- package/src/orchestration/orchestrator.js +630 -0
- package/src/orchestration/runtime-result-consumer.js +54 -0
- package/src/orchestration/scene-callbacks.js +542 -0
- package/src/orchestration/scene-orchestrator.js +601 -0
- package/src/orchestration/scene-restoration.js +129 -0
- package/src/orchestration/scene-utils.js +36 -0
- package/src/runtime/active-scenes-index.js +164 -0
- package/src/runtime/audio-fsm-port.js +187 -0
- package/src/runtime/circuit-breaker.js +588 -0
- package/src/runtime/counter-reconciliation.js +308 -0
- package/src/runtime/dispatch-engine.js +1768 -0
- package/src/runtime/failure-taxonomy.js +125 -0
- package/src/runtime/hub-cancel-port.js +122 -0
- package/src/runtime/layer-config-port.js +136 -0
- package/src/runtime/lease-manager.js +607 -0
- package/src/runtime/persistence-port.js +162 -0
- package/src/runtime/placeholder-audio-port.js +117 -0
- package/src/runtime/progress-events-port.js +121 -0
- package/src/runtime/reconciliation-engine.js +2405 -0
- package/src/runtime/retry-budget-manager.js +229 -0
- package/src/runtime/runtime-metrics.js +427 -0
- package/src/runtime/runtime-result-emitter.js +123 -0
- package/src/runtime/runtime-scheduler.js +629 -0
- package/src/runtime/scene-data-port.js +114 -0
- package/src/runtime/scene-window.js +827 -0
- package/src/runtime/video-fsm-port.js +189 -0
- package/src/runtime/worker-health.js +270 -0
- package/test/counter-reconciliation.test.js +164 -0
- package/test/mocks/redis-mock.js +221 -0
- package/test/test-bindings.js +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Animastor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @animastor/orchestration
|
|
2
|
+
|
|
3
|
+
Generation orchestration and runtime contour of the Animastor backend,
|
|
4
|
+
physically extracted from the host (`backend/src/orchestration/**` +
|
|
5
|
+
`backend/src/runtime/**` — §32.30; recon:
|
|
6
|
+
`docs/architecture/generation-module-extraction-reconnaissance.md` §32.29).
|
|
7
|
+
|
|
8
|
+
The package owns:
|
|
9
|
+
|
|
10
|
+
- the orchestration facade (stage executor + FSM-safe scene writers)
|
|
11
|
+
- the dispatch engine and its lease/quota/retry managers
|
|
12
|
+
- the reconciliation engine and counter reconciliation
|
|
13
|
+
- scene window/scheduler/worker-health
|
|
14
|
+
- the runtime-result emitter/consumer
|
|
15
|
+
- the eight O-2…O-10 port contracts (Persistence, SceneData,
|
|
16
|
+
PlaceholderAudio, ProgressEvents, AudioFsm, VideoFsm, HubCancel,
|
|
17
|
+
LayerConfig)
|
|
18
|
+
|
|
19
|
+
## Dependency direction
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
backend host → @animastor/orchestration → ports / host-bindings / contracts
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The package reaches the host (runtime config, Redis-domain state, media
|
|
26
|
+
facades, S-5 seam registry, artifact root, PW-2 workspace resolver)
|
|
27
|
+
**only** through the composition-root host-bindings seam — no
|
|
28
|
+
`backend/src` require, no storage/book/routes/services, no Redis, no PG,
|
|
29
|
+
no Express inside.
|
|
30
|
+
|
|
31
|
+
Runtime dependencies: `@animastor/contracts`, `@animastor/generation`,
|
|
32
|
+
`music-metadata`.
|
|
33
|
+
|
|
34
|
+
## Public API
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
const orchestration = require('@animastor/orchestration');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Export | Kind | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| orchestration facade | lazy | stage executor + FSM scene writers (begin/plan/dispatch/complete/fail/rollback) |
|
|
43
|
+
| `createRuntimeResultConsumer` | eager | Phase-5 result-reporting consumer |
|
|
44
|
+
| `ports` | eager | `{ persistence, sceneData, placeholderAudio, progressEvents, audioFsm, videoFsm, hubCancel, layerConfig }` |
|
|
45
|
+
| `bindHostModules` | eager | composition-root binding surface |
|
|
46
|
+
| `hostBinding` | eager | host-binding accessor |
|
|
47
|
+
| `runtime` | lazy namespace | `{ scheduler, activeScenes, reconciliation, dispatch, leaseManager, counterReconciliation, metrics, workerHealth, sceneWindow, failureTaxonomy, runtimeResultEmitter }` |
|
|
48
|
+
|
|
49
|
+
Facade exports are **lazy getters** — the FSM-writer re-exports resolve
|
|
50
|
+
the `stateOps` host binding on access. `Object.defineProperties` on the
|
|
51
|
+
root prevents eager evaluation at `require()` time.
|
|
52
|
+
|
|
53
|
+
Deep imports (`@animastor/orchestration/runtime/…` etc.) are NOT part of
|
|
54
|
+
the public surface — the exports map exposes only `'.'`.
|
|
55
|
+
|
|
56
|
+
## Host responsibilities (composition root)
|
|
57
|
+
|
|
58
|
+
1. Call `bindHostModules(…)` to wire config/state/media/seams/artifact
|
|
59
|
+
root/PW-2 resolver before accessing any lazy export.
|
|
60
|
+
2. Register `createRuntimeResultConsumer` via
|
|
61
|
+
`runtimeResultEmitter.setConsumer(…)`.
|
|
62
|
+
|
|
63
|
+
Without host binding, lazy getters throw on first access. This is
|
|
64
|
+
intentional — the package is a pure domain contour until the composition
|
|
65
|
+
root wires it.
|
|
66
|
+
|
|
67
|
+
## Tests
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm test # package-own suite (standalone, no backend required)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Backend-side guards: `backend/tests/architecture/physical-move-gate.test.js`
|
|
74
|
+
(PM-G suite) ensures the moved files are gone from `backend/src/runtime`
|
|
75
|
+
and the barrel is not consumed.
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@animastor/orchestration",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Animastor Orchestration — the generation orchestration/runtime contour of the Animastor backend, physically extracted from the host (§32.30): the unified generation lifecycle owner (orchestrator facade, stage executor, scene callbacks/restoration), the dispatch engine and its lease/quota/retry managers, the reconciliation engine and counter reconciliation, the scene window/scheduler/worker-health, the runtime-result emitter/consumer, and the eight O-2..O-10 port contracts (Persistence, SceneData, PlaceholderAudio, ProgressEvents, AudioFsm, VideoFsm, HubCancel, LayerConfig). The package reaches the host (runtime config slices, Redis-domain state layer, media facades, the S-5 seam registry, the artifact root, the PW-2 workspace resolver) ONLY through the composition-root host-bindings seam — no backend/src require, no storage/book/routes/services, no Redis, no PG, no Express inside.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"animastor",
|
|
7
|
+
"orchestration",
|
|
8
|
+
"runtime",
|
|
9
|
+
"dispatch",
|
|
10
|
+
"reconciliation",
|
|
11
|
+
"generation"
|
|
12
|
+
],
|
|
13
|
+
"main": "src/index.js",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./src/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"src/",
|
|
19
|
+
"test/",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "mocha --exit --require test/test-bindings.js test/*.test.js"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/Animastor/animastor.git",
|
|
36
|
+
"directory": "packages/animastor-orchestration"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/Animastor/animastor/tree/main/packages/animastor-orchestration#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/Animastor/animastor/issues"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@animastor/contracts": "^0.1.0",
|
|
44
|
+
"@animastor/generation": "^0.1.0",
|
|
45
|
+
"music-metadata": "^11.12.3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"chai": "^6.2.2",
|
|
49
|
+
"mocha": "^11.7.5"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// HOST BINDINGS — the package↔host seam (S-6 convention)
|
|
3
|
+
// ======================================================
|
|
4
|
+
// The moved runtime/orchestration files reach the HOST-OWNED modules they
|
|
5
|
+
// were allowed to touch (§32.29 host-stays allowlist) ONLY through this
|
|
6
|
+
// surface. It is the same zero-require contract + fail-fast call-time
|
|
7
|
+
// resolver + one set/wired/reset shape as the ports in ../runtime/*-port.js,
|
|
8
|
+
// but for the host composition instead of one adapter: the composition root
|
|
9
|
+
// (backend/src/backend.cjs) binds the real host modules once at startup and
|
|
10
|
+
// the moved files resolve them lazily at call time.
|
|
11
|
+
//
|
|
12
|
+
// What crosses here (exactly the measured §32.29 host-stays, nothing more):
|
|
13
|
+
// config — backend/src/config/runtime-config (runtime slices)
|
|
14
|
+
// state — backend/src/state (Redis-domain state layer facade)
|
|
15
|
+
// stateOps — backend/src/state/scene-state-ops (pure FSM writers)
|
|
16
|
+
// journal — backend/src/state/event-journal (append-only sink)
|
|
17
|
+
// media — { audio, image, video } host media facades
|
|
18
|
+
// genScope — backend/src/services/gen-scope (single-consumer edge)
|
|
19
|
+
// seams — backend/src/runtime/orchestration-seams (S-5 registry)
|
|
20
|
+
// artifactRoot — the artifact output root (former process.env.OUTPUT_DIR
|
|
21
|
+
// read — the §32.29 step-4a closure of the O-G9 leak)
|
|
22
|
+
// resolveWorkspaceForBook — the PW-2 workspace routing resolver (former
|
|
23
|
+
// scene-window → gpu-dispatcher lazy call — the §32.29
|
|
24
|
+
// step-4b closure; optional-load semantics preserved by
|
|
25
|
+
// the injected wrapper host-side)
|
|
26
|
+
//
|
|
27
|
+
// Deliberately NOT reachable through here: storage/**, book/**, routes/**,
|
|
28
|
+
// PG clients, Redis clients, Express, gpu-dispatcher internals. The host
|
|
29
|
+
// binds adapters; the package never requires backend/src.
|
|
30
|
+
//
|
|
31
|
+
// Docs: docs/architecture/generation-module-extraction-reconnaissance.md
|
|
32
|
+
// §32.29 (gate) · §32.30 (physical extraction landed)
|
|
33
|
+
|
|
34
|
+
const BINDING_NAMES = [
|
|
35
|
+
'config',
|
|
36
|
+
'state',
|
|
37
|
+
'stateOps',
|
|
38
|
+
'journal',
|
|
39
|
+
'media',
|
|
40
|
+
'genScope',
|
|
41
|
+
'seams',
|
|
42
|
+
'artifactRoot',
|
|
43
|
+
'resolveWorkspaceForBook',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const bindings = new Map();
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Wire the host-side implementations. Accepts a partial merge (tests may
|
|
50
|
+
* rebind individual bindings); unknown binding names are rejected — the
|
|
51
|
+
* surface cannot grow silently.
|
|
52
|
+
*
|
|
53
|
+
* RESOLVER SEMANTICS (§32.30): every binding is a ZERO-ARG FUNCTION that
|
|
54
|
+
* returns the host module/value. It is invoked at RESOLUTION time (i.e. when
|
|
55
|
+
* a moved file actually touches the host), not at binding time — the same
|
|
56
|
+
* deferral the former lazy host-module require call sites had, so host
|
|
57
|
+
* modules can be stubbed via require.cache after binding and stay visible
|
|
58
|
+
* to the moved code (test-binding parity).
|
|
59
|
+
*/
|
|
60
|
+
function bindHostModules(impls = {}) {
|
|
61
|
+
for (const [name, value] of Object.entries(impls)) {
|
|
62
|
+
if (!BINDING_NAMES.includes(name)) {
|
|
63
|
+
throw new Error(`host-bindings: unknown binding '${name}' (allowed: ${BINDING_NAMES.join(', ')})`);
|
|
64
|
+
}
|
|
65
|
+
if (typeof value !== 'function') {
|
|
66
|
+
throw new Error(`host-bindings: binding '${name}' must be a resolver function (zero-arg), got ${typeof value}`);
|
|
67
|
+
}
|
|
68
|
+
bindings.set(name, value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Test hygiene: drop all bindings (mocha afterEach hooks). */
|
|
73
|
+
function clearHostBindings() {
|
|
74
|
+
bindings.clear();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a binding at CALL time (invokes the resolver). Fail-fast with a
|
|
79
|
+
* wiring instruction — a missing binding must never degrade into a silent
|
|
80
|
+
* no-op.
|
|
81
|
+
*/
|
|
82
|
+
function hostBinding(name) {
|
|
83
|
+
const value = bindings.get(name);
|
|
84
|
+
if (typeof value !== 'function') {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`host-bindings: '${name}' is not wired — the composition root must call ` +
|
|
87
|
+
`bindHostModules({ ${name}, ... }) before orchestration runs (§32.30)`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return value();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isHostBindingWired(name) {
|
|
94
|
+
return bindings.has(name);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Lazy host-module accessor: returns a proxy that resolves the binding (and
|
|
99
|
+
* optional sub-path) at PROPERTY-ACCESS time. Lets a moved file keep its
|
|
100
|
+
* original identifier usage verbatim (`state.getAssetStates(...)`,
|
|
101
|
+
* `audio.segments.buildSegments(...)`) while the underlying host module is
|
|
102
|
+
* only resolved when actually used — same deferral the former lazy
|
|
103
|
+
* `require(...)` call sites had, but through the binding seam.
|
|
104
|
+
*/
|
|
105
|
+
function lazyHostBinding(name) {
|
|
106
|
+
const [root, ...rest] = name.split('.');
|
|
107
|
+
return new Proxy({}, {
|
|
108
|
+
get(_, prop) {
|
|
109
|
+
let target = hostBinding(root);
|
|
110
|
+
for (const key of rest) target = target[key];
|
|
111
|
+
return target[prop];
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Direct call-time host access for non-member callables (the PW-2 resolver,
|
|
118
|
+
* the artifact root): `hostCall('resolveWorkspaceForBook')(bookId)`.
|
|
119
|
+
*/
|
|
120
|
+
function hostCall(name) {
|
|
121
|
+
return hostBinding(name);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** All names the composition root is expected to wire. */
|
|
125
|
+
function requiredHostBindings() {
|
|
126
|
+
return [...BINDING_NAMES];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
BINDING_NAMES,
|
|
131
|
+
bindHostModules,
|
|
132
|
+
clearHostBindings,
|
|
133
|
+
hostBinding,
|
|
134
|
+
hostCall,
|
|
135
|
+
isHostBindingWired,
|
|
136
|
+
lazyHostBinding,
|
|
137
|
+
requiredHostBindings,
|
|
138
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// @animastor/orchestration — package root (public API)
|
|
3
|
+
// ======================================================
|
|
4
|
+
// The orchestration/runtime contour physically extracted from the backend
|
|
5
|
+
// host (§32.30; gate: §32.29 — READY FOR PHYSICAL MOVE). This root exports
|
|
6
|
+
// EXACTLY the measured host consumption surface — nothing "just in case":
|
|
7
|
+
//
|
|
8
|
+
// 1. The orchestration facade (former backend/src/orchestration/index.js,
|
|
9
|
+
// moved verbatim) — the stage executor + FSM-safe scene writers the
|
|
10
|
+
// host and the S-5 seam registry consume.
|
|
11
|
+
// 2. createRuntimeResultConsumer — the Phase-5 result-reporting consumer
|
|
12
|
+
// the composition root registers via runtimeResultEmitter.setConsumer.
|
|
13
|
+
// 3. The eight O-2..O-10 port CONTRACT modules (tier-owned, moved with
|
|
14
|
+
// the contour) — the host storage adapters bind these at startup.
|
|
15
|
+
// 4. bindHostModules / hostBinding — the composition-root binding surface
|
|
16
|
+
// that wires the host-owned modules the moved files consume
|
|
17
|
+
// (config/state/media/seams/artifact root/PW-2 resolver).
|
|
18
|
+
//
|
|
19
|
+
// §32.30: the facade exports are LAZY getters (the FSM-writer re-exports
|
|
20
|
+
// resolve the stateOps host binding on access), so the root itself builds
|
|
21
|
+
// its export object with defineProperties — a literal spread would fire
|
|
22
|
+
// those getters at require time, before the composition root binds host
|
|
23
|
+
// modules. The surface (names + facade-wins precedence) is unchanged.
|
|
24
|
+
//
|
|
25
|
+
// Everything else in the package (dispatch-engine, reconciliation-engine,
|
|
26
|
+
// scene-window, scheduler, lease/circuit/retry managers, worker-health,
|
|
27
|
+
// metrics) is INTERNAL: no host module and no host test may deep-import it.
|
|
28
|
+
//
|
|
29
|
+
// Dependency direction after the move (guarded by backend PM-G suite):
|
|
30
|
+
// backend host → @animastor/orchestration → ports/host-bindings/contracts
|
|
31
|
+
// The package requires @animastor/generation (root specifier only) and
|
|
32
|
+
// @animastor/contracts; it never requires backend/src, storage, book,
|
|
33
|
+
// routes, services, Redis or PG clients.
|
|
34
|
+
//
|
|
35
|
+
// Docs: docs/architecture/generation-module-extraction-reconnaissance.md
|
|
36
|
+
// §32.29 (frozen API) · §32.30 (physical extraction landed)
|
|
37
|
+
|
|
38
|
+
const orchestrationFacade = require('./orchestration');
|
|
39
|
+
const { createRuntimeResultConsumer } = require('./orchestration/runtime-result-consumer');
|
|
40
|
+
const hostBindings = require('./host/host-bindings');
|
|
41
|
+
|
|
42
|
+
// 1 — orchestration facade (lazy accessors over the moved facade modules)
|
|
43
|
+
const FACADE_KEYS = Object.keys(orchestrationFacade);
|
|
44
|
+
const LAZY_FACADE_PROPS = Object.fromEntries(FACADE_KEYS.map((key) => [key, {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
get() { return orchestrationFacade[key]; },
|
|
47
|
+
}]));
|
|
48
|
+
|
|
49
|
+
// 2 + 3 + 4 — eager values (no binding resolution at require time)
|
|
50
|
+
const EAGER_EXPORTS = {
|
|
51
|
+
createRuntimeResultConsumer,
|
|
52
|
+
ports: {
|
|
53
|
+
persistence: require('./runtime/persistence-port'),
|
|
54
|
+
sceneData: require('./runtime/scene-data-port'),
|
|
55
|
+
placeholderAudio: require('./runtime/placeholder-audio-port'),
|
|
56
|
+
progressEvents: require('./runtime/progress-events-port'),
|
|
57
|
+
audioFsm: require('./runtime/audio-fsm-port'),
|
|
58
|
+
videoFsm: require('./runtime/video-fsm-port'),
|
|
59
|
+
hubCancel: require('./runtime/hub-cancel-port'),
|
|
60
|
+
layerConfig: require('./runtime/layer-config-port'),
|
|
61
|
+
},
|
|
62
|
+
bindHostModules: hostBindings.bindHostModules,
|
|
63
|
+
clearHostBindings: hostBindings.clearHostBindings,
|
|
64
|
+
hostBinding: hostBindings.hostBinding,
|
|
65
|
+
isHostBindingWired: hostBindings.isHostBindingWired,
|
|
66
|
+
lazyHostBinding: hostBindings.lazyHostBinding,
|
|
67
|
+
requiredHostBindings: hostBindings.requiredHostBindings,
|
|
68
|
+
BINDING_NAMES: hostBindings.BINDING_NAMES,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// 5 — the host-facing runtime namespace: the measured routes/services/helpers
|
|
72
|
+
// consumption surface (the former backend/src/runtime/index.js barrel minus
|
|
73
|
+
// its host-stay members loop/gpuDispatcher/retentionManager). Lazy getters —
|
|
74
|
+
// no eager module loads at require time.
|
|
75
|
+
const RUNTIME_NS = {
|
|
76
|
+
scheduler: './runtime/runtime-scheduler',
|
|
77
|
+
activeScenes: './runtime/active-scenes-index',
|
|
78
|
+
reconciliation: './runtime/reconciliation-engine',
|
|
79
|
+
dispatch: './runtime/dispatch-engine',
|
|
80
|
+
leaseManager: './runtime/lease-manager',
|
|
81
|
+
counterReconciliation: './runtime/counter-reconciliation',
|
|
82
|
+
metrics: './runtime/runtime-metrics',
|
|
83
|
+
workerHealth: './runtime/worker-health',
|
|
84
|
+
sceneWindow: './runtime/scene-window',
|
|
85
|
+
failureTaxonomy: './runtime/failure-taxonomy',
|
|
86
|
+
runtimeResultEmitter: './runtime/runtime-result-emitter',
|
|
87
|
+
};
|
|
88
|
+
const LAZY_RUNTIME_PROPS = Object.fromEntries(Object.entries(RUNTIME_NS).map(([key, target]) => [key, {
|
|
89
|
+
enumerable: true,
|
|
90
|
+
get() { return require(target); },
|
|
91
|
+
}]));
|
|
92
|
+
|
|
93
|
+
const base = { ...EAGER_EXPORTS };
|
|
94
|
+
Object.defineProperties(base, LAZY_FACADE_PROPS);
|
|
95
|
+
Object.defineProperties(base, {
|
|
96
|
+
runtime: { enumerable: true, value: Object.defineProperties({}, LAZY_RUNTIME_PROPS) },
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
module.exports = base;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// Orchestration Module - v2.0.0
|
|
3
|
+
// ======================================================
|
|
4
|
+
|
|
5
|
+
// Existing contract: orchestration.dispatchStage / handle*Completed
|
|
6
|
+
// are consumed by dispatch-engine.js (require('../orchestration')).
|
|
7
|
+
// We preserve those exports and add the new Orchestrator facade alongside,
|
|
8
|
+
// so callers can migrate to orchestration.orchestrator.* incrementally
|
|
9
|
+
// without breaking the existing surface (Шаг 0, docs-claude/03_Orchestrator.md).
|
|
10
|
+
//
|
|
11
|
+
// Orchestrator facade functions (markDirtyScene, planScene, beginStage, etc.)
|
|
12
|
+
// are also spread to the top level so callers that receive 'orchestrator' via
|
|
13
|
+
// deps (reconciliation-engine, scene-asset-registry, etc.) can access them
|
|
14
|
+
// directly as deps.orchestrator.markDirtyScene() without the .orchestrator
|
|
15
|
+
// indirection. When names overlap (completeStage, failStage), the orchestrator
|
|
16
|
+
// facade version wins (it's the newer canonical implementation).
|
|
17
|
+
//
|
|
18
|
+
// §32.30: the FSM-writer re-exports in orchestrator.js are LAZY getters
|
|
19
|
+
// (they resolve the stateOps host binding on access). A literal object
|
|
20
|
+
// spread would fire them at require time — before the composition root
|
|
21
|
+
// binds host modules. Enumerate + defineProperties keeps every accessor
|
|
22
|
+
// lazy while preserving the exact surface and the facade-wins precedence.
|
|
23
|
+
const sceneOrchestrator = require('./scene-orchestrator');
|
|
24
|
+
const orchestratorFacade = require('./orchestrator');
|
|
25
|
+
|
|
26
|
+
const FACADE_KEYS = [
|
|
27
|
+
...new Set([...Object.keys(sceneOrchestrator), ...Object.keys(orchestratorFacade)]),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const LAZY_FACADE_PROPS = Object.fromEntries(FACADE_KEYS.map((key) => [key, {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get() {
|
|
33
|
+
return key in orchestratorFacade ? orchestratorFacade[key] : sceneOrchestrator[key];
|
|
34
|
+
},
|
|
35
|
+
}]));
|
|
36
|
+
|
|
37
|
+
module.exports = Object.defineProperties(
|
|
38
|
+
{ orchestrator: orchestratorFacade },
|
|
39
|
+
LAZY_FACADE_PROPS,
|
|
40
|
+
);
|