Skip to content

fix(mcp): a microflow created over MCP keeps its flow sides and notes - #1534

Merged
ako merged 3 commits into
mainfrom
fix/mcp-create-flow-sides-and-notes
Oct 21, 2026
Merged

ako merged 3 commits into
mainfrom
fix/mcp-create-flow-sides-and-notes

Conversation

@ako

@ako ako commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Builds on #1528 (merged), which added AnnotationFlow.Sides.

Problem

Microflows created over --mcp (Studio Pro's PED API) lost two things:

  1. Flow sides. The create path sent no originConnectionSide/destinationConnectionSide, so Studio Pro drew every flow right → left. @anchor, CASE outcome anchors and the builder's own side choices had no effect. Measured on 11.15.0-rc.4: a CASE built with @anchor(from: bottom, Approved: (from: right), (empty): (from: bottom, to: top)) read back 1 -> 3 on all eight flows.
  2. Notes. These were not just dropped: any @annotation failed the whole create (microflow object type *microflows.Annotation is not yet supported by the MCP backend).

Fix

  • buildFlowDocContent maps each sequence flow's connection indexes onto the constructor's side fields, using the helper the splice already used (setPEDSides, moved out of the mutator).
  • mapObjectTree maps a note to Microflows$Annotation (position, caption, size). The note lines follow the sequence flows as Microflows$AnnotationFlow elements. PED's AnnotationFlow is an element type, not a constructor: its ends are origin/destination (not originId/destinationId), and its sides are the required originConnectionIndex/destinationConnectionIndex.
  • AnnotationFlow.SidesOrDefault() (in sdk/microflows) holds the unoriented default (2 → 0). Both the modelsdk writer and the MCP backend use it, so the two engines cannot drift apart on it.
  • The skeleton adapter keeps an AnnotationFlow's $Type and shifts its origin/destination past the parameters, as it does for sequence flows.
  • On the pre-11.14 (full) constructor, a microflow with notes is refused with a clear error. Its flows carry no $Type, so a note's line could only be read as a SequenceFlow, which would be an execution edge out of the note.
  • The splice had the same wrong note-line keys. It sent originId/destinationId, which PED refuses ("/origin":"Expected reference (string), got undefined", measured). This was hidden because mapObjectTree refused the note before its line was reached. Fixed with the same pedAnnotationFlow. The splice now also adds note lines after its new sequence flows. Within one update PED stores a note line after a sequence flow added later (measured), and the splice's follow-up sets address a new sequence flow by index.

Verification

  • Unit tests in mdl/backend/mcp: sides on both constructor shapes, notes on the skeleton (positions, sizes, captions, shifted references, explicit and default sides), notes refused on the full constructor, and the splice's note line. All of them failed before the fix with the reported symptom.
  • Live, Studio Pro 11.15.0-rc.4, through the MCP tunnel. I ran the same script through the default engine and over --mcp, then compared every flow's (origin, destination, sides) after resolving PED's $id(...) references. All 10 flows are identical, both note lines included (2 → 0 and 0 → 2), as are the note positions, sizes and captions. ped_check_errors is clean on two successive calls.
  • Control, live: with the fix reverted, the same script without notes read back 1 -> 3 on every flow, and with notes it failed the create.
  • The note-line keys were checked by direct ped_update_document probes: origin/destination plus indexes is accepted, and originId/destinationId is refused.
  • make build && make test && make lint pass.

Reproduction script: mdl-examples/bug-tests/mcp-create-flow-sides-and-notes.mdl. Measurements are in docs/03-development/PED_MCP_CAPABILITIES.md (11.15 section), and the finding is recorded under .claude/skills/fix-issue/findings/mdl-backend/.

Not fixed here (found while verifying)

  • ALTER MICROFLOW insert over MCP fails on 11.15, with or without a note. Setting /flows/N/line/originControlVector on a flow added in the same ped_update_document fails the whole update with undefined is not an object (evaluating 'u.$Type'). Setting the whole line instead is accepted but not applied. A plain one-activity insert reproduces it, so the splice's note-line fix above is verified only by direct probes, not end to end.
  • An enumeration parameter from the System module ($T: System.UserType) is sent as an entity over MCP (/parameters/0/entity … not found).

Test documents left in the open Studio Pro project (PED has no delete): MyFirstModule.MCPS_CaseNotes, MCPS_CaseSidesControl, MCPS_SpliceNote, MCPS_SplicePlain, MCPS_NoteProbe.

🤖 Generated with Claude Code

The create path sent no connection sides, so Studio Pro drew every flow
right -> left: @anchor, CASE outcome anchors and the builder's own sides
were lost (11.15.0-rc.4: a CASE read back 1 -> 3 on all eight flows). A
note failed the whole create, since mapObjectTree had no Annotation case.

buildFlowDocContent now maps each sequence flow's indexes onto
originConnectionSide/destinationConnectionSide (setPEDSides, shared with
the splice). It also writes notes as Microflows$Annotation and their
lines as Microflows$AnnotationFlow elements: origin/destination plus the
required connection indexes, defaulting through the new
AnnotationFlow.SidesOrDefault, which the modelsdk writer uses as well.
The skeleton adapter keeps a note line's $Type and shifts its ends past
the parameters. On the pre-11.14 constructor, whose flows are untyped,
notes are refused rather than risk a note line read as a sequence flow.

The splice sent a note line with the constructor's originId/destinationId
keys, which PED refuses. It now uses the same mapping and adds note lines
after its new sequence flows, because PED stores an AnnotationFlow after
a SequenceFlow added later in the same update.

Verified live against Studio Pro 11.15.0-rc.4: the same script gives
identical sides on all 10 flows over --mcp and on the modelsdk engine,
note lines included; with the fix reverted every flow read back 1 -> 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ako
ako merged commit c372937 into main Oct 21, 2026
52 of 55 checks passed
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