fix(governance): make backend gate complete

This commit is contained in:
Alexandre Brandizzi 2026-07-24 14:52:37 -03:00
parent b421b5bc44
commit 4ce8e1d5fa
5 changed files with 53 additions and 46 deletions

View file

@ -21,9 +21,8 @@ jobs:
with: with:
dotnet-version: "8.0.x" dotnet-version: "8.0.x"
# CI and local run the SAME governance check (scripts/governance-check.sh). # CI and local run the same complete repository gate.
# See QUALITY_GATES.md. A green run here is equivalent to a local run. - name: Repository quality gate
- name: Governance check (restore + architecture tests + changed-file format)
shell: bash shell: bash
env: env:
BASE_REF: ${{ github.event.pull_request.base.sha }} BASE_REF: ${{ github.event.pull_request.base.sha }}

View file

@ -1,9 +1,8 @@
# AGENTS.md — SeaHaven backend (repo-specific delta) # AGENTS.md — SeaHaven backend (repo-specific delta)
This file is the **repo-specific delta** for the Seahaven backend. It layers on This file is the **repo-specific delta** for the Seahaven backend. It layers on
top of the operator/workspace agent baseline (the global `AGENTS.md` and the top of the operator/workspace agent baseline and does not repeat it. This file
agent-config-kit framework) and does not repeat it. Where this file and the may add stricter backend rules but may never weaken the workspace baseline.
baseline conflict on repo details, **this file wins for this repository**.
## Canonical governance documents (precedence) ## Canonical governance documents (precedence)
@ -40,16 +39,15 @@ Controller -> I{Feature}Service -> I{Feature}DataService -> ApplicationDbContext
Full detail: `ARCHITECTURE_AND_CODE_QUALITY.md`. Full detail: `ARCHITECTURE_AND_CODE_QUALITY.md`.
## Running the gates (local == CI) ## Running the complete gate (local == CI)
```bash ```bash
bash scripts/governance-check.sh # restore + ArchitectureTests + changed-file format bash scripts/governance-check.sh
dotnet build SeaHavenIndustries.sln -c Release
dotnet test SeaHavenIndustries.sln -c Release --no-build
``` ```
CI (`architecture-quality` workflow) calls the same `scripts/governance-check.sh` The command restores, verifies architecture and changed-file formatting, builds
so a local green run means the same thing as CI. See `QUALITY_GATES.md`. Release, and runs the full test suite. CI (`architecture-quality` workflow)
calls the same script. See `QUALITY_GATES.md`.
## Hard rules (deviation needs an ADR; no wildcard suppressions) ## Hard rules (deviation needs an ADR; no wildcard suppressions)

View file

@ -18,8 +18,8 @@
| G1 | Restore | build integrity | `dotnet restore SeaHavenIndustries.sln` | `architecture-quality` → `governance-check.sh` | | 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 | | 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 | | 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` | `ci` (reusable dotnet CI) | | 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` | `ci` (reusable dotnet 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 | | 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 | | 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` | | G8 | Error disclosure | §5 | `SanitizedErrorsTests` (part of G5) | `ci` |
@ -28,7 +28,7 @@
## How to run locally ## How to run locally
```bash ```bash
# Full local governance gate (mirrors the architecture-quality workflow): # Complete local repository gate (mirrors the architecture-quality workflow):
bash scripts/governance-check.sh bash scripts/governance-check.sh
# By default it compares against the default branch for changed-file formatting. # By default it compares against the default branch for changed-file formatting.
@ -43,15 +43,8 @@ The script:
3. computes changed `.cs` files vs `BASE_REF` (default `origin/dev`) and runs 3. computes changed `.cs` files vs `BASE_REF` (default `origin/dev`) and runs
`dotnet format --verify-no-changes --include ...` (G3). When there are no `dotnet format --verify-no-changes --include ...` (G3). When there are no
changed C# files it skips G3 with an explicit "skipped: no changed C#" line. changed C# files it skips G3 with an explicit "skipped: no changed C#" line.
4. builds the complete solution in Release with no restore (G4).
It is **fast-path only**: restore + boundary tests + changed-file format. It is 5. runs the complete solution test suite in Release with no rebuild (G5).
not a substitute for G4/G5, which the full CI run performs. Run G4/G5 locally
with:
```bash
dotnet build SeaHavenIndustries.sln -c Release
dotnet test SeaHavenIndustries.sln -c Release --no-build
```
## Migration gates (G6) ## Migration gates (G6)
@ -104,8 +97,8 @@ non-empty. A future namespace move that makes reflection return zero types will
Runtime/semantic properties (cancellation actually cancelling, a query Runtime/semantic properties (cancellation actually cancelling, a query
executing in SQL, a transaction actually committing atomically) are proven by executing in SQL, a transaction actually committing atomically) are proven by
behavior tests or provider evidence, never by reflection. behavior tests or provider evidence, never by reflection.
- The per-PR fast path (G1–G3) does **not** assert the full suite is green; - A passing script proves G1–G5 ran in sequence. It does not prove the
that is G4/G5 in CI. Report them separately. provider-backed or review-owned gates G6–G9.
## Pass / fail / skip / not-run reporting ## Pass / fail / skip / not-run reporting

View file

@ -32,7 +32,7 @@ Review order is **business-rule-first, high-signal, low-false-positive**:
A task is incomplete if it implements the current change while regressing A task is incomplete if it implements the current change while regressing
behavior that was already working. Before claiming review/merge readiness: behavior that was already working. Before claiming review/merge readiness:
- Pull the **authoritative ticket board inventory** for this component — all - Pull the **Seahaven Jira SH board inventory** — all
visible tickets, not only the current one: key, title, type, status, visible tickets, not only the current one: key, title, type, status,
component, acceptance criteria, linked PR/release, and QA evidence. component, acceptance criteria, linked PR/release, and QA evidence.
- Check the change against that inventory. A plausible regression against - Check the change against that inventory. A plausible regression against
@ -41,9 +41,9 @@ behavior that was already working. Before claiming review/merge readiness:
- **Missing board access, incomplete inventory, or missing PR-to-ticket - **Missing board access, incomplete inventory, or missing PR-to-ticket
traceability is Blocked / NOT READY** — never a pass. Say so explicitly. traceability is Blocked / NOT READY** — never a pass. Say so explicitly.
> The specific tracker for this component must be confirmed at review time If Jira cannot be reached, report the gate as **not-run / blocked**, not green.
> (Jira, Linear, or the project's authoritative board). Do not assume; if the The current workflow has no `Ready for QA` transition; merged-but-unverified
> board cannot be reached, report the gate as **not-run / blocked**, not green. work remains in the documented pre-QA status and must not be mislabeled Done.
## 3. Security, data, and authorization evidence ## 3. Security, data, and authorization evidence
@ -113,7 +113,9 @@ sweeps, no `#pragma` swaths). See architecture §10.
- **Summary** — what changed and why, in plain language. - **Summary** — what changed and why, in plain language.
- **Changes and value** — grouped by area, each with the value it delivers. - **Changes and value** — grouped by area, each with the value it delivers.
- **Ticket** — the board key(s), with traceability. - **Ticket** — the board key(s) when one applies. A missing ticket link is not
itself a blocker; missing board regression access or contradictory acceptance
criteria is.
- Link G6 migration evidence if the PR adds/changes a migration. - Link G6 migration evidence if the PR adds/changes a migration.
- Link any ADR relied upon. - Link any ADR relied upon.

View file

@ -2,13 +2,9 @@
# #
# governance-check.sh — local/CI parity governance gate for the Seahaven backend. # governance-check.sh — local/CI parity governance gate for the Seahaven backend.
# #
# Runs the fast-path gates (G1 restore, G2 ArchitectureTests, G3 changed-file # Runs G1 restore, G2 ArchitectureTests, G3 changed-file formatting, G4 Release
# formatting) exactly as the `architecture-quality` workflow does. A green run # build, and G5 full tests exactly as the `architecture-quality` workflow does.
# here means the same thing locally and in CI. See QUALITY_GATES.md. # A green run here means the same thing locally and in that CI workflow.
#
# Full build + test (G4/G5) are NOT run here; run them separately:
# dotnet build SeaHavenIndustries.sln -c Release
# dotnet test SeaHavenIndustries.sln -c Release --no-build
# #
# Usage: # Usage:
# bash scripts/governance-check.sh # bash scripts/governance-check.sh
@ -19,15 +15,26 @@ set -euo pipefail
SOLUTION="SeaHavenIndustries.sln" SOLUTION="SeaHavenIndustries.sln"
ARCH_TEST_PROJECT="Api.SeaHavenIndustries.Tests/Api.SeaHavenIndustries.Tests.csproj" ARCH_TEST_PROJECT="Api.SeaHavenIndustries.Tests/Api.SeaHavenIndustries.Tests.csproj"
log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; }
ok() { printf '\033[32mPASS\033[0m %s\n' "$1"; }
bad() { printf '\033[31mFAIL\033[0m %s\n' "$1"; }
if [[ -n "${DOTNET_BIN:-}" ]]; then
DOTNET="$DOTNET_BIN"
elif command -v dotnet >/dev/null 2>&1; then
DOTNET="$(command -v dotnet)"
elif [[ -x "$HOME/.dotnet/dotnet" ]]; then
DOTNET="$HOME/.dotnet/dotnet"
else
bad "dotnet is unavailable; set DOTNET_BIN or install the repository SDK."
exit 1
fi
# Comparison point for changed-file formatting. Default to the dev integration # Comparison point for changed-file formatting. Default to the dev integration
# branch locally; CI overrides BASE_REF/HEAD_REF with the PR base/head SHAs. # branch locally; CI overrides BASE_REF/HEAD_REF with the PR base/head SHAs.
BASE_REF="${BASE_REF:-origin/dev}" BASE_REF="${BASE_REF:-origin/dev}"
HEAD_REF="${HEAD_REF:-HEAD}" HEAD_REF="${HEAD_REF:-HEAD}"
log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; }
ok() { printf '\033[32mPASS\033[0m %s\n' "$1"; }
bad() { printf '\033[31mFAIL\033[0m %s\n' "$1"; }
# Resolve the base ref before using it for a diff. # Resolve the base ref before using it for a diff.
if ! git rev-parse --verify --quiet "${BASE_REF}^{commit}" >/dev/null; then if ! git rev-parse --verify --quiet "${BASE_REF}^{commit}" >/dev/null; then
bad "G3: BASE_REF '${BASE_REF}' does not resolve to a commit (run: git fetch origin)." bad "G3: BASE_REF '${BASE_REF}' does not resolve to a commit (run: git fetch origin)."
@ -35,11 +42,11 @@ if ! git rev-parse --verify --quiet "${BASE_REF}^{commit}" >/dev/null; then
fi fi
log "G1: restore" log "G1: restore"
dotnet restore "$SOLUTION" "$DOTNET" restore "$SOLUTION"
ok "G1: restore" ok "G1: restore"
log "G2: architecture boundary tests (dependency direction)" log "G2: architecture boundary tests (dependency direction)"
dotnet test "$ARCH_TEST_PROJECT" \ "$DOTNET" test "$ARCH_TEST_PROJECT" \
--no-restore \ --no-restore \
--filter "FullyQualifiedName~ArchitectureTests" \ --filter "FullyQualifiedName~ArchitectureTests" \
--nologo --nologo
@ -57,11 +64,19 @@ if (( ${#changed_cs[@]} == 0 )); then
printf '\033[33mSKIP\033[0m G3: no changed C# files between %s..%s\n' "${BASE_REF}" "${HEAD_REF}" printf '\033[33mSKIP\033[0m G3: no changed C# files between %s..%s\n' "${BASE_REF}" "${HEAD_REF}"
else else
printf ' checking %d changed C# file(s)\n' "${#changed_cs[@]}" printf ' checking %d changed C# file(s)\n' "${#changed_cs[@]}"
dotnet format "$SOLUTION" \ "$DOTNET" format "$SOLUTION" \
--no-restore \ --no-restore \
--verify-no-changes \ --verify-no-changes \
--include "${changed_cs[@]}" --include "${changed_cs[@]}"
ok "G3: changed-file formatting" ok "G3: changed-file formatting"
fi fi
log "governance-check: all fast-path gates passed" log "G4: Release build"
"$DOTNET" build "$SOLUTION" -c Release --no-restore --nologo
ok "G4: Release build"
log "G5: full test suite"
"$DOTNET" test "$SOLUTION" -c Release --no-build --nologo
ok "G5: full test suite"
log "governance-check: all required repository gates passed"