Traceability
Each rule points to an ADR by stable identity and relative path, preserving the origin of the constraint.
Architecture case study · open-source project
An ADR can explain why Domain must not depend on Infrastructure. The next challenge is detecting, with verifiable evidence, when the implementation stops respecting that decision.
This is a reproducible repository scenario, not a claim of production adoption or comprehensive architecture certification.
Problem
As software evolves, a convenient project reference can reverse an intended boundary. The ADR remains accepted and readable while the actual code graph tells a different story.
The consequences emerge later: domain rules learn about persistence, tests require infrastructure, and technical change crosses layers that were meant to evolve separately. The missing link is feedback between the decision and inspectable implementation evidence.
Constraints and quality attributes
Each rule points to an ADR by stable identity and relative path, preserving the origin of the constraint.
The same input should produce stable ordering, fingerprints, outcomes, and reports.
Missing, dynamic, or ambiguous evidence yields unknown, never implicit approval.
Drift, impact, and structural validation have independent contracts without mutating published formats.
Architecture decisions
adr-guard check validates metadata, sections, references, lifecycle, and other document contracts. A valid ADR does not prove that code conforms to it.
adr-guard impact correlates changed files with explicit local mappings. It identifies decisions that may need review; it does not issue a compliance verdict.
adr-guard drift evaluates opt-in rules associated with effective ADRs. Version 1 proves only exact static project references and consumes reported external tests.
AdrGuard.Core owns parsing, validation, Git inventory, impact, and drift for the CLI and MCP host. It is not a standalone public package; UI and transport remain at executable boundaries.
Complete deterministic evidence proves the declared condition.
Complete deterministic evidence proves the condition false.
Evidence is insufficient, missing, dynamic, conditional, invalid, or contradictory.
The referenced ADR is not effective under the configured lifecycle policy.
Components and contracts
MCP does not approve decisions; AI review is optional and advisory. The existing composite Action did not implicitly gain drift mode: the guide installs the tool and invokes drift in an explicit step.
Reproducible implementation
The accepted ADR states: “The Domain project must not reference the Infrastructure project.” Its consequences acknowledge that conditional or dynamically expanded references require human review.
{
"schemaVersion": "1.0",
"rules": [{
"id": "domain-no-infrastructure",
"decision": {
"stableId": "ADR-1",
"path": "docs/adr/0001-protect-domain-boundary.md"
},
"scope": { "projects": [
"src/Domain/Domain.csproj",
"src/Infrastructure/Infrastructure.csproj"
]},
"check": {
"type": "forbid-project-reference",
"from": "src/Domain/Domain.csproj",
"to": "src/Infrastructure/Infrastructure.csproj"
},
"evidence": { "source": "dotnet-project-reference" },
"failure": { "severity": "error", "onInconclusive": "unknown" },
"gate": true
}]
}adr-guard drift . --rules .adrguard-fitness.json --format json
# Fixture's documented outcome: pass
The committed Domain.csproj contains only its SDK and target framework. The complete static reference set does not contain the forbidden dependency.
<ItemGroup>
<ProjectReference Include="../Infrastructure/Infrastructure.csproj" />
</ItemGroup>
After replacing the project with the violation fixture, the repeated command reports the exact reference and line as a violation.
| Execution | Documented behavior | What it does not mean |
|---|---|---|
--policy advisory | The default; reports the violation without using it as an enforcement block. | It does not turn the violation into success. |
--policy enforce | A new, gate: true, locally verified deterministic violation exits 4. | It does not block every external failure or every violation recorded in a baseline. |
unknown outcome | Exits 3 under both policies and cannot masquerade as a green check. | It is not converted into a violation. |
| External evidence | Preserves provenance as a reported observation. | It is not attestation and never authorizes automatic blocking. |
adr-guard drift . --rules .adrguard-fitness.json \
--baseline drift-baseline.json
# Previous violation: resolved
# Current rule: pass
A baseline is created or replaced only by an explicit command and should be reviewed like code. Removing the forbidden reference restores pass; compared with a snapshot containing the finding, its history becomes resolved.
Alternatives and trade-offs
Essential for interpreting decisions and exceptions, but repetitive drift can escape attention across pull requests.
Use when: a rule has no deterministic representation or is context-sensitive.
They can analyze code more deeply but require stack-specific implementation. ADR Guard may consume results only as reported external evidence.
Use when: invariants exceed the static v1 contract.
It would resolve more conditional references but execute a complex, potentially untrusted surface. Version 1 deliberately does not invoke MSBuild.
Choice: conditions and properties remain unknown.
They reduce immediate friction but can normalize regression. Creation and replacement remain explicit owner actions.
Choice: auditable history over silent acceptance.
Limitations and risks
Version 1 inspects only exact static ProjectReference relationships in explicitly scoped .csproj files. Imports, wildcards, properties, conditions, missing files, unsafe XML, and exceeded bounds are inconclusive. It performs no network discovery or arbitrary execution.
A poorly stated rule can be deterministic yet misrepresent its ADR. Partial coverage, legitimate exceptions, and lifecycle changes still need human governance. pass means that one condition was proved under one contract—not that the solution received broad certification.
Lessons and evolution
Separating check, impact, and drift prevents “valid document,” “related change,” and “broken constraint” from becoming synonyms. Four outcome states keep missing evidence from becoming compliance.
Extracting Core reduces divergence between CLI and MCP without creating a public API. New versioned checks can evolve the system if they preserve provenance, uncertainty, compatibility, and human authority over decisions and baselines.
Evidence and references