The show command's NoteDetail and MrNoteDetail structs were missing
gitlab_id, making individual notes unaddressable in robot mode output.
This was inconsistent with the notes list command which already exposed
gitlab_id. Without an identifier, agents consuming show output could
not construct GitLab web URLs or reference specific notes for follow-up
operations via glab.
Added gitlab_id to:
- NoteDetail / NoteDetailJson (issue discussions)
- MrNoteDetail / MrNoteDetailJson (MR discussions)
- Both SQL queries (shifted column indices accordingly)
- Both From<&T> conversion impls
Deliberately scoped to show command only — me/timeline/trace structs
were evaluated and intentionally left unchanged because they serve
different consumption patterns where note-level identity is not needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document that the activity feed and since-last-check inbox cover items
in any state (open, closed, merged), while the issues and MRs sections
show only open items. Add the previously undocumented since-last-check
inbox section to the dashboard description.
The activity feed and since-last-check inbox previously filtered to
only open items via state = 'opened' checks in the SQL subqueries.
This meant comments on merged MRs (post-merge follow-ups, questions)
and closed issues were silently dropped from the feed.
Remove the state filter from the association checks in both
query_activity() and query_since_last_check(). The user-association
checks (assigned, authored, reviewing) remain — activity still only
appears for items the user is connected to, regardless of state.
The simplified subqueries also eliminate unnecessary JOINs to the
issues/merge_requests tables that were only needed for the state
check, resulting in slightly more efficient index-only scans on
issue_assignees and mr_reviewers.
Add 4 tests covering: merged MR (authored), closed MR (reviewer),
closed issue (assignee), and merged MR in the since-last-check inbox.
CLI audit scoring the current command surface across human ergonomics,
robot/agent ergonomics, documentation quality, and flag design. Paired
with a detailed implementation plan for restructuring commands into a
more consistent, discoverable hierarchy.
Add pre-flight FTS count check before expensive bm25-ranked search.
Queries matching >10,000 documents are rejected instantly with a
suggestion to use a more specific query or --since filter.
Prevents multi-minute CPU spin on queries like 'merge request' that
match most of the corpus (106K/178K documents).
is_multiple_of(N) returns true for 0, which caused debug/info
progress messages to fire at doc_num=0 (the start of every page)
rather than only at the intended 50/100 milestones. Add != 0
check to both the debug (every 50) and info (every 100) log sites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major additions to the migration plan based on review feedback:
Alternative analysis:
- Add "Why not tokio CancellationToken + JoinSet?" section explaining
why obligation tracking and single-migration cost favor asupersync
over incremental tokio fixes.
Error handling depth:
- Add NetworkErrorKind enum design for preserving error categories
(timeout, DNS, TLS, connection refused) without coupling LoreError
to any HTTP client.
- Add response body size guard (64 MiB) to prevent unbounded memory
growth from misconfigured endpoints.
Adapter layer refinements:
- Expand append_query_params with URL fragment handling, edge case
docs, and doc comments.
- Add contention constraint note for std::sync::Mutex rate limiter.
Cancellation invariants (INV-1 through INV-4):
- Atomic batch writes, no .await between tx open/commit,
ShutdownSignal + region cancellation complementarity.
- Concrete test plan for each invariant.
Semantic ordering concerns:
- Document 4 behavioral differences when replacing join_all with
region-spawned tasks (ordering, error aggregation, backpressure,
late result loss on cancellation).
HTTP behavior parity:
- Replace informational table with concrete acceptance criteria and
pass/fail tests for redirects, proxy, keep-alive, DNS, TLS, and
Content-Length.
Phasing refinements:
- Add Cx threading sub-steps (orchestration path first, then
command/embedding layer) for blast radius reduction.
- Add decision gate between Phase 0d and Phase 1 requiring compile +
behavioral smoke tests before committing to runtime swap.
Rollback strategy:
- Per-phase rollback guidance with concrete escape hatch triggers
(nightly breakage > 7d, TLS incompatibility, API instability,
wiremock issues).
Testing depth:
- Adapter-layer test gap analysis with 5 specific asupersync-native
integration tests.
- Cancellation integration test specifications.
- Coverage gap documentation for wiremock-on-tokio tests.
Risk register additions:
- Unbounded response body buffering, manual URL/header handling
correctness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `query_mentioned_in` SQL previously joined notes directly against
the full issues/merge_requests tables, with per-row subqueries for
author/assignee/reviewer exclusion. On large databases this produced
pathological query plans where SQLite scanned the entire notes table
before filtering to relevant entities.
Refactor into a dedicated `build_mentioned_in_sql()` builder that:
1. Pre-filters candidate issues and MRs into MATERIALIZED CTEs
(state open OR recently closed, not authored by user, not
assigned/reviewing). This narrows the working set before any
notes join.
2. Computes note timestamps (my_ts, others_ts, any_ts) as separate
MATERIALIZED CTEs scoped to candidate entities only, rather than
scanning all notes.
3. Joins mention-bearing notes against the pre-filtered candidates,
avoiding the full-table scans.
Also adds a test verifying that authored issues are excluded from the
mentions results, and a unit test asserting all four CTEs are
materialized.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The issue and MR ingestion paths previously inserted labels, assignees,
and reviewers one row at a time inside a transaction. For entities with
many labels or assignees, this issued N separate SQLite statements where
a single multi-row INSERT suffices.
Replace the per-row loops with batch INSERT functions that build a
single `INSERT OR IGNORE ... VALUES (?1,?2),(?1,?3),...` statement per
chunk. Chunks are capped at 400 rows (BATCH_LINK_ROWS_MAX) to stay
comfortably below SQLite's default 999 bind-parameter limit.
Affected paths:
- issues.rs: link_issue_labels_batch_tx, insert_issue_assignees_batch_tx
- merge_requests.rs: insert_mr_labels_batch_tx,
insert_mr_assignees_batch_tx, insert_mr_reviewers_batch_tx
New tests verify deduplication (OR IGNORE), multi-chunk correctness,
and equivalence with the old per-row approach. A perf benchmark
(bench_issue_assignee_insert_individual_vs_batch) demonstrates the
speedup across representative assignee set sizes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove configuration files that are no longer used:
- .opencode/rules: OpenCode rules file, superseded by project CLAUDE.md
and ~/.claude/ rules directory structure
- .roam/fitness.yaml: Roam fitness tracking config, unrelated to this
project
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove iterative feedback files that were used during plan development.
These files captured review rounds but are no longer needed now that the
plans have been finalized:
- plans/lore-service.feedback-{1,2,3,4}.md
- plans/time-decay-expert-scoring.feedback-{1,2,3,4}.md
- plans/tui-prd-v2-frankentui.feedback-{1,2,3,4,5,6,7,8,9}.md
The canonical plan documents remain; only the review iteration artifacts
are removed to reduce clutter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Draft plan for replacing Tokio + Reqwest with Asupersync, a cancel-correct
async runtime with structured concurrency guarantees.
Motivation:
- Current Ctrl+C during join_all silently drops in-flight HTTP requests
- ShutdownSignal is a hand-rolled AtomicBool with no structured cancellation
- No deterministic testing for concurrent ingestion patterns
- Tokio provides no structured concurrency guarantees
Plan structure:
- Complete inventory of tokio/reqwest usage in production and test code
- Phase 0: Preparation (reduce tokio surface before swap)
- Extract signal handler to single function
- Replace tokio::sync::Mutex with std::sync::Mutex where appropriate
- Create HTTP adapter trait for pluggable backends
- Phase 1-5: Progressive migration with detailed implementation steps
Trade-offs accepted:
- Nightly Rust required (asupersync dependency)
- Pre-1.0 runtime dependency (mitigated by adapter layer + version pinning)
- Deeper function signature changes for Cx threading
This is a reference document for future implementation, not an immediate
change to the runtime.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update CLAUDE.md and README.md with documentation for recently added
features:
CLAUDE.md:
- Add robot mode examples for `lore --robot related`
- Add example for `lore --robot init --refresh`
README.md:
- Add full documentation section for `lore me` command including all
flags (--issues, --mrs, --mentions, --activity, --since, --project,
--all, --user, --reset-cursor) and section descriptions
- Add documentation section for `lore related` command with entity mode
and query mode examples
- Expand `lore init` section with --refresh flag documentation explaining
project registration workflow
- Add quick examples in the features section
- Update version number in example output (0.9.2)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend the CLI autocorrection pipeline with two new correction rules that
help agents recover from common typos and misunderstandings:
1. SubcommandFuzzy (threshold 0.85): Fuzzy-matches typo'd subcommands
against the canonical list. Examples:
- "issuess" → "issues"
- "timline" → "timeline"
- "serach" → "search"
Guards prevent false positives:
- Words that look like misplaced global flags are skipped
- Valid command prefixes are left to clap's infer_subcommands
2. FlagAsSubcommand: Detects when agents type subcommands as flags.
Some agents (especially Codex) assume `--robot-docs` is a flag rather
than a subcommand. This rule converts:
- "--robot-docs" → "robot-docs"
- "--generate-docs" → "generate-docs"
Also improves error messages in main.rs:
- MissingRequiredArgument: Contextual example based on detected subcommand
- MissingSubcommand: Lists common commands
- TooFewValues/TooManyValues: Command-specific help hints
Added CANONICAL_SUBCOMMANDS constant enumerating all valid subcommands
(including hidden ones) for fuzzy matching. This ensures agents that know
about hidden commands still get typo correction.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new --mentions flag to the `lore me` command that surfaces items
where the user is @-mentioned but NOT already assigned, authoring, or
reviewing. This fills an important gap in the personal work dashboard:
cross-team requests and callouts that don't show up in the standard
issue/MR sections.
Implementation details:
- query_mentioned_in() scans notes for @username patterns, then filters
out entities where the user is already an assignee, author, or reviewer
- MentionedInItem type captures entity_type (issue/mr), iid, title, state,
project path, attention state, and updated timestamp
- Attention state computation marks items as needs_attention when there's
recent activity from others
- Recency cutoff (7 days) prevents surfacing stale mentions
- Both human and robot renderers include the new section
The robot mode schema adds mentioned_in array with me_mentions field
preset for token-efficient output.
Test coverage:
- mentioned_in_finds_mention_on_unassigned_issue: basic case
- mentioned_in_excludes_assigned_issue: no duplicate surfacing
- mentioned_in_excludes_author_on_mr: author already sees in authored MRs
- mentioned_in_excludes_reviewer_on_mr: reviewer already sees in reviewing
- mentioned_in_uses_recency_cutoff: old mentions filtered
- mentioned_in_respects_project_filter: scoping works
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When new projects are added to the config file, `lore sync` doesn't pick
them up because project discovery only happens during `lore init`.
Previously, users had to use `--force` to overwrite their entire config.
The new `--refresh` flag reads the existing config and updates the
database to match, without modifying the config file itself.
Features:
- Validates GitLab authentication before processing
- Registers new projects from config into the database
- Detects orphan projects (in DB but removed from config)
- Interactive mode: prompts to delete orphans (default: No)
- Robot mode: returns JSON with orphan info, no prompts
Usage:
lore init --refresh # Interactive
lore --robot init --refresh # JSON output
Improved UX: When running `lore init` with an existing config and no
flags, the error message now suggests using `--refresh` to register
new projects or `--force` to overwrite the config file.
Implementation:
- Added RefreshOptions and RefreshResult types to init module
- Added run_init_refresh() for core refresh logic
- Added delete_orphan_projects() helper for orphan cleanup
- Added handle_init_refresh() in main.rs for CLI handling
- Added JSON output types for robot mode
- Registered --refresh in autocorrect.rs command flags registry
- --refresh conflicts with --force (mutually exclusive)
These HTML files were generated for one-time analysis/review purposes
and should not be tracked in the repository.
Files removed:
- api-review.html
- gitlore-sync-explorer.html
- phase-a-review.html
Issue discussion sync was ~10x slower than MR discussion sync because it
used a fully sequential pattern: fetch one issue's discussions, write to
DB, repeat. MR sync already used a prefetch pattern with concurrent HTTP
requests followed by sequential DB writes.
This commit brings issue discussion sync to parity with MRs:
Architecture (prefetch pattern):
1. HTTP phase: Concurrent fetches via `join_all()` with batch size
controlled by `dependent_concurrency` config (default 8)
2. Transform phase: Normalize discussions and notes during prefetch
3. DB phase: Sequential writes with proper transaction boundaries
Changes:
- gitlab/client.rs: Add `fetch_all_issue_discussions()` to mirror
the existing MR pattern for API consistency
- discussions.rs: Replace `ingest_issue_discussions()` with:
* `prefetch_issue_discussions()` - async HTTP fetch + transform
* `write_prefetched_issue_discussions()` - sync DB writes
* New structs: `PrefetchedIssueDiscussions`, `PrefetchedDiscussion`
- orchestrator.rs: Update `sync_discussions_sequential()` to use
concurrent prefetch for each batch instead of sequential calls
- surgical.rs: Update single-issue surgical sync to use new functions
- mod.rs: Update public exports
Expected improvement: 5-10x speedup on issue discussion sync (from ~50s
to ~5-10s for large projects) due to concurrent HTTP round-trips.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When `--limit` is omitted, the default value is `usize::MAX` to mean
"unlimited". The previous code used `(limit + 1) as i64` to fetch one
extra row for "has more" detection. This caused integer overflow:
usize::MAX + 1 = 0 (wraps around)
The resulting `LIMIT 0` clause returned zero rows, making the `who`
subcommands appear to find nothing even when data existed.
Fix: Use `saturating_add(1)` to cap at `usize::MAX` instead of wrapping,
then `.min(i64::MAX as usize)` to ensure the value fits in SQLite's
signed 64-bit LIMIT parameter.
Includes regression tests that verify `usize::MAX` limit returns results.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update beads issue tracking state and expand the GitLab TODOs
notifications integration design document with additional
implementation details.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NEAR is an FTS5 function (NEAR(term1 term2, N)), not an infix operator like
AND/OR/NOT. Passing it through unquoted in Safe mode was incorrect - it would
be treated as a literal term rather than a function call.
Users who need NEAR proximity search should use FtsQueryMode::Raw which
passes the query through verbatim to FTS5.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Several improvements to the ingestion orchestrator:
1. Stale lock reclamation consolidation:
Previously, reclaim_stale_locks() was called redundantly in multiple
drain functions (drain_resource_events, drain_closes_issues, etc.).
Now it's called once at sync entry points (ingest_project_issues,
ingest_project_mrs) to reduce overhead and DB contention.
2. Fix status_enrichment_mode error values:
- "fetched" -> "error" when project path is missing
- "fetched" -> "fetch_error" when GraphQL fetch fails
These values are used in robot mode JSON output and should accurately
reflect the error condition.
3. Add batch_size zero guard:
Added .max(1) to batch_size calculation to prevent panic in .chunks()
when config.sync.dependent_concurrency is 0. This makes the code
defensive against misconfiguration.
These changes improve correctness and reduce unnecessary DB operations
during sync, particularly beneficial for large projects with many entities.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add pre_truncate_description() to prevent unbounded memory allocation when
processing pathologically large descriptions (e.g., 500MB base64 blobs in
issue descriptions).
Previously, the document extraction pipeline would:
1. Allocate memory for the entire description
2. Append to content buffer
3. Only truncate at the end via truncate_hard_cap()
For a 500MB description, this would allocate 500MB+ before truncation.
New approach:
1. Check description size BEFORE appending
2. If over limit, truncate at UTF-8 boundary immediately
3. Add human-readable marker: "[... description truncated from 500.0MB to 2.0MB ...]"
4. Log warning with original size for observability
Also adds format_bytes() helper for human-readable byte sizes (B, KB, MB).
This is applied to both issue and MR document extraction in extractor.rs,
protecting the embedding pipeline from OOM on malformed GitLab data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhance the timeline command with two major improvements:
1. Entity-direct seeding syntax (bypass search):
lore timeline issue:42 # Timeline for specific issue
lore timeline i:42 # Short form
lore timeline mr:99 # Timeline for specific MR
lore timeline m:99 # Short form
This directly resolves the entity and gathers ALL its discussions without
requiring search/embedding. Useful when you know exactly which entity you want.
2. Round-robin evidence note selection:
Previously, evidence notes were taken in FTS rank order, which could result
in all notes coming from a single high-traffic discussion. Now we:
- Fetch 5x the requested limit (or minimum 50)
- Group notes by discussion_id
- Select round-robin across discussions
- This ensures diverse evidence from multiple conversations
API changes:
- Renamed total_events_before_limit -> total_filtered_events (clearer semantics)
- Added resolve_entity_by_iid() in timeline.rs for IID-based entity resolution
- Added seed_timeline_direct() in timeline_seed.rs for search-free seeding
- Added round_robin_select_by_discussion() helper function
The entity-direct mode uses search_mode: "direct" to distinguish from
"hybrid" or "lexical" search modes in the response metadata.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement `lore related` command for discovering semantically similar entities
using vector embeddings. Supports two modes:
Entity mode:
lore related issues 42 # Find entities similar to issue #42
lore related mrs 99 # Find entities similar to MR !99
Query mode:
lore related "auth bug" # Find entities matching free text query
Key features:
- Uses existing embedding infrastructure (nomic-embed-text via Ollama)
- Computes shared labels between source and results
- Shows similarity scores as percentage (0-100%)
- Warns when all results have low similarity (<30%)
- Warns for short queries (<=2 words) that may produce noisy results
- Filters out discussion/note documents, returning only issues and MRs
- Handles orphaned documents gracefully (skips if entity deleted)
- Robot mode JSON output with {ok, data, meta} envelope
Implementation details:
- distance_to_similarity() converts L2 distance to 0-1 score: 1/(1+distance)
- Uses saturating_add/saturating_mul for overflow safety on limit parameter
- Proper error handling for missing embeddings ("run lore embed first")
- Project scoping via -p flag with fuzzy matching
CLI integration:
- Added to autocorrect.rs command registry
- Added Related variant to Commands enum in cli/mod.rs
- Wired into main.rs with handle_related()
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add foreign key constraint on discussions.merge_request_id to prevent orphaned
discussions when MRs are deleted. SQLite doesn't support ALTER TABLE ADD CONSTRAINT,
so this migration recreates the table with:
1. New table with FK: REFERENCES merge_requests(id) ON DELETE CASCADE
2. Data copy with FK validation (only copies rows with valid MR references)
3. Table swap (DROP old, RENAME new)
4. Full index recreation (all 10 indexes from migrations 002-022)
The migration also includes a CHECK constraint ensuring mutual exclusivity:
- Issue discussions have issue_id NOT NULL and merge_request_id NULL
- MR discussions have merge_request_id NOT NULL and issue_id NULL
Also fixes run_migrations() to properly propagate query errors instead of
silently returning unwrap_or defaults, improving error diagnostics.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Captures design decisions and acceptance criteria for adding GitLab
TODO support to lore. This plan was developed through user interview
to ensure the feature aligns with actual workflows.
Key design decisions:
- Read-only scope (no mark-as-done operations)
- Three integration points: --todos flag, activity enrichment, lore todos
- Account-wide: --project does NOT filter todos (unlike issues/MRs)
- Separate signal: todos don't affect attention state calculation
- Snapshot sync: missing todos = marked done elsewhere = delete locally
The plan covers:
- Database schema (todos table + indexes)
- GitLab API client extensions
- Sync pipeline integration
- Action type handling and grouping
- CLI commands and robot mode schemas
- Non-synced project handling with [external] indicator
Implementation is organized into 5 rollout slices:
A: Schema + Client, B: Sync, C: lore todos, D: lore me, E: Polish
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhances sync status reporting to include granular per-entity counts
that were added in database migration 027. This provides better
visibility into what each sync run actually processed.
New fields in SyncRunInfo and robot mode JSON:
- issues_fetched / issues_ingested: issue sync counts
- mrs_fetched / mrs_ingested: merge request sync counts
- skipped_stale: entities skipped due to staleness
- docs_regenerated / docs_embedded: document pipeline counts
- warnings_count: non-fatal issues during sync
Robot mode optimization:
- Uses skip_serializing_if = "is_zero" to omit zero-value fields
- Reduces JSON payload size for typical sync runs
- Maintains backwards compatibility (fields are additive)
SQL query now reads all 8 new columns from sync_runs table,
with defensive unwrap_or(0) for NULL handling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates the `lore robot-docs` manifest with comprehensive documentation
for the new since-last-check inbox feature, enabling AI agents to
discover and use the functionality programmatically.
robot-docs manifest additions:
- since_last_check response schema with cursor_iso, groups, events
- --reset-cursor flag documentation
- Design notes: cursor persistence location, --project filter behavior
- Example commands in personal_dashboard section
Agent instruction updates (AGENTS.md, CLAUDE.md):
- Added --mrs, --project, --user flags to command examples
- Added --reset-cursor example
- Aligned both files for consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a cursor-based notification inbox that surfaces actionable
events from others since the user's last `lore me` invocation. This
addresses the core UX need: "what happened while I was away?"
Event Sources (three-way UNION query):
1. Others' comments on user's open issues/MRs
2. @mentions on ANY item (not restricted to owned items)
3. Assignment/review-request system notes mentioning user
Mention Detection:
- SQL LIKE pre-filter for performance, then regex validation
- Word-boundary-aware: rejects "alice" in "@alice-bot" or "alice@corp.com"
- Domain rejection: "@alice.com" not matched (prevents email false positives)
- Punctuation tolerance: "@alice," "@alice." "(@ alice)" all match
Cursor Watermark Pattern:
- Global watermark computed from ALL projects before --project filtering
- Ensures --project display filter doesn't permanently skip events
- Cursor advances only after successful render (no data loss on errors)
- First run establishes baseline (no inbox shown), subsequent runs show delta
Output:
- Human: color-coded event badges, grouped by entity, actor + timestamp
- Robot: standard envelope with since_last_check object containing
cursor_iso, total_event_count, and groups array with nested events
CLI additions:
- --reset-cursor flag: clears cursor (next run shows no new events)
- Autocorrect: --reset-cursor added to known me command flags
Tests cover:
- Mention with trailing comma/period/parentheses (should match)
- Email-like text "@alice.com" (should NOT match)
- Domain-like text "@alice.example" (should NOT match)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Database(rusqlite::Error) catch-all variant was suggesting
'lore reset --yes' for ALL database errors, including transient
SQLITE_BUSY lock contention. This was wrong on two counts:
1. `lore reset` is not implemented (prints "not yet implemented")
2. Nuking the database is not the fix for a transient lock
Changes:
- Detect SQLITE_BUSY specifically via sqlite_error_code() and provide
targeted advice: "Another process has the database locked" with
common causes (cron sync, concurrent lore command)
- Map SQLITE_BUSY to ErrorCode::DatabaseLocked (exit code 9) instead
of DatabaseError (exit code 10) — semantically correct
- Set BUSY actions to ["lore cron status"] (diagnostic) instead of
the useless "lore sync --force" (--force overrides the app-level
lock table, but SQLITE_BUSY fires before that table is even reached)
- Fix MigrationFailed suggestion: also referenced non-existent
'lore reset', now says "try again" with lore migrate / lore doctor
- Non-BUSY database errors get a simpler suggestion pointing to
lore doctor (no more phantom reset command)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Organizations without GitLab Premium/Ultimate don't have work item
statuses configured - all their issues have status_name = NULL.
Previously, the me command filtered to only 'In Progress' and
'In Review' statuses, showing zero issues for these organizations.
Now includes NULL status as a fallback for graceful degradation.