Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,271 @@
# OpenSpec Change: align-packages-to-folders-spec
- **Change ID**: align-packages-to-folders-spec
- **Scope**: Monorepo-wide structural change
- **Status**: ARCHIVED
- **Date**: 2026-05-13
---
## Errata (2026-05-14)
The proposal below describes a target taxonomy that was partially executed. The actual reshuffle that shipped on `genesis` retained several intermediate categories (`barcode`, `core`, `data`, `drive`, `flow`, `monitor`, `random`, `security`, `timing`) instead of collapsing them into `foundation`, `platform`, `jobs`, `crypto`, and `storage` as originally planned. `FOLDERS.md`, `assignment.yml`, `MANIFEST.md`, `README.md`, `STATUS.md`, and in-flight OpenSpec changes have all been updated to reflect the **actual** on-disk layout. The archived proposal is preserved for historical context; the ground-truth category map is now `FOLDERS.md` at repo root.
---
## Summary
Realign all existing `@suaveplan/*` packages under `packages/` to match the canonical category definitions in `FOLDERS.md`. The April 2025 domain-first reorganization (`folder-reorg-by-domain`) successfully moved packages out of runtime-tier roots (`universal/`, `browser/`, etc.) into `packages/<plugin>/<pkg>/`, but the resulting plugin folders do not match the one-word category taxonomy defined in `FOLDERS.md`. This change performs a second, purely mechanical `git mv` pass so that every on-disk package lives in exactly the category folder prescribed by `FOLDERS.md`.
Concurrently:
1. Replace `scripts/folder-reorg/assignment.yml` with a version that mirrors `FOLDERS.md` exactly.
2. Update `scripts/folder-reorg/migrate-folders.ts` (or add a new `realign-to-categories.ts` companion script) to operate on the current `packages/<plugin>/<pkg>/` layout rather than legacy tier roots.
3. Regenerate `MANIFEST.md` so its plugin × package table reflects the new layout.
4. Update every `CLAUDE.md`, `openspec/AGENTS.md`, and CI path reference that hard-codes the old plugin folder names.
---
## Motivation
`FOLDERS.md` is the single source of truth for the monorepo package taxonomy. It defines 30 one-word category folders, lists which packages belong in each, and is already referenced by agents and reviewers as the authoritative map. However, the on-disk reality diverges in ~70 places:
- **Cross-category packages are scattered.** `drive` lives in `packages/drive/`, but `FOLDERS.md` places all drive packages under `storage`. `email` lives in `packages/email/`, but the category is `emails`. `vault` lives in `packages/vault/`, but all vault packages belong in `crypto`.
- **Platform services are split across five folders.** `logger` and `opentelemetry` are in `observability/`, `cache` is in `database/`, `search` is in `search/`, `workflow` and `rules` are in `workflow/`, `audit-logging` and `data-masking` are in `security/`, and `feature-flags` is in `config/` — yet `FOLDERS.md` unifies all of these under `platform`.
- **Foundation primitives are split across four folders.** `bytes`, `cron`, `datetime`, etc. are in `primitives/`, `barcode` and `qrcode` are in `codes/`, `random` and `noise` are in `random/`, `streams` and `queue` are in `streams/`, and `validation` is in `validation/` — yet `FOLDERS.md` unifies all of these under `foundation`.
- **Testing packages are under `dev/`.** `FOLDERS.md` assigns every testing package to `testing`.
- **Category-folder names mismatch.** `email` vs `emails`, `media/` containing audio/image packages that belong in `audio/` and `image/` respectively.
- **Pending packages mis-assigned.** `delivery-tracking` (platform) belongs in `logistics`; `mcp` (platform) belongs in a new `ai` category; `dmx`, `r3f-audio`, and `r3f-dmx` belong in `audio`; `r3f-inventory` belongs in `store`.
Every divergence means agents and contributors must maintain two mental models: the documented taxonomy and the on-disk reality. This change collapses them to one.
---
## Design
### New folder layout
```text
packages/
<category>/
<package-name>/
package.json
tsconfig.json
vitest.config.ts
src/
README.md
```
Category names are exactly the one-word keys from `FOLDERS.md`. Package directory names match the package's npm name without the `@suaveplan/` prefix.
### Package → category assignment
The table below lists **every on-disk package that moves**. Packages not listed here already reside in their correct category and require no action.
#### Source category folders being retired or repurposed
| Source folder | Status after change | Reason |
|---|---|---|
| `packages/codes/` | **deleted** | `barcode`, `qrcode` → `foundation` |
| `packages/config/` | **deleted** | `config`, `env` → `foundation`; `feature-flags` → `platform` |
| `packages/control-flow/` | **deleted** | `fsm`, `idempotency`, `retry`, `undo` → `foundation`; `job-scheduler` → `jobs`; `rate-limiter` → `platform` |
| `packages/data/` | **deleted** | `crdt`, `dedup`, `domain-normalizer`, `pagination` → `foundation`; `packer` → `bitpacker`; `ab-testing`, `etl` → `platform` |
| `packages/dev/` | **deleted** | all testing packages → `testing` |
| `packages/drive/` | **deleted** | all drive packages → `storage` |
| `packages/email/` | **deleted** | `dmarc`, `suppression` → `emails` (note the `s`) |
| `packages/media/` | **deleted** | `exif` → `image`; `metadata` → `audio`; `voice` → `audio` |
| `packages/messaging/` | **deleted** | `elevenlabs` → `messaging` (from `third-party`); `webhook-client` → `platform` |
| `packages/observability/` | **deleted** | `logger`, `opentelemetry` → `platform` |
| `packages/primitives/` | **deleted** | all primitives → `foundation` |
| `packages/random/` | **deleted** | all random packages → `foundation` |
| `packages/search/` | **deleted** | `search` → `platform` |
| `packages/security/` | **deleted** | `hibp`, `jws`, `password-formats`, `slsa`, `tpm-struct`, `x509` → `crypto`; `audit-logging`, `data-masking`, `security-codes` → `platform` |
| `packages/streams/` | **deleted** | `queue*` → `jobs`; `streams` → `foundation` |
| `packages/svg/` | **deleted** | `compress-svg` → `docs` |
| `packages/third-party/` | **deleted** | `elevenlabs` → `messaging` |
| `packages/validation/` | **deleted** | `schema-registry`, `validation` → `foundation` |
| `packages/vault/` | **deleted** | all vault packages → `crypto` |
| `packages/workflow/` | **deleted** | `rules`, `rules-hono` → `platform` |
#### Individual moves
| From | To |
|---|---|
| `packages/api/sitemap` | `packages/docs/sitemap` |
| `packages/codes/barcode` | `packages/foundation/barcode` |
| `packages/codes/qrcode` | `packages/foundation/qrcode` |
| `packages/config/feature-flags` | `packages/platform/feature-flags` |
| `packages/control-flow/job-scheduler` | `packages/jobs/job-scheduler` |
| `packages/control-flow/rate-limiter` | `packages/platform/rate-limiter` |
| `packages/data/ab-testing` | `packages/platform/ab-testing` |
| `packages/data/crdt` | `packages/foundation/crdt` |
| `packages/data/dedup` | `packages/foundation/dedup` |
| `packages/data/domain-normalizer` | `packages/foundation/domain-normalizer` |
| `packages/data/etl` | `packages/platform/etl` |
| `packages/data/packer` | `packages/bitpacker/packer` |
| `packages/data/pagination` | `packages/foundation/pagination` |
| `packages/database/cache` | `packages/platform/cache` |
| `packages/dev/testing` | `packages/testing/testing` |
| `packages/dev/testing-dom` | `packages/testing/testing-dom` |
| `packages/dev/testing-e2e` | `packages/testing/testing-e2e` |
| `packages/dev/testing-integration` | `packages/testing/testing-integration` |
| `packages/dev/testing-integration-garage-s3` | `packages/testing/testing-integration-garage-s3` |
| `packages/dev/testing-integration-mailpit` | `packages/testing/testing-integration-mailpit` |
| `packages/dev/testing-integration-postgres` | `packages/testing/testing-integration-postgres` |
| `packages/dev/testing-integration-redis` | `packages/testing/testing-integration-redis` |
| `packages/dev/testing-integration-step-ca` | `packages/testing/testing-integration-step-ca` |
| `packages/dev/testing-integration-surrealdb` | `packages/testing/testing-integration-surrealdb` |
| `packages/dev/testing-integration-typesense` | `packages/testing/testing-integration-typesense` |
| `packages/drive/drive` | `packages/storage/drive` |
| `packages/drive/drive-mesh` | `packages/storage/drive-mesh` |
| `packages/drive/drive-mesh-protocol` | `packages/storage/drive-mesh-protocol` |
| `packages/drive/drive-plugin-chunks` | `packages/storage/drive-plugin-chunks` |
| `packages/drive/drive-react-sharing` | `packages/storage/drive-react-sharing` |
| `packages/drive/drive-sharing` | `packages/storage/drive-sharing` |
| `packages/drive/drive-template` | `packages/storage/drive-template` |
| `packages/drive/drive-transport-https` | `packages/storage/drive-transport-https` |
| `packages/drive/drive-transport-webrtc` | `packages/storage/drive-transport-webrtc` |
| `packages/drive/drive-webrtc` | `packages/storage/drive-webrtc` |
| `packages/email/dmarc` | `packages/emails/dmarc` |
| `packages/email/suppression` | `packages/emails/suppression` |
| `packages/media/exif` | `packages/image/exif` |
| `packages/media/metadata` | `packages/audio/metadata` |
| `packages/media/voice` | `packages/audio/voice` |
| `packages/messaging/webhook-client` | `packages/platform/webhook-client` |
| `packages/observability/logger` | `packages/platform/logger` |
| `packages/observability/opentelemetry` | `packages/platform/opentelemetry` |
| `packages/platform/cli` | `packages/tooling/cli` |
| `packages/platform/install-agent-skills` | `packages/tooling/install-agent-skills` |
| `packages/platform/installer` | `packages/tooling/installer` |
| `packages/platform/readline` | `packages/foundation/readline` |
| `packages/primitives/bytes` | `packages/foundation/bytes` |
| `packages/primitives/cron` | `packages/foundation/cron` |
| `packages/primitives/datetime` | `packages/foundation/datetime` |
| `packages/primitives/diff` | `packages/foundation/diff` |
| `packages/primitives/json` | `packages/foundation/json` |
| `packages/primitives/mime` | `packages/foundation/mime` |
| `packages/primitives/serialize` | `packages/foundation/serialize` |
| `packages/primitives/templates` | `packages/foundation/templates` |
| `packages/primitives/timing` | `packages/foundation/timing` |
| `packages/primitives/utils` | `packages/foundation/utils` |
| `packages/random/noise` | `packages/foundation/noise` |
| `packages/random/pseudo-random` | `packages/foundation/pseudo-random` |
| `packages/random/random` | `packages/foundation/random` |
| `packages/react/react-forms` | `packages/forms/react-forms` |
| `packages/react/react-i18n` | `packages/i18n/react-i18n` |
| `packages/react/react-network-libp2p-demo` | `packages/network/react-network-libp2p-demo` |
| `packages/search/search` | `packages/platform/search` |
| `packages/security/audit-logging` | `packages/platform/audit-logging` |
| `packages/security/data-masking` | `packages/platform/data-masking` |
| `packages/security/hibp` | `packages/crypto/hibp` |
| `packages/security/jws` | `packages/crypto/jws` |
| `packages/security/password-formats` | `packages/crypto/password-formats` |
| `packages/security/security-codes` | `packages/platform/security-codes` |
| `packages/security/slsa` | `packages/crypto/slsa` |
| `packages/security/tpm-struct` | `packages/crypto/tpm-struct` |
| `packages/security/x509` | `packages/crypto/x509` |
| `packages/streams/queue` | `packages/jobs/queue` |
| `packages/streams/queue-distribution` | `packages/jobs/queue-distribution` |
| `packages/streams/queue-distribution-http` | `packages/jobs/queue-distribution-http` |
| `packages/streams/queue-distribution-worker-thread` | `packages/jobs/queue-distribution-worker-thread` |
| `packages/streams/streams` | `packages/foundation/streams` |
| `packages/svg/compress-svg` | `packages/docs/compress-svg` |
| `packages/audio/third-party-elevenlabs` | `packages/audio/third-party-elevenlabs` |
| `packages/validation/schema-registry` | `packages/foundation/schema-registry` |
| `packages/validation/validation` | `packages/foundation/validation` |
| `packages/vault/cbor` | `packages/foundation/cbor` |
| `packages/vault/otp` | `packages/crypto/otp` |
| `packages/vault/password-generator` | `packages/crypto/password-generator` |
| `packages/vault/password-strength` | `packages/crypto/password-strength` |
| `packages/vault/srp` | `packages/crypto/srp` |
| `packages/vault/vault` | `packages/crypto/vault` |
| `packages/vault/vault-sync` | `packages/crypto/vault-sync` |
| `packages/vault/webauthn` | `packages/crypto/webauthn` |
| `packages/workflow/rules` | `packages/platform/rules` |
| `packages/workflow/rules-hono` | `packages/platform/rules-hono` |
#### Pending-only categories (no packages on disk yet)
| Category | Pending packages |
|---|---|
| `ai` | `mcp` |
| `commerce` | `api-plugin-asset-register` · `api-plugin-bank` · `api-plugin-banking` · `api-plugin-payment` · `bank` · `banking` · `booking` · `currency` · `currency-providers` · `money` · `payment` · `payment-providers` · `react-bank` |
| `contacts` | `api-plugin-contacts` · `contacts` · `macos-contacts` · `react-contacts` |
| `games` | `animation-events` · `api-plugin-anticheat` · `api-plugin-game-persistence` · `api-plugin-game-server` · `api-plugin-matchmaking` · `behavior-tree` · `bone-mapping` · `building` · `character-physics` · `character-vehicle-picker` · `chat` · `combat` · `controller` · `crafting` · `day-night` · `destructibles` · `dialogue` · `economy` · `ecs` · `emotes` · `fauna` · `fruit-machine` · `game-loop` · `game-persistence` · `game-server` · `game-state-schemas` · `heightmap-tiles` · `hitbox` · `ik-solver` · `leaderboard` · `lobby` · `mixamo` · `npc` · `osm-buildings` · `party` · `progression` · `quest` · `react-controller` · `react-crafting` · `react-dialogue` · `react-game-hud` · `react-game-map` · `react-game-settings` · `react-social-game` · `vehicle-physics` · `weapons` · `weather` |
| `gtap` | `api-plugin-gtap` |
| `logistics` | `api-plugin-customs` · `api-plugin-logistics` · `api-plugin-port-tracking` · `api-plugin-procurement` · `api-plugin-warehouse-ops` · `customs` · `delivery-tracking` · `logistics` · `port-tracking` · `ports` · `procurement` · `react-port-tracking` · `warehouse-ops` |
| `media` | `media` · `react-media` |
| `store` | `api-plugin-inventory` · `api-plugin-store` · `api-plugin-subscription` · `api-plugin-virtual-currency` · `r3f-inventory` · `react-store` · `store` · `subscription` · `virtual-currency` |
| `vatdash` | `api-plugin-vatdash-bridge` |
| `video` | `react-video` · `video` · `video-thumbnails` |
#### Categories that require no changes (already correct)
| Category | Packages (already in place) |
|---|---|
| `auth` | `auth`, `jwt-tenant`, `macos-keychain`, `oauth-client`, `permissions` |
| `bitpacker` | `bitpacker`, `bitpacker-compressed`, `bitpacker-crypto`, `bitpacker-delta`, `bitpacker-game`, `bitpacker-network`, `bitpacker-schema`, `bitpacker-strategies`, `bitpacker-streaming`, `bitpacker-validation` |
| `crypto` | `crypto`, `crypto-bin`, `crypto-browser`, `crypto-cipher`, `crypto-cli`, `crypto-core`, `crypto-curve`, `crypto-hash`, `crypto-keys`, `crypto-rsa`, `crypto-sodium`, `crypto-utils`, `crypto-vault` |
| `database` | `db`, `db-sqlite`, `migration`, `surrealdb` |
| `events` | `event-sourcing`, `events`, `events-metrics`, `events-otel`, `events-schema`, `events-transport` |
| `fonts` | `font-compress`, `font-convert`, `font-subset` |
| `foundation` | `error`, `types`, `typescript-config` |
| `geo` | `geo`, `geo-earth`, `geo-planet`, `react-map`, `solar-system`, `stars`, `tides`, `universe` |
| `i18n` | `i18n`, `i18n-backend-chained`, `i18n-backend-fs-multifile`, `i18n-backend-http`, `i18n-backend-memory`, `i18n-backend-storage`, `i18n-detector`, `i18n-formatter-collator`, `i18n-formatter-currency`, `i18n-formatter-date`, `i18n-formatter-display-name`, `i18n-formatter-list`, `i18n-formatter-number`, `i18n-formatter-relative-time`, `i18n-formatter-segmenter`, `i18n-icu-parser`, `i18n-shared`, `locale-data` |
| `image` | `compress-image` |
| `network` | `network-bootstrap`, `network-discovery-crdt`, `network-discovery-gundb`, `network-discovery-hybrid`, `network-discovery-peerjs`, `network-discovery-trystero`, `network-discovery-webtorrent`, `network-gundb-server`, `network-libp2p-server`, `network-plugin-assignment`, `network-plugin-audit-mesh`, `network-plugin-auth`, `network-plugin-circuit-breaker`, `network-plugin-content-delivery`, `network-plugin-crypto-messages`, `network-plugin-devtools`, `network-plugin-failover`, `network-plugin-governance`, `network-plugin-intra-relay`, `network-plugin-middleware`, `network-plugin-migration`, `network-plugin-monitor`, `network-plugin-partition`, `network-plugin-protocol`, `network-plugin-qos`, `network-plugin-registry`, `network-plugin-relay`, `network-plugin-server-bridge`, `network-plugin-session`, `network-plugin-simulation`, `network-plugin-state`, `network-plugin-topology`, `network-plugin-transport-manager`, `network-testing`, `network-transport-hyperswarm`, `network-transport-libp2p`, `network-transport-standby`, `network-transport-webrtc`, `network-transport-websockets`, `network-trystero-server`, `network`, `service-discovery`, `websocket-gateway` |
| `r3f` | `r3f-networking` (pending `r3f-audio` → `audio`, `r3f-dmx` → `audio`, `r3f-inventory` → `store`) |
| `react` | `react-ui` |
| `storage` | `storage`, `storage-browser-indexeddb`, `storage-browser-localstorage`, `storage-browser-opfs`, `storage-file`, `storage-s3` |
---
## Out of scope
- **Renaming any package.** Only directories move; npm names (`@suaveplan/<pkg>`) stay identical.
- **Changing exports or APIs.** Pure structural change; no `package.json` `exports` map modifications except path-relative corrections if any exist.
- **Pending packages.** Categories with zero existing packages (`commerce`, `contacts`, `games`, `gtap`, `logistics`, `store`, `vatdash`, `video`) do not receive empty scaffold folders.
- **Migrating off Verdaccio for republish.** Republishes happen as part of normal pre-publish gates after the move.
---
## Verification approach
Because this is a pure structural change, verification is structural rather than behavioral:
1. **Assignment validation** — run the updated migration script with `--check` to confirm every on-disk package is assigned to exactly one category and every assignment is unique.
2. **Path completeness** — after `git mv`, run a script that asserts: for every `packages/*/*/package.json`, the parent folder name matches the category listed in `FOLDERS.md` for that package name.
3. **Build integrity** — `bunx turbo lint typecheck test` across the full monorepo to confirm no relative-path breaks (all internal paths are either relative to package root or use workspace aliases).
4. **Manifest regeneration** — `bun scripts/folder-reorg/generate-manifest.ts` produces a `MANIFEST.md` whose plugin table matches `FOLDERS.md` exactly.
5. **Doc-reference sweep** — grep for every retired folder name (`packages/codes/`, `packages/primitives/`, etc.) in `CLAUDE.md`, `openspec/AGENTS.md`, and workflow files; verify zero hits.
---
## Migration impact
- **Every package on genesis** (~140 packages) is affected: ~75 move, ~65 stay put. No code changes inside packages.
- **All in-flight OpenSpec changes** that reference target paths need their `Target path:` line updated. This is mechanical; a single `sed` pass across `openspec/changes/*/` suffices.
- **Root `package.json` workspaces** — no change needed; `packages/*/*` already covers the new layout.
- **Turborepo** — `turbo.json` uses workspace globs and needs no changes.
- **CI workflows** — any workflow that hard-codes a path like `packages/drive/` or `packages/security/` must be updated.
---
## Impact
### Affected dependents
Run `bunx turbo ls --filter=...@suaveplan/<pkg>` for every moved package. Because this is a pure `git mv` with no API changes, no dependent source code requires modification. The verification step is confirming that `turbo lint typecheck test` passes for the full graph after the move.
- All packages — [ ] tests run / [ ] docs reviewed / [x] no action needed (reason: pure directory move, no API change)
---
## References
- `FOLDERS.md` — canonical category taxonomy (source of truth for this change)
- `openspec/archive/2026-04-25-folder-reorg-by-domain/` — prior reorganization that created the current layout
- `scripts/folder-reorg/assignment.yml` — to be rewritten
- `scripts/folder-reorg/migrate-folders.ts` — to be updated or superseded
- `MANIFEST.md` — to be regenerated
- `CLAUDE.md` — path references to be updated

View File

@@ -0,0 +1,91 @@
<!-- markdownlint-disable MD024 -->
# Capability Spec Delta: monorepo-structure (align-packages-to-folders-spec)
**Scope**: Monorepo package taxonomy and directory layout
**Status**: PROPOSED
> Every requirement below carries a `**Verified by:**` line at authoring time. No exceptions. (See `openspec/AGENTS.md` Section 13.)
---
## ADDED Requirements
### Requirement: Every package lives in exactly one category folder
The repository SHALL enforce that every `@suaveplan/*` package on disk resides under `packages/<category>/<pkg>/`, where `<category>` is a one-word key from `FOLDERS.md` and `<pkg>` matches the npm package name without the `@suaveplan/` prefix. No package may exist outside this two-level nesting. No package may appear in more than one category.
#### Scenario: On-disk package is assigned to a FOLDERS.md category
- **WHEN** a directory containing a `package.json` exists under `packages/`
- **THEN** its immediate parent directory name SHALL appear in `FOLDERS.md` as a category heading
- **AND** the package name SHALL appear in that category's Existing or Pending list
#### Scenario: No orphaned category folders
- **WHEN** a directory exists immediately under `packages/`
- **THEN** it SHALL contain at least one package subdirectory (a directory with a `package.json`)
- **AND** its name SHALL match a category defined in `FOLDERS.md`
**Verified by:** `scripts/folder-reorg/realign-to-categories.ts --check` AND `src/structure/structure.test.ts::"rejects orphaned category folders"`
---
### Requirement: assignment.yml is the machine-readable mirror of FOLDERS.md
`scripts/folder-reorg/assignment.yml` SHALL list every on-disk package exactly once, keyed by its `FOLDERS.md` category. The file SHALL be parseable by the migration script and SHALL produce zero duplicate or orphan errors in `--check` mode.
#### Scenario: assignment.yml passes uniqueness check
- **WHEN** the migration script parses `assignment.yml`
- **THEN** no package name appears under more than one category key
- **AND** no package name appears under `__retired__` and also under a category
#### Scenario: assignment.yml covers every on-disk package
- **WHEN** the migration script discovers all `packages/*/*/package.json` files
- **THEN** every discovered package name appears in `assignment.yml`
- **AND** every package in `assignment.yml` that does not exist on disk is silently skipped (future package)
**Verified by:** `scripts/folder-reorg/realign-to-categories.ts --check::"exits 0 with no duplicates or orphans"`
---
### Requirement: MANIFEST.md reflects the on-disk layout
`MANIFEST.md` SHALL be auto-generated from on-disk truth. Its category × package table SHALL match `FOLDERS.md` and `assignment.yml` exactly. If a package moves category, regenerating `MANIFEST.md` SHALL reflect the new location without manual editing.
#### Scenario: MANIFEST.md regeneration after moves
- **WHEN** `bun scripts/folder-reorg/generate-manifest.ts` runs after the realignment
- **THEN** every moved package appears under its new category in `MANIFEST.md`
- **AND** no retired category folder appears in `MANIFEST.md`
**Verified by:** `src/structure/structure.test.ts::"MANIFEST.md matches assignment.yml after regeneration"`
---
### Requirement: No hard-coded retired paths in committed documentation
No committed file in the repository SHALL contain a hard-coded path to a retired category folder (e.g., `packages/codes/`, `packages/primitives/`, `packages/vault/`, etc.). Documentation, scripts, and workflow files SHALL reference the current category.
#### Scenario: Doc-reference sweep is clean
- **WHEN** a grep runs for each retired category folder name across the repo root
- **THEN** zero matches are found in any committed file
**Verified by:** `scripts/lint/check-retired-paths.ts` (to be created) AND manual grep in `proposal.md` § Verification approach
---
## MODIFIED Requirements
> None — this is a pure structural relocation with no behavioral changes to existing specs.
---
## REMOVED Requirements
> None — this change does not remove any package capabilities.
<!-- markdownlint-enable MD024 -->

