- commit
- 2dd42fc28864aa8a3031ba340f02d3ef33f22e52
- parent
- 6a711794180dfae5ff712b8b017352e9ee1fb916
- author
- Dami <dami.etoile@gmail.com>
No content changes.
No content changes.
No content changes.
No content changes.
No content changes.
@@ -0,0 +1,86 @@
1+# active-level-identity Specification2+3+## Purpose4+TBD - created by archiving change stabilize-active-level-identity. Update Purpose after archive.5+## Requirements6+### Requirement: The active level SHALL use a stable catalog identity7+8+The application SHALL use the existing `${packId}:${localId}` level ID as the9+canonical active-level identity. Numeric indexes MAY select a level but SHALL10+not be used as the durable identity across catalog mutations.11+12+#### Scenario: Selection survives unrelated registration13+14+- **WHEN** the active level is selected and another pack is registered before15+ it16+- **THEN** the same stable active level ID remains selected and resolves to the17+ same level18+19+#### Scenario: Replacement preserves an existing local level20+21+- **WHEN** a pack is replaced with the same pack ID and still contains the22+ active local level ID23+- **THEN** the active stable ID is preserved and resolves to the replacement24+ level25+26+#### Scenario: Replacement removes the active local level27+28+- **WHEN** a pack replacement omits the active local level29+- **THEN** selection falls back to the replacement pack's first level or the30+ first available catalog level, and no stale ID remains active31+32+### Requirement: Catalog reads SHALL preserve clone safety without repeated full clones33+34+Single-level and active-level reads SHALL resolve directly from normalized35+catalog records. Full-list compatibility methods SHALL continue returning36+fresh caller-owned data, while internal derived views SHALL be invalidated on37+pack register, replacement, and removal.38+39+#### Scenario: A caller cannot mutate a cached catalog record40+41+- **WHEN** a caller mutates a level returned by a catalog read42+- **THEN** a later read returns the normalized authored value43+44+#### Scenario: Replacement invalidates level and pack views45+46+- **WHEN** a pack is replaced with changed metadata or levels47+- **THEN** subsequent reads return only replacement data and no stale cached48+ level, pack, or level count49+50+#### Scenario: Removal invalidates active and list views51+52+- **WHEN** an imported pack is removed53+- **THEN** subsequent reads omit its levels and the active ID resolves to a54+ remaining level or `null`55+56+### Requirement: Progress and win handoffs SHALL resolve by stable identity57+58+Progress marking, win promotion, continue navigation, and pack refresh SHALL59+re-resolve the captured stable level ID before acting. A catalog mutation or60+level transition SHALL not allow an old numeric index or reused authored ID to61+promote the wrong level.62+63+#### Scenario: A win callback cannot promote a replaced level64+65+- **WHEN** a level is won and its pack is replaced before the delayed win66+ handoff runs67+- **THEN** the callback promotes only the still-resolved stable level ID or68+ safely abandons the stale handoff69+70+#### Scenario: Progress remains attached to pack and local IDs71+72+- **WHEN** levels are reordered by registration or an unrelated pack changes73+- **THEN** solved progress remains attached to the original `packId` and74+ `localId`75+76+### Requirement: Cache invalidation SHALL be observable at mutation boundaries77+78+Catalog mutations SHALL invalidate all derived active-level, pack-summary, and79+level-lookup views that can contain changed records. The invalidation SHALL80+occur before the mutation result is returned to application callers.81+82+#### Scenario: Replace refreshes summaries immediately83+84+- **WHEN** a pack replacement changes its name, world metadata, or level count85+- **THEN** the next pack and level reads expose replacement summaries without a86+ refresh-only workaround