- new gateway::schema_cache — PublishSchemaCache: compile the op's
publish_schema once per registration (value-keyed invalidation for
hot reload), cache compile failures (logged once at error level,
never retried per request)
- /publish compile failure is now fail-closed: the chunk stream
terminates with INTERNAL (500), the error text stays in the log
(no schema internals on the wire) — the per-request warn-and-skip
unvalidated ingest path is removed
- schema resolution is lazy (first chunk poll, after invoke_sink's
404/403/422 pre-checks — GW-11 order preserved) and keyed by schema
value, so re-registration/hot reload is picked up (test)
- NdjsonChunkStream: first Err item is terminal (done + stream end),
mirroring the wire pump's send(Err) + break — Ok chunks can never
follow an error on the HTTP path either (found by spy-handler test)
Verified: cargo test (308), cargo test --all-features, clippy
--all-targets -D warnings (default + all-features), fmt --check.
Tasks: review-001-publish-schema-validation-robust
Found in the sweep of completed review-001 remediation:
- /publish schema validation fails open on compile error + recompiles
per request (remediation-introduced, routes.rs:254-268)
- OAI-06 loud-degradation unblocked and still open (HTTP_0 marker)
- HY-06 ExponentialBackoff in public API + COV-02 mTLS success path
both unblocked post client-config rework
- HY-02/04/11 publish-prep docs gate (104 missing-docs warnings
re-measured)
Also flagged, not tasked here: WS-12 (alkcall demux 4 GiB discard
alloc) was never actually filed in alkcall's consumer-findings-ledger —
only CF-001 is there. File it when next touching alkcall.
taskgraph: validate clean (42), no cycles
- GW-01: /publish validates every NDJSON chunk against the op's
publish_schema (incl. the first-line chunk) via NdjsonChunkStream —
terminal Err(INVALID_INPUT)/422 on violation, matching the wire
dispatcher's per-chunk contract. Route-level fix; the alkcall spine
was explored and rejected (wire validation is pump-side by design).
- GW-06: the body is streamed, not buffered — Body::into_data_stream()
-> newline-framed BufferedLines -> lazily parsed chunk stream.
ADR-068 documents the streamed semantics and the 2 MiB per-line cap.
- GW-08: /batch capped at 100 operations (INVALID_INPUT 400).
- GW-09: internal-op batch entries now carry generated UUID request ids.
- GW-10: first publish line missing `chunk` is rejected INVALID_INPUT.
- GW-11: redundant /publish pre-checks removed; enforcement rides on
invoke_sink via the shared dispatch spine.
- HY-13: the vacuous stub test was replaced by a body-cut-short test.
- Adjacent: INVALID_OPERATION_TYPE now maps 422 (with identity) / 401
(without) in error.rs — the route relies on the shared mapper since
the pre-checks are gone (GW-03's finding; was a 500 fall-through).
Verification: cargo test 211 passed; cargo clippy --all-targets -- -D
warnings clean; cargo fmt --check clean.
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