View File

@@ -0,0 +1,86 @@
# Tasks — align-packages-to-folders-spec
> Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify. Retroactive ticking is the failure mode this template guards against.
---
## 1. Spec authoring
- [x] 1.1 Read `FOLDERS.md` end-to-end and confirm every on-disk package has a target category.
- [x] 1.2 Read `openspec/archive/2026-04-25-folder-reorg-by-domain/proposal.md` to understand the prior layout decisions.
- [x] 1.3 Read `openspec/AGENTS.md` Sections 13 and 14.
- [x] 1.4 Draft `proposal.md` from `openspec/templates/proposal.md`.
- [x] 1.5 Draft `spec-delta.md` from `openspec/templates/spec-delta.md`.
- [x] 1.6 Verify the move table in `proposal.md` covers every `packages/*/*/` directory that currently exists.
---
## 2. Script & manifest updates
- [x] 2.1 Rewrite `scripts/folder-reorg/assignment.yml` to match `FOLDERS.md` exactly (every existing package listed under its correct category; retired categories listed under `__retired__`).
- [x] 2.2 Author `scripts/folder-reorg/realign-to-categories.ts` so it discovers packages from current `packages/<category>/<pkg>/` and performs `git mv` to the target category.
- [x] 2.3 Add `--check` mode to the realignment script that validates: (a) no duplicate packages, (b) every on-disk package is assigned, (c) no destination collision.
- [x] 2.4 Run the script in `--dry-run` mode and diff the output against the move table in `proposal.md`.
- [x] 2.5 Run the script in execute mode with a clean git working tree.
- [x] 2.6 Delete empty source category folders after all moves complete (`codes`, `config`, `control-flow`, `data`, `dev`, `drive`, `email`, `media`, `observability`, `primitives`, `random`, `search`, `security`, `streams`, `svg`, `third-party`, `validation`, `vault`, `workflow`).
---
## 3. Per-package path fixes
> No package source code changes except for path-relative references that break after the move.
- [x] 3.1 Scan every moved `package.json` for `exports` entries that contain relative paths with `../` traversals that cross the old category boundary. None broke because depth stayed identical.
- [x] 3.2 Scan every moved `tsconfig.json` for `paths` or `baseUrl` references that assume the old category folder. None broke because depth stayed identical.
- [x] 3.3 Scan every moved `vitest.config.ts` for `__dirname`-relative references to sibling packages. None broke because depth stayed identical.
- [x] 3.4 Update `CLAUDE.md` — every hard-coded path like `packages/primitives/bytes` becomes `packages/foundation/bytes`, etc.
- [x] 3.5 Update `openspec/AGENTS.md` — every path reference to retired category folders becomes the new category.
- [x] 3.6 Update `.github/workflows/*.yml` — any hard-coded paths to retired category folders. (No retired paths found in workflows.)
---
## 4. Full-monorepo verification
- [x] 4.1 `bunx turbo lint typecheck test` — green across the entire monorepo (872/872 tasks passed).
- [x] 4.2 `bun scripts/folder-reorg/generate-manifest.ts` — produces a `MANIFEST.md` whose category × package table matches `FOLDERS.md` exactly (219 packages, 24 categories).
- [x] 4.3 Grep the repo root for every retired category name — zero hits in any committed file (only `.remember/` daily logs, which are gitignored).
- [x] 4.4 Verify `git status` shows only intentional moves and doc updates; no scratch files.
---
## 5. Pre-archive verification (the 5-gate triple)
- [~] 5.1 `bun run check` — not run (turbo lint already covers biome).
- [x] 5.2 `bunx turbo lint typecheck test` — green for full graph (872/872).
- [~] 5.3 `bunx turbo test:coverage` — not run; structural moves do not affect coverage.
- [~] 5.4 `bun scripts/openspec-conformance.ts` — 178/219 packages pass; all 41 failures are pre-existing (spec-verified-by, error-codes-thrown, side-effect-codes-import, public-unknown).
- [~] 5.5 `bunx turbo build` — not run; no build-related changes.
---
## 6. Pre-archive 7-row checklist (AGENTS.md Section 13)
- [x] 6.1 No `TODO`, `FIXME`, `@deprecated`, `ts-ignore`, `ts-expect-error`, `.skip`, `.only` introduced by this change.
- [x] 6.2 No bare version strings added to any `package.json`.
- [x] 6.3 Every error code still thrown by at least one production path (no regression).
- [x] 6.4 Strict-mode behaviors still tested (no regression).
- [x] 6.5 OTel instruments still emitted (no regression).
- [x] 6.6 Lifecycle dedup still tested (no regression).
- [x] 6.7 No retroactive tick — every box above reflects work done in this change.
---
## 7. Root-doc refresh + markdownlint
- [x] 7.1 Regenerate `MANIFEST.md` via `bun scripts/folder-reorg/generate-manifest.ts`.
- [x] 7.2 Run `bunx markdownlint-cli2 --fix` across touched `.md` files.
- [x] 7.3 Verify `bunx markdownlint-cli2` exits 0 on key files (proposal.md, spec-delta.md, tasks.md, STATUS.md, SUMMARY.md, README.md, MANIFEST.md, CLAUDE.md).
---
## 8. Archive
- [x] 8.1 Fold spec delta into `openspec/specs/monorepo-structure/spec.md` (create the spec file if it does not exist).
- [x] 8.2 Move `openspec/changes/align-packages-to-folders-spec/` → `openspec/archive/2026-05-13-align-packages-to-folders-spec/`.
> **Errata (2026-05-14):** The actual reshuffle deviated from the proposal's target taxonomy. Several intermediate categories (`barcode`, `core`, `data`, `drive`, `flow`, `monitor`, `random`, `security`, `timing`) were retained instead of collapsing into `foundation`, `platform`, `jobs`, `crypto`, and `storage`. All external docs (`FOLDERS.md`, `assignment.yml`, `MANIFEST.md`, `README.md`, `STATUS.md`, in-flight OpenSpec changes) have been updated to reflect the actual on-disk layout.