docs(diagrams): SVG replaces PNG, and a map of the wiki generator flow
d2 emits SVG natively; its PNG path wants a ~150 MB headless-Chromium download and prompts interactively, so every PNG here was produced by an out-of-band magick step. There is no Chromium on this system. Dropping PNG removes the dependency rather than trading one format for another, and cuts docs/diagrams/ from 17 MB to 3.3 MB. SVG renders in Gitea and in clide (`clide draw --file <path>`, which takes .d2 source directly), and diffs as text. One PNG is kept on purpose: design/star-map-concentric.png has no .d2 source. Also renders the 7 star-map .d2 files for the first time. star-map-plan.md listed their renders as a deliverable in March and the step never ran; the new `make check-diagrams` is what surfaced it. New: docs/diagrams/data-flow/wiki-generator-flow.d2 — which way the arrows point for any file under wiki/. Every edge was read in the tool's own source rather than inferred. It records the trap that keeps costing us: scaffold_bodies.py writes a body page once and never overwrites it, and the generator then reads that frontmatter directly — so a hand-edit there is not reverted, it is obeyed, and silently changes world generation. Two rendering traps found the expensive way and now written down: - A d2 `|md` block becomes an SVG <foreignObject>. ImageMagick and flutter_svg both silently drop it, so the legend was in the file and invisible in every viewer except a browser. Plain labels render as real <text> everywhere. - Container boxes fight the layout engine. Grouping nodes whose flow-depths differ forces long edge routes; this diagram went from an unreadable 2.4:1 sprawl to a legible 0.75:1 by deleting five containers and changing nothing else. Colour classes carry the grouping instead. make diagrams / make check-diagrams render and gate. Repo-specific rules in .claude/rules/diagrams.md; d2 syntax and the traps live in the user-scope d2-diagram skill, whose PNG default was flipped to SVG to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@@ -58,7 +58,7 @@ None assigned directly. Track all Q-NNN and Q-WTF-* records.
|
||||
- `decisions/` — domain-split decision files (see `decisions/README.md` for index)
|
||||
- `docs/discussions/` — archived rounds (including active rounds per D-022)
|
||||
- `docs/briefings/` — agent briefing files (you maintain these)
|
||||
- `docs/diagrams/` — decision diagrams (architecture, data-flow, entity, state, ui) — `.d2` source + `.png` renders
|
||||
- `docs/diagrams/` — decision diagrams (architecture, data-flow, entity, state, ui) — `.d2` source + `.svg` renders (`make diagrams`)
|
||||
- `docs/workshops/` — workshop briefs, outputs, and summaries
|
||||
- `TEAM.md` — team roster
|
||||
|
||||
|
||||
@@ -401,7 +401,7 @@ Consistent with existing project d2 conventions (dark background, `#1a1e24` base
|
||||
| `tooling/star-map-seed.json` | JSON config | Miri | Before map generation |
|
||||
| `docs/design/star-map.json` | JSON graph | Generated | Output of script |
|
||||
| `docs/diagrams/design/star-map-*.d2` (×7) | d2 source | Generated | Output of script |
|
||||
| `docs/diagrams/design/star-map-*.png` (×7) | PNG renders | Generated via d2 | After d2 source |
|
||||
| `docs/diagrams/design/star-map-*.svg` (×7) | SVG renders | Generated via d2 (`make diagrams`) | After d2 source — done 2026-08-20 |
|
||||
| Gateway system profile | Hand-authored | Miri | After name decided |
|
||||
| Framework amendment: add `astronomical_id` | Edit to `systems-framework.md` | Miri | After lead sign-off |
|
||||
| Naming catalog: real-star pool + fabrication rules | Embedded in this doc | Miri | Done (see naming section above) |
|
||||
|
||||
|
Before Width: | Height: | Size: 568 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 747 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 547 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 437 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 856 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 826 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 912 KiB |
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,110 @@
|
||||
# Wiki <-> generator data flow — the canonical map (D-262)
|
||||
#
|
||||
# WHAT THIS ANSWERS: for any file under wiki/, which way do the arrows point?
|
||||
# The answer differs per file, and two paths run in BOTH directions — which is
|
||||
# what everyone (agents included) keeps getting wrong.
|
||||
#
|
||||
# COLOUR is the grouping (green authored / blue tool / amber store / grey
|
||||
# generated / purple runtime). There are deliberately no container boxes: the
|
||||
# tools sit at four different depths in the flow, so boxing them together
|
||||
# forced long tangled edge routes and made the graph unreadable at pane width.
|
||||
#
|
||||
# EDGES: solid = build-time · green = runtime · dashed = one-time/bootstrap
|
||||
# red = the trap (output that is read back as input)
|
||||
#
|
||||
# Every path here was read in the tool's own source, not inferred.
|
||||
# tooling/check-dataflow-graph asserts the paths still exist; it CANNOT verify
|
||||
# that an edge's MEANING is still true — see D-262.
|
||||
#
|
||||
# View it: clide draw --file docs/diagrams/data-flow/wiki-generator-flow.d2
|
||||
# Render: make diagrams
|
||||
|
||||
direction: down
|
||||
|
||||
vars: {
|
||||
d2-config: {
|
||||
layout-engine: elk
|
||||
pad: 30
|
||||
}
|
||||
}
|
||||
|
||||
classes: {
|
||||
authored: {style: {fill: "#1f6f43"; stroke: "#8fd9ae"; font-color: "#ffffff"; bold: true; border-radius: 4}}
|
||||
tool: {shape: hexagon; style: {fill: "#2b4c7e"; stroke: "#9dc0f0"; font-color: "#ffffff"}}
|
||||
store: {shape: cylinder; style: {fill: "#7a4b12"; stroke: "#e0b070"; font-color: "#ffffff"; bold: true}}
|
||||
generated: {style: {fill: "#3a3a42"; stroke: "#9a9aa4"; font-color: "#ffffff"; border-radius: 4}}
|
||||
runtime: {style: {fill: "#5c2d6e"; stroke: "#d3a8e6"; font-color: "#ffffff"; border-radius: 4}}
|
||||
run: {style: {stroke: "#1f8f4a"; stroke-width: 3}}
|
||||
once: {style: {stroke: "#9a9aa4"; stroke-dash: 4}}
|
||||
trap: {style: {stroke: "#c0392b"; stroke-width: 3; font-color: "#c0392b"; bold: true}}
|
||||
}
|
||||
|
||||
# ---- authored (green): a human writes these ----
|
||||
econ: "wiki/economics/\nTOMLs + 37 commodity pages" {class: authored}
|
||||
corp: "wiki/corporations/*.md\n156 pages" {class: authored}
|
||||
gttr: "gttr*.md\nDrifter's Guide prose" {class: authored}
|
||||
prose: "system-page prose sections" {class: authored}
|
||||
cli: "tooling/atlas add-body\nTHE bodies catalog origin" {class: authored}
|
||||
|
||||
# ---- generators (blue hexagons) ----
|
||||
econimp: "import_economics\n+ generate_brands" {class: tool}
|
||||
sync: "wiki_sync.py" {class: tool}
|
||||
scaf: "scaffold_bodies.py\n+ body_definition_parser" {class: tool}
|
||||
hook: "populate_gttr_hook" {class: tool}
|
||||
tref: "populate_terrain_reference" {class: tool}
|
||||
hmap: "import_heightmaps\n+ planet_simulation" {class: tool}
|
||||
|
||||
# ---- stores (amber cylinders) ----
|
||||
db: "systems.db" {class: store}
|
||||
smap: "star-map.json" {class: store}
|
||||
|
||||
# ---- generated into wiki/ (grey): do not hand-edit ----
|
||||
sys: "GJ-*/index.md\nREAD-ONLY blocks" {class: generated}
|
||||
body: "bodies/{id}/index.md\nfrontmatter = body definition" {class: generated}
|
||||
assets: "heightmap · reliefmap · globe\nterrain.npz · markers.json" {class: generated}
|
||||
brands: "generated_brands.toml" {class: generated}
|
||||
|
||||
# ---- runtime (purple) ----
|
||||
cascade: "server cascade" {class: runtime}
|
||||
client: "Godot client" {class: runtime}
|
||||
|
||||
# wiki -> DB
|
||||
econ -> econimp
|
||||
corp -> econimp
|
||||
gttr -> hook
|
||||
cli -> db: "catalog"
|
||||
econimp -> db
|
||||
econimp -> brands
|
||||
hook -> db: "gttr_hook"
|
||||
|
||||
# DB -> wiki — the direction people miss
|
||||
db -> sync
|
||||
smap -> sync
|
||||
sync -> sys: "renders"
|
||||
prose -> sys: "preserved"
|
||||
sys -> scaf: "bodies table"
|
||||
scaf -> body: "writes ONCE"
|
||||
sys -> sync: "parses (bootstrap)" {class: once}
|
||||
|
||||
# the trap
|
||||
body -> econimp: "read as INPUT" {class: trap}
|
||||
|
||||
# assets
|
||||
db -> hmap {class: once}
|
||||
hmap -> assets {class: once}
|
||||
assets -> tref
|
||||
tref -> db: "terrain_reference"
|
||||
|
||||
# runtime
|
||||
db -> cascade {class: run}
|
||||
assets -> cascade: "read at runtime" {class: run}
|
||||
db -> client: "shipped" {class: run}
|
||||
|
||||
# NOTE: deliberately a plain text node, NOT a `|md` block. d2 renders markdown
|
||||
# blocks as an SVG <foreignObject> (embedded HTML), which ImageMagick and
|
||||
# flutter_svg both silently DROP — the legend then exists in the file and is
|
||||
# invisible in every viewer except a browser. Plain labels render as real
|
||||
# <text> and survive everywhere.
|
||||
legend: "READING THIS\n\nCOLOUR = kind. green authored · blue generator · amber store\n grey generated-into-wiki/ · purple runtime\nLINE = when. solid build-time · green runtime\n dashed one-time/bootstrap · RED the trap\n\n\nTWO PATHS RUN BOTH WAYS\nwiki_sync.py renders DB→wiki (generate_wiki(), routine) AND\nparses wiki→DB (import_from_wiki(), bootstrap only).\nNot a drawing error.\n\nTHE RED EDGE IS THE EXPENSIVE ONE\nscaffold_bodies.py writes a body page once and NEVER\noverwrites it; the generator then reads that frontmatter\ndirectly. A hand-edit there is not reverted — it is OBEYED,\nand silently changes world generation. Hence the\nGOVERNANCE.md prohibition.\n\nTWO ROUTES INTO THE GAME\nsystems.db ships with the build; the per-body PNGs are read\nat RUNTIME via bodies.terrain_reference, never baked in.\n\nFIELD RESOLUTION IN A BODY PAGE (body_definition_parser)\noverride > direct read > derived > inferred > seeded random.\nContinuous fields vary because they fall to the last tier;\ncategorical ones are concentrated because they come from\nthe bodies table." {
|
||||
style: {font-size: 24; font-color: "#dcdce4"; fill: "#161619"; stroke: "#9a9aa4"; border-radius: 4}
|
||||
}
|
||||
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 1006 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 753 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 667 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 634 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 638 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 354 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 766 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 678 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 868 KiB |
|
After Width: | Height: | Size: 44 KiB |