LoadBalancerPro exposes a small set of calculation-only API contracts for controlled lab validation, tests, and generated-client review, plus an optional lightweight proxy forwarding path for local/simulated upstreams.
POST /api/allocate/capacity-awarePOST /api/allocate/predictivePOST /api/allocate/evaluatePOST /api/routing/comparePOST /api/routing/decision-explorerGET /api/routing/decision-explorer/scenariosANY /proxy/**whenloadbalancerpro.proxy.enabled=trueGET /api/proxy/statusGET /api/proxy/decisions/recentGET /api/proxy/decisions/{decisionId}/explainGET /api/proxy/configPOST /api/proxy/upstreamsPATCH /api/proxy/upstreams/{id}DELETE /api/proxy/upstreams/{id}GET /api/lase/shadowPOST /api/proxy/private-network-live-validationPOST /api/scenarios/replayPOST /api/remediation/reportGET /api/lab/scenariosGET /api/lab/scenarios/{id}POST /api/lab/decisionsPOST /api/lab/runsGET /api/lab/runsGET /api/lab/runs/{runId}GET /api/lab/policyGET /api/lab/audit-eventsGET /api/lab/metricsGET /api/lab/metrics/prometheusPOST /api/lab/experiments/{experimentId}/startGET /api/evidence-training/onboardingGET /api/evidence-training/templatesGET /api/evidence-training/examplesGET /api/evidence-training/scorecardsGET /api/evidence-training/scorecards/{name}GET /api/evidence-training/scorecards/{name}/answer-templatePOST /api/evidence-training/scorecards/gradeGET /v3/api-docs
The OpenAPI document is generated by SpringDoc from controller and DTO types. Contract tests assert that the allocation, evaluation, and routing paths remain present and continue to reference the expected request and response schemas. Local/default mode keeps /v3/api-docs and Swagger UI public for developer usability. Prod/cloud-sandbox API-key mode protects /v3/api-docs, /v3/api-docs/**, /swagger-ui.html, and /swagger-ui/** with X-API-Key by default, returning HTTP 401 when the key is missing or wrong. OAuth2 mode gates generated docs by default unless loadbalancerpro.auth.docs-public=true is intentionally configured for private review. OAuth2 app roles must come from dedicated role claims, not standard scope or scp claims; IDP_CLAIM_MAPPING_EXAMPLES.md records the accepted claim shapes and scope-only denial behavior. Actuator metrics and Prometheus exposure are not widened by OpenAPI gating.
For the planned enterprise gating policy around OpenAPI, Swagger UI, and cockpit operator auth, see ENTERPRISE_COCKPIT_AUTH_PLAN.md. For deterministic localhost Postman requests that exercise these contracts without real secrets, see POSTMAN_COLLECTION.md.
Allocation and read-only evaluation requests require an explicit requestedLoad value and a non-empty servers array. Each allocation server entry requires id, cpuUsage, memoryUsage, diskUsage, capacity, weight, and healthy. Omitted required values fail validation with HTTP 400 instead of silently defaulting JSON omissions to 0, 0.0, or false. Explicit zero values remain valid where the documented numeric range allows them, and healthy must be explicitly true or false.
Allocation responses expose an allocations map, unallocatedLoad, recommendedAdditionalServers, and scalingSimulation.
Read-only evaluation responses expose acceptedLoad, rejectedLoad, unallocatedLoad, scalingSimulation, loadShedding, metricsPreview, laseShadow, and remediationPlan. The evaluation endpoint is recommendation-only: readOnly is true, metricsPreview.emitted is false, remediationPlan.advisoryOnly is true, and the endpoint must not construct CloudManager. By default, laseShadow.enabled=false and live allocation behavior is unchanged. When loadbalancerpro.lase.shadow.enabled=true, POST /api/allocate/evaluate returns a shadow-only laseShadow summary with signals considered, including tail latency, queue depth, error rate, adaptive concurrency, load shedding, shadow autoscaling, and failure scenario checks. Shadow mode may record an observation and a recommended server/action for review, but it does not alter live allocation.
The Enterprise Lab workflow promotes deterministic adaptive-routing experiments into a safe HTTP API contract. GET /api/lab/scenarios returns stable scenario metadata: scenario id, display name, category, description, signals involved, expected guardrails, supported modes, influence-safety flag, deterministic fixture version, strategy, requested load, server count, and replay event count. GET /api/lab/scenarios/{id} returns one scenario or a stable 404 not_found envelope. Scenario responses do not include environment data, API keys, bearer tokens, cloud credentials, or host discovery output.
POST /api/lab/decisions evaluates one fixed catalog scenario through the bounded adaptive core. Its optional body accepts scenarioId, mode, explicitExperimentContext, cooldownActive, and operatorStopRequested; a missing body defaults to normal-balanced-load in shadow. The versioned immutable response records five deterministic local observations per backend, rolling state, typed score factors, a bounded allocation recommendation when the mode permits one, structured guardrail output, baseline rollback target, reasons, and a content fingerprint. off and observe calculate state and scores without recommending allocation. shadow and recommend retain the baseline. active-experiment can change only returned decision data after explicit opt-in and passing guardrails. Every response reports trafficActionPerformed=false; the endpoint does not invoke proxying, CloudManager, external telemetry, cloud or tenant systems, durable storage, or traffic mutation.
POST /api/lab/runs accepts a scenario id list, mode of off, observe, shadow, recommend, or active-experiment, and optional detail-level text. Missing scenario ids default to the full deterministic catalog. The service enforces a maximum number of scenarios per run and a bounded process-local in-memory retained-run set; it does not add a database, durable production storage, cloud mutation, or external network calls. Run responses include a deterministic run id, fixed lab timestamp, selected scenario ids, baseline allocation/selected backend, shadow recommendation, recommend-mode decision, active-experiment final decision when explicitly requested and allowed, guardrail reason, rollback reason, explanation, scorecard, policy audit events, safety notes, storage mode, and bounds. GET /api/lab/runs returns bounded summaries, and GET /api/lab/runs/{runId} returns one retained run or a stable 404 not_found envelope. The scorecard reports total scenarios, baseline-vs-shadow differences, baseline-vs-influence differences, guardrail-blocked influence count, unsafe/all-unhealthy blocked count, stale/conflicting signal blocked count, explanation coverage, deterministic fixture count, mode used, and final recommendation lab evidence only / not production activation or controlled active-experiment evidence only / not production activation.
The controlled active LASE policy gate uses loadbalancerpro.lase.policy.mode with values off, shadow, recommend, and active-experiment. The default is off. shadow and recommend never change the final allocation. active-experiment requires loadbalancerpro.lase.policy.active-experiment-enabled=true plus a bounded lab/evaluation context, healthy and eligible target backend, passing capacity constraints, fresh non-conflicting signals, a non-all-unhealthy candidate set, and no rollback/disable state. Invalid policy configuration fails closed to off. GET /api/lab/policy exposes configured mode, effective mode, active-experiment flag, allowed modes, retained audit event count, latest guardrail reason, and the lab-only safety note. GET /api/lab/audit-events exposes bounded process-local audit events with timestamp, mode, context, baseline decision, recommendation, final decision, changed flag, guardrail reasons, rollback reason, and explanation summary. GET /api/lab/metrics exposes process-local lab-grade counters for lab runs, scenarios executed, policy decisions by mode, recommendations, active-experiment changes, guardrail blocks by reason, rollback/fail-closed events, audit retention/drops, explanation coverage, and rate-limit interactions. GET /api/lab/metrics/prometheus exposes the same process-local counters as deterministic Prometheus-style text for local evidence and dashboard review; it is not a production Prometheus scrape contract. See CONTROLLED_ACTIVE_LASE_POLICY_GATE.md.
POST /api/lab/experiments/{experimentId}/start is the single HTTP actuation boundary for installing an armed experiment's candidate loopback allocation. It remains off unless active-experiment mode, active-experiment-enabled, and the separate default-off loadbalancerpro.lase.policy.gated-actuation-enabled=true property all agree. It also refuses loadbalancerpro.auth.mode=none; API-key mode or OAuth2 with the allocation role must authenticate the request. The body accepts only a bounded operatorRequestId, the exact allowlisted action install-candidate-allocation, the stored decision ID, expectedState=ARMED, and the exact current experiment-record fingerprint as expectedStateVersion. Unknown fields, arbitrary targets or commands, missing or malformed values, unknown/expired decisions, stale state or version, terminal experiments, and request-ID conflicts fail closed. The synchronized service uses the armed server-side decision and existing loopback allocation/rollback seam; it does not recalculate routing, trust client explanations, execute requests, alter proxy or WRR selection, call CloudManager, or access external networks, files, shells, tenants, or production gateways. Receipts expose bounded identifiers, action, authoritative decision ID, expected and observed state/version, timestamp, outcome/reason, mutation indicator, and the bounded experiment record.
Prod/cloud-sandbox API-key mode protects /api/lab/** through the existing deny-by-default non-OPTIONS /api/** boundary. OAuth2 mode allows read access to GET /api/lab/scenarios and GET /api/lab/scenarios/{id} for configured read roles, while adaptive decision evaluation, lab run creation, retained-run lookup, policy status, and audit-event lookup use the allocation role. Local/default mode remains intentionally convenient for loopback demos. The optional process-local rate limiter includes the /api/lab/ surface when enabled and does not weaken API-key or OAuth2 requirements.
The performance baseline runner uses the existing API contracts only; it adds no runtime endpoint. docs/performance/performance-fixtures.json exercises GET /api/health, POST /api/allocate/evaluate, POST /api/routing/compare, GET /api/lab/scenarios, POST /api/lab/runs, GET /api/lab/policy, GET /api/lab/metrics, and GET /enterprise-lab.html, then writes local latency/error-rate evidence under ignored target/performance-baseline/. The Enterprise Auth Proof Lane also adds no runtime endpoint; it uses mocked-resource-server tests and scripts/smoke/enterprise-auth-proof.ps1 to prove dedicated OAuth2 role claims, scope-only denial, token lifetime rejection, issuer/audience rejection, and synthetic key-rotation examples under ignored target/enterprise-auth-proof/.
The prior CLI experiment harness remains available as an offline comparison path. Run --adaptive-routing-experiment=all through scripts/smoke/adaptive-routing-experiment.ps1 -Package to generate ignored target/adaptive-routing-experiments/ evidence. Run scripts/smoke/enterprise-lab-workflow.ps1 -Package to generate the Enterprise Lab scenario catalog JSON, lab run JSON, Markdown scorecard summary, and metadata under ignored target/enterprise-lab-runs/. Run scripts/smoke/controlled-adaptive-routing-policy.ps1 -Package to generate controlled policy evidence under ignored target/controlled-adaptive-routing/. Run scripts/smoke/enterprise-lab-observability-pack.ps1 -Package to generate metrics JSON, Prometheus-style sample text, Markdown summary, and manifest under ignored target/enterprise-lab-observability/. The default runtime allocation behavior remains unchanged; active-experiment remains explicit, guarded, and lab/evaluation-grade rather than production traffic control or production SLO certification.
Routing comparison responses expose requestedStrategies, candidateCount, timestamp, and a results array. Each result exposes the strategy id, status, selected server id when one is available, the strategy reason, considered candidates, score map, a timestamp-independent sha256:v1: decision fingerprint, Decision Vector, dominant-factor analysis, and decision-delta analysis. The fingerprint uses count-delimited, length-prefixed fields rather than delimiter joins; it is a stable comparison identity, not a signature or production audit record. The former replay snapshot/trace/capsule/readiness/source-map restatement chain is not part of the current contract. A no-healthy-server comparison still returns a controlled, fingerprinted no-selection result with chosenServerId set to null, empty candidate/scores collections, and an explanatory reason.
Routing comparison requests have an absolute DTO ceiling of 32 candidates and six explicit strategies. Operators
can lower those ceilings with loadbalancerpro.api.max-candidates and
loadbalancerpro.api.max-strategies; values outside the absolute bounds fail configuration validation. Requests
over either effective ceiling return structured HTTP 400 before comparison or Explorer payload construction. These
limits supplement the separate API request-body byte ceiling and do not authorize larger request bodies.
POST /api/routing/decision-explorer accepts the same RoutingComparisonRequest as the comparison route and returns
an array of compact RoutingExplanation v2 results derived from the already-built routing comparison response. Each
result contains only the strategy/status/selection identity and decision fingerprint, per-candidate factor contributions, compact dominant-
factor rows, the selected-vs-closest-alternative decision delta, numeric ±10% factor-weight projections, and one
boundary note. The endpoint does not return the retired confidence, diagnostics, tradeoff, shadow, replay-readiness,
reviewer-badge, evidence-packet, or agent-schema restatement graphs. The route
uses a bounded counting serialization pass before returning output and rejects output beyond
loadbalancerpro.api.max-decision-explorer-response-bytes (16 MiB by default) with structured HTTP 400; it does not
buffer a second response byte array while measuring. The configured response ceiling must remain between one byte
and the 64 MiB hard maximum or application configuration fails validation. The candidate and strategy ceilings run
before comparison and Explorer payload construction.
The route
is additive, read-only, and simulation-only: it does not mutate routing state, change strategy scoring, allocate
traffic, forward proxy traffic, call cloud or tenant systems, persist storage, execute replay, generate evidence
packets, export files, or prove production readiness, certification, live-cloud validation, real-tenant validation,
benchmark/load/stress behavior, throughput/p95/p99 behavior, replay/export behavior, storage behavior, or broader
automation. In local/default mode it follows the same local routing API convenience behavior as
POST /api/routing/compare; in prod/cloud-sandbox API-key mode and OAuth2 mode it inherits the existing
/api/routing/** protections.
GET /api/routing/decision-explorer/scenarios returns a DecisionExplorerScenarioCatalogV1 companion payload with
deterministic local synthetic scenario metadata for the Decision Explorer reviewer workflow. The catalog is additive,
read-only, same-origin, and simulation-only. It is grounded in existing source-visible local fixtures and includes
healthy baseline, partial evidence, no-healthy-server/unknown, and other safe local synthetic scenario entries. The
route does not run routing calculations, mutate routing state, change strategy scoring, allocate traffic, forward proxy
traffic, call cloud or tenant systems, persist storage, execute replay, generate evidence packets, export files, or
prove production readiness, certification, live-cloud validation, real-tenant validation, benchmark/load/stress
behavior, throughput/p95/p99 behavior, replay/export behavior, storage behavior, or broader automation.
The static Decision Explorer page is served at GET /decision-explorer.html. It calls the same-origin
POST /api/routing/decision-explorer route with deterministic synthetic routing telemetry and the same-origin
GET /api/routing/decision-explorer/scenarios route for deterministic scenario catalog metadata. It keeps the optional
API key in page memory only and renders the decision summary, candidate factor contributions, compact dominant/delta
analysis, counterfactual weight projections, raw response, and not-proven boundaries. Scenario selection is reviewer
orientation only and does not run routing by itself. The page does not persist browser or server storage, compute new
routing scores, enforce decisions, execute replay, export files, generate evidence packets, shift traffic, call cloud
or tenant systems, prove runtime behavior, or add benchmark/load/stress claims.
The current reviewer vocabulary maps directly to the compact JSON fields:
| Decision Explorer reviewer concept | Normalized reviewer-evidence group | Current API field or surface |
|---|---|---|
| Top-level explanation | Compact routing explanation | RoutingExplanation |
| Decision identity | Collision-safe, timestamp-independent digest | decisionFingerprint |
| Candidate evidence | Strategy-model factor contributions | candidates[].factors[] |
| Dominant-factor analysis | Per-candidate dominant rows | dominantFactors.candidates[] |
| Selected-vs-alternative analysis | Decision delta and factor deltas | decisionDelta |
| Counterfactual analysis | ±10% arithmetic projections | counterfactualWeightScenarios[] |
| Static browser reviewer path | Static reviewer page | /decision-explorer.html |
| Scenario catalog orientation | Scenario catalog | GET /api/routing/decision-explorer/scenarios |
Each counterfactualWeightScenarios row scales one returned selected/alternative factor contribution by -10% or
+10%, reports the adjusted contribution delta, and—when the returned final score gap is finite—reports an arithmetic
projected score gap. It does not rerun the strategy or claim that the projection would change a real selection.
Factor contributions now come from each strategy's returned comparison model: WRR exposes effective routing weight,
weighted least-load and weighted least-connections expose their additive formula terms, tail-latency power-of-two
exposes its sampled candidates and calculator breakdown, and round-robin remains positional with no invented additive
score. This proves reconciliation for the bounded comparison response only. The endpoint and page remain read-only and simulation-only and do not persist storage, export
evidence, execute replay, generate evidence packets, call external systems, mutate routing, or prove production
readiness, live-cloud behavior, real-tenant behavior, load/stress behavior, or throughput/p95/p99 behavior.
Decision Explorer Phase 1 reviewer examples live in
agent/DECISION_EXPLORER_PHASE1_REVIEWER_EXAMPLES.md. They
provide bounded request/response fragments and human/AI-agent review questions for the current local surface without
changing this read-only, simulation-only API contract or upgrading production-readiness, live-cloud, real-tenant,
benchmark/load/stress, throughput/p95/p99, replay/export/storage, evidence-packet, or automation claims.
Decision Explorer Phase 2 reviewer examples live in
agent/DECISION_EXPLORER_PHASE2_REVIEWER_EXAMPLES.md. They
provide grounded partial fragments for the scenario catalog, factor drill-down rows, candidate comparison rows, reviewer badges,
static page workflow, and additive API hardening without changing the read-only, same-origin, simulation-only
contract or upgrading production-readiness, live-cloud, real-tenant, benchmark/load/stress, throughput/p95/p99,
replay/export/storage, evidence-packet, runtime enforcement, or automation claims.
Scenario replay responses expose scenarioId, readOnly, cloudMutation, remediationPlan, and ordered steps. Remediation recommendations are advisory only and must not introduce cloud mutation or execution semantics.
Remediation report export requests accept exactly one report source: an existing read-only evaluation response or an existing scenario replay response. The response exposes the requested format, report contentType, optional Markdown report, structured json payload, and top-level readOnly, advisoryOnly, and cloudMutation flags. Report output is deterministic for the same input and does not add generated timestamps or random identifiers unless the caller supplies a report id.
Evidence training onboarding responses expose packaged policy templates, examples, scorecards, answer JSON templates, and workflow pointers for API/Postman users. Discovery routes are read-only. The scorecard grade route evaluates submitted JSON in memory, returns deterministic JSON, writes no runtime report files, and must not construct CloudManager. The operator demo walkthrough reuses these existing routes plus /api/health and Actuator readiness; it does not introduce a separate mutable demo API.
The static browser cockpit is served at GET /evidence-training-demo.html. It is not a new API contract and does not introduce new DTOs; it calls the existing health, readiness, onboarding, template, example, scorecard, answer-template, and deterministic grading routes. Its run-sequence control, stop/reset controls, checklist status, summary counters, curl snippets, response copy controls, sample payload copy/export controls, summary/transcript preview, and PASS/WARN/FAIL grading summaries are client-side only and do not write runtime reports.
The Enterprise Lab routing cockpit is served at the legacy route GET /routing-demo.html. It is not a new API contract and does not introduce new DTOs; it calls the existing health, readiness, and POST /api/routing/compare routes with controlled caller-provided telemetry. The page displays selected servers, strategy reasons, raw JSON, copyable curl, copyable payloads, reviewer/operator proof notes, and a normalized copyable summary. The cockpit remains client-side only and does not write runtime reports.
The static unified load-balancing cockpit is served at GET /load-balancing-cockpit.html. It is not a new API contract and does not introduce new DTOs; it calls the existing health, readiness, POST /api/allocate/capacity-aware, POST /api/allocate/evaluate, and POST /api/routing/compare routes with synthetic caller-provided inputs. The cockpit displays allocation results, routing decisions, load-shedding or overload signals, remediation-plan hints, raw JSON, copyable curl snippets, copyable payloads, and a side-by-side copyable summary. Its operator API-key control stores the entered key in JavaScript memory only, adds X-API-Key to protected /api/** calls after the operator configures it, clears the key on refresh/navigation, avoids localStorage and sessionStorage, avoids URLs and logs, and uses <API_KEY> in copyable curl examples instead of the entered key. Its navigation/readiness layer is browser-only: it indexes existing sections, tracks current-panel orientation, computes readiness badges from current in-memory page state, and copies a deterministic readiness summary without adding an endpoint. Its operator scenario gallery loads normal load, overload pressure, all-unhealthy degradation, and recovery/capacity-restored payloads into those same existing endpoint calls, then compares what changed between scenario runs on the client. Its operator guided walkthrough is a browser-only checklist over existing panels; it adds no endpoint, persists no state, and helps reviewers verify raw JSON, trace rows, replay output, and review packet generation in order. Its operator comparison matrix runs those packaged scenarios in deterministic order and summarizes routing, allocation pressure, load-shedding, remediation, rationale, and delta fields in a client-side table. Its operator replay mode replays a selected baseline/comparison scenario pair in order and highlights before/after differences using existing response fields and visible scenario inputs only. Its operator review packet composes existing in-memory scenario, matrix, replay, explanation, API contract trace, endpoint, payload, raw JSON reference, and safety text into a copyable and printable browser handoff. Its API contract trace maps visible panels to endpoint paths, request payload sources, raw response sources, displayed raw fields, derived client labels, unavailable fields, and mutation/safety notes without adding an endpoint. Its explanation drill-down panels show routing, allocation, overload, remediation, and scenario-delta rationale using real responses plus clearly labeled client-side derivations from visible request/response fields. Exact internal scores and every internal threshold are not exposed by the current API. Unsupported sections must be marked Not available in current API instead of fabricating behavior. The cockpit remains client-side only and does not write runtime reports. In prod/cloud-sandbox API-key mode, /api/** is deny-by-default except GET /api/health and unauthenticated OPTIONS preflight requests; local/default mode remains intentionally public for demos.
The optional lightweight reverse proxy is served at /proxy/** only when loadbalancerpro.proxy.enabled=true. It is a forwarding contract rather than a DTO-based JSON API: it forwards the caller method, /proxy path suffix, query string, body, and practical safe headers to one configured upstream selected through the request-level routing strategy registry. Request bodies stream from the servlet input to the selected upstream; a declared length above loadbalancerpro.proxy.max-request-bytes returns HTTP 413 before the body is opened, while unknown-length bodies are capped during streaming and are not retried after an overflow. Response bodies stream from the selected upstream to the servlet output through a fixed buffer; loadbalancerpro.proxy.max-response-bytes=0 leaves streamed responses unlimited by policy, while a positive value rejects known oversize before commitment and aborts an already-committed unknown-length stream at the cap. text/event-stream chunks are flushed incrementally. Responses preserve upstream status/body/safe headers and add X-LoadBalancerPro-Upstream and X-LoadBalancerPro-Strategy. Request forwarding metadata defaults to anti-spoofing strip-and-set; append accepts an inbound chain only from an immediate peer matching a configured literal trusted-proxy CIDR, while off strips the forwarding metadata without replacement. Named routes can apply validated static remove/set/add rules after that policy. Named routes can also use process-local CONSISTENT_HASH selection keyed by the immediate client address or a validated configured header. Optional route affinity verifies a route-bound HMAC cookie before strategy selection, falls back when its target is unavailable, and emits a replacement only after a successful non-retryable upstream response; the key and cookie value are never status fields. Configured unhealthy upstreams are skipped. Optional active health checks use loadbalancerpro.proxy.health-check.* settings, run as process-local background tasks, apply configured consecutive healthy/unhealthy thresholds to 2xx/3xx successes and other failures, and keep configured healthy=false as a hard disabled signal. Forwarding and status reads consume the latest snapshot without issuing probe I/O. Optional bounded retries use loadbalancerpro.proxy.retry.*, are disabled by default, default to GET/HEAD, consume a bounded process-local percentage-credit budget, and wait with capped full-jitter exponential backoff. A response is retryable only before downstream commitment; after headers/body begin delivery, an upstream stream failure aborts that response without another attempt or a replacement JSON body. Optional process-local cooldown uses loadbalancerpro.proxy.cooldown.*, is disabled by default, skips temporarily cooled-down upstreams without persistence, and retains half of positive failure memory on expiry. Optional slow start linearly ramps the effective weight of new or cooldown-recovered upstreams for weight-aware strategies and is disabled with a 0s default. Optional global and per-upstream in-flight limits are disabled with 0 defaults; when positive, strict atomic admissions return HTTP 503 plus Retry-After with proxy_concurrency_limit or proxy_upstream_concurrency_limit instead of queuing. Optional load shedding and adaptive concurrency are disabled by default, use bounded process-local observations, and never let CRITICAL priority bypass the strict cap. Priority-header mapping is disabled by default and, when configured, is trusted ingress metadata. No healthy upstream returns HTTP 503 with proxy_unavailable; an unreachable selected upstream returns HTTP 502 with proxy_upstream_failure.
The proxy strategy demo lab does not add another endpoint. It exercises the same /proxy/** forwarding contract with loopback backends and strategy settings for ROUND_ROBIN, WEIGHTED_ROUND_ROBIN, and health-aware failover. Verification uses the existing selected-upstream and strategy response headers plus GET /api/proxy/status; weighted expectations are limited to the documented local two-backend configuration and are not benchmark claims.
GET /api/proxy/status is read-only. It reports the proxy enabled flag, strategy, configured route summaries, health-check settings, retry budget/backoff and cooldown/slow-start settings, retry-budget counters, configured/effective/current global concurrency, adaptive decision state, load-shedding settings, per-upstream caps, configured/effective upstream weights, recovery-ramp state, effective health state, consecutive failure and cooldown state, local in-memory forwarding/failure/retry/cooldown counters, status-class counters, last selected upstream, and privateNetworkLiveValidation gate status. The private-network live validation status field is report-only: it shows flags, classifier decisions, reason codes, and trafficExecuted=false; it does not call the live executor or send validation traffic. The endpoint does not reset counters, persist metrics, adaptive state, retry budget, cooldown, or slow-start state, write reports, construct CloudManager, or call cloud services. Proxy mode is disabled by default, has local/no-cloud integration tests, and does not claim production gateway behavior or distributed concurrency enforcement.
The incremental proxy administration surface reuses the authenticated runtime-reload boundary and the same validated generation swap. GET /api/proxy/config returns the active generation, logical route names and strategies, logical upstream ids, configured health/weight/max-in-flight values, weight-zero drain state, and bounded pending-drain ids. It deliberately omits destination URLs, route paths, header rules, affinity material, TLS material, credentials, and request-derived values. POST /api/proxy/upstreams adds a target to an existing logical route; the legacy route name is legacy-upstreams. PATCH /api/proxy/upstreams/{id} changes weight, configured health, or drain state; drain=true applies the existing weight-zero no-new-selection contract, and drain=false restores weight 1.0 when no positive weight is supplied. DELETE /api/proxy/upstreams/{id} removes the target from the next active generation while existing in-flight work remains tracked until drained or the configured reload timeout expires. POST and PATCH bodies require expectedGeneration; DELETE requires the same value as a query parameter. A stale generation returns HTTP 409 without changing configuration, and successful mutations serialize, bump the generation once, and emit one bounded audit event containing only action, logical upstream id, generation, and outcome. Full POST /api/proxy/reload remains the bulk configuration path. These controls are process-local and do not add durable configuration history, multi-replica consensus, an external control plane, production load evidence, or production certification.
GET /api/proxy/decisions/recent is a read-only snapshot of actual proxy forwarding attempts. Each retained decision has a process-local monotonic id, capture time, active configuration generation, route and strategy, retry attempt number, strategy-or-affinity selection source, chosen upstream id, the immutable candidate-state values used for that selection, response status, measured attempt latency, retryability, and outcome. A retry therefore produces its own record. The response retains only the newest 100 records in FIFO order and reports maxRetained, retainedCount, totalCaptured, and totalDropped. It deliberately excludes request path, query, method, body, headers, cookies, routing-key values, affinity-cookie values, upstream URLs, and credentials. Records and counters survive accepted in-process config reloads but reset on process restart; they are not persistent, shared across replicas, a signed audit trail, throughput/p95/p99 evidence, or production certification. When proxy mode is disabled, the endpoint returns an empty bounded snapshot.
GET /api/proxy/decisions/{decisionId}/explain returns a compact read-only explanation only while that actual forwarding-attempt record remains in the same process-local 100-record ring. The proxy captures the route strategy's chosen candidate, considered candidate order, returned scores, compact factor contributions, reason, score preference, and collision-safe fingerprint at the same selection point as the forwarding attempt. Explanation therefore does not rerun round-robin cursors, smooth weighted state, sampled power-of-two choice, consistent-hash keys, or affinity policy after the fact. The response includes actual attempt identity/outcome metadata, the privacy-bounded candidate observations used for selection, exact and strategy-considered candidate ids, dominant factors, selected-versus-closest-alternative score and factor deltas, ±10% shared-factor weight projections, and additive contribution changes that reach a score tie. A missing, evicted, restarted-process, or disabled-proxy decision returns HTTP 404. Positional, keyed-ring, and affinity selections return explicit NOT_APPLICABLE score-delta/counterfactual status rather than invented numeric evidence.
The explanation retains no request path, query, method, body, headers, cookies, routing key, affinity value, upstream URL, or credential. Its score-tie thresholds are arithmetic over captured additive contributions only: crossing a tie changes the captured score ordering but does not rerun or actuate stateful, sampled, positional, keyed, or affinity routing. It does not mutate routing, weights, retries, admission, upstream health, cloud capacity, or traffic; persist durable evidence; establish multi-instance history; or prove production readiness, certification, SLOs, load/stress performance, throughput, or p95/p99 behavior.
When loadbalancerpro.lase.shadow.enabled=true, each completed live proxy attempt also offers an immutable LiveRoutingShadowObservation to an application-scoped single-worker queue. The queue retains at most 100 pending evaluations and uses non-blocking admission; a full or shutting-down queue drops shadow work instead of running or waiting for evaluation on the forwarding request. GET /api/lase/shadow reports liveProxyDispatch with enabled/shutdown state, queue capacity and depth, active count, and cumulative accepted/completed/dropped counts. These counters and the queue are process-local and reset on restart.
Live LASE input uses the exact candidate set used by the proxy attempt and its real rolling per-upstream in-flight, latency, error-rate, queue, health, capacity, and weight values. Autoscaling receives an explicit bounded 0–1 utilization ratio rather than dividing request/load units by replica count. The advisor keeps the last recommended AIMD concurrency limit per route across evaluations, bounded to 100 process-local target entries; it does not enforce that limit on proxy admission. Event rows expose selectionSource and candidateServerIds. Only strategy-selected attempts enter the agreement denominator; affinity-selected attempts remain visible with agreedWithRouting=null, so the headline rate does not mix affinity policy with strategy agreement. The older allocation and offline scenario entry points retain their deterministic synthetic fixture model; their output is not live proxy telemetry and must not be represented as measured traffic evidence.
Live shadow observations retain no request path, query, method, body, headers, cookies, routing-key value, affinity value, upstream URL, or credential. Shadow recommendations remain read-only: they do not alter selection, weights, retries, admission, upstream health, cloud capacity, or traffic. This local bounded evidence does not prove production latency overhead, distributed agreement, production performance, live-cloud behavior, real-tenant behavior, or production certification.
POST /api/proxy/private-network-live-validation is a protected, non-executing command contract for a future operator-triggered private-network live validation. The request accepts requestPath, optional evidenceRequested, and optional operatorAcknowledged or operatorAcknowledgement. The path validator rejects null or blank paths, absolute URLs, scheme-relative paths, query strings, fragments, traversal or encoded traversal, control characters, and backslashes before any gate decision is returned. The response always includes accepted=false, executable=false, trafficExecuted=false, evidenceWritten=false, top-level gateStatus, top-level allowedByGate, nested offline gate details, reason codes, and trafficExecution="traffic execution is not wired in this release". It also exposes the planned evidence contract without writing files: evidenceEligible, plannedEvidenceDirectory="target/proxy-evidence/", plannedEvidenceMarkdown="private-network-live-validation.md", plannedEvidenceJson="private-network-live-validation.json", redactionRequired=true, and auditTrail.auditTrailWritten=false with the planned ignored audit trail target/proxy-evidence/private-network-live-validation-audit.jsonl. Possible statuses are INVALID_REQUEST, BLOCKED_BY_GATE, and NOT_IMPLEMENTED; shared gate statuses and reason-code meanings are documented in PRIVATE_NETWORK_LIVE_VALIDATION_GATE.md. The endpoint does not call PrivateNetworkLiveValidationExecutor, does not send traffic, does not write runtime evidence or audit files, and does not expose API keys, bearer tokens, cookies, credentials, or sensitive headers. Prod/cloud-sandbox API-key mode protects the command through the existing X-API-Key mutation boundary; OAuth2 mode requires the configured allocation role.
The static proxy operator status page is served at GET /proxy-status.html. It is not a new mutable API contract and does not introduce new DTOs; it calls same-origin GET /api/proxy/status only. The page displays proxy enabled state, strategy, retry-budget/backoff, upstream health/cooldown/slow-start fields, forwarding/failure/retry/cooldown counters, status-class counters, last selected upstream, raw JSON, copyable status summaries, and local demo curl commands. Optional live refresh is browser-memory only. The page has no backend write, reset, metric mutation, storage, cloud, or monitoring-control behavior.
The checked-in proxy demo stack profiles (proxy-demo-round-robin, proxy-demo-weighted-round-robin, and proxy-demo-failover) are configuration examples for local review, not new API behavior. They activate /proxy/** only when explicitly selected, use loopback upstreams, and are documented in PROXY_DEMO_STACK.md. The Java ProxyDemoFixtureLauncher starts loopback backend fixtures for those profiles; it is documented in PROXY_DEMO_FIXTURE_LAUNCHER.md and can be launched through the Maven exec recipe in OPERATOR_PACKAGING.md. Real-backend example property files under docs/examples/proxy are copy/adapt local configuration samples only; they use loopback placeholders, do not add endpoint behavior, and do not change default proxy state.
Structured API errors expose status, error, message, path, timestamp, and details without diagnostic fields such as stack traces.
This repository does not currently include a generated-client build pipeline. Compatibility confidence comes from the OpenAPI path/schema assertions plus representative JSON shape checks. If a future client generator is introduced, keep it lightweight and run it as a contract validation lane without changing release automation or publishing generated artifacts.
POST /api/routing/compare remains read-only and recommendation-only. Its result objects expose decisionFingerprint, decisionVector, dominantFactorAnalysis, and decisionDeltaAnalysis; the former replay restatement fields are retired. These fields are derived from controlled local compare evidence; they do not execute replay, perform what-if mutation, persist audit data, recompute scores, retune weights, change routing behavior, or add upload/share/download or server-side export behavior.