The code works. The architecture is still wrong.
An AI refactor replaces UserRepository with a direct database query inside user.service.ts. Types pass. Tests pass. But the shortcut breaks the data-access boundary that later agents will copy. Mneme names ADR-004 and blocks the change in strict mode.
Code can pass tests and still break the rules.
This trace ends at the block. It shows the failure a team needs to catch, without inventing a recovery.
ADR-004 · Repository pattern is the only data-access boundary. Services depend on repository interfaces. Direct database imports, raw SQL, and ORM calls stay inside repository implementations.
-
01 Decision
The repository boundary is recorded with a service-layer file scope and explicit anti-patterns.
ADR-004 · scope: **/*.service.ts -
02 Agent change
The service bypasses its repository and opens a direct SQL path.
+ this.db.query('SELECT * FROM users ...') -
03 MnemeDENY
Strict mode names the boundary decision and blocks the file change.
DENY [ADR-004] · user.service.ts · exit 2
Reproduction recipe
Reproduce the strict boundary check
Record ADR-004, save the proposed service diff, and evaluate it in strict mode.
pipx install "mneme-hq>=0.9.0"
mneme check --mode strict \
--memory .mneme/project_memory.json \
--input user-service.diff --query "repository data access"
# FAIL [ADR-004] ยท exit 2
This page is a recipe, not a turnkey fixture: you provide the policy file and proposed diff. A corrected rerun is not included here.
What happened
Types and tests can pass while the service layer is quietly taking on database work.
Once direct SQL lands, later agents copy it and the repository layer stops being the clear boundary.
Mneme names ADR-004 and the file that broke it, so any override has to be a conscious choice.
Common questions
Why is this a DENY?
Direct data access from a service invalidates the boundary ADR-004 exists to protect. Its downstream cost compounds, so strict mode returns a non-zero failure.
Does the denial block the pull request?
Yes, when mneme check --mode strict is wired into the required CI workflow.
What happens after the block?
The developer or agent should move the query back behind UserRepository and run the check again. This page does not invent that unbundled retry.
Keep the boundary executable.
Record the pattern once, then enforce it in the editor and at the merge gate.
pipx install "mneme-hq>=0.9.0"