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.
Files changed (99) hide show
  1. package/dist/audit/cli/dispatch/quotaPool.d.ts +20 -2
  2. package/dist/audit/cli/dispatch/quotaPool.d.ts.map +1 -1
  3. package/dist/audit/cli/dispatch/quotaPool.js +38 -7
  4. package/dist/audit/cli/dispatch/quotaPool.js.map +1 -1
  5. package/dist/audit/cli/dispatch/tierRouting.d.ts +4 -1
  6. package/dist/audit/cli/dispatch/tierRouting.d.ts.map +1 -1
  7. package/dist/audit/cli/dispatch/tierRouting.js +7 -4
  8. package/dist/audit/cli/dispatch/tierRouting.js.map +1 -1
  9. package/dist/audit/cli/dispatch/types.d.ts +9 -4
  10. package/dist/audit/cli/dispatch/types.d.ts.map +1 -1
  11. package/dist/audit/cli/dispatch.d.ts +7 -0
  12. package/dist/audit/cli/dispatch.d.ts.map +1 -1
  13. package/dist/audit/cli/dispatch.js +24 -12
  14. package/dist/audit/cli/dispatch.js.map +1 -1
  15. package/dist/audit/cli/mergeAndIngestCommand.d.ts +0 -9
  16. package/dist/audit/cli/mergeAndIngestCommand.d.ts.map +1 -1
  17. package/dist/audit/cli/mergeAndIngestCommand.js +29 -1
  18. package/dist/audit/cli/mergeAndIngestCommand.js.map +1 -1
  19. package/dist/audit/cli/prompts.d.ts.map +1 -1
  20. package/dist/audit/cli/prompts.js +4 -2
  21. package/dist/audit/cli/prompts.js.map +1 -1
  22. package/dist/audit/cli/rollingAuditDispatch.d.ts.map +1 -1
  23. package/dist/audit/cli/rollingAuditDispatch.js +3 -0
  24. package/dist/audit/cli/rollingAuditDispatch.js.map +1 -1
  25. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  26. package/dist/audit/cli/semanticReviewStep.js +10 -6
  27. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  28. package/dist/audit/cli/steps.d.ts +20 -10
  29. package/dist/audit/cli/steps.d.ts.map +1 -1
  30. package/dist/audit/cli/steps.js +4 -2
  31. package/dist/audit/cli/steps.js.map +1 -1
  32. package/dist/audit/orchestrator/rollingDispatch.d.ts +7 -6
  33. package/dist/audit/orchestrator/rollingDispatch.d.ts.map +1 -1
  34. package/dist/audit/orchestrator/rollingDispatch.js +37 -19
  35. package/dist/audit/orchestrator/rollingDispatch.js.map +1 -1
  36. package/dist/audit/quota/index.d.ts +137 -8
  37. package/dist/audit/quota/index.d.ts.map +1 -1
  38. package/dist/audit/quota/index.js +9 -8
  39. package/dist/audit/quota/index.js.map +1 -1
  40. package/dist/remediate/dispatch/ownershipRegistry.d.ts +2 -22
  41. package/dist/remediate/dispatch/ownershipRegistry.d.ts.map +1 -1
  42. package/dist/remediate/dispatch/ownershipRegistry.js +7 -45
  43. package/dist/remediate/dispatch/ownershipRegistry.js.map +1 -1
  44. package/dist/remediate/steps/dispatch.d.ts +22 -1
  45. package/dist/remediate/steps/dispatch.d.ts.map +1 -1
  46. package/dist/remediate/steps/dispatch.js +89 -5
  47. package/dist/remediate/steps/dispatch.js.map +1 -1
  48. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  49. package/dist/remediate/steps/nextStep.js +89 -116
  50. package/dist/remediate/steps/nextStep.js.map +1 -1
  51. package/dist/remediate/steps/rollingSession.d.ts +15 -17
  52. package/dist/remediate/steps/rollingSession.d.ts.map +1 -1
  53. package/dist/remediate/steps/rollingSession.js +33 -57
  54. package/dist/remediate/steps/rollingSession.js.map +1 -1
  55. package/dist/remediate/steps/types.d.ts +12 -4
  56. package/dist/remediate/steps/types.d.ts.map +1 -1
  57. package/dist/remediate/steps/types.js +1 -1
  58. package/dist/shared/dispatch/admissionLoop.d.ts +245 -0
  59. package/dist/shared/dispatch/admissionLoop.d.ts.map +1 -0
  60. package/dist/shared/dispatch/admissionLoop.js +204 -0
  61. package/dist/shared/dispatch/admissionLoop.js.map +1 -0
  62. package/dist/{remediate → shared}/dispatch/ownershipScheduler.d.ts +23 -2
  63. package/dist/shared/dispatch/ownershipScheduler.d.ts.map +1 -0
  64. package/dist/{remediate → shared}/dispatch/ownershipScheduler.js +34 -6
  65. package/dist/shared/dispatch/ownershipScheduler.js.map +1 -0
  66. package/dist/shared/dispatch/pathIdentity.d.ts +26 -0
  67. package/dist/shared/dispatch/pathIdentity.d.ts.map +1 -0
  68. package/dist/shared/dispatch/pathIdentity.js +49 -0
  69. package/dist/shared/dispatch/pathIdentity.js.map +1 -0
  70. package/dist/shared/dispatch/rollingDispatch.d.ts +37 -0
  71. package/dist/shared/dispatch/rollingDispatch.d.ts.map +1 -1
  72. package/dist/shared/dispatch/rollingDispatch.js +117 -18
  73. package/dist/shared/dispatch/rollingDispatch.js.map +1 -1
  74. package/dist/shared/dispatch/unifiedRolling.d.ts +131 -0
  75. package/dist/shared/dispatch/unifiedRolling.d.ts.map +1 -0
  76. package/dist/shared/dispatch/unifiedRolling.js +161 -0
  77. package/dist/shared/dispatch/unifiedRolling.js.map +1 -0
  78. package/dist/shared/index.d.ts +12 -1
  79. package/dist/shared/index.d.ts.map +1 -1
  80. package/dist/shared/index.js +18 -1
  81. package/dist/shared/index.js.map +1 -1
  82. package/dist/shared/quota/packetCost.d.ts +29 -0
  83. package/dist/shared/quota/packetCost.d.ts.map +1 -0
  84. package/dist/shared/quota/packetCost.js +51 -0
  85. package/dist/shared/quota/packetCost.js.map +1 -0
  86. package/dist/shared/quota/reservationLedger.d.ts +100 -0
  87. package/dist/shared/quota/reservationLedger.d.ts.map +1 -0
  88. package/dist/shared/quota/reservationLedger.js +224 -0
  89. package/dist/shared/quota/reservationLedger.js.map +1 -0
  90. package/dist/shared/quota/state.d.ts +20 -0
  91. package/dist/shared/quota/state.d.ts.map +1 -1
  92. package/dist/shared/quota/state.js +50 -0
  93. package/dist/shared/quota/state.js.map +1 -1
  94. package/dist/shared/quota/types.d.ts +11 -0
  95. package/dist/shared/quota/types.d.ts.map +1 -1
  96. package/dist/shared/quota/types.js.map +1 -1
  97. package/package.json +1 -1
  98. package/dist/remediate/dispatch/ownershipScheduler.d.ts.map +0 -1
  99. package/dist/remediate/dispatch/ownershipScheduler.js.map +0 -1
