Save path: one atomic POST /views/{id}/commit (edges, ports, styles, node
add/remove, positions) replaces the multi-request save. Edge styles and
manual-edge port edits now go through dirty/undo/save instead of writing
immediately; non-manual edge ports are read-only.
Data safety: UI saves no longer clear MCP node locks or freeze the device
name into the placement label (label_override + omit-means-keep semantics,
also applied to the MCP positions tool). Adding NEs/neighbors with unsaved
edits now saves first instead of silently dropping them. Positions no longer
bypass membership caps, except persisting synthesized child-region icons.
Fixes found in acceptance: nodes added in the same commit kept (40,40)
under autoflush=False; edits on edges deleted in the same save 404'd the
whole save; box-selection drags and arrow-key moves were not marked dirty;
large canvases far from the origin opened blank and locate did nothing
because fitView waits for measurement that onlyRenderVisibleElements never
does (now fitBounds from known geometry).
Also: batch N+1 lookups in graph/positions, deterministic truncation,
outside-peer scan excludes internal edges, split TopologyPage into hooks,
fix flaky UME/LLDP port test, add scripts/topology_clear_frozen_labels.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
theme.css squashes every animation to 0.01ms x1 when the OS asks for reduced
motion, so the login earth jumped once and snapped back (position stuck at 0%).
The login stylesheet already intends the ambient spin to stay; restore it with a
class selector that outranks the universal rule.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The unanchored 'ume/' rule also matched web/src/features/ume/, so UmePage was
never committed and clean checkouts failed to build (App.tsx imports it).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Correctness (A): normalize port-map names with the template rules (snapshot v2,
v1 replays unchanged); protect mappings/templates that are referenced; stop
dropping edited mapping text; accept pulled-but-not-shutdown ports as migrated;
validate baseline ownership on project create; one canonical key form; fix
built-in template tolerances and upgrade old packaged values in place.
Cross-vendor identity (B): single identity pipeline for every path, per-side and
per-vendor interface rules, value maps, filters after normalization, mapping
pre-flight for compare and cutover projects, SQL eligibility fixes.
Data quality (V): no_data / suspect_parse / not_collected sheet states, command
slice coverage, directional compare modes, value-sorted duplicate pairing,
before-side raw names in results and CSV.
Robustness (H): bounded auto-run history, background evaluate/finish with
polling, manual route tables out of the acceptance gate, baseline row cache,
scoped duplicate-key failures, merged HF tasks with a per-NE session cap,
same-device cutover, explicit scope_by_port_map, read-only GETs, resolvable red
tickets.
Frontend: pre-flight report, mapping table view, template editor support for the
new rules, data-state banners. Docs: canonical field contract.
Not included: Huawei status parsers (no real samples), SQL-path route compare.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Use the shared ListPager (10/20/50/100/200 per page, remembered in
localStorage, default 20 instead of a fixed 10), keep the previous rows while the
next page loads and clamp the page when the total shrinks.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Performance: event-driven stdout pump (no polling thread per socket, no 200ms
coalescing stall), keystrokes written immediately, blocking SSH reads, bounded
deque queue with batch drain, incremental UTF-8 decode, buffered session log,
non-blocking session teardown, shorter login/settle waits, xterm WebGL renderer
and idle-time direct writes. Zero-latency fake device: echo p50 11ms -> 2.3ms,
command RTT 219ms -> 20ms, bulk output 2.1 -> 8.3 MB/s.
Audit: track the device's own input row server-side (webcrt_cmd_audit) and
resolve each Enter from the echoed line feed, so Tab, backspace, cursor-key
edits, history recall, paste, Ctrl-C and pagers record what actually ran.
Password lines are redacted; pending Enters are flushed on close.
Hop: stop closing the hop session when the target prints the same prompt as the
hop (system-view); recognise the Huawei "closed by the remote host" message.
Generic NEs that show a network prompt now get the network key map.
Adds bench_webcrt.py, fake_ssh_device.py and e2e_webcrt_input_scenarios.py.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove permanent list-page hint banners, keep concepts in short HelpHint popovers with scannable sections and lists.
Co-authored-by: Cursor <cursoragent@cursor.com>
With a few fails among tens of thousands of rows, 1-decimal rounding hid residual failures; keep extra precision so the UI never shows 100% when fails remain.
Co-authored-by: Cursor <cursoragent@cursor.com>
Collapse equal pair cells, hide display columns by default, fold field filters, and keep failed sheets first so diffs stand out.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show localized phases with progress bars on the runs tab and result board, and make cancel/status easier to act on during long compares.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show pending check items instead of a fake 100% pass, publish sheet results as each finishes, and use keyset chunk loads with rows-loaded progress.
Co-authored-by: Cursor <cursoragent@cursor.com>
Run compares in the background with progress, persist fails first, and store success as sampled key+row_id hydrated from source so million-row sheets no longer block the API.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose recommended_mode/hints on getManagedNe, support background exec-jobs with getNeExecJob in MCP, and allow linux_shell on MikroTik as well as Linux.
Co-authored-by: Cursor <cursoragent@cursor.com>
Create tasks via pick-NE or import log; re-import appends batches like collects, without inventory NE or SSH.
Co-authored-by: Cursor <cursoragent@cursor.com>
RR vpnv6 wrap lines with next-hop+metrics were collapsing ECMP legs; store raw_line_count/declared_total before DB truncate so collect stats stay accurate.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the horizontal scrollbar in the viewport, sticky enable/title columns, and show selected/total (and unbound) counts.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show collecting over paused schedule, enqueue sync so collect_running flips immediately, and expose export on metric sheets with a card layout for Commands.
Co-authored-by: Cursor <cursoragent@cursor.com>
Decouple heavy CLI parse via ParsePool, keep ECMP/multi-RD keys, and expose per-command CLI lines vs DB rows with raw.txt export.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add dual-lane READ vs RUN_TIMEOUT_CAP notes to .env.example and WEB.md so operators can raise the ~40min heavy cap.
Co-authored-by: Cursor <cursoragent@cursor.com>
Match live collect: include discover-backed aux CLIs in plan/export (and unbound sections); primary-only via include_aux=false.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add an Aux column for each monitor item. Drop ip_route/ipv6_route as summary enrich aux so FIB stays a standalone collect profile. Export defaults to primary commands only.
Co-authored-by: Cursor <cursoragent@cursor.com>
Plan enabled monitoring items into concrete CLIs (with aux) and download as txt from the task detail modal.
Co-authored-by: Cursor <cursoragent@cursor.com>
Skip Dest/Network headers when Total routes is 0; capture direction from match groups; expose workbook compare/data/sheet stats and prefer batch aliases in compare/cutover pickers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Filter peers by AFI (and VRF pairs for CE), support zip/pair bindings in discover UI, and tag FIB rows with address_families.
Co-authored-by: Cursor <cursoragent@cursor.com>