@volter/supercode-orchestrator 0.5.216 → 0.5.217

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 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 () => { const { settleDocuments } = await import('./git-document.mjs'); await settleDocuments(); });
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) tellOwner({ type: 'startup-step', phase: 'serving', step: 'completing the first native board round', budget_ms: 65000 });
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.216",
3
+ "version": "0.5.217",
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,7 +36,7 @@
36
36
  "check-types": "node scripts/generate-types.mjs --check"
37
37
  },
38
38
  "dependencies": {
39
- "@volter/supercode-teams": "^0.3.355",
39
+ "@volter/supercode-teams": "^0.3.361",
40
40
  "@volter/supercode-terminal": "^0.3.12",
41
41
  "@volter/supercode-harness-sdk": "^0.3.106",
42
42
  "@volter/teams": "0.2.102",