Implement the MTProto client, session bootstrap and apply

Completes the provisioner's write path. internal/tg drives BotFather as a
conversation rather than pretending it is an endpoint, creates channels,
claims usernames with fallbacks, and grants post_messages. internal/apply
sequences it: bot before administrator, test channel before public, and
state saved after every step that changed the world -- a channel that
exists but is unrecorded is worse than one that does not exist, because
the next run creates a second.

The operator session lives in OpenBao, not on disk. gotd's FileStorage
would leave a full-account credential in the working directory, where it
outlives the run and can be committed by accident.

The bot token goes straight from BotFather's reply to OpenBao and is
cleared from memory; if that write fails the error says how to recover by
hand and warns against re-running, since a retry creates a second bot.

Closes T05: the redaction salt is create-if-absent with no overwrite path,
and the test asserts it, because rotating it invalidates every longitudinal
comparison with no visible failure.

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 21:39:30 +02:00
parent 10018a99b6
commit 5ddfee8250
14 changed files with 1544 additions and 57 deletions

View file

@ -36,7 +36,7 @@ one bounded bootstrap, after which the surface is declared and converges.
```task
id: FT-WP-0002-T01
status: todo
status: progress
priority: high
state_hub_task_id: "039e5358-07c1-5b01-a186-5ece9aab75e4"
```
@ -128,7 +128,7 @@ kinds: a deferral holds one action, a block stops the run.
```task
id: FT-WP-0002-T04
status: todo
status: progress
priority: high
state_hub_task_id: "5659b72a-8309-58b6-96e9-79137ce41ed4"
```
@ -157,12 +157,13 @@ test channel has recorded a successful publication.
```task
id: FT-WP-0002-T05
status: todo
status: done
priority: high
state_hub_task_id: "d5fd905a-6abd-5ae1-9105-abc4c2a7127e"
```
Generate 32 bytes if and only if the OpenBao path is empty, and never overwrite.
**Implemented.** `secrets.CreateIfAbsent` generates 32 bytes if and only if the
OpenBao path is empty, and the package has no counterpart that overwrites.
Supersedes `FT-WP-0001` T03.
The create-if-absent rule is not defensiveness. `docs/observation.md` explains
@ -190,7 +191,7 @@ is the point of running two planes rather than one tool with a flag.
```task
id: FT-WP-0002-T07
status: todo
status: progress
priority: low
state_hub_task_id: "f3f36415-ed55-5717-b752-706b04ba5458"
```