test: pin LLink spread-copy topology loss as it.fails - #15597
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1985 passed, 0 failed · 3 flaky📊 Browser Reports
📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-08-22T04:41:07.148Z",
"gitSha": "85a51797790d84cbc6f8008c249be1bb42e1d60e",
"branch": "cb__llink-spread-test",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2051.3229999999967,
"styleRecalcs": 7,
"styleRecalcDurationMs": 5.390000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 478.233,
"heapDeltaBytes": -13828240,
"heapUsedBytes": 55150320,
"domNodes": -282,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 7.83,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-idle",
"durationMs": 2072.749999999928,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.161000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 511.44100000000003,
"heapDeltaBytes": 9447396,
"heapUsedBytes": 78742008,
"domNodes": -281,
"jsHeapTotalBytes": 5234688,
"scriptDurationMs": 11.135,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2353.827999999993,
"styleRecalcs": 78,
"styleRecalcDurationMs": 41.535999999999994,
"layouts": 12,
"layoutDurationMs": 3.8420000000000005,
"taskDurationMs": 1381.802,
"heapDeltaBytes": 3073232,
"heapUsedBytes": 71824916,
"domNodes": -283,
"jsHeapTotalBytes": 5758976,
"scriptDurationMs": 185.659,
"eventListeners": -157,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2158.0490000000054,
"styleRecalcs": 79,
"styleRecalcDurationMs": 38.528000000000006,
"layouts": 12,
"layoutDurationMs": 3.797,
"taskDurationMs": 1175.927,
"heapDeltaBytes": 4177352,
"heapUsedBytes": 73322724,
"domNodes": -279,
"jsHeapTotalBytes": 6545408,
"scriptDurationMs": 141.88299999999998,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1711.232999999993,
"styleRecalcs": 31,
"styleRecalcDurationMs": 13.306999999999999,
"layouts": 6,
"layoutDurationMs": 0.6309999999999999,
"taskDurationMs": 328.577,
"heapDeltaBytes": 3621476,
"heapUsedBytes": 72754424,
"domNodes": 73,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 10.222,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1717.9439999999886,
"styleRecalcs": 30,
"styleRecalcDurationMs": 14.427999999999997,
"layouts": 6,
"layoutDurationMs": 0.631,
"taskDurationMs": 337.11499999999995,
"heapDeltaBytes": 3800784,
"heapUsedBytes": 72730140,
"domNodes": 74,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 9.928999999999998,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 704.589999999996,
"styleRecalcs": 10,
"styleRecalcDurationMs": 6.5150000000000015,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 405.13000000000005,
"heapDeltaBytes": -7057056,
"heapUsedBytes": 61936616,
"domNodes": 16,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 31.387999999999998,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 737.2169999999869,
"styleRecalcs": 10,
"styleRecalcDurationMs": 6.292000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 419.993,
"heapDeltaBytes": -6866636,
"heapUsedBytes": 61894124,
"domNodes": 16,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 36.849,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-idle",
"durationMs": 2089.711999999963,
"styleRecalcs": 5,
"styleRecalcDurationMs": 4.397,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 585.5620000000001,
"heapDeltaBytes": -19121712,
"heapUsedBytes": 71391548,
"domNodes": -273,
"jsHeapTotalBytes": -528384,
"scriptDurationMs": 37.660000000000004,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2054.363999999964,
"styleRecalcs": 6,
"styleRecalcDurationMs": 5.193,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 558.899,
"heapDeltaBytes": -21082540,
"heapUsedBytes": 69210228,
"domNodes": -277,
"jsHeapTotalBytes": -528384,
"scriptDurationMs": 34.042,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 3236.344000000031,
"styleRecalcs": 65,
"styleRecalcDurationMs": 10.96,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2489.438,
"heapDeltaBytes": -5365148,
"heapUsedBytes": 85448216,
"domNodes": -273,
"jsHeapTotalBytes": 1007616,
"scriptDurationMs": 886.241,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 3263.9090000000124,
"styleRecalcs": 65,
"styleRecalcDurationMs": 10.727999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2505.333,
"heapDeltaBytes": 13487820,
"heapUsedBytes": 97980336,
"domNodes": -284,
"jsHeapTotalBytes": 4640768,
"scriptDurationMs": 905.172,
"eventListeners": -181,
"totalBlockingTimeMs": 16,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 4312.301999999989,
"styleRecalcs": 66,
"styleRecalcDurationMs": 11.76,
"layouts": 60,
"layoutDurationMs": 7.698,
"taskDurationMs": 2504.432,
"heapDeltaBytes": 595540,
"heapUsedBytes": 72778240,
"domNodes": -263,
"jsHeapTotalBytes": -1351680,
"scriptDurationMs": 852.9590000000001,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 4367.896000000087,
"styleRecalcs": 66,
"styleRecalcDurationMs": 11.883999999999999,
"layouts": 60,
"layoutDurationMs": 7.823,
"taskDurationMs": 2509.264,
"heapDeltaBytes": 15817808,
"heapUsedBytes": 88171492,
"domNodes": -236,
"jsHeapTotalBytes": -565248,
"scriptDurationMs": 851.9879999999999,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "legacy-node-drag",
"durationMs": 3254.6140000000037,
"styleRecalcs": 41,
"styleRecalcDurationMs": 5.7769999999999975,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2045.1819999999996,
"heapDeltaBytes": -1590964,
"heapUsedBytes": 69987928,
"domNodes": -289,
"jsHeapTotalBytes": -565248,
"scriptDurationMs": 217.302,
"eventListeners": 29,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "legacy-node-drag",
"durationMs": 3159.856999999988,
"styleRecalcs": 41,
"styleRecalcDurationMs": 5.747000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2030.164,
"heapDeltaBytes": 13124608,
"heapUsedBytes": 80510344,
"domNodes": 0,
"jsHeapTotalBytes": 1990656,
"scriptDurationMs": 198.052,
"eventListeners": 188,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2027.7550000000133,
"styleRecalcs": 3,
"styleRecalcDurationMs": 2.349,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 514.77,
"heapDeltaBytes": -19819136,
"heapUsedBytes": 72893520,
"domNodes": -272,
"jsHeapTotalBytes": -2363392,
"scriptDurationMs": 36.185,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2031.5970000000334,
"styleRecalcs": 3,
"styleRecalcDurationMs": 2.9680000000000017,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 440.83399999999995,
"heapDeltaBytes": -22453344,
"heapUsedBytes": 68895532,
"domNodes": -278,
"jsHeapTotalBytes": 2617344,
"scriptDurationMs": 36.324000000000005,
"eventListeners": -185,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 698.8789999999767,
"styleRecalcs": 47,
"styleRecalcDurationMs": 9.471,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 493.66900000000004,
"heapDeltaBytes": 17893244,
"heapUsedBytes": 87401804,
"domNodes": 20,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 133.094,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 707.6799999999821,
"styleRecalcs": 47,
"styleRecalcDurationMs": 9.871999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 498.68500000000006,
"heapDeltaBytes": 17843180,
"heapUsedBytes": 87504444,
"domNodes": 20,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 133.404,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-idle",
"durationMs": 2019.7630000000117,
"styleRecalcs": 8,
"styleRecalcDurationMs": 5.9190000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 473.159,
"heapDeltaBytes": 4040600,
"heapUsedBytes": 66725428,
"domNodes": -295,
"jsHeapTotalBytes": 4448256,
"scriptDurationMs": 6.994999999999999,
"eventListeners": -231,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2018.0239999999685,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.223999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 468.96000000000004,
"heapDeltaBytes": 8311400,
"heapUsedBytes": 78048140,
"domNodes": -293,
"jsHeapTotalBytes": 4448256,
"scriptDurationMs": 6.544000000000001,
"eventListeners": -201,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1888.6099999999715,
"styleRecalcs": 79,
"styleRecalcDurationMs": 33.617000000000004,
"layouts": 16,
"layoutDurationMs": 4.339,
"taskDurationMs": 1085.397,
"heapDeltaBytes": 7641592,
"heapUsedBytes": 77486164,
"domNodes": -296,
"jsHeapTotalBytes": 6545408,
"scriptDurationMs": 106.445,
"eventListeners": -233,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1847.454999999968,
"styleRecalcs": 76,
"styleRecalcDurationMs": 34.603,
"layouts": 16,
"layoutDurationMs": 4.342,
"taskDurationMs": 1075.8799999999999,
"heapDeltaBytes": 10346248,
"heapUsedBytes": 80237568,
"domNodes": -297,
"jsHeapTotalBytes": 5496832,
"scriptDurationMs": 106.116,
"eventListeners": -233,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-transition-enter",
"durationMs": 1391.183999999953,
"styleRecalcs": 19,
"styleRecalcDurationMs": 29.863000000000007,
"layouts": 14,
"layoutDurationMs": 13.030000000000001,
"taskDurationMs": 895.0920000000002,
"heapDeltaBytes": -7428784,
"heapUsedBytes": 82572296,
"domNodes": 13671,
"jsHeapTotalBytes": 10747904,
"scriptDurationMs": 26.490999999999993,
"eventListeners": 2383,
"totalBlockingTimeMs": 117,
"frameDurationMs": 16.666666666666696,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "viewport-pan-sweep",
"durationMs": 12315.49799999999,
"styleRecalcs": 247,
"styleRecalcDurationMs": 38.454,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 8862.928,
"heapDeltaBytes": 673184,
"heapUsedBytes": 91419788,
"domNodes": -282,
"jsHeapTotalBytes": 4644864,
"scriptDurationMs": 3050.554,
"eventListeners": -129,
"totalBlockingTimeMs": 4,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 12293.847000000027,
"styleRecalcs": 247,
"styleRecalcDurationMs": 37.57000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 8698.268,
"heapDeltaBytes": 9418872,
"heapUsedBytes": 92915340,
"domNodes": -280,
"jsHeapTotalBytes": 5394432,
"scriptDurationMs": 3024.5829999999996,
"eventListeners": -159,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 17406.724,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16793.424000000003,
"heapDeltaBytes": -55260100,
"heapUsedBytes": 162333864,
"domNodes": -6548,
"jsHeapTotalBytes": -2863104,
"scriptDurationMs": 329.94900000000007,
"eventListeners": -7473,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 17212.274999999976,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16650.464,
"heapDeltaBytes": -35946236,
"heapUsedBytes": 175636352,
"domNodes": -6548,
"jsHeapTotalBytes": -3788800,
"scriptDurationMs": 363.508,
"eventListeners": -7473,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21236.218000000008,
"styleRecalcs": 173,
"styleRecalcDurationMs": 18.66599999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20932.619,
"heapDeltaBytes": -43046444,
"heapUsedBytes": 162358176,
"domNodes": -6548,
"jsHeapTotalBytes": 512000,
"scriptDurationMs": 877.7810000000001,
"eventListeners": -7471,
"totalBlockingTimeMs": 48,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21599.220999999943,
"styleRecalcs": 180,
"styleRecalcDurationMs": 19.910999999999984,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21212.807999999997,
"heapDeltaBytes": -44520792,
"heapUsedBytes": 169001584,
"domNodes": -6548,
"jsHeapTotalBytes": -2891776,
"scriptDurationMs": 906.572,
"eventListeners": -7469,
"totalBlockingTimeMs": 91,
"frameDurationMs": 17.773333333333238,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 111.66199999991022,
"styleRecalcs": 9,
"styleRecalcDurationMs": 14.918999999999999,
"layouts": 2,
"layoutDurationMs": 0.591,
"taskDurationMs": 78.41799999999999,
"heapDeltaBytes": 3430760,
"heapUsedBytes": 69969272,
"domNodes": 111,
"jsHeapTotalBytes": 0,
"scriptDurationMs": 4.303999999999999,
"eventListeners": 49,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66666666666665,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "workflow-execution",
"durationMs": 490.42099999996935,
"styleRecalcs": 18,
"styleRecalcDurationMs": 22.744,
"layouts": 9,
"layoutDurationMs": 2.124,
"taskDurationMs": 133.397,
"heapDeltaBytes": 5755736,
"heapUsedBytes": 72247600,
"domNodes": 145,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 8.067,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
}
]
} |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## feature/ecs-migration #15597 +/- ##
========================================================
Coverage ? 82.29%
========================================================
Files ? 1900
Lines ? 107659
Branches ? 33595
========================================================
Hits ? 88594
Misses ? 18730
Partials ? 335
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
LLink's topology fields are prototype accessors over _state, so a spread copy of a link carries none of them. Covers the LLink half of the failure class that node/legacySlotLinkMutations.test.ts already pins for slots. Refs #15594
e46442b to
eef0a47
Compare
Summary
{ ...graph.links[id] }loses every topology field on this branch, and there was no test for it. This adds theLLinkhalf of the failure classnode/legacySlotLinkMutations.test.tsalready pins for slots.Changes
src/lib/litegraph/src/LLink.spreadCopy.test.ts— twoit.failscases asserting the behaviour we want, so they flip green when a fix lands.id,type,origin_id,origin_slot,target_id,target_slot.disconnectOutput, reconnect the far ends from the copies, and the downstream nodes are still wired.LLinkwent from 16 own-field declarations at merge-base6532665db9to 12 at head, with the six topology fields becoming prototype accessors over_stateand zerodefinePropertycalls. Prototype accessors are not own properties, so spread copies nothing.Case 2 is the shape ComfyUI-Custom-Scripts uses in "Add Clip Skip" and "Add LoRA" (
web/js/quickNodes.js:132,:156-157): the user's downstream wiring is disconnected and never restored. Filed as #15594.Only case 1 proves the mechanism. Case 2 is what a user reports.
Review Focus
Mutation numbers. Scratch edit defining the six fields as own enumerable accessors in the
LLinkconstructor, then reverted:The 2 failures are exactly the 2 new cases, failing with
Expect test to fail. Nothing else moved.Corpus: 1 of 29 local packs, 3 call sites — all in ComfyUI-Custom-Scripts. Measured over 157 frontend pack files, control
/registerExtension/→ 84 files. Widened toObject.assign({}, link),structuredClone, andJSON.parse(JSON.stringify(...))on link-named identifiers: 0 additional. This bounds #15594 rather than broadening it — the idiom is rare, but the one pack using it is widely installed.vue-tscalready knows. The first draft typed the copies as the spread's inferred type and produced 8TS2339errors — TypeScript models the accessors as dropped. The committed version usesPartial<LLink>, which is what a JS caller actually holds. Typecheck at 8GB: 0 errors in the new file (1494 → 1486 total, the 8 removed are mine).The file carries
// oxlint-disable no-misused-spread— that rule fires on exactly the pattern under test.Refs #15594