Skip to content

perf(retrieval): fair snapshot admission, pool right-sizing, and TTFT attribution - #292

Merged
kl3inIT merged 5 commits into
mainfrom
feat/retrieval-admission-phase1
Aug 4, 2026
Merged

perf(retrieval): fair snapshot admission, pool right-sizing, and TTFT attribution#292
kl3inIT merged 5 commits into
mainfrom
feat/retrieval-admission-phase1

Conversation

@kl3inIT

@kl3inIT kl3inIT commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 1 of ADR 0020 (retrieval admission control and pool right-sizing), per the active increment design and plan:

  • Fair 4-permit retrieval admission (RetrievalAdmissionControl, env ORGMEMORY_GRAPH_QUERY_ADMISSION_PERMITS): every snapshot storage query acquires a JVM-wide fair permit before entering LightRagQueryEngine.executePrepared. Caps retrieval's total DB draw at 4 of 8 connections, removing the pool-exhaustion mode behind the bimodal 120 s turn timeouts (18% of production turns).
  • Barrier → continuous admission: per-batch future.get() barriers replaced with submit-all + ExecutorCompletionService (completion-order failure detection, request-order consolidation, unchanged fail-closed cancellation).
  • API Hikari pool 12/2 → fixed 8/8 per the HikariCP sizing formula on the 4-vCPU shared host; worker pool untouched.
  • topK 60 → 40 (upstream LightRAG v1.5.4 default; the 60 had no recorded rationale).
  • Assistant TTFT attribution: payload-free stage events for grounding-to-prompt assembly, conversation-history load, and retrieval-completion-to-first-token, feeding OpenTelemetry spans and bounded-cardinality Micrometer timers — makes the ~2.4 s of TTFT currently unattributed above the retrieval service traceable.

No authorization path, cache identity, schema, or worker change. The compound multi-snapshot query is Phase 2, gated by ADR 0020 conditions 2–3.

Decision provenance: two-model architecture debate (Claude Fable 5 vs GPT-5.6-sol ultra, no-tools judge) consolidated in ADR 0020. Implementation by Codex gpt-5.6-sol (high) under handoff; coordinator-reviewed.

Verification

  • Terminating ./gradlew --no-daemon clean test — PASS, 108 tasks, 8m17s (repeat on the final commit: PASS).
  • Focused core retrieval/assistant/telemetry and API property/OTel/Micrometer tests — PASS.
  • New invariant tests: admission-before-storage-query with permit release, fairness, continuous admission (later space starts before an earlier straggler completes), fail-closed cancellation of outstanding tasks, topK=40/permit defaults, closed OTel attribute set, bounded Micrometer tags.
  • Production before/after Prometheus window follows the deploy (also closes the pending live proof of the 2026-07-28 LightRAG-latency increment).

Note for reviewers: retrieve_snapshot durations now include admission wait (timer starts before permit acquisition), which makes queue time observable but changes that metric's meaning across the deploy boundary.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added assistant performance monitoring for prompt preparation, response startup, history loading, success, and failure outcomes.
    • Added configurable limits for concurrent retrieval work to improve stability under load.
  • Improvements
    • Retrieval now processes multiple spaces more efficiently while preserving result order.
    • Reduced the default number of retrieved results from 60 to 40.
    • Updated production database connection pooling defaults for more predictable resource usage.

kl3inIT and others added 3 commits August 4, 2026 23:21
Consolidates the two-model architecture debate into decision 0020 and opens
the Phase 1 increment: fair 4-permit retrieval admission, API pool 8/8,
topK reverted to the upstream default, and assistant-layer TTFT attribution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kl3inIT, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09e94be0-7968-4fbe-b407-0dd8a2ee43c3

📥 Commits

Reviewing files that changed from the base of the PR and between d74711f and ccce263.

⛔ Files ignored due to path filters (1)
  • docs/increments/active/2026-08-05-retrieval-admission-phase1/plan.md is excluded by !docs/**
📒 Files selected for processing (1)
  • .tegami/2026-08-05-retrieval-admission-control.md
📝 Walkthrough

Walkthrough

The PR adds payload-free assistant stage telemetry across the core and API modules. It instruments chat-memory loads and assistant turn stages through Micrometer and OpenTelemetry. It also adds fair retrieval admission control, concurrent snapshot execution, new runtime defaults, and related tests.

Changes

Assistant observability

Layer / File(s) Summary
Stage event contract and assistant emission
core/src/main/java/com/orgmemory/core/assistant/..., core/src/test/java/com/orgmemory/core/assistant/...
Defines validated stage events and sink composition. AssistantService emits prompt-assembly and first-token events.
API telemetry sinks and memory instrumentation
apps/api/src/main/java/com/orgmemory/api/assistant/..., apps/api/src/test/java/com/orgmemory/api/assistant/..., apps/api/src/test/java/com/orgmemory/api/MetricsDistributionTests.java, apps/api/build.gradle.kts
Adds Micrometer and OpenTelemetry sinks. Wraps chat memory with ObservedChatMemory. Adds sink, memory, metric, and OpenTelemetry tests.

Retrieval control

Layer / File(s) Summary
Retrieval admission and concurrent snapshot execution
core/src/main/java/com/orgmemory/core/knowledge/retrieval/..., core/src/test/java/com/orgmemory/core/knowledge/retrieval/..., apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java, apps/api/src/test/java/com/orgmemory/api/assistant/GraphRagQueryRuntimePropertiesTests.java
Adds fair semaphore-based admission control. Snapshot queries use completion-order execution with original-order aggregation and cancellation after failure.
Runtime defaults and pool settings
apps/api/src/main/resources/application.yml, apps/api/src/main/resources/application-prod.yml
Sets four retrieval-admission permits, changes default topK to 40, and changes production HikariCP defaults to eight maximum and eight minimum idle connections.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AssistantService
  participant ObservedChatMemory
  participant AssistantStageEventSink
  participant OpenTelemetryAssistantStageEventSink
  participant MicrometerAssistantStageEventSink
  Client->>AssistantService: start assistant turn
  AssistantService->>ObservedChatMemory: load conversation history
  ObservedChatMemory->>AssistantStageEventSink: emit history-load event
  AssistantService->>AssistantStageEventSink: emit turn-stage events
  AssistantStageEventSink->>OpenTelemetryAssistantStageEventSink: export span
  AssistantStageEventSink->>MicrometerAssistantStageEventSink: record timer
  AssistantService-->>Client: stream generated tokens
Loading

Possibly related PRs

  • kl3inIT/OrgMemory#40: Both PRs add assistant and GraphRAG observability with stage-event telemetry and OpenTelemetry sinks.
  • kl3inIT/OrgMemory#57: Both PRs modify AssistantConfiguration and chat-memory wiring.
  • kl3inIT/OrgMemory#266: This PR extends the retrieval service architecture introduced there with admission control.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides comprehensive context, implementation details, and verification results, but the required verification checklist sections are empty or incomplete. Complete the verification checklist by checking boxes for test passage and gate status. Clarify documentation impact and explain why public docs do not change if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 1.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: fair snapshot admission control, pool right-sizing, and TTFT attribution through stage events.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/retrieval-admission-phase1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Tegami

This repository uses Tegami to manage releases. When your changes affect published packages, add a changelog file under .tegami/ before merging.

Create a changelog → · Changelog format

Release preview

Package Bump Version
orgmemory minor 0.2.00.3.0

Changelogs in this PR

Changelog Title
2026-08-05-retrieval-admission-control.md Improvements

Run pnpm run tegami locally to create a changelog interactively.

Managed by Tegami.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java`:
- Around line 119-121: Remove the convenience constructors in
DefaultGraphRagKnowledgeRetrievalService that instantiate
RetrievalAdmissionControl, requiring callers to provide the shared instance
explicitly. Update the remaining direct test construction to pass the existing
admission-control instance and preserve the configuration/helper call sites that
already inject one.
- Around line 592-598: Update queryPublishedSpace so the existing
SnapshotQueryResult.duration() measures only engine.executePrepared query
execution, starting its timer after admission.execute grants execution. Do not
include permit acquisition time in that duration; if admission latency must be
exposed, add it as a separate SnapshotQueryResult field rather than changing the
existing duration semantics.
- Around line 540-566: Clarify the concurrency contract around
maximumConcurrentSpaces: the fan-out in the retrieval task now starts all
requests, while shared admission is enforced separately. Decide whether
retrieval-admission-permits is the sole concurrency boundary; if so, deprecate
or remove the unused maximumConcurrentSpaces configuration and key, otherwise
implement an independent limit and document its scope. Update the related
validation and binding so the configuration behavior matches this decision.

In
`@core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java`:
- Around line 23-30: Update RetrievalAdmissionControl.execute(Callable) and the
AssistantService.search() flow to run retrieval through a Future and await it
with the turn timeout via bounded Future.get(timeout, TimeUnit). On timeout or
turn cancellation, cancel the Future, handle InterruptedException and
CancellationException, and ensure abandoned work releases any acquired admission
permit instead of blocking indefinitely.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 735f0f5c-650f-4f75-9f7b-0df608f2e0c5

📥 Commits

Reviewing files that changed from the base of the PR and between bc59ddb and d74711f.

⛔ Files ignored due to path filters (4)
  • docs/decisions/0020-authorized-multi-snapshot-query-plane.md is excluded by !docs/**
  • docs/increments/active/2026-08-05-retrieval-admission-phase1/design.md is excluded by !docs/**
  • docs/increments/active/2026-08-05-retrieval-admission-phase1/plan.md is excluded by !docs/**
  • docs/roadmap.md is excluded by !docs/**
📒 Files selected for processing (22)
  • apps/api/build.gradle.kts
  • apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java
  • apps/api/src/main/resources/application-prod.yml
  • apps/api/src/main/resources/application.yml
  • apps/api/src/test/java/com/orgmemory/api/MetricsDistributionTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/GraphRagQueryRuntimePropertiesTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSinkTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/ObservedChatMemoryTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSinkTests.java
  • core/src/main/java/com/orgmemory/core/assistant/AssistantService.java
  • core/src/main/java/com/orgmemory/core/assistant/observability/AssistantStageEventSink.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalConfiguration.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java
  • core/src/test/java/com/orgmemory/core/assistant/AssistantTurnObservationTests.java
  • core/src/test/java/com/orgmemory/core/assistant/observability/AssistantTurnEventTests.java
  • core/src/test/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalServiceTests.java
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Web · Node 24
  • GitHub Check: Backend · Java 25
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Treat the repository and runtime evidence as the engineering system of record; do not treat chat or Northstar as authoritative.
Before changing a domain, read its specification, test-coverage document, and applicable decision filenames.
Material decisions about domain boundaries, authorization, persistence, publication, concurrency, cache isolation, parity scope, or deployment require an independent architecture challenge and documented alternatives before implementation.
Do not use completed increment documents as the source for current behavior; use them only for history or archaeology.
Before using unfamiliar Spring Boot, Spring Modulith, Spring AI, Gradle, React, Vite, Tailwind, TypeScript, Next.js, or Fumadocs APIs, consult current official documentation, Context7, and the relevant verification skill.
Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work; never commit secrets or customer data.
Keep ddl-auto=validate and pair every persisted-model change with a Flyway migration.
Use the testing harness; a terminating clean test is the JVM context gate, and bootRun is not verification.

Files:

  • apps/api/src/test/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSinkTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/ObservedChatMemoryTests.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java
  • apps/api/src/main/resources/application-prod.yml
  • apps/api/build.gradle.kts
  • apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalConfiguration.java
  • core/src/main/java/com/orgmemory/core/assistant/observability/AssistantStageEventSink.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSinkTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java
  • apps/api/src/main/resources/application.yml
  • core/src/test/java/com/orgmemory/core/assistant/observability/AssistantTurnEventTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/GraphRagQueryRuntimePropertiesTests.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java
  • apps/api/src/test/java/com/orgmemory/api/MetricsDistributionTests.java
  • core/src/test/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalServiceTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java
  • core/src/test/java/com/orgmemory/core/assistant/AssistantTurnObservationTests.java
  • core/src/main/java/com/orgmemory/core/assistant/AssistantService.java
**/*.java

