Repository navigation
feat(ai): route RAG workloads by model role - #272
Conversation
…ting-luna # Conflicts: # contracts/openapi.json # docs/specs/domains/secure-graph-rag.md # docs/tests/domains/secure-graph-rag.md
|
Warning Review limit reached
Next review available in: 29 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThe change adds OpenAI reasoning-effort configuration across AI gateway administration, provider integration, query routing, graph extraction, deployment settings, the administration UI, and workload-routing evaluation. ChangesAI workload routing
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Admin
participant RouteController
participant RouteService
participant GatewayRegistry
participant ChatModelFactory
Admin->>RouteController: submit route and reasoning settings
RouteController->>RouteService: validate and persist route
RouteService->>GatewayRegistry: resolve compatible gateway
GatewayRegistry->>ChatModelFactory: create model with reasoning effort
ChatModelFactory-->>Admin: execute configured workload route
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
TegamiThis repository uses Tegami to manage releases. When your changes affect published packages, add a changelog file under Create a changelog → · Changelog format Release preview
Changelogs in this PR
Run Managed by Tegami. |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/web/test/e2e/admin-language-models.spec.ts (1)
192-269: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest the new route behavior, not only the route text.
The fixture declares
supportsOpenAiReasoningEffort: trueandGRAPH_EXTRACTION.editable: false, but the test only checks visible copy. Add browser assertions that a supported route can save"NONE"asopenAiReasoningEffort, an unsupported gateway omits that field, and the Graph route exposes no editable route controls.As per coding guidelines, “Preserve the existing browser test suite when changing the web application.”
🤖 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 `@apps/web/test/e2e/admin-language-models.spec.ts` around lines 192 - 269, Extend the browser assertions in the route test around the mocked /api/admin/ai/routes data to verify behavior, not just displayed text: save “NONE” for a route whose gateway supports OpenAI reasoning effort, confirm the request or persisted route contains that value, verify the unsupported-gateway flow omits openAiReasoningEffort, and assert the GRAPH_EXTRACTION route with editable false exposes no editable controls. Preserve the existing browser test coverage and fixture behavior.Source: Coding guidelines
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java (1)
105-158: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard
cacheKeyagainst anullmodel-route fingerprint.
cacheKeycallsCanonicalCacheKeyHasher.requireSha256(modelRouteFingerprint, "modelRouteFingerprint")without checking fornullfirst.KeywordPlanningModel.modelRouteFingerprint(UUID)defaults tonullfor implementations that do not override it.PlanningResult's constructor treatsnullas a valid, non-hashed value, butcacheKeydoes not apply the same rule.Today's implementations (
SpringAiKeywordPlanningModel,OrganizationAwareKeywordPlanningModel) always overridemodelRouteFingerprint(UUID), so the gap is not exercised yet. A futureKeywordPlanningModelthat relies on the interface default and runs with a configuredCachePolicywill fail on every call tomodelPlan.Add the same
nullcheck used inPlanningResult, or document that any model used with caching must supply a non-null fingerprint and validate that requirement explicitly with a clear error message.🛡️ Proposed guard in `cacheKey`
private ModelInvocationCache.Key cacheKey( String normalizedQuery, UUID organizationId, String strategy, String modelRouteFingerprint) { - if (cachePolicy == null || organizationId == null) { + if (cachePolicy == null || organizationId == null || modelRouteFingerprint == null) { return null; } return ModelInvocationCacheKeys.keywords(🤖 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 `@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java` around lines 105 - 158, Update cacheKey to handle a null modelRouteFingerprint consistently with PlanningResult before calling CanonicalCacheKeyHasher.requireSha256. Preserve cache-key generation for non-null fingerprints, and ensure models using the interface default fingerprint do not fail when caching is enabled.apps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java (1)
335-344: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDuplicate the editable-workload rule from a single source.
RouteResponse.deployment()hardcodes the editable set asASSISTANT_CHAT, PROMPT_EXECUTION, KEYWORD_PLANNING. The core layer expresses the same rule independently throughAiGatewayAdministrationService.requireEditableWorkload()(exercised byAiGatewayAdministrationServiceTests, wheresetRoute/clearRouterejectGRAPH_EXTRACTION). Both lists match today, but a futureAiWorkloadaddition or editability change only needs to update one of the two lists to make the admin UI drift from backend behavior: the UI could offer editing for a workload the backend rejects, or hide a workload the backend would accept.Extract this rule to one place, for example an
AiWorkload.editable()method or a shared constant in the core module, and have bothAdminAiModelControllerandAiGatewayAdministrationServiceread from it.Also applies to: 538-556
🤖 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 `@apps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java` around lines 335 - 344, Centralize the editable-workload rule currently duplicated between RouteResponse.deployment() and AiGatewayAdministrationService.requireEditableWorkload(). Add a shared AiWorkload-level method or core constant, then update both AdminAiModelController and AiGatewayAdministrationService to use it, preserving rejection of non-editable workloads such as GRAPH_EXTRACTION.integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.java (1)
76-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Gateway.toString()omits the new capability flag.
Gatewaynow carriessupportsOpenAiReasoningEffort, buttoString()still prints onlydisplayName,baseUrl,apiKey,capabilities, andtimeout.AiGatewayRegistry.ResolvedGatewayandSpringAiChatModelFactory.Requestboth include the new field in theirtoString()in this same PR. AddsupportsOpenAiReasoningEfforthere too, for consistent diagnostics when a gateway rejects a reasoning-effort request.♻️ Proposed fix
`@Override` public String toString() { - return "Gateway[displayName=%s, baseUrl=%s, apiKey=%s, capabilities=%s, timeout=%s]" - .formatted(displayName, baseUrl, apiKey.isBlank() ? "" : "***", capabilities, timeout); + return "Gateway[displayName=%s, baseUrl=%s, apiKey=%s, capabilities=%s, timeout=%s, supportsOpenAiReasoningEffort=%s]" + .formatted(displayName, baseUrl, apiKey.isBlank() ? "" : "***", capabilities, timeout, supportsOpenAiReasoningEffort); }🤖 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 `@integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.java` around lines 76 - 80, Update Gateway.toString() to include the supportsOpenAiReasoningEffort field alongside the existing gateway properties, matching the diagnostic output used by AiGatewayRegistry.ResolvedGateway and SpringAiChatModelFactory.Request.
🤖 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
`@apps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModelTests.java`:
- Around line 86-106: The RecordingChatModel test double must implement the
required ChatModel stream(Prompt) method in addition to call(Prompt) and
getOptions(). Add a stream implementation that returns the expected ChatResponse
sequence, reusing the same generated response behavior as call(Prompt), without
changing the test’s keyword payload.
In
`@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/GraphProcessingProfile.java`:
- Around line 34-36: The GraphProcessingProfile constructor must reject non-null
extractionProfile.openAiReasoningEffort() when schemaVersion == 1, since that
field is absent from schema-v1 canonical data. Add the validation alongside the
existing schema-version checks and add a test covering this invalid combination.
In
`@core/src/main/java/com/orgmemory/core/ai/AiGatewayAdministrationService.java`:
- Around line 214-233: Move the supportsOpenAiReasoningEffort read from the
non-transactional update overload into the transactional 8-parameter update
path, using the profile fetched there for both validation and persistence.
Update the overloads and their call flow so concurrent changes are not
overwritten by a stale value from the outer update method.
In `@core/src/main/resources/db/migration/V20__rag_workload_route_options.sql`:
- Around line 7-33: Update the migration’s openai_reasoning_effort column to use
text instead of varchar(16), and add NOT VALID to both new CHECK constraints so
existing production rows are not scanned during constraint creation. If the
table is populated in this migration sequence, add separate validation
statements for chk_ai_route_override_workload and
chk_ai_route_override_openai_reasoning after the constraints are created.
In `@evaluation/src/orgmemory_eval/workload_routing_runner.py`:
- Around line 178-195: Update request_json to retry transient transport failures
with a bounded number of attempts and backoff, matching the existing
RAGAS/OpenAI retry behavior where applicable. Retry only HTTP 429, HTTP 5xx, and
socket timeout errors; let all other exceptions propagate immediately. Preserve
the current successful response parsing and latency return behavior, and ensure
the final failed attempt is propagated rather than silently producing an invalid
observation.
- Around line 194-195: The observe flow must tolerate malformed provider
responses without aborting the benchmark: handle empty choices and non-dict
entities alongside existing response-shape failures, while keeping transport
failures distinct. Add the required case-key validation in main before the
request loop so missing fixture keys fail as fixture errors rather than being
recorded as provider failures; update the observe exception handling around body
parsing and entity validation accordingly.
- Around line 266-278: Update aggregate to compute meanRecall and p95LatencyMs
from successful observations only, filtering out failed items before calculating
those quality metrics. Keep samples, validResponses, providerFailures, and
errorCodes based on all observations, and preserve the existing output keys and
rounding behavior.
In `@evaluation/tests/test_workload_routing_runner.py`:
- Around line 49-51: Extend the activation assertions around
activation("keyword", ...) and activation("graph", ...) to also evaluate the
worsened p95LatencyMs input for the Keyword gate. Assert that the Keyword result
remains active while the Graph gate is rejected, proving the two gates operate
independently.
---
Outside diff comments:
In `@apps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java`:
- Around line 335-344: Centralize the editable-workload rule currently
duplicated between RouteResponse.deployment() and
AiGatewayAdministrationService.requireEditableWorkload(). Add a shared
AiWorkload-level method or core constant, then update both
AdminAiModelController and AiGatewayAdministrationService to use it, preserving
rejection of non-editable workloads such as GRAPH_EXTRACTION.
In `@apps/web/test/e2e/admin-language-models.spec.ts`:
- Around line 192-269: Extend the browser assertions in the route test around
the mocked /api/admin/ai/routes data to verify behavior, not just displayed
text: save “NONE” for a route whose gateway supports OpenAI reasoning effort,
confirm the request or persisted route contains that value, verify the
unsupported-gateway flow omits openAiReasoningEffort, and assert the
GRAPH_EXTRACTION route with editable false exposes no editable controls.
Preserve the existing browser test coverage and fixture behavior.
In
`@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java`:
- Around line 105-158: Update cacheKey to handle a null modelRouteFingerprint
consistently with PlanningResult before calling
CanonicalCacheKeyHasher.requireSha256. Preserve cache-key generation for
non-null fingerprints, and ensure models using the interface default fingerprint
do not fail when caching is enabled.
In
`@integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.java`:
- Around line 76-80: Update Gateway.toString() to include the
supportsOpenAiReasoningEffort field alongside the existing gateway properties,
matching the diagnostic output used by AiGatewayRegistry.ResolvedGateway and
SpringAiChatModelFactory.Request.
🪄 Autofix (Beta)
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: 747751bd-5fad-4a50-8ec2-5ba93df58c2f
⛔ Files ignored due to path filters (13)
contracts/openapi.jsonis excluded by!contracts/openapi.jsondocs/increments/active/2026-08-02-rag-workload-routing-luna/challenge-brief.mdis excluded by!docs/**docs/increments/active/2026-08-02-rag-workload-routing-luna/challenge-verdict.mdis excluded by!docs/**docs/increments/active/2026-08-02-rag-workload-routing-luna/design.mdis excluded by!docs/**docs/increments/active/2026-08-02-rag-workload-routing-luna/evaluation-result.jsonis excluded by!docs/**docs/increments/active/2026-08-02-rag-workload-routing-luna/plan.mdis excluded by!docs/**docs/roadmap.mdis excluded by!docs/**docs/specs/domains/ai-model-control-plane.mdis excluded by!docs/**docs/specs/domains/assistant-and-mcp.mdis excluded by!docs/**docs/specs/domains/secure-graph-rag.mdis excluded by!docs/**docs/tests/domains/ai-model-control-plane.mdis excluded by!docs/**docs/tests/domains/assistant-and-mcp.mdis excluded by!docs/**docs/tests/domains/secure-graph-rag.mdis excluded by!docs/**
📒 Files selected for processing (53)
.env.exampleARCHITECTURE.mdapps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.javaapps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModel.javaapps/api/src/main/resources/application.ymlapps/api/src/test/java/com/orgmemory/api/admin/PermissionsAdminIntegrationTests.javaapps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModelTests.javaapps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModelTests.javaapps/web/src/features/admin/components/admin-language-models-page.tsxapps/web/test/e2e/admin-language-models.spec.tsapps/worker/src/main/java/com/orgmemory/worker/graph/GraphIndexingProcessor.javaapps/worker/src/main/resources/application.ymlapps/worker/src/test/java/com/orgmemory/worker/ingestion/SourceIngestionPipelineIntegrationTests.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/ExtractionProfile.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/GraphProcessingProfile.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/LightRagGraphProcessingProfiles.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.javacomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/processing/GraphProcessingProfileTests.javacomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerCacheTests.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayAdministrationService.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayConnection.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayProfile.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayProfileView.javacore/src/main/java/com/orgmemory/core/ai/AiRoute.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverride.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideRepository.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideView.javacore/src/main/java/com/orgmemory/core/ai/OpenAiReasoningEffort.javacore/src/main/java/com/orgmemory/core/knowledge/graph/GraphProcessingProfileResolver.javacore/src/main/resources/db/migration/V20__rag_workload_route_options.sqlcore/src/test/java/com/orgmemory/core/ai/AiGatewayAdministrationServiceTests.javacore/src/test/java/com/orgmemory/core/ai/AiRouteTests.javaevaluation/README.mdevaluation/fixtures/workload-routing-v1.jsonevaluation/pyproject.tomlevaluation/src/orgmemory_eval/workload_routing_runner.pyevaluation/tests/test_workload_routing_runner.pyinfrastructure/deployment/compose.production.yamlinfrastructure/deployment/production.env.exampleintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayRegistry.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelFactory.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelProvider.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/anthropic/AnthropicMessagesChatModelFactory.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactory.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/AiGatewayPropertiesTests.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactoryTests.javaintegrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
- GitHub Check: OpenSearch adapter
- GitHub Check: Backend · Java 25
- GitHub Check: PostgreSQL GraphRAG
- GitHub Check: Web · Node 24
🧰 Additional context used
📓 Path-based instructions (9)
**/*
📄 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.
Readdocs/guidelines/agent-safety.mdbefore retrieval, AI, MCP, permission, upload, graph, or export work; never commit secrets or customer data.
Keepddl-auto=validateand pair every persisted-model change with a Flyway migration.
Use the testing harness; a terminating clean test is the JVM context gate, andbootRunis not verification.
Files:
infrastructure/deployment/production.env.exampleapps/api/src/main/resources/application.ymlevaluation/fixtures/workload-routing-v1.jsonapps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModelTests.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModel.javacore/src/main/java/com/orgmemory/core/ai/OpenAiReasoningEffort.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactoryTests.javacore/src/test/java/com/orgmemory/core/ai/AiRouteTests.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayProfileView.javaevaluation/pyproject.tomlapps/worker/src/main/java/com/orgmemory/worker/graph/GraphIndexingProcessor.javacore/src/main/resources/db/migration/V20__rag_workload_route_options.sqlintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactory.javaapps/worker/src/main/resources/application.ymlcomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/LightRagGraphProcessingProfiles.javacore/src/main/java/com/orgmemory/core/ai/AiRoute.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/anthropic/AnthropicMessagesChatModelFactory.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverride.javacore/src/main/java/com/orgmemory/core/knowledge/graph/GraphProcessingProfileResolver.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/AiGatewayPropertiesTests.javaintegrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.javaapps/worker/src/test/java/com/orgmemory/worker/ingestion/SourceIngestionPipelineIntegrationTests.javaevaluation/README.mdapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/GraphProcessingProfile.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelProvider.javaapps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModelTests.javaevaluation/tests/test_workload_routing_runner.pycore/src/main/java/com/orgmemory/core/ai/AiGatewayProfile.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/ExtractionProfile.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideRepository.javacore/src/test/java/com/orgmemory/core/ai/AiGatewayAdministrationServiceTests.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayRegistry.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideView.javaapps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelFactory.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.javainfrastructure/deployment/compose.production.yamlcore/src/main/java/com/orgmemory/core/ai/AiGatewayConnection.javaapps/api/src/test/java/com/orgmemory/api/admin/PermissionsAdminIntegrationTests.javaARCHITECTURE.mdcomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/processing/GraphProcessingProfileTests.javaapps/web/test/e2e/admin-language-models.spec.tscomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.javacomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerCacheTests.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.javaapps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.javaapps/web/src/features/admin/components/admin-language-models-page.tsxevaluation/src/orgmemory_eval/workload_routing_runner.pycore/src/main/java/com/orgmemory/core/ai/AiGatewayAdministrationService.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/OrganizationAwareKeywordPlanningModelTests.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModel.javacore/src/main/java/com/orgmemory/core/ai/OpenAiReasoningEffort.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactoryTests.javacore/src/test/java/com/orgmemory/core/ai/AiRouteTests.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayProfileView.javaapps/worker/src/main/java/com/orgmemory/worker/graph/GraphIndexingProcessor.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactory.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/LightRagGraphProcessingProfiles.javacore/src/main/java/com/orgmemory/core/ai/AiRoute.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/anthropic/AnthropicMessagesChatModelFactory.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverride.javacore/src/main/java/com/orgmemory/core/knowledge/graph/GraphProcessingProfileResolver.javaintegrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/AiGatewayPropertiesTests.javaintegrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.javaapps/worker/src/test/java/com/orgmemory/worker/ingestion/SourceIngestionPipelineIntegrationTests.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/GraphProcessingProfile.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelProvider.javaapps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModelTests.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayProfile.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/ExtractionProfile.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideRepository.javacore/src/test/java/com/orgmemory/core/ai/AiGatewayAdministrationServiceTests.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayRegistry.javacore/src/main/java/com/orgmemory/core/ai/AiRouteOverrideView.javaapps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelFactory.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayConnection.javaapps/api/src/test/java/com/orgmemory/api/admin/PermissionsAdminIntegrationTests.javacomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/processing/GraphProcessingProfileTests.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.javacomponents/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerCacheTests.javaintegrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.javacomponents/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.javaapps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.javacore/src/main/java/com/orgmemory/core/ai/AiGatewayAdministrationService.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/OrganizationAwareQueryAnswerModel.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.javaapps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.javaapps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java
core/src/main/resources/db/migration/*.sql
⚙️ CodeRabbit configuration file
core/src/main/resources/db/migration/*.sql: The repository is pre-release: V1 is the intentionally resettable clean
baseline and development data carries no migration cost. Once a release
baseline is frozen, later Flyway migrations are immutable. Check tenant
isolation, foreign keys, uniqueness, indexes, append-only evidence
semantics, safe defaults, and PostgreSQL 18 plus pgvector compatibility.
Files:
core/src/main/resources/db/migration/V20__rag_workload_route_options.sql
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/graph/GraphProcessingProfileResolver.java
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Extend the established OrgMemory product shell, design tokens, shadcn/Radix primitives, and existing layout patterns; do not introduce a separate visual system in the web application.
Generate ordinary REST clients fromcontracts/openapi.jsonusing Hey API.
Use TanStack Query for server state, TanStack Router for navigation, and limit Zustand to durable or high-frequency UI state.
Preserve keyboard accessibility, light/dark theme support, loading and error states, and responsive behavior in the web application.
Files:
apps/web/test/e2e/admin-language-models.spec.tsapps/web/src/features/admin/components/admin-language-models-page.tsx
apps/web/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Preserve the existing browser test suite when changing the web application.
Files:
apps/web/test/e2e/admin-language-models.spec.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend changes must pass lint, typecheck, tests, and a production build; perform browser verification when the flow warrants it.
Files:
apps/web/test/e2e/admin-language-models.spec.tsapps/web/src/features/admin/components/admin-language-models-page.tsx
apps/web/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/web/src/**/*.{ts,tsx}: OAuth access and refresh tokens must never enter browser JavaScript or
browser storage. Use the HttpOnly BFF session, CSRF-protected mutations,
generated Hey API data clients, accessible states, and both light and
dark themes. Handwritten transport is reserved for documented protocol
flows such as navigation redirects and streaming.
Files:
apps/web/src/features/admin/components/admin-language-models-page.tsx
🧠 Learnings (4)
📚 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/OrganizationAwareQueryAnswerModel.javaapps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.javaapps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.javaapps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java
📚 Learning: 2026-07-23T23:30:44.585Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 30
File: core/src/main/resources/db/migration/V32__evidence_scoped_graph_semantics.sql:0-0
Timestamp: 2026-07-23T23:30:44.585Z
Learning: For OrgMemory PostgreSQL Flyway migrations under core/src/main/resources/db/migration, do not recommend using `CREATE INDEX CONCURRENTLY` or `DROP INDEX CONCURRENTLY` inside application-owned Flyway migration SQL. Flyway’s schema-history connection may hold a transaction that can cause concurrent index operations to wait indefinitely (e.g., on a `virtualxid`), and docs/conventions.md forbids this pattern. If you need large production-table index replacement, pre-stage online index operations via the deployment pipeline (outside Flyway) rather than inside the migration; “ordinary” index replacement is acceptable for unreleased projections before production traffic.
Applied to files:
core/src/main/resources/db/migration/V20__rag_workload_route_options.sql
📚 Learning: 2026-08-02T08:30:57.335Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 270
File: core/src/main/java/com/orgmemory/core/assetregistry/AssetDraftRepository.java:15-23
Timestamp: 2026-08-02T08:30:57.335Z
Learning: For OrgMemory JPA repository methods using `PESSIMISTIC_WRITE`, do not add a finite lock-timeout hint as part of a behavior-preserving refactor. The V1 PostgreSQL configuration uses `lock_timeout = 0`; any finite lock timeout must be established as a platform-wide database and transaction policy rather than configured on an individual method.
Applied to files:
core/src/main/java/com/orgmemory/core/ai/AiRouteOverrideRepository.java
📚 Learning: 2026-07-27T14:53:53.633Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 92
File: infrastructure/deployment/compose.production.yaml:304-310
Timestamp: 2026-07-27T14:53:53.633Z
Learning: For OrgMemory’s Spring Boot SCIM configuration, the `application.yml`/`application-prod.yml` map `orgmemory.security.scim.*` properties via `${ORGMEMORY_SCIM_*}` placeholders. Therefore, in deployment Compose files and related environment/CI templates, set environment variables using the `ORGMEMORY_SCIM_*` names (e.g., `ORGMEMORY_SCIM_VERIFIER_KEY`) rather than “relaxed-binding-derived” names such as `ORGMEMORY_SECURITY_SCIM_*`. This is required to ensure Spring resolves the intended SCIM configuration properties.
Applied to files:
infrastructure/deployment/compose.production.yaml
🪛 ast-grep (0.45.0)
evaluation/src/orgmemory_eval/workload_routing_runner.py
[info] 186-186: use jsonify instead of json.dumps for JSON output
Context: json.dumps(payload, ensure_ascii=False)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 357-357: use jsonify instead of json.dumps for JSON output
Context: json.dumps(report, indent=2)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 358-358: use jsonify instead of json.dumps for JSON output
Context: json.dumps(report, indent=2)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[warning] 190-190: Request-controlled URL passed to urlopen; validate against an allowlist to prevent SSRF.
Context: urllib.request.urlopen(request, timeout=timeout_seconds)
Note: [CWE-918] Server-Side Request Forgery (SSRF).
(urlopen-unsanitized-data)
🪛 dotenv-linter (4.0.0)
.env.example
[warning] 13-13: [UnorderedKey] The ORGMEMORY_KEYWORD_OPENAI_REASONING_EFFORT key should go before the ORGMEMORY_OPENAI_BASE_URL key
(UnorderedKey)
[warning] 14-14: [UnorderedKey] The ORGMEMORY_GRAPH_EXTRACTION_OPENAI_REASONING_EFFORT key should go before the ORGMEMORY_KEYWORD_OPENAI_REASONING_EFFORT key
(UnorderedKey)
🪛 Squawk (2.61.0)
core/src/main/resources/db/migration/V20__rag_workload_route_options.sql
[warning] 8-8: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 14-20: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.
(constraint-missing-not-valid)
[warning] 23-33: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.
(constraint-missing-not-valid)
🔇 Additional comments (52)
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/ExtractionProfile.java (1)
16-16: LGTM!Also applies to: 44-45, 69-93, 107-107, 127-127, 150-151, 175-187
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/processing/LightRagGraphProcessingProfiles.java (1)
27-36: LGTM!core/src/main/java/com/orgmemory/core/knowledge/graph/GraphProcessingProfileResolver.java (1)
31-33: LGTM!apps/worker/src/main/java/com/orgmemory/worker/graph/GraphIndexingProcessor.java (1)
169-175: LGTM!Also applies to: 249-249
apps/worker/src/test/java/com/orgmemory/worker/ingestion/SourceIngestionPipelineIntegrationTests.java (1)
255-257: LGTM!components/graph-rag-core/src/test/java/com/orgmemory/graphrag/processing/GraphProcessingProfileTests.java (1)
4-40: LGTM!Also applies to: 50-99, 101-124, 196-196
apps/web/src/features/admin/components/admin-language-models-page.tsx (1)
416-444: 📐 Maintainability & Code QualityVerify the required web quality gates.
This change modifies route state, generated-client request bodies, and disabled control behavior. Run the repository-defined lint, typecheck, test, production-build, and browser verification commands before merge. Cover both a reasoning-capable gateway and the read-only Graph route.
Source: Coding guidelines
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java (1)
4-47: LGTM!components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java (3)
66-103: LGTM!
265-289: LGTM!
291-305: LGTM!components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java (1)
80-83: LGTM!Also applies to: 109-110, 210-215, 645-650
apps/api/src/main/java/com/orgmemory/api/assistant/GraphRagRuntimeConfiguration.java (1)
68-93: LGTM!components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerCacheTests.java (1)
28-150: LGTM!apps/api/src/test/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModelTests.java (1)
1-90: LGTM!integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java (1)
22-43: 🎯 Functional CorrectnessNo fingerprint change needed for direct construction paths.
No current code constructs
SpringAiKeywordPlanningModeloutsideOrganizationAwareKeywordPlanningModel; the organization-aware path uses its separate route fingerprint, so this narrowerv1fingerprint is not the production cache key.components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java (1)
16-42: 🎯 Functional CorrectnessNo action needed. Existing
QueryAnswerModel.Requestcalls go through the 5-arg constructor outside direct Spring-Ai tests, and the organization-aware model is tested with a non-nullorganizationId.apps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareKeywordPlanningModel.java (1)
31-52: LGTM!Also applies to: 67-79
apps/api/src/main/java/com/orgmemory/api/assistant/OrganizationAwareQueryAnswerModel.java (1)
32-48: LGTM!evaluation/README.md (1)
57-83: LGTM!evaluation/fixtures/workload-routing-v1.json (1)
1-46: LGTM!evaluation/pyproject.toml (1)
19-19: LGTM!evaluation/src/orgmemory_eval/workload_routing_runner.py (1)
149-175: LGTM!Also applies to: 209-218
evaluation/tests/test_workload_routing_runner.py (1)
9-30: LGTM!core/src/main/java/com/orgmemory/core/ai/OpenAiReasoningEffort.java (1)
5-16: LGTM!core/src/test/java/com/orgmemory/core/ai/AiRouteTests.java (1)
11-29: LGTM!ARCHITECTURE.md (1)
363-372: LGTM!apps/worker/src/main/resources/application.yml (1)
76-88: LGTM!infrastructure/deployment/compose.production.yaml (1)
67-72: LGTM!infrastructure/deployment/production.env.example (1)
75-79: LGTM!integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelProvider.java (1)
34-56: LGTM!integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactory.java (1)
36-46: LGTM!core/src/main/java/com/orgmemory/core/ai/AiGatewayProfileView.java (1)
13-13: LGTM!core/src/main/java/com/orgmemory/core/ai/AiRoute.java (1)
3-10: LGTM!core/src/main/java/com/orgmemory/core/ai/AiGatewayConnection.java (1)
16-51: LGTM!core/src/main/java/com/orgmemory/core/ai/AiGatewayProfile.java (1)
36-38: LGTM!Also applies to: 69-69, 78-78, 91-96, 136-139
core/src/main/java/com/orgmemory/core/ai/AiRouteOverrideView.java (1)
12-39: LGTM!core/src/test/java/com/orgmemory/core/ai/AiGatewayAdministrationServiceTests.java (1)
16-16: LGTM!Also applies to: 45-46, 68-72, 270-313, 315-344, 346-382
apps/api/src/main/java/com/orgmemory/api/admin/AdminAiModelController.java (2)
500-527: LGTM!
11-11: LGTM!Also applies to: 156-156, 178-178, 299-299, 385-385, 402-402, 421-455
apps/api/src/main/resources/application.yml (1)
98-110: LGTM!apps/api/src/test/java/com/orgmemory/api/admin/PermissionsAdminIntegrationTests.java (1)
139-144: LGTM!.env.example (1)
10-14: LGTM!core/src/main/java/com/orgmemory/core/ai/AiRouteOverride.java (1)
29-32: LGTM!Also applies to: 47-89, 103-106
core/src/main/java/com/orgmemory/core/ai/AiRouteOverrideRepository.java (1)
21-24: LGTM!core/src/main/java/com/orgmemory/core/ai/AiGatewayAdministrationService.java (1)
69-133: LGTM!Also applies to: 135-158, 160-212, 234-340, 342-356, 397-423, 486-525, 616-636
integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayProperties.java (1)
28-34: LGTM!Also applies to: 36-75, 105-118
integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/AiGatewayRegistry.java (1)
89-96: LGTM!Also applies to: 116-124, 133-149
integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/SpringAiChatModelFactory.java (1)
21-44: LGTM!integrations/ai-model-gateways/src/main/java/com/orgmemory/integrations/ai/gateway/anthropic/AnthropicMessagesChatModelFactory.java (1)
30-51: LGTM!integrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/AiGatewayPropertiesTests.java (1)
96-119: LGTM!integrations/ai-model-gateways/src/test/java/com/orgmemory/integrations/ai/gateway/openai/OpenAiCompatibleChatModelFactoryTests.java (1)
1-45: LGTM!
Summary
Evaluation
gpt-5.6-luna/none: passed (12/12 valid, recall 0.875 equal to baseline, p95 1423.9 ms vs 2611.9 ms)gpt-5.6-luna/none: rejected (11/12 valid, p95 4124.2 ms vsgpt-5.4-mini3233.2 ms)gpt-5.4-mini; Answer remainsgpt-5.6-solVerification
./gradlew clean test --no-daemon --max-workers=1./gradlew :core:test --no-daemon --max-workers=1after merging current mainadmin-language-models.spec.tsSummary by CodeRabbit
New Features
Documentation
Tests