ADR-117: Module guidelines
Status: Proposed Date: 2026-04-26 Related: ADR-067 (playbooks-unified-primitive), ADR-099 (brief-as-pr), ADR-107 (gates-as-playbook-primitives), ADR-109 (type-claude-step-and-observer-field), ADR-110 (observe-and-file-dominant-pattern), ADR-112 (principles tier — sibling), ADR-115 (principle-aware reviewers — sibling), ADR-116 (RAG — sibling)
Context
Today the agent brief is the only contract for module-typed work (DB changes, playbook authoring, API endpoints, UI components, ansible roles, agent briefs themselves, docs). Each brief is full prose, hand-assembled by the operator or a parent agent, drift-prone, and re-derived per ticket. The recurring memory rule feedback_warp_items_need_structural_detail.md names the symptom: stub items poison the board because there is no canonical shape for "what this kind of work needs to include".
Principles (warp #339, ADR-112) constrain system-design judgements. They do not say "a DB-changes ticket must include a rollback plan and a regenerated-types check." That is module-implementation guidance — a different scope, a different artifact, the same shape. Today that guidance is dispersed across CLAUDE.md sections, memory files, and tribal knowledge encoded in operator briefs.
The decision is tracked in warp #346 (sub-tickets r1 through r9). It collapses several open questions into a single primitive: principle-aware reviewers (ADR-115) need a per-module data source; the RAG (ADR-116) needs a categorical syllabus, not just a library; structural checks (warp #335) need to fire by module membership, not universally.
Decision
A module guideline is a versioned, immutable-on-publish per-module spec stored at dark-factory/guidelines/<id>@v<n>.md. Each guideline carries:
applies_to— file/path globs and ticket-tag patterns that match this modulerequired_steps— the ordered shape of work in this modulestructural_checks— automated checks that fire on PRs in this moduleforbidden_patterns— anti-cases (regex or rule references)ticket_body_template— the canonical issue/ticket body shape (warp-addrejects ticket bodies that fail this template)acceptance_proof_required— what the PR must demonstrate to mergeknowledge_base_routes— RAG queries the agent should run for contextreviewer_directive— the guideline-anchored prompt insertion for ADR-115 reviewersconstrained_by— citations of principles (ADR-112) this guideline rests on
The seven founding guidelines (warp #346 r3), backfilled from existing memory rules, ADRs, and CLAUDE.md sections (mostly compaction, not new content):
db-changes@v1— migrations, rollback, schema review, regenerate typesplaybook-authoring@v1— schema, hard-assert terminal, dry-run-clean auditapi-endpoint@v1— OpenAPI spec first, generated types, runtime validation, contract testsui-component@v1— gy-* convention, design tokens, smoke spec, page-type categorisationansible-role@v1— tag-friendly tasks, become true on system mods, idempotency testsagent-brief@v1— time-box, atomic chunks, no-touch-working-treedocs-authoring@v1—docs/shared/vs repo-root, AUTO-GENERATED markers, viewer-validator
Enforcement is three-layer:
warp-add— walks new ticket tags, attachesguideline_cited, rejects malformed bodies against the guideline'sticket_body_template.warp-claim— bundles the cited guideline (full text plus current version) into the claim response so the agent reads it before opening files.gyrum-review-pr— fifth gate (alongside the four personas) verifies the guideline'sacceptance_proof_requiredis satisfied; reviewers fetch the guideline alongside applicable principles and anchor blocks to both.
Versioning: bumping a guideline mints a new file (@v<n+1>.md) and writes a migration note for in-flight cites. Old version stays immutable so retroactive judgement against the version-as-of-claim remains possible.
Consequences
What becomes easier.
- Agent briefs shrink and stop drifting. The guideline owns the shape of work; the brief becomes "implement X per
playbook-authoring@v1" plus the case-specific scope. Theagent-brief@v1guideline itself codifies time-box and atomic-chunk rules so even meta-briefs follow a contract. - Ticket bodies follow a per-module template, killing the stub-ticket failure mode the operator has flagged repeatedly.
warp-addrejection is structural, not advisory. - Reviewers (ADR-115) anchor to two documents per PR — the cited principles plus the cited guideline's
acceptance_proof_required— so blocking has a much narrower premise space. - Structural checks (warp #335) fire by module membership: the
db-changeschecks run on PRs thedb-changes@v1guideline matches, not on every PR. The check stack stops being one-size-fits-all. - The RAG (ADR-116) gains a categorical layer: guidelines are syllabi that route queries; principles and ADRs are the library being queried.
What becomes harder.
- Guidelines themselves drift if unmaintained. Mitigation: a nightly stale-guideline alert (warp #346 r9) flags any guideline unreviewed for >90 days; the principles ↔ guideline back-citation lets revision-on-principle-change cascade.
- One-time authoring overhead for the seven founding modules. Most content already exists in memory and CLAUDE.md; the work is compaction and shape-enforcement, not invention.
- A new validator (
gyrum-validate-module, warp #346 r7) becomes part of the pre-PR loop. Local CLI fires it, agent runs it pre-complete, review-pr re-runs in CI as the gate. That is more friction per PR but predictable, structural friction — the kind thefeedback_structural_over_prose.mdmemory rule prefers. - Edge cases that touch two modules (a UI component that also adds an API endpoint) need guideline-composition rules. v1 keeps it simple: the PR cites both, both gates run, both must pass.
What we sign up to maintain.
- The
dark-factory/guidelines/directory, the schema, and the seven founding guideline files. gyrum-validate-moduleand its per-module check implementations.- The
warp-addrejection logic, thewarp-claimbundling logic, and the fifth review gate ingyrum-review-pr. - The nightly stale-guideline cron and its alert routing.
- Versioning + revision workflow: minting
@v<n+1>files and migration notes for in-flight cites.
Alternatives considered
- Keep guidance in CLAUDE.md sections (status quo). Rejected: CLAUDE.md is a single document per repo with no per-module structure; the consumers (warp-add, warp-claim, review-pr) cannot route to "the playbook-authoring section" without grep-hacking. Guidelines as separate, versioned files give a clean addressable shape.
- Use principles for everything — drop the guideline tier. Rejected: principles are system-design constraints ("structural beats prose"); guidelines are module-implementation contracts ("a db-change PR includes a rollback plan"). Conflating them dilutes both. The
constrained_byfield on guidelines keeps them honest by forcing each guideline to cite its underlying principles. - Per-repo guidelines instead of fleet-wide. Rejected: the seven founding modules cut across repos (every repo writes ansible roles, every UI repo authors components). Per-repo duplication re-introduces drift; fleet-wide gives one source of truth and per-repo
applies_topatterns handle the local variation. - Make guidelines mutable in place — no versioning. Rejected: an in-flight ticket claimed against
playbook-authoring@v1should be judged against v1 even if v2 lands mid-implementation. Immutable versions plus explicit migration notes is the smallest correct shape.
Supersedes: none Superseded by: none yet
Amendment — 2026-04-29 (warp#698 / ADR-124)
The eight founding guideline list grows to include pipeline-step@v1 — typed I/O ports per ADR-085, block-composition over imperative per ADR-124, generic block name plus domain-specific pipeline name, single concern per block. constrained_by cites both ADR-085 (the typed-port decision) and ADR-124 (the block-composition principle). The guideline's forbidden_patterns includes func.*\(.*RunContext\) for new code under cmd/server/pipeline/** — existing matches are legacy graduation backlog (warp#707), not gate violations.