@volter/supercode-orchestrator 0.5.59 → 0.5.61

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.
@@ -192,7 +192,7 @@ function unpublishedAlive(session) {
192
192
  if (!session.machine) return null;
193
193
  if (!session.pane) {
194
194
  if (!session.session_id) return null;
195
- try { return nativeReading(nativeSessions(session.machine, session.harness ?? 'claude-code'), session).alive; } catch { return null; }
195
+ try { return nativeReading(nativeSessions(session.machine, session.harness ?? 'claude-code', session.session_id), session).alive; } catch { return null; }
196
196
  }
197
197
  let entry = paneLists.get(session.machine);
198
198
  if (!entry || Date.now() - entry.at > READING_MS) {
@@ -205,8 +205,9 @@ function unpublishedAlive(session) {
205
205
  return entry.panes ? entry.panes.some((p) => p.pane === session.pane && !p.dead) : null;
206
206
  }
207
207
 
208
- /** Native activity comes from the machine's harness discovery, not catalogue age. One discovery (up to 2000
209
- * sessions, seconds each) serves a round's every native session on that machine, as paneLists serves its panes. */
208
+ /** Native activity comes from the machine's harness discovery, not catalogue age: each session the round reads is
209
+ * discovered by its id (about 0.2 s), once per round (tick clears them). Listing the machine's every session to find
210
+ * them (up to 2000, 1-6 s each) cost more than the sessions a board runs. */
210
211
  const discoveries = new Map();
211
212
  // A machine's pane list and harness discovery are read before a board write opens, never inside one: a door that
212
213
  // takes seconds would hold the board's write lock past a worker's own command's busy wait. A write that needs a
@@ -217,25 +218,26 @@ const txRead = (board, fn) => { readingsOnly += 1; try { return tx(board, fn); }
217
218
  /** Take the readings a board write about `session` will need, before the write. */
218
219
  function readBefore(fleet, session) {
219
220
  if (!session?.session_id || !session.machine || session.surface === 'headless') return;
220
- try { nativeSessions(session.machine, session.harness ?? 'claude-code'); } catch { /* unread: unknown inside the write */ }
221
+ try { nativeSessions(session.machine, session.harness ?? 'claude-code', session.session_id); } catch { /* unread: unknown inside the write */ }
221
222
  sessionAlive(fleet, session);
222
223
  }
223
- function nativeSessions(machine, harness) {
224
- const key = `${normalMachine(machine)}\u0000${harness}`, seen = discoveries.get(key);
225
- if (seen && Date.now() - seen.at <= READING_MS) return seen.sessions;
224
+ function nativeSessions(machine, harness, sessionId) {
225
+ const key = nativeKey(machine, harness, sessionId), seen = discoveries.get(key);
226
+ if (seen) return seen.sessions;
226
227
  if (readingsOnly) throw unavailable('native liveness is read before a board write, not inside it');
227
- const sessions = discoverNative(machine, harness);
228
+ const sessions = discoverNative(machine, harness, sessionId);
228
229
  discoveries.set(key, { at: Date.now(), sessions });
229
230
  return sessions;
230
231
  }
231
232
  // A native discovery is bounded as the fleet reading is: one that does not answer in time is unknown, read next round.
232
233
  const NATIVE_DISCOVERY_MS = 15_000;
233
- function discoverNative(machine, harness) {
234
+ const nativeKey = (machine, harness, sessionId) => `${normalMachine(machine)}\u0000${harness}\u0000${sessionId}`;
235
+ function discoverNative(machine, harness, sessionId) {
234
236
  if (offlineMachine(machine)) throw unavailable(`native liveness unavailable: machine ${normalMachine(machine)} is offline`);
235
237
  // This machine's discovery is its harness door, as every other harness read here is; another machine's is supercode's fleet arm
236
238
  const result = normalMachine(machine) === localMachine()
237
- ? doorOn(machine, 'harness.v1.sessions.discover', { harnesses: [harness], limit: 2000 }, { timeout: NATIVE_DISCOVERY_MS })
238
- : sc(['discover', '--on', machine, '--harness', harness, '--limit', '2000'], { timeout: NATIVE_DISCOVERY_MS });
239
+ ? doorOn(machine, 'harness.v1.sessions.discover', { harnesses: [harness], query: sessionId, limit: 2000 }, { timeout: NATIVE_DISCOVERY_MS })
240
+ : sc(['discover', '--on', machine, '--harness', harness, '--query', sessionId, '--limit', '2000'], { timeout: NATIVE_DISCOVERY_MS });
239
241
  const page = result.code === 0 ? lastJson(result.stdout) : null;
240
242
  if (!Array.isArray(page?.sessions)) throw unavailable(`native liveness unavailable on ${machine}: ${(result.stderr || result.stdout).trim().slice(-300)}`);
241
243
  return page.sessions;
@@ -525,8 +527,8 @@ function stopSession(board, session) {
525
527
  const r = sc(['close', addressOf(session)], { timeout: 120_000, as: boardAddress(board.label) });
526
528
  if (r.code !== 0) throw new Error(`${doorTransient(r) ? 'close deferred: ' : ''}closing native session ${addressOf(session)}: ${(r.stderr || r.stdout).trim().slice(-500)}`);
527
529
  // the close's receipt is a discovery taken after it, never the round's cached one from before
528
- discoveries.delete(`${normalMachine(session.machine)}\u0000${session.harness}`);
529
- const reading = nativeReading(nativeSessions(session.machine, session.harness), session);
530
+ discoveries.delete(nativeKey(session.machine, session.harness, session.session_id));
531
+ const reading = nativeReading(nativeSessions(session.machine, session.harness, session.session_id), session);
530
532
  if (reading.alive !== false) throw new Error(`native close has no confirmed stopped receipt for ${addressOf(session)}`);
531
533
  return;
532
534
  }
@@ -931,7 +933,7 @@ export function closeRequested(board, report, { taskId = null, caller = null, tt
931
933
  try {
932
934
  const machine = session.machine ?? localMachine();
933
935
  if (session.surface === 'native' && !session.pane) {
934
- const reading = nativeReading(nativeSessions(machine, session.harness), session);
936
+ const reading = nativeReading(nativeSessions(machine, session.harness, session.session_id), session);
935
937
  if (reading.alive == null) throw new Error(`close deferred: native liveness unknown for ${addressOf(session)}`);
936
938
  if (reading.alive) {
937
939
  const protectedNow = active.some(r => addressOf(json(r.metadata, {})?.supercode) === addressOf(session));
@@ -997,13 +999,12 @@ export function closeRequested(board, report, { taskId = null, caller = null, tt
997
999
  function observeIdle(board, fleet, settings, report, entry, effects) {
998
1000
  if (!fleet.ok) return;
999
1001
  // The published fleet says whether a session runs and its turn, not when it last wrote: that is the session's own
1000
- // record, read from its machine's discovery (one read per machine and harness a round, only when a card needs it).
1002
+ // record, read from its machine's discovery (once a round, only when a card needs it).
1001
1003
  // Without it every reading was 'no_timestamp' and no session was ever found idle.
1002
- const discovered = new Map();
1003
1004
  const updatedAt = (session) => {
1004
- const key = `${session.machine}|${session.harness ?? 'claude-code'}`;
1005
- if (!discovered.has(key)) { try { discovered.set(key, nativeSessions(session.machine ?? localMachine(), session.harness ?? 'claude-code')); } catch { discovered.set(key, null); } }
1006
- return Number(discovered.get(key)?.find((row) => row.locator?.session_id === session.session_id)?.updated_at_ms) || null;
1005
+ let rows = null;
1006
+ try { rows = nativeSessions(session.machine ?? localMachine(), session.harness ?? 'claude-code', session.session_id); } catch { /* unread: no timestamp */ }
1007
+ return Number(rows?.find((row) => row.locator?.session_id === session.session_id)?.updated_at_ms) || null;
1007
1008
  };
1008
1009
  const managers = [].concat(entry.params.managers ?? []).filter(Boolean);
1009
1010
  const running = board.db.prepare(entry.workflow.run ? "SELECT id FROM tasks WHERE current_run_id IS NOT NULL" : "SELECT id FROM tasks WHERE status = 'running'").all();
@@ -1021,7 +1022,7 @@ function observeIdle(board, fleet, settings, report, entry, effects) {
1021
1022
  if (session.surface === 'native' && sessionAlive(fleet, session) !== true) return;
1022
1023
  // a session in no pane has its turn on its machine's discovery row, which sessionAlive just read
1023
1024
  let nativeRow = null;
1024
- if (session.surface === 'native') try { nativeRow = nativeReading(nativeSessions(session.machine, session.harness ?? 'claude-code'), session).row; } catch { /* unread: no turn */ }
1025
+ if (session.surface === 'native') try { nativeRow = nativeReading(nativeSessions(session.machine, session.harness ?? 'claude-code', session.session_id), session).row; } catch { /* unread: no turn */ }
1025
1026
  const live = fleet.sessions.find((x) => x.address === addressOf(session)) ?? (nativeRow ? { address: addressOf(session), turn: nativeRow.activity?.turn ?? null } : undefined);
1026
1027
  const observedAt = now();
1027
1028
  const lastAtMs = Number(live?.last_message_at_ms) || updatedAt(session);
@@ -1537,7 +1538,7 @@ function launchPane(board, task, runId, lane, fleet, { input = null, slot = 'wor
1537
1538
  // session it did not launch, left running at its run's end) is its owner's while it runs: it is never resumed beside
1538
1539
  // itself, and the launch waits for the owner to end it.
1539
1540
  if (prev?.surface === 'native' && !prev.pane && (!prev.close_confirmed_at || prev.released)) {
1540
- const reading = nativeReading(nativeSessions(prev.machine, prev.harness), prev);
1541
+ const reading = nativeReading(nativeSessions(prev.machine, prev.harness, prev.session_id), prev);
1541
1542
  if (reading.alive == null) throw unavailable(`cannot establish native continuation liveness for ${addressOf(prev)}`);
1542
1543
  fleet.native ??= new Map(); fleet.native.set(addressOf(prev), reading);
1543
1544
  if (reading.alive && prev.released) throw unavailable(`released session ${addressOf(prev)} still runs; the launch waits for its owner to end it`);
@@ -1789,7 +1790,7 @@ function nativeListing(who) {
1789
1790
  const m = /^sc:([^:]+):([^:]+):(.+)$/.exec(String(who));
1790
1791
  if (!m || !HARNESSES[m[2]]) return null;
1791
1792
  const [, host, harness, session_id] = m;
1792
- try { return nativeReading(nativeSessions(host, harness), { session_id, harness }).alive === true ? { address: who, machine: normalMachine(host), harness, session_id, pane: null, name: null } : null; }
1793
+ try { return nativeReading(nativeSessions(host, harness, session_id), { session_id, harness }).alive === true ? { address: who, machine: normalMachine(host), harness, session_id, pane: null, name: null } : null; }
1793
1794
  catch { return null; }
1794
1795
  }
1795
1796
 
@@ -1816,7 +1817,7 @@ function adoptSession(board, id, who, { request = null, open = request, progress
1816
1817
  if (!found) throw Object.assign(new Error(`the fleet lists no live session ${who}`), { notListed: true });
1817
1818
  const [, host, harness, sessionId] = found.address.split(':');
1818
1819
  if (!HARNESSES[harness]) throw new Error(`${found.address} is ${harness}; the board keeps and resumes ${Object.keys(HARNESSES).join(' and ')} sessions`);
1819
- const native = found.pane ? null : nativeReading(nativeSessions(host, harness), { session_id: sessionId, harness });
1820
+ const native = found.pane ? null : nativeReading(nativeSessions(host, harness, sessionId), { session_id: sessionId, harness });
1820
1821
  if (found.pane ? !panePresent(host, found.pane) : native.alive !== true) throw new Error(`${found.address} has no verified live native process or pane`);
1821
1822
  const beforeRun = view(board, (db) => currentRun(db, id));
1822
1823
  const beforeSession = beforeRun?.metadata?.supercode;
@@ -1826,7 +1827,7 @@ function adoptSession(board, id, who, { request = null, open = request, progress
1826
1827
  // the session's own working directory, as discovery records it (where `--resume` finds it), else its pane's
1827
1828
  let dir = workspace ?? native?.row?.cwd;
1828
1829
  if (!dir) {
1829
- dir = nativeSessions(host, harness).find((x) => x.locator?.session_id === sessionId)?.cwd ?? null;
1830
+ dir = nativeSessions(host, harness, sessionId).find((x) => x.locator?.session_id === sessionId)?.cwd ?? null;
1830
1831
  }
1831
1832
  if (!dir && found.pane) {
1832
1833
  const r = runtimeDoor(normalMachine(host)===localMachine()?null:host,'harness.v1.panes.list',{}, { timeout: 60_000 });
@@ -2559,6 +2560,7 @@ export async function deliver({ root, slugs = null }) {
2559
2560
  */
2560
2561
  export async function tick({ root, lanes, settings, only = null, slugs = null, dispatch = true, params = {}, deploymentReceipt = false }) {
2561
2562
  fleetRoot = root;
2563
+ discoveries.clear();
2562
2564
  // a verb's flags (dispatch --max, --failure-limit) are params of this tick, read by the workflow as its own
2563
2565
  const deployment = deploymentReceipt ? workflowRevision(root) : null;
2564
2566
  const loaded = await loadWorkflow(root, { fresh: true });
@@ -167,9 +167,12 @@ const execFileAsync = promisify(execFile);
167
167
  export async function refreshRelationAnswers(board) {
168
168
  const ids = new Set();
169
169
  const entry = workflowFor(board.root);
170
- for (const row of board.db.prepare("SELECT t.*,c.blocked_by FROM tasks t JOIN supercode_cards c ON c.task_id=t.id WHERE c.blocked_by IS NOT NULL AND c.blocked_by!='[]'").all()) {
171
- if (!relationActive(board.db, board, entry, row)) continue;
172
- for (const block of json(row.blocked_by, []) ?? []) if (block.kind === 'message') ids.add(block.id);
170
+ for (const row of board.db.prepare("SELECT t.*,c.blocked_by FROM tasks t JOIN supercode_cards c ON c.task_id=t.id WHERE c.blocked_by IS NOT NULL AND c.blocked_by!='[]' AND t.status NOT IN ('done','cancelled','archived') AND NOT COALESCE(c.archived,0)").all()) {
171
+ // only an open card's message has an answer to read: a closed card, or one blocked by cards alone, needs no scope
172
+ // built for its guard (75 walked on 2026-10-04, one of them a live message blocker)
173
+ const messages = (json(row.blocked_by, []) ?? []).filter((block) => block.kind === 'message');
174
+ if (!messages.length || !relationActive(board.db, board, entry, row)) continue;
175
+ for (const block of messages) ids.add(block.id);
173
176
  }
174
177
  for (const row of board.db.prepare("SELECT e.payload FROM task_events e JOIN (SELECT task_id, MAX(id) id FROM task_events WHERE kind IN ('blocked','unblocked') GROUP BY task_id) last ON e.id=last.id JOIN tasks t ON t.id=e.task_id WHERE e.kind='blocked' AND t.status='blocked'").all()) {
175
178
  const id = json(row.payload, {})?.waiting_on; if (id) ids.add(id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-orchestrator",
3
- "version": "0.5.59",
3
+ "version": "0.5.61",
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": {