ADR-0115 — Synced workspace catalogs must be links or freshness-gated (no orphaned copies)
- Sections
- 4
- Format
- Markdown
- Order
- 151 / 156
Context
The Phase-3 family sweep (workflow wf9rvvwys) confirmed the re-architecture this program shipped —
8→6 agents, 7→11 skills, mcp 0.2.0, the ADR-0112 catalog/kit split —
was correct in file structure, but the doc/reference layer drifted because every recurring issue
mapped to a missing automated gate, not to a bad design. One drift class was a stale catalog copy.
The governed skills catalog (suspec-skills) is the single source for the universal, framework-free
skills. The workspace keeps its own copy at suspec-works/.agents/skills, which is then symlinked into
the live .claude/skills the agents actually load. That copy is a hand-synced orphan: nothing tied
it back to upstream. The sweep found it 2+ days and one re-baseline stale — it was missing skills
that had been added to the catalog and still hosting a skill the catalog had retired. Because the
live .claude/skills symlinks into this copy, agents in the workspace were loading a skill set that
silently diverged from the governed source. A human noticed on the sweep; no gate did.
This is the same failure ADR-0016 and ADR-0017 guard against at the skill-body level — the Reference Illusion and hidden mandatory content — reappearing at the catalog level: a whole governed set copied into a workspace and left to rot. A copy that can drift will drift; the only question is whether anything catches it.
Decision
A governed catalog synced into a workspace MUST NOT be an orphaned copy. Concretely, where a
workspace consumes a catalog whose single source lives elsewhere (suspec-skills → suspec-works/.agents/skills),
exactly one of the two holds:
-
Preferred — it is a link to its single source. A symlink or git submodule pointing at the governed catalog, so there is no second copy to drift. The live
.claude/skillsthen links through to the one source, and "add/retire a skill upstream" propagates with no manual sync step. -
Where a physical copy is genuinely unavoidable — it carries a freshness check. A CI job that diffs the copy against upstream and fails on any divergence (a skill present upstream but missing in the copy, a skill present in the copy but retired upstream, or a content mismatch). The copy is then gated, not orphaned: it cannot silently fall behind the source.
No third option: a governed catalog is never copied into a workspace without one of link or freshness-gate. This is the catalog-scoped form of the no-dead-reference and no-hidden-content rules of ADR-0016 / ADR-0017, and it keeps the consumed set faithful to the minimal, governed source the kit tiering assumes (ADR-0064).
Honesty level (per ADR-0063). The principle
is in force now — accepted as a convention held by discipline and review: when this workspace's
synced catalog is touched, the reviewer checks it is a link or matches upstream, and an orphaned copy is
a finding. The freshness CHECK is the toolable path and is NOT yet shipped — there is no CI job today
that diffs the copy against upstream; nothing automated catches the drift, which is exactly why the sweep
caught it by hand. Relinking the existing suspec-works/.agents/skills copy to its source (option 1), or
landing the freshness-diff CI (option 2), is follow-up work, tracked in suspec-works. Until one of
those ships, this ADR's force is convention-plus-review, and this sentence is the honest statement of
that boundary.
Level: convention now; the freshness diff is toolable (not yet shipped).
Consequences
- Positive. The governed catalog has one source of truth again; "the workspace loads a different skill set than the catalog defines" stops being possible silently. Once option 1 lands, adding or retiring a skill upstream needs zero workspace sync; once option 2 lands instead, divergence turns a CI job red instead of waiting for a human sweep.
- Cost — discipline until the gate ships. Between now and the relink/CI, the rule rests on reviewer attention; an orphaned copy can still drift in that window. This ADR does not pretend otherwise — it records the convention and names the gate that would make it real, per ADR-0063.
- Cost — link mechanics. A symlink or submodule is one more piece of repo plumbing (clone/checkout must hydrate it; tooling that walks the tree must follow links). The freshness-check alternative trades that plumbing for a CI job to build and maintain.
- Scope. This governs governed catalogs synced into a workspace (the suspec-skills →
suspec-workscase the sweep found). It does not touch how an external adopter vendors a subset of the catalog into their own repo — that remains a deliberate copy under the self-containment rule of ADR-0016.
Affected obligations / constraints
- Refines (by reference, not edit — Nygard immutability): ADR-0016 (no-dead-reference, raised from skill body to whole catalog), ADR-0017 (no hidden/silently-diverging loaded content), ADR-0064 (the consumed set stays faithful to the governed source). Relates to ADR-0112 (the catalog whose copy drifted) and ADR-0063 (the level this ADR is held at).
- Does NOT change: the catalog/kit partition, any skill format, or the artifact set. The freshness check is named here as the toolable enforcement path; it is not yet built.
Starter kit: Set up a workspace