Skip to content

fix(search): preserve exact Javadoc member citations - #114

Merged
WilliamAGH merged 63 commits into
mainfrom
dev
Jul 27, 2026
Merged

fix(search): preserve exact Javadoc member citations#114
WilliamAGH merged 63 commits into
mainfrom
dev

Conversation

@WilliamAGH

Copy link
Copy Markdown
Owner

Outcome

  • extracts canonical Oracle Javadoc member sections and persists exact DOM anchors separately from fragmentless page URLs
  • removes heuristic Javadoc URL/member rewriting so citations always use ingested source identity
  • makes remote and local reindexing atomic and exact by comparing deterministic Qdrant point IDs, upserting complete replacements before deleting obsolete points, and failing closed on ambiguous marker cleanup
  • excludes class-use and redirect-backed root type vectors, including an idempotent production prune before Java API ingestion
  • reconciles Java 21/24/25 mirrors against release-correct seed inventories and bulk-projects mirror paths
  • introduces a narrow documentation-ingestion application boundary for CLI and web callers

Production migration

After deployment, run the Java 21/24/25 mirror ingestion. The pipeline prunes retired class-use/root redirect vectors first, then reindexes all governed Javadoc pages with exact anchors.

Verification

  • make build
  • make test
  • make lint
  • documentation fetch projection tests
  • Java API fetch projection tests
  • documentation seed tests
  • retired Java API vector prune tests
  • exact Java 21/24/25 mirror verification: 5,443 / 5,710 / 5,723 pages
  • independent final review: approved with no P0/P1/P2 findings

CopilotAI review requested due to automatic review settings July 18, 2026 18:33
@coderabbitai

coderabbitaiBot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 233 files, which is 133 over the limit of 100.

To get a review, narrow the scope:
• coderabbit review --committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

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: f604c199-da0f-417e-baf7-f50ed7eca322

📥 Commits

Reviewing files that changed from the base of the PR and between 1263e64 and cec8a0c.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (263)
  • .env.example
  • .github/workflows/build.yml
  • AGENTS.md
  • Dockerfile
  • Makefile
  • README.md
  • build.gradle.kts
  • config/make/common.mk
  • config/spotbugs/spotbugs-exclude.xml
  • docs/api.md
  • docs/architecture.md
  • docs/configuration.md
  • docs/contracts/code-change.md
  • docs/development.md
  • docs/domains/all-parsing-and-markdown-logic.md
  • docs/domains/local-store-directories.md
  • docs/getting-started.md
  • docs/github-repository-ingestion.md
  • docs/ingestion.md
  • docs/pipeline-commands.md
  • docs/retrieval-pipeline.md
  • docs/type-safety-zod-validation.md
  • frontend/config/eslint.config.js
  • frontend/config/oxlintrc.json
  • frontend/package.json
  • frontend/rules/ast-grep/domain-types-in-schemas.yml
  • frontend/rules/ast-grep/no-core-record-unknown.yml
  • frontend/rules/ast-grep/no-domain-record-cast.yml
  • frontend/rules/ast-grep/no-record-string-unknown.yml
  • frontend/rules/ast-grep/no-zod-loose-types.yml
  • frontend/rules/ast-grep/types-are-not-schemas.yml
  • frontend/rules/ast-grep/warn-broken-contract-union.yml
  • frontend/src/lib/components/ChatView.svelte
  • frontend/src/lib/components/ChatView.test.ts
  • frontend/src/lib/components/LearnView.ownership.test.ts
  • frontend/src/lib/components/LearnView.svelte
  • frontend/src/lib/components/LearnView.test.ts
  • frontend/src/lib/components/MessageBubble.svelte
  • frontend/src/lib/components/MessageBubble.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/markdown.test.ts
  • frontend/src/lib/services/markdown.ts
  • frontend/src/lib/services/sse.test.ts
  • frontend/src/lib/validation/schemas.ts
  • frontend/src/lib/validation/validate.ts
  • frontend/src/test/citationPartialFailureStatus.ts
  • frontend/vite.config.ts
  • frontend/vitest.config.ts
  • gradle/libs.versions.toml
  • infra/docker-compose-qdrant.yml
  • scripts/atomic_exchange_directories.py
  • scripts/documentation_seed.py
  • scripts/fetch_all_docs.sh
  • scripts/lib/common_qdrant.sh
  • scripts/lib/documentation_fetch_metadata.sh
  • scripts/lib/documentation_fetch_sources.sh
  • scripts/lib/documentation_seed_mirrors.sh
  • scripts/lib/documentation_sources.sh
  • scripts/lib/embedding_preflight.sh
  • scripts/lib/github_identity.sh
  • scripts/migrate_qdrant_cloud_to_local.sh
  • scripts/monitor_indexing.sh
  • scripts/monitor_progress.sh
  • scripts/process_all_to_qdrant.sh
  • scripts/process_github_repo.sh
  • scripts/prune_retired_java_api_vectors.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_sync_failure_contract.sh
  • scripts/test_java_api_fetch_projection.sh
  • scripts/test_make_local_qdrant_bootstrap.sh
  • scripts/test_process_all_to_qdrant_environment.sh
  • scripts/test_process_all_to_qdrant_postconditions.sh
  • scripts/test_prune_retired_java_api_vectors.sh
  • scripts/test_qdrant_1_18_integration.sh
  • scripts/test_single_index.sh
  • scripts/update_all_github_repos.sh
  • src/main/java/com/williamcallahan/javachat/application/ingestion/DocumentationIngestionUseCase.java
  • src/main/java/com/williamcallahan/javachat/application/ingestion/FileLimit.java
  • src/main/java/com/williamcallahan/javachat/application/ingestion/PageLimit.java
  • src/main/java/com/williamcallahan/javachat/application/prompt/PromptTruncator.java
  • src/main/java/com/williamcallahan/javachat/application/search/JavaApiMethodSelector.java
  • src/main/java/com/williamcallahan/javachat/application/search/JavaInvocationSignature.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSet.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentationSetCatalog.java
  • src/main/java/com/williamcallahan/javachat/cli/GitHubRepoProcessor.java
  • src/main/java/com/williamcallahan/javachat/config/AppProperties.java
  • src/main/java/com/williamcallahan/javachat/config/DocsLocalPathMapper.java
  • src/main/java/com/williamcallahan/javachat/config/DocsSourceRegistry.java
  • src/main/java/com/williamcallahan/javachat/config/DocumentationConfig.java
  • src/main/java/com/williamcallahan/javachat/config/DocumentationManifestFieldRules.java
  • src/main/java/com/williamcallahan/javachat/config/DocumentationSeedDocumentTypeCatalog.java
  • src/main/java/com/williamcallahan/javachat/config/DocumentationSourceManifest.java
  • src/main/java/com/williamcallahan/javachat/config/EmbeddingConfig.java
  • src/main/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifest.java
  • src/main/java/com/williamcallahan/javachat/config/LocalEmbedding.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantClientConfig.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantCollectionNames.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantGitHubCollectionDiscovery.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantHealthIndicator.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantIndexInitializer.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantProperties.java
  • src/main/java/com/williamcallahan/javachat/config/QdrantRestConnection.java
  • src/main/java/com/williamcallahan/javachat/config/RemoteEmbedding.java
  • src/main/java/com/williamcallahan/javachat/config/SecurityConfig.java
  • src/main/java/com/williamcallahan/javachat/config/SpringDocsUrlNormalizer.java
  • src/main/java/com/williamcallahan/javachat/config/SystemPromptConfig.java
  • src/main/java/com/williamcallahan/javachat/domain/javaapi/JavadocMemberAnchor.java
  • src/main/java/com/williamcallahan/javachat/domain/markdown/EnrichmentKindCatalog.java
  • src/main/java/com/williamcallahan/javachat/domain/markdown/MarkdownEnrichment.java
  • src/main/java/com/williamcallahan/javachat/domain/prompt/ContextDocumentSegment.java
  • src/main/java/com/williamcallahan/javachat/domain/prompt/StructuredPrompt.java
  • src/main/java/com/williamcallahan/javachat/model/GuidedLesson.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/ChunkProcessingService.java
  • src/main/java/com/williamcallahan/javachat/service/CitationCandidateRanker.java
  • src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java
  • src/main/java/com/williamcallahan/javachat/service/DocumentFactory.java
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingBatchEmbedder.java
  • src/main/java/com/williamcallahan/javachat/service/EmbeddingModelKeepAlive.java
  • src/main/java/com/williamcallahan/javachat/service/ExternalServiceHealth.java
  • src/main/java/com/williamcallahan/javachat/service/FileIngestionMarkerStore.java
  • src/main/java/com/williamcallahan/javachat/service/GuidedLearningService.java
  • src/main/java/com/williamcallahan/javachat/service/GuidedTOCProvider.java
  • src/main/java/com/williamcallahan/javachat/service/HtmlContentExtractor.java
  • src/main/java/com/williamcallahan/javachat/service/HybridSearchService.java
  • src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java
  • src/main/java/com/williamcallahan/javachat/service/JavaApiAnchoredSection.java
  • src/main/java/com/williamcallahan/javachat/service/LocalStoreService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAIStreamingService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiCompatibleEmbeddingClient.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiPreparedRequest.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiProviderRoutingService.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiRequestFactory.java
  • src/main/java/com/williamcallahan/javachat/service/OpenAiResponseStreamException.java
  • src/main/java/com/williamcallahan/javachat/service/ProgressTracker.java
  • src/main/java/com/williamcallahan/javachat/service/QdrantPayloadFieldSchema.java
  • src/main/java/com/williamcallahan/javachat/service/QdrantRetrievalConstraintBuilder.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalConstraint.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalService.java
  • src/main/java/com/williamcallahan/javachat/service/StreamingResult.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestionProvenanceDeriver.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestionQuarantineService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestionStorageServices.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/JavaPackageExtractor.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/service/markdown/CitationProcessor.java
  • src/main/java/com/williamcallahan/javachat/service/markdown/EnrichmentPlaceholderizer.java
  • src/main/java/com/williamcallahan/javachat/support/JavaApiPageExtractor.java
  • src/main/java/com/williamcallahan/javachat/util/QueryVersionExtractor.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/IngestionController.java
  • src/main/java/com/williamcallahan/javachat/web/SseStatusContractCatalog.java
  • src/main/java/com/williamcallahan/javachat/web/SseSupport.java
  • src/main/resources/application-ci.properties
  • src/main/resources/application.properties
  • src/main/resources/docs-sources.properties
  • src/main/resources/documentation-seed-document-types.manifest
  • src/main/resources/documentation-sources.manifest
  • src/main/resources/enrichment-kinds.manifest
  • src/main/resources/guided/lessons/building-rest-apis-with-spring-boot.md
  • src/main/resources/guided/lessons/choosing-a-jvm-language.md
  • src/main/resources/guided/lessons/clojure-on-the-jvm.md
  • src/main/resources/guided/lessons/collections.md
  • src/main/resources/guided/lessons/data-access-and-testing-in-spring-boot.md
  • src/main/resources/guided/lessons/dependency-injection-and-configuration.md
  • src/main/resources/guided/lessons/groovy-on-the-jvm.md
  • src/main/resources/guided/lessons/interfaces-and-inheritance.md
  • src/main/resources/guided/lessons/modules.md
  • src/main/resources/guided/lessons/quarkus-fundamentals.md
  • src/main/resources/guided/lessons/spring-boot-fundamentals.md
  • src/main/resources/guided/lessons/spring-boot-vs-quarkus.md
  • src/main/resources/java-api-documentation-sources.manifest
  • src/main/resources/sse-status-contracts.json
  • src/test/java/com/williamcallahan/javachat/ExtractorQualityTest.java
  • src/test/java/com/williamcallahan/javachat/JavaChatApplicationTests.java
  • src/test/java/com/williamcallahan/javachat/StandaloneExtractionTest.java
  • src/test/java/com/williamcallahan/javachat/application/ingestion/IngestionLimitTest.java
  • src/test/java/com/williamcallahan/javachat/application/prompt/PromptTruncatorTest.java
  • src/test/java/com/williamcallahan/javachat/application/search/JavaApiMethodSelectorTest.java
  • src/test/java/com/williamcallahan/javachat/application/search/JavaInvocationSignatureTest.java
  • src/test/java/com/williamcallahan/javachat/cli/DocumentProcessorFailureContractTest.java
  • src/test/java/com/williamcallahan/javachat/cli/DocumentProcessorSelectionTest.java
  • src/test/java/com/williamcallahan/javachat/cli/DocumentationSourceCatalogParityTest.java
  • src/test/java/com/williamcallahan/javachat/cli/GitHubRepoProcessorIsolationTest.java
  • src/test/java/com/williamcallahan/javachat/cli/JavaApiDocumentationSourceParityTest.java
  • src/test/java/com/williamcallahan/javachat/config/AppPropertiesValidationTest.java
  • src/test/java/com/williamcallahan/javachat/config/DocsSourceRegistryTest.java
  • src/test/java/com/williamcallahan/javachat/config/DocumentationManifestFieldRulesTest.java
  • src/test/java/com/williamcallahan/javachat/config/DocumentationSourceManifestTest.java
  • src/test/java/com/williamcallahan/javachat/config/EmbeddingConfigStartupTest.java
  • src/test/java/com/williamcallahan/javachat/config/JavaApiDocumentationManifestTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantGitHubCollectionDiscoveryTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantHealthIndicatorTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantIndexInitializerTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantPropertiesTest.java
  • src/test/java/com/williamcallahan/javachat/config/QdrantRestConnectionTest.java
  • src/test/java/com/williamcallahan/javachat/config/SecurityConfigNonWebStartupTest.java
  • src/test/java/com/williamcallahan/javachat/config/SystemPromptConfigTest.java
  • src/test/java/com/williamcallahan/javachat/domain/ingestion/GitHubCollectionNamingScriptTest.java
  • src/test/java/com/williamcallahan/javachat/domain/javaapi/JavadocMemberAnchorTest.java
  • src/test/java/com/williamcallahan/javachat/domain/markdown/EnrichmentKindCatalogTest.java
  • src/test/java/com/williamcallahan/javachat/domain/markdown/MarkdownEnrichmentTest.java
  • src/test/java/com/williamcallahan/javachat/service/AuditServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ChunkProcessingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/CitationCandidateRankerTest.java
  • src/test/java/com/williamcallahan/javachat/service/DocsIngestionServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/DocumentFactoryTest.java
  • src/test/java/com/williamcallahan/javachat/service/EmbeddingBatchEmbedderTest.java
  • src/test/java/com/williamcallahan/javachat/service/EmbeddingProviderFailureTest.java
  • src/test/java/com/williamcallahan/javachat/service/EnrichmentServiceCacheTest.java
  • src/test/java/com/williamcallahan/javachat/service/ExternalServiceHealthTest.java
  • src/test/java/com/williamcallahan/javachat/service/GuidedLearningServiceCitationTest.java
  • src/test/java/com/williamcallahan/javachat/service/GuidedLessonCuratedContentTest.java
  • src/test/java/com/williamcallahan/javachat/service/GuidedTOCProviderTest.java
  • src/test/java/com/williamcallahan/javachat/service/HtmlContentExtractorTest.java
  • src/test/java/com/williamcallahan/javachat/service/HybridSearchServiceTest.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/LocalStoreServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/MarkdownServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingProviderFailureTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAIStreamingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAiCompatibleEmbeddingClientTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAiCompatibleEmbeddingClientWireTest.java
  • src/test/java/com/williamcallahan/javachat/service/OpenAiRequestFactoryTest.java
  • src/test/java/com/williamcallahan/javachat/service/QdrantRetrievalConstraintBuilderTest.java
  • src/test/java/com/williamcallahan/javachat/service/QdrantScoredPointDocumentMapperTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalConstraintTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceCitationTest.java
  • src/test/java/com/williamcallahan/javachat/service/RetrievalServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/IngestionProvenanceDeriverTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/IngestionQuarantineServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/JavaPackageExtractorTest.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/MalformedUtf8LocalDocsIngestionTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/SourceCodeFileIngestionProcessorTest.java
  • src/test/java/com/williamcallahan/javachat/service/markdown/EnrichmentPlaceholderizerTest.java
  • src/test/java/com/williamcallahan/javachat/support/EnvironmentVariablePrecedenceTest.java
  • src/test/java/com/williamcallahan/javachat/util/QueryVersionExtractorTest.java
  • src/test/java/com/williamcallahan/javachat/web/ChatControllerRetrievalDiagnosticsTest.java
  • src/test/java/com/williamcallahan/javachat/web/ChatControllerStreamingFailureTest.java
  • src/test/java/com/williamcallahan/javachat/web/ChatPreparationSseIntegrationTest.java
  • src/test/java/com/williamcallahan/javachat/web/GuidedLearningControllerBackpressureOverflowTest.java
  • src/test/java/com/williamcallahan/javachat/web/GuidedLearningControllerCuratedContentTest.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/IngestionControllerTest.java
  • src/test/java/com/williamcallahan/javachat/web/SseStatusContractCatalogTest.java
  • src/test/java/com/williamcallahan/javachat/web/SseSupportTest.java
  • src/test/resources/application-test.properties

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

