Add per-project detail rows beneath stage completion lines during multi-project
syncs, showing itemized counts (issues/MRs, discussions, events, statuses, diffs)
for each project. Previously, only aggregate totals were visible, making it hard
to diagnose which project contributed what during a sync.
Status enrichment gets proper progress bars replacing the old spinner-only
display: StatusEnrichmentStarted now carries a total count so the CLI can
render a determinate bar with rate and ETA. The enrichment SQL is tightened
to use IS NOT comparisons for diff-only UPDATEs (skip rows where values
haven't changed), and a follow-up touch_stmt ensures status_synced_at is
updated even for unchanged rows so staleness detection works correctly.
Other improvements:
- New ProjectSummary struct aggregates per-project metrics during ingestion
- SyncResult gains statuses_enriched + per-project summary vectors
- "Already up to date" message when sync finds zero changes
- Remove Arc<AtomicBool> tick_started pattern from docs/embed stages
(enable_steady_tick is idempotent, the guard was unnecessary)
- Progress bar styling: dim spinner, dark_gray track, per_sec + eta display
- Tick intervals tightened from 100ms to 60ms for smoother animation
- statuses_without_widget calculation uses fetch_result.statuses.len()
instead of subtracting enriched (more accurate when some statuses lack
work item widgets)
- Status enrichment completion log downgraded from info to debug
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract parse_retry_after_value(header, now) as a pure function to enable
deterministic testing of Retry-After header parsing. The previous
implementation used let-chains with SystemTime::now() inline, which made
it untestable and would panic on negative durations when the server
clock was behind or the header contained a date in the past.
Changes:
- Extract parse_retry_after_value() taking an explicit `now` parameter
- Handle past HTTP dates by returning 1 second instead of panicking on
negative Duration (date.duration_since(now) returns Err for past dates)
- Trim whitespace from header values before parsing
- Add test for past HTTP date returning 1 second minimum
- Add test for delta-seconds with surrounding whitespace
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 7 cleanup: migrate timeline.rs and main.rs search spinner
from stage_spinner() to stage_spinner_v2() with proper icon labels,
then remove the now-unused stage_spinner() function and its tests.
No external callers remain for the old numbered-stage API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 6 of the UX overhaul. Applies consistent visual treatment across
the remaining command outputs: stats, doctor, timeline, who, count,
and drift.
Stats (stats.rs):
- Apply render::format_number() to all numeric values (documents,
FTS indexed, embedding counts, chunks) for thousand-separator
formatting in large databases
Doctor (doctor.rs):
- Replace Unicode check/warning/cross symbols with Icons::success(),
Icons::warning(), Icons::error() for glyph-mode awareness
- Add summary line after checks showing "Ready/Not ready" with counts
of passed, warnings, and failed checks separated by middle dots
- Remove "lore doctor" title header for cleaner output
Count (count.rs):
- Right-align numeric values with {:>10} format for columnar output
in count and state breakdown displays
Timeline (timeline.rs):
- Add entity icons (issue/MR) before entity references in event rows
- Refactor format_event_tag to pad plain text before applying style,
preventing ANSI codes from breaking column alignment
- Extract style_padded() helper for width-then-style pattern
Who (who.rs):
- Add Icons::user() before usernames in expert, workload, reviews,
and overlap displays
- Replace manual bold section headers with render::section_divider()
in workload view (Assigned Issues, Authored MRs, Reviewing MRs,
Unresolved Discussions)
Drift (drift.rs):
- Add Icons::error()/success() before drift detection status line
- Replace '#' bar character with Unicode full block for similarity
curve visualization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 4 of the UX overhaul. Restructures the show issue and show MR
detail displays with consistent section layout, state icons, and
improved typography.
Issue detail changes:
- Replace bold header + box-drawing underline with indented title using
Theme::bold() for the title text only
- Organize fields into named sections using render::section_divider():
Details, Development, Description, Discussions
- Add state icons (Icons::issue_opened/closed) alongside text labels
- Add relative time in parentheses next to Created/Updated dates
- Switch labels from "Labels: (none)" to only showing when present,
using format_labels_bare for clean comma-separated output
- Move URL and confidential indicator into Details section
- Closing MRs show state-colored icons (merged/opened/closed)
- Discussions use section_divider instead of bold text, remove colons
from author lines, adjust wrap widths for consistent indentation
MR detail changes:
- Same section-divider layout: Details, Description, Discussions
- State icons for opened/merged/closed using Icons::mr_* helpers
- Draft indicator uses Icons::mr_draft() instead of [Draft] text prefix
- Relative times added to Created, Updated, Merged, Closed dates
- Reviewers and Assignees fields aligned with fixed-width labels
- Labels shown only when present, using format_labels_bare
- Discussion formatting matches issue detail style
Both views use 5-space left indent for field alignment and consistent
wrap widths (72 for descriptions, 68/66 for discussion notes/replies).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 3 of the UX overhaul. Enhances the issues, merge requests, and
notes list displays with visual indicators and improved formatting.
List display changes (src/cli/commands/list.rs):
- Add state icons to issues (opened/closed) and merge requests
(opened/merged/closed) using Icons:: helpers alongside text labels
- Replace [DRAFT] prefix with Icons::mr_draft() glyph for draft MRs
- Switch from format_relative_time to format_relative_time_compact for
tighter column widths in tabular output
- Switch from format_labels to format_labels_bare for unlabeled style
- Change format_discussions() return type from String to StyledCell so
unresolved counts render with Theme::warning() color inline
- Bold the section headers ("Issues", "Merge Requests", "Notes")
with count separated from the label for cleaner scanning
- Import Icons from render module
Test updates (src/cli/commands/list_tests.rs):
- Update format_discussions tests to assert on StyledCell.text field
instead of raw String, since the function now returns styled output
- The unresolved-count test checks starts_with/contains to handle
embedded ANSI escape codes from Theme::warning()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 2 of the UX overhaul. Replaces the old numbered-stage progress
system (1/4, 2/4...) and manual indicatif ProgressBar/ProgressStyle
setup with the new centralized progress helpers.
Sync command changes (src/cli/commands/sync.rs):
- Replace stage_spinner(n, total, msg) with stage_spinner_v2(icon, label, status)
removing the rigid numbered-stage counter in favor of named stages
- Replace manual ProgressBar::new + ProgressStyle::default_bar for docs
and embed sub-progress with nested_progress(label, len, robot_mode)
- Add finish_stage() calls that display a completion summary with
elapsed time, e.g. "Issues 42 issues from 3 projects 1.2s"
- Each stage (Issues, MRs, Docs, Embed) now reports what it did on
completion rather than just clearing the spinner silently
- Embed failure path uses Icons::warning() instead of inline Theme
formatting, keeping error display consistent with success path
- Remove indicatif direct dependency from sync.rs (now handled by
progress module)
Main entry point changes (src/main.rs):
- Add GlyphMode detection: auto-detect Unicode/Nerd Font support or
fall back to ASCII based on --icons flag, --color=never, NO_COLOR,
or robot mode
- Update all LoreRenderer::init() calls to pass GlyphMode alongside
ColorMode for icon-aware rendering throughout the CLI
- Overhaul handle_error() formatting: use Icons::error() glyph,
bold error text, arrow prefixed action suggestions, and breathing
room with blank lines for scannability
- Migrate handle_embed() progress bar from manual ProgressBar +
ProgressStyle to nested_progress() helper, matching sync command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 5 of the UX overhaul. Migrates search result display from raw
console styling to the centralized Theme system with semantic methods,
improving visual consistency and readability.
Search result changes:
- Type badges now use semantic styles (issue_ref, mr_ref) with
fixed-width alignment for clean columnar layout
- Snippet rendering uses Theme::highlight() for matched terms and
Theme::muted() for surrounding context, replacing bold+underline
- Metadata line uses Theme::username() for authors and per-part
styling with middle-dot separators instead of a single dim line
- Result numbering uses muted style with right-aligned width
- Consistent 8-space indent for metadata, snippets, and explain lines
- Header line uses muted style for search mode instead of dim+parens
- Trailing blank line moved after the result loop instead of per-result
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update test_raw_mode_leading_wildcard_falls_back_to_safe to match the
actual Safe mode behavior: OR is a recognized FTS5 boolean operator and
passes through unquoted, so the expected output is '"*" OR "auth"' not
'"*" "OR" "auth"'. The previous assertion was incorrect since the Safe
mode operator-passthrough logic was added.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Invert the timeline mention-expansion flag semantics. Previously, mention
edges were excluded by default and --expand-mentions opted in. Now mention
edges are included by default (matching the more common use case) and
--no-mentions opts out to reduce fan-out when needed.
This is a breaking CLI change but aligns with the principle that the
default behavior should produce the most useful output. Users who were
passing --expand-mentions get the same behavior without any flag. Users
who want reduced output can pass --no-mentions.
Updated: CLI args (TimelineArgs), autocorrect flag list, robot-docs
schema, README documentation and flag reference table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire the LoreRenderer singleton initialization into main.rs color mode
handling, replacing the console::style import with Theme throughout.
Key changes:
- Color initialization: LoreRenderer::init() called for all code paths
(NO_COLOR, --color never/always/auto, unknown mode fallback) alongside
the existing console::set_colors_enabled() calls. Both systems must
agree since some transitive code still uses console (e.g. dialoguer).
- Tracing: Replace .with_target(false) with .event_format(CompactHumanFormat)
for the stderr layer, producing the clean 'HH:MM:SS LEVEL message' format.
- Error handling: handle_error() now shows machine-actionable recovery
commands from gi_error.actions() below the hint, formatted with dim '$'
prefix and bold command text.
- Deprecation warnings: All 'lore list', 'lore show', 'lore auth-test',
'lore sync-status' warnings migrated to Theme::warning().
- Init wizard: All success/info/error messages migrated. Unicode check
marks use explicit \u{2713} escapes instead of literal symbols.
- Embed command: Added progress bar with indicatif for embedding stage,
showing position/total with steady tick. Elapsed time shown on completion.
- Generate-docs and ingest commands: Added 'Done in Xs' elapsed time and
next-step hints (run embed after generate-docs, run generate-docs after
ingest) for better workflow guidance.
- Sync output: Interrupt message and lock release migrated to Theme.
- Health command: Status labels and overall healthy/unhealthy styled.
- Robot-docs: Added drift command schema, updated sync flags to include
--no-file-changes, updated who flags with new options.
- Timeline --expand-mentions -> --no-mentions flag rename wired through
params and robot-docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all console::style() calls in command modules with the centralized
Theme API and render:: utility functions. This ensures consistent color
behavior across the entire CLI, proper NO_COLOR/--color never support via
the LoreRenderer singleton, and eliminates duplicated formatting code.
Changes per module:
- count.rs: Theme for table headers, render::format_number replacing local
duplicate. Removed local format_number implementation.
- doctor.rs: Theme::success/warning/error for check status symbols and
messages. Unicode escapes for check/warning/cross symbols.
- drift.rs: Theme::bold/error/success for drift detection headers and
status messages.
- embed.rs: Compact output format — headline with count, zero-suppressed
detail lines, 'nothing to embed' short-circuit for no-op runs.
- generate_docs.rs: Same compact pattern — headline + detail + hint for
next step. No-op short-circuit when regenerated==0.
- ingest.rs: Theme for project summaries, sync status, dry-run preview.
All console::style -> Theme replacements.
- list.rs: Replace comfy-table with render::LoreTable for issue/MR listing.
Remove local colored_cell, colored_cell_hex, format_relative_time,
truncate_with_ellipsis, and format_labels (all moved to render.rs).
- list_tests.rs: Update test assertions to use render:: functions.
- search.rs: Add render_snippet() for FTS5 <mark> tag highlighting via
Theme::bold().underline(). Compact result layout with type badges.
- show.rs: Theme for entity detail views, delegate format_date and
wrap_text to render module.
- stats.rs: Section-based layout using render::section_divider. Compact
middle-dot format for document counts. Color-coded embedding coverage
percentage (green >=95%, yellow >=50%, red <50%).
- sync.rs: Compact sync summary — headline with counts and elapsed time,
zero-suppressed detail lines, visually prominent error-only section.
- sync_status.rs: Theme for run history headers, removed local
format_number duplicate.
- timeline.rs: Theme for headers/footers, render:: for date/truncate,
standard format! padding replacing console::pad_str.
- who.rs: Theme for all expert/workload/active/overlap/review output
modes, render:: for relative time and truncation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate all ingestion completion logs to use nonzero_summary() for compact,
zero-suppressed output. Before: 8-14 individual key=value structured fields
per completion message. After: a single summary field like
'42 fetched · 3 labels · 12 notes' that only shows non-zero counters.
Also downgrade all 'Shutdown requested...' messages from info! to debug!.
These are emitted on every Ctrl+C and add noise to the partial results
output that immediately follows. They remain visible at -vv for debugging
graceful shutdown behavior.
Affected modules:
- issues.rs: issue ingestion completion
- merge_requests.rs: MR ingestion completion, full-sync cursor reset
- mr_discussions.rs: discussion ingestion completion
- orchestrator.rs: project-level issue and MR completion summaries,
all shutdown-requested checkpoints across discussion sync, resource
events drain, closes-issues drain, and MR diffs drain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three quality-of-life improvements to reduce log noise and improve readability:
1. logging.rs: Add CompactHumanFormat for stderr tracing output. Replaces the
default format with a minimal 'HH:MM:SS LEVEL message key=value' layout —
no span context, no full timestamps, no target module. The JSON file log
layer is unaffected. This makes watching 'lore sync' output much cleaner.
2. lock.rs: Downgrade AppLock acquire/release messages from info! to debug!.
Lock lifecycle events (acquired new, acquired existing, released) are
operational bookkeeping that clutters normal output. They remain visible
at -vv verbosity for troubleshooting.
3. ingestion/mod.rs: Add nonzero_summary() utility that formats named counters
as a compact middle-dot-separated string, suppressing zero values. Produces
output like '42 fetched · 3 labels · 12 notes' instead of verbose key=value
structured fields. Returns 'nothing to update' when all values are zero.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce src/cli/render.rs as the single source of truth for all terminal
output styling and formatting utilities. Key components:
- LoreRenderer: global singleton initialized once at startup, resolving
color mode (Auto/Always/Never) against TTY state and NO_COLOR env var.
This fixes lipgloss's limitation of hardcoded TrueColor rendering by
gating all style application through a colors_on() check.
- Theme: semantic style constants (success/warning/error/info/accent,
entity refs, state colors, structural styles) that return plain
Style::new() when colors are disabled. Replaces ad-hoc console::style()
calls scattered across 15+ command modules.
- Shared formatting utilities consolidated from duplicated implementations:
format_relative_time (was in list.rs and who.rs), format_number (was in
count.rs and sync_status.rs), truncate (was truncate_with_ellipsis in
list.rs and truncate_summary in timeline.rs), format_labels, format_date,
wrap_indent, section_divider.
- LoreTable: lightweight table renderer replacing comfy-table with simple
column alignment (Left/Right/Center), adaptive terminal width, and
NO_COLOR-safe output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch from comfy-table to the lipgloss Rust port for terminal styling.
lipgloss provides a composable Style API better suited to our new semantic
theming approach (Theme::success(), Theme::error(), etc.) where we apply
styles to individual text spans rather than constructing styled table cells.
The comfy-table dependency was only used by the list command's human output
and is no longer needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two related improvements to agent ergonomics in main.rs:
1. suggest_similar_command now matches against aliases (issue->issues,
mr->mrs, find->search, stat->stats, note->notes, etc.) and provides
contextual usage examples via a new command_example() helper, so
agents get actionable recovery hints like "Did you mean 'lore mrs'?
Example: lore --robot mrs -n 10" instead of just the command name.
2. robot-docs now includes an error_tolerance section documenting every
auto-correction the CLI performs: types (single_dash_long_flag,
case_normalization, flag_prefix, fuzzy_flag, subcommand_alias,
value_normalization, value_fuzzy, prefix_matching), examples, and
mode behavior (threshold differences). Also expands the aliases
section with command_aliases and pre_clap_aliases maps for complete
agent self-discovery.
Together these ensure agents can programmatically discover and recover
from any CLI input error without human intervention.
Three-phase pipeline replacing the single-pass correction:
- Phase A: Subcommand alias correction — handles forms clap can't
express (merge_requests, mergerequests, robotdocs, generatedocs,
gen-docs, etc.) via case-insensitive alias map lookup.
- Phase B: Per-arg flag corrections — adds unambiguous prefix expansion
(--proj -> --project) alongside existing single-dash, case, and fuzzy
rules. New FlagPrefix rule with 0.95 confidence.
- Phase C: Enum value normalization — auto-corrects casing, prefixes,
and typos for flags with known valid values. Handles both --flag value
and --flag=value forms. Respects POSIX -- option terminator.
Changes strict/robot mode from disabling fuzzy matching entirely to using
a higher threshold (0.9 vs 0.8), still catching obvious typos like
--projct while avoiding speculative corrections that mislead agents.
New CorrectionRule variants: SubcommandAlias, ValueNormalization,
ValueFuzzy, FlagPrefix. Each has a corresponding teaching note.
Comprehensive test coverage for all new correction types including
subcommand aliases, value normalization (case, prefix, fuzzy, eq-form),
flag prefix (ambiguous rejection, eq-value preservation), and updated
strict mode behavior.
- Fix MENTIONED_RE/CLOSED_BY_RE to match real GitLab format
('mentioned in issue #N' / 'mentioned in merge request !N')
- Add GITLAB_URL_RE + parse_url_refs() for full URL extraction
- Add extract_refs_from_descriptions() -> source_method='description_parse'
- Add extract_refs_from_user_notes() -> source_method='note_parse'
- Wire both into orchestrator after system note extraction
- 36 tests: regex fix, URL parsing, integration, idempotency
Adds issue:N / i:N / mr:N / m:N query syntax to bypass hybrid search
and seed the timeline directly from a known entity. All discussions for
the entity are gathered without needing Ollama.
- parse_timeline_query() detects entity-direct patterns
- resolve_entity_by_iid() resolves IID to EntityRef with ambiguity handling
- seed_timeline_direct() gathers all discussions for the entity
- 20 new tests (5 resolve, 6 direct seed, 9 parse)
- Updated CLI help text and robot-docs manifest
Moves the conn.prepare() call for fetching discussion notes outside the
per-discussion loop in collect_discussion_threads(). The SQL is identical
for every iteration, so preparing it once and rebinding parameters avoids
redundant statement compilation on each matched discussion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FTS5 boolean operators (AND, OR, NOT, NEAR) are case-sensitive uppercase
keywords that must appear unquoted in the query string. Previously, the
user-friendly query builder would double-quote every token, causing
queries like "switch AND health" to search for the literal word "AND"
instead of using it as a boolean conjunction.
Adds a FTS5_OPERATORS constant and checks each token against it before
quoting, allowing natural boolean search syntax to work as expected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds numbered stage spinners ([1/3], [2/3], [3/3]) to the timeline
pipeline stages (seed, expand, collect) so users see activity during
longer queries. TimelineParams gains a robot_mode field to suppress
spinners in JSON output mode.
Adds a [1/1] spinner to the search command for consistency, using the
shared stage_spinner from cli/progress.
Also refactors wrap_snippet() to delegate to wrap_text() with a 4-line
cap, eliminating the duplicated word-wrapping logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moves stage_spinner() from a private function in sync.rs to a pub function
in cli/progress.rs so it can be reused by the timeline and search commands.
The function creates a numbered spinner (e.g. [1/3]) for pipeline stages,
returning a hidden no-op bar in robot mode to keep caller code path-uniform.
sync.rs now imports from crate::cli::progress::stage_spinner instead of
defining its own copy. Adds unit tests for robot mode (hidden bar), human
mode (prefix/message properties), and prefix formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the downstream consumption of matched discussions from the seed
phase, completing the discussion thread feature across collect, CLI, and
integration tests.
Collect phase (timeline_collect.rs):
- New collect_discussion_threads() function assembles full threads by
querying notes for each matched discussion_id, filtering out system notes
(is_system = 0), ordering chronologically, and capping at THREAD_MAX_NOTES
with a synthetic "[N more notes not shown]" summary note
- build_entity_lookup() creates a (type, id) -> (iid, path) map from seed
and expanded entities to provide display metadata for thread events
- Thread timestamp is set to the first note's created_at for correct
chronological interleaving with other timeline events
- collect_events() gains a matched_discussions parameter; threads are
collected after entity events and before evidence note merging
CLI rendering (cli/commands/timeline.rs):
- Human mode: threads render with box-drawing borders, bold @author tags,
date-stamped notes, and word-wrapped bodies (60 char width)
- Robot mode: DiscussionThread serializes as discussion_thread kind with
note_count, full notes array (note_id, author, body, ISO created_at)
- THREAD tag in yellow for human event tag styling
- TimelineMeta gains discussion_threads_included count
Tests:
- 8 new collect tests: basic thread assembly, system note filtering, empty
thread skipping, body truncation to THREAD_NOTE_MAX_CHARS, note cap with
synthetic summary, timestamp from first note, chronological sort position,
and deduplication of duplicate discussion_ids
- Integration tests updated for new collect_events signature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces the foundation for full discussion thread support in the
timeline pipeline. Adds three new domain types to timeline.rs:
- ThreadNote: individual note within a thread (id, author, body, timestamp)
- MatchedDiscussion: tracks discussions matched during seeding with their
parent entity (issue or MR) for downstream collection
- DiscussionThread variant on TimelineEventType: carries a full thread of
notes, sorted between NoteEvidence and CrossReferenced
Moves truncate_to_chars() from timeline_seed.rs to timeline.rs as pub(crate)
for reuse by the collect phase. Adds THREAD_NOTE_MAX_CHARS (2000) and
THREAD_MAX_NOTES (50) constants.
Upgrades the seed SQL in resolve_documents_to_entities() to resolve note
documents to their parent discussion via an additional LEFT JOIN chain
(notes -> discussions), using COALESCE to unify the entity resolution path
for both discussion and note source types. SeedResult gains a
matched_discussions field that captures deduplicated discussion matches.
Tests cover: discussion matching from discussion docs, note-to-parent
resolution, deduplication of same discussion across multiple docs, and
correct parent entity type (issue vs MR).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace FTS-only seed entity discovery with hybrid search (FTS + vector
via RRF), using the same search_hybrid infrastructure as the search
command. Falls back gracefully to FTS-only when Ollama is unavailable.
Changes:
- seed_timeline() now accepts OllamaClient, delegates to search_hybrid
- New resolve_documents_to_entities() replaces find_seed_entities()
- SeedResult gains search_mode field tracking actual mode used
- TimelineResult carries search_mode through to JSON renderer
- run_timeline wires up OllamaClient from config
- handle_timeline made async for the hybrid search await
- Tests updated for new function signatures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared path resolution logic from who.rs into a new
core::path_resolver module for cross-module reuse. Functions moved:
escape_like, normalize_repo_path, PathQuery, SuffixResult,
build_path_query, suffix_probe. Duplicate escape_like copies removed
from list.rs, project.rs, and filters.rs — all now import from
path_resolver.
Additionally fixes two bugs in query_expert_details() and
query_overlap() where only position_new_path was checked (missing
old_path matches for renamed files) and state filter excluded 'closed'
MRs despite the main scoring query including them with a decay
multiplier.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Planning document for the ongoing test extraction and code organization
effort. Covers module-by-module analysis, proposed file splits, and
phased execution plan.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New module: core::file_history with resolve_rename_chain() that traces
a file path through its rename history in mr_file_changes using
bidirectional BFS (forward: old_path->new_path, backward: new_path->old_path).
Key design decisions:
- Depth-bounded BFS: each queue entry carries its distance from the
origin, so max_hops correctly limits by graph distance (not by total
nodes discovered). This matters for branching rename graphs where a
file was renamed differently in parallel MRs.
- Cycle-safe: visited set prevents infinite loops from circular renames.
- Project-scoped: queries are always scoped to a single project_id.
- Deterministic: output is sorted for stable results.
Tests cover: linear chains (forward/backward), cycles, max_hops=0,
depth-bounded linear chains, branching renames, diamond patterns,
and cross-project isolation (9 tests total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Factor out parse_since_from(input, reference_ms) so callers can compute
relative durations against a fixed reference timestamp instead of always
using now(). The existing parse_since() now delegates to it with now_ms().
Enables testable and reproducible time-relative queries for features like
timeline --as-of and who --as-of.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move inline #[cfg(test)] mod tests { ... } blocks from 22 source files
into dedicated _tests.rs companion files, wired via:
#[cfg(test)]
#[path = "module_tests.rs"]
mod tests;
This keeps implementation-focused source files leaner and more scannable
while preserving full access to private items through `use super::*;`.
Modules extracted:
core: db, note_parser, payloads, project, references, sync_run,
timeline_collect, timeline_expand, timeline_seed
cli: list (55 tests), who (75 tests)
documents: extractor (43 tests), regenerator
embedding: change_detector, chunking
gitlab: graphql (wiremock async tests), transformers/issue
ingestion: dirty_tracker, discussions, issues, mr_diffs
Also adds conflicts_with("explain_score") to the --detail flag in the
who command to prevent mutually exclusive flags from being combined.
All 629 unit tests pass. No behavior changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enriched all per-note search beads (NOTE-0A through NOTE-2I) with:
- Corrected migration numbers (022, 024, 025)
- Verified file paths and line numbers from codebase
- Complete function signatures for referenced code
- Detailed approach sections with SQL and Rust patterns
- DocumentData struct field mappings
- TDD anchors with specific test names
- Edge cases from codebase analysis
- Dependency context explaining what each blocker provides
Add quick_start section with glab equivalents, lore-exclusive features,
and read/write split guidance. Add example_output to issues, mrs, search,
and who commands. Update strip_schemas to also strip example_output in
brief mode. Update beads tracking state.
Closes: bd-91j1
Make run_search async, replace hardcoded lexical mode with SearchMode::parse(),
wire search_hybrid() with OllamaClient for semantic/hybrid modes, graceful
degradation when Ollama unavailable.
Closes: bd-1ksf
Implement drift detection using cosine similarity between issue description
embedding and chronological note embeddings. Sliding window (size 3) identifies
topic drift points. Includes human and robot output formatters.
New files: drift.rs, similarity.rs
Closes: bd-1cjx
Add references_full, user_notes_count, merge_requests_count computed
fields to show issue. Add closed_at and confidential columns via
migration 023.
Closes: bd-2g50