The relationship between wiki/, the generators, systems.db and the runtime is
a directed graph with two edges running opposite to the obvious direction and
one running backwards into its own producer. Prose renders that badly: every
document that has described it states a single ownership direction and is
therefore wrong about part of the tree. D-262 makes the diagram the source of
truth and points CLAUDE.md, Skill(wiki), project-structure.md and
wiki/GOVERNANCE.md at it.
The correction that matters most: body pages were described everywhere as
machine-owned and reverted on sync. They are not. scaffold_bodies.py writes
one once and never overwrites it, and import_economics then reads that
frontmatter directly as input — so a hand-edit is not reverted, it is obeyed,
and silently changes world generation. Worse than being overwritten, and the
actual reason GOVERNANCE.md forbids the edit.
New: tooling/check-dataflow-graph.py, wired into the Makefile and the pre-push
hook. It asserts every repo path named in a hand-authored diagram still
resolves — and its docstring states plainly what it cannot do: verify that an
edge still MEANS what it says. If wiki_sync.py stopped writing body pages
tomorrow, every path would still exist and the check would still pass. Edge
semantics stay a human check against the tool's source, so nobody reads a green
gate as a verified map.
Verified by breaking it: pointing one label at a moved path fails with exit 1
naming that path; restoring it passes. Building the checker also caught two
real vaguenesses in the diagram — "GJ-*/index.md" and "bodies/{id}/index.md"
were written without their wiki/star-systems/ prefix, which is precisely the
ambiguity this map exists to remove. Generated star-map .d2 files are excluded
by name; their correctness belongs to their generator under D-223.
Also files Q-124 + T-1246 (tooling): whether the 123 Python files under
tooling/ should become one Rust CLI of pql's calibre. The friction is real and
mostly not about the language — the permission gate prefix-matches whole
command strings and a blanket Bash(python3 *) grant is forbidden, so each tool
prompts near-individually, while a single binary is one allowlist entry. The
record requires pricing the cheap alternative (a Python dispatcher entrypoint)
before recommending Rust, and flags the hard constraint: import_economics is
stamped by source SHA, so any port must keep that contract intact through the
transition rather than disabled during it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
111 lines
5.3 KiB
Plaintext
111 lines
5.3 KiB
Plaintext
# 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: "wiki/star-systems/GJ-*/index.md\nREAD-ONLY blocks" {class: generated}
|
|
body: "wiki/star-systems/GJ-*/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}
|
|
}
|