📄 CodeRabbit inference engine (AGENTS.md)

Apply IDE inspection only to edited backend Java files.

Files:

  • apps/api/src/test/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSinkTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/ObservedChatMemoryTests.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalConfiguration.java
  • core/src/main/java/com/orgmemory/core/assistant/observability/AssistantStageEventSink.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSinkTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java
  • core/src/test/java/com/orgmemory/core/assistant/observability/AssistantTurnEventTests.java
  • apps/api/src/test/java/com/orgmemory/api/assistant/GraphRagQueryRuntimePropertiesTests.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java
  • apps/api/src/test/java/com/orgmemory/api/MetricsDistributionTests.java
  • core/src/test/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalServiceTests.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java
  • core/src/test/java/com/orgmemory/core/assistant/AssistantTurnObservationTests.java
  • core/src/main/java/com/orgmemory/core/assistant/AssistantService.java
apps/api/src/main/java/**/*.java

⚙️ CodeRabbit configuration file

apps/api/src/main/java/**/*.java: Enforce the browser-BFF and resource-server boundaries. Authentication
must resolve an active internal actor through the explicit issuer and
subject binding. Reject identity, tenant, roles, or permissions supplied
by request payloads, JWT email, or untrusted JWT role claims.

Files:

  • apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java
core/src/main/java/com/orgmemory/core/{authorization,knowledge,permission}/**/*.java

⚙️ CodeRabbit configuration file

core/src/main/java/com/orgmemory/core/{authorization,knowledge,permission}/**/*.java: Treat PostgreSQL ACL evidence as canonical and OpenFGA as the relationship
authorization decision point. Authorization must fail closed. Filtering
must happen before ranking, LIMIT, graph traversal, answer generation,
export, and citation rendering. Flag metadata or timing leak paths.

Files:

  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalConfiguration.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java
  • core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java
🧠 Learnings (1)
📚 Learning: 2026-07-26T05:46:47.443Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 61
File: apps/mcp/src/main/java/com/orgmemory/mcp/McpSecurityConfiguration.java:50-52
Timestamp: 2026-07-26T05:46:47.443Z
Learning: In OrgMemory, treat the `apps/mcp` and `apps/api` as independent protocol adapter modules. When adjusting OAuth/wire-level scopes, do not introduce a shared Java constant or create a code dependency from `apps/mcp` to `apps/api` solely to deduplicate scope values. Instead, keep OAuth/scope constants adapter-local (e.g., in the relevant adapter/security configuration classes) and ensure cross-adapter consistency via automated realm/OAuth/authorization tests, rather than via shared wiring-level constants or cross-module references.

Applied to files:

  • apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java
  • apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java
🪛 ast-grep (0.45.0)
apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java

[warning] 52-52: Avoid using untrusted input as a setAttribute() name (trust boundary violation)
Context: span.setAttribute(ENGINE, value(event.engine()))
Note: [CWE-501] Trust Boundary Violation.

(trust-boundaries-java)


[warning] 53-53: Avoid using untrusted input as a setAttribute() name (trust boundary violation)
Context: span.setAttribute(STAGE, value(event.stage()))
Note: [CWE-501] Trust Boundary Violation.

(trust-boundaries-java)


[warning] 54-54: Avoid using untrusted input as a setAttribute() name (trust boundary violation)
Context: span.setAttribute(OUTCOME, value(event.outcome()))
Note: [CWE-501] Trust Boundary Violation.

(trust-boundaries-java)


[warning] 55-57: Avoid using untrusted input as a setAttribute() name (trust boundary violation)
Context: span.setAttribute(
DURATION_NANOS,
event.duration().toNanos())
Note: [CWE-501] Trust Boundary Violation.

(trust-boundaries-java)


[warning] 59-59: Avoid using untrusted input as a setAttribute() name (trust boundary violation)
Context: span.setAttribute(FAILURE_CODE, event.failureCode())
Note: [CWE-501] Trust Boundary Violation.

(trust-boundaries-java)

🔇 Additional comments (22)
core/src/main/java/com/orgmemory/core/assistant/observability/AssistantStageEventSink.java (1)

1-86: LGTM!

core/src/main/java/com/orgmemory/core/assistant/AssistantService.java (1)

7-8: LGTM!

Also applies to: 18-19, 36-36, 49-67, 116-156, 178-191, 215-230

core/src/test/java/com/orgmemory/core/assistant/AssistantTurnObservationTests.java (1)

11-20: LGTM!

Also applies to: 38-38, 60-61, 178-211

core/src/test/java/com/orgmemory/core/assistant/observability/AssistantTurnEventTests.java (1)

22-34: LGTM!

apps/api/src/test/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSinkTests.java (1)

1-41: LGTM!

apps/api/src/test/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSinkTests.java (1)

1-87: LGTM!

apps/api/src/test/java/com/orgmemory/api/MetricsDistributionTests.java (1)

48-48: LGTM!

Also applies to: 67-67

apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java (1)

7-7: LGTM!

Also applies to: 19-21, 41-52, 75-94

apps/api/src/main/java/com/orgmemory/api/assistant/ObservedChatMemory.java (1)

1-71: LGTM!

apps/api/src/main/java/com/orgmemory/api/assistant/OpenTelemetryAssistantStageEventSink.java (1)

1-79: LGTM!

apps/api/src/main/java/com/orgmemory/api/assistant/MicrometerAssistantStageEventSink.java (1)

1-37: LGTM!

apps/api/build.gradle.kts (1)

45-45: LGTM!

apps/api/src/test/java/com/orgmemory/api/assistant/ObservedChatMemoryTests.java (1)

1-79: LGTM!

core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java (1)

14-14: LGTM!

Also applies to: 29-29, 74-75

apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagQueryRuntimeProperties.java (1)

15-15: LGTM!

Also applies to: 49-53, 106-106

core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java (1)

15-21: LGTM!

Also applies to: 32-38

core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalConfiguration.java (1)

18-24: LGTM!

Also applies to: 38-38, 55-56

core/src/main/java/com/orgmemory/core/knowledge/retrieval/DefaultGraphRagKnowledgeRetrievalService.java (1)

46-46: LGTM!

Also applies to: 91-91, 184-184, 608-611

core/src/test/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalServiceTests.java (1)

6-6: LGTM!

Also applies to: 32-40, 85-88, 178-216, 218-269, 271-327, 1062-1062, 1085-1105, 1144-1184

apps/api/src/test/java/com/orgmemory/api/assistant/GraphRagQueryRuntimePropertiesTests.java (1)

26-40: LGTM!

Also applies to: 80-107

apps/api/src/main/resources/application.yml (1)

153-154: LGTM!

apps/api/src/main/resources/application-prod.yml (1)

10-11: 🩺 Stability & Availability

No change needed.

The assistant retrieval path completes retrieval.search(...) before streaming, and retrieval-admission-permits: 4 + pool-size 8 = 12, leaving connections for the active request after admission.

			> Likely an incorrect or invalid review comment.

Comment on lines +23 to +30
<T> T execute(Callable<T> query) throws Exception {
permits.acquire();
try {
return query.call();
} finally {
permits.release();
}
}

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Trace how the assistant turn timeout terminates in-flight retrieval work.
set -euo pipefail

# Locate the turn-timeout consumer and check for interrupt-capable cancellation.
rg -n -C 6 'turn-timeout|turnTimeout' --type=java

# Inspect the assistant orchestration for timeout enforcement primitives.
fd -e java --iglob '*Assistant*' | while IFS= read -r file; do
  rg -n -C 4 'orTimeout|completeOnTimeout|awaitTermination|cancel\(|Future|shutdownNow' "$file" || true
done

# Check whether any caller bounds the retrieval search call itself.
rg -n -C 5 '\.search\(' --type=java -g '!**/test/**'

Repository: kl3inIT/OrgMemory

Length of output: 155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Java files matching retrieval/admission/assistant names:\n'
fd -e java -i 'RetrievalAdmissionControl|assistant|Assistant|turn-timeout|turnTimeout|publishedSpaces' . | sed -n '1,120p'

printf '\nSearch timeout/cancel/acquire/take usages:\n'
rg -n -C 4 'acquir|turn-timeout|turnTimeout|orTimeout|completeOnTimeout|awaitTermination|cancel\(|shutdownNow|completed\.take|RetrievalAdmissionControl' --type=java || true

printf '\nGit status/stat:\n'
git status --short
git diff --stat HEAD || true

Repository: kl3inIT/OrgMemory

Length of output: 6198


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files mentioning ORGMEMORY_ASSISTANT_TURN_TIMEOUT / assistant timeout / turn timeout:\n'
rg -n -i 'ORGMEMORY_ASSISTANT_TURN_TIMEOUT|ASSISTANT_TURN_TIMEOUT|Assistant.*Timeout|turn.*timeout|timeout.*turn' . || true

