How this site is built
Static HTML in the sgit.ai design language, released the same way as the main site and pki.sgit.ai: every push to dev is validated, auto-tagged and deployed to GitHub Pages. This site adds two checks, and both exist because of something specific about its subject.
The release pipeline
- validate — two steps. First the generators re-run in
--checkmode: every page underspecs/anddocuments/must still match the data it was generated from. Thennode admin/build/validate.js: internal links resolve, the version agrees everywhere, every page declares a canonical URL on the host named inCNAME, the catalogue carries its survey date, and the leak tripwire passes. A failure stops the release: no tag, no publish. It also runs on pull requests, so branch work is gated before it reachesdev. - tag-release — every push to
devends taggedv{release}.{major}.{minor}. The version is owned byadmin/build/version.txt, bumped exactly once per release, and must agree with the release commit's subject (site vX.Y.Z: …). CI verifies the two agree and that the bump is the next minor (or a deliberate major), then tags the release commit — which isHEADon a direct push andHEAD's parent when a pull request lands as a merge commit. The first run backfills tags for historical releases from commit subjects. - deploy — publishes the tagged working tree to GitHub Pages. Runs on manual dispatch even without a tag, never when validation failed, never from a pull request.
The rule no sibling site needs
Generate every page that describes the code, from the code, at build time.
Four artefacts in the platform's own repository are knowingly stale — capabilities.json 42 minor versions behind, the reality document 41, a README describing a package directory that does not exist, and a version file nothing reads. Every one of them went stale for the same reason: it was written once, by hand.
Sixteen hand-written spec pages would be the fifth. So:
- The catalogue is data.
data/specs.jsoncarries a row per spec, and it carries its own provenance —surveyed,repo_version,source. Validation fails if any of those are missing. - The pages are a projection of it.
gen_specs.pywritesspecs/index.htmland one page per spec;gen_documents.pywrites thedocuments/readers fromdata/documents.json. - CI re-runs both in
--checkmode and fails if a page has drifted from its source. The comparison ignores the nav and footer blocks, which are owned bychrome.pyand applied after generation. - Derived numbers are computed, then cross-checked. Family LOC, spec counts, the stable/experimental split and the browser share are all computed from the per-spec rows and compared against the summary blocks the survey recorded separately. If the two disagree the build fails rather than publishing a number nobody can reproduce.
The honest limit of this. The site repository does not contain the platform's source, so “generated from the code” means generated from a machine-readable survey of the code, carrying the date and repo version it was taken at — 24 August 2026, v0.2.71. That is a weaker guarantee than reading manifest.py directly, and it is stated here rather than implied away. Wiring the generator to the platform repository is the version of this that would close the gap.
The leak tripwire
The sibling sites ban vault-key-shaped strings from the tree. This site bans considerably more, because the platform it documents is live infrastructure and publishing a hostname here would publish an attack surface.
admin/build/validate.js fails the release if any file in the tree contains:
- the platform's AWS account id;
- any of ten live internal hostnames;
- a named live stack FQDN, matched by slug;
- anything shaped like a real EC2 instance id or AMI id;
- anything shaped like an sgit vault key.
The editorial rule it encodes is shapes, not addresses: <stack-name>.sg-compute.<zone> is documentation, a live FQDN is a target.
One deliberate exception, and it is the reason the exception mechanism exists. The bare zone sg-compute.sgraph.ai is published — on the front page and in /network/ — because this site's label collides with it and the stated decision is to claim the distinction rather than move 128 references. The zone name is the subject of that decision. Per-node FQDNs under it are not, and the slug patterns still catch them: the check blanks the allowed zone before scanning, so <a-stack-slug>.sg-compute.sgraph.ai still fails.
Releasing a change
# 1. bump the version — exactly once per release echo "v0.1.1" > admin/build/version.txt # 2. add a row to admin/versions.html, update admin/comms.html # 3. regenerate the pages python3 admin/build/gen_specs.py python3 admin/build/gen_documents.py # 4. propagate the badge and any nav/footer change to every page, # generated ones included — and stamp llms.txt and index.md python3 admin/build/chrome.py # 5. AFTER chrome: the files that read the tree and the stamped twins, # or they assemble a stale version line python3 admin/build/gen_llms_full.py python3 admin/build/gen_sitemap.py # 6. validate locally — exactly what CI runs python3 admin/build/gen_specs.py --check python3 admin/build/gen_documents.py --check python3 admin/build/gen_llms_full.py --check python3 admin/build/gen_sitemap.py --check node admin/build/validate.js # 7. commit with the version in the subject, push to dev git commit -am "site v0.1.1: what changed" git push -u origin dev
The build tooling
| File | What it owns |
|---|---|
admin/build/version.txt | The version. Single source of truth; everything else reads it |
admin/build/chrome.py | The single definition of the nav and footer, rewritten in place across every page — hand-written and generated alike. Also stamps the version into llms.txt, llms-full.txt and index.md, which on the sibling sites was hand-edited and silently missed twice |
admin/build/pagelib.py | The shared page shell and the write-or-check writer both generators use |
admin/build/gen_specs.py | Generates specs/ from data/specs.json, and cross-checks every derived total |
admin/build/gen_documents.py | Generates the documents/ readers from data/documents.json |
admin/build/gen_llms_full.py | Assembles llms-full.txt from llms.txt, index.md and briefs/ — the thing pki.sgit.ai lacks |
admin/build/gen_sitemap.py | Walks the tree for sitemap.xml, dated from the release row |
admin/build/validate.js | The release gate: version, links, canonical, provenance, leak tripwire |
data/specs.json | The spec catalogue, with its survey date and repo version |
briefs/*.md | The source documents, verbatim — two of them redacted under their own rule |
Conventions carried from the sibling sites
- Light theme, same design tokens, same honest-limitations posture, -ise not -ize.
- Source documents captured verbatim under
briefs/with a curated reader alongside — the raw file stays the source of truth and the reader renders it at load time, falling back to a link if anything fails. - Machine-readable entry points: llms.txt, llms-full.txt, index.md, and the catalogue as JSON. The sibling sites lack
llms-full.txt; this one has it. - The version badge in the nav links to the release history, so any page tells you which release you are reading — and CI enforces that they all agree.
- The stage pill states the site's maturity in the nav rather than in a footer nobody reads.
- The domain note in every footer, because that is the question this site will be asked most.
- Print styles: every page prints as a clean document.