docs(tasks): decompose review 001 remediation Units 1-5 into taskgraph tasks
21 review-001 tasks across server/adapters/client/gateway/websocket/infra, chunked from the 7-unit remediation plan in docs/reviews/001-initial-implementation-review.md. - Scope split by mechanism, not one-per-finding: 15 tasks in generation 1 (parallelizable), 6 sequenced after their file-sharing precursors - Deliberately deferred until dependent fixes land: projection/doc fidelity partial (Unit 6 beyond dependency hygiene), coverage backfills (COV-01..07 via in-task acceptance for forward.rs), and per-finding minors (OAI-06/07, HY-02/04/06/10/11, CON-08) - Cross-crate WS-12 (alkcall demux 4 GiB discard alloc) noted for filing in alkcall, not here taskgraph: validate clean, no cycles, 6 generations
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
---
|
||||
id: review-001-gateway-publish-semantics
|
||||
name: /publish + /batch gateway fixes (GW-01, GW-06, GW-08..GW-11, HY-13)
|
||||
status: pending
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: medium
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [gateway, review-001]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Review 001 findings on `src/gateway/routes.rs`'s `/publish` and `/batch`
|
||||
routes:
|
||||
|
||||
- **GW-01 (major)**: `/publish` (`routes.rs:257-276`) feeds parsed NDJSON
|
||||
straight to `invoke_sink`; `publish_schema` validation lives only in
|
||||
alkcall's wire `Dispatcher` — so a Pub op registered with
|
||||
`publish_schema` receives arbitrary attacker-controlled JSON over HTTP
|
||||
while the same op over the call protocol aborts invalid chunks.
|
||||
Handlers written against the validated-wire guarantee get a
|
||||
transport-dependent invariant. Fix: validate in the route (or move
|
||||
validation into the shared `invoke_sink` spine so both transports
|
||||
enforce it — prefer the spine if alkcall's surface allows, else the
|
||||
route).
|
||||
- **GW-10**: a first line missing `chunk` silently publishes
|
||||
`Value::Null` (`routes.rs:213`) — indistinguishable from intent since
|
||||
null is a legitimate payload. Reject with `INVALID_INPUT` (the route
|
||||
already rejects a missing `operation` this way).
|
||||
- **GW-06**: `/publish` buffers the whole NDJSON body (2 MiB-capped)
|
||||
before dispatch, contradicting ADR-068 step 4. Either stream the body
|
||||
(axum `Body` → framed stream) — the real fix — or amend ADR-068 to
|
||||
document the buffered 2 MiB semantics. Decide, then implement or
|
||||
amend.
|
||||
- **GW-08**: no cap on batch operation count; the 2 MiB body is the only
|
||||
bound and the 30 s deadline is unenforced (GW-05). Cap batch size
|
||||
(constant, e.g. 100).
|
||||
- **GW-09**: internal-op batch entries emit `request_id: null` while
|
||||
dispatched entries carry a UUID — one response body, two envelope
|
||||
shapes. Generate request ids for internal-op entries.
|
||||
- **GW-11**: `/publish` runs four registry lookups + ACL checks that
|
||||
`invoke_sink` then repeats — drop the redundant pre-checks (mirror
|
||||
`/call`/`/batch`, which deliberately rely on the registry).
|
||||
- **HY-13**: the vacuous test at `routes.rs:1572-1583`
|
||||
(`publish_body_is_fully_consumed_before_dispatch_not_required`) cites a
|
||||
socket-level test that doesn't exist — wire the early-disconnect test
|
||||
or delete the stub.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/publish` test with a `publish_schema`-registered Pub op rejects an invalid chunk (review's gate for this unit)
|
||||
- [ ] First line without `chunk` → `INVALID_INPUT`, not a null publish (test)
|
||||
- [ ] GW-06 decision landed: true streaming or ADR-068 amended; consistent tests + docs
|
||||
- [ ] Batch size capped (test); mixed-shape batch envelopes fixed
|
||||
- [ ] Redundant `/publish` pre-checks removed (dispatch still enforces)
|
||||
- [ ] `cargo test` and `cargo clippy --all-targets -- -D warnings` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/reviews/001-initial-implementation-review.md (Part C, GW-01, GW-06, GW-08..GW-11; HY-13)
|
||||
- docs/architecture/decisions/068-gateway-publish-endpoint.md
|
||||
- docs/architecture/decisions/023-operation-error-schemas.md
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills during implementation. If the GW-01 fix goes into
|
||||
> alkcall's `invoke_sink` spine, coordinate the alkcall change (small,
|
||||
> additive) and note it in the summary.
|
||||
|
||||
## Summary
|
||||
|
||||
> Filled on completion.
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: review-001-gateway-stream-errors
|
||||
name: Gateway error-fidelity — SSE terminality, mappings, Retry-After, deadline (GW-03..GW-07, GW-12..GW-14)
|
||||
status: pending
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [gateway, review-001]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Review 001 gateway error-fidelity findings
|
||||
(`src/gateway/routes.rs`, `error.rs`, `dispatch.rs`) — the response a
|
||||
caller sees must match the documented contract and match across
|
||||
transports:
|
||||
|
||||
- **GW-04**: SSE error events are not terminal — the stream continues
|
||||
after `Err` (`routes.rs:299-313`) while the wire dispatcher treats
|
||||
`Err` as terminal; two transports disagree about stream semantics
|
||||
(http-server.md:219-223 documents terminal). Emit the error frame and
|
||||
end the stream (`take_while`).
|
||||
- **GW-03**: `INVALID_OPERATION_TYPE` → 500 on `/call`//`/batch` (client
|
||||
fault reported as server fault; pollutes alerting) but 400 on
|
||||
`/publish`. Map consistently (400 or 422) and document in
|
||||
http-server.md.
|
||||
- **GW-05**: the 30 s `DEFAULT_TIMEOUT` deadline is recorded
|
||||
(`dispatch.rs:34,165`) but never enforced — a hung handler holds the
|
||||
request open indefinitely. Either enforce (`tokio::time::timeout`
|
||||
around Once-op invokes) or remove the dead metadata. Prefer enforcing;
|
||||
it is the documented contract.
|
||||
- **GW-07**: `Retry-After` machinery exists in
|
||||
`call_error_to_http_response` (`error.rs:61-75`) but the main gateway
|
||||
error path builds responses by hand (`routes.rs:319-333`) — retryable
|
||||
`HTTP_429`/`HTTP_503` reach callers with no `Retry-After` despite the
|
||||
documented mapping. Route gateway error responses through the shared
|
||||
mapper.
|
||||
- **GW-12**: ACL denial on `/subscribe` surfaces as HTTP 200 +
|
||||
`event:error` while `/call` returns 401/403. ADR-049 makes
|
||||
200-on-stream defensible, but the doc must call out the asymmetry —
|
||||
coordinate with review-001-output-projection (PRJ-05) which documents
|
||||
it.
|
||||
- **GW-13**: no SSE keep-alive/heartbeat (`routes.rs:172`) — quiet-but-
|
||||
alive streams (the normal state for subscriptions) die at LB/proxy
|
||||
idle timeouts. Add keep-alive + `retry:` field.
|
||||
- **GW-14**: stale module doc (`routes.rs:1-9` claims `/publish` is "a
|
||||
separate module"; AGENTS.md §7's "5 gateway endpoints" framing is
|
||||
similarly stale — ADR-068 made it 6).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] SSE stream ends after an error event (test); keep-alive present
|
||||
- [ ] `INVALID_OPERATION_TYPE` maps to the same status on `/call`, `/batch`, `/publish`; http-server.md table updated
|
||||
- [ ] Once-op invokes enforce the 30 s deadline (test with a hung handler)
|
||||
- [ ] Retryable errors carry `Retry-After` on all live error paths (test)
|
||||
- [ ] GW-14 docs fixed (module doc; AGENTS.md gateway-endpoint count if touched)
|
||||
- [ ] `cargo test` and `cargo clippy --all-targets -- -D warnings` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/reviews/001-initial-implementation-review.md (Part C, GW-03..GW-07, GW-12..GW-14)
|
||||
- docs/architecture/decisions/049-streaming-handler-for-subscriptions.md
|
||||
- docs/architecture/decisions/023-operation-error-schemas.md
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills during implementation. Independent of
|
||||
> review-001-gateway-publish-semantics (both touch routes.rs —
|
||||
> sequence or coordinate to avoid churn).
|
||||
|
||||
## Summary
|
||||
|
||||
> Filled on completion.
|
||||
Reference in New Issue
Block a user