Commit Graph

2 Commits

Author SHA1 Message Date
ca54bf0f82 feat(progression): read surface and change announcements (slice 10a)
reads for the UI: TotalCoins, Lives, IsRunOver, CurrentLevel,
LevelOf/IsOwned/CanAfford, HasCleared. The read half of candidate 01 -
callers get a narrow surface instead of reaching into state.

new domain events LivesChanged / TotalCoinsChanged / SkillSetChanged,
announced by comparing against the last announced value, so an operation
can neither forget to announce nor announce something unchanged.

HandlePlayerDeath now clears the spent attempt - it was still counting
towards TotalCoins after its ledger had been discarded.

republisher and EventBus extended; SkillSetChanged is what SkillManager
will reconcile against instead of the non-atomic call pairs. 65 tests.
2026-07-28 19:50:05 +02:00
627900b2e8 feat(progression): composition root and event republisher (slice 9)
ProgressionRoot autoload builds the JSON stores from
GlobalizePath("user://"), loads the Profile, reads the authored upgrade
tables into a SkillCatalogue, and owns the ProgressionService. Every
mutating operation is wrapped so draining and republishing cannot be
forgotten - the one risk of the DrainEvents design, now confined to one
file.

ProgressionEventRepublisher turns domain records into EventBus signals
(ADR-0004), so existing subscribers and scene wiring keep working. New
RunEnded signal: GameOverScreen reads Lives directly today, which is the
last-life soft-lock.

Registered after SkillManager, since the skill catalogue is built from
AvailableSkills. GameStateStore stays until slice 10 moves the callers.

Transitional: LevelStarted is republished with a catalogue index because
GhostManager names files ghost_level_{index}.json.
2026-07-28 19:43:04 +02:00