Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
# OpenSpec Change: serialize-spec-conformance
- **Change ID**: serialize-spec-conformance
- **Package**: `@suaveplan/serialize`
- **Status**: PROPOSED
- **Date**: 2026-04-26
- **Reference**: `openspec/specs/serialization/spec.md`, `openspec/archive/2026-04-19-enterprise-serialize/`
## Summary
Annotate every requirement in `openspec/specs/serialization/spec.md` with a `**Verified by:**` line, pin previously-implicit scenarios with explicit tests, close the SZ-10 (wire-format + options validation) and SZ-11 (OTel instrumentation) gaps in scope, thread `<T = unknown>` generics through the public deserialize entry points, and rectify the historical "retroactively ticked" hazard in `2026-04-19-enterprise-serialize/tasks.md` so `bun scripts/openspec-conformance.ts @suaveplan/serialize` exits 0.
## Current state
`@suaveplan/serialize` ships a complete tagged-JSON codec, MessagePack profile, Web Streams encoder/decoder, `serialize-javascript` `/unsafe` adapter, Zod-validated `TypeDefinition` registry, structured error hierarchy, and 100/100/100/100 coverage. The conformance gaps are documentary plus three previously-implicit scenarios that no test pinned explicitly:
- 12/12 requirements lack `**Verified by:**` lines.
- SZ-02 typed-array round-trip — only `Uint8Array` is tested through the public `serialize → deserialize` round-trip; the other seven typed arrays (`Int8Array`, `Int16Array`, `Int32Array`, `Uint16Array`, `Uint32Array`, `Float32Array`, `Float64Array`) only exercise the registry directly.
- SZ-03 envelope shape — the `{ "__t": "<tag>", "v": <encoded> }` wire format is implicit in encode tests but not asserted as a structural contract.
- SZ-06 MessagePack bit-identical output — "structurally equivalent" is asserted, but the spec MUST is bit-identical bytes for the same input.
- `archive/2026-04-19-enterprise-serialize/tasks.md` carries `retroactively ticked`.
## Non-goals (deferred to follow-up changes)
_None._ Two implementation gaps were originally deferred here and have since been folded back into this change at the user's request:
- **SZ-10 schema validation at the public boundary** — closed in scope. New `WireNodeSchema` + `TaggedEnvelopeSchema` + `validateWireNode` defend `deserialize` / `decodeBinary` against malformed inputs (throws `MalformedWireError`, code `SERIALIZE.CODEC.MALFORMED_WIRE`); the existing `SerializeOptionsSchema` / `DeserializeOptionsSchema` are now `.safeParse()`'d at every public entry point (throws `InvalidOptionsError`, code `SERIALIZE.OPTIONS.INVALID`).
- **SZ-11 OTel instrumentation** — closed in scope. New `src/observability/metrics.ts` exports a lazy `getSerializeMetrics()` singleton built from `metrics.getMeter('suaveplan.serialize')`. Six instruments wired into all four public entry points: `serialize.encode.bytes`, `serialize.decode.bytes`, `serialize.payload_bytes`, `serialize.encode.duration_ms`, `serialize.decode.duration_ms` (histograms) and `serialize.error.total` (counter, `code` + `format` labels). Verified by tests that wire a real, in-memory `MeterProvider` (not `vi.mock`).
A third refinement was added in the same pass: the public `deserialize`, `decodeBinary`, `legacyDeserialize`, and `deserializeEvalSafe` entry points now accept an optional `<T = unknown>` generic so callers receive `T` instead of `unknown` at the call site (type-only change, runtime unchanged).
## What changes
1. Add `**Verified by:**` line under every `### SZ-NN` block in `openspec/specs/serialization/spec.md`.
2. Add `src/codec/json/json-encode.spec-conformance.test.ts` covering:
- SZ-02: `Int8Array`, `Int16Array`, `Int32Array`, `Uint16Array`, `Uint32Array`, `Float32Array`, `Float64Array` end-to-end `serialize → deserialize` round-trip.
- SZ-03: explicit assertion that a `Date` value encodes to `{ __t: "__Date", v: <iso-string> }` (envelope shape contract).
3. Add `src/codec/msgpack/msgpack-encode.spec-conformance.test.ts` covering:
- SZ-06: `encodeBinary(x)` produces byte-identical output across two calls for the same structured input (Map keys insertion-order varied).
4. **SZ-10**: add `src/codec/wire/wire.schemas.ts` (`WireNodeSchema`, `TaggedEnvelopeSchema`, `validateWireNode`); add `MalformedWireError` and `InvalidOptionsError` to `src/errors/serialize-error.ts`; tighten `src/codec/json/json.schemas.ts` to `.strict()` with duck-typed `signal`; wire schema validation into all four public entry points; add `src/codec/wire/wire.schemas.test.ts` pinning the rejection set.
5. **SZ-11**: add `src/observability/metrics.ts` exposing `getSerializeMetrics()` + `resetSerializeMetrics()` with lazy `metrics.getMeter('suaveplan.serialize')`; emit `encode.bytes` / `decode.bytes` / `payload_bytes` / `encode.duration_ms` / `decode.duration_ms` histograms and `error.total` counter from every public entry point; add `src/observability/metrics.test.ts` using a real in-memory `MeterProvider` to assert emission.
6. **Generic threading**: thread `<T = unknown>` through `deserialize`, `decodeBinary`, `legacyDeserialize`, `deserializeEvalSafe` with `expectTypeOf` pins.
## Impact
- Public API gains: `MalformedWireError`, `InvalidOptionsError`, `WireNodeSchema`, `TaggedEnvelopeSchema`, `validateWireNode`, `getSerializeMetrics`, `resetSerializeMetrics`, `SerializeMetrics` type. New error codes `SERIALIZE.CODEC.MALFORMED_WIRE` and `SERIALIZE.OPTIONS.INVALID`.
- New tests across three files; new `src/codec/wire/` and `src/observability/` directories with co-located `.md` docs.
- `openspec/specs/serialization/spec.md` gains 12 `**Verified by:**` lines (SZ-10 / SZ-11 now reference real test IDs, no longer say "follow-up change").
- Coverage stays at 100/100/100/100.
- The `*-spec-conformance` change folder name auto-rectifies the historical retroactive-ticking flag in the conformance script.