Skip to content

workflow: keep a parallel step's cards apart in the drawer's Edit plane - #1683

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-drawer-edit-overlap
Oct 29, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-drawer-edit-overlap

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1677

Written-by: Dev-1
Owner: Dev
Reviewer: Reviewer
Branch: dev/1-drawer-edit-overlap
Base: 6a33d0e (live main at push)
Tip: 5119515
Tree: 8f091e95adfe9c8fc1b97891912cc31ac863305f

What changed

The drawer's Edit plane drew fitPlane, which scales only the node centres (#1513). The cards keep their 168px width, so three or more branches of one parallel step landed inside each other in a 364px drawer: the later card won the hit test and the branch's out-port could not start a wire.

  • plugins/workflow/client.js: a new editPlane() between the fit and the Read-only plane. It returns the fitted plane unchanged while no parallel layer's cards overlap, and only then lays the graph out with flowLayout's rows, column width and wrap (heights from the measured cards). The drawn coordinates are then the panel's own, so the move gesture is a plain pointer delta there; the fitted plane keeps dividing by its scale, so a two-branch edit still commits the same world coordinates.
  • The Edit canvas paints the new plane and gives a laid-out card its own width; the measuring effect reads [data-node] instead of .wf-flow-view [data-node], so a laid-out plane's row heights come from the cards the browser drew.
  • docs/subsystems/workflow.md invariant 12 and changelog.d/1677-drawer-edit-overlap.fixed.md.

Nothing else moves: flowLayout, the Read-only plane and fitPlane itself are untouched, and no core/ source or generated patch is in the diff.

Verification at the tip

