@volter/supercode-orchestrator 0.4.27 → 0.4.28

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.
Files changed (2) hide show
  1. package/board/dispatch.mjs +15 -14
  2. package/package.json +1 -1
@@ -475,7 +475,7 @@ function launchPane(board, task, runId, lane, fleet, { input = null } = {}) {
475
475
  if (prev && prev.machine === machine) {
476
476
  if (sessionAlive(fleet, prev)) {
477
477
  // the session is kept; the heartbeat's count belongs to the run that ended, so the new run starts it again
478
- const { missing_since: _m, goal_turns: _t, goal_nudged_at: _n, idle_since: _i, worked_since_ask: _w, ...kept } = prev;
478
+ const { missing_since: _m, goal_turns: _t, goal_nudged_at: _n, ...kept } = prev;
479
479
  session = { ...kept, mode: 'adopt', launched_at: now(), seen_at: now() };
480
480
  } else if (prev.resumable !== false) {
481
481
  const r = sc([...base, '--key', `board-${task.id}-r${runId}-resume`, '--input',
@@ -915,8 +915,10 @@ function readMailbox(board, address, report) {
915
915
  * The board's heartbeat for a pane session: a running card's session never sits idle without deciding. Each tick, a
916
916
  * session that is idle while its card is still running is asked to decide: `request-review` when the work is done,
917
917
  * `block` with its kind when it cannot go on (waiting on a person, a capability, another card), or keep working. A
918
- * goal card (Hermes's goal loop) is told to keep going. A session is asked once it has been idle a whole tick; one
919
- * seen working since the last ask answered it, and its count starts again. After the turn budget (`goal_max_turns`, else
918
+ * goal card (Hermes's goal loop) is told to keep going. Idle is judged by the session's last message time (supercode
919
+ * reads it from the transcript), never by its status label: a session is asked once its last message is a whole tick
920
+ * old; one whose messages ran on a whole tick past the last ask answered it by working, and its count starts again
921
+ * (a reply to the ask alone is not work). After the turn budget (`goal_max_turns`, else
920
922
  * `kanban.goal_max_turns`) of asks in a row with no work and no decision (a goal card: of turns), the card is blocked `needs_input` and its creator is told.
921
923
  * Whether the work is done is the session's call through its card, not an auxiliary judge's.
922
924
  */
@@ -930,23 +932,22 @@ function pursueGoals(board, fleet, settings, report) {
930
932
  const session = runRow?.metadata?.supercode;
931
933
  if (!session?.session_id || session.surface !== 'pane') return null;
932
934
  const live = fleet.sessions.find((x) => x.address?.endsWith(`:${session.session_id}`));
933
- if (!live) return null;
934
- // a session seen working since the last ask answered it by working: its count starts again (a goal card keeps
935
- // Hermes's budget of turns); one idle for less than a whole tick is between turns, not idle
936
- if (live.status !== 'idle') {
937
- if (session.idle_since || (session.goal_nudged_at && !session.worked_since_ask)) setRunSession(db, runRow.id, { ...session, idle_since: null, worked_since_ask: true });
938
- return null;
939
- }
940
- if (!session.idle_since) { setRunSession(db, runRow.id, { ...session, idle_since: now() }); return null; }
941
- if (now() - session.idle_since < settings.interval) return null;
935
+ // a supercode that reports no last message time gives no reading, and no reading gives no verdict
936
+ const lastAt = Math.floor(Number(live.last_message_at_ms) / 1000);
937
+ if (!(lastAt > 0)) return null;
938
+ // a message within the last tick is a session working or between turns, not idle
939
+ if (now() - lastAt < settings.interval) return null;
942
940
  if (session.goal_nudged_at && now() - session.goal_nudged_at < settings.interval * 2) return null;
943
- const turns = session.worked_since_ask && !task.goal_mode ? 0 : Number(session.goal_turns ?? 0);
941
+ // messages that ran on a whole tick past the last ask answered it by working: the count starts again (a goal
942
+ // card keeps Hermes's budget of turns)
943
+ const worked = Boolean(session.goal_nudged_at) && lastAt >= session.goal_nudged_at + settings.interval;
944
+ const turns = worked && !task.goal_mode ? 0 : Number(session.goal_turns ?? 0);
944
945
  const budget = task.goal_max_turns ?? settings.goalMaxTurns;
945
946
  if (turns >= budget) {
946
947
  blockIn(db, id, { reason: `its session went idle ${budget} times without deciding done or blocked; review it`, kind: 'needs_input' });
947
948
  return null;
948
949
  }
949
- setRunSession(db, runRow.id, { ...session, goal_turns: turns + 1, goal_nudged_at: now(), worked_since_ask: false });
950
+ setRunSession(db, runRow.id, { ...session, goal_turns: turns + 1, goal_nudged_at: now() });
950
951
  event(db, id, task.goal_mode ? 'goal_continued' : 'decision_asked', { turn: turns + 1, budget }, runRow.id);
951
952
  const local = normalMachine(task.machine) === localMachine();
952
953
  const where = local ? `--root ${board.root}${board.slug !== 'default' ? ` --board ${board.slug}` : ''}` : `--at ${boardAddress(board.label)}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-orchestrator",
3
- "version": "0.4.27",
3
+ "version": "0.4.28",
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": {