6.9 KiB
Capability Spec Delta: bitpacker-crypto (bitpacker-crypto-port, Option A)
Package: @suaveplan/bitpacker-crypto
Status: PROPOSED — gated on Option A acceptance in proposal.md
Every requirement below carries a
**Verified by:**line at authoring time. Option A is a deliberate scope-down: the only behavior contract this change adds is "the upstream provider abstraction is intentionally not part of@suaveplan/bitpacker-crypto." The tests that pin this contract live next to the package source.
ADDED Requirements
Requirement: Decision record exists in-tree
The package SHALL ship a SUPERSEDED.md file at the package root documenting (i) every upstream symbol intentionally not ported, (ii) the upstream file and line range it came from, (iii) the genesis replacement (a concrete @suaveplan/* package and export), and (iv) the rationale. The file SHALL be at least 200 words and SHALL include one runnable example showing how a caller wanting "encrypt then pack" achieves it via @suaveplan/packer + @suaveplan/crypto.
Scenario: SUPERSEDED.md is present and well-formed
- WHEN the file
packages/bitpacker/bitpacker-crypto/SUPERSEDED.mdis read - THEN it exists, is at least 200 words excluding code blocks, contains a section per upstream symbol listed in
proposal.mdsource mapping, and contains at least one fenced code block whose first line begins withimportfrom@suaveplan/
Scenario: every parity-table row has a SUPERSEDED.md section
- WHEN the parity-table rows in
bitpacker-modular-restructure/proposal.mdflagged "⛔ intentionally superseded; seebitpacker-crypto-port" are enumerated (5 rows) - THEN each row has a corresponding section header in
SUPERSEDED.mdand the section names the same upstream file the parity-table row referenced
Verified by: packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"SUPERSEDED.md exists and is well-formed" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"every parity-table row maps to a SUPERSEDED.md section"
Requirement: Upstream provider symbols are NOT exported
The package SHALL NOT export any of the following symbols by these exact names: BaseCryptoProvider, CryptoRegistry, LibsodiumCryptoProvider, EllipticCryptoProvider, NoOpCryptoProvider, generateNonce, concatBytes, validateKeyLength, constantTimeEqual, secureWipe, createCryptoRegistry, getGlobalRegistry, createXChaCha20Provider, createAesGcmProvider, createSecp256k1Provider, createEd25519Provider, createP256Provider, createTestProvider, createSlowProvider, createUnreliableProvider. Any future re-introduction of these names SHALL constitute a deliberate spec change reverting this decision.
Scenario: rejected symbol cannot be imported
- WHEN a TypeScript consumer writes
import { BaseCryptoProvider } from "@suaveplan/bitpacker-crypto"; - THEN the import fails to resolve at typecheck time
Scenario: every rejected symbol pinned by an it
- WHEN
SUPERSEDED.test.tsruns - THEN there is exactly one
it(...)per name in the list above and each asserts the runtime export isundefined
Scenario: parity-table rows show ⛔ status
- WHEN the parity table in
bitpacker-modular-restructure/proposal.mdis read after this change archives - THEN the five rows for
Crypto provider,Crypto registry,Crypto adapter — noop,Crypto adapter — libsodium,Crypto adapter — ellipticshow "⛔ intentionally superseded; seebitpacker-crypto-port" with no remaining 🚫 marker
Verified by: packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"BaseCryptoProvider is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"CryptoRegistry is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"LibsodiumCryptoProvider is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"EllipticCryptoProvider is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"NoOpCryptoProvider is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"generateNonce is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"concatBytes is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"validateKeyLength is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"constantTimeEqual is not a runtime export" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"secureWipe is not a runtime export"
Requirement: README routes future callers to the genesis crypto family
The package's README.md SHALL contain a "Crypto provider needs?" section that names the genesis replacement packages (@suaveplan/crypto, @suaveplan/crypto-sodium, @suaveplan/crypto-browser, @suaveplan/crypto-vault, @suaveplan/packer) and links to each. The section SHALL be ≤120 words and SHALL NOT document the rejected upstream API.
Scenario: README routing section is present
- WHEN
packages/bitpacker/bitpacker-crypto/README.mdis read - THEN it contains a level-2 heading
## Crypto provider needs?and the body names every package listed above with a markdown link
Scenario: README does not document the rejected API
- WHEN the README is grepped for
BaseCryptoProvider,CryptoRegistry, orLibsodiumCryptoProvider - THEN there are zero matches outside of the link to
SUPERSEDED.md
Verified by: packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"README has Crypto provider needs section linking the replacement packages" AND packages/bitpacker/bitpacker-crypto/SUPERSEDED.test.ts::"README does not document the rejected upstream API"
REMOVED Requirements
Requirement: Provider abstraction port from upstream bitpacker/src/crypto/
Reason: Upstream's BaseCryptoProvider / CryptoRegistry / three adapters (libsodium, elliptic, noop) are a self-referential abstraction layer over @suaveplan/crypto. No upstream consumer outside the bitpacker package itself imports any of them (verified 2026-05-02 by grep across /mnt/s/web/suaveplan/packages). Genesis already ships every underlying primitive in five focused packages (@suaveplan/crypto, crypto-sodium, crypto-browser, crypto-vault, crypto-keys) plus a higher-level chunked AEAD in @suaveplan/packer. Re-adding the abstraction would duplicate that work, conflict with the genesis structured-error / OTel conventions, and contradict the "no duplicate libraries" directive in CLAUDE.md.
Migration: Future bitpacker callers should reach for the genesis crypto family directly. See SUPERSEDED.md for the per-symbol replacement table and an "encrypt-then-pack" example using @suaveplan/packer + @suaveplan/crypto.