Bitspark constellation
accepted source ↗

ADR 0005 — topology-driven views & cross-repo propagation: generate the invariant shape, author the lesson, lint the seam

  • Status: accepted
  • Date: 2026-06-04
  • Relates: 0001 (the charter), 0002 (the manifest + edge graph), 0003 (the docs graph)
  • Implements: epic #36 — the architecture for its leaves #37#43, #48
  • Source of truth: logos research-docs/0007-…boundary.advice.md ("generate the stack, but author the lesson")

Context

Four member repos hand-maintain a "Where it sits" ASCII block (logos, ontos, thesmos, stele). They have drifted, and they are not the same drawing with a different highlight: they differ in depth, orientation, and in per-repo editorial annotations ("the law it all obeys", "admits via thesmos's law + logos check") that are not derivable from {layer, dependsOn.kind}. A naive topology-only generator would erase exactly the sentences that make each block worth reading.

The constellation figure ([0001]/[0002]) already proves the generation pattern, but the topology model has no vertical order (a DAG topo-sort is not unique; layer is a categorical tag, not a rank), and committed cross-repo artifacts go stale silently when topology changes. Epic #36 operationalizes the research-0007 advice; this ADR ratifies its architecture so the leaves can be scheduled and built. It resolves the three open questions the research left: (a) how to model vertical order, (b) how to keep editorial annotations single-sourced rather than erased, (c) how to tame cross-repo freshness and CI coupling.

Decision

1. A four-layer model and four artifact classes (#37)

Stop framing the boundary as "generate vs hand-author." It is a four-layer system — facts (machine-checkable; repo/atlas) → projection (a deliberate view of facts; atlas) → expression (visual grammar; design) → local prose/intent (repo). The predictive property is derivability × invariance pressure. Every generated or authored artifact is classed:

  • generated-fact — fully derivable, high invariance pressure, ~no rhetoric (constellation.json, family.md, .docs-manifest.json).
  • generated-view — derivable given an authored projection (order/crop/highlight) (the constellation SVGs; the stack SVGs).
  • generated-scaffold-with-authored-overlay — a tool emits the frame; the author fills interpretive claims the tool must not infer (the worktree scaffold; the per-repo stack-view captions).
  • hand-authored-linted — the artifact is the judgment; invariance is enforced by linting the seam, not regeneration (ADRs, README, the bespoke single-system figures).

Each artifact declares its class in its own provenance block (class: line in an SVG comment; _class key beside _comment in JSON; the classification table for hand-authored files). Rule of thumb, and the internal motto: generate the invariant shape; author the interpretive claims; lint the seam. The middle two classes are where the tools get smarter.

2. Provenance: input-only digests, no SHAs (#38)

Every generated artifact self-describes via a deterministic comment: class, generated-by (command + tool version), highlight, topology-digest, view-digest, design-digest, source-atlas, source-design. Digests cover inputs only — never the output, never a commit SHA, timestamp, or nonce — so the block is part of the byte-stream --check compares without creating a fixpoint, and renders stay deterministic (no perpetual --check staleness). A shared zero-dep src/provenance.mjs (node:crypto) is the single formatter; atlas diagram gen adopts it first. Input identity (this SVG) is deliberately separated from family freshness (has this repo adopted the newest topology) — the latter is solved by §4, not by embedding refs in the SVG.

3. The stack view is a generated-view: explicit order, authored-but-checked captions (#39 → #40)

Resolves open questions (a) and (b).

  • Vertical order is an explicit, named projection, not a topo-sort. It lives centrally in topology/views/stack.json (order, direction, scope, bands, validate). Topo-sort is used only as a validator/suggester: atlas topology order lint --view <v> flags a build edge that points "up" the stack, and the only escape is a declared projection exception with a required reason. atlas topology order suggest prints a candidate, never rewrites.
  • Editorial annotations are authored view data, single-sourced in the owning repo — never topology facts. dependsOn[].note stays the universal dependency gloss; per-repo docs/stack-view.json carries highlight, window, captions, labelOverrides. Captions may cite supports: ["repo:path#anchor"] which atlas checks (against the sibling's .docs-manifest.json, reusing the crosslinks docs resolution) — the sentence is authored, its references are verified. atlas collects and validates these; it does not author them (by atlas's own membership test, single-repo teaching prose has an owner — the repo).
  • Model + checks before pixels. #39 ships the schema, validate, explain --highlight, and order-lint with no design dependency and no SVG; "if the explain text feels wrong, the SVG will be wrong." #40 then renders atlas diagram stack --highlight <repo> --mode light|dark --all --check, reusing design's figureEnvelope/palette/wordmarks via the existing lazy loadDesignKit, with deterministic light/dark output embedded through the figure-manifest <picture> transclusion. The renderer draws node style from the real edge kind and the authored caption as separate layers — never conflated. It must not infer prose from dependency kind, force uniform depth, put orthogonal infra in the vertical chain, collapse the DAG without declaring the projection, or replace bespoke figures.

4. Freshness is a propagation problem (#41) — resolves open question (c)

Three separated concepts: local determinism (--check recomputes from pinned inputs), input identity (the §2 in-SVG digests), and family freshness (atlas drives updates).

  • Per-repo lockfile .atlas/lock.json (generated, committed, never hand-edited) records the atlas/design refs, the input digests, and each committed artifact's render coordinates + byte digest. atlas lock check validates a leaf's committed SVGs against its own lock — committed-files-only, no network, no token, no design checkout. A leaf's per-PR CI gate therefore never reds because atlas main moved; it only fails if this PR desynced an SVG from the lock.
  • Fan-out, not pull. On a topology/view/design change, atlas CI dispatches repository_dispatch (bitspark.toolchain.updated, with atlas_ref/design_ref/digests/ affected_artifacts/reason) to each affected leaf; the leaf's listener calls a SHA-pinned reusable workflow that regenerates in the leaf and opens an update PR (so atlas needs only dispatch scope, not write tokens across six repos; the worktree/one-PR lane is preserved). Staleness surfaces as an open PR, never a red X on an unrelated feature PR.
  • One pinned thing, not two infra checkouts. atlas releases a docs-toolchain bundle (a GitHub Release-asset tarball: bin/atlas + topology/ + views/ + design's figure.mjs + wordmarks + VERSION.json) so a leaf consumes a single pinned snapshot via ATLAS_DESIGN_DIR rather than cloning atlas and design. This keeps the zero-dependency invariant (it is a CI input, not a node_modules dependency) and the local lazy-design path unchanged.

5. Rollout, and gates first (#42, #48, #47)

  • Activate the existing dormant gates (#47) first, as the low-risk stepping stone: pure CI config over already-shipped machinery (manifest validate --reconcile, workflow check, topology sync --check, crosslinks docs), flipping the constellation from "wired but dormant" to enforced and establishing the token + skip-with-warning pattern that #41's fan-out reuses. It is gated only on the already-merged bug fixes #25/#28.
  • Stack rollout (#42): atlas dogfoods → logos (easy pilot) → ontos/thesmos/arche → stele (the hard pilot; full stack + mechanism captions; the schema-expressiveness gate — run it through explain before any SVG). design gets docs-graph only (it is orthogonal infra, not a stack node). Each member PR replaces the ASCII block with the <picture> transclusion + docs/stack-view.json + generated SVG pair + .atlas/lock.json + the toolchain workflow.
  • Docs-graph adoption (#48) runs in parallel — it depends only on the shipped docs engine (#22/#23) plus the merged slugger fix (#25), not on the renderer.

6. Contributor-journey tooling (#43) — the highest-leverage track

Independent of the stack chain; ships from atlas's committed data and degrades gracefully when siblings are absent. atlas impact is built first (it closes the loop between topology, docs reachability, and contributor action), needing a new reverse-dependency helper (usedBy/downstreamOf) and finally giving the dead dependsOn[].docs field a reader. Then explain/guide (compositions over impact), a hand-authored-but-linted concept index (concepts.json, the structured successor to glossary.md), and a per-repo docs-claim registry (docs/claims.json — README claims cite backing anchors; lint claims whose anchors disappear). Recommended split: impactexplain/guide ∥ claims ∥ concepts → cross-repo doctor / PR-explainer bot (the last needs the §4 toolchain).

Build sequence (waves, for when #36 is scheduled)

Hard dependencies (Blocked-by): #39←#37, #40←{#39,#38}, #41←{#40,#38}, #42←{#40,#41}. Independent tracks marked ∥.

  • Wave A (start immediately): #37 (artifact policy) · #47 (activate gates) · #43 impact · #48 (docs adoption).
  • Wave B: #38 (provenance, after #37) · #39 (stack schema/validate/explain, after #37) · #43 explain/guide ∥ claims ∥ concepts.
  • Wave C: #40 (stack renderer, after #39 + #38).
  • Wave D: #41 (lockfile + fan-out + toolchain bundle, after #40 + #38).
  • Wave E: #42 (multi-repo rollout, after #40 + #41) · #43 cross-repo doctor / PR bot (after #41).

Consequences

  • The three research-0007 open questions are resolved: (a) explicit named order validated against the DAG; (b) editorial captions authored once per repo, with checked anchors, never on dependsOn[]; (c) lockfile + fan-out + toolchain bundle for freshness without cross-repo CI coupling.
  • The generate-vs-author boundary is codified (#37), so future artifacts are classed instead of re-litigated. Provenance (#38) makes every generated artifact auditable and is the hook the lockfile (#41) indexes.
  • design owns expression. The "elements gallery" and rendered-PNG-in-CI ideas from the research are design's (epic Bitspark/design#92), out of atlas's scope; atlas consumes design's render ABI through the lazy kit and the toolchain bundle.
  • Zero-dependency and lazy-design resolution are preserved end to end: #39 imports no design; #40 confines it to the renderer; the toolchain bundle is a CI input, not a runtime dependency.
  • This ADR records the architecture; the leaf issues carry the concrete schemas, CLI signatures, and acceptance criteria (refined on each issue). Epic #36 is ready to schedule.

The Bitspark constellation — how the systems are built and relate.

GitHub