@@ -0,0 +1,204 @@
1
+ // Host-path admission loop — the tool-side "grant the admitted set" primitive of
2
+ // the dispatch admission-control model (spec/audit/dispatch-admission-control.md).
3
+ //
4
+ // The in-process rolling engine (rollingDispatch.ts) admits ONE packet at a time
5
+ // continuously; this is its host-subagent-path analog: at a dispatch step the tool
6
+ // admits a BATCH — as many packets as budget (and any declared in-flight cap) allow
7
+ // right now — reserving each against the shared ReservationLedger, and hands the
8
+ // host EXACTLY that granted set. The host dispatches the set, reports at
9
+ // result-ingest (merge-and-ingest), and the next `next-step` re-admits the
10
+ // remainder. The granted set's size is the instantaneous admission width — there is
11
+ // no computed concurrency number (spec: "concurrency is not a computed quantity").
12
+ //
13
+ // COST-FIRST ROUTING is a first-class property: each packet is routed to the
14
+ // CHEAPEST pool CAPABLE of it (cost-ascending among capable pools) that still has
15
+ // budget + in-flight-cap headroom, so lower-cost providers fill before pricier ones
16
+ // and overflow spills to the next-cheapest-capable pool. The capability gate and
17
+ // cost rank are inputs, so refining the complexity/risk gate is a one-predicate
18
+ // change, never a re-architecture.
19
+ import { z } from "zod";
20
+ import { estimatePacketCost } from "../quota/packetCost.js";
21
+ export const AdmissionGrantSchema = z
22
+ .object({
23
+ packet_id: z.string(),
24
+ pool_id: z.string(),
25
+ resource_key: z.string(),
26
+ lease_id: z.string(),
27
+ cost: z.number(),
28
+ })
29
+ .strict();
30
+ /** Why a packet was admitted or blocked — the per-admission explain record. */
31
+ export const AdmissionExplainSchema = z
32
+ .object({
33
+ packet_id: z.string(),
34
+ /** null only when NO pool was capable of the packet at all. */
35
+ pool_id: z.string().nullable(),
36
+ resource_key: z.string().nullable(),
37
+ admitted: z.boolean(),
38
+ reason: z.enum(["admitted", "no_capable_pool", "budget_exhausted", "cap_reached"]),
39
+ /** Present on an admit attempt against a real pool (budget headroom before it). */
40
+ headroom_before: z.number().optional(),
41
+ outstanding_before: z.number().optional(),
42
+ cost: z.number(),
43
+ })
44
+ .strict();
45
+ /**
46
+ * The admission artifact both orchestrators embed in their dispatch-quota contract,
47
+ * REPLACING the removed `max_concurrent_agents` scalar. `granted_packet_ids` is the
48
+ * set the host dispatches this step (its size is the emergent admission width);
49
+ * `declared_cap` is the verbatim per-environment hard in-flight cap (null when
50
+ * none); `leases` are reconciled (freed) at result-ingest; `explains` reconstruct
51
+ * why the fan-out was the width it was.
52
+ */
53
+ export const DispatchAdmissionSchema = z
54
+ .object({
55
+ granted_packet_ids: z.array(z.string()),
56
+ declared_cap: z.number().int().min(1).nullable(),
57
+ leases: z.array(AdmissionGrantSchema),
58
+ explains: z.array(AdmissionExplainSchema),
59
+ })
60
+ .strict();
61
+ /** Default capability gate: the pool's window must fit the packet's reservation. */
62
+ function defaultCapable(pool, packet) {
63
+ if (!Number.isFinite(pool.capacityTokens) || pool.capacityTokens <= 0)
64
+ return true;
65
+ return pool.capacityTokens >= packet.cost;
66
+ }
67
+ /**
68
+ * Admit as many packets as budget + declared caps allow this pass, routing each to
69
+ * the cheapest capable pool with headroom. Every admission RESERVES the packet's
70
+ * cost against the shared ledger under its lock, so co-located dispatch loops on one
71
+ * account cannot collectively over-admit. Returns the granted set (the host
72
+ * dispatches exactly these), the explain trail, and the blocked remainder.
73
+ *
74
+ * A pool's declared in-flight cap is enforced by COUNT of its outstanding ledger
75
+ * leases (cross-process) plus this batch's grants — the only place an explicit
76
+ * agent-count exists (a verbatim environment limit), never a computed concurrency.
77
+ */
78
+ export async function admitBatch(input) {
79
+ const capable = input.capable ?? defaultCapable;
80
+ const granted = [];
81
+ const explains = [];
82
+ const blocked = [];
83
+ // Seed per-pool in-flight COUNT from the ledger (other consumers' live leases),
84
+ // so a declared cap accounts for cross-process in-flight, then add this batch's.
85
+ const countByPool = new Map();
86
+ try {
87
+ const snapshot = await input.ledger.snapshot();
88
+ for (const leases of Object.values(snapshot)) {
89
+ for (const lease of leases) {
90
+ countByPool.set(lease.poolId, (countByPool.get(lease.poolId) ?? 0) + 1);
91
+ }
92
+ }
93
+ }
94
+ catch {
95
+ // Degrade-safe: an unreadable ledger just means cap counting starts at 0.
96
+ }
97
+ for (const packet of input.packets) {
98
+ // Cost-first-capable: cheapest capable pool first; ties break toward the more
99
+ // capable pool so equal-cost lanes prefer the one with more headroom.
100
+ const candidates = input.pools
101
+ .filter((pool) => capable(pool, packet))
102
+ .sort((a, b) => a.costRank - b.costRank || b.capabilityRank - a.capabilityRank);
103
+ if (candidates.length === 0) {
104
+ explains.push({
105
+ packet_id: packet.id,
106
+ pool_id: null,
107
+ resource_key: null,
108
+ admitted: false,
109
+ reason: "no_capable_pool",
110
+ cost: packet.cost,
111
+ });
112
+ blocked.push(packet.id);
113
+ continue;
114
+ }
115
+ let placed = false;
116
+ let lastReason = "budget_exhausted";
117
+ let lastPool = candidates[0];
118
+ for (const pool of candidates) {
119
+ if (pool.declaredCap != null && (countByPool.get(pool.poolId) ?? 0) >= pool.declaredCap) {
120
+ lastReason = "cap_reached";
121
+ lastPool = pool;
122
+ continue;
123
+ }
124
+ const decision = await input.ledger.admit({
125
+ resourceKey: pool.resourceKey,
126
+ cost: packet.cost,
127
+ budget: pool.budget,
128
+ poolId: pool.poolId,
129
+ ...(input.leaseTtlMs != null ? { leaseTtlMs: input.leaseTtlMs } : {}),
130
+ });
131
+ if (decision.admitted && decision.leaseId) {
132
+ granted.push({
133
+ packet_id: packet.id,
134
+ pool_id: pool.poolId,
135
+ resource_key: pool.resourceKey,
136
+ lease_id: decision.leaseId,
137
+ cost: packet.cost,
138
+ });
139
+ countByPool.set(pool.poolId, (countByPool.get(pool.poolId) ?? 0) + 1);
140
+ explains.push({
141
+ packet_id: packet.id,
142
+ pool_id: pool.poolId,
143
+ resource_key: pool.resourceKey,
144
+ admitted: true,
145
+ reason: "admitted",
146
+ headroom_before: decision.headroomBefore,
147
+ outstanding_before: decision.outstandingBefore,
148
+ cost: packet.cost,
149
+ });
150
+ placed = true;
151
+ break;
152
+ }
153
+ lastReason = "budget_exhausted";
154
+ lastPool = pool;
155
+ }
156
+ if (!placed) {
157
+ explains.push({
158
+ packet_id: packet.id,
159
+ pool_id: lastPool.poolId,
160
+ resource_key: lastPool.resourceKey,
161
+ admitted: false,
162
+ reason: lastReason,
163
+ cost: packet.cost,
164
+ });
165
+ blocked.push(packet.id);
166
+ }
167
+ }
168
+ return { granted, explains, blocked };
169
+ }
170
+ /**
171
+ * Build the `DispatchAdmission` contract block both orchestrators embed in their
172
+ * dispatch-quota — the single-sourced host-path admission derivation (no per-tool
173
+ * copy that could drift). Computes each packet's envelope reservation
174
+ * (`estimatePacketCost` with the declared output cap), derives the surfaced declared
175
+ * cap (the most-constraining pool's in-flight cap), and either GRANTS via
176
+ * {@link admitBatch} (host-subagent path, `grantLeases: true` — leases persist for
177
+ * reconcile at ingest) or returns a plan-only block listing every candidate
178
+ * (`grantLeases: false` — the in-process rolling engine leases per-packet itself,
179
+ * so a host grant here would double-count).
180
+ */
181
+ export async function computeDispatchAdmission(input) {
182
+ const candidates = input.packets.map((p) => ({
183
+ id: p.id,
184
+ cost: estimatePacketCost({ inputEstimate: p.inputTokens, declaredOutputCap: input.outputCap }).cost,
185
+ complexity: p.complexity,
186
+ }));
187
+ const declaredCap = input.pools.reduce((min, p) => (p.declaredCap == null ? min : min == null ? p.declaredCap : Math.min(min, p.declaredCap)), null);
188
+ if (!input.grantLeases) {
189
+ return { granted_packet_ids: candidates.map((c) => c.id), declared_cap: declaredCap, leases: [], explains: [] };
190
+ }
191
+ const admit = await admitBatch({
192
+ packets: candidates,
193
+ pools: input.pools,
194
+ ledger: input.ledger,
195
+ ...(input.capable ? { capable: input.capable } : {}),
196
+ });
197
+ return {
198
+ granted_packet_ids: admit.granted.map((g) => g.packet_id),
199
+ declared_cap: declaredCap,
200
+ leases: admit.granted,
201
+ explains: admit.explains,
202
+ };
203
+ }
204
+ //# sourceMappingURL=admissionLoop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admissionLoop.js","sourceRoot":"","sources":["../../../src/shared/dispatch/admissionLoop.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,17 @@
22
22
  * region-disjoint upstream). If either lacks the flag they serialize into
23
23
  * successive sub-waves exactly as before — the conservative default is unchanged.
24
24
  *
25
+ * Three disjointness cases, not two (the read-only distinction): (1) a node that is
26
+ * provably READ-ONLY (`read_only === true`, no writes at all) conflicts with nothing
27
+ * and admits into any sub-wave — all read-only nodes collapse into the first maximal
28
+ * sub-wave (this is how an auditor, which writes nothing, runs fully parallel as a
29
+ * degenerate case of the same scheduler); (2) a node with a DECLARED write-scope
30
+ * batches file-disjointly (the `cofile_parallel_safe` relaxation above); (3) a node
31
+ * with an EMPTY/undeclared scope is conservatively non-disjoint and admits solo among
32
+ * writers. Case (1) is distinct from case (3): an empty `write_paths` means "scope
33
+ * unresolved, might touch anything" (serialize), whereas `read_only` means "provably
34
+ * touches nothing" (always parallel).
35
+ *
25
36
  * Pure and deterministic — no I/O, no Set/Map iteration-order leak — so the
26
37
  * admission order is reproducible and unit-testable against a precomputed level.
27
38
  */
@@ -36,6 +47,15 @@ export interface OwnershipSchedulerNode {
36
47
  * Absent/false ⇒ the node serializes vs. any same-file peer exactly as before.
37
48
  */
38
49
  cofile_parallel_safe?: boolean;
50
+ /**
51
+ * The node is provably READ-ONLY — it performs no writes to the target tree, so it
52
+ * can never conflict with any peer at merge and admits into any sub-wave in full
53
+ * parallel. This is DISTINCT from an empty/undeclared `write_paths`: empty means the
54
+ * write-scope is *unresolved* (conservatively serial); `read_only` means the node is
55
+ * *known* to write nothing (an auditor). Absent/false ⇒ the node is treated as a
56
+ * writer and goes through the normal file-disjointness gating.
57
+ */
58
+ read_only?: boolean;
39
59
  }
40
60
  /**
41
61
  * Canonicalize a node's declared write-scope to physical-file identity keys.
@@ -52,8 +72,9 @@ export declare function canonicalScopeKeys(node: OwnershipSchedulerNode, root?:
52
72
  *
53
73
  * A node with an EMPTY canonical scope (unresolved/undeclared) is treated as
54
74
  * conservatively NON-disjoint: it only enters a sub-wave by itself (it blocks and
55
- * is blocked-by every peer), so it never batches with another writer
56
- * (INV-SOO-01 / CE-008).
75
+ * is blocked-by every peer writer), so it never batches with another writer
76
+ * (INV-SOO-01 / CE-008). A `read_only` node is the opposite — it writes nothing, so
77
+ * it admits into any sub-wave in full parallel (see the three-case note above).
57
78
  */
58
79
  export declare function ownershipSubWaves(level: OwnershipSchedulerNode[], root?: string): OwnershipSchedulerNode[][];
59
80
  //# sourceMappingURL=ownershipScheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownershipScheduler.d.ts","sourceRoot":"","sources":["../../../src/shared/dispatch/ownershipScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,IAAI,CAAC,EAAE,MAAM,GACZ,GAAG,CAAC,MAAM,CAAC,CAIb;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,sBAAsB,EAAE,EAC/B,IAAI,CAAC,EAAE,MAAM,GACZ,sBAAsB,EAAE,EAAE,CAoF5B"}
