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-stabilize-active-level-identity / specs / active-level-identity / spec.md
spec.md 3.3K rendered
1## ADDED Requirements23### Requirement: The active level SHALL use a stable catalog identity45The application SHALL use the existing `${packId}:${localId}` level ID as the6canonical active-level identity. Numeric indexes MAY select a level but SHALL7not be used as the durable identity across catalog mutations.89#### Scenario: Selection survives unrelated registration1011- **WHEN** the active level is selected and another pack is registered before12 it13- **THEN** the same stable active level ID remains selected and resolves to the14 same level1516#### Scenario: Replacement preserves an existing local level1718- **WHEN** a pack is replaced with the same pack ID and still contains the19 active local level ID20- **THEN** the active stable ID is preserved and resolves to the replacement21 level2223#### Scenario: Replacement removes the active local level2425- **WHEN** a pack replacement omits the active local level26- **THEN** selection falls back to the replacement pack's first level or the27 first available catalog level, and no stale ID remains active2829### Requirement: Catalog reads SHALL preserve clone safety without repeated full clones3031Single-level and active-level reads SHALL resolve directly from normalized32catalog records. Full-list compatibility methods SHALL continue returning33fresh caller-owned data, while internal derived views SHALL be invalidated on34pack register, replacement, and removal.3536#### Scenario: A caller cannot mutate a cached catalog record3738- **WHEN** a caller mutates a level returned by a catalog read39- **THEN** a later read returns the normalized authored value4041#### Scenario: Replacement invalidates level and pack views4243- **WHEN** a pack is replaced with changed metadata or levels44- **THEN** subsequent reads return only replacement data and no stale cached45 level, pack, or level count4647#### Scenario: Removal invalidates active and list views4849- **WHEN** an imported pack is removed50- **THEN** subsequent reads omit its levels and the active ID resolves to a51 remaining level or `null`5253### Requirement: Progress and win handoffs SHALL resolve by stable identity5455Progress marking, win promotion, continue navigation, and pack refresh SHALL56re-resolve the captured stable level ID before acting. A catalog mutation or57level transition SHALL not allow an old numeric index or reused authored ID to58promote the wrong level.5960#### Scenario: A win callback cannot promote a replaced level6162- **WHEN** a level is won and its pack is replaced before the delayed win63 handoff runs64- **THEN** the callback promotes only the still-resolved stable level ID or65 safely abandons the stale handoff6667#### Scenario: Progress remains attached to pack and local IDs6869- **WHEN** levels are reordered by registration or an unrelated pack changes70- **THEN** solved progress remains attached to the original `packId` and71 `localId`7273### Requirement: Cache invalidation SHALL be observable at mutation boundaries7475Catalog mutations SHALL invalidate all derived active-level, pack-summary, and76level-lookup views that can contain changed records. The invalidation SHALL77occur before the mutation result is returned to application callers.7879#### Scenario: Replace refreshes summaries immediately8081- **WHEN** a pack replacement changes its name, world metadata, or level count82- **THEN** the next pack and level reads expose replacement summaries without a83 refresh-only workaround