Supporting enforcement example · ADR-004 5 min read FAIL

# Repository pattern enforcement

An AI coding agent refactors `user.service.ts` and reaches straight into the database connection — bypassing the Repository abstraction `ADR-004` exists to protect. The diff looks clean in the editor. Mneme's enforcement layer hard-fails it before it can land.

By Theo Valmis · Published May 2026 · All scenarios

## The scenario

The codebase uses the Repository pattern as its data-access boundary. `ADR-004` records the rule:

ADR-004 · Repository pattern is the only data-access boundary. All persistence flows through repository classes (`UserRepository`, `OrderRepository`, etc). Service classes depend on repository interfaces, not on the underlying storage layer. Direct database access from a service or controller is a violation.

An engineer asks the AI assistant to "speed up `user.service.ts` by inlining the lookup." The agent obliges. The diff opens cleanly:

user.service.ts · diff
export class UserService {
constructor(private users: UserRepository) {}
constructor(private db: Database) {}
async getActive(id: string) {
return this.users.findActive(id);
return this.db.query('SELECT * FROM users WHERE id = $1 AND active = true', [id]);
}
}

Locally, this is faster. Architecturally, it dissolves the abstraction `ADR-004` exists to maintain. Once `UserService` talks to the database directly, the next refactor copies the pattern, and the repository layer becomes a residue rather than a contract.

## Without Mneme

The diff reaches review. The reviewer is moving fast on a Friday afternoon. The change is small, the SQL looks correct, the test passes. The PR merges. Three months later, four services have grown direct database calls, the repository layer has unused methods that nobody refactors out, and a new engineer asks why there's a Repository pattern that nobody uses.

This is the failure mode architectural decisions exist to prevent. It is not caught by a linter (the SQL is fine), not caught by tests (the behavior is correct), not caught by typing (the types check). The only signal is the architectural rule itself, and that rule lives in human memory unless something operationalizes it.

## With Mneme

Mneme intercepts the diff post-generation. The retriever surfaces `ADR-004` as relevant to changes touching `*.service.ts` files. The evaluator inspects the diff for direct database access patterns and matches the violation. `mneme check --mode strict` exits non-zero with a structured verdict:

mneme check · repository row
FAIL
Violates ADR-004 — Repository pattern bypassed in `user.service.ts`.

The verdict carries the originating decision ID (`ADR-004`) and the file path of the violation. A reviewer reading the CI output can navigate directly to the decision record, see the rationale, and either fix the diff or open an explicit override decision — which is itself a tracked event in `project_memory.json`.

## Why FAIL and not WARN

Architectural pattern violations have outsized downstream cost. Once one service bypasses the repository layer, the next refactor copies the pattern, and within six months the abstraction is dead. Mneme returns FAIL on architectural-pattern violations by default to keep the cost localized to the diff that introduced it. The override path exists, but it is a tracked decision rather than a silent merge.

## How to wire this up in your repo

Add an architectural-pattern decision to `project_memory.json` with `type: "architectural_pattern"`, the boundary it protects (e.g., "data-access via repository only"), the file scope (`**/*.service.ts`), and the violations to detect (direct database imports, raw SQL, ORM calls outside the repository layer).

Hook it in CI via the GitHub Actions integration: a failed `mneme check` in strict mode exits non-zero, which fails the workflow, which blocks the PR. For interactive enforcement during the editor session, the Claude Code hook intercepts `Edit` and `Write` calls and surfaces the constraint to the agent before the diff is even proposed.

For the broader argument that this enforcement layer has to live outside any single AI coding tool, see architectural governance across heterogeneous AI coding agents.

## FAQ

What is the Repository pattern in this scenario?
An architectural rule recorded as ADR-004: all data access goes through repository classes, never directly from service or controller layers. Services depend on the repository interface, not on the underlying storage. ADR-004 makes this constraint explicit so it can be referenced, queried, and enforced by Mneme rather than living only in code review folklore.
Why is this a FAIL and not a WARN?
Architectural pattern violations have outsized downstream cost. Once one service bypasses the repository layer, the next refactor copies the pattern, and within six months the abstraction is dead. Mneme returns FAIL on architectural-pattern violations by default to keep the cost localized to the diff that introduced it.
Does the FAIL verdict block the PR?
Yes — when the GitHub Actions enforcement gate is configured for strict mode. The FAIL exit code from `mneme check` fails the CI job, which blocks the PR from merging until the violation is resolved or an explicit override decision record is added. Override events are themselves tracked, so weakening the rule is a visible decision rather than a silent one.
Related governance concepts

- Architectural governance

  The system that turns team decisions into machine-evaluable constraints enforced at generation time.

- Governance before generation

  Enforcement at the point of AI intent, not at the point of human review.

- Verification contracts

  Pre-registered, machine-evaluable assertions that define what a governance check must prove.

- Deterministic enforcement

  Same input, same verdict — every run, every agent, every consumer. The precondition for auditability.

← Previous · Dependency policy (WARN) Back to demo →