Bitspark constellation
accepted source ↗

ADR 0019 — private members render in the public projections without a dead repo link

  • Status: accepted
  • Date: 2026-06-13
  • Relates: 0002 (the registry + manifest the flag lands in), 0005 (the generated views the flag is honored by), 0001 (the layer model that puts consumers in the topology)

A member can be in the family without its repo being public. private: true in topology/registry.json marks a member whose repo 404s for everyone outside the org. The public projections honor it: topology/family.md renders the name unlinked, and the site (/systems, /systems/[name], /graph) shows a private affordance instead of a repo link. The node still appears — consumers should be visible in the topology — and atlas topology sync still fetches the member's atlas.json through the org CI token.

Context

#533 (visual-atlas, the first application consumer) forces a small model decision. visual-atlas is a private repo, but topology/registry.json feeds the generated constellation figure and the public site (constellation.bitspark.xyz). We want to register it as a downstream member — consumers belong in the topology, the same way draft members are named before they are placed (ADR 0001). But a naive registration puts a node in the public projections whose repo link 404s for everyone outside the org.

The dead-link vectors are the two public views generated from the registry:

  • topology/family.md — a committed Markdown view that renders each member as a namerepo Markdown link. A private repo URL becomes a 404 link on GitHub for any outside reader.
  • the site/systems, /systems/[name], and /graph each render the member's repo as an external link; a private one is a dead link, and a docs deep-link into a private target repo 404s the same way.

The figure (diagrams/constellation-*.svg) is not a link vector — it is a visual graph with no hyperlinks, and it only draws members that have a hand-tuned layout position plus a @bitspark/design wordmark. A private downstream consumer has neither, so it is already absent from the figure; the only requirement there is that figure-coverage auditing must not demand a position for it.

Three options were weighed:

  1. a private: true flag the figure/site honor — the node stays visible, but with no public repo link (or a "private" affordance);
  2. exclude private members from the public site entirely, but keep them in the committed figure;
  3. accept the dead link (cheapest, ugliest).

Option 2 contradicts the reason we register consumers at all — they should be visible. Option 3 ships a known-broken link from the canonical public surface. Option 1 keeps the member visible and the surface honest.

Decision

Add an optional private: true flag to a registry member (topology/registry.json), schema-validated by schema/atlas-registry.schema.json alongside draft. atlas topology sync passes it through to topology/constellation.json, from which every generated view derives, so the rule is a renderer rule, not a hand edit (the constellation is generated; ADR 0002/0005).

The flag is honored as:

  • family.md — the member's name renders unlinked (bold, with no link markup). The absence of a link is the affordance in this terse generated view.
  • the site/systems, /systems/[name], and /graph render a muted "private repository" line and a private badge in place of the repo link; a docs deep-link whose target is private is suppressed.
  • the figure — unchanged: figure-coverage auditing exempts private members (as it does drafts), since a private member has no wordmark to lift and so could not be drawn even if placed.
  • atlas doctor — surfaces private members as an informational note, mirroring drafts.

The flag lives in the registry, not the member's atlas.json: whether a member is publicly linkable is a projection-policy fact owned by the public hub that does the rendering, and it must be readable without first fetching the private manifest. The repo URL stays in the registry (it is just a string, and topology sync needs it to fetch the manifest via the org CI token) — private: true governs only whether that URL is rendered as a public link.

Consequences

  • visual-atlas can be registered (#533) as draft: true, private: true, layer: downstream, with its atlas.json declaring build edges to ontos/horos — landing a visible node with no dead link. That registration is a follow-up; this ADR lands only the rule.
  • No committed artifact changes when the rule lands: with no private member in the registry yet, constellation.json, family.md, and the figure SVGs are byte-identical, so atlas doctor stays green. The mechanism is proved by unit tests (renderFamily, auditDiagram, the registry schema, the drift classifier), not by a placeholder member.
  • The repo URL is still committed in the public registry. private hides the link, not the fact that the member exists or the string of its URL; this is deliberate — the topology is a public map of who builds on whom, and a private repo's existence is not itself a secret.
  • A future member that needs its very name withheld is out of scope; that is a stronger policy (omission, not de-linking) and would be its own decision.

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

GitHub