Changelog
All notable changes to this project. Format loosely follows Keep a Changelog.
The published site is versioned by IOS XE release; the Unreleased section captures changes not yet reflected in a tagged release of the upstream YANG models.
Versions Supported
The site serves these IOS XE releases under one GitHub Pages URL with an in-app version selector (see VERSIONING.md for the architecture).
| Version | YangModels path | Status | Notes |
|---|---|---|---|
| 26.2.1 | vendor/cisco/xe/2621 | active (default) | Newest release; site default |
| 26.1.1 | vendor/cisco/xe/2611 | active | Release the lab devices run: source of Device Data (device_data) |
| 17.18.1 | vendor/cisco/xe/17181 | active | Baseline for legacy in-place artifacts |
| 17.15.x | vendor/cisco/xe/17151 | active | |
| 17.12.x | vendor/cisco/xe/17121 | active | |
| 17.9.x | vendor/cisco/xe/1791 | active | Oldest supported release |
Generated tree modules grow with every release: 620 / 637 / 683 / 715 / 742 / 758 (17.9.x → 26.2.1). 26.1.1 also keeps 24 hand-made tree pages from its original layout (766 pages in total).
Adding additional patches/minors is the mechanical runbook in VERSIONING.md §8.
What's New in 26.2.1
- 26.2.1 is the default release (953 specs, 81,560 paths, 243,024 operations, 758 tree pages). New families include NGFW and Live Protect, wireless WAT and Live-Detect, IS-IS operv2, datapath TCAM usage, IIoT power management, config-management RPCs and OpenConfig telemetry.
- What Changed Between Releases (release-compare.html): modules added, removed and changed per release pair, with YANG revision notes and schema-node diffs.
- Device data from 7 lab platforms (26.1.1 captures, shown on 26.2.1 with a note): MDT, RESTCONF, NETCONF get/get-config/subscribe and gNMI Get/Subscribe, all secret-masked.
- Portable data-collection harness (
scripts/build_kit.py): collect the same datasets from devices on an isolated network and import them back. - Dark mode everywhere, including the ~4,200 YANG tree pages, with text and buttons at WCAG AA contrast in both themes.
- No broken links: tree pages, the 404 page and generated docs were fixed, and CI checks every link in every published page.
What's New in 26.1.1
Highlights for users coming from 17.x. This is a curated summary; see the release-tagged sections below for full per-round detail.
- +27 net new YANG modules vs 17.18.1 (742 vs 715 tree modules); +122 modules vs 17.9.x (620).
- Per-release artefacts under releases/26.1.1/ — search index, YANG accountability report, Postman collections, Bruno collections, prefix map, and viewer manifests, all version-pinned. The hub's version selector resolves these at runtime.
- Deeper cfg + oper specs —
generate_cfg_from_tree.pyandgenerate_oper_from_tree.pynow emit depth-8 trees, producing ~4× more cfg paths, ~7.8× more oper paths and ~10.8× more native paths over the legacy depth-4 cap. - MDT telemetry builder —
telemetry.htmlderives a paste-readytelemetry ietf subscriptionsnippet from any operational xpath, with curated tier / cadence / on-change annotations folded in when matched. - Site quality bar — Lighthouse strict mode + axe-core gates every deploy; PWA service worker enables offline browsing of the shell.
- Tooling parity across releases — all five active releases (17.9.x, 17.12.x, 17.15.x, 17.18.1, 26.1.1) pass the same strict pyang validation and ship the same set of artefacts.
For a hands-on walkthrough of common tasks, see CONTRIBUTING.md.
Development Effort
Estimated active development time, derived from git commit timestamps with a git-hours model: commits within 120 minutes of each other count as one working session, and each session is credited +30 minutes of ramp-up for its first commit. This is an approximation — git records when work was committed, not hours actually worked — so read it as a relative-effort signal, not a timesheet. Refresh or re-tune the numbers anytime with:
python -X utf8 scripts/estimate_dev_hours.py --by day
Totals (as of 2026-10-04): 593 commits across 88 sessions, roughly 201 hours of active development between 2026-02-01 and 2026-10-04 (~0.82 h/day averaged over the 246-day span; work is bursty, so per-day rows below are far more representative than the average).
By month
| Month | Commits | Est. hours |
|---|---|---|
| 2026-02 | 234 | 59.5 |
| 2026-03 | 14 | 6.5 |
| 2026-04 | 69 | 21.7 |
| 2026-05 | 69 | 26.1 |
| 2026-06 | 82 | 29.6 |
| 2026-07 | 47 | 18.7 |
| 2026-08 | 38 | 15.9 |
| 2026-09 | 9 | 6.5 |
| 2026-10 | 31 | 16.1 |
By active day
| Date | Commits | Est. hours |
|---|---|---|
| 2026-02-01 | 86 | 13.8 |
| 2026-02-02 | 18 | 6.1 |
| 2026-02-03 | 16 | 2.1 |
| 2026-02-06 | 51 | 10.0 |
| 2026-02-07 | 20 | 5.3 |
| 2026-02-09 | 11 | 7.2 |
| 2026-02-10 | 12 | 7.4 |
| 2026-02-11 | 6 | 2.3 |
| 2026-02-13 | 9 | 2.3 |
| 2026-02-14 | 4 | 2.3 |
| 2026-02-28 | 1 | 0.5 |
| 2026-03-03 | 3 | 1.1 |
| 2026-03-27 | 8 | 4.2 |
| 2026-03-31 | 3 | 1.2 |
| 2026-04-01 | 5 | 2.7 |
| 2026-04-03 | 1 | 0.5 |
| 2026-04-25 | 17 | 6.0 |
| 2026-04-26 | 37 | 10.3 |
| 2026-04-27 | 9 | 2.2 |
| 2026-05-07 | 2 | 0.7 |
| 2026-05-11 | 1 | 0.5 |
| 2026-05-17 | 4 | 1.5 |
| 2026-05-18 | 5 | 2.7 |
| 2026-05-20 | 15 | 5.4 |
| 2026-05-21 | 1 | 0.5 |
| 2026-05-22 | 16 | 8.1 |
| 2026-05-23 | 14 | 3.1 |
| 2026-05-25 | 4 | 1.3 |
| 2026-05-29 | 1 | 0.5 |
| 2026-05-30 | 6 | 1.8 |
| 2026-06-01 | 9 | 3.0 |
| 2026-06-02 | 5 | 1.2 |
| 2026-06-09 | 8 | 2.4 |
| 2026-06-10 | 6 | 1.5 |
| 2026-06-15 | 6 | 4.9 |
| 2026-06-16 | 15 | 4.6 |
| 2026-06-17 | 4 | 1.0 |
| 2026-06-18 | 29 | 10.9 |
| 2026-07-02 | 2 | 0.7 |
| 2026-07-13 | 3 | 1.2 |
| 2026-07-14 | 1 | 0.5 |
| 2026-07-17 | 1 | 0.5 |
| 2026-07-28 | 7 | 2.3 |
| 2026-07-30 | 19 | 6.3 |
| 2026-07-31 | 14 | 7.0 |
| 2026-08-01 | 11 | 2.9 |
| 2026-08-02 | 12 | 4.5 |
| 2026-08-04 | 4 | 3.6 |
| 2026-08-13 | 5 | 2.0 |
| 2026-08-31 | 6 | 2.2 |
| 2026-09-01 | 6 | 5.0 |
| 2026-09-02 | 1 | 0.5 |
| 2026-09-03 | 1 | 0.5 |
| 2026-09-28 | 1 | 0.5 |
| 2026-10-03 | 16 | 6.3 |
| 2026-10-04 | 15 | 9.1 |
[Unreleased]
Added — config-driven MDT walk in the harness (2026-10-05)
- Running config first: new
scripts/mdt-telemetry/collector/config_get.pycapturesshow running-configandshow running-config | format restconf-jsonover SSH (output/config-<PID>.json, secrets masked by the newredact_payload.mask_cli). It is the firstkit.py collectmethod and is included in bundles and imports. kit.py walk: walks only what is configured (native-config and every*-cfgmodel in the restconf-json) plus xpaths proven on other devices, re-tries configured-but-silent xpaths with a longer window, and reports the match per device (output/match-<PID>.json). Leave-one-out over six devices kept 299/300 streaming native-config xpaths from 192–270 of 14,659, and 101/101 cfg. Kits ship the fleet walk history so they can prune too.
Fixed — release validation gate 5 and remaining text contrast (2026-10-04)
- Gate 5 (spec → tree linkage) in
scripts/validate_release.pyreadinfo.x-yang-tree-url, which no spec has, so it always passed without checking anything. It now checks the links people follow: the tree page behind every viewer "View YANG Tree" button (each spec whose tree was generated) and every accountabilitytree_url, about 1,000-1,300 links per release.tests/test_validate_release_gate5.pyproves it fails on a missing page or broken link. - Text contrast: viewer sidebar module labels, stat values, tree arrows, path counts and RPC/MIB names, accountability coverage percentages and placeholders, and the Platform Coverage "not supported" marker now reach WCAG AA (4.5:1) in both themes.
Changed — dark mode for YANG tree pages; WCAG AA buttons and chips (2026-10-04)
- Tree pages: all ~4,200 per-release tree pages and tree lists follow the site theme and have the dark/light toggle.
scripts/generate_all_pyang_trees.pyaddssite.css, the newassets/css/yang-tree.cssandsite-chrome.js(footer injection off); all 6 releases were regenerated (only the theme lines changed) and the 24 hand-made 26.1.1 pages were patched. - Buttons and chips: new
--c-brand-fillcolour (#1565c0 light / #1976d2 dark) for every white-text fill, so dark mode no longer puts white text on #42a5f5. Category chips and badges (hub, 404, Device Data, viewers, Telemetry) were darkened to 4.5:1 or better while keeping their hues; Swagger UI method badges, version badge and Authorize button too. The Device Data "All" chip was white on white when selected.
Security — no external Swagger validator call (2026-10-04)
- The viewers set
validatorUrl: null. Swagger UI otherwise loads a badge from validator.swagger.io, sending it each spec's URL; the site's CSP blocked it, which showed up as a console error.
Fixed — 26.2.1 runtime 404s; dark mode gaps; stale content (2026-10-04)
- 404s after 26.2.1 became the default: the telemetry XPath builder requested
releases/26.2.1/yang-prefix-map.json, which was never built (build_release.pynow runsbuild_yang_prefix_map.py; a test requires a prefix map for every release), and the viewers probedreleases/26.2.1/live-modules.jsonbefore falling back (they now read thedevice_datarelease directly). - Dark mode: App Map, Changelog and Platform Coverage gained dark mode and the toggle; fixed the white quick-nav bar (Code Generator, Accountability), unreadable example boxes, the Ctrl+K hint, About page pills and code, and light panels in the viewers (platform badges, live device data, base URL).
- Content: About lists 26.2.1 as the default; the accountability header reads its generated date from the data; the hub "last updated" line is current.
- Verified in a headless browser across 28 pages in both themes: no failed requests, no console errors, no unreadable text.
Added — C9300-STACK8-WAN deep MDT walk (2026-10-05)
- Per-xpath MDT walk on the Stack over the WAN, in addition to the top-level run: openconfig, ietf, other, cfg and MIB in full; oper and native-config on catalogs pruned by the new
scripts/mdt-telemetry/collector/prune_walk_catalog.py(972 of ~16,900 xpaths: those that streamed on another device or exist in the Stack's running config; 94–100% of streaming xpaths kept in leave-one-out checks), cutting about two days to about three hours. The Stack's MDT paths went from 78 to 586 (the MDT dataset now has 4,293 paths across the 7 devices).
Security — SNMP community and lab password removed from published files (2026-10-04)
- The MDT dataset (
telemetry-live-data.json) stored device fields unredacted, so the lab SNMP read community was published in cleartext (snmp_community,entLogicalCommunity). Communities also appeared as CLI text (snmp-server community X RO) and as SNMPcommunity-configlist keys in the NETCONF/gNMI/RESTCONF datasets, which name-based masking cannot see.build_live_dataset.pynow redacts like the NETCONF/gNMI builders;redact_payload.pyandharness/redact.pyalso mask communities in CLI text and community-config names (JSON, XML, JSON-escaped payloads); the RESTCONF reconciler redacts folded values.tests/test_dataset_secrets.pynow covers the MDT dataset and everyreleases/*/live-databody, and detects these forms. All 2,790 published device-data files scan clean.
- Removed the lab device password from three generator docstrings (example credentials).
Changed — C9300-STACK8-WAN fully collected; duplicate native specs removed (2026-10-04)
- C9300-STACK8-WAN: full MDT run (719 subscriptions; 39 -> 78 MDT paths), SNMP MIB bridge enabled, every GET/subscribe method re-collected over the WAN and the RESTCONF walk extended to the IETF, OpenConfig and other categories (+126 RESTCONF device/path pairs). All 7 devices now report COMPLETE coverage.
native-services-1/2/3.jsonremoved from 17.9.x, 17.12.x, 17.15.x, 17.18.1 and 26.1.1: every path in them is also innative-services.json(26.2.1 never had them). Manifests, path indexes, native capabilities, search, accountability, exports and the 26.1.1 device data were updated; no captured device data was lost (0 device/path pairs dropped).
Changed — 26.2.1 is the default release; device data has its own release (2026-10-04)
- Default: the site opens on 26.2.1, the newest release, and will always default to the newest active release (
test_default_is_newest_release; runbook VERSIONING.md 8.1). Root copies (search index, notifications, accountability, version stats, platform-support index) and the viewers' default were regenerated; hub, About and README figures show 26.2.1. - Device data release:
releases/index.jsongains"device_data": "26.1.1", the release the lab devices run. Device data builders and every collection tool (spec walk, MDT xpaths, MIB catalog, live-data refresh, harness kit) read it viascripts/_release_paths.py, replacing about ten hard-coded26.1.1values. After the lab moves to 26.2.1, changing this one value and re-collecting moves device data to 26.2.1 (VERSIONING.md 8.2). - Viewers: on a release without captures (26.2.1 today) the "Live device data" panel shows the 26.1.1 captures and says which release they came from, instead of disappearing.
- Hub "YANG Source Files" card now follows the selected release (it pointed at 17.18.1 while labelled 26.1.1).
Fixed — specs stamped with the wrong release (2026-10-04)
- Every oper, cfg, IETF, OpenConfig and base native spec in 17.9.x, 17.12.x, 17.15.x, 26.1.1 and 26.2.1 said
info.version: "17.18.1"(1,580 specs), so viewers showed the wrong release. The tree generators dropped the version they were given and the openconfig/ietf/native generators hard-coded it; all now stamp the release they build. The committed specs were corrected in place (onlyinfo.versionand the native manifest'sversionchanged; verified per file), andtests/test_spec_info_version.pyguards it. RPC (YANG revision dates) and MIB/other (1.0.0) keep their own versioning.
Fixed — 26.1.1 leftover tree pages (2026-10-04)
- Removed 27
native-*tree pages fromreleases/26.1.1/yang-trees/that were copied from the pre-release root layout in June: no 26.1.1 YANG source produces them and no other release has them. 26.1.1 accountability was regenerated (24 phantom "modules" gone: 1,444 tracked, 765 with trees), so the 26.1.1 → 26.2.1 accountability delta shows 5 removed modules instead of 29.
Fixed — broken internal links (2026-10-04)
- Tree pages: every per-release tree page (
releases/<ver>/yang-trees/*.html, 4,206 pages) linked one level too shallow, so "OpenAPI Spec", the category link and "Hub" openedreleases/<ver>/swagger-*-model/...and 404'd. Links now reach the site root; events modules link to the notifications catalog (there is no events viewer). Fixed inscripts/generate_all_pyang_trees.pyand in the published pages. - 404 page: GitHub Pages serves it at the missing URL, so its own links resolved under that path and also 404'd. Links now resolve from the site root, and release-scoped URLs redirect:
releases/<ver>/swagger-*-model/...to the viewer with#ver=<ver>, a missing tree page to that release's tree list, andreleases/<ver>/<page>.htmlto the page. - Changelog / App Map / About / Telemetry: links to repo files the site does not publish (
scripts/*.py,VERSIONING.md,CONTRIBUTING.md, ...) now open on GitHub; the shared Markdown renderer does this automatically. - Tree redirect stubs: working fallback links; the MIB tree stub falls back to the release's tree list when a release has no MIB-only index.
- Guard:
tests/test_internal_links.pychecks every static link in all 4,237 published pages against the deployed layout. The data-driven tree links (notifications, accountability, release compare; 7,912) were checked as well and all resolve.
Added — Portable data-collection harness (2026-10-04)
scripts/build_kit.pypackages a self-contained kit to collect from devices on an isolated network: harness and collector code (same relative layout, so the collectors run unchanged), slim release specs (paths and methods only, 12 MB instead of 600 MB), the root catalogs, an offline wheelhouse pinned to the tested environment, a checksum-verified Telegraf 1.40.1 binary,setup.sh, aharnesslauncher, a README andSHA256SUMS.scripts/harness/kit.py(the kit's./harness):doctor,onboard,facts,telegraf start|stop|status,collect(RESTCONF, NETCONF get/get-config/subscribe, gNMI Get/Subscribe, MDT and the RESTCONF spec walk, per device),split-mdt,coverage(the device's own YANG library vs what each method returned; COMPLETE/INCOMPLETE per device) andbundle(masks secret values, refuses to build if a secret remains, sha256 per file).scripts/harness/onboard.pyprepares a new device: local AAA (only when the device has none), HTTPS, RESTCONF, NETCONF, secure gNMI on the self-signed trustpoint and, optionally, the SNMP MIB bridge. Dry run by default;--applybacks up the running-config, checks a fresh login after enabling AAA (rolls AAA back on failure) and only saves with--save.scripts/import_harness_bundle.pybrings a bundle back: it verifies paths, checksums, PIDs and secrets, prints the plan, and with--applymoves replaced files toscripts/harness/import-archive/and rebuilds the Device Data datasets. It refuses imports that would hold less data than today (for example a--limitsmoke run) unless--allow-shrink.build_protocol_matrix.pynow picks up devices whose PID does not start with "C".- MDT collection ignores a device's own standing subscriptions: Telegraf keeps only harness subscription ids (9xxxxx), and batch idle detection counts only those records.
kit collect --timeout(RESTCONF) and--window(NETCONF subscribe) for devices reached over a WAN; collector logs underscripts/harness/kit-run/logs/now show progress while a method runs.build_restconf_augment.py --from-ref HEADkeeps the 186 reconciled RESTCONF roots when the live data is rebuilt from new captures (previously a refresh dropped them).- C9300-STACK8-WAN: SNMP MIB bridge enabled; full MDT and RESTCONF collection in progress.
Added — "What Changed Between Releases" page (2026-10-04)
- New release-compare.html (hub → More → What Changed). For each adjacent release pair it lists modules added, removed and changed with their YANG revision notes, the resolved schema-node differences (from the pyang trees, so groupings, augments and submodules are applied), and per-platform module changes. Each module links to its spec and tree at the right release. For 26.1.1 → 26.2.1 it matches the published source-level overview (+23 / −1 modules, 336 changed files, identical per-platform deltas) and links to it.
- Built by
scripts/build_release_compare.pyfrom pinned inputs only. Schema diffs use trees, not the generated specs, because older releases' specs came from earlier generator versions.
Added — IOS-XE 26.2.1 (2026-10-03)
- New release 26.2.1 from YangModels/yang
vendor/cisco/xe/2621(commitaf8dec84, published 2026-10-02): 953 specs, 243,024 operations, 759 tree pages, Postman/Bruno exports. Listed as newest in the version selector; 26.1.1 stays the default. New in 26.2.1 includes the NGFW and Live Protect families, wireless WAT and Live-Detect, IS-IS operv2, datapath TCAM usage, IIoT power management, config-management RPCs and OpenConfig telemetry;wireless-rrm-emul-operwas removed upstream. - Release pipeline fixes found while onboarding it: the tree step silently produced zero trees when
pyangwas not importable (now aborts);update_manifests.pystill targeted the pre-releases/layout (now takes--versionand keeps generator-written keys and order); the unfinished CLI-mapping / example overlays no longer fail the build when absent; the viewer patcher keeps CRLF line endings. The VERSIONING.md runbook lists the missing steps. - Accountability comparison deltas now read oldest → newest. They were computed in newest-first order, so e.g. the 87 modules added in 26.1.1 showed as "removed".
Fixed — Downloads, CI, accessibility, and test coverage (round 33, 2026-10-03)
- Bruno downloads work again (#12). Collections were gitignored and linked as folders (not downloadable). They are now built at deploy time as reproducible per-category
.tar.gzarchives (13 MB for all 245,767 26.1.1 requests), use{{host}}:{{port}}URLs with collection-level basic auth, and ship anIOS-XEenvironment. Request counts now match each release's operations. - Postman downloads rebuilt the same way. The committed collections were stale (May), hard-coded
{device}/lab-IP URLs, exceeded the 50 MB cap, and still shipped the retired events collection. They are now deploy-built.postman_collection.json.zipfiles (18.6 MB for all 5 releases vs 293 MB of committed JSON) with{{host}}:{{port}}URLs, collection-level basic auth, deterministic IDs, and schema-valid Postman v2.1 JSON. - YANG Accountability no longer reports false gaps. 20–36 notification-only modules per release showed as "no spec" with no explanation; all are in the Event Notifications catalog, which they now link to, and the
eventscategory is shown as excluded instead of 20% coverage. The_paths_indexhelper file is no longer counted as a module (totals −1), and 45–51 verified exclusion reasons per release, lost when the data was regenerated in June, were restored. - Accountability regenerated from the real YANG sources. Each release now uses its own YangModels/yang folder at the commit pinned in
meta.json, instead of falling back to the 17.18.1 set (the generator now fails if the source is missing). 26.1.1 is unchanged. The 17.x reports now count the 204–231native-aug-*specs that shipped in July but had never been counted (17.18.1: 897 of 1,382 modules with specs, previously 666 of 1,151). The generator applies the verified exclusion reasons itself, so release builds no longer drop them, and it keeps the root copy in sync with the default release. - 17.18.1 telemetry annotations restored. The 17.18.1 oper specs had lost all 61 MDT subscription annotations (
x-mdt-*xpath, tier, cadence) that the telemetry index lists; they are back, and a test now keeps every release's specs and index in sync. The telemetry indexes now use forward-slash paths and current operation IDs. Both inputs were re-verified against the published telemetry reference andMIBS.md, which reproduce the committed data exactly. scripts/_release_paths.pycommitted. It was hidden by ascripts/_*.pygitignore rule, breaking 10 generators on fresh clones. Stale artifacts it feeds were refreshed (accountability_compare.json, older releases'native-capabilities.json).- Scheduled CI green again: htmlhint (single-quoted attribute), axe (Chrome/ChromeDriver mismatch + Ubuntu 24.04 sandbox; now scans all 21 published pages), lychee (unresolvable action pin, removed
--exclude-mail, fixed broken links), G-6 refresh (missing labels; no more timestamp-only PRs). All GitHub Actions bumped to current SHA-pinned versions. - Accessibility: theme toggle has an accessible name, shared muted text meets 4.5:1, unlabeled selects labelled, scroll regions keyboard-focusable — 0 blocking axe findings. Color contrast of the legacy brand palette is reported (non-blocking) pending a design call.
- Analytics: Clarity's image beacon was blocked by every page's CSP; allowlisted.
- Dark mode: pages with hardcoded white cards (YANG Accountability, About, Exports) rendered near-white text on white in dark mode; cards, text and stat tiles now follow the dark tokens. Status badges use the shared contrast-safe status colors. Contrast findings across the 21 pages: light 697 -> 67, dark 1,089 -> 75 (the remainder is the per-category color system).
- CI coverage: the
testsworkflow now runs repo + harness tests on every push tomain(it previously ran onlytests/, and only for spec/release path changes). - Footer build label was stuck at round 25; now tied to the latest CHANGELOG round by a test.
- Viewer banner:
live-modules.jsonnow lists all 7 devices / 319 modules (was 6 / 311). - Tests: smoke S-8 (Device Data + datasets), S-9 (every export download), S-10 (remaining pages); security scan auto-covers every published page and its scripts; service-worker precache, export-manifest, live-modules and helper-import guards.
- Harness: gated
crud.pywrite path (dry-run default,writableguard, backup, rollback) with offline safety tests; read-onlydevice_readiness.py; MIB coverage reconciled per module inverify.py.
Added — Device Data page: unified MDT + RESTCONF browser (round 32, 2026-08-01)
- One page for all collected device data — device-data.html. Consolidates the previous Telemetry Data, Fleet Telemetry, and Live Device Data pages into a single Device Data browser with a transport selector: Model-Driven Telemetry (push · gRPC dial-out) and RESTCONF (pull · HTTPS GET). One UI for both — device (PID) tabs, model-flavor filter, a searchable path list, transport-aware summary tiles + Chart.js charts, and a per-path detail.
- MDT view. Real telemetry captured live from the lab fleet (C9200 / C9300 / C9400 / C9500 and a C9800 WLC, IOS XE 26.1.1) via a Telegraf
cisco_telemetry_mdtreceiver; the detail shows the streamed list keys and every captured instance's leaf values. Search matches paths, keys, and values. Data:telemetry-live-data.json(built bybuild_live_dataset.py). - RESTCONF view. Real GET responses captured per device; the detail lazily fetches and pretty-prints the exact payload. Data:
restconf-live-data.json(built byscripts/build_restconf_dataset.pyfrom the release live-examples index); payloads served on demand fromreleases/<ver>/live-data/.... - Copy. Each detail has Copy payload (full JSON) and Copy path buttons.
- Removed the now-redundant
telemetry-data.{html,js,json}andlive-data.{html,js}pages (plus the orphanedbuild_telemetry_dataset.py); nav, hub Tools bar, sitemap, service worker, security tests, the in-viewer "Live device data" banner deep-link, and docs are rewired to Device Data.
Changed — Live Data hardening, honest coverage, depth verification (round 31, 2026-07-31)
- Redaction hardened for bare auth leaves.
scripts/harness/redact.pynow also masks module-prefixed secret leaves whose names don't contain "password"/"secret" — radius/tacacskey, routing-authmd5,message-digest-key, key-chains — and strips the RESTCONF module prefix (Cisco-IOS-XE-aaa:key) before matching so a namespace can't dodge redaction.build_live_examples_index.pyre-scrubs every value at publish time, so committed data files never carry a secret even if a capture predates the fix.secret_scan.pygained a matching prefix-aware pattern. - Honest coverage metric. The Live Data coverage bar now shows module coverage (captured modules ÷ modules in that category) instead of a per-leaf path percentage — the path total is dominated by keyed-list entries and deep native-config leaves, which made the old figure misleadingly low (~1–3%).
- Capture date + coverage note. The page shows "Captured
<date>· IOS XE<ver>" (from newcaptured_from/captured_toin the index) and a note explaining the coverage denominator. - Simple release gate. A test scans
releases/26.1.1/live-datafor secrets as a backstop to publish-time redaction. - Refresh wrapper.
scripts/refresh_live_data.py --version 26.1.1 [--capture]rebuilds the sidecar from local captures and regenerates the index + per-path files in one command. - Depth probe (read-only).
scripts/harness/depth_probe.pyanswers "does a deeper keyed GET return more data than the parent?" — see DEVICE_DATA_COLLECTION.md §4.1. Full fleet sweep (6 devices × 7 categories, 26.1.1) ran with a circuit breaker armed — zero crashes, zero breaker trips. Only three modules ever returned a container the module-root GET omitted (aaa-oper/aaa-users,mdt-oper-v2/mdt-subscriptions,yang-interfaces-cfg/general), and all three are already captured independently by the exhaustive per-path GET — so there is no data gap and no keyed-list path hid data a parent GET didn't already return. The probe reusesrestconf_get(retry/backoff + reset detection), a circuit breaker, the known-unsafe-module skip, and--resume.
Added — Live device data: real captured RESTCONF responses + interactive browser (round 30, 2026-07-31)
- Real device responses captured, kept out of the specs. Every operational, config and MIB GET was captured from physical Catalyst hardware (C9200 / C9300 / C9400 / C9500 / C9600 and a C9800 wireless controller, IOS XE 26.1.1). The OpenAPI specs keep ONLY their synthetic, schema-typed
example, so the Swagger viewers stay lean and fast; the real responses are served separately (below), keyed by device PID so the same path carries samples from multiple platforms. No path / operation / module counts change (G-6 safe). - New interactive Live Data browser — device-data.html (later merged into the unified Device Data page). A dedicated hub page for exploring the captured responses: device platform tabs (one per PID), per-category coverage cards (captured vs total paths for the active device), a searchable module / path browser with category filters, and a drill-down that fetches a single small per-path data file on demand and shows the exact response the switch returned. Deep-linkable (
?ver=…#module=…&path=…&pid=…); CSP-safe (external JS, DOM-only, noinnerHTML). Reachable from the hub Tools bar. - In-viewer banner. Every
swagger-*-modelviewer shows a compact "Live device data" banner above a module's spec when real captures exist for it, deep-linking into the Live Data browser. It reads a tiny per-release module summary (live-modules.json, ~32 KB — no bodies) and refreshes on in-page module switches — fixing a stale-panel bug where a previous module's data could linger (the viewer swaps modules viahistory.replaceState, which does not firehashchange). - Build pipeline + committable data. The harness emits a gitignored sidecar (
references/live-examples-<ver>.json) from the local captures;scripts/build_live_examples_index.pyturns it into the committed, served artifacts underreleases/<ver>/: a lightweightlive-examples-index.json(coverage + navigation, no bodies), a tinylive-modules.json(for the viewer banner), and one smalllive-data/<category>/<module>/<hash>.jsonper captured path holding the actual response body. The Swagger specs are never modified — they stay lean. Wired intoscripts/build_release.py; raw captures and credentials stay local (gitignored). - Multi-device capture. Real responses were collected from six physical platforms — C9200, C9300-24UX, C9400, C9500, C9600, and a C9800 wireless controller (all IOS XE 26.1.1) — giving 311 modules / 2,699 captured paths keyed by PID (oper, config, MIB, OpenConfig, IETF and other categories). Devices are collected as independent per-device processes (parallelizable), since each box's datastore contends only with itself. MIB coverage requires the SNMP agent +
netconf-yang cisco-ia snmp-community-stringbridge, which was configured on the switches to expose MIB data over RESTCONF. - 409/429 (datastore busy) retry. IOS XE serializes config-datastore RESTCONF GETs, so parallel workers collide and the device returns
409(on the 4 newer devices ~49k config paths409'd at concurrency 6, while single- threaded they return200).scripts/harness/request.pynow treats409/429as retryable — it waits (jittered backoff) and retries on a budget separate from the 5xx/connection retries, so the collector stays concurrent and self- throttles to whatever the datastore can serve. Tunable via the collector's--conflict-retries/--conflict-backoffflags. This recovered the config / openconfig / ietf / mib / other coverage those devices were missing. - Service worker bumped to
v92-2026.07.30e;live-data.html+live-data.jsadded to the precache list.
Added — Native completeness, workflow analytics, dark mode & richer examples (round 29, 2026-07-30)
- Native config model — deep augment backfill to every release. Only 26.1.1 shipped the fully augment/uses-resolved
native-aug-*.jsonspecs; the four older releases carried a shallow native model (basecontainer nativeonly), missing the routing / ip / ipv6 / crypto / snmp-server / nat / line / vrf / logging / parameter-map subtrees that ~130 externalCisco-IOS-XE-*modules contribute viaaugmentand cross-moduleuses. Ranscripts/generate_native_augmented.py --interface-mode skip --max-depth 5for 17.9.x / 17.12.x / 17.15.x / 17.18.1, adding +21,141 / +21,556 / +23,356 / +24,265 RESTCONF config paths respectively. The/native/interfacemega-container is left as already shipped on the older releases to stay within the site size budget; 26.1.1 continues to carry full interface augments. Per-releasesearch-index.json+_paths_index.jsonrebuilt, manifests reconciled,release_counts.jsonbaseline refreshed. All five releases passvalidate_release.pygates 1–6, the strict path-depth audit, and the G-1 gate.releases/**is service-worker network-only, so no cache bump is required.
- Complete workflow analytics lifecycle.
assets/js/analytics.jsgainedstartWorkflow()/completeWorkflow()with a correlatedworkflow_id,duration_ms, and astatusofsuccess | failed | abandoned. Failures now emitstatus: 'failed'with anerror_type—missing_host/missing_pathwhen the code generator has no runnable target,spec_load_failedwhen a telemetry module spec cannot be fetched. Any workflow still open when the page is left is flushed asabandonedonpagehide(notvisibilitychange, so a tab-switch-and-return is not miscounted). Two new canonical workflows joincode_generatedandtelemetry_subscription_built:spec_explored(opening a spec in a viewer → expanding an operation) anddata_model_explored(selecting an event model in Notifications → copying an example). This enables free PostHog funnels and drop-off/duration trends.
- Dark-mode correctness across the site. The hub,
tree-compare.html, and all nineswagger-*-modelviewers now render correctly in dark mode. The hub and compare page had an inline[data-theme="dark"]variable block that tied withsite.css's--c-surfacetokens at equal specificity (site.css loaded later, so it won and surfaces stayed light); raising the inline block to:root[data-theme="dark"]fixes it. The viewers already had an extensive dark theme inassets/css/viewer.css; the one remaining gap — the hardcodedbody { background:#fafafa }in each viewer's inline<style>— is now overridden with a dark base background applied to all nine viewers at once.
- Richer, schema-typed examples.
scripts/enrich_v2_specs.pygained schema-type-paired enrichment (enum/format awareness, operational-telemetry heuristics, PID disambiguation, placeholder replacement) and was applied across all five releases and all nine categories, replacing generic placeholder values with realistic, type-correct example data wherever the flattened GET schemas allow it.
- Category card icons + service worker bumped to
v88-2026.07.30a.
Changed — Hub navigation redesign: compact Tools / Models / Docs bar (round 28, 2026-07)
- One tidy, left-aligned quick-nav bar. The hub's top toolbar was a crowded, centre-justified wrap of a dozen equally-weighted pills (a lone "Platform Coverage" kept orphaning onto its own line). It is now a single compact bar split into three labelled, divider-separated groups: Tools (interactive features), Models (the 9 data-model viewers), and Docs (App Map, About, GitHub, Changelog).
- Primary tools stay visible; secondary tools fold into a "More" menu. Search, Code Generator, YANG Report, Telemetry & Notifications, and Exports remain as top-level pills. Compare Trees, Compare Versions, Trees, and Platform Coverage moved into a More dropdown. The dropdown is a pure-CSS native
<details>element with no JavaScript, so it respects the hub's strictscript-src 'self'CSP and is keyboard-accessible for free. - Auto-hide hardened. The scroll-away nav collapse now also toggles
visibilityandpointer-events, so switching the bar tooverflow:visible(needed so the dropdown can escape the bar) never leaves invisible but still-clickable links hovering over the page when the nav is hidden. - Service worker bumped to
v79-2026.07.17d.
Added — Shareable deep-links + xpath usage analytics on Telemetry & Notifications (round 27, 2026-07)
- Copy-a-link, reopen-the-same-view. Both panes of
telemetry.html— the Telemetry XPaths builder and the Event Notifications catalog — now serialize their full selection into the URL hash viahistory.replaceState(no history spam, nohashchangeloops). A shared link restores the exact release, category, module, xpath, transport, and filters, and rebuilds the subscription snippet. - Non-clobbering hash schema. The two panes own disjoint keys — Telemetry XPaths owns
tab / ver / cat / mod / xpath / xport; Event Notifications ownsq / ntransport / ncat / nmod;verandtabare shared. Each pane preserves the other's keys when it writes, so switching tabs never wipes the other pane's state. A new Copy link button was added to each pane. - XPath usage analytics.
telemetry_xpath_usedandtelemetry_xpath_copiednow carryxpath,yang_model,model_category, andtransport, so the analytics dashboards can report which telemetry xpaths and YANG models people actually build subscriptions from. All keys pass the analytics PII allow-list. - Service worker bumped to
v77-2026.07.17b.
Added — Privacy-first product analytics: PostHog + Microsoft Clarity (round 26, 2026-07)
- One wrapper, two providers. Added
assets/js/analytics.jsexposingwindow.analytics, which fans every event out to both PostHog (product analytics / funnels / breakdowns) and Microsoft Clarity (heatmaps and session recordings). It also re-points the legacywindow.__iosxeTrackhook through itself, so existing call sites reach PostHog too. - Public, swappable config.
assets/js/analytics-config.jsholds the PostHog publicphc_project key + host and the app-version / environment overrides. The key is a client-side write key (safe to ship, like a Clarity id); leaving the placeholder disables PostHog while Clarity keeps working (fail-open, never breaks a page). - Privacy by default. Honors the browser Do-Not-Track signal for both providers; a
sanitize()layer drops or redacts PII (emails, IPv4s, hostnames, serials, tokens, full URLs) before any event leaves the browser; autocapture, pageview URL capture, and cross-page session URLs are off, and only a curated allow-list of non-PII keys (yang_model,xpath,api_path,model_category,release,transport,http_code,result,page_or_section) is forwarded. - Events wired across the site.
app_loaded,data_model_selected,api_operation_selected,api_request/api_error,export_results, andworkflow_completed, plus the telemetry / notifications specifics above. Seedocs/ANALYTICS.mdfor the full event table and dashboard breakdowns. - Service worker precaches the analytics files; consolidated at
v76-2026.07.17a.
Security — externalize SW registration + regression tests (round 25, 2026)
- Closed the CSP / inline-script gap. Top-level pages ship
script-src 'self'(no'unsafe-inline'), but the PWA service worker registration + update-toast block was injected inline, which modern browsers refuse to execute. The whole snippet moved toassets/js/sw-register.jsandscripts/inject_pwa.pynow emits<script src="assets/js/sw-register.js" defer></script>. The new module derives its SW URL + scope fromdocument.currentScript.src, so the same file works from the site root and from every viewer subdirectory. - Added
tests/test_security_regressions.pywith three parameterised guards: (a) URL-fragment / query-string values must not flow intoinnerHTML/outerHTML/document.write/insertAdjacentHTML; (b)location.href/assign/replaceassignments built from concatenation must carry a whitelist guard for the destination (catches the round-24javascript:URL exploit shape); (c) strict-CSP pages must not contain inline executable<script>blocks (JSON-LD data blocks and external<script src=...>exempted). 44 new assertions, all green. - Service worker bumped to
v18-2026.05.23and now precachesassets/js/sw-register.jsso offline reloads still see the new module.
[Pre-Unreleased — round 24]
Security — Reflected-XSS fixes in 404 + hub deep-link (round 24, 2026)
- Fixed reflected XSS in
404.htmlhash-recovery flow. When the deep-link recovery routine surfaces the “Redirecting you to …” notice, the values ofparams.specandparams.op(parsed from the URL fragment) used to flow intoinnerHTMLunescaped. A crafted URL like/404.html#spec=Cisco-IOS-XE-mib<img src=x onerror=...>would have executed the payload. The notice is now assembled with DOM nodes (textContent/createElement) so the fragment is rendered as text. - Fixed open-redirect /
javascript:URL injection on the hub#spec=model/namedeep-link.search.jspreviously didwindow.location.href = modelDir + '/index.html#spec=' + specNamewith no validation, allowing#spec=javascript:alert(1)/xto execute the JS payload via thejavascript:URL scheme. The redirect now refuses anymodelDirthat isn’t in the known whitelist of viewer category directories, andspecNameisencodeURIComponent-encoded. - Service worker bumped to
v17-2026.05.23.
[Pre-Unreleased — round 23]
Added — 404 polish, format-detection, robots noindex (round 23, 2026)
- 404 page polish. Now declares
theme-color(light/dark variants) so the mobile status bar matches the rest of the site, and emitsrobots: noindex, followso search engines don’t index error pages. format-detection: telephone=noadded to every top-level page so iOS Safari stops auto-linking version numbers like17.9.5and module dotted-paths as phone numbers.- Service worker bumped to
v16-2026.05.23.
[Pre-Unreleased — round 22]
Added — Heading permalink anchors (round 22, 2026)
- Heading anchors. Long-form pages tagged with
<body data-anchors="on">now grow a small pilcrow (¶) next to eachh2[id]/h3[id]/h4[id]on hover or keyboard focus. Click the pilcrow to jump to that section and copy the deep-link URL to the clipboard so it can be shared. Enabled onabout.html; other pages can opt in by setting the body attribute. - Service worker bumped to
v15-2026.05.23.
[Pre-Unreleased — round 21]
Added — BreadcrumbList + viewer ItemList JSON-LD (round 21, 2026)
- BreadcrumbList structured data on every top-level non-hub page (About, Accountability, Tree Compare, Code Generator, Exports, Telemetry) — helps Google render breadcrumbs in search results.
- Hub ItemList JSON-LD enumerating all 9 viewer categories (Native config / oper, Operational, IETF, OpenConfig, RPC, Events, MIB, Other) so search engines can surface direct links to each category.
- Service worker bumped to
v14-2026.05.23.
[Pre-Unreleased — round 20]
Added — Footer aria-current, Edit-on-GitHub, robots hints (round 20, 2026)
- Footer marks the active page. Links in the global footer that point at the page you’re currently viewing now emit
aria-current="page"so screen readers announce them as the current location, and a subtle bold/solid-underline treatment makes the active link easy to spot visually. - Edit on GitHub. Top-level pages (hub, About, Accountability, Compare, Code Gen, Exports, Telemetry) now expose an
Edit on GitHublink in the footer that opens the current page’s source file in the GitHub web editor on a new tab. Subdir viewer pages (which are generated) deliberately omit the link. max-image-preview:largerobots hint added on every top-level page so Google can render rich, larger thumbnails in search results.- Service worker bumped to
v13-2026.05.23.
[Pre-Unreleased — round 19]
Added — Hub SearchAction, offline 404 hint (round 19, 2026)
- Hub JSON-LD extended with
SearchAction. Google can now show a sitelinks search box that posts queries tohttps://…/?q={search_term_string}.search.jsbridges?q=to the existing#search=deep-link format, so the SearchAction lands on a real, fully-rendered result list. JSON-LD also now declarespublisher: Cisco DevNetandinLanguage: en. - 404 offline hint. When
navigator.onLine === false, the 404 page rewrites its message to explain that the page may exist but couldn’t load, and reminds the visitor that cached pages (Home, About, Accountability, Compare, Code Gen, Exports) still work. When the browser comes back online, an inline note suggests reloading. - Service worker bumped to
v12-2026.05.23.
[Pre-Unreleased — round 18]
Added — Search clear button, SEO JSON-LD (round 18, 2026)
- Native search clear-X on all filter inputs. Switched the universal search box (hub), modules filter (accountability), spec picker filter (code generator), and both per-side tree filters (tree-compare) from
<input type="text">to<input type="search">. Browsers render a built-in clear button when there's content, andautocomplete="off"+spellcheck="false"keep autofill/red-squiggle noise out of the way. - Themed clear button. Added a custom
::-webkit-search-cancel-buttonrule in assets/css/site.css so the X is visible on both light and dark backgrounds (it's near-invisible by default in dark mode). - JSON-LD structured data on About page. Added a Schema.org
WebSite+WebPage+Organizationgraph so search engines surface the page with rich metadata (name, audience, publisher). No CSP impact —application/ld+jsonisn't an executable script. - Service worker bumped to
v11-2026.05.23.
[Pre-Unreleased — round 17]
Added — Telemetry shortcuts, smooth anchors (round 17, 2026)
- Telemetry page shortcut keys. New keybindings surfaced in the
?dialog:/focus path filter,EExport CSV,CCopy YANG-push snippet. Same INPUT/TEXTAREA guard pattern as the other page-level shortcut sets. - Smooth anchor scrolling + sticky-header offset. Anchor links now scroll with
scroll-behavior: smoothsite-wide, and every heading / section with anidreservesscroll-margin-top: 80pxso the jumped-to element clears any sticky nav (e.g. the tree-compare controls bar) instead of hiding behind it. Honorsprefers-reduced-motion. - Service worker bumped to
v10-2026.05.23.
[Pre-Unreleased — round 16]
Added — Hub shortcut, tree-compare empty state (round 16, 2026)
- Hub keyboard shortcut:
/orCtrl/Cmd+Kfocuses the universal search. The search box placeholder has long advertised this, and now it actually works. Honors INPUT/TEXTAREA/contentEditable guards. Surfaced in the?help dialog. - Tree-compare empty-state placeholders. Before any module is chosen, each side of the split view now shows a friendly empty state (“Pick a module above ←” / “→”) that explains what the panel does, mentions sync-scroll + diff highlighting, and hints at the
?shortcut. Styled to match the surrounding viewer chrome and to work in both light and dark themes. - Service worker bumped to
v9-2026.05.23.
[Pre-Unreleased — round 15]
Added — Copy-as-text, footer build link, SW precache (round 15, 2026)
- Copy as Text on yang-accountability. New
Copy as Textbutton next toExport CSVproduces a paste-ready plain-text report of the currently filtered modules: header summary (release, totals, filter state) plus an aligned name/spec/tree/categories table. Truncates after 200 rows with a+N morefooter and points at CSV for the full set. Uses clipboard API with execCommand fallback for older browsers. - Page shortcut keys on yang-accountability. New keybindings surfaced in the
?dialog:EExport CSV,TCopy as Text,LShare Link,/focus search box. Standard guards for INPUT/TEXTAREA/contentEditable targets. - Build badge in footer links to changelog. The
Build v… (round N)label in the global footer is now an anchor toCHANGELOG.md#unreleased, with a dotted underline that turns solid on hover, so anyone can see exactly what shipped in this build. - Service worker precache widened. Added
about.html,yang-accountability.html,tree-compare.html,code-generator.html, andexports.htmlto the precache list so the top-level navigation resolves instantly after the first visit / installs PWA mode with the full app shell available offline. - Service worker bumped to
v8-2026.05.23.
[Pre-Unreleased — round 14]
Added — Issue templates, skeletons, PWA install, perf hints (round 14, 2026)
- GitHub issue + PR templates. New
.github/ISSUE_TEMPLATE/with three templates (bug_report.md,feature_request.md,spec_accuracy.md) and aconfig.ymlthat disables blank issues, routes upstream YANG bugs toYangModels/yang, and links to Cisco DevNet + GitHub Discussions. New.github/PULL_REQUEST_TEMPLATE.mdcovers change type, validation checklist, screenshots, and reviewer notes — making the About-page “Open a bug report” / “Request a feature” deep links land on a guided form. - Loading skeleton on
yang-accountability.html. While the per-release JSON is in flight, the table now renders eight pulse-animated skeleton rows and stat-card placeholders instead of an empty table. Honorsprefers-reduced-motion, dark-mode aware. Skeleton CSS in assets/css/site.css is reusable (.skeleton-bar,.skeleton-row). - PWA install prompt UX.
site-chrome.jsnow interceptsbeforeinstallprompt, suppresses the browser default mini-infobar, and surfaces a dismissable Install / Not now toast (bottom-left, dark-mode aware, responsive). “Not now” sets a 30-day cooldown in localStorage; if the user starts the prompt but cancels we cool down for 7 days; if they install we never prompt again. Opt-out via<body data-pwa-prompt="off">. - Performance hints. Added
<link rel="preconnect">tofonts.googleapis.comandfonts.gstatic.comon the four top-level pages that pull Roboto / Roboto Mono (index, code-generator, yang-accountability, about). Trims first-paint cost on cold-cache visits. - Service worker bumped to
v7-2026.05.23.
[Pre-Unreleased — round 13]
Added — About page, engagement CTAs, footer links (round 13, 2026)
- New
about.html— a technical-marketing landing page covering project mission, by-the-numbers stats (608 specs / 37,072 paths / 1,125 modules / 765 trees / 9 categories / 5 releases / 100% accountability), what you can do here (8 capability cards), releases table, architecture summary, and a dedicated “Open an issue, give feedback, or contribute” section with deep links into the GitHub bug-report / feature-request templates, Discussions, CONTRIBUTING.md, and the changelog. Credits / licensing block clarifies upstream YangModels licensing, Swagger UI attribution, and the not-an-official-Cisco-product disclaimer. - Header nav and footer now include an “About” link on every page; the shared footer also gains a direct “Open an issue” link to the GitHub Issues new-issue flow.
- Sitemap grown to 17 entries with
about.htmland refreshedlastmod. - Emoji-guard test now also gates
about.html, keeping the page free of decorative glyphs while still allowing HTML entities like—,©, and the functional KEEP-listed monochrome symbols. - Service worker bumped to
v6-2026.05.23so returning visitors land on the new About page and refreshed footer immediately.
[Pre-Unreleased — round 12]
Added — Page shortcuts, shared footer, copy-as-text (round 12, 2026)
- Page-specific keyboard shortcuts.
tree-compare.htmlnow responds toS(Sync Scroll),H(Highlight Diffs),E(Export),C(Copy as Text), andL(Copy Share Link).code-generator.htmlresponds toG(generate),L(Copy Share Link),X(Clear). Each page pushes its bindings ontowindow.__SHORTCUTSso the?help dialog shows them alongside the global shortcuts. All bindings ignore typing targets (inputs / textareas / selects / contenteditable) and modifier keys. - "Copy as Text" on
tree-compare.html— new button next to Export that copies the same side-by-side comparison report (header + Left tree + Right tree) to the clipboard with a 3-second "Copied!" flash and graceful fallback for older browsers. - Shared site footer injected by
site-chrome.json every page (opt-out via<body data-footer="off">). Carries quick links (Home / Accountability / Compare / Exports / Changelog) and a build badge (SITE_BUILD) for cache- busting triage. Footer is hidden in print and styled for both light + dark themes; collapses to a stacked layout below 640 px. - Service worker bumped to
v5-2026.05.22so returning visitors pick up the new page bindings, Copy-as-Text button, and footer immediately.
[Pre-Unreleased — round 11]
Added — UX polish, print, back-to-top, persistence (round 11, 2026)
- Print stylesheet —
@media printblock in assets/css/site.css now hides chrome (headers, dark toggle, share/CSV buttons, Swagger UI topbar, iframes) and forces a light palette with bordered tables, page-break avoidance on rows/cards, and full URLs appended after external links. Yang accountability, telemetry, exports, and the compare matrices print cleanly to PDF. - Floating "Back to top" button — site-chrome now injects a single shared Back-to-top control that appears after ~400 px of scroll on every page. Uses smooth scrolling, restores focus to
#main-content/main/h1, ships properaria-label/title, respects dark mode, and may be suppressed per page via<body data-back-to-top="off">. - Tree-compare toggle persistence —
Sync ScrollandHighlight Diffsstates are now persisted tolocalStorage(iosxe-tree-compare-prefs) and rehydrated on load witharia-pressedreflecting the active state. - Empty-state polish on yang-accountability — when filters return zero modules the empty row now shows a friendlier message plus a "Clear filters" button that wipes the search box, resets category + status to
all, syncs the filter-button visuals, refreshes the hash, and focuses the search box. - Service worker bumped to
v4-2026.05.22so returning visitors pick up the print stylesheet + back-to-top button immediately.
[Pre-Unreleased — round 10]
Added — UX polish, deep-links, CSV export (round 10, 2026)
- Keyboard shortcut help dialog — press
?on any page to open a focused, Esc-dismissable modal listing global shortcuts (/,Ctrl+K,Esc,Tab,Shift+Tab,Enter). Implemented in assets/js/site-chrome.js with proper focus management (returns focus on close,aria-modal,aria-labelledby). Pages may extend viawindow.__SHORTCUTS. A discoverable "? Shortcuts" button sits next to the hub search bar. yang-accountability.htmlExport CSV — downloads the currently-filtered rows as a UTF-8 BOM, RFC 4180-quoted.csvnamedyang-accountability-<ver>-<date>.csv. Columns: Module Name, Classification, Categories, Has Spec, Has Tree, Spec URLs, Tree URL, Reason Excluded.telemetry.htmlExport CSV — downloads visible Method / OpenAPI path / MDT filter xpath rows astelemetry-paths-<ver>-<spec>-<date>.csvhonoring the active path filter.yang-accountability.htmldeep-links + Copy Share Link — URL hash now preservesver,q,cat,status; filter buttons sync to URL on every change. A new Copy Share Link button reproduces the exact filter state.code-generator.htmldeep-links + Copy Share Link + version-aware picker —ver=&category=&spec=&path=&method=hash schema; per-release search-index fallback; never persists credentials.exports.htmlfilter bar — release dropdown + Postman / Bruno / All toggle with hash sync (#ver=&format=), live totals (requests + bytes), and basename-only Path display with full path in tooltip.- Postman split-by-category — each release ships 9 per-category Postman v2.1 collections to stay under GitHub's 50 MB recommended limit. Max shard 22.7 MB (native-config 26.1.1).
- Sitemap refresh + sitemap generator —
python scripts/generate_sitemap.pyrefresheslastmodon all 16 entries to today. - Accessibility —
aria-labelon filter inputs across code-generator, yang-accountability, yang-accountability-compare, tree-compare, telemetry; keyboard-activatable native-config search-clear span; close-buttonaria-labelon the code-snippet modal. - Generator output paths — Postman + Bruno manifests now write POSIX paths (forward slashes) regardless of host OS, so download links on the live site work correctly when generators run on Windows.
- Terminology — "Has Swagger Spec:" → "Has OpenAPI Spec:" on the hub.
- Service worker —
CACHE_VERSIONbumped tov3-2026.05.22to ensure returning visitors pick up this round's changes.
Added — Site quality, PWA, and per-release exports (round 9, 2026)
- Lighthouse strict + axe-core CI — site quality gates (Tier 3) added to the deploy workflow, blocking regressions in performance, accessibility, best-practices, and SEO.
- JSON minify + htmlhint (Tier 4) — deploy step now minifies JSON data files and runs htmlhint over every shipped HTML page.
- search-index v3.1 slim-down (Tier 5 + 8) — scripts/generate_search_index.py now drops empty fields and truncates module descriptions at a 160-char word boundary (down from 250). Combined effect:
search-index.jsonshipped size 1,124,074 → 1,096,810 B (−2.4% pretty, larger savings post-CI minify);max-desc-lencapped at 162. - PWA service worker + manifest (Tier 6) — service-worker.js pre-caches the app shell and serves it offline. site.webmanifest registered on all 17 top-level pages by scripts/inject_pwa.py.
- Deep-link scroll-position memory (Tier 7) — deeplink.js now stores the last
op=location underiosxe-scroll-<spec>and restores it after spec load, so refreshing or returning to a deep-link lands on the same operation row instead of the top of the page. - Update-available toast (Tier 9) — when a new service worker reaches
installedwhile an existing controller is in charge, all pages surface a small bottom-right card with a Reload button. Reload posts{type:'SKIP_WAITING'}; thecontrollerchangelistener then refreshes the page exactly once.CACHE_VERSIONbumped tov2-2026.05.20. Inline registration is CSP-safe (role=status,aria-live=polite, dismiss button, fail-silent). - Per-release Postman + Bruno exports for all 5 releases —
releases/<ver>/exports/now exists for 17.9.x, 17.12.x, 17.15.x, 17.18.1 and 26.1.1, each with 9 per-category Postman v2.1 collections, a Postman environment, apostman-manifest.json, and abruno-manifest.json. Bruno collection content remains git-ignored and is regenerated locally via scripts/generate_bruno_collection.py. Per-release request totals: 17.9.x=52,170 / 17.12.x=54,164 / 17.15.x=58,874 / 17.18.1=68,353 / 26.1.1=63,541. Cisco-IOS-XE-bgp-route-operexclusion reason —yang_accountability.json(root + all 5 per-release files) and YANG_MODULE_ACCOUNTABILITY.md updated to record"Source YANG not bundled with model package"instead ofnull.- FAQ.md — new top-level FAQ covering offline use, Catalyst 9k API discovery, on-device validation, MDT subscription, and Postman/Bruno consumption.
Added — Hub-level cross-category operation search & d8 spec depth (round 8, 2026)
- hub-search-ops.js — augments the universal search box on the landing page (
#universalSearch) with a new "Operations matching" section that surfaces individual API operations across all 9 viewer categories. Lazy-loads each category's_paths_index.json(built by scripts/build_paths_index.py) on the first user query and caches in memory. Each hit renders HTTP-method badges (GET/POST/PUT/PATCH/DELETE colour-coded) and clicks deep-link toswagger-<cat>-model/index.html#spec=<module>&op=<operationId>, handled by deeplink.js in each viewer (auto-loads spec, expands the operation row). CSP-strict (same-origin script, noeval, no inline handlers). - Depth-d8 cfg / oper specs (26.1.1) —
generate_cfg_from_tree.pyandgenerate_oper_from_tree.pymax_depthraised from 6 → 8 in bothcollect_deep_paths()andprocess_tree_file(). 26.1.1 now publishes:- cfg : 2559 paths, 10083 operations, 40 specs (+25 paths at d7 + d8)
- oper: 22144 paths, 215 specs (+566 paths at d7 + d8)
- Audit floor tightened — scripts/audit_path_depth.py
MIN_MAX_DEPTHraised cfg / oper 6 → 7. Strict mode now blocks any future regression below d7 for those two categories. - 17.x backport (shipped) — the from-tree generators were rolled out to 17.9.x, 17.12.x and 17.15.x via
_resolve_paths(version)(releases/<ver>/yang-trees/). Followed byenrich,github-links,external-docs,tree-links,mdt-annotate,manifests,stamp-spec-count,search-indexandpath-depth-audit. Depth gains:- 17.9.x : cfg 643→2519 (d2→d8), oper 1907→17136 (d3→d8), events 52→699 (d1→d2)
- 17.12.x: cfg 601→2512 (d2→d8), oper 2226→19042 (d3→d8), events 54→710 (d1→d2)
- 17.15.x: cfg 579→2546 (d2→d8), oper 2426→20465 (d3→d8), events 70→799 (d1→d2) All four active releases (17.9.x, 17.12.x, 17.15.x, 26.1.1) now PASS the strict path-depth audit floor. 17.18.1 still uses the legacy top-level
api/layout and was intentionally left untouched.
Added — Path-depth audit, tree-based generators & cross-chunk operation search (rounds 6–7, 2026)
- Tree-based generators for cfg / oper / events — generators/generate_cfg_from_tree.py, generators/generate_oper_from_tree.py and generators/generate_events_from_tree.py replace the older regex-based generators in scripts/build_release.py's
cfg-specs,oper-specsandevents-specssteps. Tree parsers walk the pyang HTML output and emit one operation per node up to the configuredmax_depth, mirroring the same approach already used by thenative_from_treeandopenconfig_from_treegenerators. On 26.1.1 this produced ~4× more cfg paths, ~7.8× more oper paths and ~10.8× more events paths versus the previous regex passes. - scripts/audit_path_depth.py — new build step that walks every
releases/<ver>/swagger-<cat>-model/api/*.json, computes a per-category depth distribution +max-depth, writesreleases/<ver>/path_depth_audit.jsonand (in--strictmode, used bybuild_release.py) fails the build if any category is below itsMIN_MAX_DEPTHfloor. Floors at end of round 7: cfg=6, oper=6, native-config=6, ietf=3, openconfig=3, other=3, events=2, mib=2, rpc=1. - Cross-chunk operation search in all 9 viewers —
paths-search.js(canonical copy in swagger-native-config-model/paths-search.js) is wired into every viewer (cfg,events,ietf,mib,native-config,openconfig,oper,other,rpc). The IIFE hooks the viewer's#searchBoxand queries the category-scoped_paths_index.json, so a path/op search resolves across all spec chunks in the category, not just the one currently rendered. 80 ms input debounce,MIN_QUERY=2,MAX_HITS=60. The hook self-skips on releases other than 26.1.1. - Spec-count manifest fixes — both scripts/stamp_spec_count.py and scripts/update_manifests.py now exclude
manifest.jsonand_paths_index.jsonwhen counting specs, so the published counts stay correct after the paths-index file landed inapi/. - Multi-root merge in
generate_cfg_from_tree.py— earlier the cfg generator emitted separate spec files perdataroot, causing 40 files vs 90 modules. The from-tree port now merges roots per module name (matching the oper generator), restoring 1-spec-per-module parity.
Added — Module-driven Telemetry XPath Builder (round 5, April 2026)
- telemetry.html rewrite — formerly a static dump of the 61 curated
telemetry-index.jsonentries; now a two-tab tool. The default tab, Module XPath Builder, lets the user pick any release / category / module and renders the MDTfilter xpathfor every operation in that spec, derived live with the formula from MDT_XPATH_SPEC.md (/<prefix>:<path-without-leading-slash>). Each row has a "Use" button that drops the xpath into a ready-to-pastetelemetry ietf subscriptionconfig snippet. Curated tier / cadence / on-change annotations fromtelemetry-index.jsonare folded in as enrichment when the derived xpath matches a catalogued entry. The original filterable curated table is preserved as the Curated Catalog tab. - scripts/build_yang_prefix_map.py — new build step that scans every
*.yangfile under each release's source directory, extracts theprefixstatement, and emitsreleases/<ver>/yang-prefix-map.json(and a top-levelyang-prefix-map.jsonfor the legacy 17.18.1 in-place layout). Output schema:{version, yang_source, module_count, modules: {moduleName: prefix}}. Built today for all five active releases: 26.1.1 (887), 17.18.1 (848), 17.15.x (799), 17.12.x (719), 17.9.x (701). - Formula verified against the existing curated 17.18.1 catalog: 60/61 entries match exactly; the single "mismatch" is a curator-chosen deeper xpath (
/interfaces-ios-xe-oper:interfaces/interface) rooted on the same operation, not a formula bug. - telemetry.js — new external script (CSP
script-src 'self'compliant); no inline JS intelemetry.html.
Added — Site-wide version awareness & quality hardening (round 4, April 2026)
- Version-aware viewers — all 9
swagger-*-model/index.htmlviewers now resolve the active release at runtime via__activeVer()/__apiBase()/__treeBase()helpers injected by scripts/patch_viewers_version_aware.py. The patcher readsreleases/index.jsononce and bakes the default version + active-versions allow-list into each viewer as__IOSXE_DEFAULT_VER__/__IOSXE_ALLOWED_VERS__. Unknown?ver=values are rejected (no more 404 storms on bad URLs). Helper block is regex-replaceable for true idempotency, and the deadgetSpecFolder()function was removed from all viewers. - scripts/normalize_manifests.py — normalises every
manifest.json(default + 4 release dirs × 9 categories = 45 manifests) to the viewer-expected schema: integertotal_modules/total_paths/total_operations/spec_countsummed from the sibling spec files, andmodulesas a flat list of string basenames. Fixes the viewer crashCannot read properties of undefined (reading 'toLocaleString'). - scripts/smoke_live.py (new, replaces
_debug_viewer.py) — headless Playwright smoke test of the live deployment. Loads version list fromreleases/index.json, walks every active release through the viewer, and exits non-zero on real failures (transient 503s ignored).--base-urlflag for staging. - tests/test_manifest_schema.py (new) — 46 parametrized pytest cases (45 manifests + 1 sanity) asserting required integer keys,
modulesaslist[str], count agreement, and that every listed module resolves to a sibling.jsonspec. - .github/workflows/tests.yml (new) — runs the manifest-schema test suite on push/PR touching
swagger-*-model/,releases/,tests/, the manifest normaliser, the viewer patcher, or itself. - index-app.js —
applyVersion()now rewrites alla[href*="swagger-"][href*="-model/index.html"]hrefs to carry?ver=<v>so category-card navigation preserves the active release.
Fixed (round 4)
- Manifest schema mismatch across release directories — old-schema manifests (missing
total_paths/total_operations,modulesas objects rather than strings) caused the viewer to crash on load. All 45 manifests rewritten vianormalize_manifests.py. - 404 storms on malformed URLs —
?ver=garbagepreviously triggered ~150 spec 404s. Now validated against the allow-list baked into the viewer; falls back silently to the default. - Mojibake repaired in 7 viewers —
â€"→—,🌳→ `,🗄→, etc., viaftfy`. CSP meta tags verified present on all 9 viewers. - Patcher fragility — anchor strings differed across viewers; idempotency previously relied on a substring sentinel. Replaced with a regex-replaceable helper block and a dead-code strip pass.
Added — Multi-release foundations (April 2026)
releases/<ver>/per-release folder layout — defined in VERSIONING.md. Per-release folders hold OpenAPI specs, pyang trees, manifests, accountability JSON, search index, telemetry index, MIB metadata, native capabilities, and Postman/Bruno exports.- VERSIONING.md — new authoritative doc covering folder layout, URL contract,
meta.jsonschema, manifest schema, "add a new release" runbook, and CI gates. - MDT_XPATH_SPEC.md — new authoritative doc defining the
/<prefix>:<container-path>MDT filter-xpath rule, OpenAPIx-mdt-*extensions, andtelemetry-index.jsonschema. - scripts/fetch_yang_release.py — sparse, shallow clone of YangModels/yang for a single release; pins commit SHA in
releases/<ver>/meta.json. - scripts/generate_all_pyang_trees.py — version-aware tree generator that writes
releases/<ver>/yang-trees/and a per-releasetree_audit.jsondocumenting every skip reason (types-only,submodule,deviation-only,augment-only,empty-tree). - scripts/build_release.py — single-release pipeline orchestrator (specs → enrichment → trees → MDT annotation → MIB metadata → native capabilities → manifests → accountability → search → Postman → Bruno).
- scripts/build_all_releases.py — iterates
releases/index.json. - scripts/validate_release.py — local pre-flight that runs every CI gate from VERSIONING.md §9.
- scripts/migrate_to_releases_layout.py — one-shot migration of the current 17.18.1 artifacts into
releases/17.18.1/. Default dry-run;--applycopies and--remove-legacydeletes the originals after copy. - releases/index.json — canonical list of releases consumed by the UI version selector.
- PROJECT_REQUIREMENTS.md §16 — new section locking the multi-release, MDT, native v2, MIB detail, exports, and accountability requirements.
- CODE_REVIEW.md resolution banner — confirms the three "Must-Fix Blockers" (XSS in
search.js, localStorage silent-fail inrecent-favorites.js, search-index race condition) are already resolved in code.
Added — Multi-release scripts & UI surfaces (round 2, April 2026)
- scripts/_release_paths.py — shared
ReleasePathshelper used by every new version-aware script; centralisesreleases/<ver>/...path resolution and provideslist_active_releases()/all_releases()againstreleases/index.json. - scripts/annotate_mdt_xpaths.py — parses
telemetry-reference.mdand stampsx-mdt-filter-xpath,x-mdt-tier,x-mdt-cadence-seconds,x-mdt-encoding,x-mdt-on-change-capable, andx-mdt-feature-sectiononto matching oper-spec operations. Emitsreleases/<ver>/telemetry-index.jsonandreleases/<ver>/telemetry-skipped.json. - scripts/parse_mibs_md.py — parses MIBS.md §3.5 full-availability matrix, §2.x functional-category roles, and §1.5 latest-inventory list, writing
releases/<ver>/mib-platform-matrix.json. - scripts/enrich_mib_metadata.py — extracts SMIv2 OID prefix, table/scalar/leaf counts, deprecated-object counts, latest-revision date, organization, and RFC reference from each MIB-derived YANG, then joins with the platform matrix into
releases/<ver>/mib-metadata.json. - scripts/build_native_capabilities.py — counts paths, operations (per HTTP method), schemas, leafs, lists, and choices across every
swagger-native-config-modelspec, writingreleases/<ver>/native-capabilities.jsonfor the Config Capabilities summary page. - scripts/build_accountability_compare.py — reads every active release's
yang_accountability.jsonand emits a unified cross-version matrix ataccountability_compare.json(withsummary,deltas, and per-moduleby_versionrows) consumed by yang-accountability-compare.html. - scripts/generate_bruno_collection.py — emits one Bruno collection per (release, model-category) pair under
releases/<ver>/exports/bruno/, with auto-split on the 50 MB cap and a top-levelbruno-manifest.json. - scripts/generate_postman_v2_collection.py — version-aware successor to the legacy
generate_postman_collection.py; emits per-(release, category) Postman v2.1 collections plus an environment file underreleases/<ver>/exports/postman/, with auto-split on the 50 MB cap and a top-levelpostman-manifest.json. The legacy script is kept untouched for backward compatibility withtools/.
UI surfaces
- index.html — version selector dropdown in the header sourced from
releases/index.json; persists inlocalStorage['iosxe-active-version']and reflects in the URL hash asver=<v>. Added quick-nav links to Compare Versions, MDT Telemetry, and Exports. - index-app.js —
initVersionSelector()andapplyVersion(); exposeswindow.__IOSXE_ACTIVE_VERSION__so other modules can scope their fetches. - search.js —
loadSearchIndexForActiveVersion()triesreleases/<ver>/search-index.jsonfirst and falls back to the legacy root index for backward compatibility. - telemetry.html — new top-level page; loads
releases/<ver>/telemetry-index.json, filters by tier (HOT/WARM/COOL), on-change capability, and free-text, links each row back to its OpenAPI spec. - exports.html — new top-level page; per-release matrix of Postman + Bruno collections from
*-manifest.jsonwith size badges and download links. - yang-accountability-compare.html — new top-level page; renders the cross-version comparison matrix and version-to-version add/remove deltas from
accountability_compare.json.
Build pipeline
- scripts/build_release.py — pipeline now includes
mibs-md-parse, switches the postman step togenerate_postman_v2_collection.py, and is the single source of truth for per-release builds. - .github/workflows/deploy-pages.yml — adds a
validate-releasesmatrix job (17.9.x,17.12.x,17.15.x,17.18.1,26.1.1) that runsscripts/validate_release.pyper cell and gates the deploy job; deploy step now copies thereleases/tree into the artifact.
Generator migration (round 2.5)
- generators/_version_args.py — shared
resolve_paths(category, mib_subdir=False)helper that strips--version <ver>fromsys.argvand returns the correct(yang_dir, output_dir, version)tuple. Legacy 17.18.1 maps toreferences/17181-YANG-modules/+swagger-<cat>-model/api/; any other version maps toreleases/<ver>/yang-source/+releases/<ver>/swagger-<cat>-model/api/. Backward compatible: generators called without--versionretain their original behaviour. - All 9 v2 spec generators (
generate_oper_openapi_v2.py,generate_cfg_openapi_v2.py,generate_native_openapi_v2.py,generate_openconfig_openapi_v2.py,generate_ietf_openapi_v2.py,generate_mib_openapi_v2.py,generate_other_openapi_v2.py,generate_events_openapi.py,generate_rpc_openapi_v2.py) now use the shared helper in their entry points and accept--version <ver>. - scripts/build_release.py —
run_step()now captures stdout/stderr and, if a step fails because a generator rejects--version(argparse "unrecognized arguments"), automatically retries without the flag. Defensive shim retained for any non-migrated tools.
Per-spec MDT panel
- swagger-oper-model/index.html — when an oper spec is loaded, fetches the active release's
telemetry-index.json, filters entries to that module, and exposes them via a toolbar toggle that opens an inline panel listing each XPath with HOT / WARM / COOL tier badges, cadence, and on-change indicators. Falls back gracefully when no telemetry index is present.
Visible UI surfaces (round 3)
- swagger-mib-model/index.html — added a MIB Details toolbar toggle. When opened it loads the active release's
mib-metadata.json(with fallback to the legacy in-place file) and renders the loaded spec's MIB record: module / OID prefix / table-scalar-leaf counts / indexes / deprecated flag / latest revision / organization / RFC / functional category / supported platforms (as badges). - swagger-native-config-model/capabilities.html (new) — standalone Native config capability dashboard. Reads
releases/<ver>/native-capabilities.json, shows totals (paths / operations / schemas / leafs / lists / choices / categories) and a sortable & filterable per-category table with deep-links into each category's spec in the Swagger UI viewer. Includes the standard release picker. - swagger-native-config-model/index.html — added a Capabilities Report link in the toolbar.
- references/native-cli-mappings.yaml (new) — curated YAML mapping table (~25 prefixes covering hostname, interfaces, BGP / OSPF, VLANs, AAA, SNMP, NTP, logging, spanning-tree, ACLs, NAT) of
path → cliso every native operation can advertise its CLI equivalent. - scripts/apply_cli_mappings.py (new) — overlay step that walks the active release's native specs (longest-prefix match, with
/dataprefix normalisation against the YAML keys) and stampsx-cli-equivalent(and optionalx-cli-notes) onto every HTTP method. Verified on 17.18.1: stamps 2,372 operations across 12 spec files. - references/native-example-overlay.yaml (new) + scripts/apply_example_overlay.py (new) — curated request-body examples for the most common native paths (hostname, Loopback, GigE, BGP, vlan-list, snmp host, ntp server, aaa new-model). The applier writes the example into each PUT/PATCH/POST's
requestBody.content["application/yang-data+json"].example. - scripts/build_release.py — pipeline now runs
apply_cli_mappings.pyandapply_example_overlay.pybetweenmib-metadataandbuild_native_capabilitiesso capability counts reflect the overlay-augmented specs.
Fixed (round 3)
- scripts/build_native_capabilities.py —
count_schema_features()only counted the top-level schema and one level of properties, so the legacy 17.18.1 native specs (which keep most of their data shape inline under each path's request/response, with only onerestconf-errorschema incomponents.schemas) reportedleafs=0 lists=0. Added depth-first_walk_schema()recursion (handles nestedproperties,items,oneOf/anyOf/allOf,patternProperties) and a newcount_path_features()that walks every operation's request/responseschema. Verified on 17.18.1:leafs=27,312,lists=3,252across 81 categories / 3,363 paths / 13,452 operations. - scripts/validate_release.py — gates now tolerate the legacy 17.18.1 in-place layout (specs at repo root,
releases/17.18.1/either missing or partially populated). Detects "no specs underreleases/<ver>/swagger-*-model/api/" and re-roots toPROJECT_ROOTfor 17.18.1 only. Gates 1, 4, 5 now globswagger-*-model/api/*.json(eliminating false hits inarchive/and other releases). Search-index, tree-audit and accountability files fall back to repo-root copies. Manifests without a declaredspec_countemit a warning instead of failing. Verified:validate_release.py --version 17.18.1exits 0 with all gates passing (666 specs parsed, 790 unique search entries).
Fixed
- Eliminated empty
{}examples in 657 specs — POST/PUT/PATCH request bodies now contain realistic, RFC 7951–compliant payloads. (scripts/enrich_v2_specs.py)- Added
build_example_from_schema()— recursively walks schemapropertiesto construct examples from leaf types and known field-name heuristics. - Added
CONTAINER_FILL(~95 templates) — maps YANG container names (e.g.,state,config,switchport,bfd,bgp) to realistic structured fills. - Added
_build_example_from_path()— path-based templates for VLAN, BGP, OSPF, ACL, AAA, NTP, SNMP, etc. - Added
_populate_empty_example()— orchestrator: schema-first, path-based fallback, finally[null]for empty YANG leaves (RFC 7951 encoding). - Result: 0 empty
{}and 0 straynullvalues across 26,331 config examples (verified across all 9 model categories).
- Added
- Fixed deep-link URLs from search results — copying/pasting a search URL now opens the correct module instead of the index page. (search.js)
updateUrlHash(query)writes#search=<query>viahistory.replaceState.handleDeepLink()parses three URL hash patterns on load:#search=<query>— runs the search#module=<name>— redirects to the module's swagger page#spec=<model>/<name>— redirects to the model'sindex.html#spec=<name>
- Added
hashchangelistener for browser back/forward sync.
Added
scripts/validate_examples_c9kv.py— Live-device validation for write-operation examples against a Catalyst 9000V (or any IOS XE 17.18.1+ device).- CLI:
--host --port --username --password --spec --method --limit --dry-run --patch-only --output - 8,066 PATCH-testable examples confirmed via
--dry-run.
- CLI:
AGENTS.md— AI agent guide (build/run, conventions, pitfalls, common tasks).CONTRIBUTING.md— Contribution workflow.CHANGELOG.md— This file.
Changed
- Inline JavaScript extracted from HTML pages to comply with strict Content Security Policy:
- index.html → index-app.js (341 lines)
- code-generator.html → code-generator.js (345 lines)
- tree-compare.html → tree-compare.js (332 lines)
- yang-accountability.html → yang-accountability.js (254 lines)
- CSP hardened —
script-src 'self' cdn.jsdelivr.net. No moreunsafe-inline.
[17.18.1] — Initial public release
The full 17.18.1 corpus, summarized:
Specifications
- 657 OpenAPI 3.0 specs across 9 model categories
- 43,726 RESTCONF API paths
- 68,353 API operations
- 60,200 example payloads
- 768 YANG/MIB tree HTML visualizations
- 848 source YANG modules tracked
- 100% module accountability (every YANG module documented or excluded with reason)
Coverage by model
| Model | Specs | Paths/Ops |
|---|---|---|
| Operational | 205 | 20,159 paths |
| MIB | 149 | 12,482 paths |
| Native Config | 81 | 13,452 ops |
| RPC | 59 | 308 RPCs |
| OpenConfig | 57 | 5,920 ops |
| Configuration | 39 | 9,452 ops |
| Events | 38 | 861 paths |
| IETF | 19 | 1,122 ops |
| Other | 10 | 4,597 ops |
Site features
- Fuse.js fuzzy search across all 657 modules
- Multi-language code generator (Python/curl/Go/Ansible/Postman)
- YANG tree comparison tool
- 100% module accountability report
- Recent + favorites (localStorage)
- 6 curated quick-start collections (day0, troubleshooting, performance, etc.)
Future
- Live C9KV validation runs in CI
- Scheduled
smoke_live.pycron job (GitHub Actions) for daily deployment regression detection - Optional
viewer-bootstrap.jsextraction to retire the 9 inline helper blocks and the patcher script