Skip to content

feat(release): authenticated terminal RAG, accessible citations, and restart-safe corpus ingestion - #192

Merged
WilliamAGH merged 76 commits into
mainfrom
dev
Aug 25, 2026
Merged

feat(release): authenticated terminal RAG, accessible citations, and restart-safe corpus ingestion#192
WilliamAGH merged 76 commits into
mainfrom
dev

Conversation

@WilliamAGH

@WilliamAGHWilliamAGH commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary

Java Chat now supports authenticated terminal RAG queries, renders source-grounded answers accessibly, and durably fetches and embeds the complete documentation corpus without concurrent writers, lost restart state, stale removed pages, or citation-identity collisions.

Changes

Features

  • Authenticated terminal RAG: Developers can authorize a Linux or macOS host in the browser and stream the same retrieval-backed answers and citations from the packaged CLI (cli/bin/javachat.js, ClerkApiKeyVerifier, CliAuthorizationPage.svelte).
  • Expanded authoritative knowledge: Retrieval can cite current Java, JVM-language, Spring, AI-tooling, infrastructure, Traefik, Porkbun, and Cloudflare sources through canonical source identities (DocsSourceRegistry, fetch_all_docs.sh).
  • Accessible cited answers: Streamed answers expose source coverage, keyboard-focusable message regions, uniquely named landmarks, and WCAG A/AA browser coverage (MessageBubble.svelte, CitationPanel.svelte, answer-accessibility.spec.ts).

Bug Fixes

  • Corpus work survives interruption and restart: Validated mirrors publish atomically, resumable archive staging is retained, predecessor proof survives user-manager restarts, stale PID state is retired only by the lease owner, and the queued job resumes behind exactly one Qdrant writer (documentation_fetch_sources.sh, run_queued_platform_documentation_staging.sh, qdrant_writer_lease.py).
  • Citation families retain every page: Java-source pages use stable per-file storage identities while exposing canonical citations; complete source runs prune removed URLs, and bounded audit queries detect a missing collision sibling (DocsSourceRegistry.resolveMirroredIngestionIdentities, LocalDocsFileIngestionProcessor.pruneRemovedSourceUrls, AuditService.auditByUrl).
  • Targeted ingestion fails closed: Blank, unknown, or mixed-invalid selectors cannot broaden into an unintended corpus, and requested sets require nonzero Qdrant postconditions (DocumentProcessor.selectDocumentationSets, process_all_to_qdrant.sh).
  • Authentication readiness is authoritative: Browser and CLI clients no longer advertise API-key operations when Clerk disables or cannot verify them (ApiKeyAvailabilityController, AuthenticatedUserController, clerkAuthentication.svelte.ts).
  • Answers retain source fidelity: Chat output preserves citation metadata, renders enrichment markers correctly, and grounds version questions on the requested major release (ChatService, SystemPromptConfig, MessageBubble.svelte).

Performance

  • Embedding fan-out stays isolated and cancellable: Bounded request waves run on dedicated virtual threads; a failed request interrupts blocked siblings instead of occupying the common pool or holding the writer lease through their retry budget (EmbeddingBatchEmbedder.embedDocuments).
  • Public audit remains bounded: Canonical-citation audits use indexed Qdrant filters and one atomically maintained citation-family file rather than scanning collections or every local marker (QdrantPayloadFieldSchema.CITATION_URL_FIELD, FileIngestionMarkerStore.storageUrlsForCanonicalCitation).

Documentation

  • Operators get reproducible deployment and ingestion commands: Guidance now reflects Dokploy and documents exact fetch, queue, selector, fingerprint, checkpoint, and verification behavior (docs/development.md, docs/ingestion.md, docs/pipeline-commands.md).

Breaking Changes

None.

Validation

  • make test
  • make build
  • make lint
  • Build & Test run 32908160098 — success, including Docker ingestion/runtime smoke
  • ADVERSARIAL: Deep — independent audit-synthesizer — 6 refuted, 0 retained, 6 added — dispositions: 18 fixed, 0 filed, 0 user-decision

WilliamAGHand others added 30 commits August 14, 2026 13:20
The retrieval corpus needs authoritative, version-pinned sources with complete provenance.
Use Wget2, safe archive extraction, and deterministic Javadoc seeding for exact source coverage.
- register canonical source citations and archive-backed API documentation
A fresh configured Qdrant store needs its collections and indexes before CLI ingestion starts.
Invoke the existing initializer in the command runner and propagate initialization failures.
- cover initializer ordering and failure propagation
Add exact, complete mirrors for Docker, Dokploy, Infisical, and Doppler.
Preserve canonical citation routes and source-specific fetch limits.
Add exact, complete mirrors for Docker, Dokploy, Infisical, and Doppler.
Preserve canonical citation routes and source-specific fetch limits.
Register official Anthropic, Claude Code, Amp, and Tinker documentation sources.
Preserve canonical citations and index Langfuse MDX documentation.
CI requires the documentation source assertion to use the repository formatter.
Preserve behavior while applying Spotless-owned line wrapping.
- format the citation URL expectation in the registry test
…the feature
A configured CLERK_SECRET_KEY was treated as proof that API-key login could
work, but Clerk gates API keys per instance. With the feature off, the
availability endpoint answered 204 while every key operation failed, sending
clients into a login that could never complete.
Recognise Clerk's feature_not_enabled code on a 403, latch it, and report the
deployment unavailable from then on. Match on the error code rather than the
bare status so transient credential and edge 403s stay retryable.
The assistant emits {{hint:}}, {{background:}}, {{reminder:}}, {{warning:}},
and {{example:}} markers that the web client renders as titled callouts. The
terminal client printed them verbatim, showing internal markup where the
website shows a formatted block.
Convert each marker to a titled terminal block during streaming, holding text
back only from an opening brace pair until its close arrives because markers
routinely straddle SSE chunks. Unrecognised tokens pass through unchanged, and
an unterminated marker is released verbatim so no answer text is lost.
Use the official Groovy archive without publishing its distribution envelope, canonicalize Quarkus guide URLs before redirect-rejecting fetches, and document Fedora's mutool package.
- preserve existing Groovy and Quarkus citation roots
- cover archive projection, discovery URLs, citations, and Fedora guidance
Add the pinned wafer-ai resource repository to the durable local embeddings queue.
Keep the enforced queue census and its contract test synchronized at 23 repositories.
- preserve dynamic repository discovery and sole-writer behavior
Preserve the existing local-only ingestion evidence and its remaining completion checks.
Keep the run ledger reviewable alongside the queue implementation it measures.
- retain completed and pending gate evidence without changing its claims
Use content fingerprints and exact Qdrant point identities as the unchanged-file contract.
Keep size and modification time as marker diagnostics without triggering duplicate embeddings.
Queue every remaining documentation mirror behind the local embedding backlog.
- Preserve durable predecessor proof and reject malformed selectors before Qdrant ingestion
Avoid maintaining a duplicate mirror-path list after the queued sources are fetched.
- Delegate full canonical selection to the CLI all selector
CopilotAI lite review requested due to automatic review settings August 25, 2026 21:29
@coderabbitai

coderabbitaiBot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 119 files, which is 19 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2b4942b4-eb37-49b0-bacf-9223b086e7c9

📥 Commits

Reviewing files that changed from the base of the PR and between 8d3ee70 and 7a9ab43.

⛔ Files ignored due to path filters (2)
  • cli/package-lock.json is excluded by !**/package-lock.json
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (119)
  • .dockerignore
  • .github/workflows/build.yml
  • .gitignore
  • AGENTS.md
  • Dockerfile
  • Makefile
  • cli/LICENSE.md
  • cli/README.md
  • cli/bin/javachat.js
  • cli/package.json
  • cli/test/javachat.test.js
  • config/ast-grep/java-web-boundary-threading-cache-jooq.yml
  • docs/development.md
  • docs/getting-started.md
  • docs/ingestion.md
  • docs/pipeline-commands.md
  • frontend/e2e/answer-accessibility.spec.ts
  • frontend/package.json
  • frontend/playwright.config.ts
  • frontend/src/App.svelte
  • frontend/src/lib/components/ChatInput.svelte
  • frontend/src/lib/components/CitationPanel.svelte
  • frontend/src/lib/components/CliAuthorizationPage.svelte
  • frontend/src/lib/components/CliAuthorizationPage.test.ts
  • frontend/src/lib/components/Header.svelte
  • frontend/src/lib/components/Header.test.ts
  • frontend/src/lib/components/MessageBubble.svelte
  • frontend/src/lib/components/MessageBubble.test.ts
  • frontend/src/lib/components/ToastContainer.svelte
  • frontend/src/lib/composables/clerkAuthentication.svelte.test.ts
  • frontend/src/lib/composables/clerkAuthentication.svelte.ts
  • frontend/src/lib/services/pageMetadata.test.ts
  • frontend/src/lib/services/pageMetadata.ts
  • frontend/src/lib/validation/schemas.ts
  • frontend/src/styles/global.css
  • frontend/src/vite-env.d.ts
  • infra/systemd/user/java-chat-local-embedding-staging.service
  • infra/systemd/user/java-chat-queued-platform-documentation-staging.service
  • scripts/documentation_seed.py
  • scripts/fetch_all_docs.sh
  • scripts/javadoc_seed.py
  • scripts/lib/common_qdrant.sh
  • scripts/lib/documentation_archives.sh
  • scripts/lib/documentation_fetch_sources.sh
  • scripts/lib/documentation_seed_mirrors.sh
  • scripts/lib/embedding_preflight.sh
  • scripts/lib/github_identity.sh
  • scripts/process_all_to_qdrant.sh
  • scripts/process_github_repo.sh
  • scripts/prune_retired_java_api_vectors.sh
  • scripts/qdrant_writer_lease.py
  • scripts/run_local_embedding_staging.sh
  • scripts/run_queued_platform_documentation_staging.sh
  • scripts/test_documentation_archives.sh
  • scripts/test_documentation_fetch_projection.sh
  • scripts/test_documentation_fetch_publication.sh
  • scripts/test_documentation_seed.py
  • scripts/test_embedding_preflight.sh
  • scripts/test_github_repository_metadata_contract.sh
  • scripts/test_github_sync_failure_contract.sh
  • scripts/test_ingestion_pid_safety.sh
  • scripts/test_local_embedding_staging_contract.sh
  • scripts/test_process_all_to_qdrant_environment.sh
  • scripts/test_prune_retired_java_api_vectors.sh
  • scripts/test_qdrant_writer_lease.sh
  • scripts/test_queued_platform_documentation_staging_contract.sh
  • src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.java
  • src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationToken.java
  • src/main/java/com/williamcallahan/javachat/adapters/out/clerk/ClerkApiKeyVerifier.java
  • src/main/java/com/williamcallahan/javachat/application/auth/ApiKeyLifecycle.java
  • src/main/java/com/williamcallahan/javachat/application/auth/ApiKeyOperationUnavailableException.java
  • src/main/java/com/williamcallahan/javachat/application/auth/VerifiedApiKey.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.java
  • src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantIndexInitializer.java
  • src/main/java/com/williamcallahan/javachat/config/SecurityConfig.java
  • src/main/java/com/williamcallahan/javachat/config/SystemPromptConfig.java
  • src/main/java/com/williamcallahan/javachat/config/WebMvcConfig.java
  • src/main/java/com/williamcallahan/javachat/domain/ingestion/SourceFileLanguage.java
  • src/main/java/com/williamcallahan/javachat/service/AuditService.java
  • src/main/java/com/williamcallahan/javachat/service/ChatService.java
  • src/main/java/com/williamcallahan/javachat/service/Chunker.java
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingBatchEmbedder.java
  • src/main/java/com/williamcallahan/javachat/service/FileIngestionMarkerStore.java
  • src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java
  • src/main/java/com/williamcallahan/javachat/service/JavaApiPageDisposition.java
  • src/main/java/com/williamcallahan/javachat/service/JavaApiPageExtraction.java
  • src/main/java/com/williamcallahan/javachat/service/QdrantPayloadFieldSchema.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsDirectoryIngestionService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/SourceCodeFileIngestionProcessor.java
  • src/main/java/com/williamcallahan/javachat/support/JavaApiPageExtractor.java
  • src/main/java/com/williamcallahan/javachat/web/ApiKeyAvailabilityController.java
  • src/main/java/com/williamcallahan/javachat/web/AuthenticatedUserController.java
  • src/main/resources/application-local.properties
  • src/test/java/com/williamcallahan/javachat/adapters/out/clerk/ClerkApiKeyVerifierTest.java
  • src/test/java/com/williamcallahan/javachat/cli/DocumentProcessorSelectionTest.java
  • src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantIndexInitializerTest.java
  • src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.java
  • src/test/java/com/williamcallahan/javachat/config/SystemPromptConfigTest.java
  • src/test/java/com/williamcallahan/javachat/domain/ingestion/SourceFileLanguageTest.java
  • src/test/java/com/williamcallahan/javachat/service/AuditServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ChatServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ChunkerTest.java
  • src/test/java/com/williamcallahan/javachat/service/EmbeddingBatchEmbedderTest.java
  • src/test/java/com/williamcallahan/javachat/service/HtmlContentExtractorTest.java
  • src/test/java/com/williamcallahan/javachat/service/HybridVectorServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/LocalStoreServiceFileMarkerTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceCitationTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/LocalDocsDirectoryIngestionServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessorTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/SourceCodeFileIngestionProcessorTest.java
  • src/test/java/com/williamcallahan/javachat/web/ApiKeyAvailabilityControllerTest.java
  • src/test/java/com/williamcallahan/javachat/web/AuthenticatedUserControllerTest.java
  • src/test/java/com/williamcallahan/javachat/web/AuthenticatedUserEndpointSecurityIntegrationTest.java
  • src/test/java/com/williamcallahan/javachat/web/BrowserErrorResponseIntegrationTest.java

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


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.

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using default effort and found 4 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for all 4 issues found in the latest run.

  • ✅ Fixed: Archive resume discards unpublished staging
    • The archive short-circuit now flows through the shared completion tail, which discards staging only when it was seeded from the published mirror and otherwise validates and publishes the resumed archive extract.
  • ✅ Fixed: Ingestion image omits writer lease
    • Added scripts/qdrant_writer_lease.py to the ingestion stage COPY so acquire_qdrant_writer_lease can exec the lease helper inside the container.
  • ✅ Fixed: API-key budget counts local rejects
    • The filter now refunds the client verification budget when verify throws ApiKeyOperationUnavailableException, so failures where Clerk never answered no longer consume the 20/min budget.
  • ✅ Fixed: Queue contract compares raw grep cuts
    • The guard-order check now captures each grep result set, requires exactly one match per anchor, and extracts line numbers only afterward, matching the local-staging contract test pattern.

