There's different sizes of TODO. For anything beyond small cleanups, yeah, an issue is probably warranted. But, filing tasks in the issue tracker aren't always the best solution either. They often become out of sync with the state of the code, and who's going to trawl through all of those low-priority issues on a regular basis? To mitigate the de-synchronization, I tend to embed links to the issue in the comment like: # TODO: Frob the foobar issue #4376
The only way an issue about technical debt becomes irrelevant is the debt is not there any more. I don't know how others treat an issue tracker; on my team, we go through issues at the start of every sprint and possibly re-prioritise. Issue became irrelevant? Close. Move on.
> They often become out of sync with the state of the code
I try to write a test when I open a ticket, demonstrating the desired behavior, and mark it such that it's checked for failure (so we notice if we've fixed it in passing) unless an environment variable is set to the particular ticket number. Sometimes I also include a test demonstrating current behavior - this helps surface the tickets if someone is working on something related.