fix(cli): stop --full-path from degrading silently (#785) - #786
Open
danmackinlay wants to merge 1 commit into
Open
fix(cli): stop --full-path from degrading silently (#785)#786danmackinlay wants to merge 1 commit into
danmackinlay wants to merge 1 commit into
Conversation
`--full-path` exists to emit openable filesystem paths. When a result can't be resolved on disk it falls back to the `qmd://` URI, which is the right call — but search/query did it unannounced *and* dropped the docid, leaving the row with neither a usable path nor an identifier field. Since 070147d (literal paths) that fallback no longer fires for normalization reasons: it means the file moved or was deleted since the last index, which is worth saying out loud. - search/query now decide per row, like multiGet() already did: resolved → on-disk path, no docid; unresolved → `qmd://` URI *with* the docid. Applies to the cli, json, md, xml and csv formats. - search/query/get/multi-get print a notice to stderr naming how many results fell back and pointing at `qmd update`. stdout stays machine-readable. - `search --format csv` always emits the `docid` column (empty when the row resolved) so column positions are stable. The `--full-path` header used to drop it, which also disagreed with printEmptySearchResults(), whose header always carries `docid`. `--files` keeps its current two-column shape under `--full-path` so `cut -d, -f2 | xargs` pipelines don't break; unresolved rows there show the qmd:// URI and are covered by the stderr notice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Dear tobi/qmd,
We would like to acknowledge that we have received your request and a ticket has been created.
A support representative will be reviewing your request and will send you a personal response.(usually within 24-48 hours).
Thank you for your patience.
…On Fri, Jul 24 2026, at 09:15 PM, tobi/qmd ***@***.***> wrote:
Fixes #785. Independent of (#785) #784 — branched from (#784) main, no overlap beyond both adding a [Unreleased] changelog block. --full-path exists to emit openable filesystem paths. Falling back to the qmd:// URI when a result can't be resolved is the right call, but search/ query did it unannounced and dropped the docid, so the row ended up with neither a usable path nor an identifier field — and nothing distinguished it from a resolved row.
Since (literal paths) this no longer fires for normalization reasons. It fires when the file moved or was deleted since the last index, which is useful information that was being swallowed. (070147d) 070147d
Before $ qmd search beta --full-path --json # beta.md was moved after indexing [ { "score": 0, "file": "./alpha.md", "title": "Alpha" }, { "score": 0, "file": "qmd://stale/beta.md", "title": "Beta" } ]
$ echo $? 0
No docid on the second row, nothing on stderr. qmd get --full-path and multi-get --full-path already kept the docid — only outputResults() keyed the decision off the flag rather than off the row.
After $ qmd search beta --full-path --json [ { "score": 0, "file": "./alpha.md", "title": "Alpha" }, { "docid": "#4cbea2", "score": 0, "file": "qmd://stale/beta.md", "title": "Beta" } ] warning: --full-path could not resolve 1 of 2 results on disk (moved or deleted since indexing); showing qmd:// + docid instead. Run 'qmd update' to refresh the index.
The warning is on stderr, so stdout stays machine-readable and pipelines are unaffected.
Changes Per-row decision in , matching search/ query multiGet(): resolved → on-disk path, no docid; unresolved → qmd:// URI with docid. Applies to cli, json, md, xml, csv. Rows are resolved up front so the count is known before anything prints. stderr notice from search, query, get and multi-get when any row falls back, pointing at qmd update. (empty when the row resolved), so columns stay positional. The search --format csv always emits the docid column --full-path header used to drop it — which also disagreed with printEmptySearchResults(), whose CSV header always carries docid, so an empty result set and a non-empty one printed different headers for the same command.
Two judgement calls worth a look Its --files is left alone. --full-path shape stays score,path, so cut -d, -f2 | xargs keeps working; adding a leading docid field only for unresolved rows would break positional parsing, and adding it unconditionally would break every existing pipeline. Unresolved rows there show the qmd:// URI and are covered by the stderr notice. Happy to change it if you'd rather have consistency with CSV. Exit code stays 0. A moved file is a stale index, not a failed search. The notice is the signal.
Tests
New test/full-path-fallback.test.ts (7 cases) over a corpus where one file is moved out from under the index: docid retention in --json, the CSV column layout, docid in the default CLI format, get and multi-get warnings, no warning when everything resolves, and no behavior change without --full-path. Existing --full-path tests in cli.test.ts (which assert resolved rows still drop the docid) pass unchanged.
Full suite: 954 passed / 7 skipped. mcp.test.ts > MCP HTTP Transport fails on my machine ( SqliteError: no such column: T.name) identically on a clean main — environmental, unrelated. You can view, comment on, or merge this pull request online at: #786 (#786) Commit Summary c6fa94a fix(cli): stop --full-path from degrading silently (#785) (c6fa94a) File Changes
( 4 files) (https://github.com/tobi/qmd/pull/786/files) M CHANGELOG.md
(19) (https://github.com/tobi/qmd/pull/786/files#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed) M README.md
(3) (https://github.com/tobi/qmd/pull/786/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5) M src/cli/qmd.ts
(97) (https://github.com/tobi/qmd/pull/786/files#diff-e7252cdb14bd10e7feaedc038d3506947354fe9b644cd034e37a7f39c580859f) A test/full-path-fallback.test.ts
(210) (https://github.com/tobi/qmd/pull/786/files#diff-5d07b48a45e8573dc7b659dcecc08a3a9fb6a647d10c1273525fc3670f235187) Patch Links: https://github.com/tobi/qmd/pull/786.patch (https://github.com/tobi/qmd/pull/786.patch) https://github.com/tobi/qmd/pull/786.diff (https://github.com/tobi/qmd/pull/786.diff)
—
Reply to this email directly, view it on GitHub, or (#786?email_source=notifications&email_token=BRF3HG4UC2DKW5FHPAG7XYL5GPGVTA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRZGM2DGOBRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW) unsubscribe. (https://github.com/notifications/unsubscribe-auth/BRF3HGYLQBBIPMH456X2FU35GPGVTAVCNFSNUABGKJSXA33TNF2G64TZHMYTCMJSGM3DKMZQGE5US43TOVSTWNBZG4ZDCMBUGYYDPILWAI)
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and (https://github.com/notifications/mobile/ios/BRF3HG6BSQOWCSJA5P5HEKD5GPGVTA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRZGM2DGOBRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVJTG633UMVZF62LPOM) Android. Download it today! (https://github.com/notifications/mobile/android/BRF3HG4GYR6KXL6DTIQI4XT5GPGVTA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRZGM2DGOBRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZTG633UMVZF6YLOMRZG62LE)
You are receiving this because you are subscribed to this thread. Message ID: <tobi/qmd/pull/786 @ github . com> [
{
***@***.***": "http://schema.org",
***@***.***": "EmailMessage",
"potentialAction": {
***@***.***": "ViewAction",
"target": "#786?email_source=notifications\u0026email_token=BRF3HG4V4PLS622UL4KZLND5GPGVTA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRZGM2DGOBRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVNTW2YLJNRPWG3DJMNVQ",
"url": "#786?email_source=notifications\u0026email_token=BRF3HG4V4PLS622UL4KZLND5GPGVTA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRZGM2DGOBRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVNTW2YLJNRPWG3DJMNVQ",
"name": "View Pull Request"
},
"description": "View this Pull Request on GitHub",
"publisher": {
***@***.***": "Organization",
"name": "GitHub",
"url": "https://github.com"
}
}
]
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #785. Independent of #784 — branched from
main, no overlap beyond both adding a[Unreleased]changelog block.--full-pathexists to emit openable filesystem paths. Falling back to theqmd://URI when a result can't be resolved is the right call, butsearch/querydid it unannounced and dropped the docid, so the row ended up with neither a usable path nor an identifier field — and nothing distinguished it from a resolved row.Since 070147d (literal paths) this no longer fires for normalization reasons. It fires when the file moved or was deleted since the last index, which is useful information that was being swallowed.
Before
No
docidon the second row, nothing on stderr.qmd get --full-pathandmulti-get --full-pathalready kept the docid — onlyoutputResults()keyed the decision off the flag rather than off the row.After
The warning is on stderr, so stdout stays machine-readable and pipelines are unaffected.
Changes
search/query, matchingmultiGet(): resolved → on-disk path, no docid; unresolved →qmd://URI with docid. Applies tocli,json,md,xml,csv. Rows are resolved up front so the count is known before anything prints.search,query,getandmulti-getwhen any row falls back, pointing atqmd update.search --format csvalways emits thedocidcolumn (empty when the row resolved), so columns stay positional. The--full-pathheader used to drop it — which also disagreed withprintEmptySearchResults(), whose CSV header always carriesdocid, so an empty result set and a non-empty one printed different headers for the same command.Two judgement calls worth a look
--filesis left alone. Its--full-pathshape staysscore,path, socut -d, -f2 | xargskeeps working; adding a leading docid field only for unresolved rows would break positional parsing, and adding it unconditionally would break every existing pipeline. Unresolved rows there show theqmd://URI and are covered by the stderr notice. Happy to change it if you'd rather have consistency with CSV.Tests
New
test/full-path-fallback.test.ts(7 cases) over a corpus where one file is moved out from under the index: docid retention in--json, the CSV column layout, docid in the default CLI format,getandmulti-getwarnings, no warning when everything resolves, and no behavior change without--full-path. Existing--full-pathtests incli.test.ts(which assert resolved rows still drop the docid) pass unchanged.Full suite: 954 passed / 7 skipped.
mcp.test.ts > MCP HTTP Transportfails on my machine (SqliteError: no such column: T.name) identically on a cleanmain— environmental, unrelated.