Add the operator seeding runbook and enforce the presence schema

Loosen the all-or-nothing stance on provisioning: where a platform has no
API to seed access, a guided runbook is the right answer. docs/seeding-runbook.md
covers the three Telegram steps that cannot be automated, and each carries a
"why not automated" line so the judgement can be revisited rather than
inherited. Telegram's steps resist automation incidentally -- nobody built
the endpoints -- unlike a control such as KYC, which resists by design and
where a weak component would be a defect rather than an opening.

Fix the schema's $id, which was a relative path and broke $ref resolution in
ordinary validators, and add the visibility/username constraint the field
descriptions already claimed. Both specs now validate, and the rejections are
tested.

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 19:30:54 +02:00
parent d26c4619b8
commit f06be1f949
4 changed files with 211 additions and 17 deletions

View file

@ -32,7 +32,7 @@ designated operator, and three things stay human — a phone number, the
`api_id`/`api_hash` web form, and the login code that mints the session. That is
one bounded bootstrap, after which the surface is declared and converges.
## T01 — Bootstrap the operator account and session
## T01 — Write the seeding runbook and bootstrap the session
```task
id: FT-WP-0002-T01
@ -41,36 +41,53 @@ priority: high
state_hub_task_id: "039e5358-07c1-5b01-a186-5ece9aab75e4"
```
**The irreducible human step.** Register a dedicated Telegram account for the
operator — never a person's own, so that a rate limit costs nothing personal.
Obtain `api_id` / `api_hash` from my.telegram.org.
**The seeding steps, done by a guided runbook.** `docs/seeding-runbook.md` is
the deliverable: register a dedicated operator account (never a person's own, so
a rate limit costs nothing personal), obtain `api_id` / `api_hash`, and run
`provision session bootstrap` to mint the MTProto session into OpenBao.
Then `provision session bootstrap` runs the interactive login once and writes the
session string to OpenBao. The command is the only interactive one in the tool,
and it exists so that the interactive part is bounded and named rather than
spread through the process.
Manual is acceptable here because it is guided, repeatable and bounded — an
operator who has never done it follows it once and gets the same result as
anyone else. What makes it acceptable is the structure, not the shortness.
Nothing else in this workplan is interactive.
Each step in the runbook carries a **Why not automated** line, and that is the
part with a future. Telegram's three steps resist automation only incidentally —
nobody built the endpoints — as opposed to a control like KYC, which resists
automation by design and where a component weak enough to allow it would be a
defect rather than an opening. So these lines are re-read when the platform
changes, and steps are deleted when a reason expires.
`provision session bootstrap` is the only interactive command in the tool. Nothing
else in this workplan is interactive.
## T02 — Publish the presence schema and the campaign's spec
```task
id: FT-WP-0002-T02
status: todo
status: progress
priority: high
state_hub_task_id: "01684264-37a5-5fe8-a491-37686e094428"
```
The schema is in `presence/telegram.schema.yaml` with a worked example beside it.
What remains is the real instance at `pr-hall-of-helix/presence/telegram.yaml`,
plus the avatar asset.
**Largely done.** The schema is in `presence/telegram.schema.yaml` with a worked
example beside it, and the real instance is at
`pr-hall-of-helix/presence/telegram.yaml`. Both validate.
The spec is editorial — a bot's name, its description, the channel titles a
stranger reads — so it belongs to the campaign. The provisioner takes a spec path
as input, which is what keeps this interface reusable by campaigns other than the
Hall of Helix.
Blocked on `pr-hall-of-helix` existing.
The schema enforces rather than describes: an `admin_rights` entry other than
`post_messages` is rejected, a private channel may not declare a username, a
public one must, and unknown fields fail instead of being ignored. A silently
dropped field is how a spec stops describing what actually exists.
**Remaining:** the avatar asset. `presence/assets/helixforge-avatar.png` is
referenced but absent, and `apply` will fail on `/setuserpic` until it exists.
It is left for a person on purpose — it is the first thing a stranger sees of
HelixForge on Telegram, and a generated placeholder would quietly become
permanent.
## T03 — Implement `provision plan`