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

13 KiB
Raw Permalink Blame History

Tasks: complete-rng-unification

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

0. Pre-flight (mandatory before any edit)

  • 0.1 Confirm bunx turbo typecheck test --filter=@suaveplan/types green at HEAD (baseline).
  • 0.2 Confirm bunx turbo typecheck test --filter=@suaveplan/testing green at HEAD (baseline).
  • 0.3 Confirm bunx turbo typecheck test --filter=@suaveplan/crypto-core green at HEAD (baseline).
  • 0.4 Confirm bunx turbo typecheck test --filter=@suaveplan/crypto green at HEAD (baseline).
  • 0.5 Confirm bunx turbo typecheck test --filter=@suaveplan/mime green at HEAD (baseline).
  • 0.6 Re-run the exhaustive grep documented in proposal.md § Audit and confirm zero NEW matches have appeared since this proposal was drafted.

1. @suaveplan/types — spec-only tightening

  • 1.1 Update packages/core/types/src/rng.md to add a "Single source of truth" section noting that @suaveplan/types is the only canonical home for Rng across the monorepo and the permitted forms of downstream redeclaration (consume-direct, extend, or distinct-concept-under-distinct-name).
  • 1.2 No code change to packages/core/types/src/rng.ts (shape is already correct).
  • 1.3 bunx turbo typecheck test --filter=@suaveplan/types — green.
  • 1.4 bunx turbo test --filter=...@suaveplan/types — foundation dependent sweep green (mandatory per §13 step 10).

2. @suaveplan/testing — migrate Rng interface to re-export

  • 2.1 Locate local declaration: packages/testing/testing/src/context/context.ts line 45 (export interface Rng { nextUint32(): number; nextFloat(): number }).

  • 2.2 Confirm structural compatibility — required members are an exact subset of canonical; canonical adds two OPTIONAL members which existing cryptoRng / seededRng may omit.

  • 2.3 Add "@suaveplan/types": "workspace:^" to packages/testing/testing/package.json dependencies (rule 8 exception: testing-infra may depend on @suaveplan/types for types-only — confirm byte-size guard still passes).

  • 2.4 Replace export interface Rng { ... } with:

    // Back-compat re-export of @suaveplan/types' canonical Rng. Prefer importing
    // Rng from @suaveplan/types directly; this forwarder will be removed in the
    // follow-up `remove-deprecated-rng-aliases` change.
    export type { Rng } from "@suaveplan/types";
    
  • 2.5 Confirm cryptoRng: Rng = { ... } and seededRng(seed): Rng still typecheck against the canonical (they provide only the required members).

  • 2.6 Update sibling context.md API reference: note Rng is now a re-export of canonical; cross-link to @suaveplan/types.

  • 2.7 No barrel edits needed — src/index.ts:61 export type { Clock, Rng } from "./context/context.js" continues to forward correctly.

  • 2.8 bunx turbo typecheck --filter=@suaveplan/testing — green.

  • 2.9 bunx turbo test --filter=@suaveplan/testing — green, zero assertion edits.

  • 2.10 bunx turbo test:coverage --filter=@suaveplan/testing — 100/100/100/100 preserved.

  • 2.11 Dependent sweep: bunx turbo test --filter=...@suaveplan/testing — every test in the monorepo flows through @suaveplan/testing, must be green.

3. @suaveplan/crypto-core — drop misleading Rng alias + defaultRng

  • 3.1 Locate local declarations in packages/crypto/crypto-core/src/primitives/random-bytes/random-bytes.ts:

    • line 9: export type ByteSource = (n: number) => Uint8Array; — KEEP.
    • line 12: export type Rng = ByteSource; — REMOVE.
    • line 19: export const defaultByteSource: ByteSource = ... — KEEP.
    • line 36: export const defaultRng: ByteSource = defaultByteSource; — REMOVE.
    • line 38–41: RandomBytesOptions { byteSource?: ByteSource; rng?: ByteSource } — drop the rng field.
    • line 62: const source = options.byteSource ?? options.rng ?? defaultByteSource; — simplify to options.byteSource ?? defaultByteSource.
  • 3.2 Add back-compat re-export at the bottom of random-bytes.ts:

    // Back-compat re-export of @suaveplan/types' canonical Rng. Prefer importing
    // Rng from @suaveplan/types directly. This forwarder exists for one release
    // cycle — the legacy local `type Rng = ByteSource` alias was structurally
    // incompatible with canonical (callable vs object) and has been removed.
    // The follow-up `remove-deprecated-rng-aliases` change will delete this line.
    export type { Rng } from "@suaveplan/types";
    
  • 3.3 Confirm @suaveplan/types is in packages/crypto/crypto-core/package.json dependencies (it already is per MANIFEST.md).

  • 3.4 Update barrel packages/crypto/crypto-core/src/primitives/random-bytes/index.ts:

    • keep type ByteSource, defaultByteSource, type RandomBytesOptions, randomBytes.
    • keep type Rng (now forwards canonical via the back-compat re-export).
    • drop defaultRng.
  • 3.5 Update barrel packages/crypto/crypto-core/src/primitives/index.ts — same: drop defaultRng, keep Rng forwarding canonical.

  • 3.6 Update barrel packages/crypto/crypto-core/src/index.ts — same: drop defaultRng, keep Rng forwarding canonical.

  • 3.7 Update sibling random-bytes.md: drop Rng and defaultRng from local API reference; add "Implementation Notes" section explaining the type-class distinction (canonical Rng is an object; ByteSource is a callable; the local Rng is now a back-compat re-export of the canonical, not the legacy callable alias).

  • 3.8 Repo-internal callsite check — confirm no crypto-core test or impl file uses defaultRng or RandomBytesOptions.rng:

    grep -rn "defaultRng\b\|\.rng:\|, rng:" packages/crypto/crypto-core/src/ --include="*.ts"
    
  • 3.9 bunx turbo typecheck --filter=@suaveplan/crypto-core — green.

  • 3.10 bunx turbo test --filter=@suaveplan/crypto-core — green, zero assertion edits.

  • 3.11 bunx turbo test:coverage --filter=@suaveplan/crypto-core — 100/100/100/100 preserved.

  • 3.12 Dependent sweep: bunx turbo test --filter=...@suaveplan/crypto-core — every consumer (crypto, crypto-rsa, crypto-vault, crypto-keys, vault, vault-sync, webauthn, crypto-cli, crypto-bin, crypto-sodium, crypto-browser) green.

4. @suaveplan/crypto — update forwarder barrel

  • 4.1 Locate Rng and defaultRng re-exports in packages/crypto/crypto/src/index.ts (currently re-exported from @suaveplan/crypto-core block).

  • 4.2 Keep the Rng re-export (it now forwards canonical via crypto-core's back-compat re-export).

  • 4.3 Drop the defaultRng re-export.

  • 4.4 Repo-internal callsite check — confirm no crypto test or impl file uses defaultRng:

    grep -rn "defaultRng\b" packages/crypto/crypto/src/ --include="*.ts"
    
  • 4.5 If any .md in packages/crypto/crypto/src/ mentions Rng or defaultRng, update to reference @suaveplan/types (canonical) and defaultByteSource (correct name for the dropped alias).

  • 4.6 bunx turbo typecheck --filter=@suaveplan/crypto — green.

  • 4.7 bunx turbo test --filter=@suaveplan/crypto — green.

  • 4.8 bunx turbo test:coverage --filter=@suaveplan/crypto — 100/100/100/100 preserved.

5. @suaveplan/mime — rename file-scope ByteSource

  • 5.1 Locate packages/data/mime/src/detection/from-stream.ts line 19: type ByteSource = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>.
  • 5.2 Rename to StreamByteSource; update the single reference at line 30 (source: StreamByteSource).
  • 5.3 Confirm the type is NOT exported from from-stream.ts (it is type, not export type) — name collision is internal only, but renaming eliminates future confusion.
  • 5.4 Update sibling from-stream.md if it mentions ByteSource.
  • 5.5 Confirm from-stream-reader.ts (which uses ReadableStream<Uint8Array> | AsyncIterable<Uint8Array> inline) is unaffected.
  • 5.6 bunx turbo typecheck --filter=@suaveplan/mime — green.
  • 5.7 bunx turbo test --filter=@suaveplan/mime — green.
  • 5.8 bunx turbo test:coverage --filter=@suaveplan/mime — 100/100/100/100 preserved.

6. Spec deltas

  • 6.1 Author specs/types/spec.md delta with ## MODIFIED Requirements block on the canonical-Rng requirement, adding the single-source-of-truth clause.
  • 6.2 Author specs/testing/spec.md delta with ## MODIFIED Requirements block documenting Rng is now a back-compat re-export.
  • 6.3 Author specs/crypto-core/spec.md delta with ## MODIFIED Requirements documenting: Rng is canonical re-export; defaultRng is removed; RandomBytesOptions.rng field is removed; ByteSource is preserved under its real name (callable byte producer, distinct from Rng).
  • 6.4 Author specs/crypto/spec.md delta with ## MODIFIED Requirements documenting the forwarder barrel update.
  • 6.5 Author specs/mime/spec.md delta with ## MODIFIED Requirements documenting the ByteSource → StreamByteSource rename.
  • 6.6 Every requirement carries **Verified by:** line at authoring time.

7. Repo-wide verification gate

  • 7.1 Repo-wide grep returns exactly the documented set:

    grep -rln "interface Rng\b\|type Rng\s*=\|class Rng\b\|RngLike\b\|RandomSource\b" \
      packages/ --include="*.ts" --exclude-dir=dist --exclude-dir=node_modules
    

    Allowed hits:

    • packages/core/types/src/rng.ts (canonical declaration)
    • packages/random/pseudo-random/src/types/seeded-rng.types.ts (legitimate SeededRng extends Rng)
    • back-compat export type { Rng } from "@suaveplan/types" forwarder lines in crypto-core/random-bytes, crypto-core/primitives/index, crypto-core/primitives/random-bytes/index, crypto-core/index, crypto/index, testing/context
  • 7.2 Repo-wide ByteSource grep — confirm zero unintended renames; only the mime file-scope occurrence has changed.

  • 7.3 Repo-wide defaultRng grep returns zero hits in genesis source (it remains in @suaveplan/crypto-rsa/src/encrypt/default-rng.ts as a function defaultRng(): Rng — that is correct usage, not the dropped alias).

  • 7.4 bunx turbo lint typecheck --filter=... (full repo) — green.

8. Doc-drift + behaviour-change propagation

  • 8.1 Per CLAUDE.md §4a: every .ts edited has its sibling .md updated in the same change set (covered by tasks 1.1, 2.6, 3.7, 4.5, 5.4).

  • 8.2 Per CLAUDE.md §13a: the ## Migration note is authored in proposal.md (already done) — verify the search command works and produces the expected callsites.

  • 8.3 Update root MIGRATION.md with the per-package migration note (canonical Rng import path, defaultRng → defaultByteSource, RandomBytesOptions.rng → byteSource).

  • 8.4 Repo-wide consumer scan:

    grep -rln "from ['\"]@suaveplan/\(crypto-core\|crypto\|testing\)['\"]" packages/ \
      | xargs grep -l "Rng\b" 2>/dev/null
    

    Every hit either continues to compile via the back-compat forwarder OR is updated to canonical import in this change set.

9. Root-doc refresh + markdownlint

  • 9.1 No package add/remove; MANIFEST.md dep graph gains one edge (@suaveplan/testing → @suaveplan/types). Run bun scripts/folder-reorg/generate-manifest.ts.
  • 9.2 STATUS.md unchanged (no new pending → completed transitions).
  • 9.3 SUMMARY.md — update @suaveplan/types, @suaveplan/testing, @suaveplan/crypto-core, @suaveplan/crypto paragraphs to mention the canonical Rng clause and the back-compat forwarder.
  • 9.4 MIGRATION.md — updated per task 8.3.
  • 9.5 bunx markdownlint-cli2 --fix — green.

10. Fold + archive

  • 10.1 Fold specs/types/spec.md delta into openspec/specs/types/spec.md.
  • 10.2 Fold specs/testing/spec.md delta into openspec/specs/testing/spec.md.
  • 10.3 Fold specs/crypto-core/spec.md delta into openspec/specs/crypto-core/spec.md.
  • 10.4 Fold specs/crypto/spec.md delta into openspec/specs/crypto/spec.md.
  • 10.5 Fold specs/mime/spec.md delta into openspec/specs/mime/spec.md.
  • 10.6 Move openspec/changes/complete-rng-unification/ → openspec/archive/<yyyy-mm-dd>-complete-rng-unification/.
  • 10.7 Open the follow-up remove-deprecated-rng-aliases change to track removal of the back-compat re-export forwarders after one release cycle.