repositoryStandards v1.1.20

ADR-005: The align/update engine reads a versioned manifest, not just prose

StatusAccepted
Date2026-07-07
AuthorƁukasz Bodurka
Tagsmethodology, align-engine, distribution

Context

A repo adopts the standard with align-to-standards and stays current with update-to-version; both are prose skills an agent interprets. ADR-005's keystone work (the versioned pin .standards-version + self-verify) made compliance checkable, but the align/update step itself is still an agent reading instructions and deciding what to do.

That leaves three forces unmet:

  • Repeatability. Prose is interpreted differently each run - and agents demonstrably make mistakes aligning a repo. The same repo + same version should converge on the same result.
  • Measurable drift. "How far is this repo from v0.7.2?" should be a number, not a vibe - so a fleet owner can see which repos are behind.
  • Precise updates. Applying a vY -> vX delta needs a machine-readable description of exactly what changed between those versions, not "re-read the changelog and figure it out."

...without losing what already works: adapt-to-the-stack (not blind copy), stack-agnostic Layer-1 simplicity, and client deviations that survive an update (ADR-004).

Options considered

  • A - Prose skills only (status quo). Keep align-to-standards / update-to-version as written workflows. Zero new artifacts, maximum flexibility; but interpretation varies run to run, drift is not measurable, and updates lean on an agent re-reading the changelog. Reliability is exactly the gap.
  • B - A declarative manifest the engine reads (recommended). Each standard version ships a manifest (data): the required files, sections, guards, and decisions an aligned repo must have, each with an adapt rule (copy / merge / fill-from-repo / reference). The align, update, and self-verify skills all read it. Drift = the diff between the repo and the manifest (a number). Update = the diff between two versions' manifests (the exact plan). Deviations are recorded manifest exceptions. Data is Layer 1 (an agent applies it, no tooling required); a Layer-2 stack may add a runner. Cost: a manifest schema to design and keep honest.
  • C - Executable migration scripts per version. Like DB migrations or Copier tasks: each version ships an up() that transforms a repo. Precise and ordered, but heavy and brittle across the infinite variety of real client repos, stack-specific, and it fights adapt-to-the-stack - a script cannot reconcile like an agent can.

Decision

Adopt Option B. The align/update engine is driven by a versioned, declarative manifest; the agent applies it (adapting to the stack), and self-verify checks the repo against the pinned version's manifest. Drift becomes a measurable diff; a version update becomes a manifest-to-manifest delta.

Reject A (the reliability and measurability gaps are the whole point) and C (too rigid for the adapt-to-stack, brownfield reality this standard targets). The manifest is data (Layer 1); any runner/tooling is Layer 2. This does not replace the prose skills - it gives them a spine to read.

Consequences

  • Positive: drift is a number; updates are precise (manifest delta); self-verify gains a concrete thing to check against; a fleet can be reported on.
  • Negative / cost we accept: a manifest schema must be designed and versioned, and kept from drifting out of sync with the actual standard (mitigation: the skills read the manifest, so it cannot rot unused; self-verify asserts it).
  • Follow-ups (now landed, ENG-2): the manifest schema exists as a real, shipped artifact (standard.manifest.json); self-verify.mjs reads it and emits a drift score. Still open: teaching align-to-standards / update-to-version to compute their plans from the manifest delta (they now reference it; full mechanization is a later increment).

Confirmation

Confirmed. self-verify.mjs reads the pinned version's standard.manifest.json and checks the repo against every entry (files, required sections, static guards), reporting drift as a number; a version/manifest mismatch fails. The schema now exists and is dogfooded (this repo ships its own manifest), so the decision is no longer a direction - it is in force.

Revisit when

  • The manifest becomes as hard to interpret or maintain as the prose it replaced (over-engineered) - then step back toward A for the parts that resist description.
  • A Copier-style 3-way merge tool makes executable, adapt-aware migrations cheap enough to reconsider C.

Builds on ADR-004 (decisions reach clients by reference, not copy) and the versioned self-update mechanism (.standards-version, update-to-version, self-verify). Governs the align-engine. Backlog: ENG-2 (built - self-verify reads the manifest) and this record (ENG-3).

Appendix - the manifest

The manifest is a real, shipped artifact: standard.manifest.json (reflected to dist/standard.manifest.json) - repository-standards describing itself at the current version. self-verify.mjs reads it; an aligned client repo carries a copy at its pinned version.

Shape. Four lists plus two policy blocks, each entry carrying a since version and an adapt rule:

  • files - the paths an aligned repo must have, each with an adapt rule (copy / merge / fill-from-repo / reference) that says how it arrives. Guards are copy; ARCHITECTURE/specs are fill-from-repo (scaffold the shell, author the body from the repo - never blind-copy); the standard's own decisions are reference (ADR-004).
  • sections - required headings inside a file (e.g. AGENTS.md must state Altitude).
  • guards - the checks that must pass, static (run anytime) or diff (run on a PR diff).
  • decisions - the catalog forks a repo must consciously record, each mapped to ADR/BDR.
  • specs / exceptions - the buildable-tier default and how a deliberate deviation is recorded so an update never silently overwrites it.

The three operations it unlocks (the whole reason for Option B):

OperationToday (prose)With the manifest
Verifyself-verify.mjs hardcodes the skeleton listit reads the pinned version's manifest and checks every entry - one source of truth, not a JS copy
Drifta judgement callcount(manifest entries the repo fails) - a number a fleet owner can sort on
Update vY -> vXre-read the changelog and figure it outthe diff of the two versions' manifests (keyed by kind + id/path), filtered by since - the exact plan

The manifest never replaces the prose skills' judgement (adapt-to-stack, brownfield reconciliation an agent does better than a script - why C was rejected); it gives them a spine to read.