@@ -22,10 +22,21 @@
22
22
  * region-disjoint upstream). If either lacks the flag they serialize into
23
23
  * successive sub-waves exactly as before — the conservative default is unchanged.
24
24
  *
25
+ * Three disjointness cases, not two (the read-only distinction): (1) a node that is
26
+ * provably READ-ONLY (`read_only === true`, no writes at all) conflicts with nothing
27
+ * and admits into any sub-wave — all read-only nodes collapse into the first maximal
28
+ * sub-wave (this is how an auditor, which writes nothing, runs fully parallel as a
29
+ * degenerate case of the same scheduler); (2) a node with a DECLARED write-scope
30
+ * batches file-disjointly (the `cofile_parallel_safe` relaxation above); (3) a node
31
+ * with an EMPTY/undeclared scope is conservatively non-disjoint and admits solo among
32
+ * writers. Case (1) is distinct from case (3): an empty `write_paths` means "scope
33
+ * unresolved, might touch anything" (serialize), whereas `read_only` means "provably
34
+ * touches nothing" (always parallel).
35
+ *
25
36
  * Pure and deterministic — no I/O, no Set/Map iteration-order leak — so the
26
37
  * admission order is reproducible and unit-testable against a precomputed level.
27
38
  */
28
- import { canonicalizeFilePath } from "./ownershipRegistry.js";
39
+ import { canonicalizeFilePath } from "./pathIdentity.js";
29
40
  /**
30
41
  * Canonicalize a node's declared write-scope to physical-file identity keys.
31
42
  * Empty input ⇒ empty set (handled conservatively by the disjointness gate).
@@ -46,8 +57,9 @@ export function canonicalScopeKeys(node, root) {
46
57
  *
47
58
  * A node with an EMPTY canonical scope (unresolved/undeclared) is treated as
48
59
  * conservatively NON-disjoint: it only enters a sub-wave by itself (it blocks and
49
- * is blocked-by every peer), so it never batches with another writer
50
- * (INV-SOO-01 / CE-008).
60
+ * is blocked-by every peer writer), so it never batches with another writer
61
+ * (INV-SOO-01 / CE-008). A `read_only` node is the opposite — it writes nothing, so
62
+ * it admits into any sub-wave in full parallel (see the three-case note above).
51
63
  */
