Skip to content

fix(workflow): load-related chooses the relation by its target collection#1630

Merged
Scra3 merged 5 commits into
feat/prd-214-server-step-mapperfrom
fix/load-related-relation-target
Jun 9, 2026
Merged

fix(workflow): load-related chooses the relation by its target collection#1630
Scra3 merged 5 commits into
feat/prd-214-server-step-mapperfrom
fix/load-related-relation-target

Conversation

@Scra3

@Scra3 Scra3 commented Jun 5, 2026

Copy link
Copy Markdown
Member

Context

Stacked on #1628 (base fix/prd-442-activity-log-target). Two distinct load-related improvements.

1. Choose the relation by its target collection

A load-related step picked the source record first (« which available record's collection best matches the request »), then the relation. With records accumulated from prior load-related steps, « Load the dvd X » latched onto an already-loaded dvd (collection matches) instead of the store that has the dvds relation → it followed dvd → store and re-loaded a store.

Fix: fuse the two choices into one over (record, relation) pairs, picked by what the relation leads to. New AI tool select-relation-to-follow (options labeled Source → relation (→ target)) replaces select-record + select-relation for load-related. preRecordedArgs (selectedRecordStepIndex / relationDisplayName) still pin source/relation; a single candidate skips the AI call. The shared select-record heuristic is untouched for read/update/trigger.

2. Thread the step title to the AI

The orchestrator sends a title on every step (ServerWorkflowStepBase.title) but the mapper dropped it. It's now mapped into StepDefinition and injected into buildContextMessage, so every AI call sees the step's intent — important when the prompt is weak/empty (e.g. a load-related prompt arriving as « Load » while the title says « Load the store »).

Verified live (_example)

account → load store → read store name → load dvd "Celine dion" → load dvd "titanic": the last step follows store#6 → dvds (GET /store/6/relationships/dvds, candidates incl. Titanic), no more dvd → store trap.

Tests

  • load-related suite migrated to the single select-relation-to-follow call + a repro test (account + loaded store + loaded dvd → "Load the dvd titanic" follows store→dvds, asserts getRelatedData(collection: 'store', relation: 'dvds')).
  • step-definition / run mappers assert title is carried through.
  • build ✅ · lint 0 error ✅.

🤖 Generated with Claude Code

Note

Fix LoadRelatedRecordStepExecutor to select relations by target collection across all available records

  • Replaces the previous single-record relation selection with a candidate pool built from all available source records, filtering out relations that lack a relatedCollectionName.
  • Introduces resolveTarget to pick a (record, relation) pair, skipping the AI call entirely when only one candidate exists.
  • Adds support for pinning selection via preRecordedArgs.selectedRecordStepIndex and preRecordedArgs.relationName (matched by technical field name); invalid pins now throw InvalidPreRecordedArgsError.
  • The new selectRelationToFollow AI tool presents labeled options combining source record, collection, and relation details, and throws InvalidAIResponseError if the model returns an out-of-set value.
  • Behavioral Change: relations without a target collection are now excluded; if all relations lack one, the executor raises NoRelationshipFieldsError instead of proceeding.

Macroscope summarized 780daee.

@qltysh

qltysh Bot commented Jun 5, 2026

Copy link
Copy Markdown

1 new issue

Tool Category Rule Count
qlty Structure High total complexity (count = 60) 1

@qltysh

qltysh Bot commented Jun 5, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

Unable to calculate total coverage change because base branch coverage was not found.

Modified Files with Diff Coverage (1)

RatingFile% DiffUncovered Line #s
New Coverage rating: A
...ow-executor/src/executors/load-related-record-step-executor.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@Scra3 Scra3 force-pushed the fix/prd-442-activity-log-target branch from 8bb1ba6 to b69167d Compare June 8, 2026 09:42
Base automatically changed from fix/prd-442-activity-log-target to feat/prd-214-server-step-mapper June 8, 2026 13:22
@Scra3 Scra3 force-pushed the fix/load-related-relation-target branch from c264c51 to a6b22c3 Compare June 8, 2026 14:31
alban bertolini and others added 5 commits June 8, 2026 19:51
…tion

A load-related step picked the source record first, by "which available
record's collection best matches the request", then the relation on it. With
records accumulated from prior load-related steps, "load the dvd X" latched
onto an already-loaded dvd (collection matches) instead of the store that has
the dvds relation — so it followed dvd→store and re-loaded a store.

Fuse the two choices into one: gather every (record, relation) pair across
available records and pick by what the relation LEADS TO. "Load the dvd X"
now follows store→dvds regardless of accumulated dvds. preRecordedArgs
(selectedRecordStepIndex / relationDisplayName) still pin source/relation;
single candidate skips the AI call. The shared select-record heuristic is
untouched for read/update/trigger (acting on an existing record of that type).

NOTE: load-related unit tests still mock the old select-relation flow — to be
migrated in a follow-up commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion

Adapt the suite to the single `select-relation-to-follow` AI call (was
`select-record` + `select-relation`): mocks return `{ relation: <label> }`,
single-candidate schemas make no AI call, bindTools counts/names updated.
Adds a repro test: with account + a loaded store + a loaded dvd available,
"Load the dvd titanic" follows store→dvds (not a relation off the dvd).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add coverage for the diff lines flagged by the coverage gate: the step-title
branch in buildContextMessage, and resolveTarget's requireRecordAtStepIndex
(pinned source via selectedRecordStepIndex, plus the no-match error path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address PR review findings:
- a pinned relationDisplayName / selectedRecordStepIndex that matches nothing
  now throws InvalidPreRecordedArgsError, not the misleading
  NoRelationshipFieldsError ("no relations configured"); the latter is kept
  only for the genuine zero-relations case.
- matchesRelation normalizes (case + separators) like findField, restoring
  fuzzy parity for pre-recorded relation names.
- resolveTarget builds the RelationTarget straight from the chosen candidate's
  field (targetFromCandidate) instead of re-resolving by displayName via
  buildTarget — removes a redundant lookup and a same-displayName mis-resolve
  hazard. RelationCandidate.field is narrowed to guarantee relatedCollectionName.
- tests: pinned-relation/source assertions made meaningful (executionParams +
  source record among several), error userMessages asserted, and a test that
  the step title reaches the select-relation-to-follow context.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…RD-433 + title fallback)

Rebasing the relation-by-target-collection fusion onto a mapper that gained
PRD-426 (technical-name preRecordedArgs), PRD-433 (previousSteps-driven record
pool) and the step-title-as-prompt-fallback rule (#1635):
- pin pre-recorded relations by technical relationName, matched exactly on
  field.fieldName (drops the displayName fuzzy matchesRelation)
- tests pass loaded records via previousSteps so getAvailableRecordRefs surfaces
  them, and use select-relation-to-follow / technical names
- the step title now reaches the select-relation context only when the prompt is
  absent (fallback rule), so its test drives an empty prompt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Scra3 Scra3 force-pushed the fix/load-related-relation-target branch from a6b22c3 to 780daee Compare June 8, 2026 17:57
@Scra3 Scra3 merged commit 6aa8faa into feat/prd-214-server-step-mapper Jun 9, 2026
30 checks passed
@Scra3 Scra3 deleted the fix/load-related-relation-target branch June 9, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants