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.

Architecture Brief — Decoupling site structure from content

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

Status: PROPOSED — for review by Dinis + the vault team Author: @website-agent (Claude Code Web session) Date: 2026-07-04 Companion: implementation__scenarios-pilot.md (the concrete first step) Pattern source: Building on sgraph.ai ↗ (docs 00–05) + the "Hosting a vault on static storage" guide (SGSend.staticMode).


TL;DR

Split riskmandate.ai into two planes with different owners, lifecycles, and quality regimes:

Migrate one content area at a time (strangler pattern), starting with the Scenarios page. Each migrated area needs exactly one change in the website vault: repoint its menu link to the new repo-owned page.


1. The problem today

Everything lives in one vault (7rfetjwz) and the repo is a dumb mirror:

  1. Structure and content are coupled. The interactive scenario engine (code) and the scenario copy (content) ship in the same build; a copy edit and an engine change ride the same release train, gated by the same build.js, owned by the same team.
  2. The version salad. The vault now carries the IFD frozen chain, HEAD singleton pages, src/pages/, src/data/, assets/, team docs, tests — 19+ published files per deploy and growing with every design snapshot. That chain is good engineering for design snapshots, but it forces all content through it.
  3. Publish = full re-clone. Every content change requires CI to clone the entire vault and redeploy the whole site. The vault moved 0.4.2 → 0.8.0 in ~two days; each sync was a manual dispatch + full rebuild.
  4. Engineering rigor lives in the wrong place. The repo (where CI, review, and tests are cheap) contains almost no code; the vault (where none of that exists beyond build gates) contains all of it.
  5. One environment. No dev/prod split; every deploy is production.

Evidence the current direction already points this way: vault release 0.5.4 externalised library content to runtime loads; the GRC scenarios plan was explicitly designed so scenario rotation is "a data edit, not a build change"; the vault ships llms.txt for agents. The architecture below completes that motion rather than fighting it.

2. Target architecture

  CONTENT PLANE                          STRUCTURE PLANE
  (SG/Vaults, one per area)              (this repo — Claude Code Web + CI)
  ─────────────────────────              ────────────────────────────────
  rm-scenarios vault                     /scenarios/ shell page
  rm-library vault (later)               /library/ shell page (later)
  rm-<area> vault (later)                shared: rm-chrome, vault-client glue,
  …                                        sanitizer, tests, CI pipeline
  authored by content/GRC agents         owned by engineering agents
  publish = sgit push                    publish = git push → tag → deploy
       │                                        │
       │            DELIVERY PLANE              │
       │   (GitHub Pages now; S3+CloudFront     │
       │    when edge features are needed)      │
       └──────────────┬─────────────────────────┘
                      ▼
              visitor's browser
       shell (static) + content (fetched → DECRYPTED CLIENT-SIDE → rendered)

The runtime model (per migrated area)

  1. The static shell page loads (repo-built, deployed by CI).
  2. It imports the vault-client (importReadKey, readObject, path/ref resolution — the same primitives sgraph.ai's shells use).
  3. It resolves the area vault's branch ref → commit → tree → content path and fetches only the objects it needs (a manifest + the content blobs) from the vault server (dev.send.sgraph.ai today).
  4. Objects are AES-256-GCM ciphertext; the browser decrypts with the area's public read key (embedded in the shell — public by design, same trust model as sgraph.ai's public-vaults.json; write keys never appear anywhere in this repo).
  5. Content renders through the shell's components, sanitized (DOMPurify) — we do not inherit sgraph's known unsanitized-injection gap (their CR-01).

Consequences: a content publish is visible on the next page load. No CI. No clone. No redeploy. And the fetches are per-object — the "full clone to publish" problem disappears for every migrated area.

What stays in the website vault

The marketing site's design-version chain (the IFD frozen deltas, the switcher, frozen.json) is a genuinely good mechanism for design snapshots and stays where it is. Migration drains the content areas out of it one at a time; the chain keeps shrinking toward what it's actually for. End state: the website vault holds the versioned marketing designs; everything editorial lives in per-area content vaults; the repo holds all code.

3. Environments: content × structure

The two planes version independently, which simplifies environments:

Delivery options for the structure split

OptionHowProsCons
A. Single Pages site (today)one repo, one site; content envs via branch pinningzero new infra; enough for the pilotno structure staging; every shell change is prod
B. Two GitHub reposthis repo → riskmandate.ai; a riskmandate.ai-dev repo → dev.riskmandate.ai (Pages is one site per repo; CI here pushes the artifact to the dev repo via deploy key)stays on Pages; real structure stagingcross-repo deploy plumbing; two Pages configs; still no edge functions
C. S3 + CloudFront (the sgraph.ai model)per-env distributions (dev./www); CF Function for rewrites; optional Lambda@Edge latermatches sgraph exactly; per-env cache control; enables live .md/llms.txt edge rendering; can serve the encrypted bare/ tree same-origin (no CORS, no send-server dependency)AWS account/secrets/infra to stand up and operate

Recommendation: run the pilot on A** (it's additive — a new page, no risk to the current site). Move to **C when either trigger fires: (1) we want live edge-rendered .md/.llm.json for agents (the vault's baked llms.txt goes stale between syncs), or (2) we adopt static hosting of the encrypted bare/ tree (SG_STATIC) and want it same-origin. B is the fallback only if AWS is blocked and structure staging becomes urgent before then.

4. Trust & hardening (non-negotiables for every shell)

5. Migration strategy (strangler)

  1. Scenarios (pilot — see the implementation brief): structured JSON content, clean logic/data split, GRC already owns the content lifecycle.
  2. Statics scenarios, then Library (the vault team already externalised its loading — it is the most vault-ready area).
  3. Each area: create vault → build shell → QA → repoint one menu link in the website vault → done. Rollback is repointing the link back.
  4. Extract the shared chrome (rm-chrome: header/menu/footer as a repo component fed by a runtime site manifest) after the second area proves the duplication — not speculatively before.
  5. End state: website vault = design snapshots only; repo = all shells and components with tests and CI; N content vaults publishing at will.

6. Decisions needed

#DecisionOwnerDefault if unblocked
1Create the rm-scenarios vault (id + keys)Dinis / vault teamnew dedicated vault
2CORS confirmation on dev.send.sgraph.aivault/platform teamassumed permissive GET
3Who ports the scenario engine JS into the repoengineering (this agent)this agent, with tests
4dev.riskmandate.ai domain + when to split envsDinisdefer past pilot
5S3/CloudFront timingDinison first edge-rendering need