This morning I hunted down a bug that was causing relative anchors to have the wrong offset. It turned out to be a more fundamental issue than I hoped. Essentially, a canonical symbol with relative anchors does its offset math with the 32B hashes where 2B addresses will ultimately live. Once it is rendered into a ROM (or loaded into memory), the offset is no longer correct.
The deeper issue is that either we need to have *anchors* become part of the canonical symbol spec, or we need to permanently assume that all addresses will be 2B and do our math based on that.
To be honest, I've been wondering how I could be "sure" that people wouldn't inflate the spec to have larger address space... so perhaps this is a blessing in disguise? It would make translating a huge pain, because it would be difficult to know which literals are addresses that can be adjusted. Assuming the 2B gap is also the simplest solution, so perhaps I should just leave it at that.
---
After a few hours of digging around and reacquainting myself with my assembly anchor logic, I was able to get addressing working according to the new plan for routine symbols. Most of the work took a few minutes, implementing a parallel "true length" counter for routine symbol rendering to use in place of the incorrect "render.len()". The rest of the time was spent hunting down an edge case which turned out to be an off-by-one error due to forgetting the implicit CAL16 opcode at the end of a RoutineCall source token; RoutineAddress tokens have a true render length of 3, but the RoutineCall tokens have 4. Either way, I can continue on with writing more Co to test device IO.