ADR-0006: Ops Site as Rendered Standing-Reference Surface
Status: Proposed (2026-05-19) Supersedes: — Superseded by: —
Context
By 19 May 2026 the system has accumulated standing knowledge in five separate places, each with a different cadence and audience:
- ADRs (
docs/adr/) — design decisions - Design note (
docs/design/DESIGN_NOTE_v2_two_stage.md) — v0.5 architecture rationale - Migrations (
src/db/migrations/) — schema history - v0.4 workbook (
data/seed/ESG_Screening_Framework_v0.4.xlsx) — historical framework reference - Slack
#esg-screening— event log, pinned canonical-spec notes, handoffs, in-session updates
Plus three "operating model" documents in three more places:
- Project instructions on claude.ai — chat-session protocol
.claude/CLAUDE.mdin the repo — CC-on-VM protocol- Pinned Slack notes — canonical hierarchy and other live conventions
Each chat session and CC-on-VM session opens with a context-reconstruction
phase: read the latest Slack handoff, re-read the canonical-spec pin,
re-derive the glossary (source vs signal_source, coverage vs
confidence, etc.) from accumulated handoffs. This is a recurring tax on
every session, and it grows as the system grows.
The recurring pattern is observable: handoffs grow longer because each one tries to compensate for the next session not having context — but each handoff is also one more thing to read at the start of the next session. The structure is fighting itself.
A standing-knowledge surface — rendered, navigable, gated — would absorb the "this is how the system is shaped" content and let handoffs shrink to "what changed since last time."
The Vextor project solved this same problem with ops.vextor.tech — a
gated technical docs site. The ESG Screening project should mirror that
pattern rather than re-invent.
Decision
Build an ops subdomain at ops.esg-screen.org that serves as the
rendered standing-reference surface for the ESG Screening system.
Hosting and gating:
- Cloudflare Pages, deployed from a separate repo (
McMillanGrubb/esg-screen-ops) - Gated by the same Cloudflare Access app as
esg-screen.org— add the subdomain to the existing app's policy. Single email allow list to maintain. - No new auth surface, no new credentials, no new monitoring.
Build approach:
- Static site generator. Default to MkDocs with the Material theme
unless
ops.vextor.techuses something different (in which case match it). Dense technical docs, dark mode out of the box, simple configuration. - Source in
docs/*.md. One-file-per-page navigation structure. - GitHub Actions builds and deploys on push to main.
Content policy: render, not replace.
For each surface, where the canonical content lives. The ops site renders from these, never duplicates:
| Surface | Canonical source | Build action |
|---|---|---|
/decisions/NNNN-* |
docs/adr/NNNN-*.md in main repo |
Direct render |
/reference/claudemd |
.claude/CLAUDE.md in main repo |
Direct render |
/architecture/scoring |
ADR-0001 + DESIGN_NOTE_v2 | Composed render |
/architecture/data-model |
Migration files + hand-written narrative | Composed render |
/scrapers/register |
Hand-written register, mirrors signal_source table |
(Live view in product) |
/ui/design-system |
ADR-0004 + ADR-0005 + base.css tokens | Composed render |
/glossary |
This site is canonical | — |
/operating-model/* |
This site is canonical | — |
/reference/v0.4-workbook |
The .xlsx file + hand-written change log | Composed render |
The two surfaces where the ops site IS canonical:
/glossary— terminology disambiguation lives here, nowhere else./operating-model/*— session protocol and handoff conventions live here, nowhere else.
Everything else, this site renders.
Live-data surfaces (/scrapers/register showing live source
status, /scrapers/health showing recent run results) do not duplicate
the product's /methodology page. The ops site's register page is
intent and design; the product's methodology page is current state.
Cross-link freely.
Consequences
Positive.
- One canonical reference surface. Chat-session and CC-on-VM openers can read one page (the architecture overview) for orientation rather than re-reading every Slack handoff.
- Handoffs can shrink. They become "since last time, X changed" rather than re-explaining methodology each cycle.
- Glossary kills repeated terminology confusion (
sourcevssignal_sourceand the rest). - Operating model consolidation. The same content currently in three places (project instructions, CLAUDE.md, pinned Slack notes) lives once, with the other three deferring.
- Matches an existing operator pattern (Vextor ops site). Pattern familiarity, no new mental model.
- Auth piggybacks on existing Cloudflare Access app. Zero new auth surface.
Negative.
- One more thing to keep updated. If the ops site drifts from the underlying canonical sources, it becomes a worse problem than no ops site — confidently wrong.
- Mitigation: render rather than replace. The ADR markdown files in the main repo stay the source; the ops site renders them. When an ADR is updated, the ops site rebuilds. The same applies for CLAUDE.md. Hand-written narrative pages (architecture overview, data model, ops intent) drift faster — these need explicit attention during cycles that change underlying behaviour.
- Authoring discipline: every CC-on-VM cycle that lands a structural change must include a docs update in the same commit. Future practice; not enforced by tooling in v1.
- Single static site, no version pinning. Looking at "the site as of three months ago" requires Git history navigation, not a UI feature. Acceptable v1 trade-off.
Hierarchy revision.
This ADR also revises the canonical hierarchy. The current pinned hierarchy is:
- ADRs
- Design note
- Migrations
- v0.4 workbook
The revised hierarchy includes the ops site as a rendered surface without changing priority:
Authoritative sources (priority order):
1. ADRs
2. Design note
3. Migrations
4. v0.4 workbook
Rendered surfaces (read these for navigability):
- ops.esg-screen.org (this site) — renders the above plus glossary
and operating-model content
- Slack #esg-screening — event log, not authority
Canonical only on the ops site:
- /glossary
- /operating-model/*
The pinned Slack note will be updated to reflect this once the site is deployed.
Implementation.
- New repo:
McMillanGrubb/esg-screen-ops. MkDocs Material theme. mkdocs.ymldefines navigation.docs/*.mdfiles for each page.- GitHub Actions workflow: on push to main, build site and deploy to Cloudflare Pages.
- Cloudflare Pages project: connected to repo, custom domain
ops.esg-screen.org. - Cloudflare Access: add
ops.esg-screen.orghostname to existingesg-screen.orgAccess app policy. Same OTP + 5-address allow list. - Initial content set: 13 pages produced 19 May (sitemap, home, glossary, session-protocol, handoff-template, canonical-hierarchy, architecture overview, data-model, scoring, stack, scraper register, scraper health, add-a-scraper, UI pages, design system, mock reference, decision log index).
Alternatives considered
- Stay with Slack pinned notes plus per-session handoffs. The status quo. Doesn't solve the recurring context-reconstruction tax. Rejected.
- Single big markdown file in the main repo (
docs/HANDBOOK.md). Lighter to build but unwieldy at scale, no navigation, no search, every chat session would have to read the whole thing or grep for fragments. Rejected. - Wiki on GitHub. Inherits authentication from GitHub itself (already mixed with the gh-CLI pattern), no Cloudflare Access gating needed. But: wikis are second-class to repos for indexing, the page-edit UX is web-only, search is poor. Rejected in favour of a proper static site.
- Notion or similar SaaS docs. Adds a non-self-hosted dependency with its own auth model, drifts further from the ADR-based source of truth, no straightforward render-from-markdown flow. Rejected.
- Make the ops site the source rather than a rendered surface. Strongest argument for this is "one place, no duplication." The argument against is stronger: ADRs need to live with the code they describe, and the v0.4 workbook is an external artefact that shouldn't be transcribed. Render is the right move.
- Build a
/docssection on the product itself. Keeps everything on one domain, one auth, one deploy. But: product changes weekly, ops docs should change rarely; mixing them couples release cadences. Separate subdomain keeps cadences independent. Rejected.
References
- Pattern source:
ops.vextor.tech(operator-grade docs site, same shape) - The 19 May 2026 chat session that surfaced the context-reconstruction problem
- Canonical-spec pinned note in
#esg-screening - ADR README (
docs/adr/README.md)