Skip to content

ADR 0003 — Repository topology: separate repositories, one fixture per purpose

  • Status: Accepted
  • Date: 2026-08-09
  • Context repos: all

Problem

Cratly is spread over six repositories. Working across them in August 2026 produced a recurring cost: a change in the adapter could not be verified against a real site without publishing it first, and consumers had to be bumped one by one afterwards. The question was whether a monorepo would make maintenance materially simpler.

What a monorepo would genuinely have fixed

Not hypothetical — each of these happened:

  • A framework feature sat on a branch for seven weeks while the editor and the fixture site already assumed it. A single repository would have made that one atomic commit.
  • A defect in media-folder resolution survived for months because no site exercised it; the adapter had no fixture its own CI could build.
  • Every release meant packing, publishing, then bumping three consumers and regenerating their manifests — run twice in one week.
  • The CI seed image drifted three revisions behind because its dependencies lived elsewhere.

What it would have cost

  • The boundary between editor and adapter is the product promise. The editor must know nothing about Scavold so that other adapters remain possible. Separate repositories make that physically true; in a monorepo it degrades into discipline, and an import across the boundary would compile without complaint.
  • The licence split (ADR 0002) would mix GPL and MIT inside one tree.
  • Adapter authors and customers would clone everything to get the part that concerns them, and a site template has to stand alone because it is copied as a GitLab project template.

Decision

Keep the repositories separate. The pain did not come from their number but from two structural faults, which are addressed directly instead:

  1. The adapter gets its own fixture site inside its repository, built and asserted by its own CI on every commit. Verifying a change stops requiring a release; publishing returns to being an act of release rather than a step in development.
  2. One fixture per purpose. test-website was serving two masters: it is the live GitLab project the editor's end-to-end tests authenticate against, with real branches and merge requests, and it was meant to be the adapter's markup fixture. That is why it contained no container block and no image for months — whoever maintains it as an editor target does not need them, and whoever changes the adapter never built it. It keeps the editor role; the adapter gets its own.

Merging tools into scavold remains defensible later — the seed image mirrors the adapter's dependency set one to one and has no independent lifecycle. It is not worth doing while a second image variant is still conceivable.

The editor, the specifications and the template stay where they are.

When this phase ends

Committing straight to main in the repositories we develop is a decision about now, not a principle. Its condition is the current one: no customer site depends on any of this productively yet. Once a usable state has proven itself in production, plain commits to main stop being the right default.

The intended shape for that phase — a leaning rather than a settled rule: when a rebuild spans repositories, branch per feature and give the branch the same name in every affected repository. That way the participants of one change are visible from the name alone, which is exactly what was missing when a framework feature sat on a branch while two other repositories already assumed it. A shared name also gives verification something to pair on, instead of leaving the connection in someone's head.

What must not come back with it is the long-lived branch. The rule from above still holds in either phase: publish the producer first, then upgrade the consumers.

Consequences

  • Cross-repository changes still need ordering: publish the producer first, then upgrade the consumers. See How the pieces fit.
  • Two fixtures have to be maintained, deliberately. They test different things — markup and manifest on one side, the editing and review workflow on the other.
  • The multi-repository cost is paid in tooling rather than in structure: the adapter's fixture job, and a documented release procedure.