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

76 lines
5.5 KiB
Markdown

## Context
The current genesis bitpacker (`packages/primitives/bitpacker/`, ~20 files) is a greenfield build providing only low-level `BitWriter`/`BitReader` and a minimal `defineBitSchema`. It lacks the schema-driven packing system, advanced strategies, streaming, delta encoding, and enterprise features that suaveplan's bitpacker (`packages/universal/bitpacker/`, ~400 files) provides.
Suaveplan's bitpacker is monolithic — everything lives in one package. This creates three problems:
1. **Bundle bloat**: Consumers who only need `BitWriter`/`BitReader` pull in game-state schemas, network simulation, and crypto checksums.
2. **Slow builds**: A change in `game/prediction/kalman-filter.ts` triggers rebuilds for all bitpacker consumers.
3. **Poor boundaries**: The dependency graph is flat, so there's no clear API contract between core, strategies, and advanced modules.
The workspace glob `packages/*/*` already supports nested packages, so we can create `packages/bitpacker/` as a plugin host without any toolchain changes.
## Goals / Non-Goals
**Goals:**
- Create a `packages/bitpacker/` directory that hosts 10 related workspace packages.
- Core package (`@suaveplan/bitpacker`) stays lightweight: bit I/O, strategy manager, base types.
- Every advanced feature is an opt-in plugin with explicit `dependencies` in its `package.json`.
- Preserve genesis additions (`zigzag`, `peek`/`seek`, `align`) in core.
- Downstream consumers (`packer`, `network-*`, `storage-*`) continue to compile and test green.
- Maintain backward compatibility for `defineBitSchema` call sites.
**Non-Goals:**
- No runtime code generation, `eval`, or schema → JS compilation.
- No replacement of standalone `BitOperations` / packer APIs (escape hatch stays).
- No general expression language for conditional predicates.
- No changes to suaveplan source (this is a genesis-only restructure).
- No attempt to make every plugin tree-shakeable to zero bytes (just package-level separation).
## Decisions
### 1. Package naming: `@suaveplan/bitpacker-*` for all plugins
**Rationale:** Keeps the npm namespace flat and discoverable. `@suaveplan/bitpacker` is the core; every plugin is a sibling name.
**Alternative considered:** `@suaveplan/bitpacker/strategies` subpath exports. Rejected because subpaths don't give independent versioning or build caching.
### 2. Core owns `BitWriter`, `BitReader`, `PackingStrategyManager`, and the `BitPacker` class
**Rationale:** The strategy manager is the coordination layer; it must live in core so that plugins can register strategies. The core does NOT own any concrete strategies beyond a minimal `InvalidSchemaStrategy` catch-all.
### 3. Strategies plugin owns ALL built-in strategies
**Rationale:** Even basic strategies (string, number, boolean) are moved out of core so that alternative strategy sets can be swapped in. Core consumers who need the default strategy set import `@suaveplan/bitpacker-strategies` and call `registerDefaultStrategies(manager)`.
### 4. Preserve `packages/primitives/bitpacker/` temporarily
**Rationale:** Avoid breaking downstream consumers mid-migration. The old package will be deprecated and removed in a follow-up change after all dependents are updated.
### 5. Each plugin re-uses suaveplan source structure internally
**Rationale:** Porting 400 files is error-prone; keeping the same internal directory layout (`src/core/`, `src/packers/`, `src/schema/`, etc.) within each plugin reduces cognitive load.
### 6. Schema plugin owns the schema registry, validation, and versioning
**Rationale:** Schema metadata is a cross-cutting concern. Centralizing it in one plugin prevents circular deps between strategies and validation.
### 7. Error hierarchy: core defines `BitpackerError`, plugins extend it
**Rationale:** Core must not depend on `@suaveplan/error` (to stay lightweight), but plugins can. This is a pragmatic compromise; if `@suaveplan/error` is lightweight enough we may migrate core later.
## Risks / Trade-offs
- **[Risk] Downstream consumers break due to import path changes** → Mitigation: keep `packages/primitives/bitpacker/` as a re-export shim until all dependents are migrated.
- **[Risk] Circular dependencies between plugins** → Mitigation: enforce DAG via CI lint rule. Core → Strategies → Schema → Validation → Streaming/Delta/Game/Network/Crypto/Compressed.
- **[Risk] Build complexity increases with 10 packages** → Mitigation: turbo pipeline caches are per-package; incremental builds should be faster, not slower.
- **[Risk] Plugin API churn during port** → Mitigation: mark all plugin public APIs as `@beta` until Phase 4 verification is complete.
- **[Trade-off] More `package.json` files to maintain** → Acceptable; monorepo tooling (bun workspaces, turbo) handles this.
## Migration Plan
1. Create `packages/bitpacker/bitpacker/` and port core from `packages/primitives/bitpacker/` + suaveplan core.
2. Create remaining 9 plugin packages, porting from suaveplan.
3. Update `packages/primitives/bitpacker/` to re-export from new core (shim).
4. Run dependent sweep (`bunx turbo test --filter=...@suaveplan/bitpacker`).
5. Update downstream consumers to import from new paths.
6. Remove shim package in follow-up change.
## Open Questions
- Should `bitpacker-crypto` depend on `@suaveplan/crypto` or stay self-contained with its own checksum implementations?
- Should `bitpacker-game` live in `packages/game/` instead of `packages/bitpacker/`? (Leaning toward keeping it under `bitpacker/` for discoverability.)
- Do we need a `bitpacker-testing` plugin with shared test fixtures and property-test helpers?