docgen: drop the superseded first pass, port the style harvester

The IR supersedes both intermediate designs (requirements D6, D7):
station/tools/docgen and the graph model that briefly lived in graphgen.
Shipping them beside atlas2/docgen would mean two graph models, which is the
thing the architecture argues against.

Carried across rather than lost:
  - style/extract.py and tokens.py, the offline theme harvester (R31). Rewritten
    to emit a *theme* — a slot-to-hex binding — rather than a whole style file,
    since what harvesting recovers is which colour a slot should be, not what a
    kind should look like.
  - graphgen/README.md, rewritten for what graphgen actually is now: the
    schema explorer. It fixes the blank station-index entry at run.py:304.

Two bugs found while doing it:
  - Canvas and ink are the two lightness extremes, not the two most common
    values. In a Graphviz SVG every label carries a fill, so the ink outnumbers
    the canvas 87 to 43 and the old rule produced a theme whose text was
    invisible against its own background.
  - A name defined in both branches of an if/else produced a duplicate id, which
    failed validation on docgen's own source. Disambiguated by line.
This commit is contained in:
2026-09-13 21:41:29 -03:00
parent 358b98f826
commit 160ee31b8c
51 changed files with 4504 additions and 2906 deletions

View File

@@ -28,10 +28,11 @@ SCHEMA ?=
STYLE ?= lucid
THEME ?=
DEPTH ?= 2
SCALE ?= 0.55
THEME_ARG := $(if $(THEME),--theme $(THEME))
.PHONY: help check ir db graph index site view self doctor clean
.PHONY: help check ir db code graph index site minimap explore docs view self doctor clean
help: ## List every target
@echo "docgen — static analysis of a tree, and the artifacts that fall out of it"
@@ -70,6 +71,35 @@ site: view ## OUT/view.json -> a self-contained docs site in OUT/site
--style $(STYLE) $(THEME_ARG)
@echo " open $(OUT)/site/index.html"
docs: ## Regenerate the figures in docs/ — docgen documented by docgen
@mkdir -p docs/img
@$(RUN) $(PKG).extractors.python --root $(HERE) -o /tmp/$(PKG)-docs.json >/dev/null
@$(RUN) $(PKG).ops /tmp/$(PKG)-docs.json --overview -o /tmp/$(PKG)-docs-view.json >/dev/null
@$(RUN) $(PKG).emitters dot /tmp/$(PKG)-docs-view.json -o docs/img/architecture.svg -q
@$(RUN) $(PKG).emitters minimap /tmp/$(PKG)-docs.json -o docs/img/minimap.svg --scale 0.5 --width 860
@$(RUN) $(PKG).emitters erd $(OUT)/ir.json -o docs/img/erd.svg 2>/dev/null \
|| echo " (erd figure kept — needs a schema IR at $(OUT)/ir.json to refresh)"
@PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG).emitters.site import VIEWER, _slots, _fill; \
from $(PKG).style import Style; import pathlib; \
pathlib.Path('$(HERE)/docs/viewer.html').write_text( \
_fill(VIEWER.replace('__TITLE__', 'docgen docs'), _slots(Style.load('lucid'))))"
@echo " open $(HERE)/docs/index.html"
explore: ## OUT/ir.json -> OUT/explore/ — navigate on one side, explore on the other
@$(RUN) $(PKG).emitters explore $(OUT)/ir.json -o $(OUT)/explore \
--style $(STYLE) $(THEME_ARG) --scale $(SCALE)
@echo " open $(OUT)/explore/explore.html"
minimap: ## OUT/ir.json -> OUT/minimap.svg — what is where, read from the colours
@$(RUN) $(PKG).emitters minimap $(OUT)/ir.json -o $(OUT)/minimap.svg \
--style $(STYLE) $(THEME_ARG) --scale $(SCALE)
code: ## Extract C#/TypeScript from SRC (needs tree-sitter)
@test -n "$(SRC)" || { echo "Error: set SRC=/path/to/tree" >&2; exit 1; }
@mkdir -p $(OUT)
@$(RUN) $(PKG).extractors code --root "$(SRC)" -o $(OUT)/ir.json
@$(RUN) $(PKG).ir $(OUT)/ir.json
index: ## OUT/ir.json -> OUT/index.md and OUT/sidebar.json
@$(RUN) $(PKG).emitters index $(OUT)/ir.json -o $(OUT)/index.md
@$(RUN) $(PKG).emitters index $(OUT)/ir.json -o $(OUT)/sidebar.json
@@ -79,12 +109,16 @@ self: ## Run the whole pipeline over soleprint itself — the honest end-to-end
@$(MAKE) --no-print-directory index OUT=$(OUT)
@$(MAKE) --no-print-directory graph OUT=$(OUT)
@$(MAKE) --no-print-directory site OUT=$(OUT)
@$(MAKE) --no-print-directory minimap OUT=$(OUT)
@$(MAKE) --no-print-directory explore OUT=$(OUT)
@echo
@echo " Read $(OUT)/index.md, or open $(OUT)/site/index.html"
doctor: ## Report whether this machine can run it
@printf 'python : '; $(PY) --version 2>&1 || echo MISSING
@printf 'dot : '; (dot -V 2>&1) || echo 'MISSING — sudo apt install graphviz (only to render)'
@printf 'tree-sit : '; $(PY) -c 'import tree_sitter, tree_sitter_c_sharp, tree_sitter_typescript; print("ok — C# and TypeScript available")' 2>/dev/null || echo 'absent — Python only. pip install tree_sitter tree_sitter_c_sharp tree_sitter_typescript'
@printf 'networkx : '; $(PY) -c 'import networkx; print(networkx.__version__ + " — for lab/ experiments")' 2>/dev/null || echo 'absent — only used in lab/'
@printf 'package : %s (from %s)\n' '$(PKG)' '$(PARENT)'
@printf 'styles : '; $(RUN) $(PKG).style 2>/dev/null \
|| $(RUN) $(PKG) 2>/dev/null \