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-packs / spec.md
spec.md 4.6K source

level-packs Specification

Purpose

TBD - created by archiving change share-level-packs. Update Purpose after archive.

Requirements

Requirement: Packs and levels SHALL have stable identities

Every pack SHALL have a stable lowercase pack id, display name, version, and ordered levels. Every level SHALL have a stable level id unique within its pack. Registry keys SHALL use the pair { packId, levelId }, and display titles SHALL not be used as identity.

Scenario: A renamed level keeps its identity

  • WHEN a pack changes a level title but retains its pack id and level id
  • THEN the registry treats it as the same level identity and updates only display metadata

Scenario: Duplicate level ids are rejected within a pack

  • WHEN a pack contains two levels with the same level id
  • THEN pack validation fails before either level is registered

Requirement: The app SHALL ship curated bundled packs

The app SHALL include a curated set of valid bundled packs, including the original three MIAU teaching puzzles as one ordered teaching pack. Bundled packs SHALL be available without a local file or URL import and SHALL pass the same identity and level validation as imported packs.

Scenario: The teaching pack is available on a clean start

  • WHEN the app starts without imported content
  • THEN the registry contains the MIAU teaching pack and its three original levels in stable order

Scenario: A bundled pack has invalid data

  • WHEN a bundled pack fails validation during startup
  • THEN the app reports the pack id and validation error and keeps other valid bundled packs available

Requirement: The registry SHALL retain multiple loaded packs

The registry SHALL retain every valid bundled, URL, and explicitly trusted local pack loaded during the session. Each pack SHALL retain its origin metadata, and selecting one pack or level SHALL not discard other valid registered content.

Scenario: Two local packs remain selectable

  • WHEN the player loads two valid packs with different pack ids
  • THEN both packs appear in the pack registry and levels from either pack can be selected

Scenario: A failed pack does not remove earlier content

  • WHEN a later import fails validation or execution
  • THEN previously registered packs remain selectable and the failed pack is absent

Requirement: The registry SHALL apply an explicit collision policy

The registry SHALL present an explicit choice when a pack id collides: Replace, which keeps the authored id and its progress, or Keep both as a copy, which creates a new fork id using the next available -2, -3, and so on suffix, records forkOf as the original id, and starts progress under the new id. A level id collision SHALL be scoped to its pack id; identical level ids in different packs SHALL coexist. Both replacement and forking SHALL validate atomically and preserve the existing pack if validation fails.

Scenario: A pack id collision offers explicit choices

  • WHEN a newly loaded pack uses an existing pack id
  • THEN the app offers Replace and Keep both as a copy, and does not change the registry until one choice is made

Scenario: Keep both creates a fresh fork

  • WHEN the player chooses Keep both as a copy for pack garden-basics
  • THEN the registry installs the imported pack under the next available id such as garden-basics-2, records forkOf: garden-basics, and starts progress under the fork id

Scenario: Replace preserves authored identity

  • WHEN the player chooses Replace for an existing pack id
  • THEN the new pack keeps that authored id and its existing progress key, subject to complete validation

Scenario: Same level id in different packs is allowed

  • WHEN two registered packs each contain a level id intro
  • THEN both levels remain addressable by their { packId, levelId } pair

Requirement: Pack selection SHALL identify the active content

The app SHALL expose the active pack id and level id to the engine and UI, and SHALL load a selected valid level through the existing engine validation path. A pack selection failure SHALL leave the previously active level playable.

Scenario: Selecting a level changes active identity

  • WHEN the player selects level intro from pack garden-basics
  • THEN the active selection reports both ids and the engine loads that level's validated data

Scenario: Selecting an unknown level is harmless

  • WHEN a stale link or UI action requests an unknown pack/level pair
  • THEN the app reports the missing identity and retains the current playable level