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.