@volter/supercode-orchestrator 0.5.154 → 0.5.156
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 -14
- package/board/dispatch.mjs +7 -3
- package/board/store.mjs +4 -0
- package/package.json +2 -2
package/board/cli.mjs
CHANGED
|
@@ -279,6 +279,9 @@ async function requestedSponsor(args) {
|
|
|
279
279
|
return { requestedByUnverified: { observation: args['requested-by'], label: resolved?.label ?? 'unresolved', request: args.request ?? null } };
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
// `list --json` reads each card's parents and standing block per card up to this many cards, and in one read of each past it
|
|
283
|
+
const LIST_PER_CARD = 64;
|
|
284
|
+
|
|
282
285
|
const tagsOf = (card) => { const tags = Array.isArray(card.tags) ? card.tags : json(card.tags, null); return Array.isArray(tags) ? tags : card.tenant ? [card.tenant] : []; };
|
|
283
286
|
|
|
284
287
|
const say = (args, human, value) => { current().out(args.json ? `${JSON.stringify(value, null, 2)}\n` : `${human}\n`); };
|
|
@@ -520,20 +523,36 @@ export async function runVerb(argv) {
|
|
|
520
523
|
if (args.json) {
|
|
521
524
|
// beyond Hermes's fields: the workflow's own status, the cards it waits on and its open run, so a reader of the
|
|
522
525
|
// whole board (a board file's sync) needs no `show` per card
|
|
523
|
-
const extra = withBoard((b) =>
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
|
|
526
|
+
const extra = withBoard((b) => {
|
|
527
|
+
// A whole board's parents and standing blocks are read once, not once per card. Asked per card, the block's
|
|
528
|
+
// read fetched every event row of every card through the card's index to answer from the few of these
|
|
529
|
+
// kinds (on 2026-10-11: 45,670 rows of a 17 MB table for 2,154 cards, to find 332), on the owner's event
|
|
530
|
+
// loop, for as long as the listing took. A short listing still asks per card: it reads less than the scan.
|
|
531
|
+
const whole = cards.length > LIST_PER_CARD;
|
|
532
|
+
const parentsOf = new Map(), standing = new Map();
|
|
533
|
+
if (whole) {
|
|
534
|
+
for (const row of b.db.prepare('SELECT child_id, parent_id FROM task_links ORDER BY child_id, parent_id').all()) {
|
|
535
|
+
if (!parentsOf.has(row.child_id)) parentsOf.set(row.child_id, []);
|
|
536
|
+
parentsOf.get(row.child_id).push(row.parent_id);
|
|
537
|
+
}
|
|
538
|
+
// in id order, so the last one kept for a card is its latest
|
|
539
|
+
for (const row of b.db.prepare("SELECT task_id, kind, payload FROM task_events WHERE kind IN ('blocked', 'unblocked', 'dependency_wait') ORDER BY id").all()) standing.set(row.task_id, row);
|
|
540
|
+
}
|
|
541
|
+
return new Map(cards.map((t) => {
|
|
542
|
+
const run = t.current_run_id ? b.db.prepare('SELECT id, status, started_at, metadata FROM task_runs WHERE id = ?').get(t.current_run_id) : null;
|
|
543
|
+
const session = run ? json(run.metadata, {})?.supercode ?? {} : {};
|
|
544
|
+
return [t.id, {
|
|
545
|
+
workflow_status: t.stage ?? t.status,
|
|
546
|
+
parents: whole ? parentsOf.get(t.id) ?? [] : b.db.prepare('SELECT parent_id FROM task_links WHERE child_id = ? ORDER BY parent_id').all(t.id).map((r) => r.parent_id),
|
|
547
|
+
run: run ? { id: run.id, status: run.status, started_at: run.started_at, session: session.address ?? session.session_id ?? null, execution: executionOf(run) } : null,
|
|
548
|
+
// the message whose answer its standing block waits for (`block --waiting-on`)
|
|
549
|
+
waiting_on: (() => {
|
|
550
|
+
const last = whole ? standing.get(t.id) : b.db.prepare("SELECT kind, payload FROM task_events WHERE task_id = ? AND kind IN ('blocked', 'unblocked', 'dependency_wait') ORDER BY id DESC LIMIT 1").get(t.id);
|
|
551
|
+
return last?.kind === 'blocked' ? json(last.payload, {})?.waiting_on ?? null : null;
|
|
552
|
+
})(),
|
|
553
|
+
}];
|
|
554
|
+
}));
|
|
555
|
+
});
|
|
537
556
|
say(args, '', cards.map((t) => ({ ...cardDict(t), ...extra.get(t.id) })));
|
|
538
557
|
return 0;
|
|
539
558
|
}
|
package/board/dispatch.mjs
CHANGED
|
@@ -838,8 +838,11 @@ async function startCards(board, fleet, lanes, settings, report, entry, effects,
|
|
|
838
838
|
};
|
|
839
839
|
for (const task of everyCard) {
|
|
840
840
|
if (only && task.id !== only) continue;
|
|
841
|
+
// a subtask or a card with a run is never started here, whatever its scope says: no scope is built to learn it (the
|
|
842
|
+
// scope of each of a board's 2,155 unarchived cards, 2,039 of them subtasks or running, was 0.8 s of every round)
|
|
843
|
+
if (task.subtask_of || task.current_run_id) continue;
|
|
841
844
|
const state = scopeFor(task).card;
|
|
842
|
-
if (
|
|
845
|
+
if (state.archived || ['done', 'cancelled'].includes(state.status)) continue;
|
|
843
846
|
if (state.dispatch_hold) { waiting(task, 'dispatch held: an explicit start or verified adoption must release it'); continue; }
|
|
844
847
|
if (workflow.run && state.paused) { waiting(task, `paused: ${state.paused.reason ?? 'manager pause'}`); continue; }
|
|
845
848
|
if (workflow.run && state.blocked_by.length) { waiting(task, `blocked by ${state.blocked_by.map(b => b.id).join(', ')}`); continue; }
|
|
@@ -3087,9 +3090,10 @@ async function activatePullRequestReviews(board, entry, report, effects, { only
|
|
|
3087
3090
|
const eligible = db => {
|
|
3088
3091
|
const task = getTask(db, id);
|
|
3089
3092
|
if (!task) return false;
|
|
3093
|
+
// a status the platform cannot request a review from needs no scope built to say so
|
|
3094
|
+
if (!transitionsFor(entry.workflow, statusOf(db, task), 'request_review').some(t => !t.by || t.by.includes('platform'))) return false;
|
|
3090
3095
|
const scope = scopeOf(db, board, task, { params: entry.params });
|
|
3091
|
-
if (
|
|
3092
|
-
scope.card.dispatch_hold || scope.card.paused || scope.card.blocked_by.length) return false;
|
|
3096
|
+
if (scope.card.dispatch_hold || scope.card.paused || scope.card.blocked_by.length) return false;
|
|
3093
3097
|
// The card's Tasks are its subtasks; an open one holds the review, and says so.
|
|
3094
3098
|
const open = scope.card.subtasks.filter(t => !['done', 'cancelled'].includes(t.status));
|
|
3095
3099
|
return open.length ? open : true;
|
package/board/store.mjs
CHANGED
|
@@ -150,6 +150,10 @@ export function layOut(db, { fresh }) {
|
|
|
150
150
|
db.exec(PUBLICATION_SCHEMA);
|
|
151
151
|
const have = new Set(db.prepare('PRAGMA table_info(supercode_cards)').all().map((c) => c.name));
|
|
152
152
|
for (const [column, type] of Object.entries(OURS_COLUMNS)) if (!have.has(column)) db.exec(`ALTER TABLE supercode_cards ADD COLUMN ${column} ${type}`);
|
|
153
|
+
// A card's subtasks are read by the arc they name, for every scope built (workflow.mjs scopeOf): without this index
|
|
154
|
+
// each read walked every card's row. Laid out here, after the column it names exists on a store of any age and before
|
|
155
|
+
// any statement is prepared; no statement names it, so a store without it is only slower.
|
|
156
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_supercode_cards_subtask_of ON supercode_cards(subtask_of)');
|
|
153
157
|
const effectColumns = new Set(db.prepare('PRAGMA table_info(supercode_effects)').all().map((c) => c.name));
|
|
154
158
|
for (const [column, type] of Object.entries(EFFECT_COLUMNS)) if (!effectColumns.has(column)) db.exec(`ALTER TABLE supercode_effects ADD COLUMN ${column} ${type}`);
|
|
155
159
|
// what changed is marked by the store itself, whoever writes it (published.mjs)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.156",
|
|
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": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"check-types": "node scripts/generate-types.mjs --check"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@volter/supercode-harness-sdk": "^0.3.
|
|
27
|
+
"@volter/supercode-harness-sdk": "^0.3.96",
|
|
28
28
|
"@volter/teams": "0.2.65",
|
|
29
29
|
"@volter/ztrack": "^2.4.23",
|
|
30
30
|
"yaml": "^2.9.0"
|