Make the **server the only source of truth** for item definitions, schema, defaults, options, validation rules, and editable behavior. The client should consume server definitions and provide UX/rendering/audio only.
This plan removes client fallback definitions and introduces a repeatable, consistent item authoring structure so adding new item types is low-risk and uniform.
A central loader in server scans `server/app/items/types/*` at boot and imports one plugin entrypoint per folder (for example `plugin.py` with `ITEM_TYPE_PLUGIN` export).
The discovered plugins are then assembled into an in-memory registry object exposing:
- validation hooks
- defaults
- ui definitions
- capabilities
- action dispatch
This means:
- adding a new item folder + plugin file is sufficient for server registration
- no hand-edited master list is required
## B) Server: Strict Params Hygiene
In update flow:
- Build next params by applying patch into current params.
- Run through type validator that:
- strips unknown keys
- normalizes known keys
- enforces types/ranges/options
- Persist only validated output.
No raw client params should persist.
## C) Server: Save Strategy
Replace synchronous `save_state()` every mutation with coalesced writes:
- mark dirty on mutation
- debounce write (e.g., 100-300ms)
- cap max delay (e.g., 1-2s)
- flush on shutdown/signal
This preserves durability while reducing event-loop blocking.
## D) Client: Schema-Driven UI Runtime
Refactor client item registry/editor to consume server schema only.
Client keeps:
- Presentation helpers
- Generic item behavior path driven only by schema/metadata
- Optional per-item UX runtime modules only where needed (example: piano key mode)
Client removes:
- static defaults/options/editability lists as authority
- fallback-driven assumptions
- requirement for per-item client modules when behavior is generic
- Mitigation: keep small per-item preview hooks while generic editor handles core commit logic.
4. Risk: debounced persistence data loss on crash.
- Mitigation: short debounce + max-delay + flush on shutdown.
---
## Suggested Execution Order for Your Repo (Practical)
1. Implement strict unknown-key stripping on server (highest impact, lowest UX risk).
2. Implement server plugin auto-discovery for item type folders.
3. Convert client item registry to require server schema payload (remove fallback authority).
4. Make item property editor fully metadata-driven with dependency rules.
5. Finalize optional client behavior modules (only for custom UX items like piano).
6. Add coalesced persistence.
---
## Definition of Done
- Server item validators fully define accepted params and drop unknowns.
- Server item types are boot-loaded from folder plugins (no manual master registry edits).
-`uiDefinitions` is complete and authoritative for all item UI config.
- Client contains no authoritative item defaults/options/editability outside server payload.
- Client has no fallback schema path.
- New item addition follows one template with predictable files/tests.
-`main.ts` has no item-type-specific runtime branches.
---
## Implementation Update (2026-02-24)
### Completed
- Phase 0:
- Added server-side contract coverage for `uiDefinitions` completeness.
- Added/kept tests for unknown-key stripping and validation behavior.
- Phase 1:
- Server item plugins are auto-discovered from `server/app/items/types/*/plugin.py`.
- Registry now builds type order/modules from discovered plugins.
- Phase 2:
- Unknown params are stripped by validators and use-path updates are revalidated before persist.
- Phase 3:
- Client item registry now requires server `uiDefinitions`; no fallback item-definition authority.
- Missing/invalid schema now disables item menus with explicit status.
- Phase 4:
- Property editor behavior is metadata-driven by `valueType/range/options/maxLength`.
-`visibleWhen` is supported and item property rows recompute live after updates.
- Phase 5:
- Client runtime behavior remains modular per item via behavior registry; `main.ts` orchestration no longer carries item-specific business branches.
- Phase 6:
- Coalesced/debounced state saving implemented.
- Flush-on-shutdown implemented.
- Save timing now configurable via:
-`storage.state_save_debounce_ms`
-`storage.state_save_max_delay_ms`
### Notes
- Client item-specific runtime is now reduced to only `piano`; simple items (`dice`, `wheel`, `clock`, `radio_station`, `widget`) run through generic client flows with no custom behavior module.
- Server item implementations now live inside per-type folders (`server/app/items/types/*/module.py`) and plugins point directly to those modules.