Skip to content

Commit 25833b9

Browse files
committed
Merge remote-tracking branch 'origin/feat/waitpoint-envelope-resolver-tri-13441' into feat/waitpoint-mint-flag-wiring-tri-13442
2 parents 8c4c6af + 5b4b060 commit 25833b9

18 files changed

Lines changed: 848 additions & 248 deletions

internal-packages/run-engine/src/engine/systems/completedWaitpointFreeze.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const _pointerKeys: Exact<keyof CompletedWaitpointsPointer, "cycleSeq" | "count"
4040

4141
const _argsKeys: Exact<
4242
keyof ResolveCompletedWaitpointsArgs,
43-
"runId" | "batchId" | "pointer" | "order" | "records"
43+
"runId" | "batchId" | "pointer" | "order" | "distinctIds" | "records"
4444
> = true;
4545
import { enhanceExecutionSnapshotWithWaitpoints } from "./executionSnapshotSystem.js";
4646

@@ -193,6 +193,7 @@ async function assertParity(
193193
batchId: batchId ?? undefined,
194194
pointer: { cycleSeq: 1, count: order.length },
195195
order,
196+
distinctIds: [...new Set(waitpoints.map((w) => w.id))],
196197
records: waitpoints.map(toRecord),
197198
};
198199
// count-carried-forward behaviour (order.length, not the record count) is covered by
@@ -406,6 +407,7 @@ describe("the completed-waitpoints freeze", () => {
406407
batchId: undefined,
407408
pointer: { cycleSeq: 1, count: 1 },
408409
order: ["wp_hook"],
410+
distinctIds: ["wp_hook"],
409411
records: [toRecord(w)],
410412
});
411413
expect(resolved).toHaveLength(1);
@@ -611,6 +613,7 @@ describe("the exhaustive parity grid", () => {
611613
batchId: readingBatchId ?? undefined,
612614
pointer: { cycleSeq: 1, count: order.length },
613615
order,
616+
distinctIds: [w.id],
614617
records: [toRecord(w)],
615618
};
616619
const resolved = await referenceResolver(

internal-packages/run-engine/src/engine/systems/executionSnapshotSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ async function getSnapshotWaitpointIdsWithPresence(
173173
* This is necessary because waitpoints can have large outputs (100KB+),
174174
* and fetching many at once can exceed Node.js string limits.
175175
*/
176-
async function fetchWaitpointsInChunks(
176+
export async function fetchWaitpointsInChunks(
177177
prisma: PrismaClientOrTransaction,
178178
waitpointIds: string[],
179179
runStore?: RunStore,

internal-packages/run-engine/src/engine/systems/waitpointSystem.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -491,14 +491,6 @@ export class WaitpointSystem {
491491
};
492492
}
493493

494-
// The record set rides the wait cycle's key once per resume, so build it here rather
495-
// than at each append site. Nothing mints a store-format waitpoint yet, so
496-
// #completedWaitpointRecordsFor returns undefined on every live path today.
497-
const completedWaitpointRecords = await this.#completedWaitpointRecordsFor(
498-
runId,
499-
blockingWaitpoints
500-
);
501-
502494
// 3. Get the run (run-ops scalars) + resolve its environment via the control-plane resolver,
503495
// so the run-ops DB can split without a cross-provider join.
504496
const run = await this.$.runStore.findRun(
@@ -616,6 +608,13 @@ export class WaitpointSystem {
616608
};
617609
}
618610
case "EXECUTING_WITH_WAITPOINTS": {
611+
// Built inside the branch, not before the switch: the statuses above return without
612+
// appending, and they must not pay an envelope read to do it.
613+
const completedWaitpointRecords = await this.#completedWaitpointRecordsFor(
614+
runId,
615+
blockingWaitpoints
616+
);
617+
619618
const newSnapshot = await this.executionSnapshotSystem.createExecutionSnapshot(
620619
this.$.prisma,
621620
{
@@ -684,6 +683,11 @@ export class WaitpointSystem {
684683
);
685684
}
686685

686+
const completedWaitpointRecords = await this.#completedWaitpointRecordsFor(
687+
runId,
688+
blockingWaitpoints
689+
);
690+
687691
//put it back in the queue, with the original timestamp (w/ priority)
688692
//this prioritizes dequeuing waiting runs over new runs
689693
const newSnapshot = await this.enqueueSystem.enqueueRun({
@@ -761,31 +765,36 @@ export class WaitpointSystem {
761765
}
762766

763767
/**
764-
* The record set for one resume, or undefined when this wait has no store-resident half.
768+
* The record set for one resume, or undefined when no blocking waitpoint carries a store-format
769+
* id.
770+
*
771+
* Gated on id FORMAT, not residency. The two are not the same during a migration: a
772+
* store-format id can still be served by the Postgres arm, exactly as run-ops ids were for
773+
* runs. Whichever arm owns it answers, so the gate only decides whether to ask at all.
765774
*
766-
* The classification gate is what keeps this inert. `parseWaitpointId` reports legacy for
767-
* every id minted today, so no live resume reads an envelope or writes a record until a
768-
* waitpoint mints in store format.
775+
* That gate is what keeps this inert. `parseWaitpointId` reports legacy for every id minted
776+
* today, so no live resume reads an envelope or writes a record until a waitpoint mints in
777+
* store format.
769778
*/
770779
async #completedWaitpointRecordsFor(
771780
runId: string,
772781
blockingWaitpoints: RunBlockEdge[]
773782
): Promise<CompletedWaitpointRecord[] | undefined> {
774-
const storeResidentIds = [
783+
const storeFormatIds = [
775784
...new Set(
776785
blockingWaitpoints
777786
.map((b) => b.waitpoint.id)
778787
.filter((id) => parseWaitpointId(id).format === "b32hexW")
779788
),
780789
];
781790

782-
if (storeResidentIds.length === 0) {
791+
if (storeFormatIds.length === 0) {
783792
return undefined;
784793
}
785794

786795
const sources = await this.coordinator.readCompletionEnvelopes({
787796
runId,
788-
waitpointIds: storeResidentIds,
797+
waitpointIds: storeFormatIds,
789798
});
790799

791800
return buildCompletedWaitpointRecords(sources);

0 commit comments

Comments
 (0)