audit-tools 0.32.8 → 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/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/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/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/steps/dispatch.d.ts +22 -1
- package/dist/remediate/steps/dispatch.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch.js +89 -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 +15 -17
- package/dist/remediate/steps/rollingSession.d.ts.map +1 -1
- package/dist/remediate/steps/rollingSession.js +33 -57
- 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/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/package.json +1 -1
- package/dist/remediate/dispatch/ownershipScheduler.d.ts.map +0 -1
- package/dist/remediate/dispatch/ownershipScheduler.js.map +0 -1
|
@@ -9,6 +9,7 @@ import { verifyPairingForFinding } from "../contractPipeline/changeClassificatio
|
|
|
9
9
|
import { spawnSync } from "node:child_process";
|
|
10
10
|
import { StateStore } from "../state/store.js";
|
|
11
11
|
import { REMEDIATION_STEP, isClarificationCategory, } from "../state/types.js";
|
|
12
|
+
import { computeDispatchAdmission, createReservationLedger, tierRank } from "audit-tools/shared";
|
|
12
13
|
import { withFileLock } from "audit-tools/shared";
|
|
13
14
|
import { captureStepBoundaryFriction } from "audit-tools/shared";
|
|
14
15
|
import { findingLead, renderFindingBadgeBody } from "audit-tools/shared";
|
|
@@ -264,7 +265,39 @@ export async function buildConfirmedPools(input) {
|
|
|
264
265
|
primaryPools.push(...sourcePools);
|
|
265
266
|
return primaryPools;
|
|
266
267
|
}
|
|
267
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Build the `AdmissionPool[]` the admission loop admits against from a schedule's
|
|
270
|
+
* per-pool capacity summaries — the remediate analog of audit's `finalizeDispatchQuota`
|
|
271
|
+
* pool mapping (both feed the single-sourced `computeDispatchAdmission`, so the two
|
|
272
|
+
* orchestrators can't drift). Budget = the pool's live remaining token budget
|
|
273
|
+
* (null ⇒ optimistic +Inf); declared cap = its host in-flight cap passed VERBATIM
|
|
274
|
+
* (null ⇒ none — the only place an explicit agent-count exists); cost/capability rank
|
|
275
|
+
* from its tier; capacity = its context window (a packet's input+output envelope must fit).
|
|
276
|
+
*/
|
|
277
|
+
function admissionPoolsFromSchedule(schedule) {
|
|
278
|
+
return (schedule.capacity_pools ?? []).map((pool) => {
|
|
279
|
+
const rankNum = tierRank(pool.rank);
|
|
280
|
+
return {
|
|
281
|
+
poolId: pool.pool_id,
|
|
282
|
+
resourceKey: pool.pool_id,
|
|
283
|
+
budget: pool.remaining_token_budget ?? Number.POSITIVE_INFINITY,
|
|
284
|
+
declaredCap: pool.host_concurrency_limit?.active_subagents ?? null,
|
|
285
|
+
costRank: rankNum,
|
|
286
|
+
capabilityRank: rankNum,
|
|
287
|
+
capacityTokens: pool.resolved_limits.context_tokens,
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
export async function buildDispatchQuota(runId, phase, schedule, admissionPackets,
|
|
292
|
+
/**
|
|
293
|
+
* Whether to LEASE the granted set against the shared reservation ledger. The
|
|
294
|
+
* host-subagent path passes `true` (the host dispatches the grant across processes,
|
|
295
|
+
* so the tool reserves-before-dispatch and reconciles at accept-node). The
|
|
296
|
+
* in-process rolling engine passes `false`: it admits + leases per-packet itself, so
|
|
297
|
+
* a host-grant lease here would double-count the same work. Mirrors audit's
|
|
298
|
+
* `finalizeDispatchQuota` grantLeases parameterization.
|
|
299
|
+
*/
|
|
300
|
+
grantLeases, quotaStateEntry) {
|
|
268
301
|
let backoffState = null;
|
|
269
302
|
const count = quotaStateEntry?.consecutive_429_count ?? 0;
|
|
270
303
|
if (count > 0) {
|
|
@@ -274,12 +307,23 @@ export function buildDispatchQuota(runId, phase, schedule, quotaStateEntry) {
|
|
|
274
307
|
current_failure_weight: computeBackoffFailureWeight(count),
|
|
275
308
|
};
|
|
276
309
|
}
|
|
310
|
+
// Admission control: instead of a computed `max_concurrent_agents`, GRANT the
|
|
311
|
+
// affordable admitted set (cost-first-capable, ledger-leased). Per-packet reservation
|
|
312
|
+
// = input estimate + output envelope (declared output cap; the learned ratio refines
|
|
313
|
+
// it once a provider reports usage — dormant on the always-on claude-code host).
|
|
314
|
+
const admission = await computeDispatchAdmission({
|
|
315
|
+
packets: admissionPackets,
|
|
316
|
+
pools: admissionPoolsFromSchedule(schedule),
|
|
317
|
+
outputCap: schedule.resolved_limits.output_tokens,
|
|
318
|
+
grantLeases,
|
|
319
|
+
ledger: createReservationLedger(),
|
|
320
|
+
});
|
|
277
321
|
return {
|
|
278
322
|
contract_version: REMEDIATION_DISPATCH_QUOTA_CONTRACT_VERSION,
|
|
279
323
|
run_id: runId,
|
|
280
324
|
phase,
|
|
281
325
|
host_concurrency_limit: schedule.host_concurrency_limit,
|
|
282
|
-
|
|
326
|
+
admission,
|
|
283
327
|
estimated_wave_tokens: schedule.estimated_wave_tokens,
|
|
284
328
|
model: schedule.model,
|
|
285
329
|
confidence: schedule.confidence,
|
|
@@ -2332,6 +2376,7 @@ export async function prepareImplementDispatch(options, runId, onlyBlockId, wave
|
|
|
2332
2376
|
items,
|
|
2333
2377
|
};
|
|
2334
2378
|
await writeJsonFile(dispatchPlanPath(options.artifactsDir, runId, "implement"), plan);
|
|
2379
|
+
const estimatedSlotTokens = itemReadFileLists.map((files) => estimateImplementSlotTokens(files, options.root));
|
|
2335
2380
|
const schedule = await scheduleWave({
|
|
2336
2381
|
hostMaxConcurrent: waveOptions?.hostMaxConcurrent,
|
|
2337
2382
|
sessionConfig: waveOptions?.sessionConfig ?? null,
|
|
@@ -2340,11 +2385,20 @@ export async function prepareImplementDispatch(options, runId, onlyBlockId, wave
|
|
|
2340
2385
|
hostModels: waveOptions?.hostModels,
|
|
2341
2386
|
hostModelId: waveOptions?.hostModelId,
|
|
2342
2387
|
itemCount: items.length,
|
|
2343
|
-
estimatedSlotTokens
|
|
2388
|
+
estimatedSlotTokens,
|
|
2344
2389
|
});
|
|
2345
|
-
|
|
2390
|
+
// Admission packets in plan order: id = the node's block id (what
|
|
2391
|
+
// `admission.granted_packet_ids` references and the host matches to nodes),
|
|
2392
|
+
// inputTokens = its estimated slot cost, complexity = the remediate default 0.5.
|
|
2393
|
+
// Keyed by block_id (same filter the frontier builder uses), so a granted id always
|
|
2394
|
+
// resolves to a frontier node.
|
|
2395
|
+
const admissionPackets = items
|
|
2396
|
+
.map((item, i) => ({ item, inputTokens: estimatedSlotTokens[i] ?? 0 }))
|
|
2397
|
+
.filter((p) => typeof p.item.block_id === "string")
|
|
2398
|
+
.map((p) => ({ id: p.item.block_id, inputTokens: p.inputTokens, complexity: 0.5 }));
|
|
2399
|
+
process.stderr.write(`[remediate-code] dispatch: implement ${items.length} item(s) ` +
|
|
2346
2400
|
`source=${schedule.source} cap=${schedule.binding_cap ?? "none"}\n`);
|
|
2347
|
-
const quota = buildDispatchQuota(runId, "implement", schedule);
|
|
2401
|
+
const quota = await buildDispatchQuota(runId, "implement", schedule, admissionPackets, waveOptions?.grantLeases ?? true);
|
|
2348
2402
|
await writeJsonFile(join(dir, "dispatch-quota.json"), quota);
|
|
2349
2403
|
return plan;
|
|
2350
2404
|
}
|
|
@@ -2870,7 +2924,37 @@ function obligationIdsForFinding(state, findingId) {
|
|
|
2870
2924
|
...(finding.verification_obligation_ids ?? []),
|
|
2871
2925
|
];
|
|
2872
2926
|
}
|
|
2927
|
+
/**
|
|
2928
|
+
* Reconcile (free) the reservation-ledger leases the dispatch grant took for this
|
|
2929
|
+
* run's granted set — the "reconcile at result-ingest" half of admission control
|
|
2930
|
+
* (spec/audit/dispatch-admission-control.md), the remediate analog of audit's
|
|
2931
|
+
* `reconcileAdmissionLeases`. The host has now reported the granted set's results, so
|
|
2932
|
+
* those reservations are no longer in flight and their budget returns to the shared
|
|
2933
|
+
* account for the NEXT grant. Best-effort + token-checked (a missing/already-freed
|
|
2934
|
+
* lease is a no-op), so a lost reconcile self-heals via the lease TTL and never blocks
|
|
2935
|
+
* the merge. Only the host-subagent grant persists leases (`grantLeases: true`); the
|
|
2936
|
+
* in-process path leases per-packet in the engine and reconciles there.
|
|
2937
|
+
*/
|
|
2938
|
+
async function reconcileAdmissionLeases(artifactsDir, runId) {
|
|
2939
|
+
const quotaPath = join(runDir(artifactsDir, runId, "implement"), "dispatch-quota.json");
|
|
2940
|
+
const quota = await readOptionalJsonFile(quotaPath);
|
|
2941
|
+
const leases = quota?.admission?.leases;
|
|
2942
|
+
if (!leases || leases.length === 0)
|
|
2943
|
+
return;
|
|
2944
|
+
const ledger = createReservationLedger();
|
|
2945
|
+
for (const lease of leases) {
|
|
2946
|
+
try {
|
|
2947
|
+
await ledger.reconcile(lease.resource_key, lease.lease_id);
|
|
2948
|
+
}
|
|
2949
|
+
catch {
|
|
2950
|
+
// Best-effort: the lease TTL reclaims budget if a reconcile is lost.
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2873
2954
|
export async function mergeImplementResults(options, runId) {
|
|
2955
|
+
// Free the grant's reservation-ledger leases now that the host has reported the
|
|
2956
|
+
// granted set's results — returns the reserved budget for the next grant.
|
|
2957
|
+
await reconcileAdmissionLeases(options.artifactsDir, runId);
|
|
2874
2958
|
const plan = await readJsonFile(dispatchPlanPath(options.artifactsDir, runId, "implement"));
|
|
2875
2959
|
if (plan.contract_version !== REMEDIATION_DISPATCH_PLAN_CONTRACT_VERSION ||
|
|
2876
2960
|
plan.phase !== "implement") {
|