@volter/supercode-orchestrator 0.5.216 → 0.5.218
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/board/cli.mjs +33 -3
- package/board/generation-owner.mjs +1 -0
- package/package.json +3 -3
package/board/cli.mjs
CHANGED
|
@@ -1913,6 +1913,12 @@ export async function serveBoardGeneration(root, args = {}, argv = ['serve', '--
|
|
|
1913
1913
|
finally { board?.close(); }
|
|
1914
1914
|
}
|
|
1915
1915
|
});
|
|
1916
|
+
// Hermes's install is located once per process (hermes-cli.mjs), a read of PATH and its files: here, before this
|
|
1917
|
+
// generation is prepared, so its activation does not spend it while the public door routes nowhere.
|
|
1918
|
+
try { (await import('../hermes-cli.mjs')).hermesInstall(); } catch { /* none installed */ }
|
|
1919
|
+
// Each activation and park step in the owner's log (the generation's output is that log), so a reading accounts
|
|
1920
|
+
// for every second the public door routes nowhere (ADR 0080, "Board ownership").
|
|
1921
|
+
const say = text => process.stdout.write(`${new Date().toISOString()} board generation ${process.pid}: ${text}\n`);
|
|
1916
1922
|
let begin, started = false, controls = Promise.resolve();
|
|
1917
1923
|
const activation = new Promise(done => { begin = done; });
|
|
1918
1924
|
const unwatchHealth = watchOwnerHealth(value => tellOwner({ type: 'health', ...value }));
|
|
@@ -1926,21 +1932,34 @@ export async function serveBoardGeneration(root, args = {}, argv = ['serve', '--
|
|
|
1926
1932
|
if (!['activate', 'park'].includes(frame?.type)) return;
|
|
1927
1933
|
controls = controls.then(async () => {
|
|
1928
1934
|
if (frame.type === 'park') {
|
|
1935
|
+
// The epoch's writer is given up at the earliest point that is still single-writer: once admitted work has
|
|
1936
|
+
// drained and the documents it fetched have settled (parkGeneration). Retiring the held boards closes their
|
|
1937
|
+
// handles, nothing more, and the successor takes a fresh epoch that fences any older writer anyway.
|
|
1938
|
+
say('park: dispatching stopped; admission closes');
|
|
1929
1939
|
stopDispatching();
|
|
1930
|
-
await parkGeneration(async () => {
|
|
1940
|
+
await parkGeneration(async () => {
|
|
1941
|
+
say('park: admitted work drained; settling documents');
|
|
1942
|
+
const { settleDocuments } = await import('./git-document.mjs'); await settleDocuments();
|
|
1943
|
+
say('park: documents settled');
|
|
1944
|
+
});
|
|
1945
|
+
say('park: the writer given up');
|
|
1931
1946
|
retireHeldBoards();
|
|
1932
1947
|
tellOwner({ type: 'parked' });
|
|
1948
|
+
say('park: parked');
|
|
1933
1949
|
} else {
|
|
1934
1950
|
grantGenerationWriter();
|
|
1935
1951
|
if (!started) {
|
|
1952
|
+
say('activation: the writer granted; the native board dispatcher starts');
|
|
1936
1953
|
tellOwner({ type: 'startup-step', phase: 'serving', step: 'starting the native board dispatcher', budget_ms: 65000 });
|
|
1937
1954
|
started = true; begin();
|
|
1938
1955
|
}
|
|
1939
1956
|
else {
|
|
1940
|
-
takeEpoch(root, () => listBoards(root).map(slug => openBoard(root, slug)));
|
|
1957
|
+
const epoch = takeEpoch(root, () => listBoards(root).map(slug => openBoard(root, slug)));
|
|
1958
|
+
say(`activation: writer epoch ${epoch} taken again`);
|
|
1941
1959
|
await registerGenerationOwner();
|
|
1942
1960
|
resumeDispatching();
|
|
1943
1961
|
admitGeneration();
|
|
1962
|
+
say('activation: registered with the machine daemon; the first clean round follows');
|
|
1944
1963
|
// The loop's next admitted round supplies the serving receipt, also for a resumed predecessor.
|
|
1945
1964
|
generationServingDue = true;
|
|
1946
1965
|
wakeGeneration();
|
|
@@ -2073,12 +2092,17 @@ async function serve(root, args = {}) {
|
|
|
2073
2092
|
if (watched !== undefined && board) heldDocumentsWatched(board, id ?? key, watched);
|
|
2074
2093
|
else if (uncertain && !board) heldDocumentsChanged();
|
|
2075
2094
|
} });
|
|
2095
|
+
// A generation's activation steps, each in its owner's log: a reading accounts for the window the public door
|
|
2096
|
+
// routes nowhere (ADR 0080, "Board ownership").
|
|
2097
|
+
const activationSaid = text => { if (inBoardGeneration && generationServingDue) log(`board generation ${process.pid} activation: ${text}`); };
|
|
2098
|
+
activationSaid('board events watched');
|
|
2076
2099
|
wakeGeneration = () => events?.wake('generation-activated');
|
|
2077
2100
|
// a machine's panes changing in its record (a session came up under its pane, a pane or its session ended) is what a
|
|
2078
2101
|
// round binds a launch, verifies an adoption and reads a session's end from: the next round is due then
|
|
2079
2102
|
const unfollowPanes = onPanesChanged(() => events?.wake('machine-record'));
|
|
2080
2103
|
// the owner holds its boards only now, its watch installed (watch before load): opened once, changed by events
|
|
2081
2104
|
holdBoards(root);
|
|
2105
|
+
activationSaid('the boards held');
|
|
2082
2106
|
// a pause of the collector holds the loop like any synchronous step: each is a step, so a block line names it
|
|
2083
2107
|
try { const { PerformanceObserver } = await import('node:perf_hooks'); new PerformanceObserver((list) => { for (const entry of list.getEntries()) noteStep('gc', entry.duration); }).observe({ entryTypes: ['gc'] }); } catch { /* no gc entries here */ }
|
|
2084
2108
|
// The board's events are published by this machine's connector, not by the dispatcher (D137, D138 step 4): the home is
|
|
@@ -2099,6 +2123,7 @@ async function serve(root, args = {}) {
|
|
|
2099
2123
|
registerGenerationOwner = registerOwner;
|
|
2100
2124
|
await registerOwner();
|
|
2101
2125
|
onLocalReopen(registerOwner);
|
|
2126
|
+
activationSaid('registered with the machine daemon');
|
|
2102
2127
|
let listenerRecords = {}, listenerReloading = null, listenerReloadDue = false, listenerReading = null;
|
|
2103
2128
|
const listenerErrors = new Set();
|
|
2104
2129
|
const listenerLog = text => { if (!listenerErrors.has(text)) { if (listenerErrors.size >= 128) listenerErrors.clear(); listenerErrors.add(text); log(text); } };
|
|
@@ -2160,6 +2185,7 @@ async function serve(root, args = {}) {
|
|
|
2160
2185
|
};
|
|
2161
2186
|
if (inBoardGeneration && generationServingDue) tellOwner({ type: 'startup-step', phase: 'serving', step: 'reading the listener configuration through its orchestration door', budget_ms: 65000 });
|
|
2162
2187
|
await reloadListeners();
|
|
2188
|
+
activationSaid('the listener configuration read');
|
|
2163
2189
|
// Retry a failed home decode without waiting for a dispatch sweep. Reading the held stream also enforces its
|
|
2164
2190
|
// heartbeat deadline and reconnects after local caller loss, even when every board's dispatching is off.
|
|
2165
2191
|
let nextListenerRead = 0;
|
|
@@ -2186,7 +2212,10 @@ async function serve(root, args = {}) {
|
|
|
2186
2212
|
let interval = 60;
|
|
2187
2213
|
let nextMailAt = Infinity;
|
|
2188
2214
|
const began = Date.now();
|
|
2189
|
-
if (inBoardGeneration && generationServingDue)
|
|
2215
|
+
if (inBoardGeneration && generationServingDue) {
|
|
2216
|
+
tellOwner({ type: 'startup-step', phase: 'serving', step: 'completing the first native board round', budget_ms: 65000 });
|
|
2217
|
+
activationSaid('the first native board round begins');
|
|
2218
|
+
}
|
|
2190
2219
|
if (wakeReason) log(`dispatch wake ${wakeReason.sources.join(', ')}; event age ${began - wakeReason.at}ms`);
|
|
2191
2220
|
wakeReason = null;
|
|
2192
2221
|
const loopStep = async (name, fn) => { const at = performance.now(); try { return await fn(); } finally { noteStep(`owner loop: ${name}`, performance.now() - at); } };
|
|
@@ -2202,6 +2231,7 @@ async function serve(root, args = {}) {
|
|
|
2202
2231
|
const dispatching = listBoards(root).filter((slug) => dispatchingOf(root, slug).on);
|
|
2203
2232
|
const reports = dispatching.length ? await ownCall(() => tick({ root, lanes: state.lanes, settings, params, slugs: dispatching, deploymentReceipt: true })) : [];
|
|
2204
2233
|
if (inBoardGeneration && generationServingDue && reports.every(report => !report.error)) {
|
|
2234
|
+
activationSaid(`the first native board round is clean (${dispatching.length} dispatching board(s))`);
|
|
2205
2235
|
generationServingDue = false;
|
|
2206
2236
|
tellOwner({ type: 'serving', pid: process.pid, boards: listBoards(root) });
|
|
2207
2237
|
}
|
|
@@ -133,6 +133,7 @@ export async function serveBoardOwner(root, args) {
|
|
|
133
133
|
record(generation);
|
|
134
134
|
generation.events.delete('serving');
|
|
135
135
|
generation.tell({ type: 'activate' });
|
|
136
|
+
log(`generation ${generation.id} (pid ${generation.process.pid}) activates`);
|
|
136
137
|
const serving = await generation.wait('serving');
|
|
137
138
|
const read = async argv => {
|
|
138
139
|
const proof = await generation.ask(JSON.stringify({ v: 1, argv, cwd: root,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.218",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The orchestrator runtime over the Volter Harness ontology: one typed operational model whose folder is its serialization, read and written through the harness orchestration doors (docs/ORCHESTRATOR-IR.md)",
|
|
6
6
|
"exports": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"check-types": "node scripts/generate-types.mjs --check"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@volter/supercode-teams": "^0.3.
|
|
39
|
+
"@volter/supercode-teams": "^0.3.365",
|
|
40
40
|
"@volter/supercode-terminal": "^0.3.12",
|
|
41
41
|
"@volter/supercode-harness-sdk": "^0.3.106",
|
|
42
|
-
"@volter/teams": "0.2.
|
|
42
|
+
"@volter/teams": "0.2.103",
|
|
43
43
|
"@volter/ztrack": "^2.4.23",
|
|
44
44
|
"yaml": "^2.9.0"
|
|
45
45
|
},
|