docs(arch): amend ADR-051 §2 — yaml_serde 0.10.x is YAML 1.2, not 1.1

Implementation verified yaml_serde 0.10.4 (and serde_yaml 0.9) implement the
YAML 1.2 core schema, where bare yes/no/on/off are strings, not booleans. The
original §2 rationale cited YAML 1.1 boolean-coercion as a present hazard
justifying JSON-first detection; it does not exist with this dependency
version.

The JSON-first decision is retained (Accepted ADR) — reframed as a defensive
default that locks the contract against a future YAML-parser swap, not a
guard against a present hazard. §2 heading, Consequences, and Assumption #2
amended; an in-place amendment note records what changed and when. The two
coercion-related tests already document yaml_serde 0.10.x's actual behavior
with explicit comments. Source doc-comments on from_yaml/from_str corrected
to stop propagating the flawed assumption. 256 tests pass; clippy clean.
This commit is contained in:
glm-5.2 committed 2026-07-06 13:30:59 +00:00
1 parent 21c4f7d252
commit 14c8340380
4 files changed
+97 -52

No files matched your search

+1 -1
View File
@@ -54,7 +54,7 @@ protocol), and hosts the HTTP-backed call-protocol adapters
| [047](../../decisions/047-remove-direct-call-http-surface.md) | Remove the Direct-Call HTTP Surface; Gateway Is the Sole Invoke Path | `POST /{service}/{op}` direct-call surface removed; the 5 gateway endpoints are the sole invoke path; per-caller `AccessControl`-filtered `/search` is the discovery; ADR-036's non-routing clauses survive |
| [048](../../decisions/048-websocket-native-session-not-gateway.md) | WebSocket Carries the Native Call-Protocol Session, Not the Gateway Shape | WS is the native `EventEnvelope` session; the gateway endpoints (`/search`/`/schema`/`/call`/`/batch`/`/subscribe`) are HTTP-only and do not appear on WS; discovery via `services/list`/`services/schema` as call-protocol ops |
| [049](../../decisions/049-streaming-handler-for-subscriptions.md) | Streaming Handler for Subscription Operations | `from_openapi` `Subscription` ops register a `StreamingHandler` (`HandlerKind::Stream`); SSE → `BoxStream<ResponseEnvelope>` |
| [051](../../decisions/051-yaml-input-for-from-openapi.md) | YAML Input Format for from_openapi | `from_openapi` accepts JSON and YAML (`from_json`/`from_yaml`/`from_str`); `from_str` is JSON-first/YAML-fallback (correctness rule, §2); YAML dep is `yaml_serde` (maintained fork of deprecated `serde_yaml`); `to_openapi` output stays JSON (out of scope, §4) |
| [051](../../decisions/051-yaml-input-for-from-openapi.md) | YAML Input Format for from_openapi | `from_openapi` accepts JSON and YAML (`from_json`/`from_yaml`/`from_str`); `from_str` is JSON-first/YAML-fallback (defensive default, §2 amended — `yaml_serde` 0.10.x is YAML 1.2, not 1.1); YAML dep is `yaml_serde` (maintained fork of deprecated `serde_yaml`); `to_openapi` output stays JSON (out of scope, §4) |
## Relevant Open Questions
+16 -8
View File
@@ -65,8 +65,12 @@ impl OperationAdapter for FromOpenAPI {
/// fork of the deprecated `serde_yaml`). Both paths produce the same
/// `serde_json::Value`-based internal type — there is one
/// `OpenAPISpec`, not a JSON and a YAML variant. `from_str` detects
/// format by trying JSON first and falling back to YAML (correctness
/// rule — ADR-051 §2).
/// format by trying JSON first and falling back to YAML (defensive
/// default — ADR-051 §2: JSON's stricter grammar is immune to any
/// YAML-specific type interpretation, present or future; with
/// `yaml_serde` 0.10.x's YAML 1.2 core schema the coercion the original
/// rationale cited is not present, but JSON-first locks the contract
/// against a future YAML-parser swap).
pub struct OpenAPISpec {
pub info: OpenAPIInfo,
pub paths: BTreeMap<String, PathItem>,
@@ -106,7 +110,7 @@ The adapter:
1. Parses the OpenAPI document (`OpenAPISpec` — `paths`, `components`,
`$ref` resolution). Accepts JSON or YAML (ADR-051 — JSON via
`serde_json`, YAML via `yaml_serde`; `from_str` detects format
JSON-first/YAML-fallback, a correctness rule — ADR-051 §2). On parse
JSON-first/YAML-fallback, a defensive default — ADR-051 §2). On parse
failure, returns `AdapterError::SchemaParse`. The TS prior art
(`@alkdev/operations/src/from_openapi.ts`) shows the parsing patterns:
`resolveRef` for `$ref`, `resolveRefsRecursive` for nested refs,
@@ -418,10 +422,14 @@ once published, the 5-endpoint gateway shape is one-way.
- **`from_openapi` error codes are prefixed `HTTP_<status>`.** No
collision with protocol-level codes (ADR-023, review #002 W20).
- **`from_openapi` accepts JSON and YAML; `from_str` detects format
JSON-first.** JSON-first is a correctness rule (ADR-051 §2), not a
style preference. `from_str` tries JSON first (strict grammar), falls
back to YAML only if JSON parse fails. `from_json`/`from_yaml` are
the explicit constructors for callers that know the format.
JSON-first.** JSON-first is a defensive default (ADR-051 §2 as
amended): JSON's stricter grammar is immune to any YAML-specific type
interpretation. With `yaml_serde` 0.10.x (YAML 1.2 core schema) the
coercion the original rationale cited is not present, but JSON-first
locks the contract against a future YAML-parser swap. `from_str` tries
JSON first, falls back to YAML only if JSON parse fails.
`from_json`/`from_yaml` are the explicit constructors for callers that
know the format.
- **`to_openapi` is a pure projection.** It consumes the registry, does
not produce entries for it. Not an `OperationAdapter`.
- **`to_openapi` output is JSON.** The published gateway doc is served at
@@ -462,7 +470,7 @@ once published, the 5-endpoint gateway shape is one-way.
| `to_openapi` gateway pattern | [ADR-042](../../decisions/042-openapi-gateway-pattern.md) | 5 fixed gateway endpoints (search/schema/call/batch/subscribe), not one path per operation; per-caller AccessControl-filtered. Supersedes ADR-036's original `to_openapi` "paths mirror `/{service}/{op}`" clause |
| `to_openapi` published-spec versioning | [ADR-045](../../decisions/045-to-openapi-gateway-spec-versioning.md) | `info.version` semver tracks the gateway endpoint contract, not the operation set; consumers detect breaking changes via the major version |
| Streaming handler for subscriptions | [ADR-049](../../decisions/049-streaming-handler-for-subscriptions.md) | `from_openapi` `Subscription` ops register a `StreamingHandler` (`HandlerKind::Stream`); SSE response → `BoxStream<ResponseEnvelope>`; `Query`/`Mutation` stay `HandlerKind::Once` |
| YAML input + JSON-first format detection | [ADR-051](../../decisions/051-yaml-input-for-from-openapi.md) | `from_openapi` accepts JSON and YAML (`from_json`/`from_yaml`/`from_str`); `from_str` is JSON-first/YAML-fallback (correctness rule, §2); YAML dep is `yaml_serde`; `to_openapi` output stays JSON (out of scope, §4) |
| YAML input + JSON-first format detection | [ADR-051](../../decisions/051-yaml-input-for-from-openapi.md) | `from_openapi` accepts JSON and YAML (`from_json`/`from_yaml`/`from_str`); `from_str` is JSON-first/YAML-fallback (defensive default, §2 amended — `yaml_serde` 0.10.x is YAML 1.2, not 1.1; JSON-first locks the contract against a future parser swap); YAML dep is `yaml_serde`; `to_openapi` output stays JSON (out of scope, §4) |
## Open Questions