Skip to content
GitHub
Decisions

ADR-067: `spectral.core` killer-test re-audit cadence

Status: Accepted (2026-04-29) — D1 + D2 superseded by ADR-069; D3 + D4 in force

Context

ADR-065 repeals ADR-024’s PR-statement governance and replaces it with three layers of spectral.core admission discipline:

  1. Per-addition articulation. Every Python module under core/<subdir>/, including __init__.py, carries a one-line module docstring stating its functional-area-membership rationale. Enforced by ruff D100 + D104; the functional-area-membership wording is convention.
  2. Structural enforcement. Validator rules 1–7 catch type-shape violations and import-direction violations.
  3. Per-PR judgment. The founder reviews each addition for “no owner context” plausibility against the docstring rationale.

What catches cumulative drift — items that pass per-PR judgment individually but, viewed together over months, fail the killer test? ADR-024’s PR-statement test failed precisely on this dimension: every type in spectral.core failed the killer test under inspection during session 20, and every one of those types had passed individual PR review under ADR-024’s discipline. A periodic re-audit is the structural backstop against the same failure mode reasserting itself.

This ADR specifies the cadence, the trigger override, and the procedure.

Decision

D1. Cadence

Superseded by ADR-069. Cadence is fully trigger-driven (no calendar floor); see ADR-069 D1 for the trigger conditions.

D2. Trigger override

Superseded by ADR-069. The 25%-growth signal carries over but is no longer an “override” since there is no calendar to override; see ADR-069 D1 for the full trigger-signal set.

D3. Procedure

  1. Walk each core/<subdir>/ in turn (events, auth, db, retention, llm, embeddings, tools).
  2. For each Python module file (including __init__.py), re-apply the killer test: “if spectral.core did not exist, where would this go?” Use the module’s admission-rationale docstring as the starting input to the test.
  3. Categorize each entry as:
    • Retain. Killer test still has no clean single-context answer; remains in core/<subdir>/.
    • Relocate. Killer test has a clean single-context home now (the consumer pattern shifted, or the type’s actual usage narrowed); mark for relocation to <context>.contracts.* or to a context’s domain/application/infrastructure layer.
    • Refine. Admission rationale needs sharper articulation (docstring update); no relocation.
  4. For each Relocate, mint or queue the relocation work as a refinement-track item per the existing epic-template doctrine. Relocations are real code moves, not paperwork.
  5. Land an audit-record document noting items audited, retentions, relocations, refinements. Brief — roughly one paragraph per core/<subdir>/. Future audits start from the previous record. (Records location is docs/audits/<YYYY-MM-DD>-core-reaudit.md per ADR-069 D2; the original planning/audits/ path was superseded.)

D4. Responsible owner

Founder under current operational reality. Re-evaluate ownership when team scaling materially shifts the landscape.

Alternatives considered

  • Per-PR governance only (no periodic audit). This was ADR-024’s mode. Failed on cumulative drift; the orchestration that produced ADR-065 is the evidence. Rejected.
  • Annual cadence. Too infrequent given alpha-pace evolution; drift can compound substantially across four quarters. Rejected.
  • Event-triggered only (e.g. on every commit to core/). Too noisy; would create review fatigue and dilute the audit’s seriousness. Rejected.
  • Continuous via lint. Lint enforces structural and import constraints (validator rules 1–7); killer-test judgment is irreducibly human (judgment of intent + actual usage patterns, not type shape). Lint cannot replace the audit; the audit cannot replace the lint. Both layered.
  • Audit triggered by spectral.core line-count growth instead of module count. Considered; rejected because module count is a cleaner proxy for “new admission decisions made” than LOC, which can grow within a single module without new admissions.

Consequences

  • Audit-record documents accumulate in docs/audits/ (per ADR-069 D2; supersedes the original planning/audits/ framing). Each audit starts from the previous record.
  • Relocations identified during audits feed normal refinement-track work; they are not separate “audit follow-up” tracks.
  • Cumulative-drift compound effect: drift that survives per-PR judgment is caught when its trigger signal fires (per ADR-069 D1). ADR-024’s failure mode (cumulative drift accumulating undetected for months) cannot recur under the layered discipline.
  • The audit’s seriousness is preserved by the trigger discipline (audits fire when there’s something to re-examine, not on a calendar; per ADR-069).