You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Root cause, confirmed via real CI history (6/6 shard-1 failures, all
after goal 0017 merged, zero before) and local reproduction (9/20
clean-canvas repeats failed with zero artificial load): goal 0017 gave
every direct-mutation service its own dataevent.Emit call, so a single
MCP update_workflow write now fires mill-data-changed TWICE
(SnapshotDraft + UpdateWorkflow) plus a third echo from the test's own
prior UI-driven CreateWorkflow. None carry payload content, so each
handler independently refetches — three fetches racing meant whichever
resolved last won unconditionally, letting a stale response beat an
already-applied newer one and wrongly show the external-change banner
on a clean canvas.
Fixed in useCanvasLiveSync.ts with a monotonic request-sequence guard
(the standard out-of-order-async-response fix): drop a fetch response
once a newer mill-data-changed event has arrived since it was
dispatched. Verified: 88 consecutive clean local repeats post-fix vs.
9/20 before it, same build.
Also: canvas-live-sync.spec.ts's cleanup hardened into an outer
try/finally (both tests) so a future assertion failure can't leave an
undeleted workflow / unattended-MCP-writes settings for later tests in
the same worker — defense-in-depth for the observed cascade,
independent of the root-cause fix. resizable-table.spec.ts's one
occurrence (PR #24, drag-handle bounding box) hardened with a
condition-based expect.poll wait at the point of use, additive to the
suite's existing retries: 1 (goal 0024 precedent, untouched).
BACKLOG.md Standing #1 checked off with the full root-cause writeup;
SPEC.md's realtime-lock section gets an Update note generalizing the
lesson for future mill-data-changed consumers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018pkViCNAuZp2vBv2K9AbUh
Copy file name to clipboardExpand all lines: docs/goals/BACKLOG.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -184,7 +184,7 @@ live-review material, interleaved during owner reviews, not a lane.**
184
184
contention flake, both confirmed transient on an isolated rerun).
185
185
186
186
**Standing — ratified order (owner-delegated prioritization, 2026-08-12: "prioritize all work to line them up"; Dependabot majors pulled to the front same day per the deps-don't-linger policy and are IN FLIGHT as their own sequential wave, not listed here)**
187
-
1. [ ] E2e CI flake investigation (owner-directed 2026-08-12: "add to the backlog when problem found so that we prioritize to unblock us"; FIRST in queue because it taxes every subsequent PR with rerun cycles — `canvas-live-sync` alone flaked twice on 2026-08-12) — distinct e2e specs failing once on a shard then green on immediate rerun, across different PRs: `resizable-table.spec.ts` (drag-handle bounding-box), `canvas-live-sync.spec.ts` (MCP `update_workflow` live-redraw assertion, ×2), and (Go side, same class) `TestMillMCPService_RealClientRoundTrip` (already fixed — 2s `Shutdown` timeout too tight for a loaded runner, bumped to 10s, PR #21). Each individually diagnosed unrelated to its PR and confirmed transient by rerun — but the pattern deserves batch investigation: under-resourced shared runners vs a shared timing-sensitivity shape in these specs vs the general suite shape surfacing one spec at a time. DoR: pull actual CI run history for pass/fail/rerun rates over the last N runs before assuming root cause; DoD: a fix (shared wait pattern, strategic retries per goal 0024's e2e-retry precedent) or a documented accept-with-reasoning, never silence.
187
+
1. [x] E2e CI flake investigation — RESOLVED 2026-08-12 (`fix/e2e-flake-hardening`). Real CI history (last ~30 `ci.yml` runs) showed `canvas-live-sync.spec.ts` failing 6/6 times on shard 1, every single occurrence at the exact same assertion (`canvas-live-sync.spec.ts:151`, the `external-change-banner` count) and every single occurrence co-occurring with a `configure-lists.spec.ts` "list-search node" flake in the SAME run (recovered on Playwright's own retry every time) — zero occurrences before goal 0017 (PR #16) merged, all 6 after. Root cause: goal 0017 gave every direct-mutation Go service its own `dataevent.Emit("workflow", id)` call, so a single MCP `update_workflow` write now fires the SAME `mill-data-changed` event TWICE (`SnapshotDraft`'s own emit via `mutateWorkflow`, plus `UpdateWorkflow`'s own emit) — plus a THIRD echo from the test's own earlier UI-driven `CreateWorkflow`, still possibly in flight when the canvas mounts. None of the three carry payload content, so each independently re-fetches via `CompositionService.Workflows()`; three fetches racing meant whichever RESOLVED last won unconditionally regardless of dispatch order, so a stale response could occasionally win the live-sync decision against a baseline a different, already-applied response had advanced past — wrongly showing the external-change banner on a genuinely clean canvas. A REAL race, confirmed via local reproduction (9/20 clean-canvas repeats failed with zero artificial load, identical assertion/line to all 6 CI failures) and a temporary event-trace instrument. Fixed in `frontend/src/composition/useCanvasLiveSync.ts`: a monotonic per-hook request-sequence ref, bumped at event ARRIVAL time, drops any fetch response that's gone stale by the time it resolves (the standard out-of-order-async-response guard) — correct regardless of how many redundant emits fire in a burst or their resolution order. Verified: 88 consecutive clean local repeats post-fix (0 failures) vs. 9/20 before it, same build. `canvas-live-sync.spec.ts`'s own cleanup (both tests) hardened into an outer try/finally regardless, so a future assertion failure can never again leave an undeleted workflow / unattended-MCP-writes settings behind for later tests in the same worker. `resizable-table.spec.ts` (1 occurrence, PR #24, drag-handle bounding-box) hardened with a condition-based `expect.poll` wait at the point of use, additive to the suite's existing `retries: 1` (goal 0024's documented precedent, untouched). `TestMillMCPService_RealClientRoundTrip` was already fixed (PR #21). Full local suite green; both suspect specs run 5x locally with zero failures.
188
188
2.[ ][0031 — AI node family](0031-ai-node-family.md) — research banked in the goal file (two adapters: openaicompat covers Ollama+BYO, anthropic native; AIProvider Configure entity; ai-completion + ai-extract-structured first). Effect-class LOCKED by owner delegation 2026-08-12 ("you're the boss"): static `ClassExternal` + `EffectForNode` downgrade to `ClassLocal` for loopback (localhost/127.0.0.1/::1) BaseURLs — remote asks by default, local Ollama frictionless. The flagship capability; conforms to node-standard.md from birth.
189
189
3.[ ] Copy-management migration ×4 (below, in order: `app/` → `composition/` → `configure/` → `views/`) then the `eslint-plugin-i18next` revisit — mechanical filler, interleaves between heavier waves when useful.
190
190
4.[ ] Workflow pins/favorites (tech debt, split from goal 0015's remainder 2026-08-12) — schema DECIDED at prioritization (orchestrator, 2026-08-12): a plain ordered workflow-ID list, store-owned (localStorage-tier alongside the frecency substrate; no per-workflow field, no new Go surface unless syncing matters later). Pinned rows sort above frecency in Quick Panel/⌘K.
0 commit comments