Skip to content

fix(chat): expanded sources stay visible and embedding warm-up probes keep cadence without pipeline logs#54

Merged
WilliamAGH merged 4 commits into
mainfrom
dev
Jun 10, 2026
Merged

fix(chat): expanded sources stay visible and embedding warm-up probes keep cadence without pipeline logs#54
WilliamAGH merged 4 commits into
mainfrom
dev

Conversation

@WilliamAGH

@WilliamAGH WilliamAGH commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Expanded citation source lists now scroll into view inside chat containers, so users can see sources immediately after opening them. Embedding keep-alive probes now start on a fixed cadence and use provider-specific warm-up paths that avoid RAG pipeline logging, reducing cold-start risk without making scheduled probes look like user retrieval work.

Changes

Bug Fixes

  • Source lists stay visible after expansion: Opening a collapsed source list now scrolls the citation list into the nearest scroll container instead of rendering it below the fold (CitationPanel.svelte).
  • Embedding warm-up probes keep their idle-prevention cadence: Scheduled probes now run at fixed-rate starts and use monotonic timing so a slow cold start does not push later probes past the provider idle window (EmbeddingModelKeepAlive.keepEmbeddingModelWarm).
  • Warm-up probes no longer look like user retrieval work in logs: Keep-alive requests call the warm-up port, and concrete providers issue the probe through private/provider request paths instead of the advised embed(List) method (EmbeddingClient.warmUp, LocalEmbeddingClient.warmUp, OpenAiCompatibleEmbeddingClient.warmUp).

Tests

  • Citation expansion behavior is covered in the frontend suite: Tests verify expansion, scroll reveal, and collapse behavior with a jsdom scrollIntoView polyfill (CitationPanel.test.ts, frontend/src/test/setup.ts).
  • Keep-alive logging regression is covered in the backend suite: The keep-alive test fails if scheduled warm-up calls embed(List) instead of the warm-up port (EmbeddingModelKeepAliveTest).

Breaking Changes

None

Related Issues

None

… pipeline logs

fixedRate replaces fixedDelay so a slow cold-start probe cannot push the
next probe past the provider's idle-unload TTL, and probe latency is
measured with the monotonic nanoTime clock. The probe now calls a
dedicated EmbeddingClient.warmUp() whose internal embed call is a
self-invocation outside the AOP proxy, so the RAG pipeline aspect's
'STEP 1: EMBEDDING GENERATION' logs stay scoped to real requests
instead of firing every 4 minutes.
…ontainers

The sources disclosure trigger sits at the very bottom of every scroll
container it appears in (chat messages, lesson content panel, mobile chat
drawer), and the citation list expands downward. Browsers never auto-scroll
to reveal newly inserted content below the fold, so the expanded list was
partially clipped on desktop and rendered entirely off-screen on mobile,
where tapping the trigger appeared to do nothing at all.

Reveal the list with scrollIntoView(block: 'nearest') once it mounts while
expanded, and give it scroll-margin-bottom clearance because the scroll
fires while the slide-down entry animation still holds the list 4px above
its settled position.

- Bind the expanded list element and scroll it into view from an $effect
- Add scroll-margin-bottom to out-clear the translateY(-4px) entry offset
- Cover expand, reveal-scroll, and collapse paths in CitationPanel tests
- Polyfill scrollIntoView in the jsdom test setup alongside scrollTo
Copilot AI review requested due to automatic review settings June 10, 2026 16:22
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 117569a9-57fb-4ae5-ba0b-9abecace395a

📥 Commits

Reviewing files that changed from the base of the PR and between f1c4610 and 6c3dd9d.

📒 Files selected for processing (9)
  • Dockerfile
  • build.gradle.kts
  • frontend/src/lib/components/Header.svelte
  • frontend/src/lib/components/Header.test.ts
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java
  • src/main/java/com/williamcallahan/javachat/service/LocalEmbeddingClient.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiCompatibleEmbeddingClient.java
  • src/main/resources/application.properties
  • src/test/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAliveTest.java
✅ Files skipped from review due to trivial changes (2)
  • src/main/resources/application.properties
  • frontend/src/lib/components/Header.svelte
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Citation list now scrolls into view when expanded within scrollable containers.
  • Accessibility

    • Header navigation tabs now include explicit accessibility labels for improved screen reader support.
  • Tests

    • Added test suites for CitationPanel component, including scroll behavior verification.
    • Added test coverage for Header component tab navigation.
  • Chores

    • Enhanced build metadata to include source commit information in deployment environment.

Walkthrough

Frontend: expanded citation lists now bind their UL and call scrollIntoView({ block: 'nearest' }) with a scroll-margin-bottom offset; tests and a jsdom polyfill added. Header tabs gained aria-labels and tests. Backend: added EmbeddingClient.warmUp(), refactored keep-alive to fixed-rate nano timing and updated clients/tests. Build: SOURCE_COMMIT flows into Gradle, Docker, and actuator info.

Changes

Citation Panel Scroll-Into-View

Layer / File(s) Summary
Citation panel scroll-into-view behavior
frontend/src/lib/components/CitationPanel.svelte
Binds the expanded citation list element and invokes scrollIntoView({ block: 'nearest' }) on expansion; adds scroll-margin-bottom CSS to offset slide-down animation.
Citation panel test suite and polyfill
frontend/src/lib/components/CitationPanel.test.ts, frontend/src/test/setup.ts
Adds Vitest suite asserting expand/collapse rendering, aria-expanded state, and scrollIntoView invocation; polyfills HTMLElement.prototype.scrollIntoView for jsdom.
Header ARIA attributes and tests
frontend/src/lib/components/Header.svelte, frontend/src/lib/components/Header.test.ts
Adds aria-label attributes to “Chat” and “Learn” tab buttons and tests their aria-selected states.

Embedding Keep-Alive Refactoring

Layer / File(s) Summary
EmbeddingClient warmUp() method and probe text
src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java
Adds EMBEDDING_WARM_UP_PROBE_TEXT and warmUp() contract documenting probe behavior and EmbeddingServiceUnavailableException failure mode.
Local/OpenAI client call-path changes
src/main/java/com/williamcallahan/javachat/service/LocalEmbeddingClient.java, src/main/java/com/williamcallahan/javachat/service/OpenAiCompatibleEmbeddingClient.java
LocalEmbeddingClient consolidates embedding fetch into fetchValidatedEmbeddings(...) used by both embed(...) and warmUp(); OpenAiCompatibleEmbeddingClient delegates null/empty embed inputs to createEmbeddings(texts) (remote flow).
Keep-alive scheduler, timing, and tests
src/main/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAlive.java, src/test/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAliveTest.java
Switches keep-alive to fixedRate, calls embeddingClient.warmUp(), measures durations with System.nanoTime() (adds NANOS_PER_MILLISECOND), updates tests to assert warmUp() usage and warm-up unavailability handling.

Build and Runtime Metadata

Layer / File(s) Summary
Gradle buildInfo and Docker propagation
build.gradle.kts, Dockerfile, src/main/resources/application.properties
Adds SOURCE_COMMIT provider in build.gradle.kts, passes SOURCE_COMMIT into Gradle from Docker build args, exposes SOURCE_COMMIT as runtime ENV, and exposes it via actuator info properties (info.deployment.commit).

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant KeepAlive as EmbeddingModelKeepAlive
  participant EmbeddingClient
  participant EmbeddingService
  Scheduler->>KeepAlive: scheduled fixed-rate probe
  KeepAlive->>EmbeddingClient: warmUp()
  EmbeddingClient->>EmbeddingService: provider embedding probe request
  EmbeddingService-->>EmbeddingClient: probe response / error
  EmbeddingClient-->>KeepAlive: success or EmbeddingServiceUnavailableException
  KeepAlive->>KeepAlive: measure duration via System.nanoTime()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • WilliamAGH/java-chat#52: Related embedding keep-alive changes touching EmbeddingModelKeepAlive and warm-up behavior.
  • WilliamAGH/java-chat#9: Related UI work where CitationPanel is used; touches citation layout/scrolling in lesson/chat flows.

Suggested labels

refactor

Poem

When citations slide down into view with care,
They nudge the viewport nearest and fair,
Warm-up probes whisper to models awake,
And builds remember the commit we make.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% 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 and concisely summarizes the two main fixes: citation panel scroll behavior and embedding warm-up probe improvements without pipeline logs.
Description check ✅ Passed The description is comprehensive and directly related to all changes in the PR, covering both frontend citation visibility fixes and backend embedding warm-up probe improvements with clear explanations of the problems and solutions.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":401,"request":{"method":"PATCH","url":"https://api.github.com/repos/WilliamAGH/java-chat/issues/comments/4672170696","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/WilliamAGH/java-chat/pull/54?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Organization UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `26d12430-56ff-4d64-aa44-ee81e950e558`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 3159c42a21b7e6f423a76efa21af963bf749aa20 and f1c461015d91643d7d8b9a864189202d281f8744.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (6)</summary>\n> \n> * `frontend/src/lib/components/CitationPanel.svelte`\n> * `frontend/src/lib/components/CitationPanel.test.ts`\n> * `frontend/src/test/setup.ts`\n> * `src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java`\n> * `src/main/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAlive.java`\n> * `src/test/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAliveTest.java`\n> \n> </details>\n> \n> ```ascii\n>  _______________________________________________________\n> < Once upon a dream, I found all the bugs in your code. >\n>  -------------------------------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `dev`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=WilliamAGH/java-chat&utm_content=54)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":1,"signal":{}}},"response":{"url":"https://api.github.com/repos/WilliamAGH/java-chat/issues/comments/4672170696","status":401,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","connection":"close","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Wed, 10 Jun 2026 16:23:37 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-media-type":"github.v3; format=json","x-github-request-id":"2B92:CB219:4FE28D2:12CFFCAA:6A298F88","x-xss-protection":"0"},"data":{"message":"Requires authentication","documentation_url":"https://docs.github.com/rest","status":"401"}}}

@coderabbitai coderabbitai Bot added enhancement New feature or request java Pull requests that update java code labels Jun 10, 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 improves chat UX and operational robustness by ensuring expanded citation lists remain visible within scroll containers and by making embedding keep-alive probes run on a fixed cadence while avoiding being logged as normal RAG pipeline embedding work.

Changes:

  • Frontend: Scroll expanded citation source lists into view and add a scrollIntoView jsdom polyfill plus component tests covering expand/scroll/collapse behavior.
  • Backend: Switch embedding keep-alive scheduling from fixedDelay to fixedRate, measure probe latency with monotonic time, and route keep-alive probes through a dedicated EmbeddingClient.warmUp() path.
  • Tests: Update/add tests to validate citation expansion behavior and ensure keep-alive probes still trigger embedding activity.

Reviewed changes

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

Show a summary per file
File Description
src/main/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAlive.java Moves keep-alive probes to fixed-rate scheduling, monotonic timing, and calls EmbeddingClient.warmUp().
src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java Adds a warmUp() method intended to issue minimal embedding probes without normal pipeline logging.
src/test/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAliveTest.java Adjusts test expectations/documentation around keep-alive probe behavior.
frontend/src/lib/components/CitationPanel.svelte Scrolls the expanded citation list into view and adds scroll margin for animation clearance.
frontend/src/lib/components/CitationPanel.test.ts Adds Vitest coverage for expand, scroll reveal, and collapse behavior.
frontend/src/test/setup.ts Adds jsdom scrollIntoView polyfill for component tests.

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

Comment thread src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java 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: f1c461015d

ℹ️ 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 src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java Outdated

@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 (1)
src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java (1)

41-54: 💤 Low value

Lovely documentation! The AOP proxy bypass rationale is crystal clear. 🎯

Your Javadoc beautifully explains why warmUp() exists as a separate method—the self-invocation detail shows deep understanding of Spring's proxy mechanics. This kind of "why" documentation is exactly what makes code maintainable long-term.

One tiny style note: the inline string "embedding model warm-up probe" at line 53 could technically be extracted to a constant per the "no inline strings" guideline. But since it's used once in a crystal-clear context, the practical value is minimal. Totally your call whether to make it:

String WARMUP_PROBE_TEXT = "embedding model warm-up probe";

Either way, this is clean, thoughtful code! The fixed-rate scheduling change in the other file pairs perfectly with this abstraction.

🤖 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/EmbeddingClient.java`
around lines 41 - 54, Extract the inline warm-up probe string used in
EmbeddingClient.warmUp() into a named constant (e.g., WARMUP_PROBE_TEXT) to
satisfy the "no inline strings" guideline; update warmUp() to call
embed(List.of(WARMUP_PROBE_TEXT)) and declare the constant near the interface
methods (static final or equivalent visibility for interfaces) so the string is
reusable and clearly identified.

Source: Coding guidelines

🤖 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 `@src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java`:
- Around line 41-54: Extract the inline warm-up probe string used in
EmbeddingClient.warmUp() into a named constant (e.g., WARMUP_PROBE_TEXT) to
satisfy the "no inline strings" guideline; update warmUp() to call
embed(List.of(WARMUP_PROBE_TEXT)) and declare the constant near the interface
methods (static final or equivalent visibility for interfaces) so the string is
reusable and clearly identified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 26d12430-56ff-4d64-aa44-ee81e950e558

📥 Commits

Reviewing files that changed from the base of the PR and between 3159c42 and f1c4610.

📒 Files selected for processing (6)
  • frontend/src/lib/components/CitationPanel.svelte
  • frontend/src/lib/components/CitationPanel.test.ts
  • frontend/src/test/setup.ts
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingClient.java
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAlive.java
  • src/test/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAliveTest.java

Mobile navigation collapsed to icon-only tabs without accessible names, and the dev deployment did not expose commit metadata for verification.

- Add accessible names and regression coverage for the Chat and Learn tabs
- Generate Spring Boot build info with the deployed source commit
- Surface deployment commit details through actuator info
@coderabbitai coderabbitai Bot added the refactor Code refactoring label Jun 10, 2026
@WilliamAGH WilliamAGH merged commit 8a4e1fd into main Jun 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request java Pull requests that update java code refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants