Implement lore sync --issue <IID> --mr <IID> -p <project> for on-demand
sync of specific entities without running the full project-wide pipeline.
Completes in seconds by fetching only targeted entities, their discussions,
resource events, and dependent data, then scoping doc regeneration and
embedding to only affected documents.
Pipeline stages: PREFLIGHT -> TOCTOU -> INGEST -> DEPENDENTS -> DOCS -> EMBED
New files:
- src/ingestion/surgical.rs: TOCTOU guard, preflight fetch, per-entity ingest
- src/ingestion/surgical_tests.rs: 17 unit/wiremock tests
- src/cli/commands/sync_surgical.rs: 719-line orchestrator
- src/embedding/pipeline_tests.rs: scoped embedding tests
- src/gitlab/client_tests.rs: get_by_iid wiremock tests
- migrations/027_surgical_sync_runs.sql: 12 surgical columns + indexes
Key changes:
- SyncOptions: issue_iids, mr_iids, project, preflight_only fields
- SyncResult: surgical_mode, surgical_iids, entity_results fields
- SyncRunRecorder: surgical lifecycle methods (set_surgical_metadata, etc)
- GitLabClient: get_issue_by_iid, get_mr_by_iid
- Scoped docs: regenerate_dirty_documents_for_sources
- Scoped embed: embed_documents_by_ids
- run_sync dispatches to run_sync_surgical when is_surgical()
- robot-docs updated with surgical sync schema + workflows
- All 1019 tests pass, clippy clean
Closes: bd-1sc6, bd-tiux, bd-159p, bd-1lja, bd-hs6j, bd-1elx, bd-arka,
bd-3sez, bd-wcja, bd-kanh, bd-1i4i, bd-3bec
3.5 KiB
Trace/File-History Empty-Result Diagnostics
AC-1: Human mode shows searched paths on empty results
When lore trace <path> returns 0 chains in human mode, the output includes the resolved path(s) that were searched. If renames were followed, show the full rename chain.
AC-2: Human mode shows actionable reason on empty results
When 0 chains are found, the hint message distinguishes between:
- "No MR file changes synced yet" (mr_file_changes table is empty for this project) -> suggest
lore sync - "File paths not found in MR file changes" (sync has run but this file has no matches) -> suggest checking the path or that the file may predate the sync window
AC-3: Robot mode includes diagnostics object on empty results
When total_chains == 0 in robot JSON output, add a "diagnostics" key to "meta" containing:
paths_searched: [...](already present asresolved_pathsin data -- no duplication needed)hints: [string]-- same actionable reasons as AC-2 but machine-readable
AC-4: Info-level logging at each pipeline stage
Add tracing::info! calls visible with -v:
- After rename resolution: number of paths found
- After MR query: number of MRs found
- After issue/discussion enrichment: counts per MR
AC-5: Apply same pattern to lore file-history
All of the above (AC-1 through AC-4) also apply to lore file-history empty results.
Secure Token Resolution for Cron
AC-6: Config file supports optional stored token
config.json accepts an optional "token" field in the gitlab section. Existing configs without this field continue to load without error.
AC-7: Token resolution chain — env var wins, config file falls back
When resolving the GitLab token, the CLI checks in order: (1) environment variable named by tokenEnvVar, (2) token field in config file. The first non-empty value wins. If neither is set, the existing TOKEN_NOT_SET error is returned.
AC-8: lore token set stores token securely
A new lore token set subcommand:
- Accepts token via
--tokenflag, stdin pipe, or interactive prompt (masked input) - Validates the token against the GitLab API before storing
- Writes the token into the existing
config.jsonwithout disturbing other fields - Sets file permissions to
0600(owner read/write only) on the config file after writing - Works in both human and robot mode
AC-9: lore token show reveals stored token
A new lore token show subcommand:
- Shows the token source (env var or config file) and a masked version by default
--unmaskflag reveals the full token value- Works in both human and robot mode
AC-10: All token lookups use centralized resolver
The 5 call sites that currently do std::env::var(&config.gitlab.token_env_var) are replaced with a single config.gitlab.resolve_token() method. No inline env var lookups remain for the GitLab token.
AC-11: lore cron install warns when no stored token
After installing the cron entry, if resolve_token() would fail without an env var (i.e., no token in config file), print a warning directing the user to run lore token set.
AC-12: TOKEN_NOT_SET error suggests lore token set
The error suggestion and actions array for TOKEN_NOT_SET include lore token set as the primary recommended fix, with env var export as the secondary option.
AC-13: lore doctor reports token source
The doctor command's GitLab check shows where the token was found: "from config file" or "from GITLAB_TOKEN env var", helping users diagnose cron issues.