Resolve P0/P1/P2 roadmap items: tests, bug fixes, docs reconciliation#3
Merged
hyperpolymath merged 4 commits intomainfrom Apr 16, 2026
Merged
Conversation
P0-1: Reconcile contradictory status docs - Fix mix.exs version 1.0.0 → 0.1.0-dev - Update STATE.a2ml completion 0 → 55, add CRG grade - Populate STATE.adoc with truthful current state - Mark IMPLEMENTATION-ROADMAP.md as historical P0-2: Add real security tests (test/security_test.exs) - Request sanitization (unknown methods, null bytes, long paths, traversal) - Header handling (trust spoofing prevention, security response headers) - SSRF resistance (proxy target validation, Host/X-Forwarded-Host) - Capability token validation (SafeTrust parsing, monotonicity, full matrix) - Gateway enforcement integration (trust level → exposure level) P0-3: Add E2E tests (test/e2e_test.exs) - Full request lifecycle (load → compile → enforce → proxy) - Policy hot-reload (atomic swap, failed reload preserves good policy) - Upstream proxy behavior (backend unavailable → 502, no policy → 503) - Health and readiness probes - Request ID propagation P0-4: Replace fuzz placeholder with real property-based tests - Remove tests/fuzz/placeholder.txt - Add test/fuzz_test.exs with StreamData property tests - Fuzz: arbitrary methods, trust strings, paths, policies, combined P0-5: Define provable MVP scope in ROADMAP.adoc - Narrow scope: HTTP verb governance prefilter only - 11 claims with explicit test-file mapping - Explicit exclusions (no GraphQL/gRPC, no multi-backend, no TLS) https://claude.ai/code/session_01TzU2xW8y2uBCaCm2mE4NUV
…s, docs
Bug fixes:
- GraphQLHandler.graphql_operation_allowed?/1 now reads policy table
from Application env instead of the hardcoded :policy_rules atom.
The hardcoded name broke after atomic policy reloads, which publish
tables under monotonic-time-suffixed names.
- Same fix applied to GRPCHandler.grpc_method_allowed?/2.
P1 concurrency tests (test/concurrency_test.exs, tagged :concurrency):
- Rate limiter: concurrent same-client bursts → expected 429s
- Rate limiter: concurrent different-client → separate buckets
- Rate limiter: internal trust bypasses limiting under load
- Rate limiter: Retry-After header present on 429
- Circuit breaker: 20 concurrent failures serialize correctly through GenServer
- Circuit breaker: concurrent allow? checks consistent under open circuit
- Circuit breaker: success resets failure counter
- Policy reload: concurrent readers never see missing table during swap
- Policy reload: failed reload preserves last good policy under load
P1 benchmarks (test/benchmark_test.exs, tagged :benchmark):
- Rate limiter per-call latency (< 100µs)
- Rate limiter throughput across unique clients
- Rate limiter internal-trust short-circuit (< 10µs)
- CircuitBreaker.allow? hot-path latency (ETS-only, ~nanosecond)
- Circuit breaker state transition cost
- Exact vs regex route lookup comparison
- 405 fast-path and health endpoint throughput
P1 operator docs:
- Add docs/SUPPORTED-FEATURES.md as single source of truth on what is
actually supported vs stubbed/planned. Covers protocols, trust sources,
policy enforcement, runtime features, and explicit out-of-scope items.
Includes operator quick-checklist (trusted_proxies, mTLS caveats, etc.).
- Add scope warning to MULTI-PROTOCOL.md clarifying that gRPC/GraphQL
handlers are stubs (aligns doc with test/research findings).
- Update docs/DEPLOYMENT.md version references from v1.0.0 to v0.1.0-dev
to match the reconciled version in mix.exs.
https://claude.ai/code/session_01TzU2xW8y2uBCaCm2mE4NUV
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
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full sweep through
ROADMAP.adocP0, P1, and P2 items. Three commits:fix(p0): resolve all 5 P0 release blockersfeat(p1): gateway hardening — bug fixes, concurrency tests, benchmarks, docsfeat(p2): bug fixes, unit tests, P2 productization docsP0 — Release Blockers (done)
mix.exs1.0.0→0.1.0-dev;STATE.a2mlcompletion: 0→55; populated emptySTATE.adoc; markedIMPLEMENTATION-ROADMAP.mdhistoricaltest/security_test.exs): 30+ tests — unknown methods, null bytes, long paths, trust spoofing, security headers, SSRF resistance, full SafeTrust matrixtest/e2e_test.exs): full request lifecycle, atomic policy hot-reload (add/remove routes, failed-reload preservation), upstream proxy failure modes, health/readiness probestest/fuzz_test.exs): StreamData property-based fuzzing; removedtests/fuzz/placeholder.txtROADMAP.adoc): 11 claims each mapped to a concrete test file; explicit exclusions (no GraphQL/gRPC, no multi-backend, no TLS)P1 — Gateway Hardening (done)
test/concurrency_test.exs): rate limiter burst contention, circuit breaker serialization through GenServer under 20 concurrent failures, policy reload never leaks a missing-table gap under concurrent readstest/benchmark_test.exs): rate limiter per-call (< 100µs) and throughput, circuit breakerallow?hot-path latency, exact vs regex vs global-fallback route lookup, full pipeline req/sdocs/SUPPORTED-FEATURES.mdas single authoritative reference for what actually works (vs stubbed/planned); scope warning onMULTI-PROTOCOL.md; version consistency indocs/DEPLOYMENT.mdGraphQLHandlerandGRPCHandlerhardcoded:policy_rulestable name — broke atomic policy reload; now reads fromApplication.get_env/2P2 — Productization (done)
docs/SCOPED-DEPLOYMENT.md): recommends fronting selected API routes first, not the whole surface; includes nginx example and rollback plandocs/RELEASE-CRITERIA.md): replaces percentage-based gating with concrete test-suite gates; explicit non-gates (topology %, LOC, module count)ROADMAP-v2.md(aspirational, out of MVP),TOPOLOGY.md(removed misleading "97% production-ready" bars; status table now backed by test files)Additional bug fixes
K9Contract.rate_limitenforced — was declared/validated but never checked. Per-route token bucket scoped to contract; gateway responds 429 +Retry-Afteron breach.K9Contract.list_all/0andcount/0— were returning non-contract entries (breach counters) as if they were contracts. Now filter by{:contract, _, _}key pattern.K9Contract.find_wildcard_match/2— wouldFunctionClauseErrorif any non-contract entry existed. Now uses:ets.match_object.extract_cert_subject/1— replaced the documented-TODO approximation with properRecord.extract-based OTPCertificate accessors. mTLS trust extraction is now OTP-version-robust.New unit tests
test/k9_contract_test.exs— registration, tiered lookup, trust threshold, rate-limit enforcement, post-proxy SLA, all four breach policies, parse safety, lifecycletest/circuit_breaker_test.exs— full FSM (closed → open → half_open → closed; half_open → open), manual trip/reset, timer cancellation, edge casesTest plan
mix test— unit + security + E2E pass (cannot run locally; no Elixir toolchain in harness)mix test --only :concurrency— rate limiter / circuit breaker / policy reload contentionmix test --only :benchmark— smoke-bounded perfmix test --only :property— fuzz propertiesTest file → claim mapping
See
docs/RELEASE-CRITERIA.md§2 "MVP Scope Gate" for the full mapping.https://claude.ai/code/session_01TzU2xW8y2uBCaCm2mE4NUV