5.8 KiB
Capability Spec Delta: audio-plugins-fx (split-audio-plugins-fx)
Package: @suaveplan/audio-fx-plugin-base, @suaveplan/audio-fx-plugin-*
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time. No exceptions. (Seeopenspec/AGENTS.mdSection 13.)
ADDED Requirements
Requirement: Per-plugin package layout
The audio FX capability SHALL be distributed as one foundation package (@suaveplan/audio-fx-plugin-base) plus one package per concrete plugin (@suaveplan/audio-fx-plugin-<name>). No package SHALL bundle more than one plugin's DSP, parameter surface, or registry entry.
Scenario: each plugin is independently installable
- WHEN a consumer adds only
@suaveplan/audio-fx-plugin-eqto itspackage.json - THEN
bun installresolvesaudio-fx-plugin-eq+audio-fx-plugin-base+ their transitive deps only, and no otheraudio-plugin-*package appears in the lockfile
Scenario: each plugin advances independently
- WHEN
audio-fx-plugin-eqgraduates to1.0.0whileaudio-fx-plugin-reverbremains at0.1.0 - THEN both packages publish from the same monorepo commit without forcing the other to bump
Verified by: packages/audio-fx/audio-fx-plugin-base/tests/dep-graph.test.ts::"audio-fx-plugin-base declares no @suaveplan/audio-fx-plugin-* deps" AND packages/audio-fx/audio-fx-plugin-eq/tests/dep-graph.test.ts::"audio-fx-plugin-eq depends on audio-fx-plugin-base only among audio-plugin-* packages"
Requirement: audio-fx-plugin-base owns the shared contract surface
@suaveplan/audio-fx-plugin-base SHALL export the AudioPlugin contract, PluginChain, ChainContext, AmbientState, BusRegistry, PluginRegistry, ChainSnapshot, and the shared error-codes.ts registry. No concrete plugin SHALL re-implement these primitives.
Scenario: contract is the single source of truth
- WHEN a new plugin package is authored
- THEN it imports
AudioPluginfrom@suaveplan/audio-fx-plugin-base/baseand never declares its own variant
Scenario: chain composition stays in base
- WHEN a consumer composes
audio-fx-plugin-eq,audio-fx-plugin-compressor, andaudio-fx-plugin-reverbinto a chain - THEN it imports
PluginChainfrom@suaveplan/audio-fx-plugin-base/chainand the chain accepts every plugin without per-plugin glue
Verified by: packages/audio-fx/audio-fx-plugin-base/src/chain/chain.test.ts::"PluginChain accepts any AudioPlugin implementation" AND packages/audio-fx/audio-fx-plugin-base/src/registry/registry.spec-conformance.test.ts::"PluginRegistry register/has/create/list invariants"
Requirement: audio-fx-plugin-base is dep-graph-isolated from concrete plugins
@suaveplan/audio-fx-plugin-base SHALL declare zero dependencies on any @suaveplan/audio-fx-plugin-* package. The dependency arrow MUST point only from concrete plugins to base, never base to plugins.
Scenario: no upward dep
- WHEN CI runs
tests/dep-graph.test.tsinaudio-fx-plugin-base - THEN the test fails if
package.jsoncontains any@suaveplan/audio-fx-plugin-*entry other thanaudio-fx-plugin-baseitself (which would be a self-dep and is also rejected)
Verified by: packages/audio-fx/audio-fx-plugin-base/tests/dep-graph.test.ts::"audio-fx-plugin-base declares no @suaveplan/audio-fx-plugin-* deps"
Requirement: Error-code namespace preserved across the split
Every error code that existed in @suaveplan/audio-plugins-fx SHALL remain reachable under the same AUDIO_PLUGIN.* namespace from either @suaveplan/audio-fx-plugin-base/error-codes (shared codes) or the relevant @suaveplan/audio-fx-plugin-<name>/error-codes (plugin-specific codes). No code SHALL be renamed, removed, or re-numbered by this change.
Scenario: shared codes resolve from base
- WHEN a caller imports
AUDIO_PLUGIN.CHAIN_SLOT_NOT_FOUNDfrom@suaveplan/audio-fx-plugin-base/error-codes - THEN the code value is byte-identical to the value previously exported from
@suaveplan/audio-plugins-fx/error-codes
Scenario: plugin-specific codes resolve from the plugin
- WHEN a caller imports an EQ-specific code from
@suaveplan/audio-fx-plugin-eq/error-codes - THEN the code is in the
AUDIO_PLUGIN.EQ.*namespace and is thrown by at least one production path inaudio-fx-plugin-eq
Verified by: packages/audio-fx/audio-fx-plugin-base/src/error-codes.test.ts::"every shared AUDIO_PLUGIN.* code preserved across split" AND packages/audio-fx/audio-fx-plugin-eq/src/error-codes.test.ts::"every AUDIO_PLUGIN.EQ.* code thrown by a production path"
Requirement: Migration leaves zero references to the old package
After this change ships, no file under packages/, apps/, scripts/, or docs/ SHALL import from @suaveplan/audio-plugins-fx. The old package directory SHALL be deleted.
Scenario: no stale imports
- WHEN CI runs
rg "@suaveplan/audio-plugins-fx" packages/ apps/ scripts/ docs/ - THEN the command exits with status 1 (no matches found)
Scenario: old package directory removed
- WHEN the post-archive tree is inspected
- THEN
packages/audio/audio-plugins-fx/does not exist
Verified by: scripts/openspec-conformance.ts audit for change split-audio-plugins-fx AND bunx turbo build whole-monorepo green
REMOVED Requirements
Requirement: Single bundled FX package
Reason: Superseded by per-plugin packaging — see ADDED requirement "Per-plugin package layout" above.
Migration: Replace import { Eq } from "@suaveplan/audio-plugins-fx/eq" with import { Eq } from "@suaveplan/audio-fx-plugin-eq". Replace import { PluginChain } from "@suaveplan/audio-plugins-fx/chain" with import { PluginChain } from "@suaveplan/audio-fx-plugin-base/chain". No runtime behavior changes.