audit-tools 0.32.7 → 0.32.9
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/LICENSE +15 -0
- package/README.md +2 -0
- package/dist/audit/cli/dispatch/quotaPool.d.ts +20 -2
- package/dist/audit/cli/dispatch/quotaPool.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/quotaPool.js +38 -7
- package/dist/audit/cli/dispatch/quotaPool.js.map +1 -1
- package/dist/audit/cli/dispatch/tierRouting.d.ts +4 -1
- package/dist/audit/cli/dispatch/tierRouting.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/tierRouting.js +7 -4
- package/dist/audit/cli/dispatch/tierRouting.js.map +1 -1
- package/dist/audit/cli/dispatch/types.d.ts +9 -4
- package/dist/audit/cli/dispatch/types.d.ts.map +1 -1
- package/dist/audit/cli/dispatch.d.ts +7 -0
- package/dist/audit/cli/dispatch.d.ts.map +1 -1
- package/dist/audit/cli/dispatch.js +24 -12
- package/dist/audit/cli/dispatch.js.map +1 -1
- package/dist/audit/cli/mergeAndIngestCommand.d.ts +0 -9
- package/dist/audit/cli/mergeAndIngestCommand.d.ts.map +1 -1
- package/dist/audit/cli/mergeAndIngestCommand.js +29 -1
- package/dist/audit/cli/mergeAndIngestCommand.js.map +1 -1
- package/dist/audit/cli/prompts.d.ts.map +1 -1
- package/dist/audit/cli/prompts.js +4 -2
- package/dist/audit/cli/prompts.js.map +1 -1
- package/dist/audit/cli/rollingAuditDispatch.d.ts.map +1 -1
- package/dist/audit/cli/rollingAuditDispatch.js +3 -0
- package/dist/audit/cli/rollingAuditDispatch.js.map +1 -1
- package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
- package/dist/audit/cli/semanticReviewStep.js +10 -6
- package/dist/audit/cli/semanticReviewStep.js.map +1 -1
- package/dist/audit/cli/steps.d.ts +20 -10
- package/dist/audit/cli/steps.d.ts.map +1 -1
- package/dist/audit/cli/steps.js +4 -2
- package/dist/audit/cli/steps.js.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.js +1 -0
- package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
- package/dist/audit/orchestrator/rollingDispatch.d.ts +7 -6
- package/dist/audit/orchestrator/rollingDispatch.d.ts.map +1 -1
- package/dist/audit/orchestrator/rollingDispatch.js +37 -19
- package/dist/audit/orchestrator/rollingDispatch.js.map +1 -1
- package/dist/audit/quota/index.d.ts +137 -8
- package/dist/audit/quota/index.d.ts.map +1 -1
- package/dist/audit/quota/index.js +9 -8
- package/dist/audit/quota/index.js.map +1 -1
- package/dist/remediate/contractPipeline/derive.d.ts +20 -0
- package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
- package/dist/remediate/contractPipeline/derive.js +91 -0
- package/dist/remediate/contractPipeline/derive.js.map +1 -1
- package/dist/remediate/dispatch/ownershipRegistry.d.ts +2 -22
- package/dist/remediate/dispatch/ownershipRegistry.d.ts.map +1 -1
- package/dist/remediate/dispatch/ownershipRegistry.js +7 -45
- package/dist/remediate/dispatch/ownershipRegistry.js.map +1 -1
- package/dist/remediate/index.d.ts.map +1 -1
- package/dist/remediate/index.js +17 -1
- package/dist/remediate/index.js.map +1 -1
- package/dist/remediate/phases/close.d.ts.map +1 -1
- package/dist/remediate/phases/close.js +3 -2
- package/dist/remediate/phases/close.js.map +1 -1
- package/dist/remediate/riskSignal.d.ts +6 -3
- package/dist/remediate/riskSignal.d.ts.map +1 -1
- package/dist/remediate/riskSignal.js +6 -3
- package/dist/remediate/riskSignal.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.d.ts +1 -2
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +80 -106
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/dispatch.d.ts +22 -1
- package/dist/remediate/steps/dispatch.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch.js +108 -5
- package/dist/remediate/steps/dispatch.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +89 -116
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/rollingSession.d.ts +82 -17
- package/dist/remediate/steps/rollingSession.d.ts.map +1 -1
- package/dist/remediate/steps/rollingSession.js +157 -58
- package/dist/remediate/steps/rollingSession.js.map +1 -1
- package/dist/remediate/steps/types.d.ts +12 -4
- package/dist/remediate/steps/types.d.ts.map +1 -1
- package/dist/remediate/steps/types.js +1 -1
- package/dist/shared/dispatch/admissionLoop.d.ts +245 -0
- package/dist/shared/dispatch/admissionLoop.d.ts.map +1 -0
- package/dist/shared/dispatch/admissionLoop.js +204 -0
- package/dist/shared/dispatch/admissionLoop.js.map +1 -0
- package/dist/{remediate → shared}/dispatch/ownershipScheduler.d.ts +23 -2
- package/dist/shared/dispatch/ownershipScheduler.d.ts.map +1 -0
- package/dist/{remediate → shared}/dispatch/ownershipScheduler.js +34 -6
- package/dist/shared/dispatch/ownershipScheduler.js.map +1 -0
- package/dist/shared/dispatch/pathIdentity.d.ts +26 -0
- package/dist/shared/dispatch/pathIdentity.d.ts.map +1 -0
- package/dist/shared/dispatch/pathIdentity.js +49 -0
- package/dist/shared/dispatch/pathIdentity.js.map +1 -0
- package/dist/shared/dispatch/rollingDispatch.d.ts +37 -0
- package/dist/shared/dispatch/rollingDispatch.d.ts.map +1 -1
- package/dist/shared/dispatch/rollingDispatch.js +117 -18
- package/dist/shared/dispatch/rollingDispatch.js.map +1 -1
- package/dist/shared/dispatch/unifiedRolling.d.ts +131 -0
- package/dist/shared/dispatch/unifiedRolling.d.ts.map +1 -0
- package/dist/shared/dispatch/unifiedRolling.js +161 -0
- package/dist/shared/dispatch/unifiedRolling.js.map +1 -0
- package/dist/shared/friction/stepBoundaryCapture.d.ts +4 -1
- package/dist/shared/friction/stepBoundaryCapture.d.ts.map +1 -1
- package/dist/shared/friction/stepBoundaryCapture.js.map +1 -1
- package/dist/shared/index.d.ts +12 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +18 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/quota/packetCost.d.ts +29 -0
- package/dist/shared/quota/packetCost.d.ts.map +1 -0
- package/dist/shared/quota/packetCost.js +51 -0
- package/dist/shared/quota/packetCost.js.map +1 -0
- package/dist/shared/quota/reservationLedger.d.ts +100 -0
- package/dist/shared/quota/reservationLedger.d.ts.map +1 -0
- package/dist/shared/quota/reservationLedger.js +224 -0
- package/dist/shared/quota/reservationLedger.js.map +1 -0
- package/dist/shared/quota/state.d.ts +20 -0
- package/dist/shared/quota/state.d.ts.map +1 -1
- package/dist/shared/quota/state.js +50 -0
- package/dist/shared/quota/state.js.map +1 -1
- package/dist/shared/quota/types.d.ts +11 -0
- package/dist/shared/quota/types.d.ts.map +1 -1
- package/dist/shared/quota/types.js.map +1 -1
- package/docs/audit-pkg/contracts.md +3 -1
- package/docs/audit-pkg/development.md +5 -4
- package/docs/audit-pkg/release.md +2 -3
- package/package.json +3 -1
- package/dist/remediate/dispatch/ownershipScheduler.d.ts.map +0 -1
- package/dist/remediate/dispatch/ownershipScheduler.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { mkdir, readFile, rename } from "node:fs/promises";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { StateStore } from "../state/store.js";
|
|
5
|
-
import { readOptionalJsonFile, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isRecord, withFsRetry, RunLogger, DISPATCH_PROMPT_HANDOFF_NOTE, renderQuotaCoverageNudge, renderTokenBudgetView, coerceJsonObjectArg,
|
|
5
|
+
import { readOptionalJsonFile, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isRecord, withFsRetry, RunLogger, DISPATCH_PROMPT_HANDOFF_NOTE, renderQuotaCoverageNudge, renderTokenBudgetView, coerceJsonObjectArg, driveRolling, resolveLedgerBudgets, setQuotaStateDir, interpretFreeFormIntent, advance, decideFrictionTriage, buildFrictionTriageBlock, planHybridDispatch, readSettledPools, addSettledPool, sourceByPoolId, classifyProvider, selectDispatchDriver, renderDispatchDriverInstruction, HostSessionQuotaSource, buildProviderModelKey, captureStepBoundaryFriction, LENSES, SEVERITIES } from "audit-tools/shared";
|
|
6
6
|
import { applyPlanPipeline, buildCoverageLedger } from "../phases/plan.js";
|
|
7
7
|
import { groundExtractedFindings } from "../phases/grounding.js";
|
|
8
8
|
import { runTriagePhase } from "../phases/triage.js";
|
|
@@ -10,7 +10,6 @@ import { runClosePhase } from "../phases/close.js";
|
|
|
10
10
|
import { validateRemediationPlan } from "../validation/remediationState.js";
|
|
11
11
|
import { mergeImplementResults, prepareImplementDispatch, readExtractedPlanIfPresent, buildConfirmedPools, executeNodeInWorktree, blockScopesFromPlan, declaredPathsFromPlan, targetedCommandsForBlock, } from "./dispatch.js";
|
|
12
12
|
import { makeProviderNodeDispatcher } from "./providerNodeDispatch.js";
|
|
13
|
-
import { ownershipSubWaves } from "../dispatch/ownershipScheduler.js";
|
|
14
13
|
import { prepareHostRollingDispatch, nodeClaimRegistry, nodeSettledPoolsPath } from "./rollingSession.js";
|
|
15
14
|
import { ClaimRegistry } from "../../shared/quota/claimRegistry.js";
|
|
16
15
|
import { claimWithBackoff, withClaimHeartbeat } from "../../shared/quota/claimLease.js";
|
|
@@ -339,9 +338,9 @@ function blockedByUnsatisfiedDependency(state) {
|
|
|
339
338
|
// The rolling scheduler replaced the wave-batch shim: instead of dispatching one
|
|
340
339
|
// fixed-size wave per next-step and folding back through `implementing`, a node
|
|
341
340
|
// becomes eligible the instant every dependency reaches a verified-complete
|
|
342
|
-
// disposition (INV-RS-01). Concurrency is
|
|
343
|
-
//
|
|
344
|
-
//
|
|
341
|
+
// disposition (INV-RS-01). Concurrency is emergent from admission control (the
|
|
342
|
+
// `dispatch-quota.json` `admission.granted_packet_ids` the tool admits against the
|
|
343
|
+
// live budget — INV-S05 / INV-QD-11), never a computed wave cap.
|
|
345
344
|
// A shared rebuild is interposed between dependency levels so a downstream node
|
|
346
345
|
// typechecks/runs against the freshly-built upstream `audit-tools/shared`
|
|
347
346
|
// surface; the rebuild is single-flight (CE-001) so the same package is never
|
|
@@ -495,103 +494,69 @@ export async function driveRollingDispatch(levels, options) {
|
|
|
495
494
|
setQuotaStateDir(options.quotaStateDir);
|
|
496
495
|
}
|
|
497
496
|
const estimateTokens = options.estimateTokens ?? (() => 2000);
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
497
|
+
const scopeForBlock = options.scopeForBlock ?? ((b) => b.touched_files ?? []);
|
|
498
|
+
const allBlocks = levels.flat();
|
|
499
|
+
const blockById = new Map(allBlocks.map((b) => [b.block_id, b]));
|
|
500
|
+
const hostSession = options.hostSession;
|
|
501
|
+
// Admission control: when a metered pool reports a finite absolute budget, the shared
|
|
502
|
+
// reservation ledger leases each node's cost before dispatch, so co-located dispatch
|
|
503
|
+
// loops on one account (a second IDE, the host + its subagents) never collectively
|
|
504
|
+
// over-admit. On the claude-code host (percent-only quota, no finite ceiling) the ledger
|
|
505
|
+
// is omitted and the reactive 429 floor is the safety — no per-dispatch lock overhead.
|
|
506
|
+
const ledgerCfg = resolveLedgerBudgets({
|
|
507
|
+
pools: options.confirmedPools,
|
|
508
|
+
sessionConfig: options.sessionConfig,
|
|
509
|
+
pendingItemTokens: allBlocks.map((b) => estimateTokens(b)),
|
|
510
|
+
});
|
|
511
|
+
// The remediate terminal adapter over the unified shared driver. What stays here is
|
|
512
|
+
// remediate's projection: a block → its ownership node (declared write-scope, so the
|
|
513
|
+
// shared `ownershipSubWaves` serializes same-file nodes / parallelizes disjoint ones)
|
|
514
|
+
// and → its dispatch packet; the shared rebuild between dependency levels; and the
|
|
515
|
+
// host-session escalation wiring. The loop, sub-wave split, and quota_paused/empty_pool
|
|
516
|
+
// terminal merge are the unified driver's.
|
|
517
|
+
const run = await driveRolling({
|
|
518
|
+
levels,
|
|
519
|
+
confirmedPools: options.confirmedPools,
|
|
520
|
+
sessionConfig: options.sessionConfig,
|
|
521
|
+
...(ledgerCfg.reservationLedger
|
|
522
|
+
? {
|
|
523
|
+
reservationLedger: ledgerCfg.reservationLedger,
|
|
524
|
+
resolvePoolBudget: ledgerCfg.resolvePoolBudget,
|
|
525
|
+
resolveOutputReservation: (_packet, poolId) => ledgerCfg.resolveOutputReservation(poolId),
|
|
515
526
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const scopeForBlock = options.scopeForBlock ?? ((b) => b.touched_files ?? []);
|
|
519
|
-
// File-ownership-disjoint admission (INV-SOO): split the level into ordered
|
|
520
|
-
// sub-waves, each a maximal file-disjoint subset (deterministic block_id
|
|
521
|
-
// tie-break AFTER the disjointness filter, INV-SOO-08). Same-file nodes land
|
|
522
|
-
// in successive sub-waves (serialize, INV-SOO-01/02) and a freed file becomes
|
|
523
|
-
// schedulable for the next sub-wave; different-file nodes share a sub-wave and
|
|
524
|
-
// parallelize up to the quota cap the dispatcher enforces (INV-SOO-03/05).
|
|
525
|
-
const subWaves = ownershipSubWaves(level.map((b) => ({
|
|
527
|
+
: {}),
|
|
528
|
+
toNode: (b) => ({
|
|
526
529
|
block_id: b.block_id,
|
|
527
530
|
write_paths: scopeForBlock(b),
|
|
528
531
|
...(b.cofile_parallel_safe !== undefined
|
|
529
532
|
? { cofile_parallel_safe: b.cofile_parallel_safe }
|
|
530
533
|
: {}),
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
});
|
|
558
|
-
dispatcher.enqueue(packets);
|
|
559
|
-
levelResults.push(...(await dispatcher.run()));
|
|
560
|
-
// Piece D: surface the wave's partial-completion terminal (quota_paused /
|
|
561
|
-
// empty_pool). Aggregate across waves keeping the EARLIEST-reset quota_paused
|
|
562
|
-
// terminal (a paused wave is retryable and should resume soonest); union the
|
|
563
|
-
// stranded ids so a later step re-dispatches all of them. An empty_pool
|
|
564
|
-
// terminal only stands when no quota_paused terminal was seen.
|
|
565
|
-
out.terminal = mergePartialTerminals(out.terminal, dispatcher.getTerminal());
|
|
566
|
-
}
|
|
567
|
-
out.levels.push({ blockIds: level.map((b) => b.block_id), results: levelResults });
|
|
568
|
-
}
|
|
569
|
-
return out;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Fold a newly-observed partial-completion terminal into the run's aggregate
|
|
573
|
-
* (piece D). Prefers `quota_paused` (retryable) over `empty_pool`; among
|
|
574
|
-
* quota_paused terminals keeps the EARLIEST `earliest_reset_at`; always unions the
|
|
575
|
-
* stranded ids so no stranded node is lost across waves.
|
|
576
|
-
*/
|
|
577
|
-
function mergePartialTerminals(prior, next) {
|
|
578
|
-
if (!next)
|
|
579
|
-
return prior;
|
|
580
|
-
if (!prior)
|
|
581
|
-
return next;
|
|
582
|
-
const strandedIds = [...new Set([...prior.stranded_ids, ...next.stranded_ids])];
|
|
583
|
-
const priorPaused = prior.reason === "quota_paused";
|
|
584
|
-
const nextPaused = next.reason === "quota_paused";
|
|
585
|
-
if (priorPaused || nextPaused) {
|
|
586
|
-
const resets = [prior.earliest_reset_at, next.earliest_reset_at].filter((r) => typeof r === "string");
|
|
587
|
-
const earliest = resets.length > 0 ? resets.sort()[0] : undefined;
|
|
588
|
-
return {
|
|
589
|
-
reason: "quota_paused",
|
|
590
|
-
stranded_ids: strandedIds,
|
|
591
|
-
...(earliest ? { earliest_reset_at: earliest } : {}),
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
return { reason: prior.reason, stranded_ids: strandedIds };
|
|
534
|
+
}),
|
|
535
|
+
toPacket: (b) => ({
|
|
536
|
+
id: b.block_id,
|
|
537
|
+
payload: { block_id: b.block_id },
|
|
538
|
+
estimatedTokens: estimateTokens(b),
|
|
539
|
+
complexity: 0.5,
|
|
540
|
+
}),
|
|
541
|
+
dispatchPacket: async (packet, slot) => options.dispatchNode(blockById.get(packet.payload.block_id), slot),
|
|
542
|
+
...(options.root !== undefined ? { root: options.root } : {}),
|
|
543
|
+
// Single-flight (CE-001) is enforced by the unified driver.
|
|
544
|
+
rebuildBetweenLevels: options.rebuildSharedBetweenLevels,
|
|
545
|
+
// Host-session escalation: feed recordLimit (write) at the rate_limited observation
|
|
546
|
+
// point and read isEscalated (strand-not-requeue). The SAME instance sized the pools,
|
|
547
|
+
// so the bounded re-limit count is account-wide.
|
|
548
|
+
...(hostSession
|
|
549
|
+
? {
|
|
550
|
+
recordRateLimit: (packet, result) => hostSession.recordLimit(result.rateLimit?.channel ?? "error", result.rateLimit?.text ?? "", packet.id),
|
|
551
|
+
isPacketEscalated: (packetId) => hostSession.isEscalated(packetId),
|
|
552
|
+
}
|
|
553
|
+
: {}),
|
|
554
|
+
});
|
|
555
|
+
return {
|
|
556
|
+
levels: run.levels.map((l) => ({ blockIds: l.nodeIds, results: l.results })),
|
|
557
|
+
rebuilds: run.rebuilds,
|
|
558
|
+
...(run.terminal ? { terminal: run.terminal } : {}),
|
|
559
|
+
};
|
|
595
560
|
}
|
|
596
561
|
/**
|
|
597
562
|
* Backends the orchestrator can drive IN-PROCESS as the per-node implement worker
|
|
@@ -665,6 +630,10 @@ export async function driveRollingImplementDispatch(options) {
|
|
|
665
630
|
hostModelId: options.waveOptions?.hostModelId,
|
|
666
631
|
// Each node runs in its own worktree, so its prompt is rooted there.
|
|
667
632
|
worktreeRootedPrompts: true,
|
|
633
|
+
// The in-process rolling engine admits + leases per-packet itself, so the
|
|
634
|
+
// dispatch-quota grant here must NOT lease (a host grant lease would
|
|
635
|
+
// double-count the same work against the shared account budget).
|
|
636
|
+
grantLeases: false,
|
|
668
637
|
});
|
|
669
638
|
if (plan.items.length === 0) {
|
|
670
639
|
return null;
|
|
@@ -1366,7 +1335,10 @@ async function buildImplementDispatchStep(ctx) {
|
|
|
1366
1335
|
const driverSelection = selectDispatchDriver({
|
|
1367
1336
|
classification: classifyProvider(hostProvider),
|
|
1368
1337
|
eligibleItemCount: rolling.session.frontier.length,
|
|
1369
|
-
|
|
1338
|
+
// The granted set's size IS the instantaneous admission width — there is no
|
|
1339
|
+
// separate concurrency number. The whole granted set runs at once, so the
|
|
1340
|
+
// driver-selection "slots" is the granted-set size.
|
|
1341
|
+
slots: rolling.session.frontier.length,
|
|
1370
1342
|
});
|
|
1371
1343
|
const rollMerge = loaderCommand(`merge-implement-results --run-id ${runId}`);
|
|
1372
1344
|
const rollNext = loaderCommand("next-step");
|
|
@@ -1383,21 +1355,23 @@ async function buildImplementDispatchStep(ctx) {
|
|
|
1383
1355
|
prompt: `
|
|
1384
1356
|
# Dispatch Implementation Work (host-subagent rolling, worktree-isolated)
|
|
1385
1357
|
|
|
1386
|
-
Each
|
|
1358
|
+
Each granted node runs in its OWN git worktree (hard isolation between nodes). The
|
|
1387
1359
|
TOOL owns commit -> verify -> merge + write-scope; you only spawn a subagent per
|
|
1388
1360
|
node and call \`accept-node\` as each finishes.
|
|
1389
1361
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1362
|
+
The tool ADMITTED this set against the live budget (and any declared in-flight cap):
|
|
1363
|
+
dispatch EXACTLY the ${rolling.session.frontier.length} node(s) below and no more.
|
|
1364
|
+
Their count is the whole grant — there is no separate concurrency cap. When they are
|
|
1365
|
+
all accepted, merge and re-invoke next-step; the tool re-grants the pending remainder.
|
|
1392
1366
|
|
|
1393
|
-
${renderDispatchDriverInstruction(driverSelection,
|
|
1367
|
+
${renderDispatchDriverInstruction(driverSelection, `the ${rolling.session.frontier.length} granted node(s)`)}
|
|
1394
1368
|
|
|
1395
|
-
Spawn ONE subagent for EACH
|
|
1369
|
+
Spawn ONE subagent for EACH granted node below. Give the subagent that node's
|
|
1396
1370
|
\`prompt\`, and set its working directory to the node's **worktree** path. The
|
|
1397
1371
|
subagent edits source files INSIDE that worktree and writes ONLY its result file.
|
|
1398
1372
|
Do NOT let any subagent edit the main repository tree.
|
|
1399
1373
|
|
|
1400
|
-
|
|
1374
|
+
Granted nodes (worktrees already created):
|
|
1401
1375
|
${nodeLines}
|
|
1402
1376
|
|
|
1403
1377
|
As EACH subagent finishes, run (substituting the finished node's block id):
|
|
@@ -1406,11 +1380,8 @@ As EACH subagent finishes, run (substituting the finished node's block id):
|
|
|
1406
1380
|
|
|
1407
1381
|
It runs the commit -> verify -> merge lifecycle for that node and prints a JSON
|
|
1408
1382
|
directive on stdout:
|
|
1409
|
-
- \`{"directive":"
|
|
1410
|
-
|
|
1411
|
-
${rolling.session.slots} running.
|
|
1412
|
-
- \`{"directive":"wait",...}\` — other nodes are still in flight; do not spawn more yet.
|
|
1413
|
-
- \`{"directive":"done",...}\` — every node has been accepted. Then run:
|
|
1383
|
+
- \`{"directive":"wait",...}\` — other granted nodes are still in flight; do not spawn more.
|
|
1384
|
+
- \`{"directive":"done",...}\` — every granted node has been accepted. Then run:
|
|
1414
1385
|
|
|
1415
1386
|
\`${rollMerge}\`
|
|
1416
1387
|
|
|
@@ -1431,8 +1402,8 @@ ${DISPATCH_PROMPT_HANDOFF_NOTE}
|
|
|
1431
1402
|
}
|
|
1432
1403
|
// Rolling per-node dispatch: prepare EVERY currently-eligible node (deps all
|
|
1433
1404
|
// verified-complete), never a single artificially-serialized block. There is
|
|
1434
|
-
// no wave-size cap — concurrency is
|
|
1435
|
-
// (`dispatch-quota.json`
|
|
1405
|
+
// no wave-size cap — concurrency is emergent from admission control
|
|
1406
|
+
// (`dispatch-quota.json` `admission.granted_packet_ids`). `prepareImplementDispatch`
|
|
1436
1407
|
// itself only admits verified-complete-eligible blocks
|
|
1437
1408
|
// (`dependencyVerifiedComplete`), so this is the rolling-eligible frontier.
|
|
1438
1409
|
const dispatchPlan = await prepareImplementDispatch({ root, artifactsDir }, runId, undefined, waveOptsImpl);
|
|
@@ -1504,15 +1475,17 @@ Read the dispatch plan and quota JSONs:
|
|
|
1504
1475
|
\`${implQuotaPath}\`
|
|
1505
1476
|
|
|
1506
1477
|
Every item in \`items\` is a node whose dependencies are all VERIFIED-COMPLETE
|
|
1507
|
-
(INV-RS-01)
|
|
1508
|
-
|
|
1509
|
-
|
|
1478
|
+
(INV-RS-01). The tool admitted a budget-bounded subset: dispatch EXACTLY the block
|
|
1479
|
+
ids in the quota file's \`admission.granted_packet_ids\` and no others — that granted
|
|
1480
|
+
set is the whole grant (there is no separate concurrency cap). Each item's
|
|
1510
1481
|
\`model_hint.tier\` suggests which model to use (small/standard/deep). If your
|
|
1511
1482
|
provider has rate limits, pace launches accordingly.
|
|
1512
1483
|
|
|
1513
|
-
For each item in \`items
|
|
1514
|
-
\`prompt_path\`. Each subagent may edit source
|
|
1515
|
-
block and must write only its assigned \`result_path\`.
|
|
1484
|
+
For each GRANTED item in \`items\` (its \`block_id\` in \`admission.granted_packet_ids\`),
|
|
1485
|
+
dispatch one subagent with that item's \`prompt_path\`. Each subagent may edit source
|
|
1486
|
+
files needed for that bounded block and must write only its assigned \`result_path\`.
|
|
1487
|
+
After the granted set is merged and you run next-step, the tool re-grants the pending
|
|
1488
|
+
remainder.
|
|
1516
1489
|
|
|
1517
1490
|
${SHARED_REBUILD_BETWEEN_LEVELS_NOTE}
|
|
1518
1491
|
|