Each enrollment scope owns its panels, ports and temp dirs, so the two run
side by side; the only shared state, the process-global database handle the
harness borrows for setup and for simulating a lost inbound, is now behind a
mutex. On Linux the suite drops from 188s to 95s.
CLAUDE.md now names the fast contract layer (node_contract_test.go, in
make test-go) next to the multi-tick nodee2e layer.
Node sync had no test with two real panels: the single-panel tests either
call the node's controller in-process or hand-set the node-sync scope, so
823db059 shipped a regression no test could see (an admin-token node
dropped every client and enable flag its master pushed).
internal/nodee2e starts a master and a node as separate panel processes
(the DB is a process-wide global, so one process cannot be both) and walks
17 operations per enrollment scope (admin token, node-sync token): adopt,
create/edit on the master, small and bulk attach, client disable, detach,
client delete, inbound disable, traffic pull and reset, node-side delete
mirrored centrally (#6219), master-side delete, node down, node-lost
inbound re-created, create/edit while down, node disabled on the master,
and selected sync mode leaving unselected inbounds alone.
Against the build before 2ffc694a it fails 6 cells for an admin-token node
and 1 for a node-sync one; on main all 34 pass, on Windows and on Linux.
`make node-e2e` builds a stub-dist binary and runs it; ci.yml runs it as
its own job where a SKIP fails the build. Xray is not started, so cells
assert the node's stored state, not traffic through the core.