Skip to content

Commit 2a1fc27

Browse files
committed
feat(p2): bug fixes, unit tests, P2 productization docs
Bug fixes: - K9Contract.enforce_pre_proxy/2 now enforces the rate_limit field that was previously declared and validated but never checked. Implements a per-route token bucket scoped to the contract (capacity = rate_limit). Gateway responds with 429 + Retry-After on contract rate-limit breach. - K9Contract.list_all/0 and count/0 now filter ETS entries by {:contract, _, _} key pattern so they ignore :breach_count counters and the new :contract_bucket rate-limit state. Previously they returned counter integers in place of contract structs (latent bug). - K9Contract.find_wildcard_match/2 uses :ets.match_object to iterate only contract entries. Previously a FunctionClauseError would be raised when a wildcard lookup occurred with any non-contract entry in the table. - gateway.ex extract_cert_subject/1 now uses Record.extract-based OTPCertificate / OTPTBSCertificate accessors. Replaces the documented TODO approximation that matched on a speculative {:Certificate, ...} tuple shape which did not match what :public_key.pkix_decode_cert actually returns in :otp mode. Unit tests: - test/k9_contract_test.exs: registration, tiered lookup (exact, :ANY, wildcard), trust threshold, rate limit enforcement, post-proxy SLA, all four breach policies, parse_breach_policy safety, count/list_all filtering, wildcard-with-mixed-entries safety. - test/circuit_breaker_test.exs: full FSM — closed → open → half_open → closed (recovery) and half_open → open (failed probe). Manual trip, reset (including timer cancellation), all_states snapshot, and defensive edge cases (non-string backends, unregistered backends). P2 productization docs: - docs/RELEASE-CRITERIA.md: replaces percentage-based release gating with concrete test-suite gates. Each MVP claim maps to a passing test file. Explicit non-gates (topology %, LOC, module count) to prevent reintroduction of the "97% production-ready" overclaim. - docs/SCOPED-DEPLOYMENT.md: recommends deploying the gateway in front of selected API routes first, not the whole application surface. Includes nginx example, rollback plan, and migration path. - TOPOLOGY.md: removed percentage bars, replaced with test-file-backed status table; added banner explaining the correction (mTLS was previously 100% but demonstrably broken). - ROADMAP-v2.md: marked as HISTORICAL/ASPIRATIONAL — features it lists (web UI, plugins, AI suggestions) are explicitly out of v0.1.0 MVP. - docs/SUPPORTED-FEATURES.md: mTLS row upgraded from "Not recommended" to "Supported with caveats" now that Record.extract is in place. - ROADMAP.adoc: P1 and P2 sections marked complete with references. - TEST-NEEDS.md: updated coverage summary (9 unit test files + security + E2E + concurrency + fuzz + benchmarks). https://claude.ai/code/session_01TzU2xW8y2uBCaCm2mE4NUV
1 parent bd8a1f7 commit 2a1fc27

11 files changed

Lines changed: 1421 additions & 137 deletions

ROADMAP-v2.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
# http-capability-gateway v2.0 Roadmap
2-
# Making It Irresistible
3-
4-
## Vision: The Gateway Everyone Wants
1+
# http-capability-gateway v2.0 Roadmap — HISTORICAL / ASPIRATIONAL
2+
3+
> **⚠️ HISTORICAL DOCUMENT (2026-04-16):** This is an aspirational v2.0 vision
4+
> written when the project was still in design phase. It is NOT on the current
5+
> release path for v0.1.0 — the features listed here (web UI, plugins, multi-protocol
6+
> full support, AI policy suggestions, etc.) are explicitly **out of MVP scope**.
7+
>
8+
> See `ROADMAP.adoc` and `docs/SUPPORTED-FEATURES.md` for the current scope and
9+
> what is actually supported today.
10+
>
11+
> Do not treat any item in this document as a commitment or an imminent feature.
12+
> It is preserved for reference and long-term direction only.
13+
14+
# Original Vision: The Gateway Everyone Wants
515

616
Transform http-capability-gateway from "good production gateway" to **"the obvious choice for API governance"** by making it:
717

ROADMAP.adoc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,16 @@ Each claim above must have at least one passing test:
7575

7676
== P1 Gateway Hardening
7777

78-
* [ ] Benchmark routing, policy evaluation, and rate limiting.
79-
* [ ] Add concurrency and failure-mode tests for rate limiter, circuit breaker, and reload paths.
80-
* [ ] Tighten operator documentation around what protocols and trust sources are actually supported.
81-
* [ ] Keep the runtime role constrained to prefiltering before origin-side enforcement.
78+
* [x] Benchmark routing, policy evaluation, and rate limiting. `test/benchmark_test.exs`.
79+
* [x] Add concurrency and failure-mode tests for rate limiter, circuit breaker, and reload paths. `test/concurrency_test.exs`.
80+
* [x] Tighten operator documentation around what protocols and trust sources are actually supported. `docs/SUPPORTED-FEATURES.md`.
81+
* [x] Keep the runtime role constrained to prefiltering before origin-side enforcement. `docs/SCOPED-DEPLOYMENT.md`.
8282

8383
== P2 Productization
8484

85-
* [ ] Use the gateway in front of selected API routes first, not the whole application surface.
86-
* [ ] Add release criteria that require executed tests rather than topology percentages.
87-
* [ ] Mark older design-only documents as historical where they no longer reflect the codebase.
85+
* [x] Use the gateway in front of selected API routes first, not the whole application surface. See `docs/SCOPED-DEPLOYMENT.md`.
86+
* [x] Add release criteria that require executed tests rather than topology percentages. See `docs/RELEASE-CRITERIA.md`.
87+
* [x] Mark older design-only documents as historical where they no longer reflect the codebase. `ROADMAP-v2.md`, `IMPLEMENTATION-ROADMAP.md`, `TOPOLOGY.md` updated.
8888

8989
== Milestones
9090

TEST-NEEDS.md

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,63 @@
22

33
## CRG Grade: C — ACHIEVED 2026-04-04
44

5-
> Generated 2026-03-29 by punishing audit.
5+
> Generated 2026-03-29 by punishing audit. Superseded 2026-04-16 by the
6+
> P0/P1/P2 test work documented below.
67
78
## Current State (updated 2026-04-16)
89

