Skip to content

Guardrails Reference — Finnest

Status: Active Date: 2026-04-16 Purpose: Authoritative enforcement reference for all Finnest project guardrails. Maps every rule to its philosophical principle from 42-COMMANDMENTS.md. Hierarchy: 42-COMMANDMENTS.md is the philosophy. This document is the enforcement matrix. CLAUDE.md (in each repo) is the operational checklist. Adapted from: AgenticAI-app/docs/architecture/10-GUARDRAILS.md (Laravel/PHP) — rewritten for Elixir/Phoenix backend and Flutter mobile.


Enforcement Tiers

Tier Symbol Meaning
Automated (CI) CI Enforced in GitHub Actions pipeline. Violations block merge.
Automated (Pre-commit) PRE Enforced by local tooling before code reaches the repo.
Code Review REV Required in PR review; human or Review Agent responsibility.
Advisory ADV Documented best practice. Not enforced by tooling.

1. Code Quality

1a. Elixir/Phoenix Backend (finnest repo)

ID Guardrail Enforcement Status Principle
CQ-01 Code passes mix format --check-formatted CI + PRE Active #5 Consistency
CQ-02 All tests pass before merge (mix test) CI Active #39 Full test suite
CQ-03 Test-first development: failing test before implementation REV Active #9 Tests prove behaviour
CQ-04 Unit + integration tests for every context function and LiveView REV Active #9 Tests prove behaviour
CQ-05 Ecto preloads explicit (Repo.preload/2 or from ... preload:); no lazy loading REV Active #1 Code is liability
CQ-06 No SELECT *; specify schema fields explicitly in Ecto queries REV Active #10 Surface area is a cost
CQ-07 Input validation via Ecto.Changeset; never in controllers/LiveView directly REV Active #5 Consistency
CQ-08 Conventional Commits format: type(scope): description REV Active #5 Consistency
CQ-09 Static analysis via Dialyzer (mix dialyzer) — zero warnings tolerated CI Active #3 Understand every line
CQ-10 ExUnit syntax; ExMachina factories for test data REV Active #5 Consistency
CQ-11 Reversible migrations: all must implement down/0 (or be change/0 with reversible ops) REV Active #36 Migrations reversible
CQ-12 Indexes on columns used in WHERE, ORDER BY, JOIN clauses REV Active #16 Data models outlive everything
CQ-13 Repo.transaction/1 for multi-table write operations REV Active #12 One error philosophy
CQ-14 Use Ecto.Repo.stream/2 for large datasets; never Repo.all on unbounded data REV Active #1 Code is liability
CQ-15 Idempotent Oban workers: safe to process more than once REV Active #38 Idempotent jobs
CQ-16 No speculative abstractions: no behaviours/protocols until 2+ implementations REV Active #2 No speculative abstractions
CQ-17 Constants over config: if a value doesn't change per environment, hardcode it REV Active #33 Constants over config
CQ-18 Match gold-standard files: new modules must follow existing OTP app patterns REV Active #32 Gold-standard files
CQ-19 Tests prove behaviour, not implementation: tests must survive internal refactoring REV Active #9 Tests prove behaviour
CQ-20 Credo strict mode (mix credo --strict); zero design issues tolerated CI Active #1 Code is liability
CQ-21 No Process.sleep/1 in production code; use GenServer messages or Oban timers REV Active #15 Prefer boring technology
CQ-22 Pattern matching over conditionals where both are natural ADV Active #5 Consistency

1b. Flutter Mobile (finnest-mobile repo)

ID Guardrail Enforcement Status Principle
CQM-01 Code passes dart format --set-exit-if-changed CI + PRE Active #5 Consistency
CQM-02 All tests pass (flutter test unit + widget + flutter test integration_test/) CI Active #39 Full test suite
CQM-03 Test-first for BLoC and services REV Active #9 Tests prove behaviour
CQM-04 Widget tests for all reusable widgets; integration tests for critical flows REV Active #9 Tests prove behaviour
CQM-05 flutter analyze passes with zero warnings CI Active #3 Understand every line
CQM-06 Flutter build succeeds for both iOS and Android CI Active #39 Full test suite
CQM-07 Null safety throughout (no ! null assertion on nullable values) REV Active #1 Code is liability
CQM-08 BLoC pattern consistent across features; no inline state management REV Active #5 Consistency
CQM-09 Feature modules are self-contained (no cross-feature imports) REV Active #34 Isolate volatility
CQM-10 Accessibility: WCAG AA, 44px touch targets, screen reader support REV Active
CQM-11 Golden tests for critical screens (update deliberately) REV Active #9 Tests prove behaviour
CQM-12 Battery-conscious: careful with background location, polling intervals, FCM frequency REV Active

2. Architecture

ID Guardrail Enforcement Status Principle
AR-01 No AWS service lock-in: Lambda, DynamoDB, SQS, SNS, Cognito, Aurora, ECS, Fargate excluded. Bedrock permitted via hexagonal AI provider adapter REV Active #30 No vendor lock-in
AR-02 No Cloudflare lock-in: Workers, KV, D1, Durable Objects excluded REV Active #30 No vendor lock-in
AR-03 OTP app structure: each domain is its own OTP application under apps/{finnest_domain}/ REV Active #34 Isolate volatility
AR-04 Cloud services accessed only through hexagonal ports (behaviours) REV Active #30 No vendor lock-in
AR-05 External DB connections (admin_central, admin_atslive during migration) are read-only REV Active #28 External data read-only
AR-06 Supervised Modular Monolith retained; no premature extraction to microservices ADV Active #21 Build for your team
AR-07 Cross-domain communication via events ONLY — no direct function calls between domain apps CI + REV Active #34 Isolate volatility
AR-08 Domain boundary enforcement via Boundary library (or equivalent); violations block merge CI Active #31 Boundaries by tooling
AR-09 No JS frameworks (React, Vue, Svelte) on web; LiveView + DaisyUI + vanilla JS only REV Active #15 Prefer boring technology
AR-10 Authentication via phx.gen.auth; external identity only through SSO integration (OAuth) REV Active #15 Prefer boring technology
AR-11 Job queue: Oban (PostgreSQL-backed), not SQS or Cloud Tasks REV Active #30 No vendor lock-in
AR-12 File storage via hexagonal FileStorage behaviour; S3 default, swappable via config REV Active #13 Exit path
AR-13 Standard PostgreSQL 17; no vendor-specific extensions beyond standard contrib REV Active #15 Prefer boring technology
AR-14 AI inference uses Australian-region endpoints only (Bedrock ap-southeast-2 / Vertex australia-southeast1) REV Active #23 PII classification
AR-15 AI providers accessed only through AiProvider behaviour; no direct Claude SDK calls in domain code REV Active #30 No vendor lock-in
AR-16 MCP at every domain boundary for agent tool access REV Active #34 Isolate volatility
AR-17 Event store is append-only: UPDATE/DELETE forbidden at DB trigger level CI + REV Active #36 Migrations reversible
AR-18 Compliance auto-blocking: Compliance.check/2 called synchronously before roster/timekeep/payroll writes REV Active #27 Never disable security defaults
AR-19 IRAP deployment is a config variant, not a code fork REV Active #30 No vendor lock-in

3. Security

ID Guardrail Enforcement Status Principle
SE-01 CSRF protection enabled (Phoenix :protect_from_forgery plug); never disable REV Active #27 Never disable security defaults
SE-02 HEEx templates escape by default; raw/1 forbidden on user content REV Active #27 Never disable security defaults
SE-03 Server-side validation via Ecto.Changeset required; client-side is UX only REV Active #27 Never disable security defaults
SE-04 Security headers via Phoenix :put_secure_browser_headers + CSP: HSTS, X-Content-Type-Options, X-Frame-Options, CSP REV Active #27 Never disable security defaults
SE-05 Rate limiting on all public endpoints (Hammer library or equivalent) REV Active #25 Rate limit public endpoints
SE-06 config :logger, level: :info in production; no :debug REV Active #26 Secrets never in code
SE-07 Environment secrets via System.get_env + runtime.exs; never hardcoded REV Active #26 Secrets never in code
SE-08 Use Plug.Crypto, Argon2, Comeonin for crypto; never roll custom REV Active #15 Prefer boring technology
SE-09 CORS configured explicitly in Phoenix endpoint for API routes REV Active #10 Surface area is a cost
SE-10 No stack traces, debug info, or runtime config exposed in production REV Active #26 Secrets never in code
SE-11 Dependency vulnerability scanning: mix deps.audit + mix sobelow in CI CI Active #14 Dependencies age
SE-12 Secret scanning: gitleaks pre-commit + CI PRE + CI Active #26 Secrets never in code
SE-13 PII handling: data classification tiers (Restricted/Sensitive/Internal/Public) REV Active #23 PII classification
SE-14 Non-root user in Docker containers (app user) REV Active #27 Never disable security defaults
SE-15 PostgreSQL TLS required in production (ssl: true) REV Active #26 Secrets never in code
SE-16 Supply chain: exact version pinning in mix.lock, Renovate soak, harden-runner on CI CI + REV Active #14 Dependencies age
SE-17 Mobile: no hardcoded secrets in APK/IPA; use flutter_dotenv + CI-injected secrets REV Active #26 Secrets never in code
SE-18 Mobile: biometric unlock for stored JWT tokens REV Active #27 Never disable security defaults
SE-19 IRAP: FIDO2 MFA mandatory, 15-min session timeout, IP allowlist REV Active #27 Never disable security defaults
SE-20 IRAP: AES-256 at rest, TLS 1.2+ in transit, CloudHSM key management for PROTECTED REV Active #27 Never disable security defaults
SE-21 Audit log is tamper-evident (hash chain on event sequence) REV Active #24 Log by ID, never PII

4. Frontend — LiveView Web

ID Guardrail Enforcement Status Principle
FE-01 HTML First: native HTML before CSS, CSS before JS hooks REV Active #35 Start simple (Gall's Law)
FE-02 Progressive Enhancement: LiveView handles interactivity; JS hooks only when necessary REV Active #35 Start simple
FE-03 DaisyUI components for all UI elements; no custom CSS without approval REV Active #5 Consistency
FE-04 No dynamic Tailwind class construction; compiler must find complete strings REV Active #5 Consistency
FE-05 Touch targets >= 44px on all interactive elements REV Active
FE-06 Contrast ratios: normal text >= 4.5:1, large text >= 3:1 (WCAG 2.2 AA) REV Active
FE-07 user-scalable=yes in viewport meta; never block zoom REV Active
FE-08 Dark mode default; both themes via DaisyUI semantic colour tokens only REV Active #5 Consistency
FE-09 Semantic HTML mandatory: <form novalidate>, <fieldset>, <legend>, ARIA REV Active #15 Prefer boring technology
FE-10 LiveView over JS hooks: use phx-click/phx-change over custom JS where possible REV Active #35 Start simple
FE-11 Alpine.js for local interactive state only; no global app state in Alpine REV Active #15 Prefer boring technology
FE-12 Animate only transform, translate, opacity; motion-safe: prefix required REV Active
FE-13 Playwright visual regression tests before committing visual changes CI Active #9 Tests prove behaviour
FE-14 Alt text on every image; alt="" with role="presentation" for decorative REV Active
FE-15 Command bar (Cmd+K) accessible on every page for power users ADV Active
FE-16 Three paths to every action: agent, notification, navigation ADV Active

5. Infrastructure & Deployment

ID Guardrail Enforcement Status Principle
IN-01 Debian-based Elixir Docker images (not Alpine — musl causes issues with NIFs) REV Active #15 Prefer boring technology
IN-02 Non-root user in containers REV Active #27 Never disable security defaults
IN-03 Multi-stage Docker builds: build stage (with dev deps) + slim runtime REV Active #1 Code is liability
IN-04 Elixir releases (mix release): compiled, self-contained, no deps at runtime REV Active #30 No vendor lock-in
IN-05 PostgreSQL slow query log enabled (log_min_duration_statement = 1000) REV Active #18 Can't see it, can't maintain it
IN-06 Production compile: MIX_ENV=prod mix compile --warnings-as-errors CI Active
IN-07 mix deps.get --only prod and mix deps.clean --unused in production builds CI Active #1 Code is liability
IN-08 Health check endpoint at /health; automatic rollback on failure REV Active #18 Can't see it, can't maintain it
IN-09 Backups: daily automated, encrypted, with restore tests ADV Active #16 Data models outlive everything
IN-10 BEAM tuning: +sbwt none +sbwtdcpu none for container environments ADV Active
IN-11 Squash merges to main; delete feature branches after merge REV Active #6 Delete before you add
IN-12 Feature branches: feature/, fix/, chore/ naming; short-lived REV Active #22 Ship smallest change
IN-13 All CI checks pass before merge to main CI Active #39 Full test suite
IN-14 At least one human review required before merge REV Active #3 Understand every line
IN-15 Database migration safety: reversible, non-destructive, human-reviewed REV Active #36 Migrations reversible
IN-16 Monitoring and alerting thresholds defined (Telemetry + Prometheus or equivalent) ADV Planned #18 Can't see it, can't maintain it
IN-17 IRAP deployment: separate CI/CD pipeline, two-person approval, security review gate REV Active #27 Never disable security defaults
IN-18 Mobile: versioned app releases; rollout via staged Play/App Store releases REV Active #22 Ship smallest change

6. Data & Database

ID Guardrail Enforcement Status Principle
DA-01 External DB Ecto repos are read-only: priv: "priv/external_repo", no migrations REV Active #28 External data read-only
DA-02 External DB schemas: @primary_key false if no primary key, explicit fields only REV Active #28 External data read-only
DA-03 Repo.transaction/1 or Multi for operations modifying multiple tables REV Active #12 One error philosophy
DA-04 Repeated query patterns extracted to context functions (3+ uses rule) REV Active #7 Three is a pattern
DA-05 utf8 encoding and en_AU.UTF-8 collation as PostgreSQL defaults REV Active #15 Prefer boring technology
DA-06 PostgreSQL shared_buffers at 25% of RAM, work_mem tuned for query load ADV Active
DA-07 Composite indexes matching query patterns; use EXPLAIN ANALYZE before shipping REV Active #16 Data models outlive everything
DA-08 Backups encrypted (AWS native encryption + separate backup key) ADV Active #26 Secrets never in code
DA-09 Backup retention: 30 daily, 12 monthly, 5 yearly (7 years for IRAP PROTECTED) ADV Active #16 Data models outlive everything
DA-10 Monthly automated restore tests against staging ADV Active #16 Data models outlive everything
DA-11 Every table has org_id for multi-tenancy (except public.organisations itself) REV Active #27 Never disable security defaults
DA-12 Every table has inserted_at, updated_at, soft-delete deleted_at REV Active #16 Data models outlive everything
DA-13 UUIDs for primary keys (distributed-ready, no auto-increment) REV Active #16 Data models outlive everything
DA-14 Event store partitioned by month for query performance ADV Active #18 Can't see it, can't maintain it
DA-15 Financial precision: all monetary values use ex_money + Postgres DECIMAL(12,4) (or DECIMAL(19,8) for unit prices). No native Float, no bare 0.0 literals in finnest_payroll, finnest_clients, finnest_compliance.awards. Custom Credo rule enforces CI + REV Active #16 Data models outlive everything
DA-16 Event store hash chain: every event computes hash = sha256(prev_hash || id || org_id || domain || event_type || payload) via DB trigger; monthly integrity verification script REV Active #16 Data models outlive everything

7. Queue & Jobs (Oban)

ID Guardrail Enforcement Status Principle
QJ-01 All Oban workers must be idempotent — safe to process more than once REV Active #38 Idempotent jobs
QJ-02 Retry logic with exponential backoff (backoff: [5, 30, 120]) REV Active #12 One error philosophy
QJ-03 Dead-letter strategy: max_attempts exceeded → DLQ table + alert REV Active #18 Can't see it, can't maintain it
QJ-04 Separate Oban queues per domain (scout_queue, verify_queue, etc.) + priority REV Active #34 Isolate volatility
QJ-05 Monitor all queues via Oban Web dashboard REV Active #18 Can't see it, can't maintain it
QJ-06 Unique constraints on time-sensitive jobs (unique: [fields: [:aggregate_id]]) REV Active #38 Idempotent jobs
QJ-07 Workflow agents (Tier 2) use Oban job chaining for multi-step processes REV Active #12 One error philosophy

8. Agent Workflow

ID Guardrail Enforcement Status Principle
AW-01 Plan before code: Analyse → Plan → Test → Implement → Verify → Review REV Active #20 Human decides what
AW-02 Read and update sprint-status.yaml at session start and end REV Active #19 Documentation is a product
AW-03 No new dependencies without explicit human approval REV Active #15 Prefer boring technology
AW-04 Infrastructure files (Dockerfile, CI, Kamal config) require human review REV Active #20 Human decides what
AW-05 No git push --force, git rebase on shared branches, or git reset --hard REV Active #6 Understand before you delete
AW-06 One branch per agent; no overlapping file edits REV Active #34 Isolate volatility
AW-07 Review Agent has veto power; code failing checklist does not merge REV Active #3 Understand every line
AW-08 Stick to defined story scope; log adjacent discoveries in retro notes ADV Active #4 Solve problem you have
AW-09 .env*, _build/, deps/, node_modules/, signing keys are off-limits REV Active #26 Secrets never in code
AW-10 Commit to feature branches only; never directly to main REV Active #22 Ship smallest change
AW-11 Agent scope budgets: target max 10 files modified, 20 per PR ADV Active #22 Ship smallest change
AW-12 AI agents in production follow confidence framework: GREEN/AMBER/RED thresholds REV Active #27 Never disable security defaults
AW-13 AI agents in production respect budget limits with circuit breaker REV Active #27 Never disable security defaults
AW-14 AI agent audit trail: every LLM call + tool call logged to event store REV Active #24 Log by ID, never PII

9. Performance

ID Guardrail Enforcement Status Principle
PF-01 Response time targets: LiveView mounts <300ms, APIs <200ms, agent chat <2s ADV Active #18 Can't see it, can't maintain it
PF-02 Slow query threshold: 1 second; target zero in normal operation ADV Active #16 Data models outlive everything
PF-03 Oban job duration targets: investigate any job exceeding 5 minutes ADV Active #38 Idempotent jobs
PF-04 Load testing required before production launch (k6 or Gatling) ADV Active #37 Measure code health
PF-05 Mobile: app launch < 2s cold, < 500ms warm ADV Active
PF-06 Mobile: offline sync reconciliation < 10s for 100 queued events ADV Active

10. Operational Strategy

ID Guardrail Enforcement Status Principle
OP-01 Structured logging: JSON format (logger_json), correlation IDs, PII-free, level-appropriate REV Active #24 Log by ID, never PII
OP-02 Feature flag lifecycle: create → develop → test → flip → cleanup within 1 sprint ADV Active #17 Flags are debt with timer
OP-03 Telemetry spans on every context function + LiveView mount REV Active #18 Can't see it, can't maintain it
OP-04 Error tracking (Sentry or similar) in production REV Active #18 Can't see it, can't maintain it

11. AI-Specific Guardrails (Finnest-Unique)

ID Guardrail Enforcement Status Principle
AI-01 Local-first routing: pattern-match + DB query before Claude API call REV Active #4 Solve the problem you have
AI-02 Deterministic guardrails for compliance: pay rates, awards, credentials = rules engines. AI queries, never overrides REV Active #27 Never disable security defaults
AI-03 Tenant isolation at MCP tool level: org_id injected by infrastructure, not agent REV Active #27 Never disable security defaults
AI-04 Agent processes never reused across tenants: session end = process termination REV Active #23 PII classification
AI-05 Correlation IDs on every event to prevent infinite agent loops; max 10 events per chain REV Active #12 One error philosophy
AI-06 Tier 3 autonomous agents are PROPOSE-only: no destructive actions without human approval REV Active #20 Human decides what
AI-07 AI provider failover chain: primary (Bedrock) → fallback (Vertex or Anthropic direct) → manual review REV Active #12 One error philosophy
AI-08 AI cost budgets: per-org daily/weekly/monthly limits with 80% warning, 100% circuit breaker REV Active #27 Never disable security defaults
AI-09 Prompt-cache-optimal structure: system prompts + MCP tool schemas ordered stable-first for 90% Anthropic cache discount. Dashboard tracks hit rate; alert if <50% for 1 hour REV Active #1 Code is liability

12. IRAP-Specific Guardrails

These apply ONLY to the IRAP deployment variant.

