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

@ -4,7 +4,8 @@
# This file is the contract it is validated against, and lives here because the
# provisioner is here. See docs/provisioning.md.
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "fluid-telegram/presence/telegram.schema.yaml"
# No $id: this schema is identified by its path in the repo. A relative $id is
# not a resolvable URI and breaks "$ref" resolution in ordinary validators.
title: "Telegram declared presence"
type: object
required: [presence]
@ -89,6 +90,21 @@ $defs:
type: object
required: [title, visibility]
additionalProperties: false
# A private channel has no username to claim. Declaring one is a mistake
# about what is being created, so it fails here rather than being ignored
# by apply -- a silently dropped field is how a spec stops describing
# what actually exists.
allOf:
- if:
properties: { visibility: { const: private } }
required: [visibility]
then:
not: { required: [username_preference] }
- if:
properties: { visibility: { const: public } }
required: [visibility]
then:
required: [username_preference]
properties:
title:
type: string