[Ops] Bot↔backend version handshake and CI contract test #93

Closed
opened 2026-07-14 19:48:03 +00:00 by claude-bot · 0 comments
Contributor

Context

The API contract between webapp/backend/app/routers/bot.py and bot/questboard_bot/api_client.py is kept in sync purely by discipline (the "same commit" rule in CLAUDE.md). Nothing at runtime or in CI verifies the pair actually match.

Current behavior

A self-hoster upgrading one image but not the other gets undefined behavior — 404s on renamed routes, silently missing fields — with no startup warning. CI never exercises the two components against each other, so a one-sided route rename merges green.

Fix / Spec

  1. Meta endpoint: add GET /api/bot/meta to webapp/backend/app/routers/bot.py returning {"app_version": "<semver>", "bot_contract_version": <int>}. The contract version is a manually bumped integer constant; document in both the root CLAUDE.md and the bot's docs that it must be bumped with any breaking change to the bot API, as part of the existing keep-in-sync rule.
  2. Bot startup handshake via api_client:
    • Contract version match → proceed, log at info.
    • App-version minor mismatch with matching contract version → prominent warning, proceed.
    • Contract version mismatch → refuse to start with a clear error naming both versions and the fix (upgrade the other component).
    • 404 from an older backend without the endpoint → warning ("backend predates version handshake"), proceed (compat).
  3. CI contract test (cheap, no running services): a pytest that
    • imports the bot's api_client and extracts every (HTTP method, path template) it calls (via inspection of its request helpers or a small registry added to the client),
    • builds the FastAPI app and asserts each extracted route exists in the route table with a compatible method.
    • Wire into the existing backend or bot CI job in .forgejo/workflows/ci.yml.

Acceptance criteria

  • Renaming a route on only one side makes the contract test fail.
  • Bot startup logs the handshake result in all four cases above (unit-testable against a mocked meta response).
  • GET /api/bot/meta requires the same X-Bot-Key auth as the rest of the bot router (or is explicitly public — decide and document).
  • CLAUDE.md documents the contract-version bump rule.

References

  • webapp/backend/app/routers/bot.py
  • bot/questboard_bot/api_client.py
  • .forgejo/workflows/ci.yml

Filed from the July 2026 full-project review.

## Context The API contract between `webapp/backend/app/routers/bot.py` and `bot/questboard_bot/api_client.py` is kept in sync purely by discipline (the "same commit" rule in CLAUDE.md). Nothing at runtime or in CI verifies the pair actually match. ## Current behavior A self-hoster upgrading one image but not the other gets undefined behavior — 404s on renamed routes, silently missing fields — with no startup warning. CI never exercises the two components against each other, so a one-sided route rename merges green. ## Fix / Spec 1. **Meta endpoint**: add `GET /api/bot/meta` to `webapp/backend/app/routers/bot.py` returning `{"app_version": "<semver>", "bot_contract_version": <int>}`. The contract version is a manually bumped integer constant; document in both the root `CLAUDE.md` and the bot's docs that it must be bumped with any breaking change to the bot API, as part of the existing keep-in-sync rule. 2. **Bot startup handshake** via `api_client`: - Contract version match → proceed, log at info. - App-version minor mismatch with matching contract version → prominent warning, proceed. - Contract version mismatch → refuse to start with a clear error naming both versions and the fix (upgrade the other component). - `404` from an older backend without the endpoint → warning ("backend predates version handshake"), proceed (compat). 3. **CI contract test** (cheap, no running services): a pytest that - imports the bot's `api_client` and extracts every `(HTTP method, path template)` it calls (via inspection of its request helpers or a small registry added to the client), - builds the FastAPI app and asserts each extracted route exists in the route table with a compatible method. - Wire into the existing backend or bot CI job in `.forgejo/workflows/ci.yml`. ## Acceptance criteria - [ ] Renaming a route on only one side makes the contract test fail. - [ ] Bot startup logs the handshake result in all four cases above (unit-testable against a mocked meta response). - [ ] `GET /api/bot/meta` requires the same `X-Bot-Key` auth as the rest of the bot router (or is explicitly public — decide and document). - [ ] CLAUDE.md documents the contract-version bump rule. ## References - `webapp/backend/app/routers/bot.py` - `bot/questboard_bot/api_client.py` - `.forgejo/workflows/ci.yml` _Filed from the July 2026 full-project review._
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#93
No description provided.