Changelog
3.72.3 · 🎨 Change a cable’s type where you expect to. The cable inspector’s Type / tier row is now a dropdown — 🔴 Feeder · 🟡 Distribution · 🟢 Drop · 🟣 P2P — right at the top of Properties. (The ability existed but hid ten rows down under the label “Reclassify” while the Type row read as fixed text — nobody found it.) Picking a tier recolours and re-widths the cable on the map instantly, switches the fibre-count and product catalogues to that tier, and flows through the BoQ/BOM and DRC. · 3.72.2 · 📐 The BoQ is a complete work plan now. It was missing the active equipment: there was no “Install & commission OLT” line at all, and the activation count only looked at home-type markers — a design drawn with ONT markers counted ZERO activations (that’s why a small OLT→ONT design showed nothing but the drop cable). Fixed: the Structures section now leads with OLT commissioning (rack, power, uplink, provisioning) and includes splitter modules and slack coils; Home activation counts home + ONT markers; and MDUs get their own activation line (entry, riser & floor distribution). Reminder: the BoQ prices LABOUR — the equipment supply list is the BOM (File ▸ Export ▸ Export BOM). · 3.72.1 · 🔧 Two field fixes, fast. Cables are genuinely visible now — thicker at every tier (drop 3.2px, distribution 4px, feeder 5px) and, the part that actually matters over satellite imagery, every cable gets a dark halo under its colour so a green drop no longer melts into green rooftops. Edit bend points works like a tool now — choosing it no longer opens the big inspector card over the very handles you are trying to drag; the map stays clear while you edit, and a plain click on the cable brings the inspector back. · 3.72.0 · 🛠 Per-user access to the Operations & Maintenance workspace. The 🎓 Hands-on training section in Users & permissions gained a fourth switch: disable the whole O&M workspace (tickets, work orders, crews, subscribers, outages, assurance, valuation…) for any account — the workspace entry disappears from their menus, opening operations directly bounces them back to Design, and ONE server chokepoint refuses the entire O&M API surface for them (design and collaboration stay untouched). Worth knowing: plain user-role accounts never had O&M access (design-only by role) — this switch is for taking it away from accounts whose ROLE would otherwise grant it (ops managers, technicians, tenant admins). Root is never locked out. · 3.71.0 · 🎓 Hands-on training mode — per-user feature lockout. In Users & permissions, expand any user (▸) and the new 🎓 Hands-on training section lets root DISABLE whole feature groups for that account: ✨ AI assistance (scans, detect-AI, co-pilot), 🔍 Detect tools (map detect + frontage), and 🤖 Auto-design — so a learner practises doing the work by hand instead of pressing the magic buttons. Enforced by the SERVER at each feature’s chokepoint (hiding the buttons is just courtesy — the API refuses too, with an honest “educational mode” message telling them to ask their administrator), and the locked buttons disappear from the learner’s toolbar and menus on their next sign-in. Un-tick to restore instantly; root accounts are never locked out. Also two map-readability fixes from the field: cables keep a fixed on-screen width at every normal zoom (the OLT→ONT path was rendering as an invisible 1.6px hairline on satellite imagery — drop cables are now 2.4px, distribution 3px, feeder 4px, and on town-scale canvas rendering the width no longer shrinks with zoom until you are fully zoomed out), and the cable bend-point handles are now sized in screen pixels — editing angles while zoomed in used to balloon them into giant dashed circles that covered the map; they stay a constant grabbable size at any zoom. · 3.70.0 · 📊 Dataset health + per-labeler drill-down in the campaign pane (root). The 🎯 campaign dashboard now shows the DATA, not just the totals: class mix (🏠 home vs 🏢 MDU with a proportion bar + confirmed-empty background areas), a 14-day activity chart (accepted houses per Baghdad day), and three trust meters — ✅ Review coverage (how much of the uploads root has actually rated), 🤝 Corroborated labels (roofs confirmed by a second labeler’s overlapping work, with the multi-labeler tile count), and ❌ Rejection churn (awaiting-redo vs already-redone, colour-coded — lower is better). Click any labeler’s name (roster or leaderboard) for the full drill-down: every upload they ever made — when, which tile, houses, rejections, redos, star rating — each row with a 🎯 Review button straight into that tile. New root-only endpoint /api/sim/ai/trainer/user/{id}/batches; the progress payload now carries the dataset block. · 3.69.0 · 🎨 Trainer workspace UI/UX overhaul. The tutorial + rules sidebar is now a 🎓 Help drawer — hidden by default, opened from the 🎓 Help button in the header (it slides OVER the workspace, so the photo never resizes mid-trace); it still opens itself on a labeler’s very first visit, and while it’s closed the Help button carries a step badge + a gentle pulse whenever the built-in guidance advances. The toolbar is organized into labelled clusters (draw · edit · view · upload) with separators, square icon buttons, and the one-line tool hint on its own row; the Upload button now fills up like a progress bar toward the 30-house gate and shows “Upload 12 / 30” so it never looks broken, just not-ready. The photo sits framed and centred on a softly-lit backdrop instead of floating in a black void. New “❌ N to redo ▸” chip next to the counter: each click jumps you straight to the next rejected house, centred, ready to redraw. Plus a consistent button system (uniform heights, hover/press states, visible keyboard focus), the daily-goal pill and counter with stable numerals, tool shortcuts spelled out in the dropdowns (P/R/F · H/M), and a navigation line added to the rules. · 3.68.0 · 🎯 Daily goal + review-and-reject for the labeling campaign. Every labeler now has a daily goal of 120 houses (root can change it in the campaign pane): the trainer header shows a live 🏠 today N / 120 progress bar that celebrates when the goal lands. Root reviews every upload on the map — in 🎯 Review, click any house to ❌ reject it back to its uploader (or ↩ restore it); rejected houses turn red-dashed for root and RED with a ✗ redo mark for the employee, who sees a ❌ N-to-redo badge the moment they open the area and simply draws the house again — the redo replaces the rejected one and clears the badge. Rejected houses never count toward totals, the daily goal, or the exported training data. The campaign pane also gained 👥 Who can train — the roster of every account with trainer access (role or 🎯 checkbox) with today’s houses vs goal and all-time totals. Also fixed: the trainer page’s dark-theme contrast (dark-on-dark dropdowns, dim labels, bright scrollbars) and a rare bug where hopping from the mapper to the trainer page showed “Could not reach the EOS server” on a healthy connection (some endpoint-security software blocks the offline-shell worker’s own network calls — pages are now fetched by the browser itself via navigation preload, with the worker stepping in only when truly offline). · 3.67.1 · 🧹 Users & permissions — cleaner + the Trainer role now shows in the ROW dropdown. Fixed: the dedicated Trainer role was in the create-user dropdown but missing from the per-row “change role” dropdown, so you couldn’t convert an existing person to a label-only trainer — it’s there now (shown as “trainer (label only)”, and picking it takes effect immediately: that account then sees ONLY the trainer, no design or operations). Decluttered the table: the cramped 🎯 checkbox + AI-mode columns are gone from the main row — the user list is back to a clean ID · Email · Employee · Role · Tenant · Status · Actions, and all the per-user controls (🎯 also-let-them-train, AI mode, daily token budget, tokens used) now live in an organized, labelled panel when you expand a row (▸). · 3.67.0 · 👥 THE TRAINER ROLE + all trainer/AI controls in Users & permissions. Managing who can label is now where you expect it: Settings ▸ 👥 Users, roles & permissions (your avatar ▸ Users) shows, per user, a 🎯 Trainer checkbox (grant a normal user the Detection trainer alongside their design work), their AI mode (Normal / Partial / Full), and — expand a row — their daily token budget + tokens used. All the per-user AI/token controls that were only in the mapper’s Settings are now here too. NEW dedicated Trainer role for EXTERNAL labelers (your boss’s ask): set a user’s role to Trainer and that account can ONLY label — it lands straight in the Detection-trainer workspace, has NO access to design or operations, and every design/ops/projects/AI endpoint refuses it (enforced server-side at one chokepoint, plus the public API face). The 🎯 checkbox stays for the other direction: a designer or ops user who should ALSO be able to label. Hardened after an adversarial security review: closed a public-API side-door, made the AI endpoints fail-closed, preserved user-id sequence + all per-user settings through the role migration, and applied security headers to every refusal. · 3.66.1 ·🖐 Trainer map PANS properly — pressing and dragging no longer grabs a tile as a ghost image (the browser’s native image-drag was hijacking the gesture; now suppressed at three levels). Also: service-worker updates now bypass the browser’s HTTP cache (updateViaCache none), so new releases reach every laptop faster. · 3.66.0 · ✨ TRAINER PHOTO ENHANCEMENT. Satellite JPEGs are naturally hazy and soft — the labeling photo now ships with a GPU unsharp-mask + contrast enhancement that makes roof edges pop and neighbouring houses separate visibly (the same pre-processing GIS analysts apply before digitizing). The ✨ button in the doodle toolbar cycles Off / ✨ / ✨✨ Strong, remembers each labeler’s choice, and defaults ON. HONEST BY DESIGN: this is display-only — the stored training data keeps the untouched original pixels (the model must learn the imagery as it really is, and the scans it will one day run on are unenhanced), and your marks map identically to both. Physics note stated plainly in the tool: no provider sells Iraq sharper than ~0.25 m/pixel; enhancement improves what your eyes get from those pixels, and the only way to truly beat the ceiling is our own drone imagery later. · 3.65.1 · 🎯 Trainer picker map fixed. Two regressions from the sharpening work in 3.65.0: (1) on a high-DPI / scaled screen the map fetched imagery one zoom level deeper for crispness, but near the imagery’s maximum native zoom those deeper tiles don’t exist — they 404’d and left the map a scatter of small floating squares. The map is back to solid, seamless tiles at the current zoom. (2) After drawing a small area the labeling photo rendered at true pixel size, which for a ~90 m area is only a few hundred pixels — so it looked tiny. The photo now FILLS the workspace (up to 2×; wheel/Ctrl+scroll to go deeper), so any area is big enough to label. · 3.65.0 · 🎯 SHARP IMAGERY + free-shape ONLY. Root cause of "couldn’t fetch satellite imagery": the imagery provider’s export fails whenever a request asks for detail finer than ~0.25 m/pixel — a small drawn shape divided into 1024 pixels crossed that line and got refused (this refines the old "1024-pixel ceiling": it was always a RESOLUTION ceiling). Every fetch is now sized to the sharpest legal resolution for its area — small shapes get small, CRISP photos instead of an error — with 3 retries for real network hiccups and an honest "draw a bigger shape (≥60 m)" guard where physics can’t deliver. Clarity, part two: the picker map now fetches DOUBLE-DENSITY tiles on high-DPI screens (Windows 125/150% scaling was stretching every tile), and the labeling photo displays at true 1:1 pixels instead of being stretched — what you see is every pixel the satellite actually has. And per the owner: the ⬛ quick square is GONE — 📍 Draw my area is the only flow; the mouse wheel scrolls the photo (Ctrl+wheel zooms) — also from 3.64.1. · 3.64.0 · 🎯 FREE-SHAPE AREAS + right-click everywhere. The training area itself is no longer a forced square: 📍 Draw my area lets the labeler click the corners of ANY shape that follows their streets (right-click removes a point, first-point-click finishes, Esc cancels; ⬛ the quick square stays as the fast option). The photo is the shape’s bounding box, everything OUTSIDE the drawn shape is dimmed in the canvas — you label inside your shape only — and the exporter + training recipe mask those outside pixels so they never train as “empty ground”. Free shapes render true-to-form on the picker map. RIGHT-CLICK context menus: an area → Open / 🗑 Delete (a trainer can delete their own area while it carries nobody else’s work; areas with others’ batches are admin-only); a marked house → 🗑 Delete / 🏠⇄🏢 reclassify; mid-outline → remove the last point. Also: the offline shell no longer hard-fails a page that was never cached (the “Failed to fetch” console error — it now shows an honest tap-to-retry screen), and the trainer got its 🎯 tab icon. · 3.63.0 ·🎯 TRAINER: the dead button + manual corner points. Root cause of “the button does nothing”: the picker map takes POINTER CAPTURE on every press to pan — and that capture was swallowing the click on every control sitting on top of it (✏️ Label, ➕➖ zoom, the area borders). The map now ignores presses that start on its controls; every button works. And marking is now fully MANUAL: 📍 corner points is the default tool — click each corner of the roof exactly where YOU want it (houses sit at every angle; nothing snaps, nothing assumes a straight rectangle), then click your first point again — or press Enter or double-click — and the shape closes; Esc cancels a run; clicking inside an existing mark still selects it. ▭ rectangle-drag and ✏️ freehand remain in the tool menu (P / R / F to switch), the toolbar hint updates per tool, and the tutorial’s step 2 now animates the corner-clicking gesture on a ROTATED house — the exact reason points beat rectangles here. · 3.62.0 ·🎯 TRAINER FIXES from the field. ▭ RECTANGLE is now the DEFAULT marking tool — 99% of our houses are rectangles, so you drag from one roof corner to the opposite corner and release; done. ✏️ Freehand loop stays as the second tool for odd shapes (toolbar toggle or R / F keys), and the animated tutorial teaches the rectangle gesture first. The area-picker’s dashed capture square now ALWAYS fits your screen (before, zoomed far in it grew past the viewport and only its edges showed — it looked broken); it shrinks with your zoom, shows its real ground size live, and the ✏️ button states plainly what it will capture. CONFIRMED AREAS SHOW THEIR BORDERS on the picker map: 🟢 green = fully labeled (pick a fresh square next to it), 🟠 amber = yours in progress (click it to CONTINUE exactly where you stopped), dashed grey = someone started there — coverage only, never names. Area borders refresh after every upload and completion. Also fixed: keyboard shortcuts no longer leak into the map screen. · 3.61.0 ·🎯 THE TRAINER IS NOW A WORKSPACE. The Detection trainer moved out of its modal into its OWN full page, entered like Operations: Workspace ▸ 🎯 Detection trainer (visible to accounts with the trainer role + root). The page owns the whole flow: ① a built-in SATELLITE MAP — drag and zoom anywhere, a dashed capture square shows exactly the ~280 m area you’ll label, and the ✏️ button stays locked until you’re close enough; ② the doodle canvas fills the workspace (same engine: close-on-collide loops, drafts, select/✕/M/H, Space-pan, undo/redo 1000, ⬆ Upload, ✅ fully-labeled / 🚫 no-buildings); ③ THE HELP LIVES INSIDE — a permanent left sidebar with the six ANIMATED how-to steps (clickable, and it follows your progress: picking an area advances it to the doodle step, uploading advances it to the finish step) plus the labeling rules, always visible, never a popup. Deep links work (root’s review ▸ “Doodle it myself” opens the page on that exact tile), your last map position is remembered, and drafts made in the old modal carry over untouched. The old in-map modal and the Detect-menu entry are gone. · 3.60.0 ·🎓 THE ANIMATED TRAINER TUTORIAL. Opening the Detection trainer for the first time now walks the labeler through the whole flow in six ANIMATED steps — every step is a live looping animation of the real gesture, not a wall of text: ① zoom to your assigned streets (the view zooms itself), ② doodle a loop around one roof (the line draws itself around a house, closes on its start point and pops the ✓ — exactly the collide-to-capture gesture), ③ the roof-not-the-compound-wall rule shown as a green-✓ right example next to a shaking red-✗ wrong example, ④ fixing mistakes (click-select ring, ✕ delete, the ↩ undo spin), ⑤ the 30-house counter filling to unlock ⬆ Upload and uploaded roofs turning green, ⑥ the ✅ “area fully labeled” stamp (and 🚫 for empty land). Back/Next, clickable step dots, auto-shows once per browser, replayable any time from the 🎓 Tutorial button in the trainer header. · 3.59.1 ·🤐 VENDOR CONFIDENTIALITY. Which AI powers the platform is now nobody’s business but the administrator’s: every user-facing surface — the co-pilot narrator header, report footers, tooltips, menus, the in-app help, the user guide and the release notes — says only “the EOS AI engine”; vendor and model identifiers are stripped from every AI response a non-root account receives (root’s admin views keep them — someone has to manage the keys); and the engine itself is under standing instructions to never disclose or hint at what powers it, even when asked directly. · 3.59.0 ·🛤 THE LONG ROAD + the 524 fix. Auto-Design on city-scale areas no longer dies with a 524: the plan now runs as a background JOB on the server (the gateway ceilings — nginx ~60 s, Cloudflare ~100 s — killed any single request while the planner was still working) and the client polls with the live elapsed banner until it’s done, however many minutes a huge district needs. THE TRAINING CAMPAIGN (built from a 6-perspective design review): the labeling program now leads to OUR OWN detection model — 📈 campaign dashboard (Settings ▸ 🎯: milestone bar in ✅ complete tiles — 100 = throwaway v0 · 300 = usable v1 + pre-annotation · 1000+ = the rented models retire — plus an HONEST deduped house counter and the labeler leaderboard), ⬇ one-click COCO dataset export (consensus-merges several users’ loops on the same roof, drops root-rejected batches, ships confirmed-empty tiles as true negatives), 🚫 “No buildings here” (empty areas teach the model what background looks like), 📖 in-tool labeling rules (roof slab not compound wall, row-house splitting, edge houses), draft AUTOSAVE (closing or crashing never loses doodles), click-a-doodle to select → ✕ delete / M·H reclass, Space-drag pan, honest upload exceptions (finishing a tile or a sparse tile never forces junk loops), duplicate-upload guard (re-labeling your own houses doesn’t inflate anyone’s numbers), per-batch loop-tightness metric in root review (catches courtyard-lassoing), review queues + pagination, training areas capped at 300 m so training imagery matches scan imagery, and a repo training/ folder with the full YOLO recipe (geographic splits, frozen test set, acceptance bar vs the rented models). Hardened: concurrent area requests can’t destroy each other’s tiles, reused tiles can’t be pruned mid-doodle, deleting a batch un-flags its tile, malformed uploads are clean 400s, edge-hugging loops clamp instead of voiding the batch. · 3.58.0 ·🎯 THE DETECTION TRAINER. Teach the rooftop scanner your own districts. It’s a per-user ROLE: root ticks the 🎯 Trainer checkbox on any account (Settings ▸ ✨ AI & tokens) and that user gains Detect ▸ 🎯 Detection trainer. Zoom to a neighbourhood, open the trainer, and the server fetches a satellite tile of exactly that view — then DOODLE: drag a freehand loop around each house, and the moment your line comes back to its start the loop closes itself and the house is captured in its own colour (MDU toggle for apartment blocks; wheel zoom; ↩↪ undo/redo with a 1000-step history). Every upload needs at least 30 houses; after an upload the SAME tile stays and your houses turn into green ✓ COMPLETE marks so you never doodle the same roof twice — several users labeling the same district is welcome (duplicate views are good training signal), but a trainer only ever sees THEIR OWN work. Root reviews every upload — who, when, how many — tile by tile in Settings ▸ 🎯 Detection trainer, rates batches ★, and can doodle too (no 30-minimum). What it honestly does: labels do NOT retrain the model — with “guide scans” on, the best-rated batches ride INSIDE every scan cell’s prompt as worked examples (few-shot, all three providers), the pre-scan token estimate honestly includes the extra cost, and every label accumulates in a clean exportable dataset for a future dedicated detection model. Scan-tile capture (opt-in) also archives what users scan for labeling; unlabeled tiles are pruned after 14 days, labeled tiles are the dataset and are kept. · 3.57.0 ·🧷 EMBED EXTRA BACKDROPS. File ▸ Import ▸ Open still REPLACES (a new file = a new design), but the new 🧷 Embed extra backdrop… APPENDS another image / SVG / CAD file into the CURRENT project — as many as you need, each positionable independently: 📐 Position backdrop now shows a dashed box on EVERY backdrop (click one to make it the active target, drag to move, corners to resize), and 🗂 Manage backdrops… lets you reorder the paint stack or remove one. An embedded file CONFORMS to the project’s existing scale — its ground-width entry sizes it in world metres and never redefines the project’s m/px (only the primary backdrop calibrates). Every AI detector asks WHICH backdrop to read when several are loaded; saves carry all backdrops (old files/clients keep working via the single-backdrop key); moving/resizing/embedding arms the autosave (this also fixes the old “backdrop move never saved” gap); big photos are downscaled on import so multiple embeds don’t bloat the project. ✖ Clear underlay asks which one when several exist. · 3.56.1 ·🔧 SCAN HOTFIX ×3 — (1) “failed to detect homes” root-caused: Esri’s imagery export hard-fails (HTTP 500) above 1024 px, and the v3.52 sharpening asked for 1536 — EVERY cell’s imagery fetch was dying. Cells now fetch at Esri’s 1024 ceiling (still ~0.25 m/px on a 256 m cell — a house is ~40 px, double the original detail), and a failed fetch fails only its own cell instead of the whole scan. (2) The scanner is CLIPPED to the site polygon — the sweep, trail, cell grid and markers can no longer paint outside your zone borders. (3) The scan label + sweep bars are SCREEN-sized at every zoom (the world-scaled banner used to fill the screen when zoomed in). · 3.56.0 ·🛰 THE SCANNER YOU CAN WATCH + 💡 pulsing trace + 🗂 sites. The AI district scan now shows a LIVE CELL GRID over your zone — pending cells faint, the ACTIVE cell bright (the view follows it as it works; move the map yourself and the follow politely stops), finished cells green, failed cells red — and rooftops are placed PROGRESSIVELY as each cell completes and verifies (zone-clipped + deduplicated), with a running “N placed” count instead of one dump at the end; the whole scan is still a single undo step. Drawn ZONES now count in the which-area picker alongside sites, and with exactly one site/zone on the map the scanner locks to it automatically. Site polygons are named “Site N” by default (menus/layers/inspector relabeled from “Project area”). The 💡 light-path trace now PULSES — the halo breathes while the bright core holds steady (animation runs only while a trace is on screen). · 3.55.0 ·👥 DIGITAL TWINS + ONE ICON PER LOCATION + 🗼 the pole ask. The map is de-cluttered: mounted equipment no longer draws its own marker — the FAT lives INSIDE its pole icon and the entrance ATB INSIDE its home icon (the host shows a count badge; clicks, marquee, Ctrl+A, the minimap and hit-testing all target the host; the current selection is never hidden). Double-click a HOME for its digital twin: the buried drop arriving from the street side it really enters, the ATB on the wall, the indoor patch and the ONT — with the ATB model, patch product, ONT model (rx window) and serial all editable in place, the live optical verdict, and one-click trace / open-the-box. Double-click a POLE carrying one FAT and it opens straight into the FAT’s splitter faceplate (breadcrumb back to the pole). Opening an entrance ATB now shows its real light path — drop IN from the FAT → fusion splice → SC/APC adapter → patch OUT to the ONT — instead of the meaningless “add a splitter” MDU shelf. Placing a pole now ASKS what it carries: spanning pole (default — just the structure), FAT + splitter, dome (vertical) or in-line (horizontal) splice closure. Auto poles now stand at the KERB (perpendicular to the street bearing — a fixed-north offset used to park them mid-carriageway), and the last diagonal remnants near intersections are gone (kerb-hug drop rule: off-street segments 17→3 on an 874-home stress city, worst deviation 2.9 m). Also measured and confirmed: cable ROUTING is provably shortest-path (A* = Dijkstra on every cable, FDT siting = brute-force optimum) — a traced light path wanders only because real GPON paths pass through the FDT split point; the median home pays just 18% over the theoretical direct line. · 3.54.0 ·🚪 HOME-ENTRANCE ATBs + 💡 THE LIGHT-PATH TRACE GLOWS ON TOP + 🛣 building entries. Auto-Design now builds the subscriber link the way it is actually installed: the buried G.657 drop runs along the street and terminates at an ACCESS TERMINAL BOX on the home’s street-facing side (~5 m in from the kerb entry), and an INDOOR pre-terminated patch cord covers the last metres to the ONT — one ATB per served home, priced as a patch (no civil), never double-counted in pigtails/OTDR, and the optical budget now honestly charges the ATB joint (+1 connector +1 splice; the BOM always did). Drop-length checks measure the REAL link (FAT→ATB→home), a per-home ATB never trips the small-cluster rule, reach rings and the FAT-fill tile stay clean, and re-running Auto-Design replaces the ATBs with the design. The 💡 trace-light-path overlay was invisible on big designs — it rendered in the SVG while every cable and marker paints on the canvas ABOVE it; the trace is now the canvas’s FINAL pass, a layered neon glow (soft halo, glow body, bright core) that stays constant-width at every zoom and sits above EVERYTHING. Also: any cable that terminates at a building (incl. direct-fed MDU distribution) now enters from the nearest kerb point instead of diving diagonally off the street. · 3.53.1 ·🗼 POLES HUG THEIR FATs + tighter street alignment. The FAT-mount pole is now placed 2.5 REAL METRES from its FAT (a raw-pixel offset used to put it tens of metres away on coarse-anchored maps, so the pole and the FAT looked like two unrelated floating objects). The planning graph now holds a true ~20 m vertex spacing at EVERY map scale (it degraded to ~96 m on coarse anchors, which made drop walks cut corners), and a drop whose kerb-entry point sits away from its walk end now walks the streets to it instead of cutting across. Residual entry slack is bounded to a kerb-corner (~≤35 m); re-run ▶ Auto-Design on an existing project to regenerate the geometry with all of this. · 3.53.0 ·🛣 DROPS FOLLOW THE STREET + ⏱ AUTO-DESIGN 4× FASTER WITH LIVE PROGRESS. Drops no longer radiate as straight “star” lines across the blocks: every drop now runs from the FAT ALONG the street and enters the home from its nearest kerb point with a short perpendicular entry — in both planner branches — and routedOn is honest (straight stars used to be mislabeled as street-routed; measured 26% straight at district zoom, now ~0). Auto-Design on a large area no longer looks frozen: the replace-confirmation is asked UP FRONT, a live banner with an elapsed counter runs during the whole server compute, a busy guard stops double-runs, and gateway timeouts get an honest message. The planner itself is ~4× faster on district-scale maps (the street graph is now subdivided in real metres, ~20 m, instead of a zoom-blind pixel step that exploded the vertex count at fine scales; the FAT-siting greedy also compacts its candidate lists) — a 630-home district that took ~36 s now plans in ~9 s, with identical design output. · 3.52.2 ·📖 DOCS — the User Guide (Help ▸ 📖 User guide) now covers everything in 3.52: the one-button Detect, the build-ready Auto-Design (pole-mounted FATs, sized chassis, readiness gate), per-cassette PON counting, the inside-view error/Retry behaviour and the protection flow; the in-app quick-start and tips were refreshed to match. · 3.52.1 ·⚡ PROTECTION PLANNER 30× FASTER — planning Type A/B/C backups on a 40+-feeder district used to rebuild its shared-risk map from scratch for every feeder (quadratic work) and could outlive the server gateway window, surfacing as “Protection planner unavailable (502)”. The risk map now grows incrementally and street A* memoises its edge checks — the same district plans in seconds with identical diverse-route results. · 3.52.0 ·🧰 THE OLT OVERHAUL + one-press COMPLETE Auto-Design + the Detect rework. Auto-Design now ends BUILD-READY: it sizes the OLT chassis to the plan’s PON count, mounts every FAT on its own pole with the splitter cassette inside, buries the drops, places access hand-holes every 450 m, auto-applies every safe DRC fix and announces the Build-readiness verdict plus the bandwidth headline (Mbps/home · PON ports · line cards · oversubscription). The inside view, the capacity engine and the DRC finally agree: PON ports are counted per splitter CASSETTE everywhere (no more 6-shown-vs-44-needed), the port-overflow violation gained a one-click chassis upsize, and Auto-distribute says exactly what it did — including when the chassis is full. Optical budgets grade in ONE batched request with honest retry/error states (the eternal Calculating… is gone); the device inside-view explains failures and offers Retry instead of a blanket unavailable; the Model dropdown no longer vanishes mid-pick; the per-OLT PON-type switch actually re-grades, re-prices and persists; the protection-plan chooser is readable. Detect became ONE button that asks what you want (homes · roads · both) scoped to your site, pulls real OSM roads on satellite views, scans rooftops ~3× sharper clipped to your zone outline, and Undo now removes auto-design trenches and streets too. · 3.51.1 ·🔧 Robustness — bumped the offline service-worker cache so any shell stored during the earlier broken-boot window is purged (a stale copy could otherwise be served on a flaky connection), and lightened the new loading-screen animation (dropped the per-frame blur) so it can never stall the boot on low-end field devices. · 3.51.0 · 🎬 NEW LOADING SCREEN — rebranded from "FTTH Mapper" to EOS, with the Daw Alfada logo and an animated optical-fibre effect: light pulses stream along fibre strands and converge on the logo (a nod to what the platform designs). Respects reduced-motion, and the animation stops the moment the app takes over. · 3.50.1 · 🔧 HOTFIX — a stray, un-escaped tag name in the 3.50.0 changelog text below opened a stray element that swallowed the whole app script, so the page stuck on the loading splash. Escaped it; the app loads normally again. (Lesson banked: a doc/changelog edit needs a real in-browser boot check, not just a JS-syntax check.) · 3.50.0 · 🔒 SECURITY HARDENING (pre-pentest) + 🛰 AI FIND ROADS & HOMES (beta). SECURITY — six findings from a full XHR/XSS/CSRF audit closed and each proven by test: (1) imported SVG underlays are now run through a real sanitiser (script / foreignObject / on* / javascript: hrefs / external refs stripped; a poisoned .svg can no longer run in a collaborator's session); (2) the context menu is rebuilt with textContent, so element titles / captions can't inject HTML; (3) map-detect bboxes are validated to four in-range numbers before the server's OpenStreetMap query (query-injection + planet-scale abuse blocked, tiles capped); (4) a Content-Security-Policy is now emitted for the app pages in Report-Only mode (watches for injection without breaking anything; violations logged to /api/sim/csp-report) — enforced next once clean; (5) cross-site state-changing requests are refused by an Origin wall (defence-in-depth CSRF; partner API + server-to-server unaffected); (6) the AI API key moved out of the request URL into a header. Then an ADVERSARIAL self-review attacked each fix and hardened them further — the SVG <style> element is stripped (not just the attribute), map-detect tiles are span-capped (no planet-scale extract), the CSP-report log is control-char sanitised (no log forging), and BoQ / business-case CSV exports neutralise spreadsheet-formula injection. Backend test-suite + dedicated security tests + browser XSS proofs all green. 🛰 AI FIND ROADS & HOMES (BETA) — Detect ▸ new advanced option: REAL AI (your configured provider) reads the imported drawing / satellite and detects BOTH the road network AND the houses in one command. Costlier (two AI passes) but far more accurate than deriving streets from the homes when the normal Find-roads misses; it never silently falls back — if AI is off it tells you. Results are estimates — verify before design. · 3.49.0 · 🤖 AUTOMATED CAD UNDERSTANDING (any project, no tuning) — importing a real design now UNDERSTANDS it, self-calibrated from the data, across all project types. (1) UNITS SELF-CALIBRATE: the DXF's declared units are sanity-checked against home spacing (or site span) and overridden when the header lies (a metre-drawn file declaring mm) — distances and costs come out real-world automatically. (2) HOMES SEAT ON THEIR PLOTS: the drawing's real linework is segmented into plots vs the street void (plot sizes learned from the drawing itself; asset SYMBOLS — villa icons, manholes, CCTV, trees — are treated as markers, not walls), and every imported home moves to the centre of its own plot; doubles/misses are flagged, never guessed. (3) ROADS FROM THE REAL STREET VOID: street centrelines are carved from the actual corridors (roads can't cross a plot by construction) and fragments are stitched with A*-routed connectors through the void — never straight bridges. (4) MEASURED, NOT CLAIMED: on the 707-villa reference, homes seat 96% (7 m median correction), the road network is ONE connected graph (9.4 km, 100% in free space, 95% of homes within 45 m), and Auto-Design routes 48 of 49 trunk cables along the streets with 47 textbook FATs — all asserted by a regression suite spanning real + synthetic projects (mm-units, rotated, MDU-wide, open-fronted plots). · 3.48.0 · 🧹 UI SWEEP — right-click fixed · 🗂 GROUPS · Edit menu · two-verb toolbar. (1) RIGHT-CLICK = MENU ONLY: right-clicking an item opened the Inspector behind the context menu (stacked panels); it now opens only the menu and never changes the selection — the Inspector opens on left-click. Copy in the menu is target-aware: it copies the item under the cursor, or the whole multi-selection when that item is part of it. (2) 🗂 GROUPS: multi-select items (or right-click one) ▸ Group ▸ — create a new group or add to one you already made; grouped items behave as ONE (click any member → the whole group selects, so they move / copy / delete together; right-click ▸ Remove from group to take one out; grouping is undoable and saves with the design). (3) EDIT MENU grew Copy (Ctrl+C) · Paste (Ctrl+V) · Delete (Del) · Select all (new: Ctrl+A). (4) The ▷ Select tool now shows a normal ARROW cursor (the ✋ Pan tool keeps the hand). (5) TOOLBAR CONSOLIDATED TO TWO VERBS — no more auto-auto / detect-detect sprawl: 🔍 Detect ▾ (from the live map · AI detect on your drawing / satellite · 🛣 Find roads · Detection settings…) and ▶ Auto-Design ▾ (Run · Design from a brief (AI) · Auto-splice · Auto-label · Options…); 🎬 Demos moved into Help ▸ Demo towns. Every old entry point still works — the menubar keeps the full text menus. · 3.47.1 · 🛣 FIND-ROADS QUALITY — the derived street network is now engineering-grade. The first cut under-densified and dropped disconnected areas, so Auto-Design clustered the FATs and ran long cables (expensive). Now the derivation matches the drawing's real corridor density, keeps EVERY corridor region (not just the biggest), and bridges the pieces into one connected site-wide network. On the 707-villa import that took Auto-Design from a fragmented plan to a “Street-routed plan — feeder & distribution follow the streets”: 47 FAT terminals (a textbook ~15 homes each, down from 300+), all DRC checks green, and a realistic costing (civil ≈ half of CAPEX, as real FTTH is). One click: Design ▸ 🛣 Find roads → ▶ Auto-Design. · 3.47.0 · 🛣 FIND THE ROADS (AI reads the drawing · or derive from the homes) — a block-only CAD or a bare set of detected homes has no road layer, so Auto-Design could only route straight-line. Design ▸ 🛣 Find roads now gives it a street network two ways. (1) THE AI READS YOUR DRAWING: when you've imported a photo / plan / CAD backdrop and AI is on, the vision model traces the road CENTRELINES — the corridors between the building rows — and lays them down as streets (server-side, your configured provider; POST /api/sim/ai/detect_roads). (2) DERIVE FROM THE HOMES: with no drawing, or if the AI is off / finds none, the streets are derived geometrically from the free space between the homes — the medial axis of the corridors — with NO AI. Either way you get an editable street network, and Auto-Design routes ALONG it instead of crow-flies (the status shows “Streets loaded → Mixed routing”). First version: it produces a connected network and gets Auto-Design onto the roads; site-wide connectivity and routing-cost tuning continue. This is the piece that turns “detect the villas” into “understand the drawing”. · 3.46.0 · 🖊 SEE THE WHOLE DRAWING (blocks expanded, like AutoCAD) — importing a DXF used to show only loose lines, so a design where the villas / manholes / site plan are drawn INSIDE blocks (nearly all of them) came in almost blank. The importer now expands every block — it reads the BLOCKS section and stamps each block's artwork (the villa outline, the manhole symbol, the site plan, roads) at its insertion point with the right rotation and scale, exactly as AutoCAD renders it — then rasterises the whole thing (a 700-villa export is ~90,000 line segments, far too many for the browser's SVG, so it's drawn to a crisp image). Two more fixes that came with it: (1) the drawing is framed to its real content — a stray title-block or legend parked far off in the coordinate space no longer shrinks the design to a dot; (2) network elements are now placed at each block's drawn position (a block's artwork often isn't at its insertion point — this file's villa symbol sits ~13k units away), so the imported homes / manholes / splitters land on the drawing, not offset from it. Result: open a real CAD design and you see it like AutoCAD, with the elements sitting on it, ready for Auto-Design. · 3.45.0 · 🧩 READ THE CAD BLOCKS — import a real design, elements and all. Professional FTTH/utility CAD (AutoCAD DWG/DXF) places every asset — a villa, a manhole, a splitter, a pole — as a block on a named layer. The importer only read raw geometry (lines/polylines) and so missed ALL of them; a 700-villa design imported as a blank backdrop. Now the DXF importer also reads INSERT block references: on import it lists every block group (layer · block · count), auto-maps each to a network element by name (UFDK_NODE_Villa → 🏠 Home, "manhol" → ⛓ Manhole, Splitter → 🔀, CCTV → skipped…), and — on your confirm — drops them at their exact positions as real, editable elements, ready for Auto-Design. You can re-map or Skip any group. The backdrop now frames the whole drawing (geometry + blocks) and the scale is set from the drawing units so distances/costs are real. DWG works too (the server converts it to DXF first). Verified on a live 708-villa / 109-manhole / 4-splitter export (820 elements placed, CCTV correctly excluded). · 3.44.0 · 🧭 PLACEMENT · CABLES · TABBED INSPECTOR · DESIGN MODE — a UX pass on the core editing loop, four fixes. (1) KEEP-PLACING: picking an element from the palette now STAYS armed — click the map to drop one, click again for another (no more re-picking Home for every house), and placing no longer pops the Inspector open. Edit an item later by selecting it or right-clicking it; Esc or the ▷ Select tool stops placing. (2) ONE DRAW = ONE CABLE: drawing a cable between two nodes created two or three duplicate cables (and stacked port-pickers) because the single mouse release ran the finalise twice — it now creates exactly one cable, one port-pick per end. (3) TABBED INSPECTOR: an element's Inspector is now organised into three tabs — Properties (what you set), Actions (what you do — connect, open device, delete…) and Information (what the app computes — optical, connectivity, status) — instead of one long scroll. Right-clicking an item now also selects it, so its Inspector is one click away. (4) 🖥 DESIGN MODE (View ▸ Design mode): the side panels collapse to give the map maximum room and selecting any element opens a fixed right-side Inspector rail (same three tabs) instead of a floating popover — a focused drafting view. · 3.43.0 · 🖱 SELECT-DRAG · COPY · PASTE (any items, smart labels) — the Select tool now does what you'd expect. (1) MARQUEE SELECT: with the ▷ Select tool, just CLICK AND DRAG a box on empty ground to select every item inside it — homes, MDUs, FATs, poles, closures, cabinets, ANYTHING, not only homes (Shift+drag adds to the current selection). Pan the map with the ✋ Pan tool, middle-mouse or Space+drag. (2) COPY & PASTE on the right-click menu (and Ctrl+C / Ctrl+V): copy the whole selection — the nodes AND the cables that run between them — then right-click ▸ 📥 Paste here to drop the cluster wherever you clicked (Ctrl+V pastes under the cursor). Any single item copies too (right-click a cable / area ▸ Copy). (3) SMART LABELS — no duplicate names, EVER: a paste CONTINUES the numbering per name-prefix, so pasting "Home 5" when Home 1–10 exist gives Home 11, Home 12…; it always takes the next free number even if there are gaps (delete Home 2, paste → Home 4, never a reused 2). FAT-1 → FAT-2, POLE-3 → POLE-4, and so on for every type. Pasted cables re-point to the pasted copies (never the originals). Everything's one undo. · 3.42.0 · ✨ POLISH PASS — closing the edges. (1) CAD reader now understands more geometry: besides LINE and LWPOLYLINE it reads CIRCLE, ARC and old-style POLYLINE/VERTEX (tessellated) — so building footprints drawn as circles/arcs/curved polylines now show up for AI detection and can be picked as streets. (2) 📐 Position backdrop now RECALIBRATES THE SCALE as you resize: if the backdrop is your scale reference (no live basemap), resizing it re-derives metres-per-pixel from the real ground size you set, so distances stay correct while you line it up. (3) Added a "Sentinel-2 recent (Sentinel Hub)" basemap option — paste a free Sentinel Hub OGC instance ID in Settings ▸ Basemap for dated/recent Sentinel-2 imagery (the keyless EOX cloudless mosaic remains the free default). (4) The ✨ AI ▸ Detect item now says it reads your imported photo / plan / CAD, not only satellite. · 3.41.0 · 🖼📐🛰 CAD DETECTION FOR ALL FORMATS · POSITION THE BACKDROP · SENTINEL IMAGERY — four things. (1) AI DETECTION NOW WORKS ON CAD DRAWINGS TOO: importing a DXF (or DWG once converted) loads the whole drawing as a visible backdrop AND the CAD import dialog now offers "🤖 Detect buildings (AI)" — the AI reads the rendered drawing and proposes the houses, exactly like it does for a photo. So detection is compatible with all uploads: image, SVG, DXF, DWG. (2) SELECT ALL / DESELECT ALL on the CAD layer picker (with a live "N / M selected" count) so picking road layers on a big drawing is one click. (3) 📐 POSITION BACKDROP (View menu): drag your imported picture / CAD backdrop to MOVE it and drag a corner to RESIZE it (Shift keeps the aspect) so you can line it up precisely with the live basemap — press Esc or the menu item again to finish. (4) 🛰 SENTINEL-2 free satellite imagery (ESA / EOX cloudless) added as a basemap provider — pick it in Settings ▸ Basemap & providers ▸ Provider (or the on-map basemap switcher); no API key, free, CC-BY. · 3.40.0 · 🤖🖼 AI DETECTS HOUSES FROM YOUR OWN IMAGE / DRAWING (no OSM or satellite needed) — the AI no longer waits for OpenStreetMap. When you import a backdrop — a photo of a site, a scanned site plan, or an SVG/CAD drawing — ✨ Advanced detect now reads THAT image with the vision model and proposes where the houses are, dropping them onto the exact spot the image sits on the canvas. It runs on any picture (aerial photo → rooftops; a plan/drawing → building footprints), reports the model's total-buildings estimate, and meters against your daily token budget like every AI call. And it's OFFERED automatically right after you import an image/drawing (a one-click "Detect the houses now?" — Partial/Full AI accounts; Normal stays quiet). ✨ Advanced detect now routes by context: an uploaded backdrop → reads that image; otherwise → the satellite district scan. Also: DWG import now has a real server converter path (LibreDWG dwg2dxf) — when the drawing can't be converted it points you at the two things that always work (Save As DXF, or import a screenshot and Advanced-detect it). Server: sim/ai_detect.detect_image + POST /api/sim/ai/detect_image; POST /api/sim/cad/dwg2dxf. +2 tests. · 3.39.0 · 📐 EXPORT TO AUTOCAD (DXF/CAD) — File ▸ Export ▸ Export AutoCAD (DXF/CAD)… writes the whole design as a real CAD drawing, not a screenshot. Every element lands on a standards-named LAYER (FTTH-FEEDER / DISTRIBUTION / DROP / P2P for cables · EQUIPMENT · STRUCTURE · PREMISES · DUCT · TRENCH · AREA · ZONE · LABELS) so you can freeze what you don't need; cables/trenches/ducts are polylines, project areas/ROW zones are closed polylines, equipment/structures/premises are circles with text labels. It exports in real GROUND METRES with north up (georeferenced designs are placed relative to the site's SW corner; a non-georeferenced design uses its own metre scale) — a surveyor-ready plan. DXF R12 is the universal CAD interchange format: it opens natively in AutoCAD, BricsCAD, ZWCAD, Civil3D and QGIS, where you can Save As .dwg if you need the binary format. Validated with ezdxf (spec-clean AC1009). · 3.38.1 · ✂🔌 CUT NOW WIRES BOTH HALVES — after you choose what sits at the cut, the digital-twin port picker opens for EACH half: "① Incoming cable · from {source}" asks which port the arriving half lands on inside the new element, then "② Outgoing cable · to {destination}" asks which port the departing half leaves from — with the source/destination named so you always know which cable you're wiring, in-use ports greyed (the second pick can't double-book the first), Esc/Skip keeps the cut and lets you assign ports later from the cable's Properties. Elements without a faceplate (pole, hand-hole) skip the pickers. The outer ends keep their original ports. · 3.38.0 · 🗺 SHARED MAP KEYS + ✂ CUT-JOINT CHOOSER — (1) The Google / Bing-Azure / HERE basemap keys are now PLATFORM-WIDE: keys saved by root apply to every user (noor, hayder, everyone — no more "no API key" on other accounts); other users' own keys act as a personal override. Root's existing keys publish to the platform automatically on next open. (2) Cutting a cable no longer forces a splice closure: the ✂ cut now asks WHAT sits at the cut — splice closure (default) · FAT · FDT cabinet · ATB · pedestal · pole · hand-hole — remembers your last choice, and the chosen element becomes the joint with its own splice/port rules. · 3.37.0 · 🛰 TILED AI SCAN — Advanced detect now actually enumerates a district. The old scan sent ONE photo of the whole area to the AI: at district scale that's 2-4 m/pixel, a house is a couple of pixels, and the model could only return a sparse, evenly-spread sample capped at 450 points — the "fake-looking" uniform scatter, ~1-10% of reality. The scan now SPLITS the area into ~512 m cells, fetches each cell's imagery at ~0.5 m/pixel (a house is 16×16 px), runs the vision model per cell (3 in parallel) and merges the detections with cross-cell dedup. Because a district is real money and minutes of wall clock: you get a COST ESTIMATE + confirmation before it starts (cells · km² · token range), the scan runs as a background job with LIVE PROGRESS on the scan banner (cell 7/24 · tokens so far), every cell is metered against your daily budget (budget exhausted = partial results kept, clearly flagged), a scan survives your browser closing (poll resumes), and each cell reports the model's own estimate of TOTAL rooftops so under-enumeration in hyper-dense blocks is called out honestly instead of silently — with a pointer to 🔍 Detect's street-frontage estimator for bulk fill. Capped at 64 cells per run (the confirm says when your area is bigger). Server: sim/ai_detect.py, POST /api/sim/ai/detect_scan (+estimate_only) + GET /api/sim/ai/detect_scan/{job}; job state lives in the DB so any backend worker answers the poll. +6 tests (417 total). · 3.36.0 · 🛡 KEY DURABILITY — every remaining way a stored key could be lost is closed. (1) OVERWRITE-RACE GUARD (server): a browser that pushes its settings before it has learned the account's roamed map keys can no longer erase them — a payload that OMITS the mapKeys field keeps what's stored (an explicit value, even empty, still replaces, so deliberate deletions stick). (2) SEALING DECOUPLED (server): the AI provider keys are now encrypted under a dedicated secret instead of the internal service token — rotating that token in the future can no longer silently corrupt every stored AI key (existing keys were re-sealed in place and verified). (3) DAILY BACKUPS: the key/user store (database + roamed settings) is now backed up nightly with 14-day retention, so even accidental server-side deletion is recoverable. +4 tests (411 total). · 3.35.2 · 🗺 MAP-KEY LOOKUP IS NOW MERGE-SAFE — the account-roamed map keys now MERGE over the browser's legacy local store instead of replacing it, so an account that hasn't adopted a key yet can never hide one that this browser still holds; opening EOS on any machine that has the old key automatically adopts it account-wide. · 3.35.1 · 👁 EYE ON AN EMPTY FIELD NOW EXPLAINS — clicking the show-key eye on an empty field used to do nothing (confusing when a key is saved: AI provider keys are WRITE-ONLY — the server never returns them, exactly like professional key consoles; the masked hint such as sk-…-000 next to the label is the proof one is stored). The eye now says this in a toast instead of staying silent; map-key fields explain that no key is stored here yet. · 3.35.0 · 🔑 KEYS THAT DON'T "DISAPPEAR" — two fixes from a real incident. (1) AI KEYS & THE GLOBAL SCOPE: an AI key saved under a tenant scope left the 🌐 Global scope empty — and ROOT accounts (which are tenant-less) resolve against Global, so root saw "no key configured" while the key sat safely one dropdown entry away, and reopening Settings (which lands on Global) showed "not set". The AI & tokens pane now shows a LIVE GLOBAL STATUS line (configured ✓ / ⚠ empty — with exactly who resolves against it), and saving keys under a tenant scope while Global is empty now OFFERS to save them as the Global default in the same click. (2) MAP KEYS NOW FOLLOW YOUR ACCOUNT: the Google / Bing-Azure / HERE basemap keys used to live only in the browser's local storage — switch browser or PC and they "vanished". They now ride your per-account roaming settings (like the rest of Application settings): sign in anywhere and your map keys are there. Existing browser-stored keys migrate to the account automatically on next sign-in; keys are still never written into a design file. The Settings modal also re-stamps the key fields whenever roamed values arrive. · 3.34.1 · 👁 SHOW-KEY TOGGLES EVERYWHERE — every API-key / secret field now has a modern eye toggle to reveal what you typed: the three map-provider keys in Settings ▸ Basemap & providers (Google · Bing/Azure · HERE), matching the eyes already on the AI provider keys in Settings ▸ AI & tokens, and the Change-password dialog's three fields (which reopen masked every time). Same line-icon style across the platform. · 3.34.0 · 🧹 MENUBAR DE-DUPLICATION — a full sweep of all 10 menus (78 items traced to their handlers) removed every non-useful duplicate. (1) THE TOOLS MENU IS GONE: all five of its items were doors into the one Settings modal — "Settings…" duplicated Edit ▸ Settings…, and the four pane deep-links (Basemap · Object detection · Display · Localization) added nothing the modal's own section nav + search doesn't do. ⚙️ Settings… now lives in exactly ONE place: the Edit menu (application scope; Project ▸ Project properties… remains the project-scope opener). (2) Removed two dead handler branches for menu items deleted long ago (Reports ▸ Export BOM / Export GeoJSON leftovers) and corrected the Reports-window footer that still pointed at one of them. (3) Closed a kill-switch bypass: disabling MDU buildings or area-scatter for a tenant now also removes their Insert-menu twins (previously only the palette buttons were pruned, so the menu still placed them); likewise Design ▸ Auto-Design and Design ▸ Design from a brief now disappear with their feature flags instead of becoming silent no-ops. (4) The user guide's five stale menu paths (Project ▸ Cloud → File ▸ Cloud & construction; Analyze ▸ Business case → the Reports window's 💰 tab) were corrected. Kept by design: the Insert menu mirrors the palette, and Design/Edit items that jump to always-visible toolbar controls — those are shortcuts, not duplicates. · 3.33.1 · ⚙️ Settings… now ALSO in the Edit menu — the settings entry point previously lived only under Tools ▸ Settings…, which made it easy to miss (and our own docs pointed at Edit). Both menu items open the same one Settings modal. · 3.33.0 · ⚙️ ONE SETTINGS MODAL — every setting now lives in Edit ▸ Settings… (or Project ▸ Project properties…), organised by section, instead of being scattered across pages and popovers. (1) ✨ AI & TOKENS moved INTO the settings modal as its own root-only section (its nav entry appears only for root): the per-tenant provider & API keys (Global default + each tenant, sealed server-side, masked hints, clear), the preferred provider, and the per-user table — AI mode (Normal/Partial/Full with the burn-tokens confirm), daily token budget, tokens spent and the expandable when-timeline. The old Administration-page section is gone (a pointer remains). (2) ⚙ AUTO-DESIGN OPTIONS (duct the feeders · duct road crossings · best-quality layout) now ALSO live in Project properties ▸ Engineering defaults — the toolbar ⚙ popover remains as a pre-run shortcut and the two stay in sync. (3) 🌙 DARK THEME is now a proper setting under Application ▸ Display & workspace (the View-menu toggle remains a shortcut). Settings rows changed outside the modal (the ⚙ popover, the theme toggle, the on-map basemap switcher) now re-sync every time the modal opens. · 3.32.0 · 🤖 FULL-AI EXPERIENCE (the AI co-pilot) — the third AI mode is now live. When an admin sets a user to FULL AI, opening the mapper shows a one-time burn-tokens confirmation ("Full AI is on — the co-pilot narrates your major actions and each narration spends tokens"); on Understood it arms an always-on 🤖 AI Co-pilot dock (bottom-right) that AUTOMATICALLY narrates and advises after the big actions — every Auto-Design and every report you open — through your tenant's configured provider (the configured AI engine), plus a Narrate now button to critique the current design any time. Each narration is metered and the dock shows your tokens-used vs budget. The design, DRC and cost engines stay authoritative — the co-pilot explains and advises, it doesn't overrule them. Normal / Partial accounts are unaffected (no co-pilot). This completes the three AI modes: Normal (no external AI) · Partial (AI buttons where offered) · Full (the co-pilot). · 3.31.0 · ✨ ADVANCED DETECT (real-AI, on the toolbar) — the real-AI home detection is now a first-class toolbar button next to 🔍 Detect, not just buried in the ✨ AI menu. 🔍 Detect reads the OpenStreetMap vectors (free, offline-style); ✨ Advanced detect reads the SATELLITE IMAGERY with your configured AI provider (the configured AI engine — whichever the admin set for your tenant) to find rooftops and count homes where OSM is empty, and it costs AI tokens (shown in the ✨ AI menu's usage strip). A Normal-mode account is told AI is off; a Partial/Full account runs it against the tenant's provider. The AI-powered budget/optimize narration already lives in the ✨ AI menu (Explain the feasibility · Design from a brief), which now also route through your configured provider. · 3.30.0 · 🧠 REAL MULTI-PROVIDER AI (multi-engine) — the ✨ AI is no longer the AI engine-only or unmetered. A new server-side gateway routes every AI call through the provider YOU configure, with real token accounting and per-user access control. (1) PROVIDER SETTINGS (Administration ▸ AI providers & tokens, root only) — set a preferred provider and its API key for the Global default AND per-tenant (each tenant can run its own provider / key), stored sealed on the server and never returned to the browser (only a masked hint). A tenant with no key falls back to the Global default. (2) THREE AI MODES per user — Normal (no external AI — only the built-in detectors/solvers), Partial (AI buttons where offered — the default), or Full (AI everywhere; carries a burn-tokens warning). Set each user's mode + a daily TOKEN BUDGET in the same panel. (3) TOKEN VISIBILITY — the user sees their own mode + today's tokens-used vs budget right in the ✨ AI menu; root sees a per-user roll-up (tokens in/out, calls, last-used) and can expand any user for the full timeline (WHEN each call happened, which provider/model, which action). (4) ENFORCEMENT — every AI endpoint now resolves the caller's tenant provider, refuses external AI in Normal mode, returns 429 when the daily token budget is spent, and records the exact token spend of each call. The deterministic engines (optical budget, DRC, cost) remain the authority — AI narrates and advises. Server-side (sim/ai_providers.py gateway + the ai_config / token-ledger / ai-mode layer in auth.py; +14 tests). · 3.29.0 · 🗂 AI CLASSIFY A MESSY IMPORT — the second ✨ AI placeholder is now live. Import a GeoJSON whose feature types don't match ours (cabinet, vault, nap, dwelling, utility_pole…) and the AI reads the distinct unrecognised labels and maps each to our element vocabulary (FDT / FDH / FAT / closure / pole / manhole / home / MDU…), then the normal importer places the plant on the right types. Labels it can't confidently place are skipped, and everything is validated against our allowed types before anything is created (the server-side AI; the mapping just teaches the importer's alias table). · 3.28.0 · 🛰 AI ROOFTOP SCANNER — the ✨ AI ▸ "Detect homes from imagery" tool is now live, with a real scanning experience. Because a wide OSM view is too small to see individual roofs, when you run it the map now ZOOMS IN and switches the basemap to SATELLITE so the rooftops are visible, then a cyan scan line sweeps across the area and LIGHTS UP each detected rooftop as it passes (green boxes for houses, purple for MDUs) before dropping the estimated homes. Run it from the ✨ AI menu (scans the current view) or by right-clicking a project area. Server-side AI vision reads the high-res satellite tiles; results are ESTIMATES to survey before construction. · 3.27.0 · 🔧 OLT PORT PICK NOW MATCHES THE DEVICE GUI — fixed the confusing mismatch where picking an OLT PON at draw time didn't line up with the OLT's inside view. (1) The picker now shows the OLT's REAL chassis: service slots numbered as they are in the device GUI (Slot 3, Slot 4… — after the control / standby / uplink slots), each a 16-port card, instead of a made-up "Slot 1 · PON 1-32" grid. (2) The device engine now HONORS your pick: a cable pinned to (say) Slot 3 / Port 12 seats that PON on Port 12 in the OLT inside view, not positionally on Port 1 — it walks each active PON back to its OLT-feeder cable, and if you picked a port it adds a card there if needed and lights the exact port you chose. Cables left on "auto" still seat positionally. · 3.26.0 · ✏️ SMOOTHER CABLE EDITING — three fixes to how a cable behaves when you click and shape it. (1) NO MORE POPUP ON EVERY CLICK — selecting a cable no longer auto-opens the "buried or aerial?" chooser; it was interrupting everything (and blocking bend editing). Set placement when YOU want it, from the cable's Properties ▸ Placement ▸ Change… (2) BEND A CABLE BY DRAGGING — a selected cable now shows a dashed ○ midpoint handle on each segment: drag it to add a corner and shape the route (drag a solid ● corner to move it, Alt-click to remove one). A straight run finally has a grab point, so pivot editing is discoverable. (3) The placement chooser is left-aligned and reachable again — its Change… button had an id-matching bug that stopped it opening. · 3.25.0 · 👥 DELETE A USER + TRANSFER THEIR WORK (root / admin) — an account can now be removed. Administration ▸ Users ▸ Delete opens a modal that first asks WHO INHERITS the person's work: every project they own is transferred to the chosen colleague and stamped with a "Transferred from {name}" note (plus an audit event), their collaborator shares are dropped, then the account and its live sessions are deleted. Root may hand the work to anyone; a tenant admin keeps it inside the tenant. The last active root can't be deleted, and you can't delete yourself. Server-side (DELETE /api/auth/users/{id}). · 3.24.0 · 🖥 DRAW-TIME PORT PICKER + CUT TOOL (Wave 2 of the connectivity program) — the click-to-pick-port flow. (1) DRAW A CABLE, PICK ITS PORTS ON THE MAP — with Draw Route, clicking the source element opens its digital-twin FACEPLATE (an OLT's chassis slots + PON LED grid; a splitter / FDT / FDH cassette's IN + OUT ports; an ODF's tray positions; a FAT / pedestal / ATB's drop ports); pick the exact port, run the cable, and the destination prompts its port the same way. Single-drop ends (ONT / home) need no prompt. The cable stores both ports. (2) NO DOUBLE-BOOKING — a port already used by another cable shows GREYED on the faceplate and can't be picked, so two feeders can't land on one PON. (3) ✂ CUT TOOL — a new Cut Cable tool (and a right-click ▸ Cut cable here) splits a cable at the exact point you click, dropping a junction; both halves keep the cable's product / civil / duct and the joint becomes a splice whose loss flows into the budget. Place any element at the cut — pole, hand-hole, closure — and reconnect each cut end to its port. Next: reconnect-drag onto placed elements, snap-to-trench, and the dangling-fibre DRC. · 3.23.0 · 🔌 PORT-AWARE CABLING + EDITING FOUNDATION (Wave 1 of the connectivity program) — the groundwork for running cables to specific PORTS, not just elements, plus long-overdue editing fixes. (1) EVERY CABLE CAN CARRY A PORT ON EACH END — select a cable and its Properties panel offers a From-port / To-port picker built from the destination element's real ports: an OLT PON (slot/port), a splitter or cassette input/output, an ODF tray position, or a drop port; the choice persists with the design and rides the as-built. (2) EDIT A CABLE'S BENDS FROM THE RIGHT-CLICK MENU — right-click any cable ▸ Edit bend points to add turns and angles (double-click the cable to add a corner, drag a handle to move it, Alt-click to remove); the cable right-click menu is now reachable at every design size (it was unreachable below 600 cables), and length — and therefore the optical budget — recomputes automatically on every edit. (3) UNDO/REDO NOW REMEMBERS WHAT IT USED TO DROP — moving a cable's bend points, editing splices and re-patching ports are full undo steps and arm autosave (previously a vertex move or a splice edit created no undo step and could be silently lost on save). (4) A "WHAT'S NEW" CARD — this panel now greets you once after each update and never again until the next version bumps. Foundation for the coming waves: the click-to-pick-port draw flow with the digital-twin inside-view picker, cut-and-splice anywhere, and full port-occupancy conflict prevention. · 3.22.0 · 📋 RECORDS + A REAL PORT CHECK — closing the last of the element-sweep findings. (1) No more silent data loss: ~20 inspector fields that were set but dropped from the as-built GeoJSON — building use (residential/commercial), phase, pole/mount/riser heights, guy lead, ground-rod length, OLT Tx, ONT Rx window, closure through-fibres / entry-ports / slack loop / operating-temp / bend radius, chamber racks, slack-coil stored length — are now written to the export, so what you set is what the records keep. (2) The closure "Entry ports" field was a promise with no check; now a real DRC (IEC 61753-1 / GR-771): declare N cable-entry ports and if more cables enter than fit, the Design Advisor flags it. (3) Corrected the mount-height tooltip that implied an automatic clearance check (it records the height for the make-ready/NESC review). · 3.21.0 · 🔬 ONT SENSITIVITY IS NOW REAL — a pinned ONT grades against ITS receiver window, not just the generic PON class. Before, the ONT model picker set a receiver window (e.g. an XGS-PON ONT's −30 dBm sensitivity) that the inspector displayed but the loss verdict ignored — it always tested against the PON class floor (B+ = −27), so a drop delivering −28/−29 dBm (fine for that ONT) was wrongly stamped FAIL, and a weak ONT could read PASS. Now the optical budget engine accepts a per-hardware receiver window: an ONT element carrying a datasheet window grades against it; a plain home with no pinned ONT still uses the standard PON-class window (so nothing changes for existing designs — verified). Wired end-to-end (optical_budget.evaluate_link + /api/sim/budget/evaluate + the server DRC + the client live grader, with full parity). Note: the OLT Tx figure is deliberately still taken from the PON class — the node's Tx is class-seeded and not yet class-tracking, so auto-applying it would wrongly cap higher-class designs; that cleanup is a follow-up. · 3.20.0 · 💵 DEFAULT CURRENCY USD — the platform now works in US Dollars by default. USD is the base currency (rate 1.00), so the reference rate card and every BOM / BoQ / business-case / report figure reads in $ with the round numbers unchanged (a $285 pole stays $285, not a converted €→$ figure). The multi-currency engine is intact: switch the project's display to € or IQD under Settings ▸ Financial & currency (defaults USD→EUR 0.92, USD→IQD 1310, all editable to your booking rate), and every money string — including the Operations workspace valuation/billing, the portfolio dashboard and the AI Quick Estimate — follows it. All hardcoded € display was routed through the one currency formatter so nothing is left showing the wrong symbol. · 3.19.0 · 🧹 ELEMENT SWEEP FIXES — after the splitter fix, a systematic audit of every element found the same class of bug elsewhere; these are the confirmed, high-impact ones. (1) €0 PRICING: FDH, ODF, pedestal, grounding and building-entry elements were absent from the cost engine's node map — they added €0 to the BOM and no line to the BoQ. Now priced + a labour takeoff line each. (2) OLT DUAL VOCABULARY: the inspector Model picker ("OLT 7-slot") and the device-GUI chassis picker ("7-slot") named the same chassis differently and never reconciled — so the device GUI ignored the picked model (always fell back to a 7-slot chassis), the BOM under-costed a device-GUI chassis pick to the 2-slot price (€5,800), and the DRC/capacity used a stale port count while the device view showed something else (an OLT could "fail port capacity" AND "show free ports" at once). Now both pickers reconcile on the chassis, OLT capacity = service-slots × 16-port cards (2-slot 32 · 7-slot 112 · 17-slot 272), and the BOM prices by chassis size regardless of which picker named it. (3) MDU BASEMENT SPLIT: a freshly-placed 4×4 MDU had no basement splitter until you happened to nudge floors/apartments — so its feed cable was over-sized and its worst-apartment Rx read ~17 dB too optimistic. Now seeded on placement. (4) SPLITTER-OVERFLOW DRC: the "N outputs but must feed M subscribers" check only covered FDT/FAT/ATB/closure — an over-split FDH, ODF, pedestal or standalone splitter passed silently. Now covered. (5) SCTE-77 LABEL: the closure direct-burial tier picker still said "Tier 22 — HS-20", conflating the SCTE-77 crush tier with the separate AASHTO wheel-load cover — corrected to match the chamber picker. · 3.18.0 · 🔧 SPLITTER FIX — one coherent split ratio. A splitter had TWO independent ratio controls that could silently contradict each other: the Model picker at the top (Generic · PLC 1:8 / 1:16 / 1:32, which set only n.ports + the label) and the cassette ratio below (1:2…1:64 + 2:N). The optical/loss/capacity/occupancy engine ONLY reads the cassette ratio — so picking "PLC 1:32 module (32 port)" changed the label but the splitter still split 1:8 (still 10.5 dB, still overflowed at 8 subscribers): the Model picker was a silent no-op, and the "32 port" was a lie. Now the two are ONE property, synced both ways: choosing a module drives the actual split (and ports), and changing the cassette updates the module label + ports — so Model, Specs, ports, cassette, schematic loss and the engine always agree. The model catalogue now covers the full 1×N range (1:2/1:4/1:8/1:16/1:32/1:64), and a standalone splitter is a single module (no more confusing "cassette 1 / 2"). 2:N protection ratios show an honest synthesised label. Engine unchanged (it was always cassette-driven); the labels no longer mislead. · 3.17.0 · 🗂 EXPLORER DETAILS — the element tree is now a working inventory, not a flat list. Every element row shows an at-a-glance summary inline (a pole's ANSI class + material, a FAT's split ratio + ports, an MDU's floors×apartments, an ONT's serial…), and selecting one opens an inline DETAIL CARD right in the tree: its identity + status/phase, model, the standards attributes that are set (material, class, height, load tier, cover, IEC enclosure category, IP, fire rating…), its LIVE connectivity (every cable in/out with the other end's name, tier and length — each a link that jumps to that element), and its structural hosting (what it's mounted on / what it hosts, also as links), plus ⌖ Zoom-to and ✎ Properties actions. Fixed a real annoyance: expanding a type group no longer collapses the moment you click anything (group open-state now survives the redraw). The full editable Inspector still lives in the right-hand panel; the Explorer is now the fast way to understand and navigate the whole design. · 3.16.0 · ⚡ AI QUICK ESTIMATE (closes the ML/automation gap — a LEARNED model, not another rule) — instant napkin-stage feasibility from a machine-learning SURROGATE of the design engine. We generated hundreds of synthetic towns, had the REAL auto-design engine design each, and fitted a log-linear ridge model (backend/sim/mapper_predict.py) mapping just homes + area → the plant it takes: trench km, cable km, FATs, FDTs, PON ports (held-out accuracy: FATs 3%, cable 9%, PON 10%, trench 19%, FDTs 26%). Analyze ▸ ⚡ Quick estimate (AI) turns those into a costed CAPEX range (with an overridable reference rate card) the instant you type two numbers — before drawing anything — so you can price a bid or sanity-check a district in seconds. It's genuinely learned (fitted by least squares on the engine's own output, not a hand-written formula) and clearly framed as an ESTIMATE: the full auto-design + cost engine remains the authority. Exposed at /api/sim/mapper/predict and on the public Open-API (/api/v1/mapper/predict). This closes the LAST of the structural gaps found in the world-leader comparison (brownfield, open API, mature solver, versioning/branches, portfolio, construction billing, NMS assurance, and now AI). · 3.15.0 · 📡 SERVICE ASSURANCE & NMS BRIDGE (closes the activation/NMS gap vs Nokia Altiplano/Calix) — the platform now closes the loop from design to LIVE network. Subscribers already carried the DESIGNED optical budget (per-drop designed Rx + the ONT Rx window, checked once at activation); this adds the ongoing loop: a northbound ingest (POST /api/sim/nms/telemetry, authenticated with the Open-API key or the first-party token) that an OLT / NMS / ACS pushes live ONT telemetry into — Rx/Tx power, temperature, oper-state, alarms — keyed by optical serial, latest-wins. Each reading is matched back to its subscriber by serial and graded against that subscriber's designed link budget: down (LOS / dying-gasp / offline), degraded (Rx outside the ONT window), marginal (drifting >3 dB below the designed Rx but still in window), or ok. The Operations workspace ▸ 📡 Network health view rolls it up (subscribers · monitored · healthy % · needing attention) and lists every subscriber worst-first with design-vs-live Rx, alarm/state, verdict and the reason — so budget drift shows up before it becomes an outage. Telemetry is stored by serial and only surfaces where the serial is YOUR subscriber (no cross-tenant leak). Server-side sim/assurance.py. · 3.14.0 · 💰 CONSTRUCTION VALUATION & MILESTONE BILLING (closes the milestone-billing gap vs Sitetracker/Render) — the build can now be PAID. Work-order execution already turned the issued design into cost-coded tasks (trench/pull/splice/install/drop/test) with quantities and a lifecycle; this values them and issues interim payment certificates (IPCs) — the instrument a fibre contractor actually invoices against. Every task is valued qty × rate from a construction rate card (€/m trench, €/m cable, €/splice cassette, €/node, €/drop, €/test); done work counts in full, in-progress at a configurable credit; tasks roll up into billing milestones (civil / cabling / splicing / structures / drops / testing). The Operations workspace ▸ 💰 Valuation & billing shows the milestone table + earned-value progress and a payment certificate that nets retention and everything previously certified, leaving the amount due this period. Issuing an IPC persists a numbered, cumulative claim so the next certificate starts from it — a real progress-billing ledger. Server-side (sim/billing.py + /projects/{id}/valuation, /valuation/certify, /claims), the certify guarded by the manager (wo.dispatch) capability. · 3.13.0 · 📊 PORTFOLIO DASHBOARD (closes the multi-project / portfolio gap) — the Operations workspace landing is now a real cross-project KPI roll-up, not just a project picker. A new server endpoint (/api/sim/projects/portfolio) aggregates, from each project's LATEST revision, the design KPIs that already live in the stored records — homes passed, CAPEX (BOM grand), cable km, build progress % — and rolls them into tenant-wide totals, scoped exactly like the project list (root: all tenants; staff: whole tenant; designers: own ∪ shared). The landing shows a totals strip (projects · homes passed · portfolio CAPEX · cable · avg build %) and every project card gains a design line (🏠 homes · 💶 CAPEX · 🧵 km). Pure roll-up of stored numbers, so the portfolio can never drift from the designs. Scale: the capacitated districting solver handles thousands of terminals in seconds, and a ~1,900-home town auto-designs end-to-end in ~14 s (the FAT-siting street-search is the next stage to optimise for larger towns). · 3.12.0 · 🌿 DESIGN VARIANTS + NAMED REVISIONS (closes the enterprise-inventory gap vs Smallworld/IQGeo) — the linear revision chain can now hold ALTERNATIVES. File ▸ Design variants saves the current design as a named branch — "all-buried" vs "aerial feeders", a value-engineered option — off the bound server project, WITHOUT touching the issued/as-built baseline. List them, COMPARE any variant against your latest revision (or another variant) with the same diff engine that powers revision diffs (added/removed/modified entities + BOM € delta), RESTORE the one you want into the editor, and delete the rest. Revisions also grow an optional human LABEL ("permit submission", "Phase 2") alongside the number. Server-side (sim/projects.py design_variants table + /projects/{id}/variants CRUD + /variants/{id}/diff), tenant- and write-permission-guarded like every project resource; variants live outside the contractual chain so exploring an option can never corrupt the construction baseline. · 3.11.0 · ⚡ MATURE OPTIMISER (closes the solver-scale gap vs Comsof/Setics) — the auto-design districting is no longer a single greedy pass. A new server-side capacitated solver (sim/mapper_solver.py) ships two textbook telecom optimisation primitives: the Esau-Williams capacitated minimum-spanning-tree (the classic concentrator/feeder aggregator — benchmarked at 80–83% shorter trunk than home-run stars on shared corridors) and a capacitated k-means districting (farthest-point seed → Lloyd relocation under capacity → nearest-neighbour swap/move local-search). Turn on Auto-Design ▸ ⚙ ▸ High-quality solver and the FDT districting uses it: tighter districts, shorter distribution + feeder cable (−4% / −7% on a uniform grid town, more on irregular demand), for ~2% extra compute. Deterministic (fixed seeds + stable tie-breaks, so a design recomputes identically) and it SCALES — the local search only examines each district's nearest neighbours, so 2000-terminal districting runs in a few seconds and full auto-design stays sub-linear-feeling on 1000+ home towns. Fast single-pass remains the default; the quality path is opt-in. · 3.10.0 · 🔌 OPEN API (closes the integration gap vs the world leaders) — the design engine is now programmable from OUTSIDE the app. A stable, versioned public surface at /api/v1/mapper/* exposes the SAME server-side engines the app uses — auto-design, topology/strand, DRC/standards, build-readiness, PON capacity, protection, duct-fit, device-view, BOM, BoQ and the DCF business case — so a partner's OSS/BSS, GIS, contractor portal or the customer's own tooling can drive planning/compliance/costing programmatically: post a design snapshot, get computed results back. Auth is by API key (X-API-Key or Authorization: Bearer), constant-time verified from a server-held key list — the first-party app keeps working unchanged behind its internal token, and one handler body serves both so the two faces can never drift. Self-documenting: GET /api/v1 is a machine-readable catalog of every operation, GET /api/v1/openapi.json is a full OpenAPI 3.0 spec BUILT FROM THE LIVE request models (so it always matches what the endpoints accept), and GET /api/v1/docs (Help ▸ Developer API) is a human reference. Crucially, only the input→output CONTRACT is published — the optimiser, rule and costing IP still runs server-side and is never returned or shipped to the browser. · 3.9.0 · 🏗 BROWNFIELD IMPORT (closes the #1 structural gap vs the world leaders) — you can now INGEST an existing network, not just export one. File ▸ Import existing plant (GeoJSON) reads a GeoJSON FeatureCollection of existing plant and materialises it: Point features → nodes (poles, manholes, hand-holes, closures, FDT/FDH/FAT cabinets, splitters, grounding, entry…) mapped by their kind/type property, WITH their standards attributes reconstructed (material, ANSI class, SCTE-77 tier, IEC closure category/IP, cover rating, depth, vendor/model/serial…); LineStrings → cables (endpoints auto-resolved to the nearest node, with fibre count, tier, cable_type, fire-rating…), ducts and trenches. It round-trips our own records-grade as-built faithfully and makes a best effort on generic GeoJSON (Esri / QGIS exports, kind→type aliases like cabinet→FDT, vault→manhole). It auto-establishes the map projection from the data's lon/lat bounds (or reads local-metre coords), tags every imported item as EXISTING + locked (a grey dashed ring on the map) so Auto-Design keeps it and DIG-ONCE reuses the imported ducts/trenches. An incumbent operator can now onboard their plant and extend it — the thing that previously made the tool greenfield-only. · 3.8.0 · 🔤 CABLE MODEL DESIGNATIONS (Chinese YD/T + international) — you can now pick the REAL cable type when running a cable, from a standards-accurate catalogue. Chinese GB/T 7424 / YD/T 901 outdoor codes — GYTA, GYTS, GYTA53, GYTA33, GYXTW, GYXTC8S, GYFTY, GYFTCY (ADSS), GYDTA… — the FTTH drop codes GJXH, GJXFH, GJYXCH, GJYXFCH, GJYXFHA, and international/ICEA structure names (loose-tube, central-tube, ribbon, rollable-ribbon, micro, flat-drop, figure-8, ADSS, SJSA-armoured, OPGW, MST). Pick one in the cable Inspector and it shows the LETTER-BY-LETTER decode + application + armoured / self-supporting flags. Every decode was researched against the standards and adversarially verified — e.g. GYXTW's W is correctly a STEEL-PE (钢-PE) sheath sandwiching two steel wires ("steel-PE-steel"), NOT aluminium; T = jelly-filled; A = APL moisture laminate (not armour — armour is the trailing numeric code 53/33); ADSS = Telcordia GR-3421; the light-armoured duct bow-drop is GJYXFHA (not the common mis-spelling GJXFA). The designation travels with the cable into the GeoJSON as-built (cable_type). · 3.7.0 · 🧵 OPTIONAL AUTO-DESIGN DUCTING (direct-burial stays the default) — a new ⚙ next to Auto-Design opens options: cables are direct-buried in the trenches by default (no conduit — the correct, common method), but you can now opt IN to duct where it matters. "🧵 Duct the feeders" pulls each feeder through a Ø50 mm conduit (future capacity + re-pull, and the per-cable duct-fit check then runs on the feeders — the cable is tagged in-duct). "🛣 Duct road-crossing segments" detects where a buried cable actually crosses a street and lays a short Ø110 mm bore there (road protection), leaving the rest of the run direct-buried. The toggles persist with the design; re-running Auto-Design replaces the auto ducts (DUCT-Auto-*) like the auto trenches, and the completion summary says what it laid. Both stay OFF unless you ask — so nothing forces conduit onto a cable that should just be direct-buried. · 3.6.0 · 🧭 DESIGN HEALTH + ONE-CLICK CLEANUP (the Advisor, closed-loop) — the Violations panel now leads with a DESIGN HEALTH score (0–100 + letter grade) that rolls up every rule fail and warning into one glance: a green 90+ means buildable, a red score means work to do. Next to it, when the DRC found issues the platform can fix unambiguously, a single ✨ Auto-fix N button applies EVERY safe fix at once — upsize the over-full cables, set ports to what's actually served, add the mid-span poles, IP68 the buried closures, 2:N-or-bond where needed — then re-runs the server DRC so you watch the score climb in real time (the banner shows the before score). This turns the per-item Advisor into a whole-design optimiser and makes auto-design closed-loop: design → check → auto-repair → re-check. Judgement calls it won't touch on its own (the ones with no unambiguous fix) stay in the list for you to decide. So "is this design buildable, and what's the fastest path to green?" is now one number and one button. · 3.5.0 · 🛡 TRUE PROTECTION DIVERSITY (SRLG across backups) — the protection planner's "fully diverse" claim is now honest. Before, each backup route only avoided its OWN primary — so two standby feeders could quietly share the same street, and every Type A/B backup silently shared the single egress out of the backup OLT. Now the SRLG mask ACCUMULATES: as each backup is routed, it must avoid its primary AND every backup already placed, so the standby feeders spread onto separate streets. Each backup reports how much path it shares with its SIBLINGS (not just its primary), and a backup that overlaps a sibling is downgraded from "diverse". And the shared BACKUP-OLT EGRESS is now flagged as the single-risk point it is — a new ⚠ Shared-risk advisories block in Reports ▸ Protection says "all N backups share the egress from OLT-Backup-1 — for true N+1 add a second backup OLT at a separate site." The overall verdict can no longer read fully-green while a single fault point or a backup-on-backup overlap remains. · 3.4.0 · 🧱 AUTO-DESIGN NOW LAYS CIVIL — the biggest coherence gap closed. Auto-Design used to return bare cable polylines with no excavation, so dig-once reuse, the BoQ trench takeoff and trench-sharing had nothing to work with. Now the planner emits DIG-ONCE TRENCHES: it collapses every buried (feeder + distribution) cable path into unique undirected street segments — so two cables sharing a street are dug ONCE — chains the contiguous segments into tidy trench runs, and materialises them as TR-Auto-N (0.4 m × 0.8 m soil, editable). Feeder/distribution already run buried via the tier civil-method defaults, so the trenches immediately drive the civil BoQ takeoff, dig-once reuse (route later cables through them) and the trench-congestion / sharing checks; re-running Auto-Design replaces the auto civil rather than stacking it. (Next: assigning ducts inside the trenches so the per-cable duct-fit check runs on auto output too.) · 3.3.0 · 🛡 TYPE C — REAL FULL DUPLICATION (fixes a modelling bug) — Type C protection was wrongly reusing Type B's 2:N first-stage change; per ITU-T G.984.1 that's not what Type C is. Type C now does proper FULL PATH DUPLICATION: it drops a SEPARATE protection splitter (role = protection, locked, a violet dashed ring on the map) beside each first-stage splitter — a parallel 1:N fed by the diverse protection path, NOT a 2:N combiner — and marks every served ONU DUAL-INTERFACE (a second receiver that switches on a working-path failure; shown as 🛡 in the home Inspector). The step tells you exactly how many splitters + ONUs it will add. The protection splitters are priced ONCE — in the Protection BOM category (the working equipment count now excludes role='protection' so there's no double charge) — and clearing the protection plan removes them again. Type B still correctly does the 2:N dual-input change. So each ITU-T G.984.1 type now lands as the RIGHT physical topology: A = shared port + diverse feeder; B = one 2:N splitter + standby port; C = a full parallel splitter + dual ONUs. · 3.2.0 · 🛡 PROTECTION THAT BUILDS ITSELF — the backup-plan flow now instantiates the real redundancy hardware and applies the standards-mandated splitter change, instead of just listing them. After you pick a Type (A/B/C), for Type B/C it asks WHERE the standby PON port lives — a 🛡 SEPARATE BACKUP OLT (recommended: adds OLT-Backup-1 with role=backup beside the CO, so the diverse feeders originate from it and the design survives a whole-OLT failure) or a 🖥 BACKUP CARD IN THE MAIN OLT (adds a standby PON line-card to a free chassis slot — cheaper, protects the feeder + port but not an OLT failure; warns if the chassis is full). Then it PROMPTS about the splitter change: per ITU-T G.984.1, the first-stage (PON-port) splitter must become 2:N — a dual-input PLC splitter, input 1 = working feeder, input 2 = the diverse protection feeder. It lists exactly which splitters change (1:8 → 2:8, 1:32 → 2:32, …) and, on Apply, converts every first-stage splitter to 2:N before planning the diverse routes. Type A shares the working port (no standby hardware, no splitter change). So a redundancy plan now lands as real, priced, standards-correct hardware — backup source, 2:N splitters and diverse routes — not a to-do list. · 3.1.0 · 🤖 SMARTER AUTO-DESIGN — Auto-Design now does two more things for you. (1) 🏢 IT SITES THE CO ITSELF — you no longer have to place an OLT first: if none exists, the planner puts the central office at the DEMAND-WEIGHTED CENTROID (a 1-median approximation that minimises total feeder reach) snapped to the nearest street vertex, and materialises it as OLT-Auto-1 (move it later if you have a real site). (2) 🛡 IT OFFERS A BACKUP PLAN — the moment the working tree is built it asks "Add a backup / protection plan?" and lets you pick the ITU-T G.984.1 type: Type A (diverse backup feeder), Type B (standby OLT PON port + diverse feeder into a 2:N splitter — the 1:1 ~50 ms scheme), or Type C (full duplication to a dual-interface ONU); pick one and it computes a physically diverse backup route for every feeder and prices it into the BOM. And thanks to the v3.0 Design Advisor, any aerial span that ends up too long now shows a one-click "✚ Add a mid-span pole" so you can keep every NESC span legal without hunting. · 3.0.0 · 🧭 DESIGN ADVISOR — every rule violation now NAMES the standard it breaks and, where the fix is unambiguous, offers a ONE-CLICK repair that recomputes the whole design. The Violations panel (and a new ⚠ strip right on the selected element in the Inspector — "show what standards we're violating" on the canvas) tags each issue with its clause — IEEE C2 NESC Rule 232/235C/261, ITU-T G.984 1:64/1:128 split, IEC 61753-1 / 60529 closure category & IP, ANSI/TIA-598 fibre & tray, NEC 770.48, BICSI OSP-DRM, TIA-758/569 — and shows a green ✚ button with the exact remedy: "Upsize this cable", "Set ports to N", "Add a mid-span pole", "Add a down-guy", "Upgrade to IP68", "Set category to S", "Add trays → N", "Add OFNR transition", "Bond & earth", "Add a splitter cassette". Click it and the platform mutates just that item and re-runs the server DRC, so you watch the design get better in real time. The suggested fix is computed server-side (mapper_rules) alongside the violation, so the advice is authoritative, not a guess. Next (v3.1): Auto-Design will place the CO itself, prompt for a backup plan + type, and auto-suggest the poles that keep aerial spans legal. · 2.99.0 · 🔀 DRAG-TO-PORT REROUTE + SLACK/SNOWSHOE (Wave 4c — COMPLETES the standards-completeness program) — your original ask, made granular. A splice closure (or any joint carrying two or more cables) now shows a 🔀 Reroute fibres button in its inside view that opens the splice matrix, and the matrix's fibre cells are now fully DRAGGABLE: grab a free fibre on one cable and drop it onto a free fibre of the other to splice it through (the click-to-select path still works too). Each splice writes a REAL range record — the same model the A-Z light-path trace, splice sheet, BoQ splice count and taper report already read — so a manual reroute is a first-class, persisted, traceable splice, not just a drawing; a delete control cuts it. Plus a new 🔁 Slack / snowshoe element: a stored cable loop with a live BICSI bend-radius check (loop radius vs 10× cable-OD unloaded / 20× loaded — ✓ OK / ⚠ unloaded-only / ✗ too tight). With this, the platform now covers the full 41-requirement OSP/ISP standards register from the IEEE/BICSI/TIA/ITU/IEC/ANSI-SCTE sweep: elements → attributes → enforcement (DRC) → certification (acceptance tests) → as-built (TIA-606/GIS) → hands-on fibre management. · 2.98.0 · 🗺 RECORDS-GRADE AS-BUILT (Wave 4b · TIA-606 + GIS) — the GeoJSON GIS hand-off is now a full as-built record. Every feature carries a TIA-606 IDENTIFIER (a stable, normalised id per pole / chamber / closure / cabinet / cable / grounding / entrance) plus its COMPLETE standards attribution: pole material · ANSI class · grade · loading district · guy strand · anchor; chamber load-tier · AASHTO cover · size · depth · duct-entries; closure environmental category · IP · sealing · form · tray count · bonding; FDH capacity · NEMA; grounding role · conductor · rods · resistance; building-entry role · transition; vendor · model · serial · lifecycle status; and — folding in Wave 4a — the fibre ACCEPTANCE TEST (measured IL, ORL, OTDR ref, tester, date) with a computed PASS/FAIL against the design budget. Cables export their placement · fire rating · pathway · aerial attachment · messenger · lashing · duct · tracer. This is the BICSI OSP-DRM benchmark for a maintainable as-built — one export now reconciles the design, the standards spec and the field certification per feature, ready for a GIS / asset system. (Final Wave-4 item: per-fibre drag-to-port reroute + slack/snowshoe.) · 2.97.0 · 🧪 ACCEPTANCE-TEST RECORDS (Wave 4a) — every subscriber link can now carry its ANSI/TIA-568.3-D turn-up certification, right on the home / ONT / MDU: test tier (Tier-1 OLTS insertion loss required · Tier-2 OTDR supplemental), method (bidirectional 1310/1550), the measured end-to-end insertion loss, the ORL, an OTDR trace reference, and tester / date. The record is graded LIVE against the design's own link budget from the strand engine — the panel shows the computed design loss and the maximum loss the link may measure and still reach the ONT, then a ✓ PASS / ✗ FAIL verdict: the measured IL must sit within the budget headroom and the ORL must be ≥ 55 dB (single-mode APC). This is the must-have that closes out a build — a design that was only modelled can now be proven as-built, per fibre. Records persist with the design. (Next in Wave 4: TIA-606 label coverage + GIS as-built, then drag-to-port reroute.) · 2.96.0 · ✅ STANDARDS DRC ENGINE (Wave 3) — the fields from Waves 1–2 are now ENFORCED. Seven new server-side (IP-protected) compliance checks join the ~25 existing ones, so the browser can neither read the rule nor fake a clean design: (1) 📶 per-PON split capacity — a PON port fanning out past 1:64 (physical) warns and past 1:128 (logical) fails, INDEPENDENT of the optical budget, so a physically un-buildable design no longer reads "ok" (closes the top adversarial-review gap); (2) 🔵 closure environment-vs-mount — a Cat A (aerial) closure mounted inside a manhole fails (a subterranean chamber floods; use Cat G/S IP68, IEC 61753-1); (3) closure IP-vs-category — a buried / vault (Cat G/S) closure rated below IP67 warns (IEC 60529); (4) splice-tray over-fill — a closure whose declared trays × fibres/tray can't hold the incoming cable's fibres warns (TIA-598 12-fibre groups); (5) metallic-armour bonding — an armoured cable entering a closure with no bond kit warns (ITU-T L.201 / NESC); (6) chamber duct-entry reconciliation — a manhole/hand-hole declaring fewer end-bells than the cables actually terminating there warns; (7) building-entry NEC 770.48 — unlisted OSP cable running > 15.24 m inside with no OFNR/OFNP transition warns. Every check consumes the exact fields shipped in v2.91–v2.95 and refreshes live as you edit them. Backed by 8 new server tests + an end-to-end browser test. Next: Wave 4 — records (acceptance tests · TIA-606 labels · drag-to-port · GIS as-built). · 2.95.0 · 🧩 FIVE NEW OSP/ISP ELEMENTS (Wave 2) — the palette gains the elements the standards sweep said were missing. 🗄️ FDH — Fibre Distribution Hub, the feeder↔distribution cross-connect cabinet (GR-3125/GR-487) with a 144/288/432/576-port capacity + NEMA 3R/4/4X rating, distinct from the FDT splitter cabinet. 🗃️ ODF — indoor Optical Distribution Frame / patch panel (19/23-in rack or wall box, port capacity, SC/LC APC-UPC adapter type, TIA-568.3) for the CO / head-end / building riser. 🚰 Pedestal — buried-plant drop terminal (GR-13), the buried counterpart of a FAT. ⚡ Grounding & bonding — a real asset: TMGB / TGB busbar, ground rod (count × length + NEC-250.53 resistance target), messenger-to-neutral bond or anchor-guy bond, with the ANSI/TIA-607 conductor size (#6 AWG min … #1/0 TBB) — the mandatory NESC 215C2 / TIA-607 element that was absent everywhere. 🚪 Building entry — the ISP entrance chain: entrance point / entrance facility / protected entrance terminal (MPOE · demarc) / MDF / IDF, the NEC-770 OSP→listed transition (→OFNR riser / OFNP plenum) with the ≤15 m unlisted-OSP allowance (live 770.48 warning), firestop and TMGB-bond flags. FDH / ODF / pedestal open as device faceplates and (FDH/pedestal) carry the Wave-1 enclosure fields; all five persist. Next: Wave 3 — the server DRC engine that validates every field shipped in Waves 1–2. · 2.94.0 · 🧵 AERIAL HARDWARE + CABLE FIRE-RATING (Wave 1d — completes the Wave-1 attribute foundation) — the CABLE (route) inspector gains two standards sections. Aerial hardware (NESC, shown when the cable is on a pole line): attachment type (strand-and-lash / figure-8 self-messenger / ADSS all-dielectric / over-lash), and — for a lashed build — the EHS messenger strand (6.6M ¼″ 6,650 lbf / 10M 5⁄16″ 11,200 / 16M 3⁄8″ 15,400, sized to the loaded span per NESC Rule 261H: ≤35% initial / 25% final / 60% max) + lashing (single / double / spinner rings). Fire rating (NEC Article 770): the cable listing (OSP-unlisted / OFN / OFNG / OFNR riser / OFNP plenum, NEC 770.179 ranks), an "enters a building" flag that reveals the in-building pathway (outdoor / horizontal / riser ≥OFNR / plenum OFNP per 770.113) and the in-building run length — with a live 770.48 warning when unlisted OSP cable runs > 15.24 m (50 ft) inside before transitioning to a listed cable. All persist on the route. (The microduct 3–16 mm catalog + NEC-40% blown-fill DRC are server-side, coming in Wave 3.) — WAVE 1 (the standards attribute layer: closure · chamber · pole · aerial/cable) IS NOW COMPLETE. Next: Wave 2 new elements (FDH · ODF · pedestal · grounding · building-entry). · 2.93.0 · 🗼 POLE ENGINEERING (Wave 1c) — the pole becomes a real structural object. Structure: full ANSI O5.1-2022 class table with the designated groundline transverse load on every option (H6 = 11,400 lbf … Class 10 = 370 lbf), a wood-species picker (conditional on Material = wood; Southern Pine / Douglas-Fir 8,000 psi … Western Larch 8,400) driving the class→circumference lookup, NESC construction grade (C general / B crossings, with the Table 253-1 overload factors), and the NESC Rule 250B loading district (Heavy ½″ ice / Medium ¼″ / Light no-ice). Setting (RUS 1724E): a soil class that derives the embedment + total pole length live from the above-ground height (set depth = 10% of length + 2 ft, ±soil). Riser now expands into a guard type (PVC / steel / HDPE) + top height. Aerial (NESC): joint-use reveals a supply-voltage class (the 40 in / 1.02 m comm-worker safety zone; >22 kV = engineered), and "Guyed" expands into the real down-guy detail — lead distance (≈1:1 lead-to-height), EHS guy strand (¼″ 6,650 lbf … 7⁄16″ 20,800 lbf), anchor type (screw / plate / rock / swamp / deadman) and a guy-guard marker. A FAT / closure mounted on a pole gains its mount method (band-and-clamp no-drill vs through-bolt) + mount height. All persist; the NESC clearance / worker-zone / guy-required DRC that consumes these lands in Wave 3. (Aerial cable messenger/sag + microduct + fire-rating are Wave 1d, next.) · 2.92.0 · ⛓️ CHAMBER STANDARDS (Wave 1b) — manholes & hand-holes gain the rest of their standards attributes. The SCTE-77 tier now shows its live DESIGN / TEST load (test = 1.5× rated: Tier 5 = 5,000/7,500 · 8 = 8,000/12,000 · 15 = 15,000/22,500 · 22 = 22,500/33,750 lbf) and — IMPORTANT correction — the tier labels no longer claim "Tier 22 = HS-20 highway"; SCTE-77 rates only occasional NON-deliberate traffic. Deliberate roadway traffic is now a SEPARATE "Cover & frame" axis: AASHTO H-20 / HS-20 cover rating (16,000 lbf wheel — a metal/RC cover+frame that a chamber in the travelled way legally requires regardless of tier), plus cover security (bolt-down / pentagon / locking) and the TIA-606-C cast legend ("FIBER OPTIC"). New Access & racking section: person-entry (confined-space, OSHA — defaults from manhole vs hand-hole type) drives a cable-racking model (racks/wall × arms → slack-coil capacity, TIA-569/BICSI). New Drainage & bonding (open-gravel / sump / sealed + NEC-250 racking bond) and Duct-entries (end-bell count, reconciles with the duct-bank). All persist; the tier-vs-traffic + duct-reconciliation DRC lands in Wave 3. · 2.91.0 · 🔵 CLOSURE ENCLOSURE STANDARDS (Wave 1a of the OSP/ISP standards-completeness program) — every splice-closure-family element (closure · FAT · FDT · ATB) gains a standards "Enclosure" block in the Inspector: IEC 61753-1 environmental category (Cat A aerial / G ground / S subterranean — a closure rated for the wrong mounting is now a settable, checkable fact), Telcordia GR-771 sealing method (one-shot heat-shrink vs re-enterable gel / mechanical / encapsulant) + IEC 60529 IP rating (IP54…IP68), form factor (dome butt vs inline both-ends), TIA-598 splice-tray fill (trays × fibres/tray, 12-fibre groups), splice ROLE (express loop-through with uncut through-fibres vs branch/butt vs terminal drop — feeds A-Z trace accuracy), ITU-T L.201 / NESC metallic bonding & earthing (single-point vs both-ends), GR-771 stored-slack radius (30/20/15 mm) + slack-loop length, cable-entry port count + shape, operating-temperature range, and — for a loose direct-buried closure — its ANSI/SCTE-77 crush tier (a hosted closure inherits its manhole/hand-hole's tier instead). Hosted closures auto-seed their category from the host (pole → aerial, chamber → subterranean). All fields persist with the design; the server DRC that validates them (category-vs-mount, tray over-fill, unbonded armour, tier-vs-traffic) lands in Wave 3. This is the first of 41 verified requirements from the IEEE/BICSI/TIA/ITU/IEC/ANSI-SCTE standards sweep. · 2.90.0 · 🏗 STRUCTURAL HOSTING — poles & chambers now CONTAIN equipment. Double-click a pole, manhole or hand-hole and it opens a HOST view instead of a bare property list: it shows what's mounted inside, and lets you add more. A pole can carry a 📦 FAT + splitter, a 🔀 standalone splitter, a 🔵 dome closure or a 🟦 in-line closure; a manhole / hand-hole holds one or more splice closures to reroute the cables running through it. Each mounted item is a real device — click 🔍 Open to drop into its faceplate (closure splice-trays / splitter LED grid), and 🔗 Connect to wire the cables at the structure INTO it: feed an arriving cable onto the item (re-points its end onto the closure/splitter so the strand engine splices the fibres through), or route a new cable out to any destination. Mounted items fan out around the host on the map and the structure shows a cyan badge with its mount count; removing a host removes its mounted gear. Hosting travels with the design (hostId persists). This is the OSP reality — a chamber isn't a node, it's a room full of closures — and it's grounded in a full IEEE/NESC · BICSI · TIA · ITU-L · FOA · ISO/IEC · ANSI/SCTE standards sweep (49 ranked requirements; the pole/chamber structure fields in 2.89 were the first tranche). · 2.89.0 · POLE + CHAMBER TYPE / MATERIAL / DIMENSIONS — you can now specify what a pole or chamber actually IS. A pole gains a Structure section: Material (wood ANSI O5.1 · spun or hexagonal concrete · galvanised steel · FRP composite), ANSI O5.1 strength Class (H2..7), and a Riser (u-guard) flag — on top of the existing NESC aerial fields. A manhole / hand-hole gains a Chamber section: Material (precast / polymer concrete · HDPE · fibreglass composite · brick), Size class, ANSI/SCTE-77 Load-rating tier (5 pedestrian / 8 driveway / 15 off-roadway / 22 HS-20 traffic) and Depth. All persist with the design. (Structural hosting — chambers holding closures, poles holding a FAT/splitter/closure — is being designed from a full OSP/ISP standards sweep, coming next.) · 2.88.0 · SPLICE-CLOSURE INSIDE VIEW — a splice closure is a fibre JOINT, not a splitter host, and its inside view now says so: it draws real 12-splice organiser TRAYS sized to the closure fibre capacity (e.g. 48F → 4 trays), each fibre passing through shown in its slot colour-coded by where it goes. Tiles read Feed-in · Splices (used/capacity) · Trays instead of the splitter Ports/Spare. An empty closure shows its empty trays + the right guidance ("wire a cable to it, or right-click a cable ▸ Insert mid-span closure") — no more misleading "add a splitter below" on an element that has no splitter control. · 2.87.0 · RENDERER CRASH-PROOFING — an adversarial review of the 1000-house E2E build found the colour-less-area crash was one of a whole CLASS: drawZones / drawTrenches / drawDucts / drawRoutes and routeLengthM() all read .points / .polyline unguarded, so ONE malformed element (from a programmatic add, or an imported / hand-edited design file) threw inside redraw and blacked out the entire map every frame. All are now guarded — a bad element is skipped, never fatal. The map can no longer be taken down by one stray object. · 2.86.0 · MAIN/BACKUP OLT + E2E HARDENING — OLTs now have a ROLE: 🟢 Main (working) or 🛡 Backup (hot-standby), set in the Inspector and shown on the device chassis. The protection planner now originates Type A/B diverse backup feeders FROM the backup OLT (the real ITU-T G.984.1 standby-port scheme) when one is present. Also hardened the map renderer: a hand-built / imported project Area without a colour no longer crashes the canvas (defaults the colour, skips malformed polygons). Shipped alongside a full CO→ONT 1000-house Type-B reference design (scenarios/scenario-1000house-typeB.json). · 2.85.0 · SPLITTER FACEPLATE FIXES — (1) "+ Add splitter" now has an explicit ratio picker and adds the RATIO YOU CHOSE (it used to always add 1:8 regardless); it defaults to the module model's ratio. (2) Output ports now lay out 8 PER ROW like a real splitter face. (3) The INPUT is now drawn — an IN port on the left of each module (with the working feed fibre). (4) 2:N (dual-input, protection) ratios are now selectable everywhere — a 2:N module shows two inputs (working + protection). · 2.84.0 · UI/UX — DRAGGABLE MODALS + DIALOG/INSPECTOR POLISH — (1) the device modal, the Reports window and the small dialogs (Add-card, placement, containment) can now be DRAGGED anywhere by their title bar, and remember where you put them. (2) FIXED: the "+ Add card" picker was rendering unstyled at the bottom of the page and behind the device modal — its dialog CSS is now always injected and its z-index sits above every modal, so it opens on top where you clicked. (3) The item Inspector popover got a proper polish: aligned rows with focus rings, real toggle switches instead of raw browser checkboxes, styled section headers (accent bar + uppercase), and a slightly wider panel so labels stop wrapping. · 2.83.0 · VENDOR-NEUTRAL — the OLT device GUI is now brand-free: the chassis picker offers generic sizes (2 / 4 / 7 / 15 / 17-slot) instead of named vendor models, and the card / capacity hints read “16-port GPON line card”. No third-party brand names anywhere in the design tooling. · 2.82.0 · 🖥 DEVICE TWINS GO PRO — the interactive element twins gain three things: (1) PER-PORT OPTICAL — every subscriber port shows its Rx power + budget margin (click a port), computed by the server link-budget engine; ports with a thin amber/red ring are warn/fail on optical, and an OLT PON shows its worst-case downstream margin. (2) DRAG-TO-RE-PATCH — drag a subscriber from its port onto a spare port on the same splitter to change its physical patch; the pin persists (n.patch) and the server honours it in the port assignment. (3) 🏷 LABEL SHEET — one click prints an ANSI/TIA-606 port-label sheet (device → bay/slot → port → destination → fibre → Rx/margin) for the OLT and every passive element. Server: sim/mapper_device.py now returns per-output optical + honours port patches. · 2.81.0 · 🖥 EVERY ELEMENT IS NOW A DIGITAL TWIN — double-click any element and it opens as an interactive device, not a static diagram. FAT / FDT / splitter / ATB draw a real faceplate: the feed-in, each splitter cassette as a module with its output ports as a live LED grid (green → subscriber drop · purple → MDU · amber → a downstream splitter · grey = spare) — click any port for its destination. A bare splice closure opens as its pass-through fibre tray. Add or remove splitter cassettes and change the split ratio right on the device, and swap the model. Backed by the server device engine (sim/mapper_device.py) — the ports map to the strand engine's real fibre allocation. Joins the OLT chassis GUI (v2.80) so now every clickable element is a live twin. · 2.80.0 · 🖥 REAL OLT DEVICE GUI + element views — double-click an OLT (or Inspector ▸ Open device GUI) and it opens a real chassis: pick the chassis size (2 / 4 / 7 / 15 / 17-slot, vendor-neutral) and the chassis draws its slots — control, uplink, power and the service slots. Each service slot holds a line CARD of a technology (GPON / XGS-PON / combo, 8 or 16 PON ports); every PON port is a live LED (green in-use · grey free · amber near-limit · red over-subscribed) mapped to the splitter it feeds — click one to see its subscribers, split, Mbps and oversubscription. + Add a card (choose the technology) into any empty slot, or hit ⚡ Auto-distribute to pack the active PONs onto cards and add cards as they fill up. Overflow (more PONs than the chassis can seat) is flagged so you upsize the model. The chassis dimensioning + PON→port assignment is server-side (sim/mapper_device.py). FAT / FDT / splitter / closure / MDU keep their strand-engine inside view (real fibre-by-fibre ports + editable cassettes). · 2.79.0 · 🔌 CABLE PLACEMENT + DUCT-FIT — click a cable and it now asks how it's installed: 🟫 Buried or 🗼 Aerial. Aerial → reuse-pole vs new-pole-line. Buried → direct-buried or in a duct; pick the duct and get a LIVE fit verdict computed to the standards: pulled conduit uses NEC Chapter 9 area fill (53% one cable / 31% two / 40% three+), blown microduct uses the 0.6–0.7 cable-OD-to-bore diameter ratio, and an over-size cable (e.g. a Ø18.8 mm 144F cable in a Ø10 bore) is rejected outright — with the slimmest duct that WOULD fit suggested one click away. Cable OD comes from fibre count + structure; both the fit maths and the duct catalog are server-side (sim/mapper_ductfit.py). The Inspector shows the placement + a Change… button. · 2.78.0 · 🛡 PROTECTION NOW PRICED IN THE BOM — the diverse backup routes from the protection planner now fold into the Bill of Materials as a dedicated “Protection” category: the NEW (unshared — that's the whole point) diverse civil at full trench rate + the protection cable mirroring each primary's fibre count + the type equipment deltas (standby OLT port, 2:N cassette, second splitter, dual ONUs). It carries overhead like any CAPEX and is toggleable (BOM category checkbox “🛡 Protection”); excluded from per-phase breakdowns (redundancy is design-wide). Backups still live in state.protection as a decoupled overlay — zero impact on the network/DRC/capacity engines. · 2.77.0 · 🛡 PROTECTION / BACKUP-ROUTE PLANNER (standards-based redundancy, ITU-T G.984.1) — pick a protection Type (A = backup feeder fibre · B = standby OLT PON port + a DIVERSE second feeder into a 2:N first-stage splitter, the common 1:1 ~50 ms scheme · C = full duplication down to a dual-interface ONU) and a scope (feeder / distribution / last-mile), and the planner computes a physically DIVERSE backup route for every primary route in scope. Diversity is real: the server re-runs the street-graph A* on a residual graph with the primary's own street edges EXCLUDED (Shared-Risk-Link-Group avoidance, endpoints exempt), so the backup shares no trench/duct/pole — the report proves it (per-route "shared m", target 0, + diverse %). NEW Reports ▸ 🛡 Protection tab: type/scope/shared-risk-band knobs, the equipment delta to add (standby port, 2:N splitter, second splitter, dual ONUs) and the per-route diversity verdict. Backups draw dashed on the map (Analyze ▸ 🛡 Protection routes), colour-coded by verdict. Server-side engine (sim/mapper_protection.py); backups are a planning overlay that travels with the design. · 2.76.0 · 📶 CAPACITY & BANDWIDTH ENGINE (the "ratio game") — every premise now knows what it actually gets: per-home Mbps = usable PON line rate (ITU-T G.984 2.488G / G.9807.1 XGS 9.953G × usable-rate factor) ÷ the total split on that home's exact splitter chain (from the strand engine). NEW Reports ▸ 📶 Capacity tab: per-home average tiles, per-PON-port table (which premises are on which PON, units, split, committed Mbps, oversubscription verdict vs your contention target) and per-OLT dimensioning (active PON ports → line cards needed, 16-port card norm). Editable knobs: package Mbps, contention N:1, ports/card, efficiency %. NEW Analyze ▸ 📶 Bandwidth-per-home map overlay (green ≥300 · light ≥100 · yellow ≥50 · orange ≥25 · red below). Server-side engine (sim/mapper_capacity.py). · 2.75.0 · DETECT NOW WORKS RELIABLY (server-side Overpass) — object detection was silently importing 0 streets / 0 homes in dense areas (esp. Iraq): the browser can only reach a couple of CORS-enabled Overpass mirrors and couldn't tell a busy 504 from a regional mirror that answers 200 with an empty result (a Swiss mirror returned nothing for Baghdad). The Overpass fetch now runs SERVER-SIDE (sim/mapper_detect.py): a curated pool of GLOBAL mirrors (overpass-api.de / kumi / mail.ru) is queried IN PARALLEL, the first with actual data wins (an empty answer never poisons it), with a real User-Agent + retry. Baghdad’s Al-Salam district now imports ~645 streets and, with the frontage fill, ~6,000+ estimated homes in seconds. The browser no longer calls Overpass at all. · 2.74.0 · DETECT RELIABILITY (superseded) — client-side Overpass mirror fallover. ·2.73.0 · MAP UX FIXES — (1) cables are now a clean, screen-constant 2–4 px at every zoom (vector-effect: non-scaling-stroke) instead of ballooning into thick ribbons when you zoom in; (2) hover/click now hits the item you're actually pointing at — nodeAt's hit target matches the DRAWN icon size (was a world-unit blob that grew to ~150 px at high zoom and grabbed a neighbouring FAT/closure), and the CLOSEST node wins so a house next to infrastructure resolves to the house. · 2.72.0 · IP-PROTECTION P3d-ii (OSM detection classification cutover) — the OpenStreetMap→demand classification (building footprints → home vs MDU by real shoelace area + building:levels + apartments tag; residential/commercial/public use split; garage/shed skip-list; address-point gap-fill homes; poles/manholes/cabinets; metre-based dedup) now runs SERVER-SIDE (sim/mapper_detect.py, POST /api/sim/mapper/detect); the classify loop is DELETED from the browser (−86 lines). The client keeps only the public Overpass fetch, the geo-referencing and node creation. Proven at 6/6 byte-exact parity + 10/10 end-to-end. THE DETECT + FRONTAGE IP IS NOW SERVER-SIDE. · 2.71.0 · IP-PROTECTION P3d-i (frontage synthesis cutover) — the Iraq gap-fill heuristic (estimate homes along street frontage where OSM has roads but few building outlines: spacing/offset/both-kerbs with spatial-hash dedup against real premises) now runs SERVER-SIDE (POST /api/sim/mapper/frontage); planFrontageHomes() is DELETED from the browser. Proven at 5/5 byte-exact position parity. · 2.70.0 · IP-PROTECTION P3a (DCF cutover) — the discounted-cash-flow business case (CAPEX-by-year phasing, subscriber ramp, NPV / IRR / payback / profitability-index) now runs SERVER-SIDE (sim/mapper_dcf.py, POST /api/sim/mapper/dcf); computeDcf() is DELETED from the browser. Also FIXES a latent bug: bomByPhase() (the per-phase BOM breakdown) had been returning zeros for phased designs since the BOM cutover made computeBom async — it is now a correct server-backed accessor. Proven at 5/5 parity. · 2.69.0 · IP-PROTECTION P2d (build-readiness cutover) — the buildability/utilisation dashboard (DRC roll-up, home reachability + optical-verdict split, port/splitter/FAT utilisation, conduit fill, fibre headroom, take-rate, overall verdict) now runs SERVER-SIDE (POST /api/sim/mapper/readiness — a pure assembly of the network + occupancy + violations + per-home optical, all already server-side); computeBuildReadiness() is DELETED from the browser. Proven at 3/3 parity. THIS COMPLETES THE DESIGN-ENGINE BUNDLE — auto-design, cost/BOM, strand engine, DRC rules, BoQ and build-readiness all run server-side now. · 2.68.0 · IP-PROTECTION P2c (BoQ cutover) — the Bill of Quantities / deliverables takeoff (civil dig by ground, duct laying by product, cable install by tier, fusion/termination/OTDR from strand records, structures, activation) now runs SERVER-SIDE (sim/mapper_boq.py, POST /api/sim/mapper/boq); computeBoq() is DELETED from the browser (takeoff + civil pricing catalogs no longer in View-Source). Proven at 3/3 parity. · 2.67.0 · IP-PROTECTION P2b (DRC engine cutover) — the design-rule engine (the ~25 topology/optical/civil/BICSI-OSP/NESC-aerial checks) + per-node capacity occupancy now run SERVER-SIDE (sim/mapper_rules.py, POST /api/sim/mapper/rules → {violations, occ}); evaluateRules() + computeOccupancy() are DELETED from the browser — the compliance logic is no longer in View-Source and the client can't fake a clean design. Proven at 4/4 structural parity. · 2.66.0 · IP-PROTECTION P2a (strand-engine cutover) — the network topology + strand-continuity engine (OLT→home tree, per-node loss accumulation, fibre demand + auto cable sizing, and the deterministic per-fibre strand map: route layouts, cassette feed fibres, OLT ODF frames) now runs SERVER-SIDE (sim/mapper_network.py, POST /api/sim/mapper/network); computeNetwork() + assignFibers() are DELETED from the browser — the client fetches the network and hydrates it onto live objects. Proven at exact parity (5/5, incl. a 173-node design). · 2.65.0 · IP-PROTECTION P1 (auto-design cutover) — the Auto-Design planning optimiser (street-cost serving areas, greedy max-coverage FAT siting, capacity districting, trench-minimising FDT placement) now runs SERVER-SIDE (sim/mapper_autodesign.py, POST /api/sim/mapper/autodesign, auth-gated + kill-switched); the browser sends only the demand snapshot and materialises the returned FAT/FDT/cable plan — the algorithm is no longer in View-Source. Follows the cost/BOM cutover (v2.64). · P5 — THE AERIAL / NESC PACK (the last structural gap): poles carry real attachment engineering (height, comms attach, joint-use supply height, guyed, make-ready); NESC rules check comms↔supply separation (40 in), midspan ground clearance with sag (18 ft over road crossings — detected against the street network), and guys at line-angle AND dead-end poles; guys & make-ready count in the BoQ; and File ▸ Export ▸ SPIDAcalc hands the pole line to a loading engineer in SPIDA’s open JSON exchange format. Plus v2.55–59: strand model · deliverables · optimizer v2 · field loop.