Skip to content

fix(chat): make streaming, citations, and ingestion deterministic#77

Merged
WilliamAGH merged 40 commits into
mainfrom
dev
Jul 13, 2026
Merged

fix(chat): make streaming, citations, and ingestion deterministic#77
WilliamAGH merged 40 commits into
mainfrom
dev

Conversation

@WilliamAGH

@WilliamAGH WilliamAGH commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

PR #77 makes stateful chat streaming single-execution, preserves citation evidence through reranking and redaction, and gives Java API ingestion one validated source catalog with truthful partial-fetch behavior. It also keeps CSRF protection stateless without breaking secure cookie deletion.

Changes

Streaming

  • Chat and guided POST streams no longer replay failed requests; completed user/assistant exchanges are stored atomically only after the answer finishes.
  • Provider fallback events have one canonical owner, and the UI shows the provider selected during fallback.
  • Non-abort SSE fetch and reader failures invoke the error callback exactly once and reject with the original failure; cancellations remain silent.
  • OpenAI SDK reads inherit the whole-request timeout so provider gateways remain the owner of first-output and inter-output deadlines.
  • Wrapped OkHttp whole-call timeouts are classified as provider failures rather than caller cancellations, preserving backoff, fallback, and retryability behavior.

Retrieval and citations

  • Candidate deduplication uses content identity before reranking, preserving distinct chunks from the same page while final citation pills remain deduplicated.
  • Guided PDF chunks are converted and page-anchored one-to-one before final URL deduplication, retaining distinct pages and collapsing duplicate chunks on the same page.
  • Distinct unmapped local files retain private raw identities for deduplication while every displayed URL and log value remains redacted.

Documentation ingestion

  • java-api-documentation-sources.manifest is the sole owner of complete Java API source rows for Java 21, 24, and 25.
  • Java and Bash parsers reject invalid headers, field counts, integers, booleans, blank or unsafe text, malformed HTTPS base URLs, unsafe mirror paths, duplicate releases, and duplicate mirror paths.
  • The shell boundary preserves all eight manifest fields and manifest order without reconstructing Java rows.
  • A manifest release selects the Java Javadoc seed strategy; URL text no longer controls behavior, so a canonical host change cannot silently switch fetch strategies.
  • rejectRegex and allowPartial reach both Java and generic fetch boundaries, and incomplete retained mirrors still block overall completion.
  • Java API ingestion selectors accept only the exact canonical manifest path; display names, generated IDs, release aliases, legacy quick aliases, and case variants are rejected.

Security and frontend contracts

  • Cookie-backed CSRF validation remains stateless, uses SameSite=Lax, rejects missing or mismatched token pairs, and emits a secure immediate-deletion cookie on HTTPS logout.
  • SSE contract tests cover GET failures, non-OK and missing-body responses, server error events, provider status payloads, and exact error identity through chat and guided wrappers.

Breaking Changes

  • Java API ingestion selectors must use exact manifest paths such as java/java25-complete; legacy shorthand, display-name, generated-ID, and case-insensitive aliases are removed.
  • Automatic browser replay of failed stateful streams is removed; users explicitly resubmit.
  • OPENAI_STREAMING_READ_TIMEOUT_SECONDS is no longer read; the SDK read timeout inherits OPENAI_STREAMING_REQUEST_TIMEOUT_SECONDS.
  • The internal shell fetch projection is now the complete eight-field manifest row; the legacy seven-field projection is rejected.
  • HTTP endpoints and SSE event names remain compatible.

Verification

  • Pre-push lint, frontend production build, JVM production build, and all 352 backend tests passed.
  • Frontend lint, type checks, production build, and all 98 tests passed.
  • Focused provider-timeout, citation, manifest, selector, and CSRF suites passed (31 tests).
  • Shell syntax, ShellCheck, unsafe-row rejection, host-independent dispatch, eight-field fetch parity, and partial-mirror tests passed.
  • All review threads are resolved.

Related Issues

None.

Make the resource manifest the sole owner of complete Java API mirror records.
Project it into Java and Bash consumers, reject malformed or incomplete
catalogs, and document the ownership rules for future agents.
Deduplicate candidates by the strongest available identity so reranking keeps
distinct chunks from one page. Collapse final citations by canonical source URL.
Persist completed exchanges atomically and emit provider fallback state from one canonical notice stream. Remove client-side POST replay so failed stateful requests cannot duplicate chat or lesson work.
Use Java-compatible identifier continuation categories when detecting language keywords. Cover characters accepted by Unicode identifier rules but rejected by Java, plus Java-specific dollar and control characters.
Give lesson navigation and title presentation a focused component while preserving the canonical learning state in LearnView. Cover the back-to-lessons interaction through the rendered view.
Record the user and assistant turns only after chat or guided streaming completes. This keeps the controller call sites aligned with the atomic memory API and leaves failed streams out of session history.
Oracle Javadoc mirrors can legitimately land below their expected HTML
minimum on an interrupted or throttled fetch, yet the fixed threshold
treated any short mirror as a hard failure and quarantined the partial
result, discarding work that incremental reruns could resume.

Thread the manifest's seventh projection field (ALLOW_PARTIAL) through
fetch_docs and its Oracle/generic helpers so sources flagged partial keep
a validated short mirror with a warning instead of failing, and skip the
pre-fetch quarantine that would erase it. Extract fetch_documentation_source
to project one seven-field row into the fetch boundary and guard the script
so it can be sourced by tests without executing.

- Add partial_mirror_allowed parameter to validate_fetch_result,
  fetch_oracle_javadoc_seed, fetch_docs_mirror, and fetch_docs
- Add fetch_documentation_source to parse and dispatch a seven-field row
- Add scripts/test_java_api_fetch_projection.sh asserting manifest rows
  retain seven distinct fetch fields in order
The projection parity test proved the seventh field survived manifest
projection but never exercised what the flag does, leaving the
partial-mirror branch of validate_fetch_result and the pre-fetch
quarantine guard in fetch_docs without behavioral coverage.

Drive both policies directly: assert allowPartial=true keeps a validated
below-minimum mirror while allowPartial=false rejects it, and that
fetch_docs quarantines an incomplete mirror only when partial mirrors are
disallowed. Use a mktemp docs root with an EXIT trap so the test leaves no
artifacts behind.

- Add validate_fetch_result true/false assertions for below-minimum counts
- Add fetch_docs quarantine assertions gated on the partial-mirror policy
- Replace the hardcoded docs root with a self-cleaning mktemp directory
Copilot AI review requested due to automatic review settings July 13, 2026 19:30
@WilliamAGH WilliamAGH added bug Something isn't working enhancement New feature or request java Pull requests that update java code javascript Pull requests that update javascript code labels Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a reusable guided-lesson header with responsive “All Lessons” navigation.
    • Added canonical Java API source cataloging and a CLI option to list available Java API sources.
    • Improved documentation filtering using catalog paths.
  • Bug Fixes

    • Streaming failures are now reported without replaying requests or duplicating responses.
    • Provider fallback status is displayed more reliably.
    • Improved citation deduplication and Java keyword detection for Unicode text.
    • CSRF failures now return consistent JSON responses.
  • Documentation

    • Updated ingestion, pipeline, configuration, and architecture guidance.

Walkthrough

This change centralizes Java API documentation sources, revises streaming retries and persistence, adds a reusable lesson header, improves SSE and citation handling, updates CSRF and timeout behavior, and expands Java keyword detection coverage.

Changes

Java API source catalog

Layer / File(s) Summary
Catalog ownership and documentation
AGENTS.md, docs/..., src/main/resources/java-api-documentation-sources.manifest
Documents manifest ownership and updates ingestion commands.
Manifest-driven fetch projections
scripts/fetch_all_docs.sh, scripts/lib/...
Validates manifest rows, lists projections, handles partial mirrors, and writes metadata.
Java manifest parsing and registry integration
src/main/java/.../config/*, src/main/java/.../cli/DocumentationSetCatalog.java
Parses manifest records and derives URL mappings and documentation sets.
Documentation-set selection and parity validation
src/main/java/.../cli/*, src/test/java/...
Uses canonical selectors and verifies Java, shell, catalog, and manifest projections remain aligned.

Streaming and conversation flow

Layer / File(s) Summary
Streaming contracts and failure classification
src/main/java/.../service/*, src/test/java/...
Removes provider-change fields, adjusts timeout ownership, and classifies recoverable failures.
Atomic conversation persistence
ChatMemoryService.java, ChatController.java, GuidedLearningController.java
Persists complete exchanges after stream completion.
Ordered SSE and direct client delivery
SseSupport.java, frontend/src/lib/services/{chat,guided,sse}.*
Orders notice events, reports transport failures, and removes client replay behavior.

Frontend lesson and language behavior

Layer / File(s) Summary
Guided lesson header
frontend/src/lib/components/GuidedLessonHeader.svelte, LearnView.*
Extracts the lesson title and return control into a typed component.
Provider status display
frontend/src/lib/composables/..., ChatView.test.ts
Displays structured fallback provider details.
Java keyword boundary detection
frontend/src/lib/services/{javaLanguageDetection,markdown.test}.ts
Expands Unicode identifier handling and boundary coverage.

Retrieval, citation, security, and configuration

Layer / File(s) Summary
Document and citation deduplication
RetrievalService.java, GuidedLearningService.java, related tests
Deduplicates by content hash, canonical URL, and anchored citation URL.
Stateless CSRF handling
SecurityConfig.java, CsrfAccessDeniedHandler.java, related tests
Uses cookie-based CSRF tokens and uniform invalid-CSRF responses.
Timeout and architecture documentation
docs/configuration.md, application*.properties, architecture docs
Documents request-timeout ownership and atomic exchange persistence.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ChatController
  participant OpenAIStreamingService
  participant SseSupport
  participant ChatMemoryService
  Client->>ChatController: Start streaming request
  ChatController->>OpenAIStreamingService: streamResponse(...)
  OpenAIStreamingService-->>SseSupport: Streaming notices and text chunks
  SseSupport-->>Client: Ordered provider/status SSE events
  OpenAIStreamingService-->>ChatController: Stream completion
  ChatController->>ChatMemoryService: addExchange(sessionId, userQuery, fullResponse)
Loading

Possibly related PRs

Suggested labels: refactor, documentation

Poem

Catalogs align, streams softly flow,
Exchanges land where records grow.
Lessons wear a header bright,
Citations shed duplicate light.
Unicode keywords dance in flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main themes: streaming, citations, and ingestion determinism.
Description check ✅ Passed The description is directly related to the changeset and covers the main streaming, citation, ingestion, and security updates.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

Replace the session-coupled CSRF repository with Spring Security's cookie repository so valid cookie/header tokens survive stateless requests. Keep the browser-visible token lifetime and consistent JSON denial response on the verified framework boundary.

- Configure SameSite and max-age through the cookie customizer
- Remove server-session token metadata and expiry branching
- Cover stateless success and missing-token failure through MockMvc
@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation refactor Code refactoring labels Jul 13, 2026

Copilot AI 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.

Pull request overview

This PR tightens end-to-end streaming correctness (single execution per stateful request, accurate provider fallback signaling, and atomic conversation persistence), improves retrieval behavior for same-page evidence chunks, and centralizes complete Java API documentation sources into a canonical manifest consumed by Java + shell + CLI.

Changes:

  • Emit fallback-provider SSE events from a single notice stream (provider event precedes fallback status/text) and record chat history only after successful stream completion.
  • Preserve distinct same-page retrieval chunks for reranking while deduplicating citation pills by canonical (fragmentless) source URL.
  • Add a canonical java-api-documentation-sources.manifest and project it consistently into citation normalization, CLI doc sets, and doc-fetch scripts (plus parity/validation tests).

Reviewed changes

Copilot reviewed 49 out of 49 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/main/java/com/williamcallahan/javachat/web/SseSupport.java Emits ordered provider/status SSE sequences from runtime streaming notices.
src/main/java/com/williamcallahan/javachat/web/GuidedLearningController.java Avoids pre-stream history mutation; commits completed exchanges only.
src/main/java/com/williamcallahan/javachat/web/ChatController.java Avoids pre-stream history mutation; commits completed exchanges only.
src/main/java/com/williamcallahan/javachat/service/StreamingResult.java Simplifies streaming result contract to provider + text + notices.
src/main/java/com/williamcallahan/javachat/service/StreamingAttemptContext.java Removes provider-change sink plumbing from attempt context.
src/main/java/com/williamcallahan/javachat/service/OpenAIStreamingService.java Publishes replayable fallback notices without separate provider-change stream.
src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java Refines retryability rules for streaming failures (auth/rate-limit/not-found no longer retryable).
src/main/java/com/williamcallahan/javachat/service/ChatMemoryService.java Adds atomic addExchange to keep user/assistant turns aligned.
src/main/java/com/williamcallahan/javachat/service/RetrievalService.java Dedupes candidates by content hash then canonical URL; dedupes citations by fragmentless URL.
src/main/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifest.java Loads and validates the canonical Java API source manifest.
src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java Projects Java API sources from the manifest; keeps non-Java sources in properties.
src/main/java/com/williamcallahan/javachat/cli/DocumentationSetCatalog.java Builds CLI base doc sets by projecting manifest-driven Java API sources.
src/main/resources/java-api-documentation-sources.manifest Canonical inventory of complete Java API mirrors (21/24/25).
src/main/resources/docs-sources.properties Removes Java API base entries; keeps only non-complete-mirror sources.
scripts/lib/documentation_sources.sh Parses/validates manifest for shell and provides projection helpers.
scripts/fetch_all_docs.sh Adds manifest-driven Java API listing and fetch integration; improves failure reporting.
frontend/src/lib/services/streamRecovery.ts Removes client-side automatic stream retry/replay logic.
frontend/src/lib/services/streamRecovery.test.ts Removes tests for the deleted retry/replay behavior.
frontend/src/lib/services/chat.ts Uses single-pass streamSse (no POST replay) for chat streaming.
frontend/src/lib/services/chat.test.ts Updates expectations to “no replay” behavior on stream failures.
frontend/src/lib/services/guided.ts Uses single-pass streamSse (no POST replay) for guided streaming.
frontend/src/lib/services/guided.test.ts Updates expectations to “no replay” behavior on guided stream failures.
frontend/src/lib/composables/createStreamingState.svelte.ts Includes active provider in visible stream status details.
frontend/src/lib/services/javaLanguageDetection.ts Updates Java identifier-part detection to better match Java keyword boundaries.
frontend/src/lib/services/markdown.test.ts Extends keyword-boundary tests (Unicode + $ + control chars).
frontend/src/lib/components/LearnView.svelte Extracts lesson header UI into a focused component.
frontend/src/lib/components/GuidedLessonHeader.svelte New component for lesson header navigation/title with accessibility label.
frontend/src/lib/components/LearnView.test.ts Adds coverage for returning to lesson list via the header button.
frontend/src/lib/components/ChatView.test.ts Adds coverage for displaying the active fallback provider in status UI.
src/test/java/com/williamcallahan/javachat/web/StreamingProviderFallbackSseEventTest.java Verifies fallback provider/status ordering and single subscription to replayed notice stream.
src/test/java/com/williamcallahan/javachat/web/GuidedSseCitationEventTest.java Updates test construction for new StreamingResult signature.
src/test/java/com/williamcallahan/javachat/web/GuidedLearningControllerStreamingFailureTest.java Updates test construction for new StreamingResult signature.
src/test/java/com/williamcallahan/javachat/web/ChatControllerStreamingFailureTest.java Updates test construction for new StreamingResult signature.
src/test/java/com/williamcallahan/javachat/web/ChatControllerSessionValidationTest.java Updates session seeding to use addExchange.
src/test/java/com/williamcallahan/javachat/service/ChatMemoryServiceTest.java Refactors tests to validate exchange-based persistence semantics.
src/test/java/com/williamcallahan/javachat/service/StreamingAttemptContextTest.java Updates tests for removed provider-change sink argument.
src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java Expands recoverability tests and updates provider naming to enum names.
src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java Adds regression test for same-page chunk preservation and citation deduping.
src/test/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizerTest.java Uses manifest-driven Java API base URL instead of hardcoded release URL.
src/test/java/com/williamcallahan/javachat/StandaloneExtractionTest.java Projects Java API extraction sources from the manifest instead of hardcoding releases.
src/test/java/com/williamcallahan/javachat/ExtractorQualityTest.java Projects Java API extraction sources from the manifest instead of hardcoding releases.
src/test/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifestTest.java Cross-validates manifest grammar enforcement in Java and bash.
src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java Ensures local-mirror → remote-base mapping is complete and unique per release/path.
src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java Enforces parity across manifest, CLI catalog projection, and fetch script listing.
docs/pipeline-commands.md Documents canonical Java API manifest ownership and listing command usage.
docs/ingestion.md Updates ingestion guidance to use canonical manifest listing for doc-set paths.
docs/domains/all-parsing-and-markdown-logic.md Updates referenced persistence method name to addExchange.
docs/contracts/code-change.md Adds explicit governed-catalog “single semantic owner” guidance.
AGENTS.md Adds explicit Java API catalog ownership/projection rules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/lib/documentation_sources.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a97a5e398a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/fetch_all_docs.sh Outdated
The projection test exercised the generic mirror path but left the Oracle
Javadoc branch unverified, so a regression that dropped the partial-mirror
policy while dispatching Oracle seeds or validating their fetch result
would have gone unnoticed.

Assert that fetch_docs forwards the partial-mirror policy to
fetch_oracle_javadoc_seed, and that fetch_oracle_javadoc_seed in turn hands
it to validate_fetch_result, by stubbing each boundary and capturing the
propagated flag.

- Capture the policy forwarded into fetch_oracle_javadoc_seed via fetch_docs
- Capture the policy fetch_oracle_javadoc_seed forwards to validate_fetch_result

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java (1)

234-235: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Optional: extract a createStreamingService(RateLimitService) overload to cut setup duplication.

The new OpenAiProviderRoutingService(rateLimitService, 600, ApiProvider.GITHUB_MODELS.getName()) + new OpenAIStreamingService(...) pairing repeats verbatim across four tests, only because each needs a custom pre-stubbed RateLimitService mock. An overload taking the mock as a parameter would remove the copy-paste without losing flexibility.

♻️ Suggested helper
+    private OpenAIStreamingService createStreamingService(RateLimitService rateLimitService) {
+        OpenAiRequestFactory requestFactory =
+                new OpenAiRequestFactory(new Chunker(), new PromptTruncator(), "gpt-5.2", "gpt-5", "");
+        OpenAiProviderRoutingService providerRoutingService = new OpenAiProviderRoutingService(
+                rateLimitService, 600, RateLimitService.ApiProvider.GITHUB_MODELS.getName());
+        return new OpenAIStreamingService(
+                rateLimitService, requestFactory, providerRoutingService, new OpenAiStreamingFailureReporter());
+    }

Also applies to: 284-285, 331-332, 389-390

🤖 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
`@src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java`
around lines 234 - 235, Optionally add a
createStreamingService(RateLimitService) test helper overload in
OpenAIStreamingServiceTest that constructs OpenAiProviderRoutingService with the
supplied mock, the existing 600 limit, and GITHUB_MODELS, then creates the
streaming service. Replace the repeated provider-routing and
OpenAIStreamingService setup at the referenced test locations with this helper
while preserving each test’s custom mock configuration.
src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java (1)

176-209: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid recoverability tree, but its message-matching tail duplicates isStreamingFallbackEligible.

The classification logic itself (auth/rate-limit/not-found → non-recoverable, IO/SSE/overflow → recoverable, status-code bucket, message-substring fallback) is well justified and matches the new test coverage (recoverableStreamingFailureTreatsNotFoundAsNonRetryable, recoverableStreamingFailureRejectsAuthenticationAuthorizationAndRateLimitFailures). However, the final 7-line message-substring block (Lines 201-208) is byte-for-byte identical to the tail of isStreamingFallbackEligible (Lines 161-167). Two independently-maintained copies of the same substring list will drift the next time one is updated but not the other.

♻️ Extract the shared substring check into one helper
-        String exceptionMessage = throwable.getMessage();
-        if (exceptionMessage == null) {
-            return false;
-        }
-        String normalizedMessage = AsciiTextNormalizer.toLowerAscii(exceptionMessage);
-        return normalizedMessage.contains("invalid stream")
-                || normalizedMessage.contains("malformed")
-                || normalizedMessage.contains("unexpected end of json input")
-                || normalizedMessage.contains("timeout")
-                || normalizedMessage.contains("temporarily unavailable")
-                || normalizedMessage.contains("connection reset")
-                || normalizedMessage.contains("connection closed");
+        return matchesTransientStreamingMessage(throwable.getMessage());
     }

+    private boolean matchesTransientStreamingMessage(String exceptionMessage) {
+        if (exceptionMessage == null) {
+            return false;
+        }
+        String normalizedMessage = AsciiTextNormalizer.toLowerAscii(exceptionMessage);
+        return normalizedMessage.contains("invalid stream")
+                || normalizedMessage.contains("malformed")
+                || normalizedMessage.contains("unexpected end of json input")
+                || normalizedMessage.contains("timeout")
+                || normalizedMessage.contains("temporarily unavailable")
+                || normalizedMessage.contains("connection reset")
+                || normalizedMessage.contains("connection closed");
+    }

Apply the same replacement to the tail of isStreamingFallbackEligible (Lines 161-167).

As per coding guidelines, **/*.{java,kt} requires applying "Clean Code, DDD, DRY, YAGNI, KISS, and Clean Architecture."

🤖 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
`@src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java`
around lines 176 - 209, Extract the duplicated normalized-message substring
matching from isStreamingFallbackEligible and isRecoverableStreamingFailure into
one private helper, reusing the existing AsciiTextNormalizer logic and
recognized phrases. Replace both method tails with calls to that helper while
preserving their current classification behavior.

Source: Coding guidelines

frontend/src/lib/services/guided.test.ts (1)

94-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing assertion for the newly added onError call.

Line 102 adds callbacks.onError?.({ message: "Provider stream unavailable" }) to the mock, but the test only asserts on onStatus (lines 120-126). The sibling test in chat.test.ts (forwarding non-retryable status) does assert onError's payload — this test should do the same so a regression in onError forwarding for the guided-chat path is caught.

✅ Suggested assertion addition
     expect(streamSseMock).toHaveBeenCalledTimes(1);
     expect(onStatus).toHaveBeenCalledWith(
       expect.objectContaining({
         code: "stream.provider.fatal-error",
         retryable: false,
       }),
     );
+    expect(onError).toHaveBeenCalledWith({ message: "Provider stream unavailable" });
   });
🤖 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 `@frontend/src/lib/services/guided.test.ts` around lines 94 - 127, Add an
assertion in the guided-chat test for the onError mock, verifying it receives
the provider stream failure message after streamGuidedChat rejects. Keep the
existing retry-count and onStatus assertions unchanged.
scripts/fetch_all_docs.sh (1)

