I finally managed to do the thing I wanted with AsciiDoctor!
The key bit, which I found by reading another extension, was that there is a parse_content method on extensions. This will parse some AsciiDoc text and append it to an existing node (you can also create a new node as the parent and pull out the bits one at a time).
The choice to do work at parsing time was something I intentionally avoided in igk because it makes life much harder: the input format is no longer trivially isomorphic with the post-parsing AST, which increases the cognitive load on people writing extensions. This experience has 100% confirmed my belief that this was the right choice.