Maintaining these pages
Evidence basis: source-verified at the pinned commit. Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. The procedure describes the libcna.com scripts and data files as they exist at the pinned snapshot; they were read, not re-run, for this page.
Documentation freshness is a reproducible human workflow: choose a CNA revision, inspect its diff and the contracts it touches, update the reviewed prose, regenerate the indexes, validate the links and facts, and commit the new revision marker together with the documentation. This page states the pin policy that governs the whole Development area, then the procedure for advancing the pin, what stays hand-reviewed and what is generated, what each checker verifies, and how to preview and review. It describes the libcna.com repository as it is at snapshot 009d40f5; every script named here lives in that repository's scripts directory (its inventories and ledgers in the audit directory), and all were read, not re-run, for this page. The task recipe for a CNA change is Update libcna.com after CNA changes.
Pin policy
- The pin is one file.
cnaheadat the root of the libcna.com repository holds a full 40-character commit and a newline:009d40f5dd085c4e674d3479675fac84b12b3e0a, on CNA'snextbranch (24 September 2026). It is the documentation snapshot, not a release: CNA's product version string at that commit is still0.1.0-alpha.1, and the tagv0.1.0-alpha.1is only the historical baseline the snapshot is compared with. - Everything factual is tied to that commit. Source links in the Development area are blob or tree links carrying the full hash (never a moving branch) and are checked against the Git tree at that commit; the generated references are computed from that commit's Git objects; the user documentation states the same commit in each page footer; and the canonical numbers (25 renderer identities in 21 families, 7 platforms, 4 audio implementations, the test inventory, the C ABI version) live in
data/current-facts.json, checked against the pages. - CNA moves faster than the pin.
nextand the maintainer's own CNA checkout keep advancing, often on a working branch. When this snapshot was pinned, that checkout was seven commits past it (renderer performance work with its plans and notes), and none of those commits is documented. Pages never describe behaviour from commits after the pin; the update recipe includes a check that no post-pin task identifier or feature leaked into the text. - Readers compare before they trust. Before using a trace for a new patch, compare your branch with the snapshot and re-read the changed paths (the comparison commands), and treat every path and symbol as a navigation hint on a different revision.
- External projects are pinned separately. Bindings, sample projects and the hosted demos are recorded at their own revisions in
data/current-facts.json(external_pinned) and are evidence for those revisions, not for the snapshot. - The pin moves atomically or not at all. A new
cnaheadwithout the matching prose, pinned links, constants and generated pages is a defect; see the procedure below.
Advance the documented revision
- Fetch and identify the intended CNA
nextcommit. In your CNA clone (the site tooling defaults to a sibling directory../cna, overridable withCNA_REPO, and only ever reads its Git objects), record the old and new full hashes and confirm ancestry withgit merge-base --is-ancestor. Decide the new commit deliberately: a batch of integrated work is easier to audit than a moving head, and the whole area is re-verified against it. - Review the diff, grouped by module, build selection, API and lifecycle. Measure it mechanically first, then read it:
Commit subjects carry task identifiers, soOLD=009d40f5dd085c4e674d3479675fac84b12b3e0a NEW=<the new 40-character commit> git -C ../cna merge-base --is-ancestor $OLD $NEW && echo "ancestor" git -C ../cna rev-list --count $OLD..$NEW git -C ../cna rev-list --count --first-parent $OLD..$NEW git -C ../cna rev-list --count --merges $OLD..$NEW git -C ../cna diff --name-status $OLD $NEW -- cmake CMakePresets.json .github/workflows git -C ../cna diff --stat $OLD $NEW -- modules/runtime modules/platform modules/graphicsgit log --first-parent --format=%s $OLD..$NEWshows the campaigns that landed. The Phase-1 audit derived its workstream table this way: campaigns and merges to the affected pages, using the Phase-1 ledger009d40f5-phase1-delta.mdas the model. For each page the delta touches, rungit diff $OLD $NEW -- <path>for every source path the page links (they are the token links, so the old hash in the page lists them). - Make a read-only tree of the new commit for the checks that read files. The retired-renderer scan and snippet compile checks use an extracted worktree of the pinned commit (
CNA_TARGET_TREEforvalidate_all.shandcheck_snippet.sh; the scan also takes--baseand--target). Everything else reads Git objects and never checks out, resets or cleans anything in the CNA repository. - Re-read the affected implementations; never update prose from filenames or commit messages alone. A renamed file proves nothing about behaviour, and a commit subject is a claim. Re-verify each affected claim (paths, symbols, ordering, ownership, counts, test names and registration, CMake defaults) against the new tree, and keep the distinction between source-verified, test-present and observed on every page.
- Write the full 40-character commit to
cnahead, then recomputedata/current-facts.json(identities and families, platform and audio counts, test files and definitions, workflow files, XNA counts, C ABI version, headers and routes, commit statistics) from the new tree, and update the per-area fact sheets and the delta ledger kept in the audit directory that record how each number was derived. - Replace the old hash and the constants that embed it. Hand-written pinned links in the user documentation; the footer sentence and date in
site_nav.py(and the copy baked into every page); theCNA_TARGETconstant invalidate_presentation.py; the snapshot patterns incheck_facts.py; the diagram labels inmake_architecture_diagram.py, then regenerateimg/architecture-diagram.svg; and the date constants insite_dev.pyandbuild_site_indexes.py. A search of the repository for the old hash (outside the audit directory) is the completeness test: every remaining hit must be a deliberate historical reference. - Regenerate, rebuild and re-index.
A built page carries the hash inside its expanded links. Rebuilding from the fragment re-expands every source-link token against the new tree and fails the build for a path that no longer exists; a page edited in place needs the scripted replacement above and then the link checker, which verifies each pinned path.python3 ./scripts/generate_dev_reference.py # the five generated reference pages, from the pinned Git objects python3 ./scripts/site_dev.py build --src <fragments> development/<page>.html # authored pages, tokens re-expanded and re-validated python3 ./scripts/site_dev.py sync # sidebar, breadcrumb and pager regions of every Development page python3 ./scripts/build_site_indexes.py # search-index.json, sitemap.xml and dateModified stamps bash ./scripts/validate_all.sh # every site validator - Inspect the generated diff, then run the checks. Read what the generator changed (counts, options that appeared or vanished, modules added), fix the prose that depended on it, and run the per-page validator on every touched Development page before the full run.
Revision changes are atomic. Do not commit a new cnahead with old prose or old pinned links. The checkers reject mismatched markers: check_source_links.py treats a Development-page link pinned to any commit other than cnahead, or to a moving ref, as an error, and validate_presentation.py requires cnahead to equal the commit its own constant names. Commit the pin, the prose, the generated pages and the indexes together.
What remains manually reviewed
Architecture, lifecycle, ownership, workflows, invariants, debugging advice, threading statements and every evidence label are authored prose. Generation intentionally does not synthesize architectural explanations: a human must trace the changed symbols, read the current source and decide whether each sentence, each test name and each ordering claim is still true. Two kinds of edit deserve extra care. A statement of absence (“no test asserts”, “no workflow names”) can be invalidated by any new file, so it needs a fresh search at the new commit. A statement of count or default should come from the generated pages or data/current-facts.json, not from memory; the fact checker fails a page whose whole-registry count disagrees with the canonical value.
What is generated
- Module inventory and entry files (Module index), with header, source and test counts and the renderer directories, from
git ls-treeof the pinned commit. - CMake option inventory (CMake option index), from a syntactic scan of every
option(),cmake_dependent_option()andset(... CACHE ...). - Test target and registration inventory (Test target index), from
add_executableandadd_testdeclarations. - Public header inventory (Public header index), the non-Internal headers under
include/CNAandinclude/Microsoft. - Selection axes (Selection axes index), derived from the identity, registry, platform and audio CMake files so the counts used across the site have one mechanical source. The generator refuses to write it when those sources disagree with each other or with the canonical counts.
- Client-side search index and sitemap from the visible metadata of every page (
build_site_indexes.pyreads each page's title, description, canonical URL and keywords), and the page furniture of Development pages (sidebar, breadcrumb, pager, table of contents, evidence box and related-pages block) fromdev_manifest.pyand each page's metadata. - The architecture diagram
img/architecture-diagram.svg, whose labels are facts from the fact sheets (make_architecture_diagram.py).
Generated pages carry a Generated page notice and should be changed through their generator, except when fixing the generator's output. They are syntactic: they locate declarations and files and do not establish behaviour, build success or test results. The repository also keeps records that are not served (the site's _config.yml excludes the audit and scripts directories and plan.md from the published output): plan.md (the audit summary and how to read it), the Phase-1 ledger 009d40f5-phase1-delta.md, the presentation baselines and comparisons, the per-area fact sheets and editorial guides, and developer-absorption-phase2.md, the Phase-2 absorption ledger that records, for each unit of source material folded into the Development area, where its knowledge went and what was verified, corrected or dropped.
Checks performed
validate_all.sh is the single entry point. It runs every validator below, prints overall: PASS or FAIL and skips the retired-renderer scan when the extracted TARGET tree is absent. It was read, not run, for this page.
| Script | What it verifies |
|---|---|
validate_site.py | Parses every HTML file (and with html5lib installed, a strict HTML5 parse of every page), rejects duplicate ids, checks JSON-LD blocks, requires a title, description, canonical URL matching the file path and og:title and og:description, resolves every local link and #fragment, and checks that search-index.json and sitemap.xml contain every public page exactly once (only 404.html and search.html are excluded). |
validate_presentation.py | Structural checks on owner-designated content: cnahead equals its constant plus one newline, the homepage Quick Stats, the showcase's real-XNA verification section, the Speedy Blupi section and its primary call to action, and that no baseline primary call to action was lost or downgraded without a recorded disposition. |
compare_presentation.py and --phase2 | Compares the working tree's presentation inventory (sections, calls to action, links, cards, images, stats, tables) with a recorded baseline and fails on an unexplained loss; the Phase-2 mode compares against the inventory taken before the Development area and uses a stricter size guard (a reduction over ten per cent of a page or block). |
check_facts.py | Checks that data/current-facts.json's numbers appear on the pages that must carry them, that superseded alpha.1 numbers are not presented as current, and that a whole-registry count written on any page, Development pages included, equals the canonical value. |
check_source_links.py | Reads Git objects. In the Development area every link into the CNA repository must be a blob or tree link pinned to cnahead whose path exists at that commit (or a commit link reachable from it); a moving ref or another commit is an error. Elsewhere TARGET-pinned links are validated and moving refs are counted. Links into pinned binding repositories are validated against the local sibling checkout when it exists. |
site_dev.py check | The manifest in dev_manifest.py against the disk: every planned Development page exists and no Development page is missing from the manifest. |
developer_ledger.py check | Conservation of absorbed knowledge during the Phase-2 absorption: every unit has an action, every destination page exists, every source heading is mapped and every mapped destination anchor exists, cited source paths are carried or explained, and page size and code tokens are not silently thinned. |
check_retired_renderers.py | Fails if public content names a renderer identity CNA has retired. The set is derived from the CNA registries at run time and is never stored in the repository. |
git diff --check | Whitespace errors in the change. |
Two more tools run per page or per change rather than in validate_all.sh. check_dev_page.py <page> validates one Development page while it is written (strict HTML5, ids, JSON-LD, metadata, that every local link and fragment resolves with links to manifest pages not yet built reported as pending, that every CNA link is pinned to the snapshot and exists there, no retired identity, alpha.1 only as history, no first-person voice and no vocabulary of the earlier standalone manual). check_snippet.sh syntax-checks a C++ snippet against the pinned headers with g++ -std=c++23 -fsyntax-only and writes nothing. browser_qa.py (headless Chrome over the DevTools protocol, pointed at a running static server) reports horizontal overflow, header rows, console errors, failed images and the lowest text contrast per URL, viewport and colour scheme.
Local preview
cd libcna.com
bash ./scripts/validate_all.sh
python3 -m http.server 8000
# open http://localhost:8000
No compilation and no package manager are involved: the site is static HTML, CSS and a little JavaScript, published from the repository root by GitHub Pages. The pages use relative links, so most of the site also renders from file://, but a local server matches how the pages are served and is what browser_qa.py expects. The validators need Python 3 with beautifulsoup4 (the fact and presentation checks) and, for strict parsing, html5lib; the extracted TARGET tree is needed only for the retired-renderer scan and the snippet check.
Review checklist
- Can a newcomer find the owner of each changed subsystem, from the change map and the module index?
- Do all capability and completeness claims have code plus test evidence, and is each evidence label (source-verified, tests present, and any recorded-by-CNA level) the right one? “The implementation exists” is not “the behaviour is proven”, and a named test is registered, not passed.
- Are source links pinned to
cnaheadand alive, with no line-number anchors? - Do the commands exist in the current presets and scripts at the pin?
- Are known gaps stated, scoped and evidenced, not disguised as planned features and not copied from a stale note?
- Does every number come from
data/current-facts.jsonor a generated page, and isalpha.1used only as history? - Does the text name no retired renderer identity, and does it keep to the snapshot framing (a development snapshot on
next, not a release)? - Does the site remain useful with JavaScript disabled, and does the page hold at phone width?
Related: Generated references, Getting started as a maintainer and the Maintainer Handbook.
Related pages
The same subsystem is explained at four altitudes. These are the neighbouring pages at each one.
- Architecture
- Architecture overview
- Internals
- Repository map
- Maintainer workflow
- Update libcna.com after CNA changes · Getting started as a maintainer · Maintainer Handbook
- Tests and validation
- Verification and known issues
- Reference
- Generated references · Module index · CMake option index