Create PR

Or push these changes by commenting:

@cursor push 434cad135b
Preview (434cad135b)
diff --git a/Dockerfile b/Dockerfile--- a/Dockerfile+++ b/Dockerfile@@ -78,7 +78,7 @@
&& groupadd --gid 1001 appuser \
&& useradd --uid 1001 --gid 1001 --create-home --shell /bin/bash appuser
-COPY scripts/process_all_to_qdrant.sh scripts/+COPY scripts/process_all_to_qdrant.sh scripts/qdrant_writer_lease.py scripts/
COPY scripts/with_build_state_lock.sh scripts/BuildStateLock.java scripts/
COPY scripts/lib/common_qdrant.sh scripts/lib/shell_bootstrap.sh \
scripts/lib/env_loader.sh scripts/lib/embedding_preflight.sh scripts/lib/
diff --git a/scripts/fetch_all_docs.sh b/scripts/fetch_all_docs.sh--- a/scripts/fetch_all_docs.sh+++ b/scripts/fetch_all_docs.sh@@ -607,6 +607,10 @@
if [ "$existing_count" -gt 0 ]; then
log "${BLUE}ℹ Existing mirror: $existing_count HTML files${NC}"
fi
+ # A complete source-matched archive staging skips re-extraction. Whether it is+ # a disposable copy of the published mirror or an unpublished resume is decided+ # by staging_seeded_from_published_mirror in the shared completion tail below.+ local archive_source_already_complete="false"
if [ -n "$archive_format" ] \
&& [ "$FORCE_REFRESH" != "true" ] \
&& [ "$existing_count" -ge "$min_files" ] \
@@ -614,12 +618,8 @@
"$staging_directory" "$name" "$min_files" "$identity_regex" "$forbidden_identity_regex" \
&& validate_staged_documentation_identity \
"$staging_directory" "$name" "$required_identity_page" "$required_identity_text" "$expected_meta_version"; then
+ archive_source_already_complete="true"
log "${GREEN}✓ $name already fetched: $existing_count HTML files (validated pinned archive)${NC}"
- if ! discard_documentation_fetch_staging_directory "$staging_directory"; then- log "${RED}✗ Could not discard validated archive staging for $name${NC}"- return 1- fi- return 0
fi
# Proactive cleanup for known legacy Spring mirror layouts that otherwise mask incomplete fetches.
if [[ "$name" == *"Spring Framework Javadoc"* ]]; then
@@ -632,7 +632,9 @@
quarantine_versioned_reference_subdirs "$fetch_target_directory" "$name" "^1\\.1$"
fi
- log "${YELLOW}Fetching $name...${NC}"+ if [ "$archive_source_already_complete" != "true" ]; then+ log "${YELLOW}Fetching $name...${NC}"+ fi
if ! mkdir -p "$fetch_target_directory" || ! cd "$fetch_target_directory"; then
if [ -n "$staging_directory" ] \
&& ! discard_documentation_fetch_staging_directory "$staging_directory"; then
@@ -664,14 +666,18 @@
"$partial_mirror_allowed" \
"${plain_text_required_fragments[@]}" || documentation_fetch_status=$?
elif [ -n "$archive_format" ]; then
- fetch_documentation_archive \- "$url" \- "$fetch_target_directory" \- "$name" \- "$min_files" \- "$archive_format" \- "$archive_strip_components" \- "$archive_publication_root" || documentation_fetch_status=$?+ if [ "$archive_source_already_complete" = "true" ]; then+ DOCUMENTATION_SOURCE_ALREADY_COMPLETE="true"+ else+ fetch_documentation_archive \+ "$url" \+ "$fetch_target_directory" \+ "$name" \+ "$min_files" \+ "$archive_format" \+ "$archive_strip_components" \+ "$archive_publication_root" || documentation_fetch_status=$?+ fi
elif [ -n "$java_release" ] || [ "$javadoc_seed" = "true" ]; then
local java_api_fetch_required="true"
if ! generate_javadoc_seed "$url" "$fetch_target_directory" \
diff --git a/scripts/test_queued_platform_documentation_staging_contract.sh b/scripts/test_queued_platform_documentation_staging_contract.sh--- a/scripts/test_queued_platform_documentation_staging_contract.sh+++ b/scripts/test_queued_platform_documentation_staging_contract.sh@@ -74,11 +74,26 @@
grep -Fq './scripts/process_all_to_qdrant.sh --doc-sets=all' "$queued_launcher" \
|| fail_queued_platform_test "queued job does not invoke the canonical documentation registry"
-completion_gate_line="$(grep -n "expected_staging_invocation_journal | grep -Fq 'LOCAL_STAGING_COMPLETE'" "$queued_launcher" | tail -1 | cut -d: -f1)"-invocation_receipt_line="$(grep -n '^mv -- "$STAGING_INVOCATION_RECEIPT.next"' "$queued_launcher" | cut -d: -f1)"-writer_lease_line="$(grep -n '^acquire_qdrant_writer_lease$' "$queued_launcher" | cut -d: -f1)"-source_refresh_line="$(grep -n './scripts/fetch_all_docs.sh --doc-sets=' "$queued_launcher" | cut -d: -f1)"-ingestion_start_line="$(grep -n './scripts/process_all_to_qdrant.sh --doc-sets=' "$queued_launcher" | cut -d: -f1)"+completion_gate_locations="$(grep -n "expected_staging_invocation_journal | grep -Fq 'LOCAL_STAGING_COMPLETE'" "$queued_launcher" || true)"+invocation_receipt_locations="$(grep -n '^mv -- "$STAGING_INVOCATION_RECEIPT.next"' "$queued_launcher" || true)"+writer_lease_locations="$(grep -n '^acquire_qdrant_writer_lease$' "$queued_launcher" || true)"+source_refresh_locations="$(grep -n './scripts/fetch_all_docs.sh --doc-sets=' "$queued_launcher" || true)"+ingestion_start_locations="$(grep -n './scripts/process_all_to_qdrant.sh --doc-sets=' "$queued_launcher" || true)"+for guard_order_locations in \+ "$completion_gate_locations" \+ "$invocation_receipt_locations" \+ "$writer_lease_locations" \+ "$source_refresh_locations" \+ "$ingestion_start_locations"; do+ if [ "$(printf '%s\n' "$guard_order_locations" | sed '/^$/d' | wc -l | tr -d ' ')" -ne 1 ]; then+ fail_queued_platform_test "queued guard-order anchors do not each match exactly once"+ fi+done+completion_gate_line="${completion_gate_locations%%:*}"+invocation_receipt_line="${invocation_receipt_locations%%:*}"+writer_lease_line="${writer_lease_locations%%:*}"+source_refresh_line="${source_refresh_locations%%:*}"+ingestion_start_line="${ingestion_start_locations%%:*}"
if [ "$completion_gate_line" -ge "$invocation_receipt_line" ] \
|| [ "$invocation_receipt_line" -ge "$source_refresh_line" ] \
|| [ "$source_refresh_line" -ge "$writer_lease_line" ] \
diff --git a/src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.java b/src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.java--- a/src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.java+++ b/src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.java@@ -105,6 +105,7 @@
try {
verifiedKey = apiKeyLifecycle.verify(presentedSecret.get());
} catch (ApiKeyOperationUnavailableException verificationFailure) {
+ refundClientVerification(request.getRemoteAddr());
log.error("Clerk API key verification was unavailable", verificationFailure);
writeError(response, HttpStatus.SERVICE_UNAVAILABLE, VERIFICATION_UNAVAILABLE_MESSAGE);
return;
@@ -134,6 +135,17 @@
return verificationCount.incrementAndGet() <= CLERK_VERIFICATION_MAXIMUM_REQUESTS_PER_MINUTE;
}
+ // The budget tracks answered Clerk verifications only. An unavailable outcome+ // (missing credential, latched-off feature, exhausted capacity, or an+ // unanswered provider call) must not consume it, or purely local failures+ // could 429 later real verifications.+ private void refundClientVerification(String clientAddress) {+ AtomicInteger verificationCount = clientVerificationCounts.getIfPresent(clientAddress);+ if (verificationCount != null) {+ verificationCount.decrementAndGet();+ }+ }+
private static Optional<String> presentedApiKey(HttpServletRequest request) {
if (!AUTHENTICATED_USER_PATH.equals(request.getRequestURI())
&& !API_KEY_REVOCATION_PATH.equals(request.getRequestURI())

You can send follow-ups to the cloud agent here.

Comment threadscripts/fetch_all_docs.sh
Comment threadDockerfile

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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:990f5ea223

ℹ️ 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 threadDockerfile
Comment threadscripts/run_local_embedding_staging.sh Outdated
Comment threadGATES.md Outdated

CopilotAI 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.

🔵 Needs a closer look

It introduces security-sensitive authentication changes plus critical ingestion/write-coordination behavior across many layers, requiring careful human verification beyond this automated review.

Pull request overview

This PR expands Java Chat’s authenticated surfaces and ingestion pipeline reliability: it adds Clerk-backed API-key authentication for a packaged CLI, improves “source record” fidelity in streamed answers/citations, and hardens long-running documentation ingestion so it survives restarts and enforces a single Qdrant writer.

Changes:

  • Add Clerk API-key lifecycle + auth filter path (API key availability probe, /api/me identity, /api/me/api-key revocation, CSRF exemption only for API-key bearers).
  • Strengthen ingestion correctness and durability (exact Qdrant point identity checks, writer lease, restart-safe staging/queue scripts, fail-closed doc-set selection + Qdrant readiness gate).
  • Improve UX/accessibility and testing coverage (CLI authorization route, citation/source semantics in prompts, keyboard-focusable message regions, Playwright+axe checks).
File summaries
FileDescription
src/test/java/com/williamcallahan/javachat/web/BrowserErrorResponseIntegrationTest.javaAdds SPA forwarding coverage for /cli/authorize.
src/test/java/com/williamcallahan/javachat/web/AuthenticatedUserEndpointSecurityIntegrationTest.javaAdds integration coverage for API-key auth + revocation.
src/test/java/com/williamcallahan/javachat/web/AuthenticatedUserControllerTest.javaUpdates controller unit tests for Authentication-based identity + key revocation.
src/test/java/com/williamcallahan/javachat/web/ApiKeyAvailabilityControllerTest.javaNew unit test for API-key availability endpoint behavior.
src/test/java/com/williamcallahan/javachat/service/RetrievalServiceCitationTest.javaAdds regression coverage for legacy Spring Boot SQL URL normalization.
src/test/java/com/williamcallahan/javachat/service/ingestion/SourceCodeFileIngestionProcessorTest.javaUpdates ingestion tests for exact-point identity checks and replacement behavior.
src/test/java/com/williamcallahan/javachat/service/HybridVectorServiceTest.javaAdjusts exact-point identity tests for new overload usage.
src/test/java/com/williamcallahan/javachat/service/HtmlContentExtractorTest.javaAdds frameset-navigation exclusion coverage for Java API extraction.
src/test/java/com/williamcallahan/javachat/service/ChunkerTest.javaNew coverage for tokenizer special-token quoting scenarios.
src/test/java/com/williamcallahan/javachat/service/ChatServiceTest.javaAdds coverage for “unspecified” source record version behavior.
src/test/java/com/williamcallahan/javachat/domain/ingestion/SourceFileLanguageTest.javaNew coverage for .mdx classification.
src/test/java/com/williamcallahan/javachat/config/SystemPromptConfigTest.javaAdds tests for new system-prompt clauses (control flow + source fidelity).
src/test/java/com/williamcallahan/javachat/config/SecurityConfigTest.javaAdds tests for CSRF exemption narrowness and API-key bearer auth.
src/test/java/com/williamcallahan/javachat/config/QdrantIndexInitializerTest.javaUpdates initializer test for fail-closed batch readiness requirement.
src/test/java/com/williamcallahan/javachat/cli/DocumentProcessorSelectionTest.javaExpands selector rejection semantics + verifies Qdrant readiness gating.
src/main/java/com/williamcallahan/javachat/web/AuthenticatedUserController.javaAdds Authentication-based identity and API-key self-revocation endpoint.
src/main/java/com/williamcallahan/javachat/web/ApiKeyAvailabilityController.javaAdds deployment readiness endpoint for CLI key creation flow.
src/main/java/com/williamcallahan/javachat/support/JavaApiPageExtractor.javaExcludes frameset navigation shells from Java API ingestion.
src/main/java/com/williamcallahan/javachat/service/JavaApiPageExtraction.javaGeneralizes “excluded” semantics and adds navigation-page exclusion constructor.
src/main/java/com/williamcallahan/javachat/service/JavaApiPageDisposition.javaAdds navigation-page exclusion enum value.
src/main/java/com/williamcallahan/javachat/service/ingestion/SourceCodeFileIngestionProcessor.javaSwitches to exact stored point identity checks (vs. count-based coverage).
src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.javaExcludes navigation shells, increases batching, and aligns marker checks with fingerprints.
src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsDirectoryIngestionService.javaIncreases local ingestion batching.
src/main/java/com/williamcallahan/javachat/service/HybridVectorService.javaAdds hasExactPointIdsForUrl overload for collection kind + strengthens validation.
src/main/java/com/williamcallahan/javachat/service/EmbeddingBatchEmbedder.javaAdds bounded request waves + transient retry behavior for embedding batches.
src/main/java/com/williamcallahan/javachat/service/Chunker.javaUses ordinary encoding to handle quoted special tokens safely.
src/main/java/com/williamcallahan/javachat/service/ChatService.javaPrepends structured “SOURCE RECORD” headers to retained context documents.
src/main/java/com/williamcallahan/javachat/domain/ingestion/SourceFileLanguage.javaAdds .mdx support to documentation classification.
src/main/java/com/williamcallahan/javachat/config/WebMvcConfig.javaForwards /cli/authorize to SPA index shell.
src/main/java/com/williamcallahan/javachat/config/SystemPromptConfig.javaAdds generated-control-flow and source-fidelity clauses to core prompt.
src/main/java/com/williamcallahan/javachat/config/SecurityConfig.javaAdds Clerk API-key auth filter, narrows CSRF exemption, and avoids session lane for API keys.
src/main/java/com/williamcallahan/javachat/config/QdrantIndexInitializer.javaAdds fail-closed readiness requirement for batch ingestion.
src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.javaFail-closed doc-set selection, --app-jar, and Qdrant readiness gating.
src/main/java/com/williamcallahan/javachat/application/auth/VerifiedApiKey.javaNew verified API-key identity record (no secret).
src/main/java/com/williamcallahan/javachat/application/auth/ApiKeyOperationUnavailableException.javaNew exception type for provider-unavailable key operations.
src/main/java/com/williamcallahan/javachat/application/auth/ApiKeyLifecycle.javaNew provider-agnostic API-key lifecycle interface.
src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationToken.javaNew Authentication token for verified API keys.
src/main/java/com/williamcallahan/javachat/adapters/in/web/security/ClerkApiKeyAuthenticationFilter.javaNew filter for API-key bearer authentication + rate limiting.
scripts/test_queued_platform_documentation_staging_contract.shContract test ensuring queued staging remains behind sole writer.
scripts/test_prune_retired_java_api_vectors.shExtends contract to ensure writer lease usage only on validated paths.
scripts/test_process_all_to_qdrant_environment.shExtends environment contract tests (log archival, lease ordering, help/invalid args).
scripts/test_local_embedding_staging_contract.shNew contract test for local-only staging + cloud credential masking.
scripts/test_github_sync_failure_contract.shEnsures no lease acquisition / network access on invalid inputs.
scripts/test_embedding_preflight.shUpdates expected embedding batch sizes for new batching behavior.
scripts/test_documentation_fetch_publication.shEnsures staging copies don’t share mutable inodes with published mirrors.
scripts/test_documentation_archives.shNew offline archive extraction tests (zip/tar + unsafe path rejection).
scripts/run_queued_platform_documentation_staging.shNew queued staging runner gated behind predecessor completion + writer lease.
scripts/run_local_embedding_staging.shNew local staging runner enforcing local Qdrant-only + pinned repo cleanliness.
scripts/qdrant_writer_lease.pyNew Python helper for exclusive writer lease acquisition.
scripts/prune_retired_java_api_vectors.shAcquires writer lease before pruning.
scripts/process_github_repo.shAdds writer lease acquisition before cache refresh/sync/ingest.
scripts/process_all_to_qdrant.shAdds --app-jar, log archival, fail-closed selector, and lease ordering.
scripts/lib/embedding_preflight.shUpdates probe batch size to align with new batch behavior.
scripts/lib/documentation_seed_mirrors.shAdds safe copy-to-staging helper; generalizes seed mirror verification names.
scripts/lib/documentation_archives.shNew shared archive fetch/extract utility with safety checks.
scripts/lib/common_qdrant.shAdds shared writer lease acquisition helpers.
scripts/javadoc_seed.pyGeneralizes deterministic Javadoc seed generation without regex HTML parsing.
MakefileAdds CLI tests and additional shell contract tests.
infra/systemd/user/java-chat-queued-platform-documentation-staging.serviceAdds queued staging unit with durable predecessor proof.
infra/systemd/user/java-chat-local-embedding-staging.serviceAdds local staging unit with completion proof + queue trigger.
GATES.mdAdds run ledger for local staging completion evidence.
frontend/src/vite-env.d.tsUpdates deployment docs reference to Dokploy/Infisical.
frontend/src/styles/global.cssAdjusts accent colors and improves code/citation readability.
frontend/src/lib/validation/schemas.tsAdds Zod schemas for CLI authorization and API-key creation response.
frontend/src/lib/services/pageMetadata.tsAdds metadata for CLI authorization route.
frontend/src/lib/services/pageMetadata.test.tsAdds tests for CLI authorization route resolution behavior.
frontend/src/lib/composables/clerkAuthentication.svelte.tsAdds auth lifecycle phase + CLI API-key creation with schema validation.
frontend/src/lib/composables/clerkAuthentication.svelte.test.tsAdds test ensuring malformed secret isn’t logged; updates phase expectations.
frontend/src/lib/components/ToastContainer.svelteAdjusts toast container semantics (toasts provide status roles).
frontend/src/lib/components/MessageBubble.test.tsAdds keyboard-focusability coverage for user message regions.
frontend/src/lib/components/MessageBubble.svelteMakes user message bubble focusable region for keyboard scrolling.
frontend/src/lib/components/Header.test.tsUpdates tests to use auth “phase” state.
frontend/src/lib/components/Header.svelteSwitches auth gating from isLoaded to lifecycle phase.
frontend/src/lib/components/CliAuthorizationPage.test.tsNew tests for CLI authorization query validation and sign-in gating.
frontend/src/lib/components/CliAuthorizationPage.svelteNew CLI authorization SPA page and loopback redirect.
frontend/src/lib/components/CitationPanel.svelteImproves expanded-trigger color contrast.
frontend/src/lib/components/ChatInput.svelteImproves hint text contrast.
frontend/src/App.svelteAdds CLI authorization view and skips CSRF refresh on that route.
frontend/playwright.config.tsAdds Playwright E2E configuration for accessibility runs.
frontend/package.jsonAdds test:browser and Playwright/axe dev deps; adjusts oxfmt ignore-path.
frontend/package-lock.jsonLocks Playwright and axe dependencies.
frontend/e2e/answer-accessibility.spec.tsNew axe-based E2E checks for cited answers + CLI authorization landmarks.
docs/pipeline-commands.mdUpdates ingestion/fetch docs (Wget2, selector semantics, seed generator naming).
docs/ingestion.mdUpdates pipeline overview terminology and prerequisites (Wget2).
docs/getting-started.mdUpdates prerequisites (Wget2).
docs/development.mdUpdates deployment references (Dokploy).
DockerfileAdds “ingestion” target stage and updates ignore-file copy path.
cli/README.mdAdds CLI install and usage docs.
cli/package.jsonAdds publishable CLI package manifest and commands.
cli/package-lock.jsonLocks CLI package metadata.
cli/LICENSE.mdAdds CLI license text.
AGENTS.mdUpdates repository rules summary (Dokploy/Infisical + expanded rule references).
.gitignoreIgnores Playwright test output and ensures cli/bin/ is tracked.
.github/workflows/build.ymlAdds macOS portability job, CLI pack/test checks, Playwright+axe CI runs, ingestion image build.
.dockerignoreExcludes Playwright output directories from Docker context.
Review details

Files not reviewed (2)

  • cli/package-lock.json: Generated file
  • frontend/package-lock.json: Generated file
  • Files reviewed: 102/109 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

A pinned detached-HEAD repository clone with no refs/remotes/origin/HEAD
(wafer-ai gpu-perf-engineering-resources) made the branch fallback's
symbolic-ref exit 128 inside a command substitution assignment, which
set -e escalated into aborting the entire staging run. Branch identity
is already best-effort downstream (envOrEmpty, guarded echo), so resolve
it to empty instead of failing the run.
Keep singleton documentation on canonical URLs while disambiguating only files that share one citation.
Migrate collided vectors and markers once, then skip unchanged files by exact point identity.
Keep one existing canonical identity per shared citation and disambiguate only the remaining pages.
Avoid redundant legacy deletes while retaining collision-free markers and exact skip behavior.
Recognize the dedicated embedding batch component as the approved virtual-thread fan-out owner.
Comment threadsrc/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java Outdated
Comment threadsrc/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java Outdated
Persist runtime-owned batch settings, recover stale PID state only under the writer lease, and resume queued work against the live invocation.
Keep collision-aware audit and embedding fan-out behavior consistent across retries while removing the obsolete run ledger.

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

There are 4 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues. You can view the agent here.

Reviewed by Cursor Bugbot for commit 3c269b8. Configure here.

@cursor

cursorBot commented Aug 25, 2026

Copy link
Copy Markdown

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Disambiguated URLs share storage prefixes
    • Changed the disambiguation marker to start with a dot that survives safe-name sanitization, so sibling identities no longer extend the canonical URL's safeName+"_" parsed-chunk prefix and owner prune/replacement scans cannot sweep sibling parsed files.
  • ✅ Fixed: Collision owner depends on file order
    • Replaced first-in-list ownership with a deterministic shortest-path (lexicographic tie-break) rule, so the outer type page whose filename names the cited source always owns the bare citation URL regardless of inventory order or later-added nested siblings.

Create PR

Or push these changes by commenting:

@cursor push 31905be67e
Preview (31905be67e)
diff --git a/src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java b/src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java--- a/src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java+++ b/src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java@@ -38,7 +38,13 @@
private static final String PATH_SEPARATOR_TEXT = "/";
private static final String GITHUB_BLOB_PATH = "/blob/";
private static final String GITHUB_TREE_PATH = "/tree/";
- private static final String INGESTION_IDENTITY_QUERY_PREFIX = "?java-chat-mirror=";+ /**+ * Starts with a literal dot because {@code LocalStoreService} safe names keep dots while rewriting other+ * separators to underscores; a disambiguated identity therefore never extends the canonical URL's+ * {@code safeName + "_"} parsed-chunk prefix, so pruning the canonical owner cannot sweep sibling files.+ */+ private static final String INGESTION_IDENTITY_MARKER = ".java-chat-mirror.";+
private static final String SPRING_FRAMEWORK_MARKER = "spring-framework";
private static final String SPRING_FRAMEWORK_LEGACY_DUPLICATE_JAVADOC_PREFIX =
"docs/current/api/current/javadoc-api/";
@@ -688,11 +694,11 @@
}
}
- private static String ingestionIdentityQuery(String mirroredRelativePath) {+ private static String ingestionIdentitySuffix(String mirroredRelativePath) {
String encodedMirrorPath = Base64.getUrlEncoder()
.withoutPadding()
.encodeToString(mirroredRelativePath.getBytes(StandardCharsets.UTF_8));
- return INGESTION_IDENTITY_QUERY_PREFIX + encodedMirrorPath;+ return INGESTION_IDENTITY_MARKER + encodedMirrorPath;
}
private static Optional<String> resolveJavaSourceCitation(String sourceBaseUrl, String mirroredRelativePath) {
@@ -756,44 +762,54 @@
/**
* Resolves per-file storage identities, disambiguating only canonical URLs shared by multiple mirror files.
+ *+ * <p>Each shared citation keeps exactly one file on the bare canonical URL: the file with the shortest+ * path (lexicographic tie-break). Nested-type pages always extend the outer type page's file name, so+ * the page that actually names the cited source owns the URL regardless of inventory order, and+ * later-added siblings never reassign an existing owner's identity.</p>
*/
public static Map<Path, String> resolveMirroredIngestionIdentities(Path mirrorRoot, List<Path> documentFiles) {
Objects.requireNonNull(mirrorRoot, "mirrorRoot");
List<Path> requiredDocumentFiles = List.copyOf(Objects.requireNonNull(documentFiles, "documentFiles"));
Path absoluteMirrorRoot = mirrorRoot.toAbsolutePath().normalize();
Map<Path, String> canonicalUrlsByFile = new LinkedHashMap<>();
+ Map<String, Path> canonicalIdentityOwners = new LinkedHashMap<>();
Map<String, Integer> canonicalUrlCounts = new LinkedHashMap<>();
for (Path documentFile : requiredDocumentFiles) {
Path absoluteDocumentFile = documentFile.toAbsolutePath().normalize();
resolveMirroredPath(absoluteMirrorRoot, absoluteDocumentFile).ifPresent(canonicalUrl -> {
canonicalUrlsByFile.put(absoluteDocumentFile, canonicalUrl);
+ canonicalIdentityOwners.merge(+ canonicalUrl, absoluteDocumentFile, DocsSourceRegistry::preferredCanonicalIdentityOwner);
canonicalUrlCounts.merge(canonicalUrl, 1, Integer::sum);
});
}
- Map<String, Path> canonicalIdentityOwners = new LinkedHashMap<>();
Map<Path, String> ingestionIdentities = new LinkedHashMap<>();
canonicalUrlsByFile.forEach((documentFile, canonicalUrl) -> {
boolean citationCollision = canonicalUrlCounts.getOrDefault(canonicalUrl, 0) > 1;
- if (!citationCollision) {+ if (!citationCollision || documentFile.equals(canonicalIdentityOwners.get(canonicalUrl))) {
ingestionIdentities.put(documentFile, canonicalUrl);
return;
}
- Path canonicalIdentityOwner =- canonicalIdentityOwners.computeIfAbsent(canonicalUrl, ignoredUrl -> documentFile);- if (canonicalIdentityOwner.equals(documentFile)) {- ingestionIdentities.put(documentFile, canonicalUrl);- return;- }
String mirroredRelativePath = absoluteMirrorRoot
.relativize(documentFile)
.toString()
.replace(WINDOWS_PATH_SEPARATOR, UNIX_PATH_SEPARATOR);
- ingestionIdentities.put(documentFile, canonicalUrl + ingestionIdentityQuery(mirroredRelativePath));+ ingestionIdentities.put(documentFile, canonicalUrl + ingestionIdentitySuffix(mirroredRelativePath));
});
return Map.copyOf(ingestionIdentities);
}
+ private static Path preferredCanonicalIdentityOwner(Path currentOwner, Path candidateOwner) {+ String currentOwnerPath = currentOwner.toString();+ String candidateOwnerPath = candidateOwner.toString();+ if (candidateOwnerPath.length() != currentOwnerPath.length()) {+ return candidateOwnerPath.length() < currentOwnerPath.length() ? candidateOwner : currentOwner;+ }+ return candidateOwnerPath.compareTo(currentOwnerPath) < 0 ? candidateOwner : currentOwner;+ }+
private static boolean pathEndsWith(String normalizedRoot, String relativeMirrorPath) {
return normalizedRoot.equals(relativeMirrorPath)
|| normalizedRoot.endsWith(PATH_SEPARATOR_TEXT + relativeMirrorPath);
@@ -1129,7 +1145,7 @@
}
private static String stripIngestionIdentity(String url) {
- int identityStart = url.indexOf(INGESTION_IDENTITY_QUERY_PREFIX);+ int identityStart = url.indexOf(INGESTION_IDENTITY_MARKER);
return identityStart < 0 ? url : url.substring(0, identityStart);
}
}
diff --git a/src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java b/src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java--- a/src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java+++ b/src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java@@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import com.williamcallahan.javachat.config.DocsSourceRegistry.DocumentationCitationPathStyle;
import com.williamcallahan.javachat.config.DocsSourceRegistry.DocumentationSource;
@@ -147,7 +148,7 @@
Path singletonTypePage = mirrorRoot.resolve("com/fasterxml/jackson/databind/JsonNode.html");
Map<Path, String> ingestionIdentities = DocsSourceRegistry.resolveMirroredIngestionIdentities(
- mirrorRoot, List.of(outerTypePage, nestedTypePage, singletonTypePage));+ mirrorRoot, List.of(nestedTypePage, outerTypePage, singletonTypePage));
String outerStorageUrl =
ingestionIdentities.get(outerTypePage.toAbsolutePath().normalize());
String nestedStorageUrl =
@@ -156,13 +157,14 @@
ingestionIdentities.get(singletonTypePage.toAbsolutePath().normalize());
assertNotEquals(outerStorageUrl, nestedStorageUrl);
+ assertTrue(nestedStorageUrl.startsWith(outerStorageUrl + ".java-chat-mirror."));
assertEquals(
DocsSourceRegistry.normalizeDocUrl(outerStorageUrl),
DocsSourceRegistry.normalizeDocUrl(nestedStorageUrl));
assertEquals(
DocsSourceRegistry.resolveMirroredPath(mirrorRoot, outerTypePage)
.orElseThrow(),
- DocsSourceRegistry.normalizeDocUrl(outerStorageUrl));+ outerStorageUrl);
assertEquals(
DocsSourceRegistry.resolveMirroredPath(mirrorRoot, singletonTypePage)
.orElseThrow(),

You can send follow-ups to the cloud agent here.

Mirror URLs with the same public citation could leave Qdrant chunks unaccounted.
Persist citation families, index their payload key, and query both identities during auditing.
- Re-index document extraction when citation metadata changes and prune matching GitHub tree URLs.
A failed embedding request could leave a blocked sibling running for the full request duration.
Submit cancellable tasks directly and interrupt the executor when a wave fails.
- Cover interruption of a blocked sibling request.
The documentation queue was not enabled in the user manager, so it did not resume after restart.
Install it under default.target and enforce that durable lifecycle in the contract test.
- Keep predecessor handoff and completion proof intact.
@WilliamAGHWilliamAGH added the enhancement New feature or request label Aug 25, 2026
@WilliamAGHWilliamAGH changed the title feat(release): secure terminal access, accessible cited answers, and durable documentation ingestionfeat(release): authenticated terminal RAG, accessible citations, and restart-safe corpus ingestionAug 25, 2026
@WilliamAGHWilliamAGH added bug Something isn't working documentation Improvements or additions to documentation labels Aug 25, 2026
@WilliamAGH
WilliamAGH merged commit 709abcf into mainAug 25, 2026
10 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@WilliamAGH