ID Guardrail Enforcement Status Principle
IR-01 AI provider: AWS Bedrock Sydney ONLY (no direct Anthropic API) REV Active #23 PII classification
IR-02 All data in ap-southeast-2 (Sydney): primary, backups, logs, metadata, caches REV Active #23 PII classification
IR-03 Separate PostgreSQL instance (no data co-residency with commercial) REV Active #27 Never disable security defaults
IR-04 Separate VPC with no peering to commercial infrastructure REV Active #27 Never disable security defaults
IR-05 Go boundary proxy in front of Phoenix (ISM-listed language security boundary) REV Active #27 Never disable security defaults
IR-06 FIDO2 MFA mandatory on every login (no "remember me") REV Active #27 Never disable security defaults
IR-07 15-minute session timeout, 10-minute idle lock REV Active #27 Never disable security defaults
IR-08 IP allowlist (client network ranges only) REV Active #27 Never disable security defaults
IR-09 CloudHSM key management (FIPS 140-2 Level 2+ for PROTECTED) REV Active #27 Never disable security defaults
IR-10 Audit retention: 7 years, tamper-evident (hash chain), immutable storage REV Active #24 Log by ID, never PII
IR-11 JIT admin access via AWS SSM Session Manager; zero standing access REV Active #27 Never disable security defaults
IR-12 Two-person approval required for IRAP production deployments REV Active #20 Human decides what
IR-13 Disabled integrations: SEEK, Indeed, LinkedIn, Calendly, WhatsApp, Google/Apple OAuth REV Active #23 PII classification
IR-14 Dependency audit includes SBOM generation and CVE monitoring CI Active #14 Dependencies age
IR-15 Mobile: separate IRAP build with feature flags; no Firebase Analytics REV Active #23 PII classification
IR-16 Mobile: MDM (Intune) enrollment required for defence tenant users REV Active #27 Never disable security defaults

Summary Statistics

Category Count CI PRE REV ADV
Code Quality — Elixir (CQ) 22 4 1 16 1
Code Quality — Flutter (CQM) 12 3 1 8 0
Architecture (AR) 19 2 0 16 1
Security (SE) 21 2 1 18 0
Frontend — LiveView (FE) 16 1 0 13 2
Infrastructure (IN) 18 4 0 12 2
Data & Database (DA) 16 1 0 10 5
Queue & Jobs (QJ) 7 0 0 7 0
Agent Workflow (AW) 14 0 0 12 2
Performance (PF) 6 0 0 0 6
Operational (OP) 4 0 0 3 1
AI-Specific (AI) 9 0 0 9 0
IRAP-Specific (IR) 16 1 0 15 0
Total 180 18 3 139 20

Key Changes from AgenticAI-app Version

This document adapts the original AgenticAI-app guardrails (113 rules) for the Finnest stack. Notable changes:

Replaced

  • mix format replaces Pint
  • Dialyzer + Credo replaces PHPStan + PHPMD
  • Boundary library replaces Deptrac
  • ExUnit + ExMachina replaces Pest + factories
  • Ecto.Changeset replaces Form Requests
  • Oban replaces Laravel Queue/Horizon
  • LiveView + HEEx replaces Blade
  • Phoenix replaces Laravel

Added (New to Finnest)

  • Section 1b: Flutter Mobile (CQM) — 12 rules for mobile code quality
  • Section 11: AI-Specific (AI) — 8 rules covering agent architecture (local-first routing, deterministic guardrails, tenant isolation, confidence framework, cost budgets)
  • Section 12: IRAP-Specific (IR) — 16 rules for IRAP deployment variant
  • AR-16, AR-17, AR-18, AR-19MCP boundaries, event store immutability, compliance auto-blocking, IRAP as config variant
  • DA-11, DA-12, DA-13, DA-14 — multi-tenancy, soft deletes, UUIDs, event store partitioning

Removed (Laravel-specific, not applicable)

  • OPcache (PHP-specific)
  • composer.json / composer.lock conventions
  • Laravel Horizon (replaced by Oban Web)
  • Blade-specific rules (replaced by HEEx equivalents)

This document is the enforcement reference. 42-COMMANDMENTS.md is the philosophy. CLAUDE.md (in each code repo) is the operational checklist. All three must stay aligned.