The plugin talks to the hosted book, not a directory on the laptop

The plugin opened a directory on the customer's own machine and edited it, so a customer got back a commit hash and a plausible net worth from a ledger we do not host, do not back up and do not serve.

The failure mode here is not that hosted mode was missing. The plugin succeeded. server.py opened ~/.countbean/main and wrote to it, there was no HTTP call anywhere in the package, and nothing errored — so nothing prompted anyone to look.

The client half now goes over the wire using the auth path that was already built: the per-book API key mints a short-lived, book-scoped token, and that token goes to the runtime. It uses stdlib urllib and adds no dependency, because this package installs into a venv on a customer’s laptop on first run and a new dep there is a new way for that to fail.

Two refusals are deliberate. A half-configured hosted setup raises instead of falling back to the local directory, because falling back recreates this bug just as silently. And health reports the book id, so a mismatch refuses before any write — books share one Fly app, so an address really can answer for somebody else’s book.