Commit Graph
2 Commits
Author SHA1 Message Date
glm-5.3-flash 2ec02fd578 feat(adapters): enforce advertised input schemas at call time (OAI-18, option a)
Decision: advertise == enforce. The key allowlist (OAI-02) stays as the
first gate with its established unknown-key message; a compiled leaf
validator now runs second, so required/type/enum/pattern/bounds
violations surface as INVALID_INPUT 422 naming the keyword — not as
upstream round-trips.

- new src/adapters/input_validation.rs: CompiledInputSchema compiles an
  op's input_schema once at import with the jsonschema crate (same
  2020-12 dialect publish_schema uses) and validates peer input at call
  time; the compile-time copy is hardened closed-by-default
  (additionalProperties: false injected when absent) so the validator
  reproduces the allowlist's unknown-key semantics; explicit
  additionalProperties:true catch-all and schema values are preserved;
  the original spec value is never mutated
- from_openapi/from_jsonschema import(): compile per registration,
  capture the validator in the handler closure (re-import recompiles —
  the closure capture is the invalidation story); a non-compilable
  input schema fails import loudly (AdapterError::SchemaParse naming
  the operation), matching the publish_schema fail-closed precedent
- from_openapi generated input schemas now carry
  additionalProperties:false explicitly, so the /schema advert states
  the enforced rule and external schema-driven validators reach the
  same verdicts
- forward/forward_stream/build_request gain an
  Option<&CompiledInputSchema> parameter; enforcement runs after the
  allowlist
- round-trip test (review 002 Test-gap 10): the /schema-exported
  input_schema is compiled with the same validator and driven against
  build_request over a 10-input violation matrix — accept-sets exactly
  equal in both directions; the chain-test that lets advertise/enforce
  drift surface as a CI failure
- ADR-066: new decision section (advertise==enforce) with the trust-
  boundary reasoning and the rejected option (b) rationale
- module + enforce_input_schema docs updated to the two-gate shape

cargo test --all-features 596 pass; clippy --all-features/-D warnings,
fmt, doc gates clean.

docs(tasks): mark review-002-fu-oai18-decision done
2026-08-31 07:18:53 +00:00
glm-5.3-flash 5acc561eca docs(tasks): re-validate bracketed follow-up into 3 tasks (OAI-18 decision, streaming-coverage residue, doc-gate fix)
The bracketed planning task's five candidates, re-validated against
the post-bulk tree (0a932e5, all 23 bulk tasks done, 446/568 green):

1. OAI-18 -> review-002-fu-oai18-decision: still key-allowlist-only;
   bulk blockers (yaml/path-item) both landed. Task records the
   enforce-vs-scope-the-advert decision framework from review 002.
2. CON-08/CON-09 close() lever: deferred still (documented v1
   contracts unchanged, no consumer pressure) — not tasked.
3. Cross-crate: CF-001..004 all open in alkcall, no alkhttp-side task;
   PRJ-16 guard already documents its defense-in-depth re-scope
   disposition (no work when CF-004 lands).
4. Stale-comment sweep: mostly absorbed by the bulk (SRV-11 comment
   rewritten in-fix); residue = 3 cargo-doc warnings + WsTimeouts
   redundant Default -> review-002-fu-doc-warnings.
5. ADR-045 version audit: clean (1.4.0 + annotations + test pin).

Post-bulk coverage re-pass (95.89% regions, bulk's new code fully
covered: PRJ-16 guard, body cap, router reorder, batch cap, WS
knobs, OAI-11 node budget all exercised) surfaced one unanticipated
residue -> review-002-fu-stream-error-coverage (forward_stream
build-error arm never exercised on a Sub op; PEM read-failure arms;
over-cap poll_write; SSE split-CRLF edge; from_value structural
rejects; WsTimeouts Default).

Bracketed pass itself marked completed (planning consumed).
taskgraph: 69 valid, no cycles; 3 pending.
2026-08-31 05:40:46 +00:00