Skip to content

LLM gateway: ct audit + mandatory ct on ILlmClient (phase 4 of #352)#359

Merged
rockfordlhotka merged 2 commits intomainfrom
feature/llm-gateway-ct-audit
May 8, 2026
Merged

LLM gateway: ct audit + mandatory ct on ILlmClient (phase 4 of #352)#359
rockfordlhotka merged 2 commits intomainfrom
feature/llm-gateway-ct-audit

Conversation

@rockfordlhotka
Copy link
Copy Markdown
Member

Final phase of design/llm-gateway.md. Closes the cancellation contract: audits every existing ILlmClient call site and makes ct a mandatory parameter so future violations cannot be introduced silently.

Builds on phases 1 (#355) and 3 (#358).

Audit results

16 ILlmClient.GetResponseAsync call sites across the codebase. 13 already passed ct correctly. 3 violations found and fixed:

File Issue
RockBot.Memory/MemoryTools.cs:352 Background SaveMemory worker via Task.Run — no caller-supplied ct
RockBot.Skills/SkillTools.cs:193 Background skill summary generation via Task.Run — no caller-supplied ct
RockBot.Host/SessionSummaryService.cs:152 Timer-driven evaluation — no caller-supplied ct

All three are detached background work with no natural ct. They now pass CancellationToken.None explicitly, with comments documenting the design choice and noting that a future refactor could plumb IHostApplicationLifetime.ApplicationStopping for graceful shutdown of in-flight LLM calls. The audit forces this to be intentional rather than accidental.

Compile-time enforcement

  • ILlmClient.GetResponseAsync (both overloads) drop = default on cancellationToken. The compiler now catches any future call site that tries to omit it.
  • LlmClient implementation matched (defaults removed for consistency).
  • Two existing call sites (AgentCardSummarizer, McpBridgeService) used the named-arg pattern cancellationToken: ct which silently picked up the default for options. These are made explicit with options: null in the same change.

Tests

  • Adds ExecuteAsync_CancellationWhileInFlight_AbortsAndReleasesSlot to close the in-flight cancellation gap the design called for in this phase. Verifies cancellation mid-operation aborts, releases the slot, and follow-up calls succeed.
  • 13/13 LlmGatewayTests pass.
  • 629/629 Host tests pass.
  • Full solution test run clean.

Test plan

  • dotnet build RockBot.slnx — clean
  • dotnet test --filter "FullyQualifiedName~LlmGatewayTests" — 13/13 pass
  • Full Host suite — 629/629 pass
  • Full solution test run — all projects pass

Closes #352

Phase 1 (concurrency cap), phase 3 (bounded queue), and phase 4 (ct audit + mandatory ct) all landed. Phase 2 (gateway retry) was dropped in favor of keeping SDK retry enabled.

🤖 Generated with Claude Code

rockfordlhotka and others added 2 commits May 7, 2026 20:37
Final phase: makes the cancellation contract enforceable at compile time
and fixes the call sites that were silently dropping ct.

Audit results across the codebase: 16 ILlmClient.GetResponseAsync call
sites. 13 already passed ct correctly. 3 violations found:

- src/RockBot.Memory/MemoryTools.cs:352 (background SaveMemory worker
  via Task.Run — no caller-supplied ct)
- src/RockBot.Skills/SkillTools.cs:193 (background skill summary
  generation via Task.Run — no caller-supplied ct)
- src/RockBot.Host/SessionSummaryService.cs:152 (timer-driven
  evaluation — no caller-supplied ct)

All three are detached background work. They now pass
CancellationToken.None explicitly with comments documenting the design
choice and a note that future work could plumb
IHostApplicationLifetime.ApplicationStopping for graceful shutdown of
in-flight calls. The audit forces this to be intentional rather than
accidental.

Compile-time enforcement:
- ILlmClient.GetResponseAsync (both overloads) drop the
  "= default" on cancellationToken. Callers must now pass it explicitly;
  the compiler catches future violations.
- LlmClient implementation matched (defaults removed for consistency).
- Two existing call sites (AgentCardSummarizer, McpBridgeService) used
  the named-arg pattern `cancellationToken: ct` which silently picked
  up the default for `options`; these are made explicit with `options: null`.

Tests:
- Adds ExecuteAsync_CancellationWhileInFlight_AbortsAndReleasesSlot,
  closing the in-flight cancellation gap the design called out for this
  phase. Verifies that cancelling ct mid-operation aborts, releases the
  slot, and that follow-up calls succeed (no leaked slots).
- 13 LlmGatewayTests pass; 629 Host tests pass; full solution test run
  clean.

This completes #352. Phase 1 (concurrency cap), phase 3 (bounded queue),
and phase 4 (ct audit + mandatory ct) all landed; phase 2 (gateway
retry) was dropped in favor of keeping SDK retry enabled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rockfordlhotka rockfordlhotka merged commit 0672fab into main May 8, 2026
1 check passed
@rockfordlhotka rockfordlhotka deleted the feature/llm-gateway-ct-audit branch May 8, 2026 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LLM gateway: per-tier concurrency cap, retry, ct propagation

1 participant