The "new hire test"
When I'm thinking about technical debt, I like to use the "new hire test".
In this, I imagine that somebody joins the team and starts asking questions about how the code works. It makes it easy to spot surprising things.
"5 parameters work one way but the 6th differently. Why?"
"Before deployment you need to do X. Why it's needed to be done manually instead of automatically?"
"Most events go through A->B->C, but this one goes A->C directly. Why?"
"All other components go through an API but this specific one reads directly from the database. What's the reason?"
When my imaginary answer is along the lines of "it was written like this and we're not touching it", or "it's because back then the teams were separated that way", or the worst "well, somebody cut some corners" then I know that I have work to do.
Of course, there are good answers to these questions. Maybe there is a hot path that generates most of the costs and it pays off not to go through an API but go directly to a database. Or when automating a manual step brings more problems than what it solves. Or maybe the 6th parameter is fundamentally different than the rest and needs to work differently.
So the benefit of the exercise is not to ask all the questions but to identify the ones that have no good answers.
While it's unrealistic to expect that a system's current state is exactly how a full rewrite would look like, it's important to move that way.