Skip to content

feat: Phase 4 — Telegram interactive approval bot#9

Open
constgemm wants to merge 2 commits into
mainfrom
feature/telegram-approve
Open

feat: Phase 4 — Telegram interactive approval bot#9
constgemm wants to merge 2 commits into
mainfrom
feature/telegram-approve

Conversation

@constgemm

Copy link
Copy Markdown
Owner

The propose-then-approve gate, moved from the terminal (--commit) to your phone.

Flow

For each new candidate not contradicted by Dawarich, telegram.py:

  1. sends a card showing every field — missing ones flagged ⚠ missing — with an inline ✅ Approve / ⏭ Skip keyboard;
  2. waits for your tap (long-poll getUpdates, so the container needs no inbound port);
  3. on Approve, writes the flight to AirTrail and replies "✅ Wrote LX1246 LSZH->ESSA … AirTrail now has N flights.";
  4. on Skip or timeout, writes nothing.

Robustness

  • callback_data is namespaced (lay:ok:<idx>) so taps from other bots in the chat are ignored; decisions are buffered by index so out-of-order/duplicate taps aren't lost.
  • Priming drains stale updates so an old tap can't leak into a fresh run.
  • A write failure is reported in-chat, never raised.
  • All Telegram HTTP and AirTrail post/fetch are injectable → fully tested offline.

Changes

  • telegram.py — config, Bot API transport, card rendering, approval session, run_approvals.
  • populate.py — opt-in step (TELEGRAM_APPROVE=1 or --telegram-approve).
  • Dockerfile, .env.example, README.
  • tests/test_telegram.py — 10 tests. Suite on this branch: 39 green.

Touches the same populate.py import block + main() as PRs #7/#8 — trivial conflict resolve on whichever merges later.

Needs from you: a bot token from @Botfather + your chat id (→ .env / infra-secrets, never committed). The token is a secret — keep it out of the vault.

🤖 Generated with Claude Code

constgemm and others added 2 commits July 7, 2026 23:42
Moves the propose-then-approve gate from the terminal (--commit) to the phone.
For each NEW candidate not contradicted by Dawarich, telegram.py sends a card
showing every field (missing ones flagged) with an Approve/Skip inline button;
on Approve it writes the flight to AirTrail and replies with the new total
("AirTrail now has N flights"). Skip or timeout writes nothing.

Uses long-poll getUpdates, so the container needs no inbound port. callback_data
is namespaced (lay:ok:<idx>) and decisions are buffered by index, so stray or
out-of-order taps are handled. All HTTP + AirTrail post/fetch are injectable.

- populate.py: opt-in approval step (env TELEGRAM_APPROVE or --telegram-approve).
- Dockerfile copies telegram.py; .env.example + README document it (token is a
  SECRET — .env only).
- 10 tests: card rendering, eligibility filter, approve/skip/timeout/failure
  paths, enable gating. Full suite: 39 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	.env.example
#	Dockerfile
#	populate.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant