Skip to content

Normalize issue ids in relation getters - #210

Open
mkwlsn wants to merge 1 commit into
marcus:mainfrom
mkwlsn:fix/normalize-ids-in-relation-getters
Open

Normalize issue ids in relation getters#210
mkwlsn wants to merge 1 commit into
marcus:mainfrom
mkwlsn:fix/normalize-ids-in-relation-getters

Conversation

@mkwlsn

@mkwlsn mkwlsn commented Sep 1, 2026

Copy link
Copy Markdown

GetIssue normalizes a bare id, but six relation getters do not. A caller that passes the raw argument resolves the issue and then silently gets nothing back for its relations.

Repro

td show abc123      # resolves, but omits handoff, session log, git state, blocking edges
td show td-abc123   # complete record

Both return the same issue with an identical first line. On a real issue the bare form printed 24 lines and the prefixed form 53. There is no error, and the output ends cleanly on SESSIONS INVOLVED, so it reads as a complete record. A blocked issue shows no blocker.

Root cause

cmd/show.go:113 keeps the raw argument:

issueID := args[0]

GetIssue on line 138 succeeds because it normalizes its own local copy, so issueID is still bare. Lines 144 to 158 pass it to GetLogs, GetLatestHandoff, GetLinkedFiles, GetDependencies, GetBlockedBy, and GetStartSnapshot. Each queries abc123 against rows keyed td-abc123 and returns empty. Each call discards its error with _, so nothing surfaces.

The fix

Normalize in the six getters, matching how AddComment, AddHandoff, and about forty other call sites in internal/db already do it.

I went with the DB layer rather than issueID = issue.ID at the callsite because the callsite fix leaves the next caller of these getters exposed to the same bug. Happy to switch to the one-line version if you would rather keep normalization at the CLI boundary.

Relationship to #199

#199 named GetLatestHandoff(issueID) as part of this defect. Its write paths now normalize, so td comment abc123 succeeds and stores td-abc123 correctly. The read path it described was still open, and that is what this fixes. I have not used a closing keyword since the scope of that issue is yours to judge.

Tests

internal/db/bare_id_relations_test.go covers GetDependencies, GetBlockedBy, and GetLogs, asserting the bare and prefixed forms agree. Without the change it fails:

bare id returned 0 deps, prefixed returned 1; the two must agree
bare id returned 0, prefixed returned 1; the two must agree
bare id returned 0 logs, prefixed returned 1; the two must agree

make fmt clean. make test green across all packages, including the e2e suite.

Note on scope

td dep add still rejects bare ids with FOREIGN KEY constraint failed, which is a loud failure rather than a silent one, so I left it alone. Worth deciding separately whether bare ids should be accepted uniformly or rejected uniformly. Right now td dep and td tree accept them, td dep add rejects them, and td show accepted them while quietly returning less.

GetIssue normalizes a bare id, but six relation getters did not, so callers
that pass the raw argument resolve the issue and then silently get nothing
back for its relations.

The visible case is `td show`. cmd/show.go:113 keeps the raw arg in issueID.
GetIssue on line 138 succeeds because it normalizes its own local copy, leaving
issueID bare. Lines 144-158 pass that to GetLogs, GetLatestHandoff,
GetLinkedFiles, GetDependencies, GetBlockedBy, and GetStartSnapshot, each of
which queries `abc123` against rows keyed `td-abc123`. Every one returns empty,
and every call discards its error, so nothing surfaces.

Result: `td show abc123` and `td show td-abc123` return the same issue, but the
bare form omits CURRENT HANDOFF, SESSION LOG, GIT STATE, and the BLOCKED BY /
BLOCKS edges. On a real issue that was 24 lines against 53. The output ends
cleanly, so it reads as complete, and a blocked issue appears unblocked.

Fixed in the DB layer rather than at the callsite, matching how AddComment,
AddHandoff, and about forty other call sites already normalize. A callsite fix
would leave the next caller of these getters exposed to the same bug.

marcus#199 named GetLatestHandoff as part of the same defect. Its write paths now
normalize, so `td comment abc123` works, but the read path it described did not.

Test fails without the change, with bare returning 0 where prefixed returns 1.
make fmt clean, make test green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant