docs(core,chain): tighten the `ChainTask` driver contract
Two gaps in the protocol between a task and its driver, one on each side.
Task side: `resolve_query(height, None)` means "the chain source has no
block at this height", and it is terminal — the height leaves the pending
set and is never requested again. A driver that passed `None` on an I/O
error would permanently record a real block as absent, turning a confirmed
transaction into an unconfirmed one with no error surfaced anywhere, i.e.
a silently wrong balance. The recovery path already exists: leave the
height unresolved and retry it, which is what `unresolved_queries` is for.
Driver side: `LocalChain::run_task` rejected `TaskProgress::Blocked` with
`unreachable!()`. That was right about the outcome — this driver resolves
every height a task announces via `Query` before polling again, so a task
that announces what it needs never has anything outstanding — but it gave
the reason as a property of the driver rather than of the task, and the
panic was undocumented. Reaching that arm means the task is waiting on
heights it never announced. Such a task would also hang a streaming
driver, which starts fetches only for announced heights, so serving it by
draining `unresolved_queries()` would hide the bug behind the one driver
everyone tests against. Panic with a message that names the violation,
document it under `# Panics`, and cover it with a test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NND8BhEmYTYdLRv4dbUUro