printf '\nRetrievalAdmissionControl.java:\n'
cat -n core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java

printf '\nAssistantConfiguration.java:\n'
cat -n apps/api/src/main/java/com/orgmemory/api/assistant/AssistantConfiguration.java

printf '\nAssistantProperties.java:\n'
cat -n apps/api/src/main/java/com/orgmemory/api/assistant/AssistantProperties.java

printf '\nAssistantController.java relevant excerpts:\n'
wc -l apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java
sed -n '1,260p' apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java

printf '\nAssistantService.java if present:\n'
if [ -f core/src/main/java/com/orgmemory/core/assistant/AssistantService.java ]; then
  rg -n -C 5 'Future|Executor|submit|CompletableFuture|timeout|queryPublishedSpaces|retrieval|search' core/src/main/java/com/orgmemory/core/assistant/AssistantService.java || true
fi

Repository: kl3inIT/OrgMemory

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Focused search for assistant turn timeout implementation:\n'
rg -n -C 4 'withTimeout|scheduledExecutorService|setTimeout|ORGMEMORY_ASSISTANT_TURN_TIMEOUT|turnTimeout|completed\.take|CompletionQueue|RetrievalAdmissionControl|permit' --type=java . | sed -n '1,240p'

printf '\nFocused listing for timeout-related files:\n'
fd -e java -i 'Timeout|turn|completion|queue|retrieval|Assistant' . | sed -n '1,200p'

printf '\nAssistant controller focused excerpts:\n'
rg -n -C 8 'get|Future|CompletableFuture|Thread|interrupt|timeout' apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java || true

Repository: kl3inIT/OrgMemory

Length of output: 41342


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'AssistantController.java outline and relevant excerpt:\n'
wc -l apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java
sed -n '1,170p' apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController|cat -n

printf '\nRetrievalAdmissionControl exact file:\n'
cat -n core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java

printf '\nAssistantService.java outline and relevant terms:\n'
wc -l core/src/main/java/com/orgmemory/core/assistant/AssistantService.java
rg -n -C 8 'Future|Executor|submit|CompletableFuture|turnTimeout|timeout|search|queryPublishedSpaces|RetrievalAdmissionControl|cancel|interrupt' core/src/main/java/com/orgmemory/core/assistant/AssistantService.java || true

Repository: kl3inIT/OrgMemory

Length of output: 404


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'AssistantController.java outline:\n'
ast-grep outline apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java --view compact || true

printf '\nAssistantController.java first 160 lines:\n'
sed -n '1,160p' apps/api/src/main/java/com/orgmemory/api/assistant/AssistantController.java | cat -n

printf '\nAssistantService.java size and timeout/retrieval search:\n'
wc -l core/src/main/java/com/orgmemory/core/assistant/AssistantService.java
rg -n -C 10 'Future|Executor|submit|CompletableFuture|turnTimeout|timeout|queryPublishedSpaces|search\(|RetrievalAdmissionControl|future\.cancel|cancel\(|interrupt|completion|taken|take\(' core/src/main/java/com/orgmemory/core/assistant/AssistantService.java || true

Repository: kl3inIT/OrgMemory

Length of output: 9761


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'AssistantService.java full implementation:\n'
cat -n core/src/main/java/com/orgmemory/core/assistant/AssistantService.java

printf '\nUiMessageStream.java timeout implementation:\n'
wc -l apps/api/src/main/java/com/orgmemory/api/assistant/UiMessageStream.java
cat -n apps/api/src/main/java/com/orgmemory/api/assistant/UiMessageStream.java

printf '\nGraphRagKnowledgeRetrievalService relevant search/admission:\n'
wc -l core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalService.java
rg -n -C 12 'search\(|RetrievalAdmissionControl|completionQueue|published\(|queryPublishedSpaces|submit|Future|cancel' core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalService.java || true

Repository: kl3inIT/OrgMemory

Length of output: 20779


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'GraphRagKnowledgeRetrievalService.java outline:\n'
ast-grep outline core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalService.java --view digest || true

printf '\nGraphRagKnowledgeRetrievalService.java excerpts:\n'
wc -l core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalService.java
sed -n '1,320p' core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagKnowledgeRetrievalService.java | cat -n

printf '\nGraphRagRetrievalPolicy relevant defaults:\n'
cat -n core/src/main/java/com/orgmemory/core/knowledge/retrieval/GraphRagRetrievalPolicy.java

printf '\nRead-only behavioral probe for blocking queues/semaphores:\n'
python3 - <<'PY'
import threading, time

class Probe:
    pass

def blocking_take():
    p = Probe()
    p.q = []
    p.done = threading.Event()
    def producer():
        time.sleep(1)
        p.q.append(1)
        p.done.set()
    threading.Thread(target=producer, daemon=True).start()
    # Java BlockingQueue.take blocks until an element becomes available.
    # This loop would also block in a real production use if the producer never comes.
    for _ in range(5):
        if p.done.is_set:
            return p.q
        time.sleep(0.1)
    return "blocked"

try:
    # Semaphore.acquire(0) also blocks until a permit is released by another thread.
    from threading import BoundedSemaphore
    s = BoundedSemaphore(0)
    print("semaphore initial:", s.acquire(blocking=False))
    print("take blocked:", threading.Thread(target=blocking_take).daemon == True)
except Exception as e:
    print("probes:", repr(e))
PY

printf '\nSearch for any interrupt/cancel handling in assistant stream or timeout tests:\n'
rg -n -C 6 'interrupt|cancel\(|shutdownNow|turnTimeout|turn timed out|AssistantStreamAborted|blocks|acquir|take\(' apps/core apps/api core/src/test -g '*.java' || true

Repository: kl3inIT/OrgMemory

Length of output: 33633


Use bounded blocking waits for turn cancellation.

AssistantService.search() runs synchronously, then UiMessageStream.encode() applies the turn timeout only to the returned stream. Timeout cancellation does not interrupt the blocking RetrievalAdmissionControl.execute(Callable) queue or Future.get() wait because AssistantTurn does not hold the retrieval Future; it only holds the generated Flux. Run the search work through a bounded Future.get(timeout, TimeUnit), cancel the future on turn cancellation, and handle InterruptedException/CancellationException so admission permits are released or not consumed by abandoned turns.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java`
around lines 23 - 30, Update RetrievalAdmissionControl.execute(Callable) and the
AssistantService.search() flow to run retrieval through a Future and await it
with the turn timeout via bounded Future.get(timeout, TimeUnit). On timeout or
turn cancellation, cancel the Future, handle InterruptedException and
CancellationException, and ensure abandoned work releases any acquired admission
permit instead of blocking indefinitely.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially pre-existing, partially real — recording as a tracked follow-up rather than fixing here. Pre-existing: the turn timeout has never interrupted the synchronous AssistantService.search() — it applies to the returned stream only, before this PR too. New in this PR: an abandoned turn can additionally wait in the fair admission queue and will still consume a permit + one storage query after its timeout fired (bounded zombie work: at most one executePrepared per queued space, permits are always released in finally). At current production concurrency (45 turns/week, 4 permits) the waste window is small, and plumbing the turn deadline into the retrieval path crosses the Phase 1 scope boundary (ADR 0020 keeps timeout semantics unchanged). Added to the increment plan as a deferred finding so the Phase 2 compound-query port — which replaces this call path entirely — must address bounded, cancellable admission (deadline-aware acquire + cooperative cancellation between UiMessageStream and the retrieval future).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kl3inIT, acknowledged. The finding remains valid, but the Phase 1 scope decision is reasonable.

The current behavior bounds abandoned retrieval work, and RetrievalAdmissionControl releases permits reliably. Phase 2 must make admission deadline-aware and connect UiMessageStream cancellation to the retrieval Future.

🐇💭


✏️ Learnings added
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 292
File: core/src/main/java/com/orgmemory/core/knowledge/retrieval/RetrievalAdmissionControl.java:23-30
Timestamp: 2026-08-04T17:14:17.867Z
Learning: In the Java assistant retrieval flow, the turn timeout applies to the stream returned by synchronous `AssistantService.search()` and does not interrupt the retrieval call. `RetrievalAdmissionControl.execute(Callable)` uses a fair semaphore and releases permits in `finally`. The Phase 2 compound-query port must add deadline-aware admission and cooperative cancellation between `UiMessageStream` and the retrieval future.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kl3inIT
kl3inIT merged commit f733766 into main Aug 4, 2026
18 checks passed
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.

1 participant