Implementation doctrine

Site Build

How the SIBurst static interface is built, checked, and validated. The site is built for review only. It is not published (DEC-024).

1. Architecture

canonical Markdown (*.md)
canonical fixture (data/demonstration-fixture.json)
site sources (src/site/)
        ↓
tools/build_site.py
        ↓
docs/   (generated; never edited by hand — DEC-022)
Source Role
src/site/index.template.html The main page: seven stage sections, the persistent demonstration panel, and the reference entry.
src/site/reference.template.html The shell for each generated reference page.
src/site/reference-index.template.html The reference index shell.
src/site/assets/system.css The only stylesheet.
src/site/assets/system.js The only script: a vanilla JavaScript module.
Output in docs/ Produced from
index.html The template, the canonical fixture (static figures, counts, labels, anchors), and governed copy extracted from the Markdown.
assets/system.css, assets/system.js Byte copies of src/site/assets/.
data/demonstration-fixture.json A byte copy of data/demonstration-fixture.json.
reference/*.html, reference/index.html Canonical Markdown rendered by the pinned renderer.

Flow is one-way. Nothing in docs/ is ever an input.

2. Commands

python -m pip install --require-hashes -r requirements-build.txt
python tools/build_site.py                       # build docs/
python tools/build_site.py --check               # fail if docs/ differs from a fresh build
python tools/validate_site.py                    # validate the generated site
python -m http.server 8000 --directory docs      # local preview at http://localhost:8000/

Local preview needs no build step and no application server. Opening docs/index.html directly from disk shows the complete static document. The enhanced demonstration needs HTTP, because browsers block fetch on file: URLs, and the static document stays in place when that happens.

3. Deterministic build

4. Governed copy

The page does not restate doctrine. The build extracts these exact strings from the canonical sources, and fails if one cannot be found:

Copy Source
Tagline and claim-boundary sentence README.md
Thesis paragraph FOUNDATION_THESIS.md, "Thesis"
Stage captions INTERFACE_CONTRACT.md §5.4 reference captions
Scope statement (SYSTEM DEMONSTRATION — …) INTERFACE_CONTRACT.md §5.2
Stage names and state labels data/demonstration-fixture.json
Entity, relationship, and stub counts; anchor pairs data/demonstration-fixture.json (derived, anchors)
Reference document roles The document tables in README.md

The accessible state descriptions in the template are implementation copy. Their counts and anchor names are filled from the fixture.

5. Reference generation (DEC-017)

Item Value
Renderer markdown-it-py
Version 3.0.0, hash-pinned in requirements-build.txt
Transitive dependency mdurl 0.1.2, hash-pinned
License MIT (both packages)
Mode CommonMark with tables; raw HTML disabled; no linkify or typographic replacement

markdown-it-py was selected because:

It runs only inside tools/build_site.py. It does not ship to the public site, which performs no Markdown conversion at runtime.

Generation rules:

6. Runtime

Runtime dependency count: 0. The public runtime consists of static HTML, one stylesheet, inline SVG, one vanilla JavaScript module, and the local fixture.

Content Security Policy

Set with a <meta http-equiv> on every page:

default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self';
connect-src 'self'; font-src 'none'; object-src 'none'; frame-src 'none';
base-uri 'none'; form-action 'none'

Reference pages use script-src 'none' and omit connect-src. The pages contain no inline scripts, <style> elements, or style attributes. The script sets geometry through SVG attributes and one CSS custom property through the CSSOM, both of which the policy allows. frame-ancestors cannot be set through a <meta> element; it belongs to the server headers when publishing is authorized.

JavaScript architecture (system.js)

The script is an ES module (<script type="module">). It has two parts.

Pure functions, exported and tested in Node without a browser:

DOM code:

The script contains no entity, relationship, cluster, coordinate, or anchor data. Rendering is event-driven: each event requests at most one requestAnimationFrame. There is no loop, no interval, and no timer, so the system is still whenever the visitor is.

Progress

Native scrolling drives progress. The stage sections are sized in proportion to the contract ranges:

Stage Height
S0 84vh
S1 126vh
S2 105vh
S3 91vh
S4 112vh
S5 98vh
S6 84vh

The section under a reference line (mid-viewport, or mid-way down the reading area on narrow screens) gives the stage. The position within it gives p inside that stage's range. The ranges in use are exactly those of INTERFACE_CONTRACT.md §6.2.

There is no scroll-jacking, no wheel handling, and no snapping. Fragments #s0 to #s6 and #reference are ordinary anchors and work with and without JavaScript.

7. Demonstration rendering

Coordinates. The landscape scene is 640 × 440 SVG units and the portrait scene is 440 × 640, each with a 40-unit margin.

Lattice.

Field. Fixture coordinates are scaled into the inner area:

Both are inside the validated 9:16 to 16:9 range. Nothing is recomputed.

Routes (routable relationships). One deterministic orthogonal convention:

The rail used is the one above the lane for same-lane relationships, and the rail the two lanes share for adjacent-lane relationships. The same inputs always give the same path, and nothing moves along a link.

Stubs (unroutable relationships, S2–S3).

S4 phases, with internal t (never displayed):

t range Phase
0–0.25 Rails retire (opacity).
0.25–0.70 The same entity elements move from S3 positions to Field coordinates.
0.70–1 Routes straighten into direct paths, stubs extend to their partners, and ticks fade.

Easing is monotonic smoothstep, with no overshoot.

Reduced motion.

S5 identity. The display name "SIBurst" is attached to the demonstration boundary (INTERFACE_CONTRACT.md §4.2):

8. Reference Field (DEC-025)

S6 opens onto the reference layer, which contains a Reference Field: a map of the 15 canonical documents drawn in the post-transition grammar. It has a shared space, direct links, and relationship-based placement, with no rails. It is not part of the demonstration system and uses none of its identifiers.

Edge law. Documents A and B are linked if and only if the canonical Markdown of A names B's exact file name, or B names A's, outside fenced code blocks. The name may appear as a link target, in inline code, or in text. The match must not be part of a longer identifier. Reciprocal references collapse into one undirected edge, and self-references are ignored. No edge comes from similarity, titles, inference, or layout convenience.

Layout. A deterministic stress majorization, computed at build time:

Labels. Placement is deterministic. Each label, in document order, takes the first of eight candidate positions (single line, then two lines) that stays inside the boundary and overlaps no placed label and no node.

Accessibility. The map is aria-hidden and contains no links. The reading-order lists on the main page and on reference/index.html name every document and its explicit references in text, so the map adds no second keyboard sequence.

tools/validate_site.py re-derives the edges independently from the Markdown. It fails on any ungrounded, missing, duplicated, or self edge, a missing node, a non-direct link, or a list that disagrees with the map. It also reports the mean distance between linked and unlinked documents.

9. Progressive enhancement (DEC-023)

The HTML document is complete without JavaScript. It contains, in order, all seven stages, each with:

It also contains the S5 transition record with its text equivalent, and the reference layer.

After the script has loaded and indexed the fixture and built the scene, it adds js-ready to the root element and reveals the persistent panel. CSS then hides the per-stage figures. If loading or initialization fails, nothing changes and the static document remains.

When the viewport is shorter than about 30rem (including 400% zoom), the persistent panel yields to the per-stage figures, so every entity and anchor stays visible without leaving too little room to read.

10. Colour and budgets

The colour roles from VISUAL_SYSTEM.md §2, on background #F3F2EE. Contrast is measured by tools/validate_site.py.

Role Value Contrast Minimum
Primary information #15171B 16.02:1 4.5
Secondary information #4A4E55 7.46:1 4.5
Structure (rails, boundary, receded Field) #7A7F86 3.60:1 3.0
Dormant signal #545A63 6.21:1 3.0
Active signal #1F4E8C 7.42:1 3.0
Threshold warning (S2–S3 only) #A1420F 5.68:1 4.5
Post-transition distinction (S4–S6 only) #0D6657 6.14:1 4.5
Focus indicator #1F4E8C 7.42:1 3.0

Budgets (INTERFACE_CONTRACT.md §8):

tools/validate_site.py measures both and fails if either is exceeded.

11. Validation

Command What it proves
python tools/validate_fixture.py Gate 0: the fixture passes every law.
python tools/build_site.py --check docs/ is exactly the build output.
python tools/validate_site.py Generation integrity, runtime surface, CSP, structure and links, claim boundary, fixture integration, static fallback, S5 identity placement, Reference Field grounding, contrast, budgets, and public safety.
python -m unittest discover -s tests Fixture and site mutation tests.
node --test tests/site-state.test.mjs State, geometry, and interpolation logic, and agreement between static figures and runtime geometry.

.github/workflows/site-validation.yml runs all of these with read-only permissions. It never deploys.

12. Not performed

Sprint 3 does not publish. It adds no GitHub Pages configuration, DNS, or deployment workflow, and it does not launch the site. Those are a separate gate (DEC-024).