Add import-only dev and staging state with least-privilege HCP authentication and plan safety guards.
6.6 KiB
Quality Gates (canonical)
Status: canonical. This document owns how the architecture and code-quality rules are enforced: the gate list, the local command, the CI mapping, and the pass/fail/skip reporting semantics. The meaning of each rule lives in
ARCHITECTURE_AND_CODE_QUALITY.md.CI and local run the same check. Every gate below is executed by
scripts/governance-check.sh. Thearchitecture-qualityworkflow calls that script so a green run means the same thing locally and in CI. Do not add a check to CI that is not also runnable locally through the script (and vice versa).
Gate inventory
| # | Gate | Protects (architecture §) | Local command | CI step |
|---|---|---|---|---|
| G1 | Restore | build integrity | dotnet restore SeaHavenIndustries.sln |
architecture-quality → governance-check.sh |
| G2 | Architecture boundary tests | §1, §3 (dependency direction) | dotnet test Api.SeaHavenIndustries.Tests ... --filter FullyQualifiedName~ArchitectureTests --no-restore |
same script |
| G3 | Changed-file formatting | §1 (conventions) | dotnet format SeaHavenIndustries.sln --no-restore --verify-no-changes --include <changed .cs> |
same script |
| G4 | Release build | compile correctness | dotnet build SeaHavenIndustries.sln -c Release --no-restore |
architecture-quality and ci |
| G5 | Full test suite | behavior | dotnet test SeaHavenIndustries.sln -c Release --no-build |
architecture-quality and ci |
| G6 | Migration gates | §7 | see §"Migration gates" below | on-demand / release |
| G7 | Cancellation forwarding | §6 | behavior tests on changed I/O paths + analyzer | review-enforced on changed paths |
| G8 | Error disclosure | §5 | SanitizedErrorsTests (part of G5) |
ci |
| G9 | Board-backed regression | review framework | REVIEW_AND_PR_FRAMEWORK.md inventory |
review-enforced |
| G10 | Terraform import plan safety | live infrastructure adoption | python scripts/test-terraform-import-plan-check.py |
architecture-quality → governance-check.sh |
How to run locally
# Complete local repository gate (mirrors the architecture-quality workflow):
bash scripts/governance-check.sh
# By default it compares against the default branch for changed-file formatting.
# Override the comparison point:
BASE_REF=origin/dev bash scripts/governance-check.sh
BASE_REF=main bash scripts/governance-check.sh
The script:
dotnet restore(G1)- runs the
ArchitectureTestsfilter with--no-restore(G2) - computes changed
.csfiles vsBASE_REF(defaultorigin/dev) and runsdotnet format --verify-no-changes --include ...(G3). When there are no changed C# files it skips G3 with an explicit "skipped: no changed C#" line. - builds the complete solution in Release with no restore (G4).
- runs the complete solution test suite in Release with no rebuild (G5).
- verifies that the Terraform plan guard rejects create, delete, replacement, and unapproved update actions (G10).
Migration gates (G6)
Provider-real, not reflection-derived. Run against the configured provider:
- Actual-provider discovery — confirm the runtime provider matches the configured connection (e.g., SQL Server / Npgsql) from configuration, not from package guesses.
- Snapshot consistency —
dotnet ef migrations script --idempotent(or a model diff) shows no phantom operations;ModelSnapshotmatches the model. - Empty-db apply —
dotnet ef database updateagainst a fresh empty database applies the full history cleanly. - Supported-prior upgrade — upgrade from each still-supported prior migration applies cleanly.
- Rollback — report not guaranteed unless a real downgrade was exercised against the provider. Never claim "EF can roll it back" untested.
Migration gates are run on-demand and gated for releases; they are not in the per-PR fast path because they require a database. A PR that adds/changes a migration must document the G6 evidence in the PR description.
Cancellation forwarding (G7)
For changed async I/O paths, the requirement (§6) is verified forwarding, not a signature checkbox. Acceptable evidence, any one of:
- a behavior test asserting the
CancellationTokenreaches the data service / EF call; or - an analyzer diagnostic confirming propagation on the changed method.
A parameter that exists but is swallowed/default-ed is a fail. If an
analyzer is unavailable for a path, a behavior test is required; silence is not
acceptable. Review enforces this on changed paths.
Architecture discovery must fail on zero (G2 invariants)
Each reflection invariant in ArchitectureTests asserts the discovered set is
non-empty. A future namespace move that makes reflection return zero types will
fail the gate rather than silently pass. The current invariants:
- Controllers inject neither
DbContext, concrete data services, nor concrete service implementations. - Business services inject neither
DbContextnorIConfiguration. - Business services depend on interfaces (not concrete service/data-service implementations) for their data and persistence dependencies.
What this does not claim
- Reflection over constructors proves wiring shape, not runtime behavior. Runtime/semantic properties (cancellation actually cancelling, a query executing in SQL, a transaction actually committing atomically) are proven by behavior tests or provider evidence, never by reflection.
- A passing script proves G1–G5 ran in sequence. It does not prove the provider-backed or review-owned gates G6–G9.
Pass / fail / skip / not-run reporting
Every gate result is reported as exactly one of:
- pass — ran and succeeded, with evidence.
- fail — ran and failed; cite the failing test/command and output.
- skipped — intentionally not run for this change (e.g., no changed C# for G3); name the gate and the reason.
- not-run — could not run (environment/dependency missing); name the blocker.
A PR is not "green" if any applicable gate is fail, skipped-without-justification, or not-run. Never infer a pass from silence.
Adding or changing a gate
- Any new executable check goes into
scripts/governance-check.shand thearchitecture-qualityworkflow together (or into the full CI for G4/G5-type checks). One source of truth for local and CI. - A new rule documents its meaning in
ARCHITECTURE_AND_CODE_QUALITY.mdand its command/mapping here. - Explicit, documented exceptions only — no wildcard suppressions (see
ARCHITECTURE_AND_CODE_QUALITY.md§10).