52
64
  export function ownershipSubWaves(level, root) {
53
65
  const ordered = [...level].sort((a, b) => a.block_id.localeCompare(b.block_id));
@@ -63,13 +75,28 @@ export function ownershipSubWaves(level, root) {
63
75
  // co-batch on a shared key IFF both are `cofile_parallel_safe`.
64
76
  const claimant = new Map();
65
77
  let waveHasEmptyScopeNode = false;
78
+ // A writer or empty-scope node has been admitted to this sub-wave. Gates the
79
+ // empty-scope node's solo admission: it may enter only when no writer and no
80
+ // prior empty-scope node is present. A `read_only` co-resident is NOT a writer,
81
+ // so it never trips this — read-only nodes stay fully inert to the conflict logic.
82
+ let waveHasWriter = false;
66
83
  const leftover = [];
67
84
  for (const node of remaining) {
68
85
  const scope = scopeOf.get(node.block_id);
86
+ // Case 1: provably READ-ONLY (writes nothing) ⇒ conflicts with nothing. Admit to
87
+ // the current sub-wave unconditionally; never claim a path, never set or consult
88
+ // the writer/empty-scope flags. All read-only nodes therefore collapse into the
89
+ // first (maximal) sub-wave — an auditor's full-parallel degenerate case.
90
+ if (node.read_only === true) {
91
+ wave.push(node);
92
+ continue;
93
+ }
69
94
  const isEmpty = scope.size === 0;
70
- // Empty-scope node admits only into an otherwise-empty sub-wave (solo).
95
+ // Case 3: empty/undeclared scope conservatively non-disjoint. Admits only into
96
+ // a sub-wave with no other writer and no prior empty-scope node (solo among
97
+ // writers; read-only co-residents don't count).
71
98
  if (isEmpty) {
72
- if (wave.length === 0) {
99
+ if (!waveHasWriter && !waveHasEmptyScopeNode) {
73
100
  wave.push(node);
74
101
  waveHasEmptyScopeNode = true;
75
102
  }
@@ -78,7 +105,7 @@ export function ownershipSubWaves(level, root) {
78
105
  }
79
106
  continue;
80
107
  }
81
- // A real-scope node cannot share a wave with an empty-scope node, nor with
108
+ // Case 2: a real-scope node cannot share a wave with an empty-scope node, nor with
82
109
  // any node it shares a canonical path with — UNLESS both this node and every
83
110
  // same-file incumbent it collides with are `cofile_parallel_safe`.
84
111
  if (waveHasEmptyScopeNode) {
@@ -104,6 +131,7 @@ export function ownershipSubWaves(level, root) {
104
131
  for (const key of scope)
105
132
  claimant.set(key, node);
106
133
  wave.push(node);
134
+ waveHasWriter = true;
107
135
  }
108
136
  subWaves.push(wave);
109
137
  remaining.length = 0;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownershipScheduler.js","sourceRoot":"","sources":["../../../src/shared/dispatch/ownershipScheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The single-sourced path canonicalization for ownership identity (INV-SOO-09).
3
+ *
4
+ * Resolves a path to a stable physical-file key: absolute (against `root` when
5
+ * supplied, else cwd), `..`/`.`-collapsed (via `resolve`), separators normalized
6
+ * to `/`, and case-folded on a case-insensitive filesystem. All spellings of one
7
+ * file therefore collide, closing the rel/abs/case/`..` mismatch (CE-004).
8
+ *
9
+ * Symlink identity is a RECORDED RESIDUAL, not silently treated as disjoint
10
+ * (INV-SOO-09 / fail-3): when `resolveSymlinks` is set and the path exists, the
11
+ * realpath is folded in so `link.ts → x.ts` collides; when realpath is
12
+ * unavailable (path absent, or FS symlink resolution out of scope) the lexical
13
+ * canonical key is used and the unresolved case degrades to the downstream merge
14
+ * guard rather than being asserted disjoint here.
15
+ *
16
+ * This is the ONLY normalization scheme for ownership identity — callers must
17
+ * not introduce a second one (failure-mode: path-identity mismatch). It lives in
18
+ * `audit-tools/shared` so BOTH orchestrators' ownership scheduling resolves file
19
+ * identity identically (a remediate write-scope and an audit read-scope key the
20
+ * same file the same way).
21
+ */
22
+ export declare function canonicalizeFilePath(path: string, opts?: {
23
+ root?: string;
24
+ resolveSymlinks?: boolean;
25
+ }): string;
26
+ //# sourceMappingURL=pathIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathIdentity.d.ts","sourceRoot":"","sources":["../../../src/shared/dispatch/pathIdentity.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GACtD,MAAM,CAgBR"}
@@ -0,0 +1,49 @@
1
+ import { realpathSync } from "node:fs";
2
+ import { isAbsolute, resolve, sep } from "node:path";
3
+ /**
4
+ * Whether the host filesystem is case-insensitive for path identity. win32 and
5
+ * darwin default to case-insensitive volumes; linux is case-sensitive. Used so
6
+ * `src/A.ts` and `src/a.ts` collide on a Windows/macOS volume (one physical
7
+ * file) but stay distinct on Linux — INV-SOO-09 canonical physical-file identity.
8
+ */
9
+ const CASE_INSENSITIVE_FS = process.platform === "win32" || process.platform === "darwin";
10
+ /**
11
+ * The single-sourced path canonicalization for ownership identity (INV-SOO-09).
12
+ *
13
+ * Resolves a path to a stable physical-file key: absolute (against `root` when
14
+ * supplied, else cwd), `..`/`.`-collapsed (via `resolve`), separators normalized
15
+ * to `/`, and case-folded on a case-insensitive filesystem. All spellings of one
16
+ * file therefore collide, closing the rel/abs/case/`..` mismatch (CE-004).
17
+ *
18
+ * Symlink identity is a RECORDED RESIDUAL, not silently treated as disjoint
19
+ * (INV-SOO-09 / fail-3): when `resolveSymlinks` is set and the path exists, the
20
+ * realpath is folded in so `link.ts → x.ts` collides; when realpath is
21
+ * unavailable (path absent, or FS symlink resolution out of scope) the lexical
22
+ * canonical key is used and the unresolved case degrades to the downstream merge
23
+ * guard rather than being asserted disjoint here.
24
+ *
25
+ * This is the ONLY normalization scheme for ownership identity — callers must
26
+ * not introduce a second one (failure-mode: path-identity mismatch). It lives in
27
+ * `audit-tools/shared` so BOTH orchestrators' ownership scheduling resolves file
28
+ * identity identically (a remediate write-scope and an audit read-scope key the
29
+ * same file the same way).
30
+ */
31
+ export function canonicalizeFilePath(path, opts = {}) {
32
+ const { root, resolveSymlinks = false } = opts;
33
+ let abs = isAbsolute(path)
34
+ ? resolve(path)
35
+ : resolve(root ?? process.cwd(), path);
36
+ if (resolveSymlinks) {
37
+ try {
38
+ abs = realpathSync(abs);
39
+ }
40
+ catch {
41
+ // Symlink/realpath unavailable (path absent or FS resolution out of scope):
42
+ // keep the lexical key — the unresolved symlink case is a recorded residual
43
+ // handled by the downstream merge guard, never asserted disjoint here.
44
+ }
45
+ }
46
+ const slashed = abs.split(sep).join("/");
47
+ return CASE_INSENSITIVE_FS ? slashed.toLowerCase() : slashed;
48
+ }
49
+ //# sourceMappingURL=pathIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathIdentity.js","sourceRoot":"","sources":["../../../src/shared/dispatch/pathIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErD;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,OAAqD,EAAE;IAEvD,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAC/C,IAAI,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC;QACxB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QACf,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IACzC,IAAI,eAAe,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;YAC5E,4EAA4E;YAC5E,uEAAuE;QACzE,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/D,CAAC"}
@@ -34,6 +34,7 @@ import type { SessionConfig } from "../types/sessionConfig.js";
34
34
  import type { CapacityPool, PartialCompletionTerminal } from "../quota/capacity.js";
35
35
  import type { QuotaStateEntry } from "../quota/types.js";
36
36
  import type { WorkerOutputChannel } from "../quota/errorParsing.js";
37
+ import type { ReservationLedger } from "../quota/reservationLedger.js";
37
38
  /** A dispatchable unit of work. TPacket is opaque to the engine. */
38
39
  export interface RollingDispatchPacket<TPacket> {
39
40
  /** Stable, unique identifier for this packet within a run. */
@@ -98,6 +99,14 @@ export interface InFlightEntry<TPacket> {
98
99
  startedAt: number;
99
100
  estimatedTokens: number;
100
101
  promise: Promise<RollingDispatchResult<TPacket>>;
102
+ /**
103
+ * Reservation-ledger lease held for this in-flight packet (spec admission model).
104
+ * Set only when a `reservationLedger` was configured; reconciled (freed) in
105
+ * `handleResult` when the packet completes. `resourceKey` is the pool id the lease
106
+ * was taken against, needed to reconcile. Null/undefined when no ledger is wired.
107
+ */
108
+ leaseId?: string | null;
109
+ resourceKey?: string;
101
110
  }
102
111
  /** Mutable state of the rolling dispatcher. */
103
112
  export interface RollingDispatchState<TPacket> {
@@ -168,6 +177,34 @@ export interface RollingDispatchConfig<TPacket> {
168
177
  * leave the source unfed (no escalation can ever fire).
169
178
  */
170
179
  recordRateLimit?: (packet: RollingDispatchPacket<TPacket>, result: RollingDispatchResult<TPacket>) => void;
180
+ /**
181
+ * Shared token-reservation ledger (spec/audit/dispatch-admission-control.md, the
182
+ * proactive admission layer). When supplied, every dispatched packet LEASES its
183
+ * output-envelope cost against the account-keyed ledger BEFORE dispatch and
184
+ * reconciles the lease on completion — so two co-located dispatch loops pointed at
185
+ * the SAME ledger file (same `provider#account/model` meter) each see the other's
186
+ * outstanding reservations and cannot both optimistically assume the full budget.
187
+ * The resourceKey is the pool id (`pool.id` is already `provider#account/model`).
188
+ * Omit to leave the in-process `InFlightTokenTracker` as the sole accounting
189
+ * (behaviour identical to before this field existed). The reactive 429/backoff
190
+ * floor still catches any residual under-reservation regardless.
191
+ */
192
+ reservationLedger?: ReservationLedger;
193
+ /**
194
+ * Live remaining token budget for a pool's resourceKey (its `pool.id`). Consulted
195
+ * only when `reservationLedger` is set — it is the budget the ledger admits
196
+ * against (`budget - Σ outstanding_leases >= cost`). Return a non-finite value
197
+ * (the default) for an optimistic/unbounded budget, in which case the ledger only
198
+ * prevents co-located double-counting and never gates on an absolute token ceiling.
199
+ */
200
+ resolvePoolBudget?: (poolId: string) => number;
201
+ /**
202
+ * Output-token envelope (spec Resolved decision 1) added to a packet's INPUT
203
+ * `estimatedTokens` to form the reservation cost. Consulted only when
204
+ * `reservationLedger` is set. Default 0 → the lease reserves the input estimate
205
+ * alone; the reactive floor still catches output under-reservation.
206
+ */
207
+ resolveOutputReservation?: (packet: RollingDispatchPacket<TPacket>, poolId: string) => number;
171
208
  }
172
209
  /** Options for tuning the dispatcher (intentionally minimal per INV-S05). */
173
210
  export interface RollingDispatchOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"rollingDispatch.d.ts","sourceRoot":"","sources":["../../../src/shared/dispatch/rollingDispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rollingDispatch.d.ts","sourceRoot":"","sources":["../../../src/shared/dispatch/rollingDispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,mBAAmB,CAAC;AAanF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,oEAAoE;AACpE,MAAM,WAAW,qBAAqB,CAAC,OAAO;IAC5C,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,8CAA8C;AAC9C,MAAM,WAAW,qBAAqB,CAAC,OAAO;IAC5C,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,EAAE,SAAS,GAAG,cAAc,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1D,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,mBAAmB,CAAC;QAC7B,IAAI,EAAE,MAAM,CAAC;QACb;;;;;;;;;WASG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wDAAwD;AACxD,MAAM,WAAW,aAAa,CAAC,OAAO;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACvC,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB,CAAC,OAAO;IAC3C,YAAY,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B;;;;;OAKG;IACH,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B;;;;;;;;OAQG;IACH,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC1B;AAED,kEAAkE;AAClE,MAAM,WAAW,qBAAqB,CAAC,OAAO;IAC5C,qDAAqD;IACrD,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,aAAa,EAAE,aAAa,CAAC;IAC7B;;;OAGG;IACH,cAAc,EAAE,CACd,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EACtC,IAAI,EAAE,YAAY,KACf,OAAO,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,uFAAuF;IACvF,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EACtC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,KACnC,IAAI,CAAC;IACV;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,CACzB,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EACtC,MAAM,EAAE,MAAM,KACX,MAAM,CAAC;CACb;AAED,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;IACzD;;;;OAIG;IACH,GAAG,IAAI,OAAO,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjD,sDAAsD;IACtD,QAAQ,IAAI,QAAQ,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;IACpD;;;;;OAKG;IACH,WAAW,IAAI,yBAAyB,GAAG,IAAI,CAAC;CACjD;AAMD;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAE1D,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKtD,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKrD,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAG1C;AAMD,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,OAAO,EAC3C,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,GACrC,MAAM,CAER;AA+CD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EACpC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EACtC,cAAc,EAAE,YAAY,EAAE,EAC9B,eAAe,EAAE,oBAAoB,EACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAClD,aAAa,EAAE,aAAa,EAC5B,gBAAgB,GAAE,WAAW,CAAC,MAAM,CAAa,EACjD,iBAAiB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,EAC1D,GAAG,GAAE,MAAmB,GACvB,YAAY,GAAG,IAAI,CAqErB;AAMD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAC7C,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EACtC,OAAO,GAAE,sBAA2B,GACnC,iBAAiB,CAAC,OAAO,CAAC,CA8iB5B"}