Skip to content

feat(routing): publish and serve no-route revisions - #270

Draft
nerdalert wants to merge 7 commits into
praxis-proxy:mainfrom
nerdalert:feat/deny-all-overlay
Draft

nerdalert wants to merge 7 commits into
praxis-proxy:mainfrom
nerdalert:feat/deny-all-overlay

Conversation

@nerdalert

@nerdalert nerdalert commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Summary

When the last eligible provider is withdrawn, AGN must publish a new no-route decision instead of leaving an older, permissive route in service. This PR makes an empty candidate set an authoritative, versioned routing state and connects that state to the supported running gateway paths.

This is the shared prerequisite in #258 for provider-gateway path health (#20) and sovereignty-zone enforcement (#78). Those policies are not implemented here.

Routing behavior

  • When a provider is withdrawn and others remain eligible, Grid publishes an updated overlay and new requests use the remaining providers.
  • When the last eligible provider is withdrawn, Grid publishes an empty overlay. A compatible gateway accepts that revision and returns 404 for new requests, including sessions previously bound to the withdrawn provider. Routing resumes when an eligible provider returns.
  • A valid empty overlay is an authoritative routing decision. Malformed updates are different: they retain the last valid revision. existing_only also remains distinct from withdrawal; it can serve an existing session but cannot accept a new one.

Breaking change and release dependency

🟥 On hold for the next release: this PR requires Praxis AI #1539 to merge, a compatible AI image to be published, and the Grid chart default to be updated before this Grid change merges or ships. Grid now publishes a valid empty overlay whenever the last eligible provider is withdrawn; there is no compatibility opt-in. The current chart-default AI 0.4.0 image rejects that snapshot.

This is a prerelease compatibility change. Every consumer of a Grid-managed overlay must be upgraded and rolled out with empty-snapshot support. Deployments using generated GatewayRef.consumerConfig must also mount the versioned overlay at /etc/praxis/routing/routing-overlay.json and roll out the new generated config, which now reads live candidates from that file instead of embedding them in startup YAML. The next release must qualify the paired AI and Grid images together; do not deploy this Grid change with the old chart-default image.

Consumer paths

Grid-managed path No-route and update contract
Praxis intelligent_route with overlay_file The scoped, digest-verified v1 envelope may contain candidates: []. Candidate revisions hot-reload; invalid revisions retain the last valid snapshot.
Operator-generated GatewayRef.consumerConfig Generated praxis.yaml supplies filter and endpoint plumbing, while the same watched overlay supplies live candidates. Candidate-only withdrawal hot-reloads. Changes to listeners, filter chains, endpoints, or TLS still require the consumer owner to reload or roll out its configuration.
Embedded grid-gateway Watches its serving ConfigMap and swaps candidate and provider-hop snapshots. GatewayRef.providerHopEndpoints is independent of consumerConfig; the gateway verifies those declared hops against its configured mTLS backends. Ambiguous same-named verified/plaintext backends fail startup.

Manual static intelligent_route.candidates are not a runtime-withdrawal path.

Qualification

The provider-traffic Kind qualification passed 9/9 scenarios on the source snapshot preceding the final gateway trust-validation change:

  • 60/60 serial round-robin requests attributed 20/20/20 across the three providers.
  • Provider A withdrawal with attributed fallback to B/C; then withdrawal of all providers.
  • Matching empty Grid, Praxis accepted, and Praxis serving revisions, zero serving candidates, unattributed 404 responses for fresh and previously bound requests, no provider POST-counter increase, and attributed 200 after restoration.
  • Embedded gateway empty-state denial and restoration; scoped teardown.

The static-weighted regression passed all three 60-request distribution phases on that snapshot.

Static checks

  • Root make lint, gateway-workspace strict Clippy, and git diff --check pass on this branch.

References

Scope note

Admission-time schema tightening for GatewayRef.providerHopEndpoints may be more than this initial no-route change needs. The controller already rejects invalid nonempty hop declarations. The optional CRD validation work is preserved on nerdalert/grid:review/provider-hop-admission-validation for separate review if the API contract calls for it.

@coderabbitai

coderabbitai Bot commented Oct 3, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
@nerdalert
nerdalert force-pushed the feat/deny-all-overlay branch from 664c74b to 75e9e78 Compare October 3, 2026 02:07
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
@nerdalert nerdalert added the holding-pattern Waiting for discussions or contributor updates in order to proceed label Oct 3, 2026
@nerdalert nerdalert added blocked and removed holding-pattern Waiting for discussions or contributor updates in order to proceed labels Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant