Skip to content

feat(projection): derived sequence fragments, message elements and view inverses - #23

Merged
Mearman merged 33 commits into
mainfrom
feat/projection-gaps
Oct 11, 2026
Merged

Mearman merged 33 commits into
mainfrom
feat/projection-gaps

Conversation

@Mearman

@Mearman Mearman commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Phase 2b of the process-graph plan: the remaining gaps in @exadev/process-graph-projection, plus inverses that turn an edited view back into a diff against the model.

I checked each gap from the plan against main with a test on the order process first. toStateMachine already scopes by affects, toSwimlane already draws empty lanes for declared participants, and toSequence already wraps authored fragments, so those three needed nothing. Two were real: toSequence never derived alt/opt/loop/par from decisions, loops and forks, and no projection read message elements (they were only ever reported as a loss).

Derived fragments come from the model's structure and are restricted to the scenario path. A decision transition whose target can reach the decision again is a loop transition (the same rule graph-domain's loopTransitions uses); the decision's forward branches give an alt, or an opt when one of two branches goes straight to where they meet; a fork gives a par. Each derived fragment names the decision or fork it came from, and one holding exactly an authored fragment's messages is dropped in favour of the authored one. A step leaving an actorless element such as a fork or join is now sent by whoever reached it, which is what lets a par show its branches' messages.

