# `@suaveplan/cbor` — RFC 8949 CBOR encoder/decoder + RFC 9052 COSE bridge **Package**: `@suaveplan/cbor` (NEW) **Status**: PROPOSED **Type**: new-package (genesis-original; greenfield — no upstream port) **Date**: 2026-05-10 **Path**: `packages/vault/cbor/` ## Why `@suaveplan/webauthn` parses CTAP2 authenticator data, attestation statements, and COSE_Key public keys (RFC 9052), every one of which is a CBOR-encoded payload. The package gates on a universal-tier CBOR codec. External alternatives (`cbor-x`, `cbor`) drag in CommonJS interop hazards, oversize transitive deps, and decode behaviors that diverge from RFC 8949 §5.1 strict well-formedness. An in-house, RFC-cited, zero-dependency codec keeps `webauthn` universal-tier and lets every future consumer (CWT per RFC 8392, dCBOR, COSE-keyed vault attachments) share one canonical implementation with one error registry, one OTel surface, and one deterministic-encoding profile. ## What changes ### New package: `@suaveplan/cbor` - ADDED: `packages/vault/cbor/` package scaffold (`package.json`, `tsconfig.lib.json`, `vite.config.ts`, `vitest.config.ts`, `README.md`). - ADDED: `src/encoder/encoder.ts` — `Encoder` class and `encode(value, options?): Uint8Array` for RFC 8949 major types 0–7 with preferred-serialization shortest-form integers (§4.2.1). - ADDED: `src/encoder/encoder.types.ts` — `EncoderOptions`, `IndefiniteLengthMarker`, `PreferFloat16` flag, `MaxItems`, `MaxDepth`. - ADDED: `src/encoder/indefinite.ts` — opt-in indefinite-length encoder for arrays / maps / byte strings / text strings (§3.2). Disabled when `deterministic: true`. - ADDED: `src/encoder/half-float.ts` — IEEE-754 binary16 encode helper (major type 7 / value 25). Opt-in via `EncoderOptions.preferFloat16`. - ADDED: `src/encoder/deterministic.ts` — RFC 8949 §4.2.1 + §4.2.2 deterministic profile: shortest-form integers, sorted map keys (lexicographic over canonical CBOR-encoded key bytes), no indefinite-length encodings, half-float disabled. - ADDED: `src/encoder/dcbor.ts` — dCBOR profile (draft-mcnally-deterministic-cbor) exported under the `./deterministic` subpath, layering reduction rules for numeric values and prohibition of `undefined` / `simple-value` over the deterministic baseline. - ADDED: `src/decoder/decoder.ts` — `Decoder` class and `decode(bytes, options?): unknown` for RFC 8949 major types 0–7. Strict mode (default) enforces every §5.1 well-formedness rule. - ADDED: `src/decoder/decoder.types.ts` — `DecoderOptions`, `Tagged`, `DecoderMode = "strict" | "lax"`. - ADDED: `src/decoder/well-formed.ts` — well-formedness checker per §5.1 (`isWellFormed(bytes): boolean`, plus internal helpers used during decode). - ADDED: `src/decoder/half-float.ts` — IEEE-754 binary16 decode (parity with reference implementation; never gated, always available). - ADDED: `src/streaming/pull-decoder.ts` — `PullDecoder` over `Uint8Array` and `AsyncIterable` / `ReadableStream` exposing `next(): Promise>` so callers materialize one item at a time. Bounded-memory; never buffers the whole stream. - ADDED: `src/sequences/sequences.ts` — RFC 8742 CBOR Sequences encode (`encodeSequence(items, options?): Uint8Array`) and decode (`decodeSequence(bytes, options?): unknown[]`, plus `decodeSequenceStream` async iterator). - ADDED: `src/tags/registry.ts` — `TagRegistry` with `register(tag, handler)` / `unregister(tag)` / `lookup(tag)`. Built-in tags: 0 (RFC 3339 date/time), 1 (epoch), 2 (positive bignum), 3 (negative bignum), 21 (base64url), 22 (base64), 23 (base16), 24 (encoded CBOR), 32 (URI), 35 (regex), 55799 (self-describe). - ADDED: `src/tags/tagged.ts` — `Tagged` value object (`{ tag: number, value: T }`) returned by the decoder for unknown tags in strict mode-with-fallthrough and in lax mode. - ADDED: `src/cose/cose-key.ts` — `decodeCoseKey(bytes): CoseKey` returning the discriminated union `OkpKey | Ec2Key | RsaKey | SymmetricKey` per RFC 9052 §7. Exported under the `./cose` subpath. - ADDED: `src/cose/jwk.ts` — `coseKeyToJwk(key): JsonWebKey` and `jwkToCoseKey(jwk): CoseKey` round-trip helpers. - ADDED: `src/cose/alg-map.ts` — `coseAlgToCryptoAlg(alg)` mapping COSE algorithm labels (-7 ES256, -8 EdDSA, -35 ES384, -36 ES512, -257 RS256, etc.) to genesis-internal `@suaveplan/crypto-curve` algorithm IDs. - ADDED: `src/cose/cose.types.ts` — `CoseKey`, `OkpKey`, `Ec2Key`, `RsaKey`, `SymmetricKey`, `CoseAlg`, `CoseKty`, `CoseCurve`, `CoseKeyOp`. Discriminated by `kty`. - ADDED: `src/diagnostic/diagnostic.ts` — `toDiagnostic(value): string` emitting RFC 8949 §8 diagnostic notation. Marked debug-only in docs; never invoked by encoder / decoder hot paths. - ADDED: `src/errors/error-codes.ts` — `defineCodes("CBOR", [...])` registry with `MALFORMED`, `UNEXPECTED_TYPE`, `UNKNOWN_TAG_STRICT`, `NESTED_TOO_DEEP`, `LENGTH_OVERFLOW`, `INDEFINITE_NOT_ALLOWED`, `NON_DETERMINISTIC` plus `CborError extends SuaveplanError`. - ADDED: `src/observability/metrics.ts` — `cbor.encode_duration_ms` + `cbor.decode_duration_ms` histograms; `cbor.tag_total{tag}` + `cbor.error_total{code}` counters. Wired into encode / decode hot paths. - ADDED: `src/schemas/schemas.ts` — Zod boundary schemas for `EncoderOptions`, `DecoderOptions`, `TagHandlerSchema`, `CoseKeySchema` discriminated union, `JwkSchema`. Validated at every public entry point; failures surface as `CBOR.MALFORMED` (decoder input) or as a Zod-wrapped boundary error (option misuse). - ADDED: `src/__benchmarks__/encode.bench.ts`, `decode.bench.ts`, `cose-key.bench.ts` — mitata benchmarks for 1 KiB COSE_Key, 1 MiB nested map, 100 KiB array of small items. - ADDED: `src/index.ts` — explicit named re-exports of the public surface (no `export *`). ### Subpath exports - `.` — root barrel: encode, decode, `Tagged`, `TagRegistry`, error codes, OTel. - `./encoder` — `Encoder`, `encode`, `EncoderOptions`, half-float helper. - `./decoder` — `Decoder`, `decode`, `DecoderOptions`, well-formedness checker. - `./streaming` — `PullDecoder` (whole-item) + `ChunkDecoder` (partial-item) over `AsyncIterable` / `ReadableStream`. - `./sequences` — RFC 8742 `encodeSequence` / `decodeSequence` / `decodeSequenceStream`. - `./tags` — `TagRegistry`, `Tagged`, built-in tag handlers. - `./deterministic` — RFC 8949 §4.2 deterministic profile + dCBOR profile. - `./cose` — `COSE_Key` parsing, `JWK` round-trip, alg-map, plus `COSE_Sign` / `COSE_Sign1` / `COSE_Encrypt` / `COSE_Encrypt0` / `COSE_Mac` / `COSE_Mac0` encode / decode / verify / decrypt (RFC 9052 §4–§6). - `./cwt` — RFC 8392 CBOR Web Token claim encode / decode / verify with time-window validation. - `./cddl` — RFC 8610 CDDL lexer / parser / validator. - `./diagnostic` — `toDiagnostic` debug emitter. - `./errors` — `CBOR_CODES`, `CborError`, `CborErrorCode`. ### Dependencies - `@suaveplan/error workspace:^` — `defineCodes`, `SuaveplanError` base. - `@suaveplan/types workspace:^` — shared interface contracts (`Clock` for CWT time validation, base interfaces). - `@suaveplan/crypto-curve workspace:^` — only consumed by `./cose` (`coseAlgToCryptoAlg`, `verifyCoseSign1`) and `./cwt` (`verifyCwt`). Root + `./encoder` + `./decoder` + `./cddl` + `./streaming` + `./sequences` + `./tags` + `./diagnostic` subpaths do NOT depend on `crypto-curve` at runtime. - `@suaveplan/crypto-cipher workspace:^` — only consumed by `./cose` (`decryptCoseEncrypt0`) for AES-GCM / ChaCha20-Poly1305 AEAD primitives. - `@suaveplan/crypto-hash workspace:^` — only consumed by `./cose` (`verifyCoseMac0`) for HMAC-SHA-{256,384,512}. - `@opentelemetry/api catalog:observability` — encode/decode histograms, tag/error counters, COSE / CWT / CDDL operation spans. - `tslib catalog:build`. - `zod catalog:forms` — option boundary validation. - **No** `@noble/*`, `cbor-x`, `cbor`, `@stablelib/*`, browser globals, or Node built-ins. Pure TypeScript over `Uint8Array` + `DataView`. ## Out of scope (residual) Per maintainer instruction, every previously-deferred capability has been folded back IN-scope (CWT, full COSE Sign/Sign1/Encrypt/Encrypt0/Mac/Mac0, CDDL parser+validator, partial-item streaming). The only remaining residual exclusion: - **CBOR-LD / SD-CBOR-LD** — distinct semantic-web layer (RDF + JSON-LD context compression) above CBOR; addressed in a separate `@suaveplan/cbor-ld` package when a consumer requests it. **Justification**: CBOR-LD requires a JSON-LD context resolver and an RDF graph model neither of which are CBOR-codec concerns; folding it in would couple this package to a semantic-web stack none of the current or pending consumers need. Not a silent gap. ## In-scope additions (Wave 2 — folded back per maintainer) ### CWT (RFC 8392) — `./cwt` subpath - ADDED: `src/cwt/claims.ts` — `CwtClaims` discriminated record with the seven IANA-registered claim labels (1 `iss`, 2 `sub`, 3 `aud`, 4 `exp`, 5 `nbf`, 6 `iat`, 7 `cti`) plus a `private[label]` slot for unregistered labels; encoder accepts `Date | number` for time-typed claims and round-trips through `Tagged(1, epoch)` per RFC 8392 §3. - ADDED: `src/cwt/encode.ts` — `encodeCwt(claims, options): Uint8Array` producing a deterministic-encoded claim set ready to be wrapped in `COSE_Sign1` or `COSE_Mac0`. - ADDED: `src/cwt/decode.ts` — `decodeCwt(bytes): CwtClaims` returning the typed claim set; rejects malformed labels with `CBOR.UNEXPECTED_TYPE`. - ADDED: `src/cwt/verify.ts` — `verifyCwt(token, key, options): Promise` orchestrating `COSE_Sign1` / `COSE_Mac0` verification via `@suaveplan/crypto-curve` (delegated through the COSE algorithm map) and time-window validation against an injectable `Clock`. - ADDED: `src/cwt/cwt.types.ts` — `CwtClaims`, `CwtVerifyOptions`, `CwtVerifyResult`, `CwtPrivateClaim`. - Errors used: `CBOR.UNEXPECTED_TYPE`, new `CBOR.CWT_EXPIRED`, `CBOR.CWT_NOT_YET_VALID`, `CBOR.CWT_AUDIENCE_MISMATCH`, `CBOR.CWT_ISSUER_MISMATCH`, `CBOR.CWT_SIGNATURE_INVALID`. ### COSE structures (RFC 9052 §4–§6) — extend `./cose` subpath - ADDED: `src/cose/sig-structure.ts` — `buildSigStructure(context, protected, externalAad, payload): Uint8Array` per RFC 9052 §4.4. Five contexts: `"Signature"`, `"Signature1"`, `"CounterSignature"`, `"MAC"`, `"MAC0"`. - ADDED: `src/cose/sign.ts` — `encodeCoseSign({ protected, unprotected, payload, signers }): Uint8Array` and `decodeCoseSign(bytes): CoseSign` covering RFC 9052 §4.1 multi-signer messages (CBOR tag 98). - ADDED: `src/cose/sign1.ts` — `encodeCoseSign1({ protected, unprotected, payload, signature }): Uint8Array` / `decodeCoseSign1(bytes): CoseSign1` / `verifyCoseSign1(msg, key, options): Promise` covering RFC 9052 §4.2 single-signer messages (CBOR tag 18). Wires the algorithm-map → `@suaveplan/crypto-curve` ECDSA / EdDSA verifiers. - ADDED: `src/cose/encrypt.ts` — `encodeCoseEncrypt({ protected, unprotected, ciphertext, recipients }): Uint8Array` / `decodeCoseEncrypt(bytes): CoseEncrypt` covering RFC 9052 §5.1 multi-recipient encrypted messages (CBOR tag 96). - ADDED: `src/cose/encrypt0.ts` — `encodeCoseEncrypt0({ protected, unprotected, ciphertext }): Uint8Array` / `decodeCoseEncrypt0(bytes): CoseEncrypt0` / `decryptCoseEncrypt0(msg, key, options): Promise` covering RFC 9052 §5.2 single-recipient encrypted messages (CBOR tag 16). Wires AES-GCM / ChaCha20-Poly1305 via `@suaveplan/crypto-cipher`. - ADDED: `src/cose/mac.ts` — `encodeCoseMac({ protected, unprotected, payload, tag, recipients }): Uint8Array` / `decodeCoseMac(bytes): CoseMac` covering RFC 9052 §6.1 multi-recipient MAC messages (CBOR tag 97). - ADDED: `src/cose/mac0.ts` — `encodeCoseMac0({ protected, unprotected, payload, tag }): Uint8Array` / `decodeCoseMac0(bytes): CoseMac0` / `verifyCoseMac0(msg, key, options): Promise` covering RFC 9052 §6.2 single-recipient MAC messages (CBOR tag 17). Wires HMAC-SHA-{256,384,512} via `@suaveplan/crypto-hash`. - ADDED: `src/cose/headers.ts` — `CoseHeader` map type, header-label registry covering RFC 9052 §3.1 (`alg`, `crit`, `content type`, `kid`, `IV`, `Partial IV`, `counter signature`). - New errors: `CBOR.COSE_SIG_INVALID`, `CBOR.COSE_AEAD_FAILED`, `CBOR.COSE_HEADER_INVALID`, `CBOR.COSE_RECIPIENT_NOT_FOUND`. ### CDDL (RFC 8610) parser + validator — `./cddl` subpath - ADDED: `src/cddl/lexer.ts` — RFC 8610 ABNF token stream (`identifier`, `=`, `/`, `//`, `*`, `+`, `?`, `..`, `&`, `~`, control operators `.size` `.bits` `.regexp` `.cbor` `.within` `.and` `.lt` `.le` `.gt` `.ge` `.eq` `.ne` `.default`, integer / text-string / byte-string / float literals, comments). - ADDED: `src/cddl/parser.ts` — `parseCddl(source): CddlAst` producing the typed AST per RFC 8610 §3 grammar (rules, types, groups, occurrence indicators, ranges, choices, control operators, generic parameters). - ADDED: `src/cddl/ast.ts` — `CddlAst`, `CddlRule`, `CddlType`, `CddlGroup`, `CddlOccurrence`, `CddlChoice`, `CddlControl`, `CddlGenericParam` discriminated unions. - ADDED: `src/cddl/validate.ts` — `validateCbor(value, schema, options): CddlValidationResult` walking a decoded CBOR value against a CDDL rule by name; emits a structured error path on mismatch (`{ path: (string | number)[], expected, got }`). - ADDED: `src/cddl/built-ins.ts` — RFC 8610 §3.8 prelude (`uint`, `nint`, `int`, `bstr`, `tstr`, `bool`, `nil`, `null`, `undefined`, `tdate`, `time`, `number`, `text`, `bytes`, `float`, `float16`, `float32`, `float64`, `any`). - ADDED: `src/cddl/control-ops.ts` — control-operator implementations (`.size` length bound, `.bits` set membership, `.regexp` pattern match, `.cbor` nested-CBOR bytes, `.within`, `.and`, comparison ops, `.default`). - ADDED: `src/cddl/cddl.types.ts` — option / result types, error path discriminator. - New errors: `CBOR.CDDL_PARSE_FAILED`, `CBOR.CDDL_VALIDATION_FAILED`, `CBOR.CDDL_RULE_NOT_FOUND`, `CBOR.CDDL_UNDEFINED_REFERENCE`. ### Partial-item streaming — extend `./streaming` subpath - ADDED: `src/streaming/chunk-decoder.ts` — `ChunkDecoder` for incremental decode of one CBOR item *larger than memory* over `AsyncIterable` / `ReadableStream`. Emits `{ kind: "string-chunk" | "bytes-chunk" | "array-start" | "array-end" | "map-start" | "map-end" | "tag" | "value" | "break" }` events as the underlying bytes flow in. Bounded memory regardless of item size. - ADDED: `src/streaming/chunk-decoder.types.ts` — `ChunkDecoderEvent` discriminated union, `ChunkDecoderOptions`. - New error: `CBOR.STREAM_INTERRUPTED` for mid-item disconnect. ## Source mapping This package is genesis-original; no `../suaveplan/enterprise/cbor.md` line range exists for any feature. Per maintainer instruction the source-of-record is the RFC itself. | Requirement | RFC source | Notes | |---|---|---| | Encoder for major types 0–7 with preferred-serialization shortest-form integers | RFC 8949 §3.1 + §4.2.1 | `unsigned`, `negative`, `byte-string`, `text-string`, `array`, `map`, `tag`, `simple/float` | | Indefinite-length arrays / maps / strings (opt-in) | RFC 8949 §3.2 | Disallowed when `deterministic: true`; throws `INDEFINITE_NOT_ALLOWED` | | Tagged items + built-in tag registry (0, 1, 2, 3, 21, 22, 23, 24, 32, 35, 55799) | RFC 8949 §3.4 + IANA CBOR Tags Registry | Each tag's semantics cited in sibling `.md`; tag 24 (encoded CBOR) re-enters the decoder | | Half-precision float encode (opt-in) + decode | RFC 8949 §3.3 (Major 7 / value 25) + §D | Binary16 IEEE-754; reference test vectors in §A | | Preferred serialization (shortest-form ints, no indefinite) | RFC 8949 §4.1 + §4.2.1 | Always-on; deterministic profile is a strict superset | | Deterministic encoding profile | RFC 8949 §4.2.1 + §4.2.2 | Sorted map keys via lexicographic comparison over canonical encoded key bytes | | dCBOR profile | draft-mcnally-deterministic-cbor (latest) §3 | Reduction rules for numeric values; prohibits `undefined` / generic simple values | | RFC 8742 CBOR Sequences encode + decode | RFC 8742 §2 + §3 | Concatenation of zero-or-more well-formed CBOR items; no enclosing array | | Decoder strict-mode well-formedness | RFC 8949 §5.1 | Includes "no extraneous bytes after item" (§5.1.2) and "all break stops have a matching indefinite start" | | Decoder lax mode | RFC 8949 §5.2 (basic validity) | Lax mode applies §5.2 only; strict mode adds §5.1 | | Streaming pull-decoder | RFC 8949 §3.2 + §5.1 | Bounded memory; consumer drives via `next()` | | Bounded recursion + bounded item count | RFC 8949 §1.2 (security considerations) + §10 | `maxDepth: 64` default → `NESTED_TOO_DEEP`; `maxItems: 1_000_000` default → `LENGTH_OVERFLOW` | | `decodeCoseKey` returning typed key union | RFC 9052 §7 + IANA COSE Key Common Parameters | Discriminator on `kty` (label 1) | | `coseKeyToJwk` / `jwkToCoseKey` round-trip | RFC 9052 §7.1 + RFC 8037 §2 + RFC 7518 §6 | EC2/OKP/RSA/symmetric round-trip | | COSE alg label → genesis algorithm ID | RFC 9053 §2 + IANA COSE Algorithms Registry | -7 ES256, -8 EdDSA, -35 ES384, -36 ES512, -257 RS256, …; rejects unknown labels | | Sig_structure / Enc_structure / MAC_structure builders | RFC 9052 §4.4 + §5.3 + §6.3 | Five contexts: `Signature`, `Signature1`, `CounterSignature`, `MAC`, `MAC0`; deterministic-encoded | | `COSE_Sign` / `COSE_Sign1` encode + decode + verify | RFC 9052 §4.1 + §4.2 + IANA CBOR Tags 98 / 18 | Wires ECDSA / EdDSA via `@suaveplan/crypto-curve` | | `COSE_Encrypt` / `COSE_Encrypt0` encode + decode + decrypt | RFC 9052 §5.1 + §5.2 + IANA CBOR Tags 96 / 16 | Wires AES-GCM / ChaCha20-Poly1305 via `@suaveplan/crypto-cipher` | | `COSE_Mac` / `COSE_Mac0` encode + decode + verify | RFC 9052 §6.1 + §6.2 + IANA CBOR Tags 97 / 17 | Wires HMAC-SHA-{256,384,512} via `@suaveplan/crypto-hash` | | COSE header registry (`alg`, `crit`, `content type`, `kid`, `IV`, `Partial IV`, `counter signature`) | RFC 9052 §3.1 + IANA COSE Header Parameters | Typed `CoseHeader` map; rejects malformed labels | | CWT claim labels (`iss`/`sub`/`aud`/`exp`/`nbf`/`iat`/`cti`) | RFC 8392 §3 + IANA CWT Claims | Typed `CwtClaims` discriminator; epoch tag round-trip | | CWT verify (signature + time window) | RFC 8392 §7 + RFC 9052 §4.2 / §6.2 | Delegates to `verifyCoseSign1` / `verifyCoseMac0`; `Clock` injected | | CDDL lexer + parser | RFC 8610 §3 ABNF grammar | Full prelude; control operators; generic params; comments | | CDDL validator with structured error path | RFC 8610 §3 + §3.8 prelude | `{ path, expected, got }` discriminator on mismatch | | CDDL control operators | RFC 8610 §3.8.1–3.8.16 | `.size`, `.bits`, `.regexp`, `.cbor`, `.within`, `.and`, comparisons, `.default` | | Partial-item streaming (`ChunkDecoder`) | RFC 8949 §3.2 (indefinite-length forms) | Event stream of `string-chunk` / `bytes-chunk` / container-start/end / break; bounded memory regardless of item size | | Diagnostic notation | RFC 8949 §8 | Debug-only emitter; never on hot path | ### Requirements with no source line | Requirement | Justification | |---|---| | `defineCodes("CBOR", [...])` 7-code registry | Genesis convention — every package surfaces typed errors via `@suaveplan/error`. The seven codes (`MALFORMED`, `UNEXPECTED_TYPE`, `UNKNOWN_TAG_STRICT`, `NESTED_TOO_DEEP`, `LENGTH_OVERFLOW`, `INDEFINITE_NOT_ALLOWED`, `NON_DETERMINISTIC`) each map to a distinct §5.1 / §10 failure class so callers can branch on root cause. | | Zod boundary schemas at every public option type | Genesis convention (CLAUDE.md §2 / §11). Catches caller misuse at the boundary; option misuse never silently degrades into malformed bytes. | | OTel surface (`cbor.encode_duration_ms`, `cbor.decode_duration_ms`, `cbor.tag_total`, `cbor.error_total`) | Genesis convention — every hot-path package emits histograms + counters. Tag attribute is bounded by IANA registry size; error code attribute is bounded by the 7-entry code registry. | | 300-line file budget + 100/100/100/100 coverage + sibling `.md` per impl file | CLAUDE.md global rules (Quality + Documentation sections). | | Property-based round-trip tests (fast-check) + deterministic-mode commutativity | CLAUDE.md "no mocks" rule; round-trip is the only test that proves encoder + decoder agree on the wire format under arbitrary structures. | | Mitata benchmarks under `src/__benchmarks__/` | CLAUDE.md global benchmark requirement. Baseline numbers feed the README perf table and a future CI regression gate. | | Tag-handler registry pluggability | Future consumer extensibility — `webauthn` may register WebAuthn-specific tags (e.g. AAGUID handling) without modifying this package. | ## Verification approach Each requirement carries a `**Verified by:**` line in the spec delta naming concrete `it(...)` titles inside the test files below. - `packages/vault/cbor/src/encoder/encoder.test.ts` — major types 0–7 encode, preferred-serialization shortest-form integers, simple-value encoding, float32 / float64 encode. - `packages/vault/cbor/src/encoder/encoder.spec-conformance.test.ts` — RFC 8949 Appendix A test vectors (every published vector produces the byte sequence in the appendix). - `packages/vault/cbor/src/encoder/indefinite.test.ts` — opt-in indefinite-length emission for arrays / maps / strings; rejected under `deterministic: true`. - `packages/vault/cbor/src/encoder/half-float.test.ts` — binary16 encode for normal, subnormal, ±0, ±Inf, NaN, smallest-normal, largest-normal. - `packages/vault/cbor/src/encoder/deterministic.test.ts` — sorted map keys; shortest-form ints; no indefinite-length output; throws `NON_DETERMINISTIC` when caller forces an indefinite item. - `packages/vault/cbor/src/encoder/dcbor.test.ts` — dCBOR reduction rules; rejects `undefined`; property-based commutativity. - `packages/vault/cbor/src/decoder/decoder.test.ts` — major types 0–7 decode; tagged-value materialization; `Tagged` for unknown tags; strict-mode rejects extraneous trailing bytes. - `packages/vault/cbor/src/decoder/decoder.spec-conformance.test.ts` — RFC 8949 Appendix A round-trip; §5.1 well-formedness rules; lax vs strict. - `packages/vault/cbor/src/decoder/well-formed.test.ts` — `isWellFormed` returns false for every §5.1 failure class. - `packages/vault/cbor/src/decoder/half-float.test.ts` — binary16 decode parity with reference encoder; subnormals; payload-preserving NaN. - `packages/vault/cbor/src/streaming/pull-decoder.test.ts` — pulls one item per `next()`; bounded memory under a 1 GiB sequence (test asserts heap delta upper bound); cancels on `signal.aborted`. - `packages/vault/cbor/src/sequences/sequences.test.ts` — RFC 8742 encode + decode; empty sequence; mixed-major-type sequence; partial-trailing-byte rejection in strict mode. - `packages/vault/cbor/src/tags/registry.test.ts` — register / lookup / unregister; double-register rejects; unknown tag in strict-fallthrough returns `Tagged`. - `packages/vault/cbor/src/tags/builtin.test.ts` — every built-in tag (0, 1, 2, 3, 21, 22, 23, 24, 32, 35, 55799) round-trips through the registry. - `packages/vault/cbor/src/cose/cose-key.test.ts` — RFC 9052 §7 sample EC2, OKP, RSA, symmetric keys decode to the typed union; `kty` discriminator works. - `packages/vault/cbor/src/cose/jwk.test.ts` — ES256 EC2 ↔ JWK round-trip; Ed25519 OKP ↔ JWK round-trip; RS256 RSA ↔ JWK round-trip (with `n`/`e` base64url encoding); symmetric key round-trip. - `packages/vault/cbor/src/cose/alg-map.test.ts` — every IANA-registered alg label this package supports maps to the right `@suaveplan/crypto-curve` ID; unknown label throws `UNEXPECTED_TYPE`. - `packages/vault/cbor/src/cose/sig-structure.test.ts` — RFC 9052 §4.4 vectors for all five contexts produce byte-identical canonical output. - `packages/vault/cbor/src/cose/sign1.test.ts` — RFC 9052 Appendix C.2 ES256 / EdDSA test vectors round-trip; tampered signature rejected with `COSE_SIG_INVALID`; tag-prefix and tagless inputs both supported. - `packages/vault/cbor/src/cose/sign.test.ts` — multi-signer encode + decode; per-signer header preserved; verify-any returns the matching signer index. - `packages/vault/cbor/src/cose/encrypt0.test.ts` — RFC 9052 Appendix C.3 AES-GCM-256 vector decrypts; tampered ciphertext rejected with `COSE_AEAD_FAILED`; ChaCha20-Poly1305 round-trip. - `packages/vault/cbor/src/cose/encrypt.test.ts` — multi-recipient encode + decode; per-recipient KEK lookup. - `packages/vault/cbor/src/cose/mac0.test.ts` — HMAC-SHA-256 / 384 / 512 round-trip; tampered MAC rejected. - `packages/vault/cbor/src/cose/mac.test.ts` — multi-recipient MAC round-trip. - `packages/vault/cbor/src/cose/headers.test.ts` — header label registry round-trip; malformed label rejected with `COSE_HEADER_INVALID`. - `packages/vault/cbor/src/cwt/claims.test.ts` — every IANA claim label round-trips; `Date` ↔ epoch via tag 1; private claims preserved. - `packages/vault/cbor/src/cwt/encode.test.ts` — deterministic claim-set encoding; canonical bytes stable across two runs. - `packages/vault/cbor/src/cwt/decode.test.ts` — RFC 8392 Appendix A vectors decode to typed claims. - `packages/vault/cbor/src/cwt/verify.test.ts` — `COSE_Sign1`-wrapped CWT verifies; expired token throws `CWT_EXPIRED`; `nbf` future throws `CWT_NOT_YET_VALID`; audience-mismatch throws `CWT_AUDIENCE_MISMATCH`. - `packages/vault/cbor/src/cddl/lexer.test.ts` — RFC 8610 §3 token-stream coverage including comments, control operators, ranges. - `packages/vault/cbor/src/cddl/parser.test.ts` — every grammar production from RFC 8610 §3; rejects malformed source with `CDDL_PARSE_FAILED` carrying line / column. - `packages/vault/cbor/src/cddl/validate.test.ts` — RFC 8610 Appendix examples (CWT schema, COSE_Sign schema) validate against real RFC vectors; mismatch surfaces `{ path, expected, got }`. - `packages/vault/cbor/src/cddl/built-ins.test.ts` — every prelude type accepts its conforming values and rejects non-conforming. - `packages/vault/cbor/src/cddl/control-ops.test.ts` — every control operator (`.size`, `.bits`, `.regexp`, `.cbor`, `.within`, `.and`, comparisons, `.default`) tested with conforming + non-conforming input. - `packages/vault/cbor/src/streaming/chunk-decoder.test.ts` — emits expected event sequence for an indefinite-length text-string in 3 chunks; bounded heap delta over a 10 GiB synthetic indefinite byte-string; aborts mid-item with `STREAM_INTERRUPTED`. - `packages/vault/cbor/src/diagnostic/diagnostic.test.ts` — RFC 8949 §8 sample diagnostic strings emit byte-identical output. - `packages/vault/cbor/src/errors/error-codes.test.ts` — every code in the registry is thrown by ≥1 production code path; `expectTypeOf().toEqualTypeOf<…>()` pins the literal union. - `packages/vault/cbor/src/observability/metrics.test.ts` — encode/decode histograms record under a real in-memory `MeterProvider`; `cbor.tag_total{tag}` increments per decoded tag; `cbor.error_total{code}` increments on every thrown `CborError`. - `packages/vault/cbor/src/schemas/schemas.test.ts` — every Zod schema rejects malformed options with the genesis boundary error. - `packages/vault/cbor/src/encoder/property.test.ts` — fast-check round-trip: arbitrary `JsonValue`-like structures encode → decode → byte-identical. - `packages/vault/cbor/src/encoder/deterministic-property.test.ts` — fast-check: deterministic encoder emits byte-identical output across two runs on shuffled-key maps. - `packages/vault/cbor/src/index.test.ts` — every documented subpath export resolves. ## Migration impact None — additive only; this is the first delta of a new package. No existing code in genesis imports from `@suaveplan/cbor`. `@suaveplan/webauthn` is the gating consumer and lands in a follow-up change once this package archives; that change will add the dep edge and migrate `webauthn`'s CTAP2 / attestation parsers off any external CBOR placeholder. ## Impact ### Affected dependents `bunx turbo ls --filter=...@suaveplan/cbor` returns no current dependents (the package does not yet exist on `genesis`). The pending consumer is: - `@suaveplan/webauthn` — [ ] tests run / [ ] docs reviewed / [x] no action needed in THIS change (reason: webauthn is itself pending migration; consumer wiring lands in the webauthn migration change once that proposal is opened, per `STATUS.md`). No foundation-package fan-out applies (this is a new universal-tier leaf package; foundation deps `@suaveplan/error` and `@suaveplan/types` are unchanged).