📝 Walkthrough

Walkthrough

The pull request adds canonical documentation-source selection, batch Java API seed projection, release-aware Javadoc seeding, retired-vector pruning, structured Java API extraction with exact anchors, replacement-aware ingestion, and updated citation metadata handling with extensive tests.

Changes

Documentation pipeline

Layer / File(s)Summary
Canonical selection and cleanup
scripts/fetch_all_docs.sh, scripts/prune_retired_java_api_vectors.sh, scripts/process_all_to_qdrant.sh
Adds canonical cross-manifest selectors and pre-ingestion Qdrant pruning with batched deletion and verification.
Seed generation and documentation
scripts/documentation_seed.py, scripts/lib/documentation_seed_mirrors.sh, scripts/oracle_javadoc_seed.py, docs/pipeline-commands.md, src/main/resources/java-api-documentation-sources.manifest
Adds batch mirror projection, release-specific Javadoc roots, excludes class-use URLs, updates selector documentation, and lowers Java API HTML thresholds.

Java API ingestion

Layer / File(s)Summary
Structured extraction and chunk metadata
src/main/java/com/williamcallahan/javachat/service/HtmlContentExtractor.java, ChunkProcessingService.java, DocumentFactory.java, JavaApi*.java
Extracts overview and member sections with exact DOM anchors and carries anchors through validated chunk metadata and hashing.
Replacement-aware storage
src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java, HybridVectorService.java, LocalStoreService.java, ingestion/*
Adds deterministic point-identity checks, complete URL replacement, obsolete marker/chunk pruning, and Java API-specific local ingestion behavior.
Application wiring
src/main/java/com/williamcallahan/javachat/application/ingestion/DocumentationIngestionUseCase.java, cli/DocumentProcessor.java, web/IngestionController.java
Introduces the ingestion use-case boundary and wires CLI and web entry points to it.

Validation

Layer / File(s)Summary
Regression and integration coverage
scripts/test_*, src/test/java/com/williamcallahan/javachat/service/*, src/test/java/com/williamcallahan/javachat/service/ingestion/*
Tests selector routing, seed generation, extraction immutability, exact anchors, replacement identity, pruning, citation behavior, and ingestion failure handling.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • WilliamAGH/java-chat issue 95 — covers the same Javadoc anchor citation behavior updated in RetrievalService.

Possibly related PRs

Suggested labels:bug, documentation, java, refactor

Suggested reviewers:copilot

Poem

Anchors bloom where Javadocs flow,
Old vectors fade, new chunks grow.
Select a source, inspect the page,
Qdrant turns a cleaner age.
Seeds march on, precise and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 24.32% 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 nameStatusExplanation
Title check✅ PassedThe title clearly matches the core change: preserving exact Javadoc member citations instead of heuristic rewriting.
Description check✅ PassedThe description is detailed and directly aligned with the PR’s Javadoc citation, ingestion, and mirror-pruning changes.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 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.

@coderabbitaicoderabbitaiBot added bug Something isn't working documentation Improvements or additions to documentation java Pull requests that update java code refactor Code refactoring labels Jul 18, 2026

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.

Pull request overview

This PR updates the documentation ingestion and retrieval pipeline to preserve exact Oracle Javadoc member anchors as first-class metadata (separate from fragmentless page URLs), and makes both remote and local reindexing more deterministic/atomic by replacing URL-scoped Qdrant point sets based on stable point IDs rather than point counts.

Changes:

  • Introduces structured Java API extraction (JavaApiPageExtraction) that keeps overview text separate from anchored member sections, and threads an exact anchor metadata field through chunking → storage → citation rendering.
  • Replaces heuristic Javadoc URL/member rewriting with “use ingested source identity” behavior, and adds URL replacement semantics in Qdrant (replaceUrlDocuments) plus exact point-ID coverage checks.
  • Adds strict retired-Java-API vector pruning (class-use pages + redirect-backed root type pages) and strengthens fetch/seed tooling around canonical selector identities.

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
src/test/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizerTest.javaRemoves tests for heuristic member/type canonicalization (feature removed).
src/test/java/com/williamcallahan/javachat/StandaloneExtractionTest.javaUpdates diagnostics to use extractJavaApiPage(...).combinedText().
src/test/java/com/williamcallahan/javachat/service/RetrievalServiceCitationTest.javaUpdates citation tests for exact-anchor metadata behavior and de-heuristicization.
src/test/java/com/williamcallahan/javachat/service/LocalStoreServiceTest.javaAdds coverage for deleting obsolete ingestion markers by stored hash prefixes.
src/test/java/com/williamcallahan/javachat/service/ingestion/MalformedUtf8LocalDocsIngestionTest.javaAdjusts malformed UTF-8 behavior expectations to account for prune boundary changes.
src/test/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneServiceTest.javaAdds tests for preserving replacement parsed chunks and hash-prefix marker cleanup.
src/test/java/com/williamcallahan/javachat/service/HybridVectorServiceTest.javaAdds tests for exact point-id coverage and atomic URL replacement semantics.
src/test/java/com/williamcallahan/javachat/service/HtmlContentExtractorTest.javaAdds tests for exact DOM anchors, class-use exclusion, and non-mutating extraction.
src/test/java/com/williamcallahan/javachat/service/DocsIngestionServiceTest.javaAdds tests for fragmentless crawl, Java API segmentation, replacement logic, and class-use deletion.
src/test/java/com/williamcallahan/javachat/service/ChunkProcessingServiceTest.javaAdds tests for Java API page segmentation, anchor hashing, and fragmentless URL validation.
src/test/java/com/williamcallahan/javachat/ExtractorQualityTest.javaUpdates extraction quality checks to use the new Java API extraction shape.
src/main/resources/java-api-documentation-sources.manifestAdjusts minimum HTML file thresholds for governed Java API mirrors.
src/main/java/com/williamcallahan/javachat/web/IngestionController.javaRoutes ingestion through a new application boundary (DocumentationIngestionUseCase).
src/main/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizer.javaRemoves heuristic type canonicalizer (no longer used).
src/main/java/com/williamcallahan/javachat/util/JavadocNestedTypeResolver.javaRemoves heuristic nested-type URL refinement.
src/main/java/com/williamcallahan/javachat/util/JavadocMemberAnchorResolver.javaRemoves heuristic member-anchor derivation.
src/main/java/com/williamcallahan/javachat/util/JavadocLinkResolver.javaRemoves heuristic Javadoc link resolver facade.
src/main/java/com/williamcallahan/javachat/service/RetrievalService.javaSwitches citations to use ingested exact-anchor metadata and canonicalizes URLs accordingly.
src/main/java/com/williamcallahan/javachat/service/QdrantPayloadFieldSchema.javaAdds ANCHOR_FIELD to the canonical Qdrant metadata schema.
src/main/java/com/williamcallahan/javachat/service/LocalStoreService.javaAdds strict deletion of obsolete chunk markers selected by stored hash prefixes.
src/main/java/com/williamcallahan/javachat/service/JavaApiPageExtraction.javaNew record representing overview + anchored member extraction for Java API pages.
src/main/java/com/williamcallahan/javachat/service/JavaApiPageDisposition.javaNew enum classifying whether Java API pages are indexable (e.g., class-use excluded).
src/main/java/com/williamcallahan/javachat/service/JavaApiAnchoredSection.javaNew record preserving one authoritative member anchor + member text.
src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.javaMoves to exact-point-id coverage checks and Java API structured ingestion + exclusion handling.
src/main/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneService.javaAdds “prune obsolete state after replacement” path (vectors + markers + parsed chunks).
src/main/java/com/williamcallahan/javachat/service/HybridVectorService.javaAdds atomic URL replacement and exact point-id coverage checks via Qdrant scroll identity.
src/main/java/com/williamcallahan/javachat/service/HtmlContentExtractor.javaAdds structured Java API extraction (exact DOM anchors, class-use exclusion) and avoids mutation via cloning.
src/main/java/com/williamcallahan/javachat/service/DocumentFactory.javaIntroduces canonical chunk metadata record including optional exact anchor field.
src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.javaImplements new ingestion use case boundary; adds fragmentless crawling + URL replacement ingestion flow.
src/main/java/com/williamcallahan/javachat/service/ChunkProcessingService.javaAdds Java API page chunking with anchor-aware deterministic hashing and global chunk indexing.
src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.javaDepends on DocumentationIngestionUseCase instead of concrete service.
src/main/java/com/williamcallahan/javachat/application/ingestion/DocumentationIngestionUseCase.javaNew application boundary interface for ingestion runs.
scripts/test_prune_retired_java_api_vectors.shNew script-level test harness for retired Java API vector pruning without live Qdrant.
scripts/test_java_api_fetch_projection.shExtends tests to verify selector routing between non-Java docs and Java API projections.
scripts/test_documentation_seed.pyAdds tests for batch mirror-path projection and Oracle Javadoc seed constraints.
scripts/prune_retired_java_api_vectors.shNew strict pruning script for retired Java API vectors (class-use + redirect-backed roots).
scripts/process_all_to_qdrant.shRuns retired Java API prune before ingestion based on effective selector.
scripts/oracle_javadoc_seed.pyMakes root-page seed inventory release-correct; removes class-use seed generation.
scripts/lib/documentation_seed_mirrors.shSwitches to batch mirror-path projection for Java API seeds.
scripts/fetch_all_docs.shStrengthens --doc-sets to select canonical identities across both manifests before fetching.
scripts/documentation_seed.pyAdds --project-mirror-paths-file for batch projection and collision validation.
docs/pipeline-commands.mdUpdates docs for the new selector semantics and adds examples.

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

Comment on lines +274 to +279
private static boolean belongsToReplacement(
ParsedChunkReference parsedChunkReference, Set<String> replacementHashSet) {
return replacementHashSet.stream()
.anyMatch(replacementChunkHash ->
replacementChunkHash.startsWith(parsedChunkReference.storedChunkHashPrefix()));
}
Comment on lines 474 to 476
/**
* Refines a raw document URL and gates Javadoc member anchors to {@code api-docs} metadata.
*
* Projects an authoritative ingested Javadoc anchor before applying legacy nested-type refinement.
*/

@coderabbitaicoderabbitaiBot 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: 10

Caution

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

⚠️ Outside diff range comments (3)
src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java (2)

341-350: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Return a typed marker-transition failure on the skipped path.

markFileIngested wraps write failures in IllegalStateException, but this call is outside a catch block. A marker filesystem error therefore escapes process and can abort the batch instead of returning a failed LocalDocsFileOutcome.

🤖 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/ingestion/LocalDocsFileIngestionProcessor.java`
around lines 341 - 350, Update the skipped-file path in process around
markFileIngested so marker filesystem failures are caught and converted into the
typed failed LocalDocsFileOutcome, matching the processor’s existing failure
handling. Preserve the skip logging and successful marker update behavior, and
ensure the exception does not escape process or abort the batch.

361-614: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Extract the newly added workflows from the two monolithic services.

  • src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java#L361-L614: move marker/reindex policy and replacement persistence into focused application components.
  • src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java#L401-L484: move URL-scoped scrolling, identity reconciliation, and obsolete-point deletion into a focused Qdrant component.

As per coding guidelines, “>500 LOC is a monolith. Extract pieces you touch into clean-architecture roots (Large Files).”

🤖 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/ingestion/LocalDocsFileIngestionProcessor.java`
around lines 361 - 614, Extract the marker/reindex policy and replacement
persistence workflow from LocalDocsFileIngestionProcessor methods
inspectExistingMarker, inspectUnmarkedVectors, supersededCollectionNames,
processDocuments, storeDocuments, and marker methods into focused application
components, updating the processor to delegate while preserving behavior. Also
update
src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java
lines 401-484 by extracting URL-scoped scrolling, identity reconciliation, and
obsolete-point deletion into a focused Qdrant component, with
HybridVectorService delegating to it; both sites require these extractions
without changing existing outcomes.

Source: Coding guidelines

src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java (1)

183-205: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate every hash before replacing the Qdrant corpus.

Line 197 silently skips missing hash metadata after Qdrant has already been replaced, leaving local markers inconsistent. Build and validate all marker inputs before the external mutation; fail the run if any replacement document lacks its hash.

As per coding guidelines, “Use typed exception handling patterns; propagate meaningful errors, never swallow silently.”

🤖 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/DocsIngestionService.java`
around lines 183 - 205, The replaceAndMarkDocuments flow must validate every
replacement document’s hash before calling
hybridVectorService.replaceUrlDocuments. Update markDocumentsIngested or
introduce a validation step to reject any document missing
QdrantPayloadFieldSchema.HASH_FIELD, propagating a meaningful typed exception
instead of silently continuing; only perform the Qdrant replacement after
validation succeeds.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/test/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessorTest.java (1)

620-649: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the six-argument helper with a test fixture object.

The added overload extends an already long positional collaborator train, making call-site mistakes increasingly easy. Bundle these dependencies into a named test fixture or builder.

As per coding guidelines, “>4 parameters use parameter object or builder; never add 5th positional argument.”

🤖 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/ingestion/LocalDocsFileIngestionProcessorTest.java`
around lines 620 - 649, Replace the overloaded six-argument
createIngestionProcessor helpers with a named test fixture or builder that
groups the collaborator dependencies, including quarantineService. Update all
call sites to construct or configure this fixture and pass it to
createIngestionProcessor, eliminating the positional parameter train while
preserving the existing default mock behavior.

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.
Inline comments:
In `@docs/pipeline-commands.md`:
- Around line 93-97: Update the Java API refresh example in the documentation to
obtain selector values from --list-java-api-sources instead of hard-coding the
current release list. Keep the example manifest-driven so future Java API
sources are included automatically, and remove the explicit
java/java21-complete, java/java24-complete, and java/java25-complete inventory.
In
`@src/main/java/com/williamcallahan/javachat/application/ingestion/DocumentationIngestionUseCase.java`:
- Line 15: Replace the raw int ingestion limits in
DocumentationIngestionUseCase.crawlAndIngest and its related API boundaries with
validated PageLimit and FileLimit records. Add constructor validation rejecting
zero or negative values, and update CLI, tests, and direct callers to construct
these records only after transport/input validation so ingestion always receives
valid application values.
In
`@src/main/java/com/williamcallahan/javachat/service/ChunkProcessingService.java`:
- Around line 375-406: Remove Optional-valued constructor inputs from the
segment models: in ChunkProcessingService.java lines 375-406, keep
JavaApiPageSegment construction behind the overview and member factories, and in
lines 436-452 retain any nullable anchor representation privately; callers must
not supply Optional. In DocumentFactory.java lines 167-230, preserve the
withAnchor and withoutAnchor factories while encapsulating absent-anchor
handling inside their implementation.
In
`@src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java`:
- Around line 254-260: Update fetchPageSnapshot to use a named maximum
response-size constant instead of maxBodySize(0), and configure jsoup to enforce
that cap. Ensure oversized responses fail the crawl before full body
materialization, while retaining the existing snapshot preparation for responses
within the limit.
- Around line 57-65: Update the DocsIngestionService constructor to inject
AppProperties instead of the `@Value` app.docs.root-url parameter, then initialize
the root URL from AppProperties.getDocs().getRootUrl(). Remove the direct `@Value`
wiring while leaving the other constructor dependencies unchanged.
- Around line 239-244: Update the link-discovery flow in DocsIngestionService
around removeUrlFragment to normalize the configured root and candidate URLs as
parsed origin/path components rather than relying on startsWith(rootUrl). Before
queueing or continuing any crawl, validate the final response URL after
redirects and reject URLs whose host, port, or path falls outside the configured
source boundary.
In
`@src/main/java/com/williamcallahan/javachat/service/HtmlContentExtractor.java`:
- Around line 28-33: Extract the Java API-specific page classification,
overview, anchor parsing, and member extraction logic from HtmlContentExtractor
into a new focused JavaApiPageExtractor under the project’s canonical
architecture root, placing its extraction contract alongside it or in an
adjacent canonical location. Update HtmlContentExtractor to delegate to this
component while retaining only generic HTML cleanup responsibilities, and
preserve the existing public behavior.
In
`@src/main/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneService.java`:
- Around line 120-132: In the cleanup flow containing parsedChunkReferences and
obsoleteChunkHashes, invoke deleteObsoleteChunkIngestionMarkersByHashPrefixes
before deleteChunkIngestionMarkers so ambiguous prefixes fail closed before any
exact-marker deletion occurs. Preserve the existing arguments and subsequent
deleteObsoleteParsedChunks call.
In
`@src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java`:
- Around line 287-326: The ingestion flow around chunkingOutcome.documents()
currently accepts partial results; update it to trigger the existing
force-processing path whenever chunkingOutcome.skippedChunks() is greater than
zero, not only when chunkingOutcome.skippedAllChunks() is true. Ensure the
complete forced document set is processed and its hashes recorded, while
retaining the current fast path for outcomes with no skipped chunks.
In
`@src/main/java/com/williamcallahan/javachat/service/JavaApiAnchoredSection.java`:
- Around line 14-30: Make JavadocMemberAnchor the single validated domain type
for exact DOM identifiers: add and validate this record in
JavaApiAnchoredSection.java, then change JavaApiAnchoredSection to accept it. In
ChunkProcessingService.java lines 464-471, remove the local anchor validator and
construct/use JavadocMemberAnchor. In DocumentFactory.java lines 240-245, remove
its duplicate validation and serialize the canonical anchor’s string value.
---
Outside diff comments:
In
`@src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java`:
- Around line 183-205: The replaceAndMarkDocuments flow must validate every
replacement document’s hash before calling
hybridVectorService.replaceUrlDocuments. Update markDocumentsIngested or
introduce a validation step to reject any document missing
QdrantPayloadFieldSchema.HASH_FIELD, propagating a meaningful typed exception
instead of silently continuing; only perform the Qdrant replacement after
validation succeeds.
In
`@src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java`:
- Around line 341-350: Update the skipped-file path in process around
markFileIngested so marker filesystem failures are caught and converted into the
typed failed LocalDocsFileOutcome, matching the processor’s existing failure
handling. Preserve the skip logging and successful marker update behavior, and
ensure the exception does not escape process or abort the batch.
- Around line 361-614: Extract the marker/reindex policy and replacement
persistence workflow from LocalDocsFileIngestionProcessor methods
inspectExistingMarker, inspectUnmarkedVectors, supersededCollectionNames,
processDocuments, storeDocuments, and marker methods into focused application
components, updating the processor to delegate while preserving behavior. Also
update
src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java
lines 401-484 by extracting URL-scoped scrolling, identity reconciliation, and
obsolete-point deletion into a focused Qdrant component, with
HybridVectorService delegating to it; both sites require these extractions
without changing existing outcomes.
---
Nitpick comments:
In
`@src/test/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessorTest.java`:
- Around line 620-649: Replace the overloaded six-argument
createIngestionProcessor helpers with a named test fixture or builder that
groups the collaborator dependencies, including quarantineService. Update all
call sites to construct or configure this fixture and pass it to
createIngestionProcessor, eliminating the positional parameter train while
preserving the existing default mock behavior.
🪄 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: 7bf67b10-7722-4464-bfd6-25cac31e07f3

