Commit Graph

8 Commits

Author SHA1 Message Date
teernisse
20753608e8 fix(cli): flex-col min-width clamping and formatting consistency
- render.rs: clamp flex column width to min(min_flex, natural) instead
  of a hardcoded 20, preventing layout overflow when natural width is
  small; rewrites flex_width test to be terminal-independent
- list/issues.rs: adopt .flex_col() builder on table construction
- list/mrs.rs, list/notes.rs: consolidate multi-line StyledCell::styled
  calls to single-line format
- explain.rs: adopt flex_width() for related-issue title truncation,
  consolidate multi-line formatting
2026-03-13 11:13:40 -04:00
teernisse
6d85474052 refactor(cli): adopt flex-width rendering, remove data-layer truncation
Replace hardcoded truncation widths across CLI commands with
render::flex_width() calls that adapt to terminal size. Remove
server-side truncate_to_chars() in timeline collect/seed stages so
full text is preserved through the pipeline — truncation now happens
only at the presentation layer where terminal width is known.

Affected commands: explain, file-history, list (issues/mrs/notes),
me, timeline, who (active/expert/workload).
2026-03-13 11:03:04 -04:00
teernisse
1bbdcb70ef fix(explain): align human output with render module conventions
The explain command's human-mode output was hand-rolled with raw
println! formatting that didn't use any of the shared render.rs
infrastructure. This made it visually inconsistent with every other
command (me, who, search, timeline).

Changes to print_explain():
- Section headers now use render::section_divider() with counts,
  producing the same box-drawing divider lines as the me command
- Entity refs use Theme::issue_ref()/mr_ref() color styling
- Entity state uses Theme::state_opened/closed/merged() styling
- Authors/usernames use Theme::username() with @ prefix
- Project paths use Theme::muted()
- Timestamps use format_relative_time() for recency fields (created,
  first/last event, last note) and format_date() for point-in-time
  fields (key decisions, timeline events), matching the conventions
  in me, who, and timeline respectively
- Note excerpts use render::truncate() instead of manual byte slicing
- Related entity titles are truncated via render::truncate()
- Indentation aligned to 4-space content under section dividers

Robot JSON output is unchanged -- it continues to use ms_to_iso() for
all timestamp fields, consistent with the rest of the robot API.
2026-03-13 09:59:19 -04:00
teernisse
7e5ffe35d3 feat(explain): enrich output with project path, thread excerpts, entity state, and timeline metadata
Multiple improvements to the explain command's data richness:

- Add project_path to EntitySummary so consumers can construct URLs from
  project + entity_type + iid without extra lookups
- Include first_note_excerpt (first 200 chars) in open threads so agents
  and humans get thread context without a separate query
- Add state and direction fields to RelatedIssue — consumers now see
  whether referenced entities are open/closed/merged and whether the
  reference is incoming or outgoing
- Filter out self-references in both outgoing and incoming related entity
  queries (entity referencing itself via cross-reference extraction)
- Wrap timeline excerpt in TimelineExcerpt struct with total_events and
  truncated fields — consumers know when events were omitted
- Keep most recent events (tail) instead of oldest (head) when truncating
  timeline — recent activity is more actionable
- Floor activity summary first_event at entity created_at — label events
  from bulk operations can predate entity creation
- Human output: show project path in header, thread excerpt preview,
  state badges on related entities, directional arrows, truncation counts
2026-03-12 10:08:22 -04:00
teernisse
6aff96d32f fix(sql): add ORDER BY to all LIMIT queries for deterministic results
SQLite does not guarantee row order without ORDER BY, even with LIMIT.
This was a systemic issue found during a multi-pass bug hunt:

Production queries (explain.rs):
- Outgoing reference query: ORDER BY target_entity_type, target_entity_iid
- Incoming reference query: ORDER BY source_entity_type, COALESCE(iid)
  Without these, robot mode output was non-deterministic across calls,
  breaking clients expecting stable ordering.

Test helper queries (5 locations across 3 files):
- discussions_tests.rs: get_discussion_id()
- mr_discussions.rs: get_mr_discussion_id()
- queue.rs: setup_db_with_job(), release_all_locked_jobs_clears_locks()
  Currently safe (single-row inserts) but would break silently if tests
  expanded to multi-row fixtures.
2026-03-10 17:10:52 -04:00
teernisse
06889ec85a fix(explain): address review findings — N+1 queries, duplicate decisions, silent errors
1. fetch_open_threads: replace N+1 loop (2 queries per thread) with a
   single query using correlated subqueries for note_count and started_by.
2. extract_key_decisions: track consumed notes so the same note is not
   matched to multiple events, preventing duplicate decision entries.
3. build_timeline_excerpt_from_pipeline: log tracing::warn on seed/collect
   failures instead of silently returning empty timeline.
2026-03-10 16:43:06 -04:00
teernisse
08bda08934 fix(explain): filter out NULL iids in related entities queries
entity_references.target_entity_iid is nullable (unresolved cross-project
refs), and COALESCE(i.iid, mr.iid) returns NULL for orphaned refs.
Both paths caused rusqlite InvalidColumnType errors when fetching i64.
Added IS NOT NULL filters to both outgoing and incoming reference queries.
2026-03-10 15:54:54 -04:00
teernisse
32134ea933 feat(explain): implement lore explain command for auto-generating issue/MR narratives
Adds the full explain command with 7 output sections: entity summary, description,
key decisions (heuristic event-note correlation), activity summary, open threads,
related entities (closing MRs, cross-references), and timeline excerpt (reuses
existing pipeline). Supports --sections filtering, --since time scoping,
--no-timeline, --max-decisions, and robot mode JSON output.

Closes: bd-2i3z, bd-a3j8, bd-wb0b, bd-3q5e, bd-nj7f, bd-9lbr
2026-03-10 15:04:35 -04:00