contract(issue#1): pin sse_client to gitea issue + seed default labels

Convert the sse_client contract into an issue-scoped contract bound to
the freshly-filed gitea issue #1. Frontmatter migrates from module-shape
(module:/purpose:) to issue-shape (target_module:/scope:/prd:) per
CONTRACT-FORMAT §2.1.I. The prd: block pins to issue #1's body SHA-256
(abcbc49467e86f1d at 2026-05-21T03:57:37+00:00); drift check verifies
the pin matches the live issue body.

scripts/contract_drift_check.py needs pyyaml; added to [dev] in
pyproject.toml. Without it the drift check (and the contract parser)
fail with ModuleNotFoundError — that's a scaffold hole I'd hit again
on a fresh checkout.

Also seed 17 default labels on gitea via tea so issue tracking has a
working vocabulary out of the gate. Five buckets: Sleipnir gating
(ready-for-agent, blocked-needs-contract, blocked-needs-dependency),
triage (needs-triage, needs-architect-decision, needs-info), type
(bug, enhancement, task, documentation), resolution (duplicate,
wontfix, invalid), Ratatoskr-specific area (sse-client, tui, cli,
observability). Labels are gitea-side state — not in this commit.

Known: contract_parser.py --validate ERRORs on the issue-scoped
frontmatter because the parser is v2.0-shape. CONTRACT-FORMAT §2.1.L
H10 explicitly marks parser kind-aware validation as a Brokkr-side
follow-up. Parser is a canonical-synced file so we do NOT patch it
locally (would drift from corviduo-project-template).
This commit is contained in:
vh
2026-05-20 20:59:46 -07:00
parent 72d477f516
commit 999b0b4765
4 changed files with 63 additions and 4 deletions
@@ -1,7 +1,7 @@
---
contract_version: "2.1"
module: "ratatoskr.sse_client"
purpose: "Worldtree Conversation API SSE consumer — turn streaming, in-process reconnect via Last-Event-ID, and server-side turn cancellation. Single shared consumer for TUI and stdout presenters."
target_module: "ratatoskr.sse_client"
scope: "Implement the Worldtree Conversation API SSE consumer for Ratatoskr. Single module bundling stream_turn (POST + SSE iteration), reconnect_turn (Last-Event-ID resume), cancel_turn (server-side cancel POST), and the private _parse_sse_id helper. The module is the shared API-consumption surface for both presenters (Textual TUI in ratatoskr.tui and stdout in --send mode via ratatoskr.cli); neither forks the SSE parsing. No core.* / worldtree.* imports — spec-only dependency (boundary enforced by tests/test_no_worldtree_imports.py)."
depends_on:
- "httpx"
- "httpx-sse"
@@ -12,6 +12,14 @@ language: "python"
complexity: "high"
estimated_loc: 320
confidence: 0.85
prd:
issue: 1
issue_url: "https://gitea.phasefinal.com/vh/ratatoskr/issues/1"
body_sha256_16: "abcbc49467e86f1d"
lock_in_comment_id: null
lock_in_sha256_16: null
lock_in_at: null
pinned_at: "2026-05-21T03:57:37+00:00"
assumptions:
- "Worldtree spec pin (`docs/conversation-api-spec.md` at v1.0, repo SHA `55101e909abcd2219833266b6f905c5bc956e0f0`) is the wire contract. Event names, JSON shapes, status codes, and `id:` format are read FROM the spec, not from any Worldtree source import."
- "`httpx-sse` correctly parses the full SSE wire format including multi-line `data:`, `id:`, `event:`, `retry:`, and comment lines. Hand-rolled `data:`-only parsing is rejected (would silently drop the load-bearing composite `id:`)."