Align AGENTS.md with the FT-WP- prefix the hub already registered, and rewrite INTENT.md and SCOPE.md, which were still the generated stubs and carried none of the composed-post framing the interface is built around. Fix two artifact inconsistencies: R-1's retry comment still described POST /v1/hall-entries idempotent on entry_id, from before the reframe to composed posts; and the seed pressure record listed only one of the two hypotheses that cite it. Rename it to match its id. Replace the manual T01-T03 route with FT-WP-0002. The Bot API cannot create a bot or a channel, so provisioning is an MTProto client acting as a designated operator account (Canon INT-03), driven from a declared presence spec owned by the campaign. One bounded human bootstrap remains and docs/provisioning.md says why it cannot be removed. 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
335 lines
12 KiB
Markdown
335 lines
12 KiB
Markdown
---
|
||
id: FT-WP-0001
|
||
type: workplan
|
||
title: "Establish HelixForge's Telegram identity and publish the Hall of Helix"
|
||
domain: infotech
|
||
repo: fluid-telegram
|
||
status: active
|
||
owner: worsch
|
||
topic_slug: fluid-telegram
|
||
created: "2026-09-04"
|
||
updated: "2026-09-04"
|
||
planning_priority: high
|
||
planning_order: 1
|
||
depends_on:
|
||
- FLUID-WP-0008
|
||
related_repos:
|
||
- fluid-core
|
||
- helix-forge
|
||
- hall-of-helix
|
||
state_hub_workstream_id: "a660ed65-700e-5b54-8d91-a556b73518f0"
|
||
---
|
||
|
||
# FT-WP-0001 — Telegram identity and the Hall of Helix channel
|
||
|
||
Establish a Telegram identity for HelixForge and a channel publishing composed
|
||
posts about hall-of-helix work, as the first real FLUID interface.
|
||
|
||
**The channel does not republish entries.** A hall entry is a considered
|
||
first-person account written for a colleague reading a repository. A channel
|
||
post is short, personal, entertaining and written to travel. The post is
|
||
composed *from* the entry and is a different piece of writing; the entry is the
|
||
source and the check, never the payload.
|
||
|
||
Composition happens before this interface is called. That boundary is
|
||
architectural: composing is a probabilistic editorial task, and
|
||
`ArchitectureBlueprint.md` §48.1 forbids an LLM in the mandatory request path.
|
||
It is also editorial: a post speaks about a named person's work in HelixForge's
|
||
voice, and that deserves a human read before it goes out.
|
||
|
||
Everything that could be prepared without credentials has been: the governing
|
||
intent, the R-1 contract, the adapter's connector contract, the observation
|
||
configuration, the seed pressure record, and two competing hypotheses for the
|
||
first experiment. See `docs/` and the handover package at
|
||
`fluid-core/docs/handover/fluid-telegram.md`.
|
||
|
||
What remains needs either a person with a Telegram account or a running
|
||
adapter.
|
||
|
||
**T01–T03 have moved.** They were written as manual steps; they are now
|
||
provisioned from a declared specification by `FT-WP-0002`, and the three tasks
|
||
below are kept as the record of what must be true rather than as instructions to
|
||
follow. The Bot API cannot create a bot or a channel, so provisioning is an
|
||
MTProto client acting as a designated operator account (Canon INT-03); one
|
||
bounded human bootstrap remains, and `docs/provisioning.md` says exactly what it
|
||
is and why it cannot be removed.
|
||
|
||
## T01 — Register the bot
|
||
|
||
```task
|
||
id: FT-WP-0001-T01
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "a5449e86-3181-54b6-a0fe-e5c761b3e4ba"
|
||
```
|
||
|
||
**Superseded by `FT-WP-0002` T04.** The bot is registered by the provisioner
|
||
from the declared presence spec, not by hand: BotFather `/newbot` driven over
|
||
MTProto, name, about text, description and avatar set from the spec, and the
|
||
token written straight to OpenBao without passing through a terminal. Consistent
|
||
with `HF-WP-0002` (bao.coulomb.social).
|
||
|
||
What survives from the original step is the requirement, not the method: a
|
||
reader encountering the bot cold should recognise it as HelixForge. That is now
|
||
`bot.name` / `bot.about` / `bot.description` in the spec, where it is reviewable
|
||
before it is applied.
|
||
|
||
Close this task when `FT-WP-0002` T04 has run. See `docs/provisioning.md`.
|
||
|
||
## T02 — Create the channels
|
||
|
||
```task
|
||
id: FT-WP-0001-T02
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "597ab1b7-5903-5a5d-a510-0a6946325404"
|
||
```
|
||
|
||
**Superseded by `FT-WP-0002` T04.** Both channels are created by the
|
||
provisioner via `channels.createChannel`, private test channel first (Canon
|
||
PUB-01), with the bot added as administrator through `channels.editAdmin`.
|
||
|
||
The ordering and the rights are no longer conventions a person is trusted to
|
||
follow. `apply` will not touch the public channel until the test channel has
|
||
recorded a successful publication, and it grants **Post Messages** and refuses
|
||
anything wider *even if the spec asks for it* — the intent forbids the system
|
||
from holding a right it may not exercise, so the grant is the right place to
|
||
enforce that.
|
||
|
||
Every verification below still runs against the private channel, and nothing
|
||
reaches the public channel until a person has looked at a rendering.
|
||
|
||
Close this task when `FT-WP-0002` T04 has run.
|
||
|
||
## T03 — Generate and store the redaction salt
|
||
|
||
```task
|
||
id: FT-WP-0001-T03
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "bbe5da73-e604-5dfe-b25f-fba802f67618"
|
||
```
|
||
|
||
**Superseded by `FT-WP-0002` T05.** The provisioner generates 32 bytes if and
|
||
only if the OpenBao path is empty, and has no path that overwrites one. Injected
|
||
as `FLUID_REDACTION_SALT`.
|
||
|
||
It must never change: see `docs/observation.md` for why rotating it silently
|
||
invalidates every longitudinal comparison. Making that a property of the tool
|
||
rather than a note in a workplan is the whole reason the step moved.
|
||
|
||
Close this task when `FT-WP-0002` T05 has run.
|
||
|
||
## T04 — Record the intent and publish R-1
|
||
|
||
```task
|
||
id: FT-WP-0001-T04
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "13a92a96-2f87-5de2-a69c-7edc21f3a0c7"
|
||
```
|
||
|
||
```bash
|
||
export FLUID_INTERFACE=helix-forge-telegram-publishing
|
||
fluid intent put --version IEI-1 --file InterfaceEvolutionIntent.md --activate
|
||
# fill the digest in revisions/R-1.yaml, then
|
||
fluid revision publish --file revisions/R-1.yaml --key-file "$FLUID_SIGNING_KEY" \
|
||
--adaptation-classes presentation --approved-by "$USER" --traffic-share 1.0
|
||
```
|
||
|
||
Generate a real signing key pair for this; `--ephemeral-key` is development
|
||
only, and a revision signed with one stops verifying after a restart.
|
||
|
||
## T05 — Build the adapter
|
||
|
||
```task
|
||
id: FT-WP-0001-T05
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "c89782da-9896-5957-b729-7c35165a0067"
|
||
```
|
||
|
||
Implement the three operations in `contracts/r1.openapi.yaml` against the
|
||
connector contract in `docs/adapter-contract.md`. TypeScript with grammY is the
|
||
natural choice; the wire contract makes the language irrelevant to fluid-core.
|
||
|
||
Three requirements carry the weight: publication is idempotent on `post_id`; a
|
||
post arriving without `reviewed_by` or a consent basis is refused with 403; and
|
||
a post that exceeds the limit for the form being published is refused rather
|
||
than truncated. The adapter renders and delivers. It never writes.
|
||
|
||
## T06 — Establish the composition step
|
||
|
||
```task
|
||
id: FT-WP-0001-T06
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "317bef32-e82e-586a-8947-8cbb330f6c98"
|
||
```
|
||
|
||
Build the step that turns a hall entry into a post: condensed, personal,
|
||
entertaining, reach-optimized, carrying a link back to the source entry.
|
||
|
||
For now this lives here, as a script plus a review queue. It is temporary by
|
||
design — T13 extracts it into `pr-hall-of-helix` — so keep the seam clean. The
|
||
composition step's only interface to publishing is `POST /v1/channel-posts`,
|
||
and it must not reach into the adapter or the evidence store.
|
||
|
||
Each composition records the `variant` label of the strategy that produced it.
|
||
Without that label the campaign cannot later compare strategies, and inferring
|
||
it from timestamps is the kind of reconstruction that quietly stops being
|
||
accurate.
|
||
|
||
Human review is not a nicety here. A generated condensation can put a claim in
|
||
someone's mouth that their own entry never made, and in the audit trail an
|
||
unfaithful post looks exactly like a faithful one. The reviewer reads the post
|
||
against the entry, and their name goes in `reviewed_by`.
|
||
|
||
## T07 — Record the consent basis for hall participants
|
||
|
||
```task
|
||
id: FT-WP-0001-T07
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "6a91ea08-8814-58f3-8297-a7ca63405294"
|
||
```
|
||
|
||
Ninety-four entries already exist, written by people and agent sessions who
|
||
took a seat in the hall without anyone mentioning a Telegram channel.
|
||
|
||
Decide and record the basis on which HelixForge may write publicly about that
|
||
work. If `hall-of-helix/ENTRY.md` is to carry a standing agreement, add it and
|
||
say plainly that it is revocable. Contributors who predate it should be asked
|
||
rather than assumed into it.
|
||
|
||
Absence of objection is not consent, and the interface refuses a post carrying
|
||
no basis, so this blocks T10.
|
||
|
||
## T08 — Publish one post to the private channel
|
||
|
||
```task
|
||
id: FT-WP-0001-T08
|
||
status: todo
|
||
priority: high
|
||
state_hub_task_id: "5e5cd89a-e7b1-5aaf-9331-ece424afe5e3"
|
||
```
|
||
|
||
The first real test. Compose one post from one entry, have it reviewed, publish
|
||
it to the private channel, and confirm by looking at it:
|
||
|
||
- the post reads well and is worth a stranger's attention;
|
||
- it does not claim anything the source entry does not support;
|
||
- the source link works and the attribution is right;
|
||
- re-publishing the same `post_id` edits rather than duplicates;
|
||
- the evidence store holds the post text but no Telegram user identity and no
|
||
bot token;
|
||
- `fluid audit trace R-1` reconstructs the publication, naming the reviewer and
|
||
the source entry.
|
||
|
||
The second bullet is the one that needs a person. Everything else can be
|
||
automated; whether a condensation is fair to the person it describes cannot.
|
||
|
||
## T09 — Implement both delivery forms as R-2 and R-3
|
||
|
||
```task
|
||
id: FT-WP-0001-T09
|
||
status: todo
|
||
priority: medium
|
||
state_hub_task_id: "649e7df6-6c07-5cc8-a022-d1eadcdb7236"
|
||
```
|
||
|
||
R-2 implements `H-tg-visual` — portrait attached, and Telegram's 1024-character
|
||
caption limit with it. R-3 implements `H-tg-textonly` — a text message with the
|
||
full 4096 available. Both are presentation adaptations over the same contract,
|
||
so neither needs a contract change. Verify both against the private channel
|
||
before either sees a subscriber.
|
||
|
||
The two arms impose different length limits on the composer, which is the one
|
||
place delivery and composition genuinely couple.
|
||
|
||
## T10 — Open the public channel and start publishing
|
||
|
||
```task
|
||
id: FT-WP-0001-T10
|
||
status: todo
|
||
priority: medium
|
||
state_hub_task_id: "b469b9b8-a1a8-5f76-a1bb-dd51dd4d2ce5"
|
||
```
|
||
|
||
Point the production adapter at the public channel. Blocked on T07: no post
|
||
goes out about anyone's work without a recorded consent basis.
|
||
|
||
Do not batch-publish the backlog. Ninety-four posts in a burst is a rate-limit
|
||
problem, an unkind introduction for a new subscriber, and — more to the point —
|
||
ninety-four compositions nobody has had time to read properly. Publish
|
||
selectively and at a human pace, and let the backlog be a source to draw on
|
||
rather than a queue to drain.
|
||
|
||
## T11 — Run the first delivery experiment
|
||
|
||
```task
|
||
id: FT-WP-0001-T11
|
||
status: todo
|
||
priority: low
|
||
state_hub_task_id: "eb09fcaf-f1bc-5e38-918e-c66f638d356f"
|
||
```
|
||
|
||
Start `E-tg-delivery` once the channel has roughly 100 subscribers. Before then
|
||
the evaluator will report INCONCLUSIVE, and that is the correct answer rather
|
||
than a reason to shorten the window.
|
||
|
||
At one post per week, a 90-day experiment yields about twelve posts. That is
|
||
thin, and the honest expectation is that the first run is inconclusive and
|
||
informs a better-powered second one. Record that expectation in the
|
||
experiment's amendments rather than discovering it as a disappointment.
|
||
|
||
## T12 — Close the loop
|
||
|
||
```task
|
||
id: FT-WP-0001-T12
|
||
status: todo
|
||
priority: low
|
||
state_hub_task_id: "9f8a7724-3e5c-5a36-9e3e-e6837bd0ffdd"
|
||
```
|
||
|
||
Record the hypothesis outcome, resolve `CG-tg-delivery`, and promote the winner.
|
||
Then confirm `fluid audit trace` reconstructs the whole chain, from the register
|
||
mismatch through to the promoted revision.
|
||
|
||
That trace is the deliverable. It is what makes this the first FLUID interface
|
||
rather than a bot that posts to a channel.
|
||
|
||
## T13 — Extract the campaign into pr-hall-of-helix
|
||
|
||
```task
|
||
id: FT-WP-0001-T13
|
||
status: todo
|
||
priority: medium
|
||
state_hub_task_id: "d471516c-2f20-525f-8d79-7814160851fb"
|
||
```
|
||
|
||
Everything about *what to say and when* moves to a new repository,
|
||
`pr-hall-of-helix`, under the `pr-` prefix for public-relations campaigns. What
|
||
stays here is the deterministic delivery interface.
|
||
|
||
The split follows the boundary the intent already draws (§7):
|
||
|
||
| Moves to `pr-hall-of-helix` | Stays in `fluid-telegram` |
|
||
|---|---|
|
||
| Composition and the editorial voice | The R-1 contract and its revisions |
|
||
| Choosing which work is worth a post | The adapter |
|
||
| Variant strategies and their competition | Delivery experiments (`CG-tg-delivery`) |
|
||
| Consent records and the review queue | Per-variant engagement reporting |
|
||
| The publishing cadence | Bot and channel configuration |
|
||
|
||
The campaign becomes a *consumer* of this interface — cohort
|
||
`hall-publishing-jobs` — and runs its own FLUID loop over its own artifacts,
|
||
using the per-variant engagement this interface reports.
|
||
|
||
Two things this buys. `fluid-telegram` becomes reusable for any HelixForge
|
||
campaign rather than being about the Hall of Helix specifically. And the Hall of
|
||
Helix campaign becomes an ongoing offering with its own intent, budget and
|
||
cadence, rather than living inside a workplan that was supposed to finish.
|
||
|
||
Do this once the loop has closed at least once (T12). Extracting a seam before
|
||
you have used it is how you find out you cut it in the wrong place.
|