clone

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

main
miau-is-true / openspec / specs / level-schema-boundary / spec.md
spec.md 6.0K rendered
1# level-schema-boundary Specification23## Purpose4TBD - created by archiving change consolidate-level-schema-boundary. Update Purpose after archive.5## Requirements6### Requirement: Level inputs SHALL cross one canonical normalization boundary78The host SHALL expose one pure level normalization and validation boundary for9standalone engine levels, trusted CommonJS levels, and data-only shared levels.10The boundary SHALL clone caller data before normalization, SHALL not execute11code or access presentation state, and SHALL return canonical level data with12explicit object kinds, uppercase word and noun tokens, and explicit automaton13action objects. A context profile MAY add pack identity and size limits, but it14SHALL reuse the same structural checks and canonical output.1516#### Scenario: Direct and pack paths produce equivalent canonical data1718- **WHEN** the same valid level is passed to direct engine creation and to a19 CommonJS pack preview20- **THEN** both paths use equivalent canonical gameplay fields, including21 inferred kinds, token casing, IDs, and automaton actions2223#### Scenario: Input is not mutated2425- **WHEN** a caller supplies lowercase tokens, omitted kinds, or shorthand26 automaton steps and then mutates the original input after normalization27- **THEN** the canonical level and the active game remain unchanged and the28 original input retains its original values2930### Requirement: Legacy level shorthand SHALL be normalized at input3132During the compatibility window, the boundary SHALL accept omitted object33`kind` when `text` or `noun` makes the kind unambiguous, case-insensitive word34and noun tokens, and automaton pattern strings `U`, `D`, `L`, `R`, and `W`.35Canonical output SHALL materialize these as `kind: 'word'` or `kind: 'object'`,36uppercase tokens, and `{ action: 'move', dx, dy }` or `{ action: 'wait' }`.37Unknown shorthand, non-cardinal vectors, and unsupported action fields SHALL38remain errors. The boundary SHALL not emit new shorthand in CommonJS exports39or shared payloads.4041#### Scenario: Legacy automaton shorthand survives a share round trip4243- **WHEN** a valid level uses `['L', 'W', 'R']` in an automaton pattern and is44 exported to CommonJS or encoded as a shared pack45- **THEN** loading or decoding succeeds, the normalized pattern contains three46 explicit action objects, and a game created from the result has the same47 next transitions as the source game4849#### Scenario: Ambiguous shorthand fails consistently5051- **WHEN** a level contains an unsupported pattern string or a diagonal52 `{ action: 'move', dx: 1, dy: 1 }`53- **THEN** direct engine creation, CommonJS preview, and shared decoding all54 reject the same structural issue before play or installation5556### Requirement: Pack-only policy SHALL be an explicit adapter5758The pack profile SHALL require a stable lowercase level ID, enforce the59documented pack-level and pack-count bounds, and retain duplicate-ID checks.60The standalone engine profile MAY omit pack-only identity fields and SHALL not61silently inherit pack limits. Pack policy errors SHALL preserve the canonical62field path and SHALL occur before catalog registration.6364#### Scenario: A standalone fixture remains playable without a pack ID6566- **WHEN** a valid direct engine fixture has width, height, and objects but no67 `id`68- **THEN** direct game creation succeeds with canonical gameplay data6970#### Scenario: Pack identity is required before installation7172- **WHEN** a CommonJS pack contains a level without a stable lowercase `id`73- **THEN** preview reports the level path, rejects the pack atomically, and74 leaves existing catalog content unchanged7576### Requirement: Error adapters SHALL preserve canonical issue identity7778The shared boundary SHALL report stable issue codes and source paths. The79engine adapter SHALL retain its level-labeled `TypeError`/`RangeError` style;80the CommonJS adapter SHALL retain `ModValidationError` paths and source81context; and the shared decoder SHALL retain its player-readable invalid-pack82error. Adapters MAY add filename, pack, or level labels but SHALL not duplicate83structural validation or alter issue severity.8485#### Scenario: One malformed object has equivalent diagnostics8687- **WHEN** `objects[0]` has an invalid coordinate type through all three input88 paths89- **THEN** each path reports the same structural issue code and object index,90 while retaining its existing caller-specific error envelope9192### Requirement: Canonical data SHALL round-trip through sharing and export9394CommonJS export and data-only shared encoding SHALL serialize canonical level95data only. Decoding or loading SHALL revalidate through the boundary before96returning normalized data. A valid canonical level SHALL preserve gameplay97fields through CommonJS export/import and share encode/decode, including98automata metadata and optional authored level metadata.99100#### Scenario: Export/share parity preserves gameplay101102- **WHEN** a pack with words, objects, automata, and level metadata is exported103 and shared, then imported through both supported paths104- **THEN** both results compare equal on canonical gameplay data and create105 games with matching initial snapshots and first accepted transitions106107#### Scenario: Invalid shared data cannot bypass the boundary108109- **WHEN** a shared payload contains malformed level data or unsupported110 metadata111- **THEN** decoding fails before catalog installation and does not execute112 CommonJS or leave partial content registered113114### Requirement: Boundary parity SHALL be a release gate115116The project SHALL maintain focused fixtures covering canonical valid levels,117legacy shorthand, invalid coordinates, duplicate IDs, invalid tokens,118automaton action errors, and share/export round trips. The gate SHALL run the119direct engine, CommonJS loader, and data-only sharing paths against those120fixtures, followed by the full Node suite and production build.121122#### Scenario: Parity fixtures catch validator drift123124- **WHEN** one path accepts or normalizes a fixture differently from the125 canonical boundary126- **THEN** the focused parity test fails with the path and issue difference127 before the change can be marked complete