Skip to content

[Detail Bug] Java version extraction misreads time-quantity phrases like "Java 6 months ago" as release requests #245

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_cbeea9a2-5f20-431d-b7dc-1fd583a4c9c5

Introduced in cacf649 by @WilliamAGH on Sep 1, 2026

Summary

  • Context: QueryVersionExtractor.extractVersionNumbers parses learner queries to find Java release versions. It has three production callers: (1) RetrievalService.queryVersionEvidence scopes Java API documentation retrieval from its result (RetrievalService.java:656, :669) on the default chat path; (2) ChatService.buildContextSegments calls extractVersionNumbers again directly (ChatService.java:279) to label per-document source-record headers; (3) GuidedLearningService.buildStructuredGuidedPromptWithContext calls it (GuidedLearningService.java:236) to choose retrieval context doc sets on the guided-learning path. QueryVersionExtractor.boostQueryWithVersionContext also rewrites the hybrid-search query from the retained tokens (RetrievalService.java:354 → QueryVersionExtractor.java:62-65).
  • Bug: The EXPLICIT_QUANTITY_SUFFIX_PATTERN added by commit cacf6493 to reject Java <N> <time-unit> quantity phrases omits the most common time units — years, weeks, months — while rejecting days?|hours?|minutes?|seconds?|times|lines?.
  • Actual vs. expected: A temporal phrase such as switched to Java 6 months ago extracts [�"6�] as a Java release. The expected behavior is []. The report's basis for "expected" is an inference (see "Evidence: hypothesised intent, not evidenced"), not a stated rule.
  • Impact: All three consumption paths receive a spurious version token, but the impact on each is mild:
    • Guided-learning path: the retrieval supplements for a Java lesson lose the dev-java source (Oracle's external tutorial content from dev.java/learn/) and are narrowed to java/java21-complete (API reference, v21) instead of dev-java + java/java25-complete. The lesson's own prose tutorial — the curated markdown at src/main/resources/guided/lessons/<slug>.md — is loaded unconditionally and prioritised HIGH regardless of the bug (see "Guided-learning path: what is and isn't lost"). So the consequence is a degradation of retrieval-supplement diversity (tutorial+API → API-only), not a loss of all tutorial prose.
    • Chat path: the configured default (Java 25) retrieval scope becomes a spurious Java 21 scope — a swap between two valid, current Java API corpora, so practical degradation is mild.
    • Header injection: a requestedVersions="6" header is injected into the LLM context, byte-for-byte identical to what the system intentionally emits for a genuine out-of-range Java 6 request — the bug changes whether that path is taken, not what it emits.

Code with Bug

private static final Pattern EXPLICIT_QUANTITY_SUFFIX_PATTERN =
        Pattern.compile("[\\s-]+(?:days?|hours?|minutes?|seconds?|times|lines?)\\b", Pattern.CASE_INSENSITIVE); // <-- BUG 🔴 missing years?|weeks?|months?
quantitySuffixMatcher.region(explicitVersionMatcher.end(), query.length());
if (quantitySuffixMatcher.lookingAt()) {
    continue;   // only fires when the noun after the digits is one of days/hours/minutes/seconds/times/line[s]
}
retainedVersions.add(explicitVersionMatcher.group(1));

Explanation

extractVersionNumbers first matches Java|JDK ... <digits> and then uses EXPLICIT_QUANTITY_SUFFIX_PATTERN to skip extraction when the digits are immediately followed by a “quantity noun” (e.g., Java 100 days of practice). Because the suffix pattern does not include months|weeks|years, phrases like Java 6 months ago are not recognized as quantity phrases and the digits are retained as a requested Java version.

This spurious token is then consumed by multiple flows:

  • Guided learning: requestedVersions becomes non-empty, so effectiveDocSetsFor(...) replaces the lesson’s normal doc sets (dev-java + java/java25-complete) with Java API-only doc sets resolved from the spurious version (ultimately java/java21-complete), reducing retrieved supplement diversity.
  • Chat retrieval: the spurious token causes version evidence to resolve to Java 21 and overrides the configured default Java 25 scope.
  • Context headers: ChatService.buildContextSegments embeds requestedVersions="6" in the source-record header for Java docs, matching the “adjacent-same-family” pathway.

Recommended Fix

Extend the suffix pattern and add test cases:

private static final Pattern EXPLICIT_QUANTITY_SUFFIX_PATTERN =
        Pattern.compile("[\\s-]+(?:days?|hours?|minutes?|seconds?|times|lines?|weeks?|months?|years?)\\b", Pattern.CASE_INSENSITIVE); // <-- FIX 🟢 add weeks?|months?|years?

Caveat: this expands existing word-hyphen false positives (already present for days?) to new noun-hyphen compounds such as Java N year-ahead / month-release / week-long.

History

This bug was introduced in commit cacf649. The commit added the new EXPLICIT_QUANTITY_SUFFIX_PATTERN filter (along with its region-based check in extractVersionNumbers) to reject quantity phrases like "Java 100 days of practice" while preserving genuine release requests like "Java 21"; however, the original regex enumerated only days?|hours?|minutes?|seconds?|times|lines? and never included the longer duration units months?|weeks?|years?, so the incompleteness was present from the moment the filter was first created rather than being introduced by a later edit.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions