sgit newsroom v0.1.29 · snapshot 2026-09-24

Reading room · riskmandate.ai

On this page

Reading room / riskmandate.ai · raw text · live ↗

From riskmandate.ai, the page as fetched on 2026-09-25 · open the live page ↗Everything on this sheet is the source site's own text; the newsroom's chrome is outside it.

How riskmandate.ai actually works

Rendered from docs/how-the-website-works.md in the repository. The text below is that file. Source: https://riskmandate.ai/admin/briefs/how-the-website-works/↗ · noindex · written by scripts/site/build-admin.mjs

How a page is put together, what happens when the browser loads one, and where each thing lives. Current as of v1.0.0; see the addendum below for what has been added since, and .claude/onboarding/01-map.md for the current map.

Addendum, v1.17.0. The mechanics below still hold. Since v1.0.0 the site has gained, each with its own script under scripts/site/ and a --check in CI: the Agent Behaviour Policy vaults (build-abp-vault.mjs, one directory per vault under site/vaults/, derived from four input files; the renderer once in site/vaults/_app/, every vault carrying a loader — see docs/briefs/architecture__vaults-in-vaults-for-behaviour-policies.md), the library page and one page per vault (build-abp-pages.mjs, from site/vaults/index.json), dated PDF editions of every Lab page (render-lab-pdfs.mjs, registered by digest in site/lab-editions.json), the GitHub link and licence line on every page (add-licence-chrome.mjs), the brief register (site/briefs-register.json, checked by digest), the pages.json page list with unlisted, private and link entries, and the admin console under site/admin/ (build-admin.mjs, v1.23.0; admin.html redirects to it) as the index of all of it. The page counts and the test list in the body are the v1.0.0 figures; npm run check runs everything CI runs today.

The one-paragraph version

site/ is the website. GitHub Pages serves that directory byte for byte — there is no build step, no framework, no bundler and no server. Each page is a single self-contained HTML document: its own <style>, its own <script>, its own data inlined at the top. Open one with file:// and it renders. Navigation between pages is <a href>; the shared header is drawn by one small custom element that every page carries a copy of. Four pages fetch something at runtime, and only from the same origin.

Before v1.0.0 all of this lived in an SG/Vault and was served through a host <iframe>. site/versions/1.0.0.md ↗ is the record of that change.


1. What the browser does

GET https://riskmandate.ai/plug.html
  └─ Pages serves site/plug.html — one document, ~58KB, nothing else required
       <style>   the whole page's CSS, tokens first
       <body>    the markup, including <rm-menu> and any page components
       <script>  one IIFE: RM.data (inlined), then each component, then boot

  1. custom elements self-register as the script runs
  2. boot.js calls RM.components.nav.wire(document)
  3. <rm-menu> renders the header from RM.data.pages  → <a href> per page
  4. page components render their own content

No page waits on anything to become readable: the prose is in the document the server sent. Components add the interactive parts on top.

2. The anatomy of a page

Every page is the same five things in the same order.

WhatWhy it is inline
<head>title, description, canonical URL, Open Graph, favicon, and a <link rel="alternate"> to the page's markdown twincrawlers and link unfurls read the document, not a manifest
<style>design tokens on :root, then the shared header rules, then this page's ownone request per page; a page can't render half-styled
<body><header class="top"> with <rm-menu> and the version link, the content, the footer—
<script>RM.data — this page's name and the site's page list, as JSONthe menu is identical everywhere and needs no fetch
the components, then boot.jsplain concatenation, source order matters

Design tokens

Declared on :root in every page, identical everywhere:

--bg #F7F6F2   --bg2 #EFEDE7   --card #FFFFFF  --ink #0D0D0C   --canvas #0A0A09
--text #1A1917 --muted #4A4845 --faint #8A8780 --border #E2DFD8
--green #1A7F5A --green-2 #22c55e --greenBg #EBF5F0
--gold #B45309 --red #C0392B --blue #1D4ED8
--wrap 1000px  --r 10px  --r-sm 8px

Colours in a page are tokens. A literal hex outside :root is a bug, except inside the brand SVG, which is a fixed artwork.

3. The components

Four are on every page. The rest are on the one or two pages that need them.

On all 24 pages

Where needed

ComponentPagesWhat it does
registry, vault-demos, vault-pagethe 6 demo pages + demos.htmlthe demo catalogue and the embed that opens each demo's own SG/Vault with its own public read key
risk-queue, dataindex, acceptance, grant-gapthe acceptance-queue figure
iofeedback, library, versionsRM.services.siteIo — a same-origin fetch, and the only runtime IO in the site
markdown, version, versionsversionsthe version record
library, medialibraryarticles from assets/library/library.json, talks and the deck from assets/media/media.json
insurabilityindexthe Insurability Index card
plug-profile, state-grid, scenarios, statics, ramm-figure, ramm-pyramid, brand, options, loop, prompt, window-pickerone page eachthat page's figure or interaction

Components never use innerHTML. Everything is built with dom.el and textContent — which is what makes it safe to render a markdown file that was fetched at runtime.

4. The four pages that fetch

Everything else is complete in the document. These four are not, and each has a reason:

The live demos also load vaults — but in their own <iframe>, from dev.vault.sgraph.ai, each with its own published read key. Those keys are public by design. No write credential of any kind belongs in site/, and a test asserts none is there.

5. Versions

The number in the header is the site version. It links to versions.html, which renders versions/index.json plus one markdown note per release — 36 of them, 35 carried over from the vault and flagged reconstructed because the builds they describe are not in this repository.

Cutting a release is deliberate:

node scripts/site/release.mjs 1.0.1 "What changed, in a line"
# writes site/versions/1.0.1.md, updates index.json, restamps every page's
# version chip, and updates riskmandate_ai/version

Then write the notes, commit, push. CI checks the three places agree, tags that commit v1.0.1, and deploys. Nothing increments the version on your behalf — a release is a note somebody wrote, and the tag is what lets versions/index.json name the commit each release was built from.

6. Generated files

node scripts/site/generate.mjs rebuilds everything in site/ that is derived from something else:

FileDerived from
<page>.mdthat page's prose. Anything a component renders at runtime is in the page, not the twin.
sitemap.xml, 404.htmlthe page list in index.html
llms.txtthe page list plus each page's title and description
robots.txtfixed
versions.mdversions/index.json

They are committed, not built at deploy time — site/ is served exactly as it is in the repository. generate.mjs --check fails if any of them is stale, and runs as a CI gate, so a page cannot ship with a twin that contradicts it.

7. The pipeline

.github/workflows/ci-pipeline.yml, on push to qa/dev/main or manual dispatch:

check          node --test tests/site/*.mjs
               node scripts/site/generate.mjs --check
   ↓
tag            tag this commit v<versions/index.json:latest>, if not already tagged
   ↓
build          touch site/.nojekyll, upload site/ as the Pages artifact
   ↓
deploy         actions/deploy-pages

The deploy always follows the tag, so the live site never claims a version that resolves to nothing.

8. Tests

node --test tests/site/*.mjs — 17 checks, no dependencies:

9. What is not here any more

scripts/migrate/collapse-to-v1.mjs is the one-off that did the conversion. It is kept as the statement of what "reconstructed" means for v1.0.0 — run it against a fresh clone of the vault and it reproduces the snapshot. Nothing in CI runs it.