Files
gitlore/docs/issues/001-timeline-missing-project-in-entity-ref.md
Taylor Eernisse 4185abe05d docs: add feature ideas catalog, time-decay scoring plan, and timeline issue doc
Ideas catalog (docs/ideas/): 25 feature concept documents covering future
lore capabilities including bottleneck detection, churn analysis, expert
scoring, collaboration patterns, milestone risk, knowledge silos, and more.
Each doc includes motivation, implementation sketch, data requirements, and
dependencies on existing infrastructure. README.md provides an overview and
SYSTEM-PROPOSAL.md presents the unified analytics vision.

Plans (plans/): Time-decay expert scoring design with four rounds of review
feedback exploring decay functions, scoring algebra, and integration points
with the existing who-expert pipeline.

Issue doc (docs/issues/001): Documents the timeline pipeline bug where
EntityRef was missing project context, causing ambiguous cross-project
references during the EXPAND stage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 10:16:48 -05:00

141 lines
4.3 KiB
Markdown

# 001: Timeline human output omits project path from entity references
- **Severity:** medium
- **Component:** `src/cli/commands/timeline.rs`
- **Status:** open
## Problem
The `lore timeline` human-readable output renders entity references as bare `#42` or
`!234` without the project path. When multiple projects are synced, this makes the
output ambiguous — issue `#42` in `group/backend` and `#42` in `group/frontend` are
indistinguishable.
### Affected code
`format_entity_ref` at `src/cli/commands/timeline.rs:201-207`:
```rust
fn format_entity_ref(entity_type: &str, iid: i64) -> String {
match entity_type {
"issue" => format!("#{iid}"),
"merge_request" => format!("!{iid}"),
_ => format!("{entity_type}:{iid}"),
}
}
```
This function is called in three places:
1. **Event lines** (`print_timeline_event`, line 130) — each event row shows `#42`
with no project context
2. **Footer seed list** (`print_timeline_footer`, line 161) — seed entities listed as
`#42, !234` with no project disambiguation
3. **Collect stage summaries** (`timeline_collect.rs:107`) — the `summary` field itself
bakes in `"Issue #42 created: ..."` without project
### Current output (ambiguous)
```
2025-01-20 CREATED #42 Issue #42 created: Login timeout bug @alice
2025-01-21 LABEL+ #42 Label added: priority::high @dave
2025-01-22 CREATED !234 MR !234 created: Refactor auth middleware @alice
2025-01-25 MERGED !234 MR !234 merged @bob
Seed entities: #42, !234
```
When multiple projects are synced, a reader cannot tell which project `#42` belongs to.
## Robot mode is partially affected
The robot JSON output (`EventJson`, line 387-416) DOES include a `project` field per
event, so programmatic consumers can disambiguate. However, the `summary` string field
still bakes in bare `#42` without project context, which is misleading if an agent uses
the summary for display.
## Proposed fix
### 1. Add project to `format_entity_ref`
Pass `project_path` into `format_entity_ref` and use GitLab's full reference format:
```rust
fn format_entity_ref(entity_type: &str, iid: i64, project_path: &str) -> String {
match entity_type {
"issue" => format!("{project_path}#{iid}"),
"merge_request" => format!("{project_path}!{iid}"),
_ => format!("{project_path}/{entity_type}:{iid}"),
}
}
```
### 2. Smart elision for single-project timelines
When all events belong to the same project, the full path is visual noise. Detect
this and fall back to bare `#42` / `!234`:
```rust
fn should_show_project(events: &[TimelineEvent]) -> bool {
let mut projects = events.iter().map(|e| &e.project_path).collect::<HashSet<_>>();
projects.len() > 1
}
```
Then conditionally format:
```rust
let entity_ref = if show_project {
format_entity_ref(&event.entity_type, event.entity_iid, &event.project_path)
} else {
format_entity_ref_short(&event.entity_type, event.entity_iid)
};
```
### 3. Fix summary strings in collect stage
`timeline_collect.rs:107` bakes the summary as `"Issue #42 created: title"`. This
should include the project when multi-project:
```rust
let prefix = if multi_project {
format!("{type_label} {project_path}#{iid}")
} else {
format!("{type_label} #{iid}")
};
summary = format!("{prefix} created: {title_str}");
```
Same pattern for the merge summary at lines 317 and 347.
### 4. Update footer seed list
`print_timeline_footer` (line 155-164) should also use the project-aware format:
```rust
result.seed_entities.iter()
.map(|e| format_entity_ref(&e.entity_type, e.entity_iid, &e.project_path))
```
## Expected output after fix
### Single project (no change)
```
2025-01-20 CREATED #42 Issue #42 created: Login timeout bug @alice
```
### Multi-project (project path added)
```
2025-01-20 CREATED group/backend#42 Issue group/backend#42 created: Login timeout @alice
2025-01-22 CREATED group/frontend#42 Issue group/frontend#42 created: Broken layout @eve
```
## Impact
- Human output: ambiguous for multi-project users (the primary use case for gitlore)
- Robot output: summary field misleading, but `project` field provides workaround
- Timeline footer: seed entity list ambiguous
- Collect-stage summaries: baked-in bare references propagate to both renderers