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.
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.1.1 | vendor/cisco/xe/2611 |
active (default) | Newest release; site default |
| 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 |
Tree-module counts are monotonic across versions: 620 / 637 / 683 / 715 / 742 (17.9.x → 26.1.1).
Adding additional patches/minors is the mechanical runbook in VERSIONING.md §8.
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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
WebSiteWebPage+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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- all 5 per-release files) and YANG_MODULE_ACCOUNTABILITY.md
updated to record
- FAQ.md — new top-level FAQ covering offline use, Catalyst 9k API discovery, on-device validation, MDT subscription, and Postman/Bruno consumption.
- 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.
- 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.
- 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.
- 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.
- 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.
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.
- 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/.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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).
- 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.
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.
- 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.
The full 17.18.1 corpus, summarized:
- 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)
| 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 |
- 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.)
- 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