110 lines
5.8 KiB
Markdown
110 lines
5.8 KiB
Markdown
# OpenSpec Change: unify-rng-across-packages
|
|
|
|
- **Change ID**: unify-rng-across-packages
|
|
- **Package**: `@suaveplan/types` (canonical) + downstream consumers
|
|
- **Design**: ./design.md
|
|
- **Spec delta**: ./specs/types/spec.md
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-05-17
|
|
|
|
## Why
|
|
|
|
The 2026-04-27 `types-contract-tightening` change widened the canonical `Rng`
|
|
interface in `@suaveplan/types` (adding optional `nextBytes` and
|
|
`nextIntInRange` members) and explicitly **deferred** migration of the
|
|
packages that were redefining `Rng`-shaped interfaces locally
|
|
(`crypto-core`, `cache`, `idempotency`). That deferral has lapsed: every
|
|
fresh package author who needs randomness still has to choose between
|
|
importing the canonical `Rng` or hand-rolling a local one, and the existing
|
|
local redefinitions silently fork the contract.
|
|
|
|
This change closes the loop. It migrates every genesis package with a local
|
|
`Rng` type to consume the canonical `Rng` from `@suaveplan/types`, leaving
|
|
deprecated aliases in place for one release cycle so consumers can update at
|
|
their own pace.
|
|
|
|
## What changes
|
|
|
|
For each affected genesis package, the source files that currently declare a
|
|
local `Rng` interface are migrated to:
|
|
|
|
1. Import the canonical `Rng` from `@suaveplan/types`.
|
|
2. Re-export the canonical `Rng` from the original module path under the
|
|
original name, with a "Backwards-compatibility alias for `@suaveplan/types`
|
|
`Rng`" prose comment (per CLAUDE.md §2 — no `@deprecated` JSDoc).
|
|
3. Add `@suaveplan/types` as a `workspace:^` dependency where missing.
|
|
4. Re-run `bunx turbo typecheck` and `bunx turbo test` to confirm zero
|
|
runtime / behavioural change.
|
|
|
|
The spec delta is a `## MODIFIED Requirements` block on the existing
|
|
`Rng has optional bounded operations` requirement in `openspec/specs/types/`
|
|
that adds an explicit single-source-of-truth clause: no other `@suaveplan/*`
|
|
package may declare its own `Rng` interface; downstream packages that need a
|
|
narrower or wider random-source shape MUST either consume `Rng` directly or
|
|
define a sub-interface that `extends` it.
|
|
|
|
## Impact
|
|
|
|
### Affected dependents
|
|
|
|
Run `bunx turbo ls --filter=...@suaveplan/types` to enumerate. Packages that
|
|
currently declare a local `Rng` type (surveyed via
|
|
`grep -rln "interface Rng\b\|type Rng = " packages/`) are:
|
|
|
|
- `@suaveplan/crypto-core` — [x] tests run / [x] docs reviewed / [ ] no action needed
|
|
(declares `type Rng = ByteSource` as a back-compat alias in
|
|
`src/primitives/random-bytes/random-bytes.ts`)
|
|
- `@suaveplan/crypto` — [x] tests run / [x] docs reviewed / [ ] no action needed
|
|
(re-exports the alias from `crypto-core` via `src/index.ts`)
|
|
- `@suaveplan/testing` — [x] tests run / [x] docs reviewed / [ ] no action needed
|
|
(declares a full `interface Rng` in `src/context/context.ts`; consumed by
|
|
`src/factories/factory/factory.ts`)
|
|
|
|
For every other dependent of `@suaveplan/types`: [x] no action needed —
|
|
they already consume `Rng` from `@suaveplan/types` and are unaffected by
|
|
this change.
|
|
|
|
### Source mapping (local Rng → canonical)
|
|
|
|
| Package | Local file | Local symbol | Action |
|
|
|---|---|---|---|
|
|
| `@suaveplan/crypto-core` | `src/primitives/random-bytes/random-bytes.ts` | `type Rng = ByteSource` | Replace with deprecated re-export of canonical `Rng`; keep `ByteSource` (distinct contract). |
|
|
| `@suaveplan/crypto` | `src/index.ts` | re-export `Rng` from `crypto-core` | Update re-export to point at canonical alias. |
|
|
| `@suaveplan/testing` | `src/context/context.ts` | `interface Rng { nextUint32; nextFloat }` | Import canonical `Rng`; re-export as deprecated alias. Add `@suaveplan/types` workspace dep (rule 8 exception). |
|
|
|
|
### Verification
|
|
|
|
- **Verified by:** `bunx turbo typecheck test --filter=@suaveplan/crypto-core`
|
|
- **Verified by:** `bunx turbo typecheck test --filter=@suaveplan/crypto`
|
|
- **Verified by:** `bunx turbo typecheck test --filter=@suaveplan/testing`
|
|
- **Verified by:** `bunx turbo typecheck test --filter=...@suaveplan/testing`
|
|
(dependents of `testing` consume `Rng` transitively via `factory.ts`)
|
|
- **Verified by:** repo-wide grep `grep -rln "interface Rng\b\|type Rng = " packages/ --include="*.ts" | grep -v "/dist/\|/node_modules/"` returns only the canonical declaration in `packages/core/types/src/rng.ts` plus the deprecated alias forwarders the change introduces.
|
|
|
|
## Out of scope
|
|
|
|
- **Widening the canonical `Rng`.** If a consumer needs additional members
|
|
(e.g. `nextBigInt`, streaming bytes), open a separate
|
|
`types-contract-tightening`-style change against `@suaveplan/types`.
|
|
- **Removing the deprecated aliases.** Follow-up change (one release cycle
|
|
after this one archives) removes the `Rng` re-exports from `crypto-core`,
|
|
`crypto`, and `testing`. Tracked as a TODO in this proposal's design.md.
|
|
- **Upstream-only packages (`cache`, `idempotency` upstream RNG redefinitions).**
|
|
The 2026-04-27 deferral text named `cache` and `idempotency` as RNG-shape
|
|
redefiners. On genesis, `@suaveplan/idempotency` and the three cache
|
|
packages (`@suaveplan/cache`, `cache-storage`, `cache-redis`) do **not**
|
|
currently reference `Rng` at all (verified by grep). When those packages
|
|
port the upstream randomness features, the migration must consume the
|
|
canonical `Rng` directly — there is no local type to migrate here yet.
|
|
- **Runtime behaviour changes.** This change is type-only; the test suite
|
|
must remain green pre- and post-migration with zero assertion edits.
|
|
|
|
## Migration
|
|
|
|
- **Old**: consumers importing `Rng` from `@suaveplan/crypto-core`,
|
|
`@suaveplan/crypto`, or `@suaveplan/testing`.
|
|
- **New**: import `Rng` from `@suaveplan/types`.
|
|
- **Search command**: `grep -rln "from ['\"]@suaveplan/\(crypto-core\|crypto\|testing\)['\"]" packages/ | xargs grep -l "Rng\b"`
|
|
- **Recommended replacement**: `import type { Rng } from "@suaveplan/types"`.
|
|
The deprecated alias re-exports remain functional for one release cycle.
|