CB-578 stage A: classify a usage-limit refusal instead of a completed reply #58

Closed
agent wants to merge 0 commits from worker/cb578a-516499-2 into main
Member

Adds a per-profile exhaustedPattern regex (opt-in, no vendor wording in Java) and a new Rendezvous.Kind/MessageService.Outcome.BACKEND_EXHAUSTED distinct from WORKER_FAILED/GONE. When a turn ends with no bridge_reply and the scrape matches the configured pattern, CompletionResolver resolves the send as BACKEND_EXHAUSTED (reason carries the matched line) instead of handing back the scrape as a completed reply. Wired through REST (BridgedApp) and MCP (BridgeMcp) surfaces. Coverage is logged at startup via CompletionResolver.coverage(...), naming which profiles have a pattern configured, following FleetHealthMonitor.coverage's pattern. A profile with no pattern configured is unaffected (verified by test).

Stage B (quarantine the credential) and Stage C (snapshot the work) are out of scope here.

Tests: mvn -f bridged/pom.xml clean install — Tests run: 704, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESS.

Adds a per-profile `exhaustedPattern` regex (opt-in, no vendor wording in Java) and a new `Rendezvous.Kind`/`MessageService.Outcome.BACKEND_EXHAUSTED` distinct from `WORKER_FAILED`/`GONE`. When a turn ends with no bridge_reply and the scrape matches the configured pattern, `CompletionResolver` resolves the send as BACKEND_EXHAUSTED (reason carries the matched line) instead of handing back the scrape as a completed reply. Wired through REST (`BridgedApp`) and MCP (`BridgeMcp`) surfaces. Coverage is logged at startup via `CompletionResolver.coverage(...)`, naming which profiles have a pattern configured, following `FleetHealthMonitor.coverage`'s pattern. A profile with no pattern configured is unaffected (verified by test). Stage B (quarantine the credential) and Stage C (snapshot the work) are out of scope here. Tests: `mvn -f bridged/pom.xml clean install` — Tests run: 704, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESS.
agent added 1 commit 2026-08-15 09:55:26 +02:00
CB-578 stage A: classify a usage-limit refusal instead of a completed reply
CI / build (pull_request) Failing after 59s
CI / contract (pull_request) Successful in 1m10s
541df87272
A backend that refuses on a subscription usage limit leaves the pane healthy but
the turn ends with no bridge_reply; the completion fallback used to scrape and
hand that refusal back as if it were a real answer. CompletionResolver now
matches the scrape against a per-profile exhaustedPattern (config, never a
vendor string) and resolves the send as Rendezvous.Kind/Outcome.BACKEND_EXHAUSTED
with a reason carrying the matched line, kept distinct from GONE/WORKER_FAILED.
A profile with no pattern configured is unaffected. Coverage is logged at
startup via CompletionResolver.coverage(...), naming which profiles have a
pattern and which don't, following FleetHealthMonitor.coverage's pattern.
Owner

Merged to main as 2c2196a.

Lead verification (not the implementer's numbers): own build of this branch merged onto main — 704 tests, BUILD SUCCESS, exit 0, 46 test classes, no failure reports.

Acceptance criteria checked one by one:

  • Pattern comes from config, not code — Profile.exhaustedPattern, compiled once at startup. ✅
  • No vendor wording in Java — grep -rniE "usage limit|rate limit|quota|resets at|too many requests" bridged/src/main/java/ returns nothing. ✅
  • Required dependency, no defaulting overload — CompletionResolver takes ExhaustedPatternLookup with Objects.requireNonNull and no convenience constructor; ExhaustedPatternLookup.none() is the explicit inert stand-in that omits the fact rather than inventing one. ✅
  • A profile with no pattern behaves exactly as today — unset/blank normalises to null in the compact constructor, so the profile is absent from the map, the lookup returns null, and the code falls straight through to the existing completion path. ✅

Deviation from my brief, accepted. The brief asked for a terminal HealthState.BACKEND_EXHAUSTED. The implementer declined and put the signal on Rendezvous.Kind / MessageService.Outcome instead. I checked the argument against the code and it is right: FleetHealth.decide() is a pure classifier over HealthSnapshot, which carries only booleans, AgentStatus and MemberSession.State — never pane text. FleetHealth's own javadoc already says ERROR_ON_SCREEN "is not decided yet because it needs a bounded pane detection read and an adapter-specific fatal signature; status facts alone must not guess it." Adding a second declared-but-unproduced value would have repeated a gap the class already documents as a problem. The signal now lives where the evidence actually is.

Follow-up noted, not blocking. The pattern map is built once in Bridged.main from the startup config snapshot, so exhaustedPattern is a deferred key — adding one to a profile at runtime does nothing until a restart, and bridged.example.yaml does not say so yet. I will carry that into the Features entry.

Merged to `main` as **2c2196a**. Lead verification (not the implementer's numbers): own build of this branch merged onto `main` — **704 tests, BUILD SUCCESS, exit 0**, 46 test classes, no failure reports. Acceptance criteria checked one by one: - **Pattern comes from config, not code** — `Profile.exhaustedPattern`, compiled once at startup. ✅ - **No vendor wording in Java** — `grep -rniE "usage limit|rate limit|quota|resets at|too many requests" bridged/src/main/java/` returns nothing. ✅ - **Required dependency, no defaulting overload** — `CompletionResolver` takes `ExhaustedPatternLookup` with `Objects.requireNonNull` and no convenience constructor; `ExhaustedPatternLookup.none()` is the explicit inert stand-in that *omits* the fact rather than inventing one. ✅ - **A profile with no pattern behaves exactly as today** — unset/blank normalises to `null` in the compact constructor, so the profile is absent from the map, the lookup returns `null`, and the code falls straight through to the existing completion path. ✅ **Deviation from my brief, accepted.** The brief asked for a terminal `HealthState.BACKEND_EXHAUSTED`. The implementer declined and put the signal on `Rendezvous.Kind` / `MessageService.Outcome` instead. I checked the argument against the code and it is right: `FleetHealth.decide()` is a pure classifier over `HealthSnapshot`, which carries only booleans, `AgentStatus` and `MemberSession.State` — never pane text. `FleetHealth`'s own javadoc already says `ERROR_ON_SCREEN` "is not decided yet because it needs a bounded pane detection read and an adapter-specific fatal signature; status facts alone must not guess it." Adding a second declared-but-unproduced value would have repeated a gap the class already documents as a problem. The signal now lives where the evidence actually is. **Follow-up noted, not blocking.** The pattern map is built once in `Bridged.main` from the startup config snapshot, so `exhaustedPattern` is a **deferred** key — adding one to a profile at runtime does nothing until a restart, and `bridged.example.yaml` does not say so yet. I will carry that into the Features entry.
ltms closed this pull request 2026-08-15 10:03:53 +02:00
Some checks are pending
CI / build (pull_request) Failing after 59s
CI / contract (pull_request) Successful in 1m10s

Pull request closed

Sign in to join this conversation.