Implement the R-1 adapter (FT-WP-0001 T05/T09); mark workplans blocked

Builds internal/adapter and cmd/adapter: the three contracts/r1.openapi.yaml
operations, idempotency on post_id, the reviewed_by/consent-basis refusals,
per-form (R-2/R-3) length limits, and Markdown-to-Telegram rendering, all
against a Sender interface so it's testable without a live bot token.

Every other open task in FT-WP-0001 and FT-WP-0002 needs something this repo
can't supply on its own: the human session bootstrap in FT-WP-0002 T01, the
fluid CLI from fluid-core, or a person's judgment (consent basis, editorial
review, publishing pace). Set both workplans to status: blocked and flagged
FT-WP-0002-T01 needs_human on the hub, since it's the single blocker gating
everything else.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 278411@bnt-lap001
Assistant-Session: 19568045-15bc-4b88-ba3d-8e95b4f9c6f1
This commit is contained in:
tegwick 2026-09-27 23:15:29 +02:00
parent f7f5302903
commit bfebca3aee
10 changed files with 1052 additions and 6 deletions

View file

@ -4,12 +4,12 @@ type: workplan
title: "Establish HelixForge's Telegram identity and publish the Hall of Helix"
domain: infotech
repo: fluid-telegram
status: active
status: blocked
flavor: implementation
owner: worsch
topic_slug: fluid-telegram
created: "2026-09-04"
updated: "2026-09-14"
updated: "2026-09-27"
planning_priority: high
planning_order: 1
depends_on:
@ -47,6 +47,13 @@ first experiment. See `docs/` and the handover package at
What remains needs either a person with a Telegram account or a running
adapter.
**Blocked (2026-09-27).** T05 and T09 are implemented and merged. Everything
else still open needs one of: the human session bootstrap in `FT-WP-0002` T01
(which the live provisioning apply for T01–T03 waits on), the `fluid` CLI from
`fluid-core` (T04), or a person's judgment call (T07's consent basis, T08's
editorial review, T10's publishing pace). None of that can be resolved from
this repo alone; re-open by working `FT-WP-0002` T01 first.
**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
@ -145,7 +152,7 @@ only, and a revision signed with one stops verifying after a restart.
```task
id: FT-WP-0001-T05
status: todo
status: done
priority: high
state_hub_task_id: "c89782da-9896-5957-b729-7c35165a0067"
```
@ -159,6 +166,17 @@ 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.
**Done.** Go, not TypeScript — the wire contract makes the language irrelevant,
and Go keeps one toolchain for the whole repo. `internal/adapter` (`adapter.go`,
`render.go`, `store.go`, `telegram.go`, `telemetry.go`) plus `cmd/adapter`. All
three operations are implemented against `Sender`, an interface the real Bot
API client (`BotAPISender`) and the tests both satisfy — the same pattern
`internal/apply.Surface` uses for MTProto. Idempotency, the `reviewed_by` and
consent-basis refusals, the per-form length limit, and the Markdown-to-Telegram
rendering rules are covered by `internal/adapter/*_test.go`. What is not yet
exercised is a real Telegram channel: that needs a live bot token, which waits
on `FT-WP-0002` T01.
## T06 — Establish the composition step
```task
@ -234,7 +252,7 @@ automated; whether a condensation is fair to the person it describes cannot.
```task
id: FT-WP-0001-T09
status: todo
status: done
priority: medium
state_hub_task_id: "649e7df6-6c07-5cc8-a022-d1eadcdb7236"
```
@ -248,6 +266,15 @@ 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.
**Implemented as part of T05, not as a separate build.** `adapter.Config.
AttachVisual` selects the arm: false is R-3 (`SendMessage`, 4096-char limit),
true is R-2 (`SendPhoto` with the composed text as caption, 1024-char limit).
One adapter instance still serves one channel, per the adapter contract; which
revision it speaks is a deployment-time config choice
(`ATTACH_VISUAL`), not a code fork. Both arms are covered in
`internal/adapter/adapter_test.go`. Verifying against the private channel with
real Telegram traffic is unchanged and still waits on `FT-WP-0002` T01.
## T10 — Open the public channel and start publishing
```task

View file

@ -4,12 +4,12 @@ type: workplan
title: "Provision the Telegram presence from a declared specification"
domain: infotech
repo: fluid-telegram
status: active
status: blocked
flavor: implementation
owner: worsch
topic_slug: fluid-telegram
created: "2026-09-04"
updated: "2026-09-14"
updated: "2026-09-27"
planning_priority: high
planning_order: 2
depends_on:
@ -33,6 +33,13 @@ 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.
**Blocked (2026-09-27).** T02–T08 are done. T01 is the only remaining task and
it is irreducibly manual — a dedicated phone number, the `api_id`/`api_hash`
web form, and the interactive login code are things only an operator with a
Telegram account can supply; see `docs/requests/ops-warden-telegram-operator-lane.md`
for the credential-lane request. Nothing else in this workplan can proceed
until that bootstrap runs.
## T01 — Write the seeding runbook and bootstrap the session
```task