370-377: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

--list-java-api-sources output format doesn't match the docs' "copy relativeMirrorPath" instruction. The script prints full raw manifest rows; the docs assume users can lift a bare path from that output.

  • scripts/fetch_all_docs.sh#L370-L377: change the listing loop to print just relativeMirrorPath per line (see diff in the per-file comment above), or otherwise make the printed format match what DOCS_SETS expects.
  • docs/pipeline-commands.md#L123-L134: once the script prints bare paths, this instruction becomes accurate as-is; until then, add a cut -d'|' -f3 step to show users how to extract the path from a raw row.
🤖 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 `@scripts/fetch_all_docs.sh` around lines 370 - 377, Update the
--list-java-api-sources listing loop in scripts/fetch_all_docs.sh to print only
each source’s relativeMirrorPath, matching the paths expected by DOCS_SETS. No
direct change is needed in docs/pipeline-commands.md lines 123-134 because the
documentation becomes accurate once the script emits bare paths.
🤖 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 `@scripts/lib/documentation_sources.sh`:
- Around line 162-177: Update append_java_api_fetch_sources to emit DOC_SOURCES
entries with exactly six fields, matching fetch_all_docs.sh’s expected url,
target directory, name, cut directories, minimum files, and reject regex
structure. Remove the allowPartial value from the DOC_SOURCES append while
leaving the projection parsing unchanged.

In `@src/main/java/com/williamcallahan/javachat/service/RetrievalService.java`:
- Around line 187-223: Update deduplicateByContentHashThenHashlessCanonicalUrl
so hashless file:// document URLs always use
DocsSourceRegistry.normalizeDocUrl(documentUrl) as the deduplication key,
removing the separate resolveLocalPath/canonicalizeHttpDocUrl fallback path.
Preserve the existing handling for non-file URLs, blank URLs, and content-hashed
documents.

---

Nitpick comments:
In `@frontend/src/lib/services/guided.test.ts`:
- Around line 94-127: Add an assertion in the guided-chat test for the onError
mock, verifying it receives the provider stream failure message after
streamGuidedChat rejects. Keep the existing retry-count and onStatus assertions
unchanged.

In `@scripts/fetch_all_docs.sh`:
- Around line 370-377: Update the --list-java-api-sources listing loop in
scripts/fetch_all_docs.sh to print only each source’s relativeMirrorPath,
matching the paths expected by DOCS_SETS. No direct change is needed in
docs/pipeline-commands.md lines 123-134 because the documentation becomes
accurate once the script emits bare paths.

In
`@src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java`:
- Around line 176-209: Extract the duplicated normalized-message substring
matching from isStreamingFallbackEligible and isRecoverableStreamingFailure into
one private helper, reusing the existing AsciiTextNormalizer logic and
recognized phrases. Replace both method tails with calls to that helper while
preserving their current classification behavior.

In
`@src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java`:
- Around line 234-235: Optionally add a createStreamingService(RateLimitService)
test helper overload in OpenAIStreamingServiceTest that constructs
OpenAiProviderRoutingService with the supplied mock, the existing 600 limit, and
GITHUB_MODELS, then creates the streaming service. Replace the repeated
provider-routing and OpenAIStreamingService setup at the referenced test
locations with this helper while preserving each test’s custom mock
configuration.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 794201be-3214-4a74-8b70-836544d73486

