Constellation Member Taxonomy — Primary, Addon, Projection; Recursion in the Level Graph, Not Git; Uniform Forge Rule

Accepted

ontoref
ADR-048 fixed the constellation layout (non-versioned parent, independent git

Context

ADR-048 fixed the constellation layout (non-versioned parent, independent git sub-repos, spine at parent) on one implicit assumption: one folder = one publication boundary (code→Forgejo, outreach→public, vault→private). Reality stressed that assumption from two directions the original ADR did not name.

(1) DERIVATION/COUPLING. Some surfaces exist by relation to another member, not autonomously. The daemon UI is served by ontoref-daemon (peer ontoref-ui), shares code's remote/visibility/release. desktop is an app with its own cycles, versions and multi-license terms. examples are CI-tested fixtures that also feed docs and workshops. study-group is a workshop format that consumes examples. None of these map cleanly to "a folder with one boundary".

(2) INTRA-MEMBER VISIBILITY SPLIT. Some surfaces carry the boundary inside the build pipeline, not between folders. presentations are md slides (own cycles) that project to public PDFs. web is a distributable pack rendered to jesusperez.pro; site renders to ontoref.dev — different deploy targets, same public visibility. docs is the extreme case: one generated source routed to dev (code), public (outreach) and private (vault) audiences, served by an external docserver (/Users/Akasha/Development/docserver, a peer like stratumiops, not a member).

The pull this created was toward git submodules / nested repos to mirror the apparent recursion (code{daemon,UI,examples}, outreach{site,web,presentation, study-group}). That pull is the error this ADR closes: it would reify a logical recursion into the most expensive substrate (git topology + version-pinning + clones), and — decisively — a submodule IS clone-and-pin, which contradicts the project's own witness-not-clone invariant (ADR-028). ontoref describing its own internal structure by cloning would be anti-PAP of its deepest axiom.

Decision

Classify every constellation member into exactly one of three categories, decouple the logical recursion from the git topology, and fix a uniform forge rule.

THREE CATEGORIES - Primary — owns a publication boundary (distinct remote + visibility) OR a distinct release lifecycle. Gets its own git repo. Members: code/, outreach/, vault/, desktop/. - Addon — exists by a declared dependency edge to a Primary, with its own lifecycle. Gets its own repo ONLY when it earns its own boundary; otherwise it is a node in the level graph inside its Primary. desktop is an Addon-that-earned-Primary (ADR-054 capture surface, multi-license); the daemon UI is an Addon that stays inside code/. - Projection — one source, the frontier lives INSIDE the build. Never its own repo. Four sub-shapes the build routes: copy assets/ — canonical → identical materialized copies reveal site — projects the live graph (ADR-057) visibility-split presentation — private/undeployed src → public PDF multi-boundary docs — one source → dev/public/private slices by audience (ADR-046 view) → docserver

DECISION DRIVER. "Own repo?" is decided by publication boundary or release lifecycle, never by conceptual separability. Conceptual recursion is carried by the level graph (ADR-045 relative chains + manifest.hosts co-tenancy, resolved by witness, never cloned), decoupled from the filesystem (ADR-028). Submodules are forbidden as a structural mechanism; they are admissible only if a sub-surface earns an independent boundary AND needs version-pinning into a parent — a condition zero current surfaces meet, and even then the ontoref-native form is co-tenancy-by-witness, not a git submodule.

UNIFORM FORGE RULE. Forgejo (repo.jesusperez.pro) is always the canonical origin. GitHub is always a one-way push-mirror (Forgejo native push-mirror, force-overwrite of all refs → de-facto read-only) or absent — never canonical of anything. rad (Radicle) is an optional sovereign peer, pushed separately, never inside the mirror chain. vault is excluded from every mirror (Forgejo private only). code/ carries all three (Forgejo canonical + rad sovereign + GitHub mirror); outreach/ and desktop/ carry Forgejo canonical + GitHub mirror; vault/ Forgejo private only.

PLACEMENTS. examples → code/ (CI fixtures), projected to outreach docs and consumed by study-group via co-tenancy. presentations → src in outreach/presentation/ (public repo, PDFs deployed, sources not); strategically sensitive decks are the exception routed to vault. study-group → outreach/, hosts the examples chain by witness (ADR-045 instance-as-host). docs → not a member: a multi-boundary projection whose private branch is sourced tags-in-place (each member carries its own docs tagged by audience; docserver composes the slices), per ADR-046/060.

DEV-INTERNAL OVERLAY. Each member's dev-internal process and config (.coder/, .claude/) is gitignored from the public-mirrored history and tracked instead in a private 'bare-overlay' repo: a separate git-dir at <member>/.internal.git (itself gitignored) whose work-tree is the member root and which tracks only those two dirs. It pushes ONLY to a private Forgejo remote and is NEVER mirrored — the same boundary as vault, one sensitivity tier below it (plaintext, not SOPS). The public repo and the overlay coexist on one working tree via distinct git-dirs (plane-habitability), which is NOT a submodule (no .gitmodules, no pin). Tooling: code/scripts/internal-overlay.nu (setup / onboard / commit / run), generic for any project with the same .coder/.claude layout.

Constraints

  • Soft Every constellation member is classified as exactly one of Primary | Addon | Projection; a new member declares its category before it is wired.
  • Hard No constellation member uses git submodules to express internal structure or cross-member composition; recursion is carried by the level graph (ADR-045 co-tenancy), resolved by witness, never cloned.
  • Soft Forgejo is the canonical origin of every materialized member; GitHub appears only as a one-way push-mirror, never as canonical.
  • Hard vault/ is excluded from every public mirror — it has no github.com remote and no rad:// peer; Forgejo private only.
  • Soft An Addon declares its dependency edge to the Primary it derives from (desktop → code via cargo path dependency), so the derivation is explicit, not implied by colocation.
  • Soft A member's .coder/ and .claude/ are gitignored from the public repo and tracked in a private bare-overlay repo (git-dir at <member>/.internal.git, work-tree the member root) that pushes only to a private remote — never github/rad.
  • Soft A Projection surface (assets, site, web, presentations, examples, docs) does not become its own git repo; it lives inside a Primary and the build routes its visibility.

Alternatives considered

  • Git submodules / nested repos to mirror the conceptual recursion, with examples/presentations nested insiderejected: A submodule is clone-and-pin, contradicting witness-not-clone (ADR-028) — ontoref would violate its own invariant to describe itself. It also reintroduces version-pinning the constellation does not want and the friction ADR-048 already rejected. Recursion belongs in the level graph (ADR-045), resolved by witness, not in git topology.
  • Promote every conceptually separable surface (daemon UI, site, web, examples) to its own reporejected: Conceptual separability is not a publication boundary. This proliferates repos with shared remotes/visibility/cadence, multiplying remotes and CI for surfaces that share one boundary — the opposite of ADR-048's minimal topology. The driver is the boundary, not the concept.
  • Make GitHub canonical for the public-facing members (outreach), since the audience lives thererejected: Splits the sovereignty model into special cases and cedes a canonical to a centralized host. The one-way mirror already delivers reach without surrendering authority; a uniform Forgejo-canonical rule is more coherent with the project's sovereignty axioms.
  • Add a fourth top-level category for cross-boundary surfaces like docsrejected: docs is not a new category — it is a Projection whose build fans out to multiple visibility targets. Naming it a sub-shape (multi-boundary) of Projection keeps the taxonomy at three and reuses the existing projection machinery (ADR-046 views, ADR-060 mdbook) instead of inventing a parallel concept.

Anti-patterns

  • Submodules to Mirror Conceptual Recursion — Reaching for git submodules / nested repos to express a member's internal sub-surfaces. A submodule is clone-and-pin, contradicting witness-not-clone; it reifies a logical recursion into git topology and reintroduces version-pinning the constellation does not want.
  • A Repo Because It Is Separable — Promoting a surface to its own git repo because it is conceptually distinct, when it shares the remote, visibility and release cadence of its host. Multiplies remotes and CI for surfaces that share one publication boundary.
  • Letting the Public Mirror Hold Authority — Making GitHub the canonical origin of a public-facing member because the audience lives there. Cedes a canonical to a centralized host and fragments the sovereignty model into special cases.

Related ADRs

ADR-048 · ADR-054 · ADR-045 · ADR-028 · ADR-013 · ADR-057 · ADR-060 · ADR-046

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.