mesh/merge-gate pass: builds desk-channel, messenger, telegram → novox; no bus step; every machine composes with the change as it did without (4 of 4 compo…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery-group group fix/373-one-message-per-condition ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
- A comeback before the clearing was said rings when it is urgent now, and says the reminder or escalation that was waiting when it cleared. - Comebacks never said are counted apart, so "again, Nth time" counts only what the operator was told; an urgent comeback after a said clearing rings again in place of its message. - telegram sends the new message before deleting the earlier one, so a failed send leaves the operator a message. - desk-channel keeps a machine's notification on record when its replace fails, and says a message shown nowhere as failed. - A store that cannot be read sends a new message instead of holding it. - Tests for each, and for a reminder in a burst and a clearing the channel could not take.
104 lines
7.0 KiB
Markdown
104 lines
7.0 KiB
Markdown
# telegram
|
|
|
|
A channel of the operator's conversation: kind `telegram` of the `channel` and `intake` benches the router
|
|
(`messenger`) declares (novox/hq ADR 0234, ADR 0259). It reaches the operator away from the machines, and it
|
|
proves who answered: Telegram authenticates the sender, and the router compares it with the account linked
|
|
as the operator.
|
|
|
|
- **Shows what the router sends** (its kind's worker on the `channel` queue): a message, a question with
|
|
buttons — each button carries only the router's one-time ticket — or an edit of a message shown before.
|
|
It sends to the account the router names as linked, or, before one is, to the chat a `/start` came from.
|
|
A message sent under a handle already shown (a reminder, an escalation) **replaces** it (issue 373): the
|
|
new message is sent, ringing as its kind rings (an edit here notifies nobody), and then the earlier one is
|
|
deleted; one the service will not delete loses its buttons and says a newer message follows. A send that
|
|
fails leaves the earlier message.
|
|
- **Says what the operator chose** on `intake` under its own kind: a tapped button (`choice`), with the
|
|
sender as Telegram authenticated it; `/start` (`link`); a message it could not deliver (`failed`); and
|
|
whether it can send (`standing`). Only a private chat with the account itself counts.
|
|
- **A tap is acknowledged on the phone with the router's word on it** (issue 372): the router answers a
|
|
choice with a message in reply to it — "You chose Approve: recorded, and claude-code was told.", or why it
|
|
was not taken — and this channel shows that as the tap's own acknowledgement, the short line Telegram
|
|
shows over the chat. A word with more to it (a refusal's reason, Details) is also said in the chat, where it
|
|
stays. Nothing is acknowledged before the router's word, so the phone never says "recorded" for what was
|
|
not; without a word in 13 seconds the tap is acknowledged with words that claim nothing, and the word when it
|
|
comes is said in the chat. A secret is never an acknowledgement.
|
|
- **A code** (six digits, the one shown on the desk when linking) is asked of the router as a proof, by
|
|
request and reply: never in an event, never kept, and deleted from the chat at once.
|
|
- **Judges nothing.** Whether the sender is the operator, and what an answer may do, is the router's.
|
|
|
|
## The defects of the client it replaces (novox/hq to-be 46 §12)
|
|
|
|
| | fixed here |
|
|
|---|---|
|
|
| D1 | up to 4096 characters arrive whole; longer is cut and the cut said |
|
|
| D4 | a warning or a clearing arrives without sound; an urgent message or a question rings |
|
|
| D5 | a rate limit is waited out as told |
|
|
| D6 | a refusal is a permanent failure, said to the router and not retried; an edit to the same text is a success |
|
|
| D7 | the deprecated preview flag is gone |
|
|
| D8 | a request that cannot be written is said |
|
|
| D10 | `standing` checks the token with Telegram (`getMe`), not only that a value is present |
|
|
|
|
D2 and D3 (a reopening said by an edit; a clearing edits the first message) are the router's, and D9 the
|
|
watcher's.
|
|
|
|
## How it keeps the token from the agents (novox/hq ADR 0259 §8, as revised)
|
|
|
|
- **It runs as the account `telegram`, in a runtime of its own, on a bus account of its own** (`runs-as`). The
|
|
machine's runtime runs as the operator's account — which every agent runs as — and never carries it; the
|
|
controller refuses to compose it there.
|
|
- **Its state directory, its bot token and its bus credential belong to `telegram`**, 0700 and 0600
|
|
(`secrets-owner`). The operator's account reads none of them, and cannot attach to its process.
|
|
- **Only this kind's holder says this kind's choices, links and codes**: the bus grants those subjects to its
|
|
own account alone.
|
|
- **The router believes it proves its sender only so placed**, and only while the controller's self-check
|
|
finds no agent able to become root without a person on its machine or the router's (`agent-root`).
|
|
- **If an agent holds root on the machine, none of this holds**: root reads the token and every credential.
|
|
- **A tap counts only on a message showing the words it put there.** It keeps a digest of what each message
|
|
shows; a tap on one whose words differ — changed by another holder of the token — or on one it never showed
|
|
is refused on the phone and never said to the router.
|
|
|
|
## Where an approval from Telegram means something (a known gap, accepted by the operator on 2026-10-09)
|
|
|
|
The router does not measure or enforce what follows, and does not hold approvals back for it: the operator
|
|
accepted the gap for now, and novox/hq issue 344 records it with what closes it.
|
|
|
|
An approval from Telegram proves only that the linked account tapped. It is meaningful where nothing working
|
|
for the operator can tap in their name, which on a machine where agents run needs all three of:
|
|
|
|
1. **The agents run under an account of their own, without sudo** (novox/hq ADR 0266), so they cannot become
|
|
root or the operator.
|
|
2. **That account has no access to the operator's X display** — no Xauthority cookie for it. X11 has no
|
|
isolation between the clients of one display: a program on it reads every key typed and can click any
|
|
window, the Telegram client's buttons among them.
|
|
3. **The operator's Telegram Desktop data is readable by the operator alone** (`~/.local/share/TelegramDesktop/tdata`,
|
|
0700). Found 0755 with its files 0644: any account on the machine can copy the session and be the operator
|
|
on Telegram from elsewhere.
|
|
|
|
Until agents have their own account on a machine, the operator's Telegram client on that machine is not
|
|
counted as safe: **approve from the phone.** No module of the catalogue installs Telegram Desktop today, so
|
|
nothing of the mesh keeps `tdata` 0700 yet; the operator sets it by hand (`chmod -R go-rwx` on it) until one
|
|
does.
|
|
|
|
## Where it runs
|
|
|
|
Held once for the mesh: assign it to the control node, the stably reachable one. Long polling is outbound
|
|
only, so no route into the mesh is needed, and a stolen token can read updates (a conflict says so) but
|
|
never inject one.
|
|
|
|
## What the operator gives
|
|
|
|
1. **A bot**: in Telegram, talk to @BotFather, `/newbot`, a name and a username. BotFather answers with the
|
|
bot's token. Keep it on the phone; never paste it into a chat with an agent.
|
|
2. **The token, to the vault**, as this module's own secret `telegram-token`: the vault's verb for a secret
|
|
given at the desk, or `secret accept <control node> telegram telegram-token` at a terminal on the control
|
|
node, which reads it without echoing it. Then push the control node.
|
|
3. **The link**: send the bot `/start`. A six-digit code appears on the desk; send it to the bot within ten
|
|
minutes. The account answers acknowledgements at once and approves an hour later; every channel says so.
|
|
`messenger_identities` shows it. `messenger_unlink` asks the linked account itself whether to unlink it.
|
|
|
|
## Tools
|
|
|
|
| tool | does |
|
|
|---|---|
|
|
| `telegram_status` | whether it can send and why not (never the token), the bot's name, when updates last arrived, the last delivery and error, counts since start, and its rules |
|