📥 Commits

Reviewing files that changed from the base of the PR and between 17a5051 and a97a5e3.

📒 Files selected for processing (49)
  • AGENTS.md
  • docs/contracts/code-change.md
  • docs/domains/all-parsing-and-markdown-logic.md
  • docs/ingestion.md
  • docs/pipeline-commands.md
  • frontend/src/lib/components/ChatView.test.ts
  • frontend/src/lib/components/GuidedLessonHeader.svelte
  • frontend/src/lib/components/LearnView.svelte
  • frontend/src/lib/components/LearnView.test.ts
  • frontend/src/lib/composables/createStreamingState.svelte.ts
  • frontend/src/lib/services/chat.test.ts
  • frontend/src/lib/services/chat.ts
  • frontend/src/lib/services/guided.test.ts
  • frontend/src/lib/services/guided.ts
  • frontend/src/lib/services/javaLanguageDetection.ts
  • frontend/src/lib/services/markdown.test.ts
  • frontend/src/lib/services/streamRecovery.test.ts
  • frontend/src/lib/services/streamRecovery.ts
  • scripts/fetch_all_docs.sh
  • scripts/lib/documentation_sources.sh
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSetCatalog.java
  • src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java
  • src/main/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifest.java
  • src/main/java/com/williamcallahan/javachat/service/ChatMemoryService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAIStreamingService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalService.java
  • src/main/java/com/williamcallahan/javachat/service/StreamingAttemptContext.java
  • src/main/java/com/williamcallahan/javachat/service/StreamingResult.java
  • src/main/java/com/williamcallahan/javachat/web/ChatController.java
  • src/main/java/com/williamcallahan/javachat/web/GuidedLearningController.java
  • src/main/java/com/williamcallahan/javachat/web/SseSupport.java
  • src/main/resources/docs-sources.properties
  • src/main/resources/java-api-documentation-sources.manifest
  • src/test/java/com/williamcallahan/javachat/ExtractorQualityTest.java
  • src/test/java/com/williamcallahan/javachat/StandaloneExtractionTest.java
  • src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java
  • src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java
  • src/test/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifestTest.java
  • src/test/java/com/williamcallahan/javachat/service/ChatMemoryServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/StreamingAttemptContextTest.java
  • src/test/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizerTest.java
  • src/test/java/com/williamcallahan/javachat/web/ChatControllerSessionValidationTest.java
  • src/test/java/com/williamcallahan/javachat/web/ChatControllerStreamingFailureTest.java
  • src/test/java/com/williamcallahan/javachat/web/GuidedLearningControllerStreamingFailureTest.java
  • src/test/java/com/williamcallahan/javachat/web/GuidedSseCitationEventTest.java
  • src/test/java/com/williamcallahan/javachat/web/StreamingProviderFallbackSseEventTest.java
💤 Files with no reviewable changes (2)
  • frontend/src/lib/services/streamRecovery.ts
  • frontend/src/lib/services/streamRecovery.test.ts

Comment thread scripts/lib/documentation_sources.sh
Preserve nonempty partial mirrors for incremental retries without reporting
them as completed fetches. Track partial sources separately and fail the
fetch command before Qdrant ingestion until every configured minimum is
satisfied.

Extract metadata emission from the fetch orchestrator so the touched script
retains one orchestration responsibility, and document the resulting
pipeline contract.
Remove the redundant SDK read deadline so provider gateways remain the sole owner of first-output and inter-output timing while the whole request keeps its configured bound.
Use the framework's stateless session-cookie lifetime so logout can emit an immediate deletion cookie, and cover mismatched and single-sided token rejection.
Preserve document-to-citation alignment through PDF page estimation, then collapse only citations that resolve to the same final page anchor.
Invoke the canonical error callback exactly once for non-abort fetch and reader failures while preserving rejection identity and silent cancellation.
Keep every selectable Java documentation set manifest-backed and reject legacy quick tokens that no longer have fetch or citation mappings.
Prove that unresolved file URLs retain their raw identity because normalizing them to the shared redacted sentinel would collapse unrelated documents.
Move routing and failure-classification tests into their focused owner so the streaming service suite remains below the repository monolith threshold.
@WilliamAGH WilliamAGH changed the title fix(chat): no duplicate stream replay, complete same-page retrieval, and Java 21 API ingestion fix(chat): make streaming, citations, and ingestion deterministic Jul 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/test/java/com/williamcallahan/javachat/service/GuidedLearningServiceCitationTest.java (1)

45-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Nice coverage of the happy path — consider also covering the partial-failure path.

This test nails the core regression scenario (distinct-page chunks preserved, same-page chunks collapsed). One gap: nothing exercises buildPageAnchoredCitations when one document's conversion throws inside retrievalService.toCitations — worth a companion test asserting that a failing document is skipped from pairing (no size-mismatch to enhanceWithPageAnchors) while the remaining citations still get anchored correctly.

🤖 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
`@src/test/java/com/williamcallahan/javachat/service/GuidedLearningServiceCitationTest.java`
around lines 45 - 75, Add a companion test for
GuidedLearningService.citationsForBookDocuments that makes
retrievalService.toCitations throw for one document while returning citations
for another. Assert the failing document is skipped, enhanceWithPageAnchors
receives only the remaining citations without a size mismatch, and the
successful citation retains its expected page URL and anchor.
src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java (1)

38-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reference CSRF_INVALID_MESSAGE from its canonical owner instead of duplicating.

The message string is duplicated verbatim from CsrfAccessDeniedHandler.CSRF_INVALID_MESSAGE (private). If the handler's message changes, this test constant will silently drift. Per coding guidelines, tests must bind governed concepts from their canonical owner without duplicated inventories. Consider making the handler's constant public so the test can import it directly.

♻️ Proposed refactor

In CsrfAccessDeniedHandler.java:

-    private static final String CSRF_INVALID_MESSAGE =
+    public static final String CSRF_INVALID_MESSAGE =
             "CSRF token missing or invalid. Refresh the page and retry the request.";

In SecurityConfigTest.java:

+import com.williamcallahan.javachat.adapters.in.web.security.CsrfAccessDeniedHandler;
+
     private static final String CSRF_COOKIE_SAME_SITE_POLICY = "Lax";
-    private static final String CSRF_INVALID_MESSAGE =
-            "CSRF token missing or invalid. Refresh the page and retry the request.";
+    private static final String CSRF_INVALID_MESSAGE = CsrfAccessDeniedHandler.CSRF_INVALID_MESSAGE;
🤖 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 `@src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java`
around lines 38 - 39, Remove the duplicated CSRF_INVALID_MESSAGE from
SecurityConfigTest and expose the existing constant from CsrfAccessDeniedHandler
with appropriate public visibility. Update the test to reference
CsrfAccessDeniedHandler.CSRF_INVALID_MESSAGE directly, preserving the canonical
message value and avoiding a second inventory.

Source: Coding guidelines

scripts/lib/documentation_fetch_metadata.sh (1)

20-67: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Reuse count_html_files instead of duplicating the find/wc/tr pattern six times.

Lines 62-67 hand-roll find <dir> -name "*.html" 2>/dev/null | wc -l | tr -d ' ' for each Spring source, duplicating logic that already exists as count_html_files (used throughout fetch_all_docs.sh, e.g. in validate_fetch_result). Reusing it keeps the counting logic in one place and guarantees these reported numbers stay consistent with whatever counting rules count_html_files applies (including any future exclusions).

Separately, the aggregate total_html_files/total_files (Lines 22, 24) scan the full $DOCS_ROOT tree, which also sweeps up anything currently sitting in $DOCS_ROOT/.quarantine (populated by quarantine_incomplete_dir/quarantine_path). Since quarantine snapshots accumulate across runs, these totals can silently drift away from the actual "live" documentation corpus size over time.

♻️ Example fix for the duplicated counts
-    "spring_boot_complete": "$(find "$DOCS_ROOT/spring-boot-complete" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')",
-    "spring_framework_complete": "$(find "$DOCS_ROOT/spring-framework-complete" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')",
-    "spring_ai_reference_stable": "$(find "$DOCS_ROOT/spring-ai-reference" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')",
-    "spring_ai_reference_2": "$(find "$DOCS_ROOT/spring-ai-reference-2" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')",
-    "spring_ai_api_stable": "$(find "$DOCS_ROOT/spring-ai-api-stable" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')",
-    "spring_ai_api_2": "$(find "$DOCS_ROOT/spring-ai-api-2" -name "*.html" 2>/dev/null | wc -l | tr -d ' ')"
+    "spring_boot_complete": "$(count_html_files "$DOCS_ROOT/spring-boot-complete")",
+    "spring_framework_complete": "$(count_html_files "$DOCS_ROOT/spring-framework-complete")",
+    "spring_ai_reference_stable": "$(count_html_files "$DOCS_ROOT/spring-ai-reference")",
+    "spring_ai_reference_2": "$(count_html_files "$DOCS_ROOT/spring-ai-reference-2")",
+    "spring_ai_api_stable": "$(count_html_files "$DOCS_ROOT/spring-ai-api-stable")",
+    "spring_ai_api_2": "$(count_html_files "$DOCS_ROOT/spring-ai-api-2")"
🤖 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 `@scripts/lib/documentation_fetch_metadata.sh` around lines 20 - 67, Update
write_documentation_fetch_metadata to use count_html_files for each Spring
directory count instead of repeating find/wc/tr pipelines. Also adjust
total_html_files and total_files calculations so DOCS_ROOT/.quarantine and its
contents are excluded, keeping aggregate statistics limited to the live
documentation corpus.
🤖 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.

Nitpick comments:
In `@scripts/lib/documentation_fetch_metadata.sh`:
- Around line 20-67: Update write_documentation_fetch_metadata to use
count_html_files for each Spring directory count instead of repeating find/wc/tr
pipelines. Also adjust total_html_files and total_files calculations so
DOCS_ROOT/.quarantine and its contents are excluded, keeping aggregate
statistics limited to the live documentation corpus.

In `@src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java`:
- Around line 38-39: Remove the duplicated CSRF_INVALID_MESSAGE from
SecurityConfigTest and expose the existing constant from CsrfAccessDeniedHandler
with appropriate public visibility. Update the test to reference
CsrfAccessDeniedHandler.CSRF_INVALID_MESSAGE directly, preserving the canonical
message value and avoiding a second inventory.

In
`@src/test/java/com/williamcallahan/javachat/service/GuidedLearningServiceCitationTest.java`:
- Around line 45-75: Add a companion test for
GuidedLearningService.citationsForBookDocuments that makes
retrievalService.toCitations throw for one document while returning citations
for another. Assert the failing document is skipped, enhanceWithPageAnchors
receives only the remaining citations without a size mismatch, and the
successful citation retains its expected page URL and anchor.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 02948cc1-769b-4c70-bcde-eae1ec6cab56

📥 Commits

Reviewing files that changed from the base of the PR and between a97a5e3 and 3f4d567.

📒 Files selected for processing (22)
  • docs/configuration.md
  • docs/pipeline-commands.md
  • frontend/src/lib/services/sse.test.ts
  • frontend/src/lib/services/sse.ts
  • scripts/fetch_all_docs.sh
  • scripts/lib/documentation_fetch_metadata.sh
  • scripts/test_java_api_fetch_projection.sh
  • src/main/java/com/williamcallahan/javachat/adapters/in/web/security/CsrfAccessDeniedHandler.java
  • src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ExpiringCookieCsrfTokenRepository.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSetCatalog.java
  • src/main/java/com/williamcallahan/javachat/config/SecurityConfig.java
  • src/main/java/com/williamcallahan/javachat/service/GuidedLearningService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAIStreamingService.java
  • src/main/resources/application-dev.properties
  • src/main/resources/application.properties
  • src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java
  • src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java
  • src/test/java/com/williamcallahan/javachat/service/GuidedLearningServiceCitationTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingTimeoutContractTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
💤 Files with no reviewable changes (3)
  • src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ExpiringCookieCsrfTokenRepository.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAIStreamingService.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSetCatalog.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
  • docs/pipeline-commands.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java (1)

164-176: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract the duplicated transient-message heuristic.

The 7-line normalized-message substring check is now byte-for-byte duplicated between isStreamingFallbackEligible (Lines 169-175) and isRecoverableStreamingFailure (Lines 210-216). Since this diff switched isRecoverableStreamingFailure from delegating to isStreamingFallbackEligible into its own explicit copy, any future tweak to the pattern list (e.g. adding a new transient-error keyword) will need to be made in two places to stay in sync — a classic DRY trap for error-classification logic that both fallback selection and recoverability checks depend on.

As per coding guidelines, **/*.java: "Apply Clean Code, DDD, DRY, YAGNI, KISS, and Clean Architecture."

♻️ Proposed extraction
+    private static boolean isTransientStreamMessage(String normalizedMessage) {
+        return normalizedMessage.contains("invalid stream")
+                || normalizedMessage.contains("malformed")
+                || normalizedMessage.contains("unexpected end of json input")
+                || normalizedMessage.contains("timeout")
+                || normalizedMessage.contains("temporarily unavailable")
+                || normalizedMessage.contains("connection reset")
+                || normalizedMessage.contains("connection closed");
+    }

Then in both isStreamingFallbackEligible and isRecoverableStreamingFailure:

-        return normalizedMessage.contains("invalid stream")
-                || normalizedMessage.contains("malformed")
-                || normalizedMessage.contains("unexpected end of json input")
-                || normalizedMessage.contains("timeout")
-                || normalizedMessage.contains("temporarily unavailable")
-                || normalizedMessage.contains("connection reset")
-                || normalizedMessage.contains("connection closed");
+        return isTransientStreamMessage(normalizedMessage);

Also applies to: 199-217

🤖 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
`@src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java`
around lines 164 - 176, Extract the shared normalized-message substring
heuristic from isStreamingFallbackEligible and isRecoverableStreamingFailure
into one private helper, preserving the null handling and all existing keywords.
Update both methods to delegate to that helper so future transient-error pattern
changes are maintained in a single location.
🤖 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 `@scripts/lib/documentation_sources.sh`:
- Around line 33-79: Update is_absolute_https_remote_base_url and
is_normalized_relative_mirror_path to reject literal asterisk characters in
their inputs, alongside the existing whitespace/backslash validation. Ensure
both validators return failure before accepting values containing “*”,
preserving all existing URL and mirror-path checks.

---

Outside diff comments:
In
`@src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java`:
- Around line 164-176: Extract the shared normalized-message substring heuristic
from isStreamingFallbackEligible and isRecoverableStreamingFailure into one
private helper, preserving the null handling and all existing keywords. Update
both methods to delegate to that helper so future transient-error pattern
changes are maintained in a single location.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e8142bf6-c56e-46af-8547-44e155721246

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4d567 and c11049b.

📒 Files selected for processing (17)
  • frontend/src/lib/services/chat.test.ts
  • frontend/src/lib/services/guided.test.ts
  • frontend/src/lib/services/sse.test.ts
  • scripts/fetch_all_docs.sh
  • scripts/lib/documentation_sources.sh
  • scripts/test_java_api_fetch_projection.sh
  • src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSet.java
  • src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java
  • src/main/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifest.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalService.java
  • src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java
  • src/test/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifestTest.java
  • src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (8)
  • frontend/src/lib/services/guided.test.ts
  • frontend/src/lib/services/chat.test.ts
  • src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalService.java
  • src/test/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifestTest.java
  • src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java
  • scripts/fetch_all_docs.sh

Comment thread scripts/lib/documentation_sources.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request java Pull requests that update java code javascript Pull requests that update javascript code refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants