(plan) update the plan to captures more
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# T10.4 — HTTP API surface
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Phase | P10 — Orchestration |
|
||||
| Size | L — over 3 days |
|
||||
| Status | Not started |
|
||||
| Flags | — |
|
||||
| Spec | inlined below |
|
||||
| Blocks | T10.6, T10.7, T10.9 |
|
||||
|
||||
## Goal
|
||||
|
||||
`axum` HTTP service binding one method table — spawn / status / stream /
|
||||
episode / transcript / rewind / cancel / retry / goal / metrics — to
|
||||
`poimen-sdk` ports. One method set: HTTP today, the same table T9.2's stdio
|
||||
JSON-RPC binds to later.
|
||||
|
||||
## Facts (inlined — no spec read needed)
|
||||
|
||||
- **The protocol is a published artifact** — INDEX.md's own rule for the
|
||||
sidecar applies equally here: methods added, never repurposed; fields
|
||||
added, never removed, from the first commit.
|
||||
- HTTP is a transport binding onto `poimen-sdk` (T9.1), not a bespoke access
|
||||
layer with its own business logic. Handlers translate, they do not decide.
|
||||
- `/v1/problems` and `/v1/plans/{id}/approve|reject` route to T10.6's
|
||||
workflow, not implemented here — this task defines the routes and
|
||||
request/response contracts; T10.6 fills in plan-draft semantics.
|
||||
- `/v1/runs/{id}/stream` tails the same committed log the outbox relay reads
|
||||
— SSE, not a second read path.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Stand up the `axum` service, one route module per resource: runs, plans,
|
||||
goals, metrics.
|
||||
2. `POST /v1/runs` → spawn_run. Request `{tenant, workflow_ref, input,
|
||||
goal_id?, dispatch_key?}`. Response `{run_id, status}`.
|
||||
3. `GET /v1/runs/{id}`, `/episode` (T1.7), `/attempts/{step}/{n}/transcript`
|
||||
(T1.6 `BlobRef` dereference), `/stream` (SSE).
|
||||
4. `POST /v1/runs/{id}/rewind` (T2.3), `/cancel`, `/attempts/{step}/retry`
|
||||
(T1.4).
|
||||
5. `GET /v1/goals/{id}` (T10.1 `GoalView`).
|
||||
6. `GET /v1/metrics`, `/v1/runs/{id}/metrics` (T8.2's existing list, scoped).
|
||||
7. Auth/tenant resolution: reject any request without a resolvable
|
||||
`TenantId` before touching the kernel — no implicit tenant.
|
||||
8. Version the route set from commit one: additive only, document the rule
|
||||
inline in the router module.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Full request/response cycle for spawn → poll → episode → transcript
|
||||
against an embedded `redb` backend.
|
||||
- Rewind, cancel, retry each produce the same log-level effect as calling
|
||||
the underlying kernel function directly — no HTTP-layer divergence.
|
||||
|
||||
## Verify
|
||||
|
||||
**Harness:** embedded `redb`, stub model, `axum` test client
|
||||
(`tower::ServiceExt::oneshot`).
|
||||
|
||||
**Integration test** — `tests/it_http_api_surface.rs`:
|
||||
1. `POST /v1/runs`; assert 200 with `run_id`; assert kernel shows
|
||||
`Scheduled`.
|
||||
2. `GET /v1/runs/{id}` until terminal; assert status matches kernel state
|
||||
exactly at each poll.
|
||||
3. `GET /v1/runs/{id}/episode`; assert shape matches T1.7's `EpisodeView`,
|
||||
includes failed attempts.
|
||||
4. `GET /v1/runs/{id}/attempts/{step}/{n}/transcript`; assert returned bytes
|
||||
match `BlobStore` content directly (T1.6).
|
||||
5. `POST .../rewind`; assert new `BranchId` created, parent branch still
|
||||
readable via all-branches.
|
||||
6. `POST .../retry`; assert new `AttemptNo`, prior attempt record
|
||||
unmodified.
|
||||
7. `POST .../cancel` mid-run; assert `Cancelled` reached (matches T1.3's
|
||||
cancel matrix).
|
||||
8. Request with no resolvable tenant; assert rejected before any kernel call
|
||||
— instrument kernel entrypoints, assert zero calls.
|
||||
|
||||
**Command:** `cargo test -p api http_api_surface`
|
||||
|
||||
**False pass:**
|
||||
- Asserting HTTP 200 without checking underlying kernel state — a route that
|
||||
accepts and silently drops a request passes this.
|
||||
- Testing transcript retrieval only for a successful attempt — failed-attempt
|
||||
transcripts are the debugging case that matters most.
|
||||
|
||||
## Traps
|
||||
|
||||
- Putting business logic (retry policy, plan validation) in the HTTP
|
||||
handler instead of the kernel/port layer. The handler is a transport, not
|
||||
a second brain.
|
||||
- Resolving `BlobRef`s eagerly inside `/episode` "for convenience" — T4.3's
|
||||
regression, one layer up.
|
||||
|
||||
---
|
||||
|
||||
Background (not required to do this task):
|
||||
[rust-agentic-sys.md](../../../rust-agentic-sys.md) §8.5, §10.1 ·
|
||||
[../../INDEX.md](../../INDEX.md) (embedding contract, ~line 60-86) ·
|
||||
[T1.7-episode-query-surface.md](T1.7-episode-query-surface.md) ·
|
||||
[T1.6-prompt-and-output-blob-capture.md](T1.6-prompt-and-output-blob-capture.md)
|
||||
Reference in New Issue
Block a user