From b3c2aa81cc1ed5b59937969170143dbd77f4580e Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Sat, 20 Jun 2026 09:03:26 +0200 Subject: [PATCH 1/3] test(workflow-executor): legacy and deterministic Load Related Record coexist (PRD-552) Explicit backward-compatibility regression: within one run, the same executor takes the AI path for a legacy prompt-only step (no preRecordedArgs) and the deterministic no-AI path for a step with source + relation pinned. fixes PRD-552 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../load-related-record-step-executor.test.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts index c945024f40..c1a841fbfe 100644 --- a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts +++ b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts @@ -3585,6 +3585,70 @@ describe('LoadRelatedRecordStepExecutor', () => { }); }); + // PRD-552: legacy prompt-only steps and new deterministic steps must coexist — the same executor + // takes the AI path for one and the deterministic (no-AI) path for the other within one run. + describe('backward compatibility (PRD-552): legacy and deterministic coexist', () => { + it('runs the AI path for a legacy step and the deterministic path for a configured step', async () => { + // Legacy prompt-only step → AI selects the relation. + const legacy = makeMockModel({ relationName: 'Orders', reasoning: 'r' }); + await new LoadRelatedRecordStepExecutor( + makeContext({ + model: legacy.model, + stepDefinition: makeStep({ executionType: StepExecutionMode.FullyAutomated }), + }), + ).execute(); + + expect(legacy.bindTools).toHaveBeenCalled(); + + // Deterministic step (source + relation pinned) → no relation AI call. + const ordersSchema = makeCollectionSchema({ + collectionName: 'orders', + collectionDisplayName: 'Orders', + fields: [ + { + fieldName: 'customer', + displayName: 'Customer', + isRelationship: true, + relationType: 'BelongsTo', + relatedCollectionName: 'customers', + }, + ], + }); + const deterministic = makeMockModel(); + const runStore = makeMockRunStore({ + getStepExecutions: jest.fn().mockResolvedValue([ + { + type: 'load-related-record', + stepIndex: 1, + executionResult: { + relation: { name: 'order', displayName: 'Order' }, + record: { collectionName: 'orders', recordId: [99], stepIndex: 1 }, + }, + selectedRecordRef: makeRecordRef(), + }, + ]), + }); + const result = await new LoadRelatedRecordStepExecutor( + makeContext({ + model: deterministic.model, + runStore, + agentPort: makeMockAgentPort([ + makeRelatedRecordData({ collectionName: 'customers', recordId: [7], values: {} }), + ]), + workflowPort: makeMockWorkflowPort({ customers: makeCollectionSchema(), orders: ordersSchema }), + previousSteps: [makeLoadRelatedPreviousStep(1)], + stepDefinition: makeStep({ + executionType: StepExecutionMode.FullyAutomated, + preRecordedArgs: { selectedRecordStepId: 'load-1', relationName: 'customer' }, + }), + }), + ).execute(); + + expect(result.stepOutcome.status).toBe('success'); + expect(deterministic.bindTools).not.toHaveBeenCalled(); + }); + }); + describe('record pool after revision', () => { it('re-executes a revised load step from the base record, not from the dead branch record', async () => { // Given: the run loaded an owner before the user revised the "Load store" step. The From 48a49eff0e0fbf5cc106b0f5643f177193db1904 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Sat, 20 Jun 2026 09:04:01 +0200 Subject: [PATCH 2/3] style: prettier formatting (PRD-552 test) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../test/executors/load-related-record-step-executor.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts index c1a841fbfe..f4a178e907 100644 --- a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts +++ b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts @@ -3635,7 +3635,10 @@ describe('LoadRelatedRecordStepExecutor', () => { agentPort: makeMockAgentPort([ makeRelatedRecordData({ collectionName: 'customers', recordId: [7], values: {} }), ]), - workflowPort: makeMockWorkflowPort({ customers: makeCollectionSchema(), orders: ordersSchema }), + workflowPort: makeMockWorkflowPort({ + customers: makeCollectionSchema(), + orders: ordersSchema, + }), previousSteps: [makeLoadRelatedPreviousStep(1)], stepDefinition: makeStep({ executionType: StepExecutionMode.FullyAutomated, From 7412b6a8ea6a8fa0cbacabd14c6bc1fe29d8d79a Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 22 Jun 2026 11:51:06 +0200 Subject: [PATCH 3/3] test(workflow-executor): address review comments Co-Authored-By: Claude Opus 4.8 (1M context) --- .../test/executors/load-related-record-step-executor.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts index 3063a9b1b6..f6f3402fb4 100644 --- a/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts +++ b/packages/workflow-executor/test/executors/load-related-record-step-executor.test.ts @@ -3603,8 +3603,6 @@ describe('LoadRelatedRecordStepExecutor', () => { }); }); - // PRD-552: legacy prompt-only steps and new deterministic steps must coexist — the same executor - // takes the AI path for one and the deterministic (no-AI) path for the other within one run. describe('backward compatibility (PRD-552): legacy and deterministic coexist', () => { it('runs the AI path for a legacy step and the deterministic path for a configured step', async () => { // Legacy prompt-only step → AI selects the relation.