Skip to content

[Detail Bug] List formatting: colon in list item drops everything after the colon #149

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_69f8a87c-1f22-4eb8-b220-82f13463f7e1

Introduced in #3 by @WilliamAGH on Jan 23, 2026

Summary

  • Context: For "Monday: 9:00 AM" between list markers:
  • Bug: normalizeEntryLabel() unconditionally truncates list item text at the first colon, causing silent data loss.
  • Actual vs. expected:
    • Actual behavior:
      • Input: "Schedule: 1. Monday: 9:00 AM 2. Tuesday: 2:30 PM"
      • Output: <ol><li>Monday</li><li>Tuesday</li></ol>
      • Lost: "9:00 AM", "2:30 PM" — time information permanently discarded
    • Expected behavior: Preserve content after colons when the colon does not introduce a nested list.
  • Impact: Silent corruption of legitimate LLM output including times, ratios, scores, URLs, definitions, and explanations.

Code with Bug

// InlineListParser.java:328-343
private static String normalizeEntryLabel(String raw) {
    String label = raw == null ? "" : raw.trim();
    int colonIndex = label.indexOf(':');
    if (colonIndex > 0) {
        label = label.substring(0, colonIndex).trim(); // <-- BUG 🔴 unconditional truncation at ':' causes data loss
    }
    while (!label.isEmpty()) {
        char last = label.charAt(label.length() - 1);
        if (last == '.' || last == '!' || last == '?') {
            label = label.substring(0, label.length() - 1).trim();
        } else {
            break;
        }
    }
    return label;
}

Explanation

  • List parsing first tries to treat : as a nested-list separator in splitNestedList by parsing the text after the colon (tail) as a list.
    • If tail parses as a list, normalizeEntryLabel only receives the pre-colon labelPart (which contains no colon), so the colon-stripping code is redundant.
    • If tail does not parse as a list (e.g., "Monday: 9:00 AM"), the parser falls through and calls normalizeEntryLabel with the original string; the unconditional colon truncation then drops legitimate content (times, ratios like 3:1, URLs, definitions, etc.).
  • This creates contradictory behavior: splitNestedList effectively says “only split on colon when it introduces a nested list,” but normalizeEntryLabel says “always split on colon,” causing silent truncation.

Recommended Fix

Remove lines 330-333 (the unconditional colon truncation):

private static String normalizeEntryLabel(String raw) {
    String label = raw == null ? "" : raw.trim();
    while (!label.isEmpty()) {
        char last = label.charAt(label.length() - 1);
        if (last == '.' || last == '!' || last == '?') {
            label = label.substring(0, label.length() - 1).trim();
        } else {
            break;
        }
    }
    return label;
}

History

This bug was introduced in commit c7aa9a1. The refactoring replaced a regex-based inline list parser with a DOM-manipulation approach, and introduced normalizeEntryLabel() to clean item labels. The method was designed to strip trailing punctuation but inadvertently also strips content after the first colon for items without nested lists, changing behavior from the previous implementation which preserved the entire string when no nested markers were detected.

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