# Tasks: enterprise-money **Change ID**: enterprise-money **Package**: `@suaveplan/money` **Target path**: `finance/currency/money` **Prerequisites on Verdaccio**: `@suaveplan/error`, `zod` --- ## 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. ## 1. Scaffold - [ ] Create full directory tree per `proposal.md`. - [ ] `package.json` at `0.1.0`, `"sideEffects": false`, exports `"."` + `core/money` + `core/currency-registry` + `core/currencies` + `core/money-range` + `formatting` + `allocation` + `schemas` + `serialization`. - [ ] Deps: `@suaveplan/error workspace:^`, `zod catalog:forms`, `tslib catalog:build`. - [ ] DevDeps: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `fast-check catalog:testing`, `@suaveplan/testing workspace:^`. - [ ] `tsconfig.json` extending `library.json`; `vitest.config.ts` with `createTestConfig()`. - [ ] Scripts: `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check`. ## 2. Error hierarchy - [ ] `src/error-codes.ts`: define `MoneyErrorCode` union; implement `MoneyError`, `CurrencyMismatchError`, `UnknownCurrencyError`, `AllocationError`, `ParseError` extending `SuaveplanError`; `registerMoneyErrorCodes()`; eager call. ## 3. Currency registry + ISO data - [ ] Implement `CurrencyRegistry` in `src/core/currency-registry/currency-registry.ts`: internal `Map`; all methods per API surface. - [ ] `src/core/currencies/currencies.ts`: ISO 4217 data (≥50 common currencies minimum, full list preferred); seed the global `CurrencyRegistry.global()` on module load. - [ ] Write tests: register/get/virtual/multiplier; `getCurrencyOrThrow` throws `UnknownCurrencyError`; virtual vs ISO separation. ## 4. Money class - [ ] Implement `Money` in `src/core/money/money.ts`: - `fromMajor(value, currency, registry?)`: use `BigInt(Math.round(Number(value) * Number(multiplier)))` for number; use exact decimal-string parse for string inputs (no float intermediate). - All arithmetic: BigInt operations; throw `CurrencyMismatchError` on mismatched currencies. - `toDecimalString()`: format as exact decimal (e.g. `"12.34"` for USD with 2 minor units). - `toJSON()` / `Money.withRegistry(registry)`. - Negative-zero guard: ensure `0n` never becomes `-0n`. - [ ] Write `money.test.ts` (≤500 lines): all operators, edge cases, currency mismatch, negative-zero, decimal-string round-trip. ## 5. Formatting + parse - [ ] Implement `formatMoney`, `formatMoneyCompact`, `parseMoney` in `src/formatting/formatter/formatter.ts`. - [ ] `parseMoney`: handle comma decimals, grouped separators, currency symbol removal via `Intl.NumberFormat`. - [ ] Write `formatter.test.ts`: multiple locales, compact, parseMoney round-trip. ## 6. Allocation - [ ] Implement all five allocators + `sumMoney` + `minMoney` + `maxMoney` + `applyRounding` in `src/allocation/allocator/allocator.ts`. - [ ] Remainder redistribution: no minor unit lost or invented. - [ ] Write `allocator.test.ts`: even/ratio/percentage edge cases, remainder, sum invariant. ## 7. MoneyRange - [ ] Implement `MoneyRange` in `src/core/money-range/money-range.ts`: constructor validates `min <= max`; all methods per API surface. - [ ] Write `money-range.test.ts`: contains, intersect (null on no overlap), union, toArray. ## 8. Zod schemas + serialization - [ ] Implement `MoneyLikeSchema`, `CurrencyCodeSchema`, `FormatOptionsSchema` in `src/schemas/money-schemas/money-schemas.ts`. - [ ] Implement `moneyToJSON` / `moneyFromJSON` in `src/serialization/json/json.ts`. - [ ] Write tests for each. ## 9. Property-based tests - [ ] `tests/property.test.ts` (fast-check, `{ timeout: 30000 }`): - `a + b - b = a` for arbitrary same-currency `Money` pairs. - `allocateEvenly(m, n)` sums to `m`. - `allocateByRatios(m, rs)` sums to `m`. - `toDecimalString` round-trip identity. - `parseMoney(formatMoney(m, locale), m.currency, locale)` equals `m` for common locales. - `MoneyRange` `intersect` is commutative and associative on overlapping ranges. ## 10. Docs + verify + publish - [ ] All `.md` files per layout; root `README.md` with arithmetic quick-start, allocation example, MoneyRange, API table. - [ ] `bunx turbo lint --filter=@suaveplan/money` — zero errors. - [ ] `bunx turbo typecheck --filter=@suaveplan/money` — zero errors. - [ ] `bunx turbo test --filter=@suaveplan/money` — all pass. - [ ] `bunx turbo test:coverage --filter=@suaveplan/money` — 100%. - [ ] `bun scripts/publish.ts --package @suaveplan/money`. - [ ] Update `CLAUDE.md`; archive to `openspec/archive/2026-04-24-enterprise-money/`.