Make the plan honest and the runbook's paths real

Two things that would have gone wrong on the first live run.

The plan promised "create bot.avatar" and apply had no avatar code at all:
/setuserpic needs a photo upload that is not implemented. A plan that
promises an action apply silently skips is worse than one that admits the
gap, because it makes every other line less trustworthy. The avatar is now
deferred, with instructions for setting it by hand.

The runbook wrote secrets to "<interface-path>/telegram/...", which is not
what the code computes. An operator following it would have put api_id and
api_hash somewhere the tool never looks, and found out at the first
connection attempt. Both documents now carry the real paths --
<mount>/fluid-telegram/<campaign>/telegram/<key> -- with a copy-pasteable
bao kv put for the one secret written by hand, and a verify step before
the session is minted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172sgCZEEDJcnQmr4SGDvKa

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1361245@bnt-lap001
Assistant-Session: b3b428ef-f3e6-4688-b091-01f71461d66a
This commit is contained in:
tegwick 2026-09-04 22:02:56 +02:00
parent 5ddfee8250
commit 014ee5c746
4 changed files with 90 additions and 18 deletions

View file

@ -118,12 +118,15 @@ Reconciliation is **converging, never destructive**:
Nothing sensitive enters the spec or the resolved state. Both are committed.
| Secret | Path | Rule |
Paths are computed as `<mount>/fluid-telegram/<campaign>/telegram/<key>`, so two
campaigns on one interface cannot read each other's credentials.
| Secret | Key | Rule |
|---|---|---|
| MTProto session string | `bao:.../telegram/operator-session` | Provisioning only. Never given to the adapter. |
| `api_id` / `api_hash` | `bao:.../telegram/operator-app` | Provisioning only. |
| Bot token | `bao:.../telegram/bot-token` | Written by `apply` the moment BotFather issues it, read by the adapter at start. Never logged, never echoed, not even in error text. |
| Redaction salt | `bao:.../telegram/redaction-salt` | **Create-if-absent, never overwrite.** |
| `api_id` / `api_hash` | `operator-app` | The only one written by hand. Provisioning only. |
| MTProto session string | `operator-session` | Written by `session bootstrap`. A full-account credential: provisioning only, never given to the adapter, never on disk. |
| Bot token | `bot-token` | Written by `apply` the moment BotFather issues it, read by the adapter at start. Never logged, never echoed, not even in error text. |
| Redaction salt | `redaction-salt` | **Create-if-absent, never overwrite.** |
The salt rule is a hard one. `docs/observation.md` explains why: rotating it
silently invalidates every longitudinal comparison the interface has ever made,