STORY-F-002: Boundary library config + CI enforcement (AR-07)¶
Epic: Foundation Priority: Must Have Story Points: 2 Status: Not Started Assigned To: Unassigned Created: 2026-04-17 Sprint: 1
User Story¶
As the Lead Developer, I want Boundary library enforcing cross-domain communication rules at compile time with CI blocking violations, so that the AR-07 "events-only cross-domain" rule is enforced by tooling (per Commandment #31) and cannot erode under pressure.
Description¶
Background¶
ADR-005-F mandates events-only cross-domain communication. Commandment #31 says boundaries enforced by convention alone will erode — tooling must enforce. The Boundary library (saleyn/boundary hex package by Saša Jurić) inspects compile output and fails when a module references another boundary it hasn't declared a dependency on.
This is the only acceptable structural defence against a future developer adding alias Finnest.Payroll.Something inside Finnest.Roster — which would silently break ADR-002-F / ADR-005-F.
Scope¶
In scope:
- Add
{:boundary, "~> 0.10", runtime: false}to umbrella rootmix.exs .boundary.exsat umbrella root declaring allowed dependencies:- Every domain app →
finnest_coreallowed finnest_web→ any domain allowed (HTTP edge exception)finnest_agents→ any domain MCP allowed (agent-tier exception)finnest_core→ nothing (pure foundation)- Domain A → Domain B forbidden
- The single sync exception (
Finnest.Compliance.check/2) allowed for 5 callers only (roster, timekeep, payroll, clients, assets) — note this is Phase 0 scaffolding; the actual check function lands with compliance domain in F-015 / F-018 / later stories - Boundary annotations in each app's
lib/finnest_<domain>.exdeclaringuse Boundary, top_level?: trueor equivalent - CI integration:
mix boundaryruns in.github/workflows/ci-finnest.yml(added in F-005) and fails the build on violation - Pre-commit hook (local)
mix boundaryruns as part ofmix check
Out of scope:
- Runtime boundary enforcement (not needed — compile-time is enough)
- Exceptions for test-only code (handle if friction arises in F-007)
Technical Notes¶
- Boundary docs: https://hexdocs.pm/boundary/Boundary.html
- The tricky part is the
Finnest.Compliance.check/2exception — only 5 apps may call it. Recommended approach: declare acompliance_consumersub-boundary that exposes onlyFinnest.Compliance.check/2and list roster/timekeep/payroll/clients/assets as permitted callers. - Write an architecture test in
test/architecture/boundary_test.exsthat assertsmix boundaryexits zero on a clean build — belt-and-braces beyond the CI step - Reference Saša Jurić's blog posts on Boundary (search "boundary elixir jurić") for patterns
Dependencies¶
- Blocked by: STORY-F-001 (umbrella must exist)
Acceptance Criteria¶
-
boundarydep added to umbrellamix.exs -
.boundary.exsat umbrella root declares all app boundaries + dependency rules - Each app has
use Boundarydeclaration in its top-level facade module -
mix boundarycompletes with zero violations on clean scaffold - Deliberate test: add
alias Finnest.PayrollinsideFinnest.Roster→mix boundaryfails the build (demonstrate, then revert) - Deliberate test:
finnest_coretrying toalias Finnest.Web→mix boundaryfails (demonstrate, then revert) -
Finnest.Compliance.check/2callable from roster/timekeep/payroll/clients/assets only — confirmed via boundary rules (stub function is fine for now; real impl in later story) -
mix boundaryruns as part of CI (F-005) — asserted in CI config - Architecture test file
test/architecture/boundary_test.exsasserts clean state
Testing Requirements¶
- Architecture test
test/architecture/boundary_test.exsrunsmix boundary --format jsonand asserts zero violations - Manual validation test (documented in story): introduce a violation, observe
mix boundaryfailure, revert - CI integration tested by pushing a deliberate violation to a feature branch and confirming CI rejects merge
References¶
../architecture/architecture.md§Architectural Invariants #2, §System Components Dependency rules../adrs/adr-002-F-supervised-modular-monolith.md../adrs/adr-005-F-event-driven-cross-domain-communication.md../10-GUARDRAILS.mdAR-07, AR-08- Commandment #31 — boundaries enforced by tooling