clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

main
miau-is-true / openspec / changes / archive / 2026-09-24-consolidate-level-schema-boundary / proposal.md
proposal.md 1.9K source

Why

Level data currently crosses several validation boundaries with slightly different rules. createGame() infers object kinds and accepts legacy automaton direction strings, while the CommonJS loader validates a related shape and normalizes it later. Data-only sharing has another copy of the same normalization. This makes a level valid through one path but invalid through another, and makes future mechanics expensive to add safely.

What Changes

  • Define one pure, host-owned level normalization and validation boundary for authored level data.
  • Make direct engine creation, trusted CommonJS loading, and data-only sharing use that boundary before their own context-specific error adapters.
  • Preserve the current legacy level shorthand during a documented migration: inferred kind, case-insensitive word tokens, and U/D/L/R/W automaton steps are accepted at input and materialized as canonical data.
  • Add parity fixtures proving valid data, invalid data, legacy normalization, and CommonJS/share round trips agree before play or installation.

Capabilities

New Capabilities

  • level-schema-boundary: canonical level normalization, validation, and adapters for engine, CommonJS, and data-only sharing.

Modified Capabilities

  • commonjs-mods: use the canonical level boundary instead of maintaining a second level validator.
  • level-sharing: validate and normalize shared levels through the same boundary used by local CommonJS previews and direct engine creation.

Impact

The implementation will add a small data/schema module and reduce duplicated level checks in src/engine.js, src/mods.js, and src/share.js. It will add focused tests for direct creation, local module loading, shared payloads, and export/import. Existing normalized pack fields, level IDs, rules semantics, and trusted-local CommonJS execution remain unchanged.