910
| Category | Count | Notes |
1011
|-------------|-------|-------|
11-
| Unit tests | 7 | gateway, policy_compiler, policy_loader, policy_validator, policy_property, performance, http_capability_gateway |
12+
| Unit tests | 9 | gateway, policy_compiler, policy_loader, policy_validator, policy_property, performance, http_capability_gateway, **circuit_breaker**, **k9_contract** |
1213
| Security | 1 | security_test.exs: sanitization, headers, SSRF, capability tokens (30+ tests) |
1314
| E2E | 1 | e2e_test.exs: full lifecycle, policy hot-reload, upstream proxy, health probes (20+ tests) |
15+
| Concurrency | 1 | concurrency_test.exs: rate limiter contention, circuit breaker serialization, atomic reload under load |
1416
| Fuzz | 1 | fuzz_test.exs: property-based fuzzing with StreamData (6 properties) |
15-
| Benchmarks | 0 | None |
16-
17-
**Source modules:** ~19 Elixir modules (gateway, circuit_breaker, proxy, rate_limiter, safe_trust, graphql_handler, grpc_handler, policy_*, minikaran, logging, etc.) + 2 Idris2 ABI + 4 Zig FFI.
18-
19-
## What's Missing
20-
21-
### P2P (Property-Based) Tests
22-
- [ ] Policy compilation: fuzz arbitrary YAML policies through compiler
23-
- [ ] Rate limiter: property tests for token bucket invariants
24-
- [ ] Circuit breaker: state machine property tests (closed->open->half-open)
25-
- [ ] GraphQL/gRPC handler: arbitrary request shape handling
26-
27-
### E2E Tests
28-
- [ ] Full request lifecycle: client -> gateway -> upstream -> response
29-
- [ ] Multi-protocol routing (HTTP, GraphQL, gRPC through single gateway)
30-
- [ ] Policy hot-reload under load
31-
- [ ] Health check / readiness probe validation
32-
33-
### Aspect Tests
34-
- **Security:** Request sanitization, header injection, SSRF prevention, capability token validation — covered in `test/security_test.exs`
35-
- **Performance:** No load tests, no latency benchmarks, no throughput measurement
36-
- **Concurrency:** No tests for concurrent connections, race conditions in rate limiter, circuit breaker under contention
37-
- **Error handling:** No tests for upstream timeout, malformed requests, policy parse failures
38-
39-
### Build & Execution
40-
- [ ] `mix test` runner verification
41-
- [ ] Zig FFI integration test execution
42-
- [ ] Container build + smoke test
43-
44-
### Benchmarks Needed
45-
- [ ] Request routing latency (per-protocol)
46-
- [ ] Policy evaluation overhead
47-
- [ ] Rate limiter throughput
48-
- [ ] Circuit breaker state transition cost
49-
50-
### Self-Tests
51-
- [ ] Configuration validation on startup
52-
- [ ] Policy schema self-check
53-
- [ ] Capability token format verification
17+
| Benchmarks | 2 | performance_test.exs (existing) + benchmark_test.exs (rate limiter / circuit breaker / route lookup) |
18+
19+
**Source modules:** ~19 Elixir modules + 2 Idris2 ABI + 2 Zig FFI parsers.
20+
21+
## Coverage Summary
22+
23+
### ✅ Covered
24+
25+
- **P2P (Property-Based) Tests**
26+
- Policy compilation: arbitrary YAML through compiler (`test/fuzz_test.exs`)
27+
- Circuit breaker: state machine transitions (`test/circuit_breaker_test.exs`)
28+
- Rate limiter: token bucket under contention (`test/concurrency_test.exs`)
29+
30+
- **E2E Tests**
31+
- Full request lifecycle (`test/e2e_test.exs`)
32+
- Policy hot-reload under load (`test/concurrency_test.exs`)
33+
- Health check / readiness probe validation (`test/e2e_test.exs`)
34+
35+
- **Aspect Tests**
36+
- **Security:** Request sanitization, header injection, SSRF prevention, capability token validation (`test/security_test.exs`)
37+
- **Concurrency:** Rate limiter and circuit breaker under contention (`test/concurrency_test.exs`)
38+
- **Performance:** Rate limiter, circuit breaker, route lookup benchmarks (`test/benchmark_test.exs`)
39+
40+
- **Benchmarks**
41+
- Rate limiter throughput (`test/benchmark_test.exs`)
42+
- Circuit breaker state transition cost (`test/benchmark_test.exs`)
43+
- Exact vs regex vs global-fallback route lookup (`test/benchmark_test.exs`)
44+
- Policy evaluation overhead (`test/performance_test.exs`)
45+
- Full plug pipeline throughput (`test/benchmark_test.exs`)
46+
47+
### ⚠️ Still Missing
48+
49+
- **Multi-protocol routing tests** — GraphQL/gRPC handlers are stubs per `docs/SUPPORTED-FEATURES.md`, so this is out of MVP scope rather than "missing".
50+
- **Zig FFI integration test execution** — requires zig toolchain; covered by separate FFI build step.
51+
- **Container build smoke test** — performed in CI, not in `mix test`.
52+
- **Error handling: upstream timeout** — Req receive_timeout covered implicitly; no dedicated test.
53+
- **Real-CA mTLS integration test** — code uses `Record.extract` accessors but no live cert in test fixtures.
54+
- **Self-tests for config validation on startup** — Application.start refuses without policy, but no dedicated assertion.
5455

5556
## Priority
5657

57-
**CRITICAL.** 19 modules with 7 unit tests = 37% coverage by file count. A security gateway with ZERO security tests is a contradiction. No benchmarks for a performance-sensitive proxy is unacceptable. No concurrency tests for a concurrent system is negligent.
58+
Originally **CRITICAL** when only 7 unit tests covered 19 modules.
59+
Now: the release gate in `docs/RELEASE-CRITERIA.md` maps every MVP claim
60+
to a concrete test file. Remaining items are clearly marked above and
61+
are not release blockers for v0.1.0.
5862

5963
## FUZZ STATUS
6064

TOPOLOGY.md

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
2-
<!-- TOPOLOGY.md — Project architecture map and completion dashboard -->
3-
<!-- Last updated: 2026-02-28 -->
2+
<!-- TOPOLOGY.md — Project architecture map and component status -->
3+
<!-- Last updated: 2026-04-16 -->
4+
5+
> **Note (2026-04-16):** The "completion percentage" model used in earlier
6+
> versions of this document was misleading — components claimed as "100%"
7+
> (e.g., mTLS) were verified-broken in review. This document now reports
8+
> **implementation status** rather than topology percentages. For the
9+
> authoritative "what works today" picture, see `docs/SUPPORTED-FEATURES.md`.
10+
> For release gating, see `docs/RELEASE-CRITERIA.md`.
411
512
# http-capability-gateway — Project Topology
613

@@ -48,38 +55,42 @@
4855
└─────────────────────────────────────────┘
4956
```
5057

51-
## Completion Dashboard
52-
53-
```
54-
COMPONENT STATUS NOTES
55-
───────────────────────────────── ────────────────── ─────────────────────────────────
56-
CORE GATEWAY
57-
Policy Loader (DSL v1) ██████████ 100% YAML spec parsing stable
58-
Validator ██████████ 100% Schema validation verified
59-
Compiler (Tiered Lookup) ██████████ 100% O(1) exact + O(r) regex + O(1) global
60-
Enforcement Engine ██████████ 100% Verb gating verified
61-
Security Headers ██████████ 100% OWASP hardened (nosniff, DENY, etc.)
62-
63-
INTERFACES & LOGS
64-
HTTP Proxy Layer ████████░░ 80% Scaling logic refining
65-
Structured JSON Logs ██████████ 100% Audit-grade logs stable
66-
Stealth Profiles ██████░░░░ 60% Limited profile active
67-
Prometheus Metrics ██████████ 100% Telemetry export active
68-
69-
HEALTH & TRUST
70-
Health Check (/health) ██████████ 100% Uptime, version, status
71-
Readiness Check (/ready) ██████████ 100% Policy + ETS validation
72-
mTLS Trust Extraction ██████████ 100% Certificate-based trust levels
73-
Trust Header Extraction ██████████ 100% X-Trust-Level header support
74-
75-
REPO INFRASTRUCTURE
76-
Justfile Automation ██████████ 100% Standard build/run tasks
77-
.machine_readable/ ██████████ 100% STATE.scm tracking
78-
Containerfile ██████████ 100% Chainguard-based deployment
79-
80-
─────────────────────────────────────────────────────────────────────────────
81-
OVERALL: █████████░ ~97% Production-ready, optimised
82-
```
58+
## Component Status
59+
60+
Statuses below are backed by executed tests. See `docs/SUPPORTED-FEATURES.md`
61+
for detailed caveats.
62+
63+
| Component | Status | Verified By |
64+
|-----------|--------|-------------|
65+
| **CORE GATEWAY** | | |
66+
| Policy Loader (DSL v1) | Supported | `test/policy_loader_test.exs` |
67+
| Validator | Supported | `test/policy_validator_test.exs` |
68+
| Compiler (Tiered Lookup) | Supported | `test/policy_compiler_test.exs`, `test/benchmark_test.exs` |
69+
| Enforcement Engine | Supported | `test/gateway_test.exs`, `test/e2e_test.exs` |
70+
| Security Headers | Supported | `test/security_test.exs` |
71+
| Atomic Policy Reload | Supported | `test/e2e_test.exs`, `test/concurrency_test.exs` |
72+
| **INTERFACES & LOGS** | | |
73+
| HTTP Proxy Layer | Supported | `test/e2e_test.exs` (502 on backend down) |
74+
| Structured JSON Logs | Supported | Emitted by `log_decision/7`; no direct assertion |
75+
| Stealth Profiles | Supported | `test/gateway_test.exs` stealth describe block |
76+
| Prometheus Metrics | Supported | `GET /metrics` covered by e2e setup |
77+
| **HEALTH & TRUST** | | |
78+
| Health Check (`/health`) | Supported | `test/e2e_test.exs` |
79+
| Readiness Check (`/ready`) | Supported | `test/e2e_test.exs` |
80+
| Trust Header Extraction | Supported | `test/security_test.exs` |
81+
| Trust Header Spoofing Protection | Supported | `test/security_test.exs` |
82+
| mTLS Trust Extraction | Supported with caveats | Code uses `Record.extract` accessors; no integration test against a real CA yet |
83+
| Rate Limiter (trust-scoped) | Supported | `test/concurrency_test.exs`, `test/benchmark_test.exs` |
84+
| Circuit Breaker | Supported | `test/circuit_breaker_test.exs`, `test/concurrency_test.exs` |
85+
| K9 Service Contracts | Supported | `test/k9_contract_test.exs` |
86+
| **PROTOCOL HANDLERS** | | |
87+
| HTTP/REST | Supported | Full test coverage |
88+
| GraphQL | Stub only | `check_operation_policy/2` always returns true; do not use in production |
89+
| gRPC | Stub only | `forward_grpc_request/5` returns hardcoded response; do not use in production |
90+
| **REPO INFRASTRUCTURE** | | |
91+
| Justfile Automation | Supported | N/A (developer tooling) |
92+
| `.machine_readable/` | Supported | `STATE.a2ml` authoritative |
93+
| Containerfile | Supported | Builds documented in `docs/DEPLOYMENT.md` |
8394

8495
## Key Dependencies
8596

@@ -94,10 +105,14 @@ HTTP Traffic ───────► Enforcement ──────────
94105

95106
This file is maintained by both humans and AI agents. When updating:
96107

97-
1. **After completing a component**: Change its bar and percentage
98-
2. **After adding a component**: Add a new row in the appropriate section
99-
3. **After architectural changes**: Update the ASCII diagram
100-
4. **Date**: Update the `Last updated` comment at the top of this file
108+
1. **Status changes**: A component moves to "Supported" only when it has at
109+
least one executed test. Do not claim completion based on code presence.
110+
2. **Adding a component**: Add a new row with the test file that verifies it.
111+
If no test exists, mark as "Stub only" or "Not implemented".
112+
3. **Architectural changes**: Update the ASCII diagram in the System Architecture section.
113+
4. **Date**: Update the `Last updated` comment at the top of this file.
114+
5. **No percentages**: Percentage-based completion claims are banned —
115+
they encouraged unjustified optimism (see 2026-04-16 correction note).
101116

102117
Progress bars use: `` (filled) and `` (empty), 10 characters wide.
103118
Percentages: 0%, 10%, 20%, ... 100% (in 10% increments).

docs/RELEASE-CRITERIA.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
2+
3+
# Release Criteria — HTTP Capability Gateway
4+
5+
**Version:** applies from v0.1.0 onward
6+
**Last updated:** 2026-04-16
7+
8+
This document replaces any earlier percentage-based release gating.
9+
A release is either ready or it isn't, and readiness is determined by
10+
**executed tests**, not topology coverage bars or design-document
11+
completion claims.
12+
13+
## Principle: Executed Tests, Not Topology
14+
15+
The ROADMAP.adoc P0 section explicitly calls out the problem:
16+
17+
> Add release criteria that require executed tests rather than topology
18+
> percentages.
19+
20+
Historically, documents like `TOPOLOGY.md` advertised "OVERALL: ~97%
21+
Production-ready" while core features (e.g., mTLS certificate subject
22+
extraction) were demonstrably broken when reviewed. This caused false
23+
confidence. Going forward, release readiness is measured only by what
24+
the test suite actually exercises.
25+
26+
---
27+
28+
## v0.1.0 Release Gate
29+
30+
A v0.1.0 release SHALL meet **all** of the following criteria. Each one is
31+
checkable by running the test suite or inspecting a deterministic artefact.
32+
33+
### 1. Test-suite Gate
34+
35+
- [ ] `mix test` exits 0 (unit tests + security + E2E pass)
36+
- [ ] `mix test --only :concurrency` exits 0 (concurrency/failure modes)
37+
- [ ] `mix test --only :property` exits 0 (property-based tests)
38+
- [ ] No test is tagged `:skip` or `@tag :pending` in main branch
39+
- [ ] The fuzz suite (`test/fuzz_test.exs`) exits 0 with default `max_runs`
40+
41+
### 2. MVP Scope Gate
42+
43+
For each claim in `ROADMAP.adoc` "MVP Proof Requirements" table, there
44+
must be at least one passing test in the specified file:
45+
46+
- [ ] Policy loading → `test/policy_loader_test.exs`
47+
- [ ] Policy validation → `test/policy_validator_test.exs`
48+
- [ ] Policy compilation → `test/policy_compiler_test.exs`
49+
- [ ] Trust extraction → `test/security_test.exs`
50+
- [ ] Verb governance → `test/gateway_test.exs`, `test/e2e_test.exs`
51+
- [ ] Allow/deny decisions → `test/e2e_test.exs`
52+
- [ ] Stealth mode → `test/gateway_test.exs`
53+
- [ ] Rate limiting → `test/concurrency_test.exs`, `test/benchmark_test.exs`
54+
- [ ] Health/readiness → `test/e2e_test.exs`
55+
- [ ] Atomic policy reload → `test/e2e_test.exs`, `test/concurrency_test.exs`
56+
- [ ] Request sanitization → `test/security_test.exs`
57+
- [ ] Trust spoofing prevention → `test/security_test.exs`
58+
- [ ] No atom exhaustion → `test/fuzz_test.exs`
59+
- [ ] No crash on arbitrary input → `test/fuzz_test.exs`
60+
- [ ] Circuit breaker FSM → `test/circuit_breaker_test.exs`
61+
- [ ] K9 contracts → `test/k9_contract_test.exs`
62+
63+
### 3. Documentation Gate
64+
65+
- [ ] `docs/SUPPORTED-FEATURES.md` lists no "Supported" feature without
66+
a corresponding test file
67+
- [ ] `STATE.adoc` version matches `mix.exs` version
68+
- [ ] `.machine_readable/STATE.a2ml` version matches `mix.exs` version
69+
- [ ] No historical document claims current-state facts without a prominent
70+
"HISTORICAL" banner
71+
72+
### 4. Security Gate
73+
74+
- [ ] No unaddressed High-severity findings in `report.json`
75+
- [ ] No `String.to_atom/1` or `String.to_existing_atom/1` calls on user-supplied input
76+
- [ ] No hardcoded secrets (verified by `panic-attacker` scan)
77+
- [ ] Security headers verified on all response paths (including denied/health/metrics)
78+
79+
### 5. Operator Gate
80+
81+
- [ ] `docs/SUPPORTED-FEATURES.md` operator checklist is reviewable before deployment
82+
- [ ] `docs/DEPLOYMENT.md` version references match `mix.exs` version
83+
- [ ] At least one reference deployment described in `docs/SCOPED-DEPLOYMENT.md`
84+
(selected routes, not whole surface)
85+
86+
---
87+
88+
## What is NOT a Release Gate
89+
90+
The following are deliberately excluded from the release gate because they
91+
proved to be misleading:
92+
93+
- **Topology percentages**: Component completion bars.
94+
- **Lines of code**: LOC is not a progress metric.
95+
- **Number of modules implemented**: Code presence ≠ correctness.
96+
- **Design doc completion**: Documents describing a feature ≠ the feature working.
97+
- **Self-declared status**: A module claiming "stable" in its `@moduledoc`
98+
is not evidence of stability.
99+
100+
These may still appear in dashboards for informational purposes, but they
101+
do not gate the release.
102+
103+
---
104+
105+
## Pre-release Checklist
106+
107+
Before tagging a release, execute in order:
108+
109+
```bash
110+
just build # or: mix compile --warnings-as-errors
111+
just test # mix test (P0 unit + security + E2E + fuzz)
112+
mix test --only :concurrency # P1 contention tests
113+
mix test --only :benchmark # P1 benchmarks (smoke bounds only)
114+
just security-scan # panic-attacker / scorecard
115+
just doctor # environment validation
116+
```
117+
118+
All commands MUST exit 0. If any fail, the release is blocked regardless
119+
of how many "97% complete" bars the topology shows.
120+
121+
---
122+
123+
## Amendment Policy
124+
125+
This document can only be amended by:
126+
127+
1. Adding a new gate (stricter release criteria) — any maintainer.
128+
2. Removing a gate — requires explicit rationale in the commit message
129+
explaining why the previous gate was wrong or is now covered elsewhere.
130+
3. Renaming a test file — update the referring section atomically in the
131+
same commit.
132+
133+
Weakening the gates without evidence undermines the entire point of this
134+
document.

0 commit comments

Comments
 (0)