feat(workflow-executor): add 3-way execution mode to the load related record step (PRD-148)#1728
Open
matthv wants to merge 11 commits into
Open
Conversation
… record step (PRD-148) Manual presents the narrowed list with no AI; AI-assisted suggests a record; Full AI selects + loads and auto-skips on no source record, empty list, or AI judging none relevant. selectedRecordRef is optional now (no-source skip); the wire serializer guards it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 new issues
|
|
Coverage Impact ⬆️ Merging this pull request will increase total coverage on Modified Files with Diff Coverage (1)
🛟 Help
|
…resolveTarget (PRD-148) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… candidate list (PRD-148) When the HasMany candidate list is truncated to fit the AI prompt budget, -1 (none relevant) is no longer offered — the AI picks from what it saw, so a match in the unseen tail is not silently skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…PRD-148) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hercemer42
requested changes
Jul 1, 2026
…e AI decline (PRD-148) Full AI no longer silently skips when it can't load a relevant record. With nothing relevant it degrades to an AI-assisted confirmation (a human decides, "No X to load" pre-checked); no source record now surfaces an error like the await modes instead of skipping. AI-assisted may decline too (allowNone), and the record-selection prompt tells the AI to return -1 on an impossible request rather than forcing a weak match. pendingData carries a suggestNoRecord flag so the front distinguishes an active "nothing relevant" from a plain no-suggestion (Manual). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pin LoadRelatedRecordStepDefinitionSchema behaviour: each valid mode parses to its own value (incl. 'manual' → 'manual'), a missing mode defaults to AutomatedWithConfirmation, and an invalid mode is rejected rather than silently coerced (no `.catch`, so a `manual` typo can't flip AI prefill back on). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…AI failure Load Related Record 3-way execution mode hardening. Bundled because the changes are interwoven in the executor and its test: - feat: Full AI now degrades to an AI-assisted confirmation when the AI returns a best guess but cannot confidently single one out among several viable candidates. selectBestRecordIndex gains a `confident` flag (distinct from the existing -1 "none relevant" sentinel, whose semantics are unchanged); an ambiguous positive pick pre-selects the best guess as suggestedRecord for a human to confirm instead of auto-loading. Confident picks still auto-load; a missing flag defaults to confident (backward compatible). - fix: AI failure/timeout in any AI mode (relation pick, field/record ranking, or a Full AI auto-load) now degrades to the deterministic Manual path — deterministic candidate list presented for the user to pick — instead of erroring the run or auto-skipping. AI calls are tagged via an internal marker so genuine config/data errors still surface. - fix: refreshCandidatesForField rebuilds pendingData from scratch on a field switch (keeping only the immutable relation list) so no stale suggestion state (suggestedRecord / suggestNoRecord) lingers. - style: drop ticket IDs from comments and test titles. - test: pin the truncated-list none-guard (noneAllowed = allowNone && !truncated — the AI is not offered -1 when the list was truncated). - tighten selectBestFromRelatedData options so allowNone only applies when rank is true. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Close the changed-lines coverage gap on the refreshCandidatesForField AI-failure catch: add a test where the ranking AI call throws during a field switch and the step degrades to the deterministic no-AI list (false branch), and one where a non-AI data-fetch failure is rethrown as a step error rather than degrading (true branch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t name Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…able Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Execution logic for the 3-way Execution mode (Manual / AI-assisted / Full AI) on the workflow Load Related Record step. Part of PRD-148 — 3-PR set (executor +
ForestAdmin/forestadmin-serverorchestrator +ForestAdmin/forestadmineditor).manual): present the narrowed candidate list with no AI — no relation chooser, no record suggestion. Single-record relations (xToOne, or HasMany with 1 candidate) still pre-fill, since that's the only option, not an AI pick. The Zod schema drops.catch(AutomatedWithConfirmation)and addsManual, so amanualvalue is no longer silently coerced back into AI prefill (same reasoning as TriggerAction).automated-with-confirmation, default): AI suggests a record, user confirms (unchanged).fully-automated): AI selects and loads. Auto-skips (persistsexecutionResult: { skipped: true }+success) when there is no source record (SourceRecordMissingError, Full-AI only), an empty candidate list, or the AI judges none relevant (select-record-by-contentreturns-1via the new Full-AI-onlyallowNone).selectedRecordRefis now optional onLoadRelatedRecordStepExecutionData(absent only on the no-source Full-AI skip); the wire serializer omits it instead of dereferencingundefined.Tests
97 tests in the executor suite. Added: Manual = no AI / no pre-selection (incl. relation switch), Manual single-record pre-fill, Full-AI skip on each of the 3 causes, await-mode no-source still errors (regression guard), serializer no-source round-trip.
Validation
Validated end-to-end on the local stack (account → bills) across the 3 modes, plus a local multi-agent code review — 1 Critical found & fixed: serializer crash (503) on the no-source Full-AI skip.
Relates to PRD-148.
🤖 Generated with Claude Code
Note
Add Manual execution mode to
LoadRelatedRecordStepExecutorwith auto-skip for FullyAutomatedManualas a validexecutionTypefor the load-related-record step; in Manual mode, AI is not called for relation selection or candidate suggestion — the first eligible relation is picked deterministically and nosuggestedRecordis included.FullyAutomatedmode, steps now auto-skip (via newpersistSkip) when there is no source record, no linked xToOne record, or when the AI ranks all candidates as irrelevant (returns-1).selectBestRecordIndexgains anallowNoneoption so AI can return-1only when the candidate list was not truncated, preventing forced selections.fetchRecordForRelationandfetchXToOneRecordRefnow returnnullon absence instead of throwing, with callers deciding skip vs. error behavior.selectedRecordRefis made optional inLoadRelatedRecordStepExecutionDataand the wire serializer skips the field when absent, fixing a serialization crash on auto-skipped steps.executionTypeschema no longer coerces unknown values toAutomatedWithConfirmation; invalid values will now fail validation instead of being silently swallowed.Changes since #1728 opened
suggestNoRecordflag instead of auto-skipping when no relevant record exists [9ee1164]suggestNoRecordfield toLoadRelatedRecordPendingDataand updatedLoadRelatedRecordStepExecutionDatainterface documentation [9ee1164]collectCandidateIdsandresolveAndLoadAutomatic[9ee1164]LoadRelatedRecordStepExecutordegrades to manual candidate selection when AI ranking fails during field switch [71542cd]LoadRelatedRecordStepExecutorpropagates non-AI errors during field switch instead of degrading [71542cd]LoadRelatedRecordStepExecutor.resolveAndLoadAutomaticmethod [44e23be]LoadRelatedRecordStepExecutorFullyAutomated BelongsTo functionality [44e23be]AiAssistUnavailableErrorclass and multiple methods inLoadRelatedRecordStepExecutorincludingdoExecute,refreshCandidatesForField,degradeToManualAwaitInput,selectBestFromRelatedData,withAiAssist, andselectBestRecordIndexwithin theworkflow-executorpackage [9fcdda2]load-related-record-step-executor.test.tsfile in theworkflow-executorpackage [9fcdda2]Macroscope summarized 4f8b398.