6.2 KiB
Capability Spec Delta: bitpacker (bitpacker-hardening)
Package: @suaveplan/bitpacker and the bitpacker family
Status: PROPOSED
Every requirement carries a
**Verified by:**line. All requirements are above-baseline genesis-policy additions; there is no upstream source for them. Every requirement is additive instrumentation or test infrastructure with no behaviour change.
ADDED Requirements
Requirement: Public types are Zod-validated at package boundaries
Every package in the bitpacker family SHALL expose a Zod schema for each public input type and SHALL validate untrusted inputs at the package boundary (the entry method that accepts a value from outside the package). Internal recursion MUST NOT re-validate.
Scenario: invalid input rejected at boundary
- WHEN a caller passes a value that does not match the boundary's Zod schema
- THEN the package throws a
BitpackerErrorwhosecauseis the Zod error and whose code isINVALID_SCHEMA
Scenario: internal recursion does not re-validate
- WHEN the strategy chain recurses into a sub-schema that has already been validated at the entry boundary
- THEN no Zod schema is parsed during the recursion (verified by spying on the schema parser's call count)
Verified by: packages/bitpacker/<each-pkg>/tests/zod-boundary.test.ts::"throws BitpackerError with INVALID_SCHEMA on bad input" AND ::"does not re-validate during internal recursion"
Requirement: Public schemas registered with schema-registry
Every package in the bitpacker family SHALL register its public Zod schemas with @suaveplan/schema-registry under namespace "bitpacker", with the package name as the schema name and version: 1.
Scenario: schemas present after import
- WHEN a consumer imports the package's
register-schemassubpath - THEN
schemaRegistry.get("bitpacker", "<pkg-name>", 1)returns a populated entry
Verified by: packages/bitpacker/<each-pkg>/tests/registered.test.ts::"registers schemas under namespace 'bitpacker'"
Requirement: OTel spans emitted at hot-path boundaries
Every package in the bitpacker family SHALL emit one OTel span per top-level pack/unpack call, named suaveplan.bitpacker.<pkg>.<operation>. Per-chunk events MUST be nested span events, not standalone spans.
Scenario: span emitted on pack
- WHEN a consumer calls a top-level pack/unpack method
- THEN exactly one span is emitted with the canonical name and attributes
{schema.kind, byte.count, success}
Verified by: packages/bitpacker/<each-pkg>/tests/otel.test.ts::"emits one span per top-level pack/unpack call"
Requirement: fast-check property tests cover round-trip soundness
Every package that exposes a pack/unpack pair SHALL ship a tests/property/*.property.test.ts file using fast-check to assert that for every value matching the schema's arbitrary, unpack(pack(v)) ≡ v.
Scenario: round-trip property holds for every public schema kind
- WHEN a fast-check arbitrary generates 100 values for a schema kind
- THEN every generated value round-trips byte-identically
Verified by: packages/bitpacker/<each-pkg>/tests/property/round-trip.property.test.ts::"round-trip is identity for <kind>"
Requirement: mitata benchmarks have committed baselines and CI gate
Every package that exposes a public encoder/decoder SHALL ship a bench/*.bench.ts file using mitata, with baseline timings committed to scripts/bench/bitpacker-baselines.json. CI SHALL fail the bench:check task if any benchmark regresses by more than 10% from the committed baseline.
Scenario: regression caught by CI gate
- WHEN a code change makes a benchmarked operation 11%+ slower than its committed baseline
- THEN
bunx turbo bench:checkexits non-zero with the regressed operation's name and percentage
Verified by: scripts/bench/check-baselines.test.ts::"flags regressions over 10%"
Requirement: _version strategy supports opt-in forward tolerance
The VersionPackingStrategy in @suaveplan/bitpacker-strategies SHALL accept an optional _tolerance: "strict" | "forward" field on the version-schema shape. When _tolerance is absent or "strict", the strategy SHALL throw BitpackerError(INVALID_SCHEMA) on any wire-version mismatch (current behaviour). When _tolerance: "forward" is set and the schema also carries an _allowedVersions: number[], the strategy SHALL accept any wire version listed in that array and proceed with the schema's _schema field for decoding. When _tolerance: "forward" is set without _allowedVersions, the strategy SHALL accept any wire version >= 0 and proceed with _schema. The on-wire byte format is unchanged: a 16-bit unsigned big-endian version followed by the schema-encoded payload.
Scenario: strict mode rejects mismatched wire version
- WHEN a consumer unpacks bytes whose wire version differs from the schema's
_versionand_toleranceis absent or"strict" - THEN the strategy throws
BitpackerError(INVALID_SCHEMA)with the expected and received versions in the error context
Scenario: forward-tolerant mode accepts a listed version
- WHEN a consumer unpacks bytes whose wire version is listed in
_allowedVersionsand_tolerance: "forward"is set - THEN the strategy decodes the payload via
_schemawithout throwing
Scenario: forward-tolerant mode without allowlist accepts any version
- WHEN a consumer unpacks bytes with
_tolerance: "forward"and no_allowedVersionsfield - THEN the strategy decodes any wire version >= 0 via
_schema
Scenario: forward-tolerant mode rejects a version outside the allowlist
- WHEN a consumer unpacks bytes whose wire version is NOT in the supplied
_allowedVersions, with_tolerance: "forward" - THEN the strategy throws
BitpackerError(INVALID_SCHEMA)with the expected version, the received version, and the allowed-versions list in the error context
Verified by: packages/bitpacker/bitpacker-strategies/src/strategies/version/version.test.ts::"throws on strict mismatch" AND ::"accepts a listed version when _tolerance: forward" AND ::"accepts any version when _tolerance: forward without allowlist" AND ::"rejects an unlisted version under _tolerance: forward"