1## ADDED Requirements23### Requirement: Level inputs SHALL cross one canonical normalization boundary45The host SHALL expose one pure level normalization and validation boundary for6standalone engine levels, trusted CommonJS levels, and data-only shared levels.7The boundary SHALL clone caller data before normalization, SHALL not execute8code or access presentation state, and SHALL return canonical level data with9explicit object kinds, uppercase word and noun tokens, and explicit automaton10action objects. A context profile MAY add pack identity and size limits, but it11SHALL reuse the same structural checks and canonical output.1213#### Scenario: Direct and pack paths produce equivalent canonical data1415- **WHEN** the same valid level is passed to direct engine creation and to a16 CommonJS pack preview17- **THEN** both paths use equivalent canonical gameplay fields, including18 inferred kinds, token casing, IDs, and automaton actions1920#### Scenario: Input is not mutated2122- **WHEN** a caller supplies lowercase tokens, omitted kinds, or shorthand23 automaton steps and then mutates the original input after normalization24- **THEN** the canonical level and the active game remain unchanged and the25 original input retains its original values2627### Requirement: Legacy level shorthand SHALL be normalized at input2829During the compatibility window, the boundary SHALL accept omitted object30`kind` when `text` or `noun` makes the kind unambiguous, case-insensitive word31and noun tokens, and automaton pattern strings `U`, `D`, `L`, `R`, and `W`.32Canonical output SHALL materialize these as `kind: 'word'` or `kind: 'object'`,33uppercase tokens, and `{ action: 'move', dx, dy }` or `{ action: 'wait' }`.34Unknown shorthand, non-cardinal vectors, and unsupported action fields SHALL35remain errors. The boundary SHALL not emit new shorthand in CommonJS exports36or shared payloads.3738#### Scenario: Legacy automaton shorthand survives a share round trip3940- **WHEN** a valid level uses `['L', 'W', 'R']` in an automaton pattern and is41 exported to CommonJS or encoded as a shared pack42- **THEN** loading or decoding succeeds, the normalized pattern contains three43 explicit action objects, and a game created from the result has the same44 next transitions as the source game4546#### Scenario: Ambiguous shorthand fails consistently4748- **WHEN** a level contains an unsupported pattern string or a diagonal49 `{ action: 'move', dx: 1, dy: 1 }`50- **THEN** direct engine creation, CommonJS preview, and shared decoding all51 reject the same structural issue before play or installation5253### Requirement: Pack-only policy SHALL be an explicit adapter5455The pack profile SHALL require a stable lowercase level ID, enforce the56documented pack-level and pack-count bounds, and retain duplicate-ID checks.57The standalone engine profile MAY omit pack-only identity fields and SHALL not58silently inherit pack limits. Pack policy errors SHALL preserve the canonical59field path and SHALL occur before catalog registration.6061#### Scenario: A standalone fixture remains playable without a pack ID6263- **WHEN** a valid direct engine fixture has width, height, and objects but no64 `id`65- **THEN** direct game creation succeeds with canonical gameplay data6667#### Scenario: Pack identity is required before installation6869- **WHEN** a CommonJS pack contains a level without a stable lowercase `id`70- **THEN** preview reports the level path, rejects the pack atomically, and71 leaves existing catalog content unchanged7273### Requirement: Error adapters SHALL preserve canonical issue identity7475The shared boundary SHALL report stable issue codes and source paths. The76engine adapter SHALL retain its level-labeled `TypeError`/`RangeError` style;77the CommonJS adapter SHALL retain `ModValidationError` paths and source78context; and the shared decoder SHALL retain its player-readable invalid-pack79error. Adapters MAY add filename, pack, or level labels but SHALL not duplicate80structural validation or alter issue severity.8182#### Scenario: One malformed object has equivalent diagnostics8384- **WHEN** `objects[0]` has an invalid coordinate type through all three input85 paths86- **THEN** each path reports the same structural issue code and object index,87 while retaining its existing caller-specific error envelope8889### Requirement: Canonical data SHALL round-trip through sharing and export9091CommonJS export and data-only shared encoding SHALL serialize canonical level92data only. Decoding or loading SHALL revalidate through the boundary before93returning normalized data. A valid canonical level SHALL preserve gameplay94fields through CommonJS export/import and share encode/decode, including95automata metadata and optional authored level metadata.9697#### Scenario: Export/share parity preserves gameplay9899- **WHEN** a pack with words, objects, automata, and level metadata is exported100 and shared, then imported through both supported paths101- **THEN** both results compare equal on canonical gameplay data and create102 games with matching initial snapshots and first accepted transitions103104#### Scenario: Invalid shared data cannot bypass the boundary105106- **WHEN** a shared payload contains malformed level data or unsupported107 metadata108- **THEN** decoding fails before catalog installation and does not execute109 CommonJS or leave partial content registered110111### Requirement: Boundary parity SHALL be a release gate112113The project SHALL maintain focused fixtures covering canonical valid levels,114legacy shorthand, invalid coordinates, duplicate IDs, invalid tokens,115automaton action errors, and share/export round trips. The gate SHALL run the116direct engine, CommonJS loader, and data-only sharing paths against those117fixtures, followed by the full Node suite and production build.118119#### Scenario: Parity fixtures catch validator drift120121- **WHEN** one path accepts or normalizes a fixture differently from the122 canonical boundary123- **THEN** the focused parity test fails with the path and issue difference124 before the change can be marked complete