Found during the Go-parity audit. This is the highest-priority finding: the watch model advertises a capability it does not have.
The defect
Watch.regions (src/core/types.ts:31) is documented as "Regions to search. At least one." A grep for regions across src/ outside tests finds only that declaration and two comments. CapacityWatcher.check() never reads it.
The region a check actually queries comes from somewhere else entirely: truffleFinderAdapter(finder, region) (src/live/truffle-adapter.ts:45) takes a single region string and stamps it onto every result. So:
const watcher = new CapacityWatcher({ finder: truffleFinderAdapter(aws, "us-east-1") });
await watcher.check({ watchId: "w1", instanceTypePattern: "p5.*",
regions: ["us-east-1", "us-west-2", "eu-west-1"] }); // ← 2 of 3 ignored
…returns a match stamped region: "us-east-1" and never looks at us-west-2 or eu-west-1. Nothing warns. The caller asked to watch three regions and got one, with a plausible-looking result.
For a capacity tool this is the worst possible failure shape: the whole point of watching multiple regions is that scarce capacity (p5, g6e) appears somewhere first. A watch that silently searches one region will sit "waiting" while capacity is free two regions over.
Go's searchBestMatch passes w.Regions (plural) straight into SearchInstanceTypes(ctx, w.Regions, matcher, …) — the region set is honoured, and the returned InstanceTypeResult carries its own Region.
Root cause
truffle-ts's LiveFinder.search dedupes across regions by instance type and drops region identity (truffle-ts/src/live/live-finder.ts:111-113), and its InstanceType has no region field. The adapter's header comment says so honestly. So lagotto-ts couldn't have done this correctly with the upstream API as it stands.
Blocked on truffle-ts#31 (region identity in multi-region search). Once InstanceType carries region, the adapter can stop stamping and check() can iterate watch.regions.
Fix
check() iterates watch.regions and evaluates candidates per region, keeping the global cheapest (Go's behaviour).
- The adapter takes the region set, or is dropped once truffle-ts returns per-region results.
- Until then, do not fail silently. If a watch names more regions than the finder can serve, throw or emit a warning — the #63 invariant: a narrowed search must not be indistinguishable from a completed one.
Also missing while here: availableAZs is never populated (truffle-ts doesn't produce it, tracked in truffle-ts#33), so orderAZs always receives [], candidateAzs is always empty, and a watch with availabilityZones pinned matches nothing on the on-demand path — evaluate returns null when a pin is set and no offered AZ matches. That's a second silent-empty-result path worth its own test.
Found during the Go-parity audit. This is the highest-priority finding: the watch model advertises a capability it does not have.
The defect
Watch.regions(src/core/types.ts:31) is documented as "Regions to search. At least one." A grep forregionsacrosssrc/outside tests finds only that declaration and two comments.CapacityWatcher.check()never reads it.The region a check actually queries comes from somewhere else entirely:
truffleFinderAdapter(finder, region)(src/live/truffle-adapter.ts:45) takes a single region string and stamps it onto every result. So:…returns a match stamped
region: "us-east-1"and never looks at us-west-2 or eu-west-1. Nothing warns. The caller asked to watch three regions and got one, with a plausible-looking result.For a capacity tool this is the worst possible failure shape: the whole point of watching multiple regions is that scarce capacity (p5, g6e) appears somewhere first. A watch that silently searches one region will sit "waiting" while capacity is free two regions over.
Go's
searchBestMatchpassesw.Regions(plural) straight intoSearchInstanceTypes(ctx, w.Regions, matcher, …)— the region set is honoured, and the returnedInstanceTypeResultcarries its ownRegion.Root cause
truffle-ts's
LiveFinder.searchdedupes across regions by instance type and drops region identity (truffle-ts/src/live/live-finder.ts:111-113), and itsInstanceTypehas noregionfield. The adapter's header comment says so honestly. So lagotto-ts couldn't have done this correctly with the upstream API as it stands.Blocked on truffle-ts#31 (region identity in multi-region search). Once
InstanceTypecarriesregion, the adapter can stop stamping andcheck()can iteratewatch.regions.Fix
check()iterateswatch.regionsand evaluates candidates per region, keeping the global cheapest (Go's behaviour).Also missing while here:
availableAZsis never populated (truffle-ts doesn't produce it, tracked in truffle-ts#33), soorderAZsalways receives[],candidateAzsis always empty, and a watch withavailabilityZonespinned matches nothing on the on-demand path —evaluatereturns null when a pin is set and no offered AZ matches. That's a second silent-empty-result path worth its own test.