Skip to content

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

Open
Scra3 wants to merge 5 commits into
fix/prd-442-activity-log-targetfrom
fix/load-related-relation-target
Open

fix(workflow): load-related chooses the relation by its target collection#1630
Scra3 wants to merge 5 commits into
fix/prd-442-activity-log-targetfrom
fix/load-related-relation-target

Conversation

@Scra3
Copy link
Copy Markdown
Member

@Scra3 Scra3 commented Jun 5, 2026

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 load-related step to select relations by target collection

  • Rewrites LoadRelatedRecordStepExecutor relation selection to build candidates from all available records and choose by target collection name, rather than by source record resemblance.
  • Introduces resolveTarget() to consolidate record and relation resolution; skips AI when only one eligible candidate exists.
  • Updates SELECT_RELATION_SYSTEM_PROMPT to instruct the AI to choose relations by their target collection.
  • Adds an optional title field to step definitions and includes it in the system context message built by BaseStepExecutor.
  • Behavioral Change: pre-recorded args with an unmatched selectedRecordStepIndex now throw InvalidPreRecordedArgsError instead of falling through silently; the AI tool for relation selection is renamed to select-relation-to-follow and requires choosing from explicit labeled options.

Macroscope summarized c264c51.

…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>
@qltysh
Copy link
Copy Markdown

qltysh Bot commented Jun 5, 2026

2 new issues

Tool Category Rule Count
qlty Structure Function with many returns (count = 6): mapTask 1
qlty Structure High total complexity (count = 60) 1

alban bertolini and others added 2 commits June 5, 2026 12:20
The orchestrator sends a `title` on every step (ServerWorkflowStepBase.title)
but the mapper dropped it. Carry it into the domain StepDefinition and inject
it into buildContextMessage, so every AI call sees the step's human intent —
which matters when the prompt is weak or empty (e.g. a load-related step whose
prompt arrives as "Load " while the title says "Load the store").

- add optional `title` to shared StepDefinition fields
- map `task.title` / `condition.title` in step-definition-mapper
- buildContextMessage appends `Step title: "<title>"` when present

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>
@qltysh
Copy link
Copy Markdown

qltysh Bot commented Jun 5, 2026

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (3)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
...ow-executor/src/executors/load-related-record-step-executor.ts100.0%
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/executors/base-step-executor.ts100.0%
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/adapters/step-definition-mapper.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.

alban bertolini and others added 2 commits June 5, 2026 14:01
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>
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.

1 participant