# restore-crypto-cleanup-duplicates — remove primitive duplicates from `@suaveplan/crypto` **Packages:** `@suaveplan/crypto`, `@suaveplan/crypto-core` **Status:** PROPOSED **Type:** refactor (no behaviour change; no public surface change) **Carved from:** `restore-crypto-keychain-packer` umbrella (2026-05-03) ## Why When the genesis crypto stack was sliced into `@suaveplan/crypto-core` (primitives) and `@suaveplan/crypto` (opinionated layer), the primitive implementations were duplicated rather than re-exported. Today `crypto/src/` holds 46 files of `aead/`, `agree/`, `auth-box/`, `sealed-box/`, `sign/`, `primitives/`, and `engines/` that are exact copies of the same modules in `crypto-core/src/`. This blocks the import-allowlist conformance gate (slice 4): the gate's purpose is to mechanically prevent consumers from reaching past `@suaveplan/crypto` into the primitive layer. With duplicate implementations sitting inside `crypto/src/`, the gate would either flag self-imports or accept what it should reject. Cleanup must come first. The fix is mechanical: delete the duplicate files, replace each previously-published export with a typed re-export from `@suaveplan/crypto-core`. The public surface of `@suaveplan/crypto` does not change — every symbol that was importable yesterday is importable today, just sourced from one place. ## What changes ### Removed (from `@suaveplan/crypto/src/`) - `aead/` — 5 files (delete) - `agree/` — 6 files (delete) - `auth-box/` — 5 files (delete) - `sealed-box/` — 5 files (delete) - `sign/` — 9 files (delete) - `primitives/` — 10 files (delete) - `engines/` — 6 files (delete) Total: 46 source files removed. ### Modified - `@suaveplan/crypto/src/index.ts` — every primitive-surface symbol becomes a typed re-export from `@suaveplan/crypto-core` (e.g. `export { aead, ed25519, x25519, sealedBox, authBox, ... } from "@suaveplan/crypto-core"`). - `@suaveplan/crypto/package.json` — remove `@suaveplan/crypto-cipher`, `@suaveplan/crypto-curve`, `@suaveplan/crypto-hash`, `@suaveplan/crypto-utils` from direct deps if they are only used by the duplicated files (they will be transitively available via `crypto-core`). Keep them only if the opinionated modules (`keychain`, `derivation`, `bundles`, `domain-tags`, `authority`) genuinely import them directly. ### Preserved (inside `@suaveplan/crypto/src/`) - `authority/` — 3 files - `bundles/` — 7 files - `derivation/` — 10 files - `domain-tags/` — 3 files - `keychain/` — 12 files - `errors/` — 6 files - `constants/` — N/A - `index.ts` (rewritten) ## Out of scope - Folding `crypto-keys` and `crypto-vault` into `crypto` — slice 2. - Building the missing modules (`packer`, `chunked-packer`, `vault`, `revocation`, `audit-log`, `identity`, `wire-format`) — slice 3. - The import-allowlist conformance gate — slice 4 (this slice unblocks it). - `crypto-cli`, `slsa` migration — slice 4. ## Source mapping | Requirement | Source | Notes | |---|---|---| | Remove duplicates; re-export from `crypto-core` | `restore-crypto-keychain-packer` umbrella, "Why" | Above-baseline genesis slice plan | | Public surface byte-identical after change | Genesis policy (CLAUDE.md §Workflow rule 5) | Preserve full public surface during rewrites | ## Verification approach - `bunx turbo build --filter=@suaveplan/crypto` produces a `dist/index.d.ts` whose public symbol set is byte-identical to the pre-change snapshot (committed at `tests/before.dts.txt`); diff is zero lines. - `bunx turbo lint typecheck test --filter=@suaveplan/crypto` green. - `bunx turbo test:coverage --filter=@suaveplan/crypto` still 100/100/100/100 over the *retained* opinionated modules (the deleted modules' coverage now sits in `crypto-core`). - Every existing in-monorepo consumer of `@suaveplan/crypto` still compiles and tests green (`...@suaveplan/crypto` dependent sweep). ## Migration impact None. Public surface unchanged. No consumer needs to update an import.