Message elements are drawn on the sequence path with their own ends, label and mode, and folded into the flowchart edge, hand-off and state machine transition that pass through them (the state machine taking the message's event as the trigger). Flowchart edges and state machine transitions now list the model transitions they stand for, which the inverses rely on.

The inverses are diffFlowchart, diffSwimlane, diffStateMachine and diffSequence. Each takes the edited view and returns a ModelDiff matched by element and transition id (added, removed, renamed, relaned and readdressed elements; added, removed, rewired and changed transitions; renamed events). Anything the view doesn't pin down is inferred: true: a new terminator's or bar's role, edits to a state machine transition that folds a decision (its later steps are shared with other chains), and nearly everything a sequence edit implies about steps and ownership. confirmChanges confirms them, and applyModelDiff refuses with UnconfirmedChangeError until nothing inferred is left. Edits the model can't express, such as a changed node shape or a lane for an entity, throw instead of being dropped. They're all exported flat through the process-graph entry point with no name collisions.

Every new test runs on the order process fixture plus three variants of it (message elements, a payment retry loop, parallel fulfilment with an optional gift wrap). I broke the code once per behaviour to check that each test fails.

@Mearman
Mearman marked this pull request as ready for review October 10, 2026 15:36
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-11T00:18:05.538650Z ff54234 Manual request

Security findings

Advisory findings (18)

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Mearman
Mearman force-pushed the feat/projection-gaps branch from f29fc47 to a80d26b Compare October 10, 2026 15:38
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

1 similar comment
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@Mearman
Mearman force-pushed the feat/projection-gaps branch from a80d26b to 1a76962 Compare October 10, 2026 15:50
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: 1a769620db

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread packages/core/graph/projection/src/chains.ts Outdated
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: bd81eae3c7

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread packages/core/graph/projection/src/derived-fragments.ts Outdated
Comment thread packages/core/graph/projection/src/inverse-sequence.ts Outdated
@Mearman
Mearman force-pushed the feat/projection-gaps branch from 6b046b7 to ccd788e Compare October 10, 2026 16:48
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: ccd788e5ef

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread packages/core/graph/projection/src/chains.ts Outdated
Comment thread packages/core/graph/projection/src/derived-fragments.ts Outdated
Comment thread packages/core/graph/projection/src/inverse-flowchart.ts Outdated
Comment thread packages/core/graph/projection/src/diff.ts Outdated
@Mearman
Mearman force-pushed the feat/projection-gaps branch from ed3da98 to a60c68c Compare October 10, 2026 19:59
@Mearman Mearman closed this Oct 10, 2026
@Mearman Mearman reopened this Oct 10, 2026
@Mearman Mearman closed this Oct 10, 2026
@Mearman Mearman reopened this Oct 10, 2026
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: a60c68c739

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread packages/core/graph/projection/src/fragments.ts Outdated
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: f7c0f716d9

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread packages/core/graph/projection/src/chains.ts Outdated
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

An unknown error occurred
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Mearman
Mearman force-pushed the feat/projection-gaps branch from 5308dd5 to 37f6bb0 Compare October 10, 2026 20:54
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@Mearman
Mearman force-pushed the feat/projection-gaps branch from 37f6bb0 to bdf73d2 Compare October 10, 2026 20:57
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

2 similar comments
@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@Mearman

Mearman commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

@codex security review

…asses

Derived fragments walked and kept the whole reachable set of every
forward branch to find where the branches meet, so a decision whose
branches share one tail did work quadratic in the model. Where branches
meet is now the decision's or fork's immediate post-dominator over
forward transitions, found for every element in one dominator pass, and
the scenario is read once: an alt or opt holds the messages from the
branch taken until the path reaches that point, a par follows each
branch taken from its fork, and a loop holds the messages inside its
decision's component.

Authored fragments are matched to messages through an index of their
bodies, and placement marks the span each placed fragment covers, so no
step scans the list of candidates or messages.
How many forward branches a decision or fork has, where they meet and
whether a decision draws an opt are now found once per element before
the path is read, rather than recomputed for every step that leaves it.
…n read

Every chain copied its run of folded elements, so a long run of messages
fanning out to many ends, or entered from many sources, cost the run's
length once per chain. Each projection now indexes the folded elements
once: their components are condensed, each component's reachable drawn
elements are found in reverse topological order and shared along runs
with nothing to add, and the elements entered from exactly one folded
element form a forest recording the last trigger, effect and guard above
each, so a single route's labels come from its two ends. A chain's
transitions, through and joined guards, and an edge's label, are built
only when read.

The inverses match edges and transitions by their first transition and
end, read from the projection's own record, and act on the steps from
folded elements into an end once however many chains share them.
… by them

A derived alt or opt listed every position it held, so decisions nested
inside one another that all meet at the path's end kept positions
quadratic in the nesting. An operand now holds either a run, by its
ends, or a list, and fragments are compared and placed by the ends of
their spans: a segment tree records when each placed fragment covers a
node, and the innermost fragment at a position is the latest placement
on its path to the root. No span is expanded into its positions, and
which operand holds a position is a map lookup for listed positions and
a binary search over runs.
The chain index kept a list of reachable targets for every folded
component, copying its successor's list, so a comb of messages each with
its own exit stored references quadratic in its length. A component now
either takes over the list of a successor nothing else extends and
prepends its own targets as cells, or points at its own targets and its
successors' structures. The index stores one reference per cell, own
target and successor, linear in the elements and transitions; duplicates
are removed when a component's targets are first read, and the read is
remembered.
…ry start

A component whose own exits a later component already reached could
not extend that list, so it fell back to a structure that every start
walked again, and many starts into one run did work quadratic in its
length. Each component's targets are now a list of cells holding each
target once, shared with the components after it, kept free of
duplicates while building by a layered set: extended in place by the
sole way into its way on, otherwise laid thinly over it, and over the
last way on at a merge. A component lists the own targets nothing
further on reaches, then those further on. The index stays linear in
the elements and transitions, and reading a start walks only its own
targets.
…ed fragments

Matching authored fragments appended a position for every fragment
and message pair, so many fragments over a repeated step did work in
the product of the two. The positions arriving at each element are now
found once and shared by every operand whose body holds that element;
an operand is its elements and their lists, and its extent, coverage
and which operand holds a position are read from them without
expanding.
A table crosses each shape found to need quadratic work (a comb of
messages, a diamond of combs, decisions nested to one meet, many
sources into one run, a run fanning out, repeated steps under many
authored fragments, a wide fork, branches sharing one tail, a decision
with many ways round) with every projection, and the edit lists with
the inverses. Work is counted over the collection operations the
projections are built from and measured per item of input and output,
which must stay level as each shape doubles.
The layered sets behind each component's targets grew a layer at every
merge, so serial diamonds of messages rescanned every earlier target
through an ever deeper set. A component now gets one flat array of its
targets only when it is read on its own: it is entered from an element
that is not folded, or from two or more components. Every other
component is read as part of the one before it, so it is visited once
in all. Arrays are built on demand and remembered; a generation stamp
per target removes duplicates in constant time, a component with
nothing to add shares the array it reads, and the only builder of an
array nothing else reads extends it in place. The work is linear in
the elements and transitions plus the arrays that must be copied, and
the reading order is unchanged.
…verses

Deleting or editing many edges or state machine transitions whose
folded chains share an end walked that end's arriving steps once per
edge. Omitted and edited chains are now grouped by the end they share,
so the steps into each end are removed, rewired or changed once, and
edits to the same end that disagree are refused.
…d deletions

Work is now counted over set and map lookups as well, so walks over
linked structures that test membership as they go are measured. The
scaling table gains serial diamonds of messages through every
projection and deletion of every edge or transition of sources sharing
one end through both inverses, and its shapes move to a test support
module.
A shape whose state machine output is itself quadratic took longer
than the test timeout to build at the shared size with every
collection call counted. Projected shapes now start smaller, still
large enough that quadratic work doubles per item, while the edit rows
keep the larger size, which a rescan per edited item needs to overtake
the fixed cost of re-projecting the model.
…per chain

Every chain into a target destructured the list of folded steps
arriving at it into its first item and a copy of the rest, so many
paths converging on one end copied that list once per path. Chains now
read its length and its one item by index. The other places that took a
list apart the same way read it by index too, though each ran once per
element or component.
…log time

Placing a fragment inside an authored operand counted the operand's
positions across all of its elements for each nested fragment, so one
fragment over a long path with a fragment inside it per step did work
quadratic in the path. A fragment with one operand holds its whole
span; an operand held by elements keeps a set of them, against which an
authored fragment inside it is checked by its own elements; any other
span is checked by binary search or position by position, whichever is
shorter.
…ested authored fragments

Work is now also counted at each step of an array's iterator, so
spreads, destructuring and loops over lists are measured. The scaling
table gains many paths converging on one end through every projection,
at the size where its quadratic part shows, and an authored fragment
over the path with one inside it per step through the sequence diagram.
…gets

Each merged chain walked everything its start reaches and filtered it
by what leads to its own target, so reading every edge of a start with
many common targets walked the same folded branches again per target.
The walk from a start is now done once, numbering what it meets and
indexing transitions by where they arrive; a chain's union is gathered
by walking back from its target over that index and put in walk order,
so it costs the size of the union.
…edge

The scaling table gains a flowchart entry that reads every edge's lists
and label, counting what it reads as output, a shape of two folded
branches leading to many common ends, and an unchanged flowchart of
those merged edges diffed against its model.
The walk behind merged chains entered everything a start reached, so
many short chains sharing a run of messages that leads nowhere each
walked and kept that run. The folded elements that lead to some
accepted element are now found once, by walking back from the accepted
elements, and every walk and the carried messages enter only those.
Walks are shared per component, from its first member in model order,
since every member of a component reaches the same elements.
The scaling table gains diamonds sharing a run that leads nowhere, and
one half of which leads somewhere, through every projection and an
unchanged flowchart diff. Edit rows are measured per item of their
input, the model and the edited view as read, as the projection rows
are.
Folding an element draws one chain per way in and drawn element it
leads to, so many sources through one message, or a run of messages,
to many ends drew every source to every end: quadratic output from
linear input. An element is now folded only when the distinct entering
transitions reaching it times the distinct drawn elements it reaches,
through folded elements, is no more than their sum. The counts are
capped sets carried once each way over the condensed folded graph.
An element left unfolded is reported, with the transitions touching it,
as an unrepresented element by the flowchart, swimlane and state
machine; hand-offs and the inverses follow the same index.
The scaling table gains many sources through one message, and through
two, to many ends, and a test that the flowchart, hand-offs and state
machine draw no more edges than the model has transitions for those
shapes as they double.
@Mearman
Mearman force-pushed the feat/projection-gaps branch from 614b048 to ff54234 Compare October 11, 2026 00:14
@Mearman

Mearman commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

@codex security review

1 similar comment
@Mearman

Mearman commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: ff542343ba

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@Mearman
Mearman merged commit a610839 into main Oct 11, 2026
14 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant