I haven't got any more tests working, but I've cracked 85 percent coverage. However, I've come to the conclusion that my mental model of how StoryStates work is flawed, and I should probably collapse most of the states together. I'm not exactly sure how big of a deal this will be, but hopefully it'll make things easier.
Basically, I'd been visualizing the states as cleanly switching between streams of different kinds of output (text and choices), when what actually seems to happen is that choices are generated throughout the course of streaming text output, then expected to be looked at when the text stream ends. This was not obvious to me, because it's not immediately obvious how to author content that causes the distinction to matter. The test that had me realize this accomplishes such a thing by generating the choices, then generating the content using a thread. The choices will show up in the same place as usual in the interface, but they were actually generated first.
I think all I need to do to handle this is to eliminate ChoiceState and have LineState go directly to ReadyState when it can't continue. I might change how I model this stuff, and have LineState be the only state that's permissible in most functions, and have ReadyState just wrap it.
It's possible that I'll end up dropping more distinctions by the time I'm done working with this, but I want to try having them.
I'm going to hope there are no more complications, but we'll see. For now, I really should get to bed.