📥 Commits

Reviewing files that changed from the base of the PR and between 76420a2 and 1263e64.

📒 Files selected for processing (43)
  • docs/pipeline-commands.md
  • scripts/documentation_seed.py
  • scripts/fetch_all_docs.sh
  • scripts/lib/documentation_seed_mirrors.sh
  • scripts/oracle_javadoc_seed.py
  • scripts/process_all_to_qdrant.sh
  • scripts/prune_retired_java_api_vectors.sh
  • scripts/test_documentation_seed.py
  • scripts/test_java_api_fetch_projection.sh
  • scripts/test_prune_retired_java_api_vectors.sh
  • src/main/java/com/williamcallahan/javachat/application/ingestion/DocumentationIngestionUseCase.java
  • src/main/java/com/williamcallahan/javachat/cli/DocumentProcessor.java
  • src/main/java/com/williamcallahan/javachat/service/ChunkProcessingService.java
  • src/main/java/com/williamcallahan/javachat/service/DocsIngestionService.java
  • src/main/java/com/williamcallahan/javachat/service/DocumentFactory.java
  • src/main/java/com/williamcallahan/javachat/service/HtmlContentExtractor.java
  • src/main/java/com/williamcallahan/javachat/service/HybridVectorService.java
  • src/main/java/com/williamcallahan/javachat/service/JavaApiAnchoredSection.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/LocalStoreService.java
  • src/main/java/com/williamcallahan/javachat/service/QdrantPayloadFieldSchema.java
  • src/main/java/com/williamcallahan/javachat/service/RetrievalService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/IngestedFilePruneService.java
  • src/main/java/com/williamcallahan/javachat/service/ingestion/LocalDocsFileIngestionProcessor.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocLinkResolver.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocMemberAnchorResolver.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocNestedTypeResolver.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizer.java
  • src/main/java/com/williamcallahan/javachat/web/IngestionController.java
  • 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/service/ChunkProcessingServiceTest.java
  • src/test/java/com/williamcallahan/javachat/service/DocsIngestionServiceTest.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/LocalStoreServiceTest.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/LocalDocsFileIngestionProcessorTest.java
  • src/test/java/com/williamcallahan/javachat/service/ingestion/MalformedUtf8LocalDocsIngestionTest.java
  • src/test/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizerTest.java
💤 Files with no reviewable changes (5)
  • src/main/java/com/williamcallahan/javachat/util/JavadocMemberAnchorResolver.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocLinkResolver.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocNestedTypeResolver.java
  • src/test/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizerTest.java
  • src/main/java/com/williamcallahan/javachat/util/JavadocTypeCanonicalizer.java

Comment threaddocs/pipeline-commands.md
Comment on lines +120 to +132
List<ParsedChunkReference> parsedChunkReferences = readParsedChunkReferences(sourceUrl);
Set<String> obsoleteChunkHashes = new LinkedHashSet<>();
if (previousFileRecord != null) {
obsoleteChunkHashes.addAll(previousFileRecord.chunkHashes());
}
obsoleteChunkHashes.removeAll(replacementHashSet);
if (!obsoleteChunkHashes.isEmpty()) {
localStoreService.deleteChunkIngestionMarkers(List.copyOf(obsoleteChunkHashes));
}
localStoreService.deleteObsoleteChunkIngestionMarkersByHashPrefixes(
obsoleteStoredHashPrefixes(parsedChunkReferences, replacementHashSet),
List.copyOf(replacementChunkHashes));
deleteObsoleteParsedChunks(parsedChunkReferences, replacementHashSet);

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Check prefix ambiguity before deleting any exact markers.

deleteChunkIngestionMarkers mutates state before deleteObsoleteChunkIngestionMarkersByHashPrefixes can reject an ambiguous prefix. If ambiguity is found, cleanup has already partially completed. Invoke the prefix-based fail-closed operation first, then delete remaining exact hashes.

Proposed ordering
- if (!obsoleteChunkHashes.isEmpty()) {- localStoreService.deleteChunkIngestionMarkers(List.copyOf(obsoleteChunkHashes));- }
localStoreService.deleteObsoleteChunkIngestionMarkersByHashPrefixes(
obsoleteStoredHashPrefixes(parsedChunkReferences, replacementHashSet),
List.copyOf(replacementChunkHashes));
+ if (!obsoleteChunkHashes.isEmpty()) {+ localStoreService.deleteChunkIngestionMarkers(List.copyOf(obsoleteChunkHashes));+ }
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
List<ParsedChunkReference> parsedChunkReferences = readParsedChunkReferences(sourceUrl);
Set<String> obsoleteChunkHashes = newLinkedHashSet<>();
if (previousFileRecord != null) {
obsoleteChunkHashes.addAll(previousFileRecord.chunkHashes());
}
obsoleteChunkHashes.removeAll(replacementHashSet);
if (!obsoleteChunkHashes.isEmpty()) {
localStoreService.deleteChunkIngestionMarkers(List.copyOf(obsoleteChunkHashes));
}
localStoreService.deleteObsoleteChunkIngestionMarkersByHashPrefixes(
obsoleteStoredHashPrefixes(parsedChunkReferences, replacementHashSet),
List.copyOf(replacementChunkHashes));
deleteObsoleteParsedChunks(parsedChunkReferences, replacementHashSet);
List<ParsedChunkReference> parsedChunkReferences = readParsedChunkReferences(sourceUrl);
Set<String> obsoleteChunkHashes = newLinkedHashSet<>();
if (previousFileRecord != null) {
obsoleteChunkHashes.addAll(previousFileRecord.chunkHashes());
}
obsoleteChunkHashes.removeAll(replacementHashSet);
localStoreService.deleteObsoleteChunkIngestionMarkersByHashPrefixes(
obsoleteStoredHashPrefixes(parsedChunkReferences, replacementHashSet),
List.copyOf(replacementChunkHashes));
if (!obsoleteChunkHashes.isEmpty()) {
localStoreService.deleteChunkIngestionMarkers(List.copyOf(obsoleteChunkHashes));
}
deleteObsoleteParsedChunks(parsedChunkReferences, replacementHashSet);
🤖 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/ingestion/IngestedFilePruneService.java`
around lines 120 - 132, In the cleanup flow containing parsedChunkReferences and
obsoleteChunkHashes, invoke deleteObsoleteChunkIngestionMarkersByHashPrefixes
before deleteChunkIngestionMarkers so ambiguous prefixes fail closed before any
exact-marker deletion occurs. Preserve the existing arguments and subsequent
deleteObsoleteParsedChunks call.

@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:1263e6496c

ℹ️ 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".

@@ -247,41 +287,43 @@ public LocalDocsFileOutcome process(Path root, Path file) {
List<Document> documents = chunkingOutcome.documents();
if (!documents.isEmpty()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Force complete local replacements after partial skips

When local chunk-hash markers cause only some chunks to be skipped but Qdrant is missing the skipped points, such as after a collection reset that leaves data/index intact, this early return upserts only the non-skipped documents and then records the full chunk-hash inventory for the file. The run reports success while the URL is missing every skipped chunk until a later ingestion happens to detect the exact-ID mismatch, so the local path needs the same complete-replacement check used by the crawler before marking the file complete.

Useful? React with 👍 / 👎.

A canceled bounded-elastic retrieval could finish after the test that created it, leaking an unrelated pipeline error into the next test's global log capture. Synchronize the actual retrieval task before disposing the stream so suite order and machine timing cannot change the outcome.
The test's real sleep could consume the entire shared query deadline under
loaded CI scheduling. Sequential dispatch timestamps already verify that later
queries receive the remaining budget without making the assertion flaky.
The guided lesson page header already owns the lesson title, so remove each
curated document's duplicate opening heading. Guard the content resources so a
second primary heading cannot be reintroduced.
Track malformed URL-scoped parsed files as obsolete cleanup candidates while
keeping unverified hashes away from ingestion-marker deletion. This prevents
corrupt local artifacts from surviving every replacement run.
Select the runtime constructor explicitly when Spring sees the service's test
constructor. Cover CLI-profile context creation so batch ingestion cannot fail
before document processing begins.
Keep GitHub synchronization with its direct runtime owner and fail when active-generation discovery or repository metadata cannot be verified.
Own source selection, stable-version validation, citation provenance, and configurable documentation roots at their runtime boundaries.
Align the OpenAI client, Qdrant client and server, and gRPC stack while isolating local Qdrant storage for the new embedding generation.
Use Qwen 4B at 2,560 native dimensions with intent-specific gateway tiers, strict response validation, and no competing remote provider path.
Require exact 4B/2,560 core schemas and active GitHub prefixes, and keep readiness down when governed collection validation fails.
Extract plural Java release requests, search each requested API generation under exact source constraints, and preserve per-release evidence through reranking and final prompt limits. Keep guided prompts scoped to the requested releases while leaving non-Java lesson retrieval unconstrained by incidental Java version mentions.
Reserve the floating chat control footprint in the lesson scrollport's programmatic target area so expanded source links are not obscured on mobile. Correct the modules lesson's duplicate greeting punctuation.
A query naming an exact Java method overload (for example
java.util.List.of(E, E)) was routed through the general reranker, which
scores candidates by semantic similarity and can rank a package-use or
overview page above the authoritative overload page. Multi-release
comparisons could therefore answer from documents that never described
the requested overload.
Exact-overload queries now retrieve Java API citation candidates
directly, order them with CitationCandidateRanker, and skip reranking
entirely. Missing evidence raises instead of silently degrading to
whatever the reranker surfaced, and each requested release must supply
its own evidence. Detection is gated on the retrieval constraint
targeting a Java API doc set, so non-Java scopes that merely mention
Java syntax keep the ordinary reranked path.
- Add requiresExactJavaOverloadEvidence to gate the exact-overload path
on JavaApiMethodSelector plus the constraint's Java API doc sets
- Add requireExactOverloadEvidence to fail loudly when a requested
release has no official overload evidence
- Retrieve and order exact-overload candidates in retrieveCandidates and
bypass rerankerService when building prompt documents
- Cover multi-release exact-overload grounding and the non-Java scope
exclusion in RetrievalServiceTest
Parse chained Thread.Builder.start parameters without collapsing malformed identifier whitespace. Preserve exact Javadoc routing only for the supported Runnable signatures and keep unknown chains on broad retrieval.
Send repository guidance through the Responses API instructions field while keeping context and learner input separate. Strengthen Java code validity and current virtual-thread terminology at the prompt owner.
Disable gRPC idle mode at the pinned implementation's exact threshold so retrieval does not spend its shared query budget reconnecting after quiet periods.
Complete undispatched collection futures with the actual shared-budget failure instead of leaving them pending and misreporting a downstream Qdrant timeout.
Return stable retry guidance for retrieval and reranking failures without exposing exception classes, collection names, or upstream messages anywhere in the SSE payload.
Upgrade the lint and validation toolchain to releases that consume the
patched brace-expansion API without compatibility overrides. Migrate the
renamed Zod lint rule and retain the established Vitest mock policy.
Keep every Oxlint entry point scoped to project files when Docker installs
node_modules without the repository ignore file. This restores the image
validation stage after the lint toolchain upgrade.
Route local, dev, and production through the same generation-specific
collection names while retaining profile-scoped ingestion state. Reject
legacy environment-prefixed routing and fail readiness for unhealthy
Qdrant collections.
Cover shared core and GitHub naming at Java and shell boundaries and
update the operational documentation to match the runtime contract.
Own the normal runtime collection-creation policy in Spring properties so
only explicit ingestion and ephemeral CI profiles may bootstrap missing
Qdrant collections.
Keep remote Qdrant startup fail-closed while allowing local developer
commands to initialize schemas on loopback-only instances. Document and
test the fresh local startup contract.
The recursive release-note crawl admitted unrelated Java 26 pages into the governed Java 25 source root. Publish the single canonical page with the verified request identity while retaining atomic staging and source validation.
- Fetch only the stable Java 25 release-notes page
- Verify the dispatch and browser request identity
The shell preflight could issue embedding probes too quickly and ignored provider Retry-After backpressure. Enforce the locked embedding generation before network access and pace every batch-tier request without allowing unsafe retry values.
- Require qwen 4B vectors at exactly 2560 dimensions
- Honor bounded Retry-After values for all failed statuses
- Verify one-second pacing and fail-closed response validation
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 documentationjavaPull requests that update java coderefactorCode refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@WilliamAGH