Files
suaveplan/openspec/archive/2026-04-19-enterprise-serialize/tasks.md
2026-05-27 23:29:53 +01:00

7.1 KiB

Archived 2026-04-19: all tasks retroactively ticked; package shipped under universal/primitives/serialize.

Tasks: enterprise-serialize

1. Scaffold

  • 1.1 Create packages/universal/serialize/ with package.json, tsconfig.json, tsconfig.lib.json, vite.config.ts, vitest.config.ts, README.md skeleton
  • 1.2 Register coverage thresholds at 100/100/100/100 in vitest.config.ts; provider = istanbul
  • 1.3 Add cross-cutting guard tests in tests/: dep-graph, no-disallowed, tree-shake
  • 1.4 Add serialization catalog group to root package.json: { "@msgpack/msgpack": "^3.0.0", "serialize-javascript": "^6.0.0" }
  • 1.5 Add package to root CLAUDE.md, README.md, and STRUCTURE.yml
  • 1.6 Configure subpath exports in package.json: "." (main) and "./unsafe" (eval-safe adapter)

2. Errors

  • 2.1 Implement src/errors/serialize-error.ts — SerializationError extends SuaveplanError
  • 2.2 Implement subclasses: CircularReferenceError, MaxDepthExceededError, MaxSizeExceededError, UnsupportedTypeError
  • 2.3 defineCodes for: SERIALIZE.CODEC.CIRCULAR_REFERENCE, SERIALIZE.CODEC.MAX_DEPTH, SERIALIZE.CODEC.MAX_SIZE, SERIALIZE.CODEC.UNKNOWN_TAG, SERIALIZE.REGISTRY.DUPLICATE_TAG, SERIALIZE.LEGACY.REFUSED
  • 2.4 Export SerializationErrorCode, SerializationErrorContext, SerializationErrorOptions
  • 2.5 Implement src/error-codes.ts — registerSerializeErrorCodes(), SERIALIZE_ERROR_METADATA, SerializeErrorCode (re-exported from main entry)
  • 2.6 Tests for all error subclasses, code narrowing, walkCauses

3. Type registry

  • 3.1 Implement src/registry/registry.ts — registerType(def), unregisterType(tag), listTypes(), getType(tag), getTypeByCtor(ctor)
  • 3.2 Implement src/registry/registry.types.ts — TypeDefinition
  • 3.3 Pre-register built-in types: Date, Map, Set, BigInt, Uint8Array, Int8Array, Int16Array, Int32Array, Uint16Array, Uint32Array, Float32Array, Float64Array, URL, RegExp
  • 3.4 Throw SERIALIZE.REGISTRY.DUPLICATE_TAG on duplicate registration
  • 3.5 Unit tests: register/unregister, getType, getTypeByCtor, duplicate error, list
  • 3.6 Co-located src/registry/registry.md

4. Tagged-JSON codec

  • 4.1 Implement src/codec/json/json-encode.ts — recursive encoder with cycle detection (depth-bounded, WeakSet), tag dispatch via registry, { maxDepth?, maxSize?, signal? } options
  • 4.2 Implement src/codec/json/json-decode.ts — tag parser, reconstruction via registry decode
  • 4.3 Wire as serialize(value, opts?) → string and deserialize(json, opts?) → unknown
  • 4.4 Honour AbortSignal (check every 256 nodes)
  • 4.5 deepClone implemented via deserialize(serialize(value))
  • 4.6 Unit tests: every built-in type round-trips; nested; circular → error; max-depth → error; max-size → error; unknown tag → error
  • 4.7 Co-located src/codec/json/json-encode.md and json-decode.md

5. MessagePack binary codec

  • 5.1 Implement src/codec/msgpack/msgpack-encode.ts — wraps @msgpack/msgpack with registry tag dispatch; produces bit-identical output for identical inputs (sorted keys)
  • 5.2 Implement src/codec/msgpack/msgpack-decode.ts — paired decoder
  • 5.3 Wire as encodeBinary(value, opts?) → Uint8Array and decodeBinary(bytes, opts?) → unknown
  • 5.4 Unit tests: every built-in type; binary round-trip; structural equivalence with JSON codec output
  • 5.5 Co-located src/codec/msgpack/msgpack-encode.md and msgpack-decode.md

6. Streaming codec

  • 6.1 Implement src/codec/stream/stream-encode.ts — encodeStream(value, opts?) → ReadableStream<Uint8Array> via Web Streams API; chunks by MessagePack frame
  • 6.2 Implement src/codec/stream/stream-decode.ts — decodeStream(stream, opts?) → ReadableStream<unknown>; reassembles frames
  • 6.3 Honour AbortSignal in both directions
  • 6.4 Unit tests: small value → single chunk; large value → multiple chunks; stream cancel
  • 6.5 Co-located src/codec/stream/stream.md

7. Codec index + Codec type

  • 7.1 Implement src/codec/index.ts — re-exports serialize, deserialize, encodeBinary, decodeBinary, encodeStream, decodeStream, deepClone, SerializeOptions, DeserializeOptions, Codec
  • 7.2 Codec type: { serialize, deserialize, encodeBinary, decodeBinary }

8. Legacy adapters (main export)

  • 8.1 Implement src/legacy/legacy.ts — legacySerialize(value) and legacyDeserialize(json) — old format with no new tags; for migration only; emit dev-mode console warning
  • 8.2 Tests: old-format strings deserialize correctly; round-trip matches
  • 8.3 Co-located src/legacy/legacy.md

9. Unsafe subpath (/unsafe)

  • 9.1 Implement src/adapters/eval-safe/eval-safe.ts — serializeEvalSafe, deserializeEvalSafe using serialize-javascript; emits security warning on first call in dev mode
  • 9.2 Implement src/adapters/index.ts — re-exports eval-safe adapter
  • 9.3 Configure "./unsafe" subpath export in package.json pointing to the adapters build
  • 9.4 Verify main bundle does NOT import serialize-javascript (tree-shake test)
  • 9.5 Tests for eval-safe round-trip, security warning emission, isolation from main bundle
  • 9.6 Co-located src/adapters/eval-safe/eval-safe.md with prominent security callout

10. OTel instrumentation

  • 10.1 Histogram serialize.payload_bytes (by format label: json / msgpack)
  • 10.2 Counter serialize.error.total (by error code label)
  • 10.3 No-op without exporter (tested)

11. Property-based tests (fast-check)

  • 11.1 deserialize(serialize(x)) deep-equals x for every built-in type
  • 11.2 decodeBinary(encodeBinary(x)) deep-equals x
  • 11.3 JSON ↔ msgpack structural equivalence for all built-in types
  • 11.4 Any circular graph always throws CircularReferenceError
  • 11.5 Custom tag: registered → encode/decode round-trip; unregistered input → UnsupportedTypeError

12. Benchmarks

  • 12.1 src/__benchmarks__/json.bench.ts — serialize / deserialize 10 KB nested object (mitata)
  • 12.2 src/__benchmarks__/msgpack.bench.ts — encodeBinary / decodeBinary 10 KB nested object
  • 12.3 src/__benchmarks__/clone.bench.ts — deepClone vs structuredClone baseline
  • 12.4 Publish baseline numbers in README

13. Docs

  • 13.1 Co-located .md for every implementation file (≥200 words, examples, API reference)
  • 13.2 Rewrite README.md with public API, design rationale, tag format spec, consumer guide, security section for /unsafe
  • 13.3 bun run docs:check --filter=@suaveplan/serialize ≥ 90%

14. Verify and publish

  • 14.1 bunx turbo lint typecheck test --filter=@suaveplan/serialize green
  • 14.2 bunx turbo test:coverage --filter=@suaveplan/serialize at 100/100/100/100
  • 14.3 bunx turbo build --filter=@suaveplan/serialize green
  • 14.4 bun scripts/publish.ts --package @suaveplan/serialize to Verdaccio at 0.0.0
  • 14.5 Archive OpenSpec change to openspec/archive/2026-04-18-enterprise-serialize/