Every function of the stock Capital Device Modeler, how our replacement handles it, and the evidence. Everything marked Same was exercised against live Capital and read back independently. Four actions were also run through both user interfaces and compared request by request.
AngularJS 1.x, minified, no extension point. Kept on the server as capitalwebapp.war.stock; tools\rollback.ps1 restores it.
React + TypeScript, same war name and layout, served at /devices/. Deployed and verified 2026-09-25 (sha256 c19ed858…).
| Function | Stock Device Modeler | Replacement 0.9.5 | Status | Evidence |
|---|---|---|---|---|
| Navigation and shell | ||||
| Getting to a module | Landing page with three tiles (Device Modeler, Component Library, Dictionary); ICD and library browsers open as modal dialogs | One top bar (ICDs, Connectivity, Library, Dictionary); master list on the left, editor on the right | Differs | Same routes: stock hash links such as #/ICD/editICD/{uid} open the same object |
| Deep links | Hash form works; path form /devices/{name}/ICD/editICD/{uid} returns 404 | Hash form works from a cold load; path form redirected to the hash form | Same | AUDIO UNIT:A opened cold. Not tested from the ConnectivityHub plugin |
| Login, permissions | Capital login; buttons follow functional permissions | Same login and session cookie; same permission gates (create/edit/delete/assign/import/export ICD, dictionary edit) | Same | Checked against whoami permission lists |
| ICDs | ||||
| ICD list and text search | Query-driven list in the ICD browser | Full list with search box; power queries below | Same | 13 stock ICDs listed with release level and part number |
| View all fields and sections | Form plus Descendants, Pins, Footprint, Nets, Properties sections | Same fields and sections | Same | AUDIO UNIT:A compared field for field with the stock page |
| New ICD | Green + opens a blank form; uid minted up front | New opens a blank form; uid minted up front | Same | Side-by-side: 41 request fields identical apart from name; stored objects 0 differences |
| Pins and nets entry | Spreadsheet grid; nets typed in a search box inside the Nets cell; "Copy selected" duplicates a pin with its nets | Table; bulk add (1-12 or A,B,C); "+ net" per pin, several nets per pin | Differs | Both store the same pinSignalAssociations; read back on ZZTEST_ICD2 |
| Net attributes and options | Shield, signal group, option expression per net | Same | Same | Shield true, signal group GRP/AUDIO, net option read back |
| Option expression dialog | Project options, operators, validation | Same, with the same project-options lookup | Same | G1..G7 listed, bogus name rejected, G1 || G2 saved |
| Applicability, Projects, Domains | Design and Project tags, domains | Same tag contexts | Same | 2-Audio, Aerospace ELA Power Design saved; no domains exist here |
| User properties (ICD, pin, net) | Editable; rich-text ones read-only | Same | Same | PinColor=Red, NetGauge=22AWG, ZZ Note=hello read back |
| Release levels and locking | Allowed transitions only; Obsolete locks the form | Same transitions and the stock lock reason | Same | A1 Draft to Obsolete (locked) to Draft |
| Assign part, clear part | Pulls type code, footprint, supplier/customer PN and pins from the part | Same, via the library picker | Same | ZZTEST_ICD2_copy + ZZTEST_DEV3: all fields and pins A1/A2 |
| Copy, Revise, Create descendant | Unsaved template, then Create | Same two-step flow | Same | ZZTEST_ICD2_copy:A, :A1, _child:A (parent link read back) |
| Ancestor ICD picker | Candidate parents list | Same list | Same | Picked from 18 candidates; parent read back |
| Delete | Confirm dialog, then delete | Confirm, then delete | Same | Side-by-side: identical DELETE /icds/{uid}, 204, both gone |
| Export, Import, Import Merge | .zip round trip | Same endpoints | Same | 11,913-byte export re-imported; merge updated in place |
| XSD import | Server-defined XML import (?dataType=xsd) | Same call wired up | Untested | No sample file exists here; format undocumented |
| Create component from ICD | Library device from the ICD's pins | Same | Same | ZZTEST_DEV_FROM_ICD2 created and assigned |
| ICD Table Editor | Multi-ICD grid edit | Same | Same | Role changed, pins untouched |
| Harness footprint (pin to cavity) | Connector clones and cavity mapping; duplicate cavity refused | Same rules | Same | J1/J2 clones of C-81334 mapped and read back |
| Backshell signals | Nets on a backshell; footprint locked while one exists | Same, footprint kept intact on save | Same | BS1 on J1 edited and read back with footprint intact |
| Power queries | From site icdqueries.json (absent here: stock shows none) | Site file when present, built-in set otherwise | Same | Applicable 2-Audio 17; role ZZTEST 5 |
| Net filter in the ICD form | Starting-with filter | Wildcards * and ? | Same | Z*1A pin 1 only |
| Component library | ||||
| Latest devices, search | Fixed "Latest Devices" list (25 shown) plus search | Same list; Enter queries Capital and also finds new parts the fixed list omits | Same | 27 latest |
| New, edit, copy, revise device | Pins, properties by type code, footprints and cavity mapping, customer/supplier PNs | Same, with the stock "one preferred supplier" rule | Same | Side-by-side edit: 43 request fields identical apart from the text typed |
| Type code change dialog | Remove / Keep / Revert | Same three choices | Same | Revert kept DEV, nothing dirty |
| Library power queries, select mode | Site queries; picker for ICD assign part | Same | Same | Type code ZZTEST* 8 |
| Sort order of lists | Own natural sort (1N-... before 10-...) | The ported stock sort in the dictionary, ICD list, table editor, cavity pickers and pin grid (rows never move while typing) | Same | Port identical to the stock function on 16,641 name pairs; the stock ICD master list order itself was not observed |
| Dictionary | ||||
| Devices, Logic Designs, Nets grids | Column filters and sort, locked by default | Same, Unlock table to edit | Same | 14 / 5 / 119 entries |
| Add, edit, delete, rename, properties | One Save sends a delta | Same delta format | Same | Side-by-side add: 16 fields identical apart from name (after the 0.9.2 fix) |
| Saved filters, validation | Per-browser saved filters; length and unique-name checks | Same | Same | Filter survived reload; duplicate blocked |
| Dictionary Import / Export | Buttons present, server answers 404 | Not offered | N/A | Network-dictionary actions; broken in stock |
| Signals / Messages | Not in Device Modeler | Not in scope | N/A | Separate Capital Dictionary app |
| Only in the replacement | ||||
| ICD Connectivity view | None: ICDs load one at a time | Every ICD and its nets on one diagram; all / one ICD / one net; zoom and pan | New | 20 ICDs, 34 nets (29 shared) live |
| Straight, pin-facing wiring | n/a | Pins face their partner; 3+ endpoint nets drawn as a bus with tees; no wire crosses a box | New | Live data: 56 to 28 bends, 17 to 0 wires through boxes (0.9.0 to 0.9.5) |
| Drag boxes, saved positions | n/a | Drag any box; wires re-route around it; Re-layout restores; saved views keep the positions | New | Moved box keeps every pin wired, 0 wires through boxes; round trip in logic tests |
| Connectivity checks | n/a | Nets that go nowhere, near-duplicate names, impossible option combinations, non-overlapping effectivities, duplicate or unwired pins, nets not in the dictionary | New | 15 genuine findings on live data; error branches proven on built-to-fail input |
| Compare revisions | n/a | Fields, applicability, pins, nets, options, and other ICDs affected | New | Matches an independent diff of the raw data |
| Grouping and background layout | n/a | Group by applicability, project or role; layout in two workers | New | 300 synthetic ICDs grouped: 10 boxes, 0.4 s, clean |
| Export and saved views | n/a | SVG of the diagram, CSV of the From/To table, named views per browser | New | Exported SVG parses with every box and wire |
| Supplyframe risk badges | n/a | Risk beside supplier part numbers and in the part picker, via a same-origin forwarder | New | Built by a companion session; nothing writes to Capital |
| Connectivity filters | n/a | Applicability, project, effectivity, options at ICD, pin and net level | New | Lesson 1 shows 1 ICD, 2-Audio 17: both match a direct query |
| Build-list filter | n/a | Matches the stock BuildList tag context | Untested | None of the 116 projects has a build list yet |
| From / To table | n/a | Every connection with expandable details under the diagram | New | 48 rows on live data |
| Read-back after every save | Saves and reloads | Re-reads the object and says so ("Saved and read it back") | New | Catches Capital's empty-200 answer for deleted ICDs |
| Self-test and contract check | None | #/selftest: 10 live write checks incl. 2 that must fail; read-only check of every Capital endpoint against a recorded shape snapshot | New | Self-test 10 of 10 (0.9.4); contract 14 of 14 |
| Version marker and rollback | None | Page carries its version; deploy and rollback scripts verify by what the server returns | New | dm-replacement-version 0.9.2 read from /devices/ |
The same four actions done by hand in the unmodified stock app and in ours, with every request recorded by a logging proxy, compared on the request sent and on the object Capital stored. A scripted comparison then replays all 23 recorded stock writes, across 11 operations, through the replacement's own code: all match, with two accepted differences, and a planted change is caught.
2 pins on one net, Design tag, effectivity. 41 fields: only the name differs, plus one extra empty field from ours that Capital accepts. Stored objects identical.
First run exposed a bug in ours: new rows re-sorted while typing, which lost the name and edited the wrong row. Server data restored, fixed in 0.9.2, rerun identical.
Identical request and 204 answer; both ICDs gone by query, with a control query proving an existing ICD is still found.
43 fields: only the text typed and the concurrency timestamp differ. Ours also displayed the stock app's edit correctly before changing it.
| Measure | 0.9.0 | 0.9.5 |
|---|---|---|
| Bends | 56 | 28 |
| Wire segments through a box | 17 | 0 |
| Overlapping wire pairs | 2 | 0 |
| Pins off a west or east edge | 2 | 0 |