Files
2026-05-27 23:29:53 +01:00

8.3 KiB

Enterprise hardening — @suaveplan/packer extensibility cluster

Package: @suaveplan/packer Status: PROPOSED Type: feature Design: (inline below — scope is well-bounded by the 5-item brief) Spec delta: ./specs/packer/spec.md

Why

Cluster #1 (enterprise-packer-integrity, archived 2026-05-19) landed BLAKE3 content-addressable digests, the bundle-level Merkle root, mandatory integrity verification on unpack, full OpenTelemetry instrumentation, and i18n-keyed error messages. Cluster #2 (enterprise-packer-resilience, archived 2026-05-19) added retry, idempotency, whole-file AbortSignal, and Clock / Rng injection.

This is the third and final cluster, addressing the remaining enterprise/packer.md audit gaps (L41, L42, L48, L72, L75):

  1. No @suaveplan/schema-registry integration — the Zod option schemas exist in src/schemas/packer.schemas.ts but are not registered with the canonical versioned registry, and the chunk-format version byte has no companion registry entry that records V1 as the shipping format and reserves the path to V2.
  2. No @suaveplan/feature-flags rollout surface — the audit calls for "Feature flags via @suaveplan/feature-flags for format-version rollouts" (L48); today the package writes V1 unconditionally and has no rollout path for a future V2 wire format.
  3. No plugin / extension surface — the audit calls for "A plugin / extension interface (where it makes sense) so downstream packages can contribute behaviour without forking" (L72). Today the packer is closed: every transform, integrity strategy, and codec is hard-wired.
  4. No fast-check property tests — the audit calls for "Property-based tests (fast-check) for pack/unpack round-trips and streaming- equivalence-to-batch invariants" (L42).
  5. No mitata benchmark suite — the audit calls for "Performance — benchmark suite in src/__benchmarks__, published numbers in the README, regression gate in CI" (L75).

After this cluster lands, @suaveplan/packer meets every checkbox in the enterprise/packer.md §3 + §4 + §6 acceptance criteria.

What changes

  • ADDED: src/schemas/registration.ts — registers every Zod schema in src/schemas/packer.schemas.ts plus a packer-chunk-format subject with V1 as the shipping wire-format version under a BACKWARD compatibility policy. getPackerSchemaRegistry() returns the process-singleton registry; registerPackerSchemas(registry) performs the registration against any caller-supplied SchemaRegistry.
  • ADDED: @suaveplan/schema-registry as a runtime dependency.
  • ADDED: src/flags/flags.ts — PackerFeatureFlags provider interface and defaultPackerFlags() no-op provider that returns the V1 default for every flag. resolvePackerFlags(opts) adapts a caller-supplied @suaveplan/feature-flags Evaluator or a raw provider into the internal PackerFeatureFlags shape.
  • ADDED: flags?: PackerFlagsOptions on PackerOptions. The write path now reads packer.format.v2 from the resolved provider — when enabled, Packer.pack throws PackerError(PACKER.FORMAT_VERSION_UNSUPPORTED) with the catalog message packer.error.FORMAT_VERSION_UNSUPPORTED.v2-not-implemented (versioning gate — V2 is a future change, not a deferral).
  • ADDED: @suaveplan/feature-flags as a runtime dependency.
  • ADDED: src/plugins/plugins.ts — PackerPlugin contract, six lifecycle hooks (onPackStart, onEntry, onPackEnd, onUnpackStart, onEntryDecoded, onUnpackEnd), order-deterministic invocation via PluginPipeline.runHook(name, ctx). Plugin errors surface as PackerError(PACKER.PLUGIN_FAILED).
  • ADDED: plugins?: ReadonlyArray<PackerPlugin> on PackerOptions. Packer.pack and Unpacker.unpack invoke every registered plugin's hooks in declaration order.
  • ADDED: PACKER.FORMAT_VERSION_UNSUPPORTED and PACKER.PLUGIN_FAILED error codes in error-codes.ts.
  • ADDED: src/__property__/round-trip.property.test.ts and src/__property__/determinism.property.test.ts — fast-check property-based round-trip, streaming↔batch equivalence, determinism.
  • ADDED: src/__benchmarks__/packer.bench.ts — mitata benchmark suite covering whole-file pack/unpack, chunked pack (single + 1000 chunks), integrity verify, plugin overhead. bun run benchmark script in package.json and a Benchmarks section in README.md.
  • ADDED: mitata as a devDependency (already present in the root catalog as catalog:testing).
  • MODIFIED: src/index.ts — exports getPackerSchemaRegistry, registerPackerSchemas, PackerPlugin, defaultPackerFlags, resolvePackerFlags, and the plugin / flags / registration types.

Out of scope

  • V2 wire format implementation — this cluster lands the registry entry and the feature-flag gate; the V2 codec is a follow-up change that flips the throw into real encoding work. The throw is the spec contract for V2-not-implemented; not a deferral.
  • Mutation testing — orthogonal to the audit; opens a follow-up.
  • Codemod for breaking option changes — there are none in this cluster.

Source mapping

This change derives from ../suaveplan/enterprise/packer.md.

Requirement Source lines Notes
PACKER-26 (@suaveplan/schema-registry integration) L41 Verbatim — "Zod schemas … @suaveplan/schema-registry integration, versioned evolution with explicit format-version bytes".
PACKER-27 (@suaveplan/feature-flags rollouts) L48, L79 Verbatim — "Feature flags via @suaveplan/feature-flags for format-version rollouts" / "Feature flags for any risky new behaviour".
PACKER-28 (plugin / extension interface) L72 Verbatim — "A plugin / extension interface (where it makes sense) so downstream packages can contribute behaviour without forking".
PACKER-29 (fast-check property tests) L42 Verbatim — "Property-based tests (fast-check) for pack/unpack round-trips and streaming-equivalence-to-batch invariants".
PACKER-30 (mitata benchmark suite) L75 Verbatim — "Performance — benchmark suite in src/__benchmarks__, published numbers in the README, regression gate in CI".

Requirements with no source line

None — every requirement maps directly to an audit bullet.

Verification approach

  • src/schemas/registration.test.ts + .spec-conformance.test.ts — pins registry contents, V1 evolution metadata, BACKWARD compatibility on subject reuse.
  • src/flags/flags.test.ts + .spec-conformance.test.ts — pins default no-op provider, custom evaluator wiring, V2 throw path.
  • src/plugins/plugins.test.ts + .spec-conformance.test.ts — pins hook ordering, error surface, downstream plugin example (noop logger
    • double-integrity SHA-256 sidecar).
  • src/__property__/round-trip.property.test.ts — pack→unpack identity
    • streaming↔batch equivalence under arbitrary inputs.
  • src/__property__/determinism.property.test.ts — deterministic output under seeded Rng + fixed Clock.
  • src/__benchmarks__/packer.bench.ts — runnable via bun run benchmark; baseline numbers published in README.md.

Migration impact

Public-surface additions only. No existing signature changes shape — the new options are all optional with platform defaults. Two consumer packages (@suaveplan/drive-plugin-chunks, @suaveplan/drive-webrtc) are audited and the sweep is part of the gates; no existing call site changes shape.

Impact

Affected dependents

Run bunx turbo ls --filter=...@suaveplan/packer to enumerate.

  • @suaveplan/drive-plugin-chunks — [x] tests run / [x] docs reviewed / [ ] no action needed
  • @suaveplan/drive-webrtc — [x] tests run / [x] docs reviewed / [ ] no action needed

If tests run is unchecked for any dependent, the change MUST NOT be folded into the canonical spec.

Migration

No behavioral change for callers that did not pass the new options. Existing calls keep their previous semantics:

  • No plugins passed: no hooks fire; behaviour identical to cluster #2.
  • No flags passed: defaultPackerFlags() is used; every flag returns the V1 default and Packer.pack writes the V1 format.
  • No registry interaction needed: callers that did not use @suaveplan/schema-registry before do not need to start now — registration is a process-singleton side effect available on demand.