76 lines
5.5 KiB
Markdown
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?
|