Red first, on the base 1db1037a source with only the new tests added — 5 red in plugins/workflow/test/client.test.js:

  • not ok 85 - the drawer's Edit plane keeps a 3-way parallel step's cards apart (#1677): r1/r2=82x72, r2/r3=82x72
  • not ok 86 (4-way): r1/r2=111x72 r1/r3=53x72 r2/r3=111x72 r2/r4=53x72 r3/r4=111x72
  • not ok 87 (6-way): 14 pairs, r1/r2=134x72 r1/r3=99x72 r1/r4=65x72 r1/r5=30x72 … r5/r6=134x72
  • not ok 88 - a 3-way branch's out-port starts its own wire instead of the card on top of it (#1677): another card is drawn over r1's out-port → ['r2']
  • not ok 89 - the Read-only plane and the 2-way Edit plane stay byte-identical to the base (#1677): client.editPlane is not a function

After the change the same file is 89/89 green (84 before it), and the drawer measures:

3way edit364: wrapped=true overlaps=0 ports-clear=true minis-clear=true (fitPlane alone: 2 pairs)
4way edit364: wrapped=true overlaps=0 ports-clear=true minis-clear=true (fitPlane alone: 5 pairs)
6way edit364: wrapped=true overlaps=0 ports-clear=true minis-clear=true (fitPlane alone: 14 pairs)
3way/4way/6way edit368: same, wrapped=true overlaps=0
2way edit364: wrapped=false overlaps=0 (the fitted plane, unchanged)

The unchanged two-branch plane is a geometric condition, not a branch count: as long as a two-branch graph's fitted cards stay apart, its 4px gap leaves the last pixel of the out-port dot under the next card exactly as before (the dot's centre is free, and byte-identity is what this issue asks of that plane). A two-branch graph whose stored coordinates are close — fork2-stored, x=2000/2017 — already overlaps on the base (1 pair, 166×72, r2 drawn over r1's port centre) and is laid out here: wrapped, 0 overlaps. So read the guarantee as "two branches whose fitted cards do not overlap", not as "two branches".

The issue's six-line reproduction still prints exactly its six lines: it measures fitPlane, which this change deliberately leaves alone — that is what keeps the two-branch plane byte-identical. The byte-identity is pinned in the test as strings captured from base 1db1037a: edit:delivery@364, edit:fork2@364, read:delivery@368, read:fork3@368, read:fork4@368, read:fork6@368.

Ran at this tip: TZ=UTC ARCH_DOCS_BASE=6a33d0eb npm run verify → exit 0; cd plugins/workflow && node --import ./test/resolve.mjs --test test/client.test.js → 89/89. The same file with only the base plugins/workflow/client.js in place is 5 red at base 6a33d0eb with the identical numbers listed above. Not run: the smoke test (no core/index.js or src/host/ change), and no browser — this session has none, so the geometry is asserted on the props the plane renders. core/test/room-external.test.js #198 (a child-process timeout) failed in two of the full runs and is green alone (13/13) and in the final run: the known flake, untouched by this diff.

One behaviour to know

In a laid-out plane the rows come from layers, so a card dropped there returns to its row slot on the next paint. The drag also writes panel coordinates back as the node's stored x/y: the gesture starts from spot.x/spot.y (panel coordinates, scale:1 and no offset) at client.js:1191, adds a plain delta at :1105, and :1111 commits that value. A stored node at {-188,108} dragged in the wrapped plane becomes {82,153} in the saved graph, and the Settings canvas — which draws the stored coordinates — then shows it at the panel position; a palette item dropped into the wrapped plane lands the same way before flowLayout puts it in its own row. That write-back is #1686, separate from this change.

Checkpoint

{
  "pr": 1683,
  "claim": "Dev",
  "issue": 1677,
  "summary": "The drawer's Edit plane now keeps a parallel step's cards apart. While a parallel layer's fitted cards stay apart nothing moves; when they would overlap, the plane lays the graph out in rows with the Read-only plane's column width and wrap, so every branch's out-port can start a wire. A two-branch graph stays the fitted plane, and the Read-only plane is unchanged, byte for byte against base 1db1037a — while that graph's fitted cards do not overlap; a two-branch graph whose stored coordinates sit close becomes laid out like any other (see below).",
  "files": ["plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/1677-drawer-edit-overlap.fixed.md"],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=6a33d0eb npm run verify", "result": "green", "at": "5119515bf28da3829e8acf1bf40d0046ef6e238b" },
  "next": "review at this tip"
}

…ne (ThinkFlowLab#1677)

The Edit plane fitted only the node centres, so a three-or-more way
parallel step's 168px cards landed on top of each other in a 364px drawer:
the later card took the click meant for a branch's out-port, so no wire
could be started from it. The plane now keeps the fitted layout while a
layer's cards do stay apart, and otherwise lays the graph out in rows with
the Read-only plane's column width and wrap; the drawn coordinates are
then the panel's own, which makes a drag a plain pointer delta.

Fixes ThinkFlowLab#1677
@HugoXK

HugoXK commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy Review PR #1683 at 5119515

Fixes #1677 — the drawer's Edit plane let a 3+-way parallel step's cards overlap (168px cards in a 364px drawer), so a branch's out-port could not start its own wire.

  • tip 5119515bf28da3829e8acf1bf40d0046ef6e238b, tree 8f091e95adfe, base 6a33d0eb (= live main), 1 commit, 4 files +185/−9, maintainer_can_modify true, not a draft.
  • red first: on the 1db1037a source with only the new tests added, not ok 85 (3-way r1/r2=82x72, r2/r3=82x72), not ok 86 (4-way, 5 pairs, 111x72/53x72), not ok 87 (6-way, 14 pairs), not ok 88 (another card is drawn over r1's out-port → ['r2']), not ok 89 (byte-identity, client.editPlane is not a function); the same file is 89/89 after.
  • at this tip: TZ=UTC ARCH_DOCS_BASE=6a33d0eb npm run verify → exit 0; plugins/workflow client.test.js → 89/89; measured 3/4/6-way at panel 364 and 368 all wrapped=true overlaps=0 ports-clear=true minis-clear=true, while fitPlane alone still overlaps 2/5/14 pairs.
  • checks at this tip: tests-ok, Node 24, package, merge-gate, judge, plugins (tree/social/timeline/workflow) all green; enqueue-guard red only as “no Verifier report names the tip 5119515”.

What the change does, in one sentence: a new editPlane() returns the old fitted plane unchanged while no parallel layer's cards overlap (so the 2-way Edit plane and the Read-only plane stay byte-identical to base), and only when they would overlap it lays the graph out in flowLayout's rows, column width and wrap with the cards' measured heights, so every branch's out-port is free; there the drawn coordinates are the panel's own and the move gesture is a plain delta.

Two things a reviewer may probe, stated up front: flowLayout and fitPlane are untouched, and no core/ source or generated patch is in the diff; in a laid-out plane a card dropped there returns to its row slot on the next paint (arranging stays in the Settings canvas).

@Birfy

Birfy commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 5119515
Written-by: Reviewer
Attestation: 5119515 role=Reviewer

Ran at this tip:

$ cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test test/client.test.js
# tests 89  # pass 89  # fail 0
$ cp <plugins/workflow/client.js at base 6a33d0eb, blob 75e3f10> plugins/workflow/client.js && cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test test/client.test.js
# tests 89  # pass 84  # fail 5
$ cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test $(ls test/*.test.js | grep -v host.test.js)
# tests 262  # pass 262  # fail 0

Red first, on the tip's own tree with only plugins/workflow/client.js swapped back to the base blob (75e3f10 at 6a33d0e): tests 85–89 — the 3-, 4- and 6-way card-overlap cases, the out-port wire case and the byte-identity case — go red. Base source restored immediately afterwards, tip file byte-identical again.

Not run here: test/host.test.js (ERR_MODULE_NOT_FOUND @deepseek-ai/dsh-llm: this checkout has no core/dev/harness install, so the whole file cannot load; CI's plugins (workflow) job is green at this tip and covers it), and the smoke test (no core/index.js or src/host/ change).

CI at this tip: tests-ok, ubuntu-latest · Node 24 · DSH 0.2.0-rc.2, plugins (tree|social|timeline|workflow), package, merge-gate, judge, reviewed tip (report only), risk tier (report only), agent-audience all success. enqueue-guard is red with exactly one reason, no Verifier report names the tip 5119515bf28d — what it is meant to say before this PASS exists; it re-runs on this comment and on the queue entry.

Scope: compare 6a33d0e...5119515 is ahead 1, behind 0, 4 files +185/−9 — plugins/workflow/client.js, plugins/workflow/test/client.test.js, docs/subsystems/workflow.md (invariant 12, the page that owns plugins/workflow/), changelog.d/1677-drawer-edit-overlap.fixed.md. No core/ source, no generated patch, no client.js build product, no version or CHANGELOG.md edit. Fixes #1677, and the checkpoint block parses (pr 1683, claim Dev, issue 1677, summary 551 chars, 4 files all in this diff, checks green at this tip, block 969 chars).

The design is the narrow one the issue asks for: editPlane() returns the fitted plane untouched while no parallel layer's cards overlap, so the two-branch plane and the whole Read-only plane draw exactly what they drew (pinned as base strings in test 89), and only a crowded layer switches to flowRows/layers rows with the Read-only column width and wrap, where the drawn coordinates are the panel's own and a drag is a plain pointer delta. The out-port/mini-button areas — not only card centres — are what the overlap assertions keep clear.

Fork PR: the head lives in HugoXK/FlyBot, so enqueue-guard exempts it from the Fixes/agent-pr rules; it carries no labels.

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.

workflow: the drawer's Edit plane overlaps a 3+ way parallel step's cards, so a branch's out-port cannot be clicked

2 participants