Commit Graph

6 Commits

Author SHA1 Message Date
7a69292066 feat(progression): json stores on a real filesystem (slice 8)
new progression.adapters project, no engine reference. Stores take a
directory path; Godot resolves user:// with GlobalizePath and passes it
in, which is what makes them testable at all - originally I'd written
this slice off as untestable.

version lives in a file envelope, not the snapshot, so the domain only
knows the current shape. A newer-build save reports Corrupt with a
reason instead of masquerading as "no save" and getting overwritten.

atomic write via temp + rename. One file per aggregate: saving a run
leaves the profile file byte-identical, asserted.

guard rail fixed - it was matching prose in doc comments, now anchored
to using-directives plus a project.assets.json check. 63 tests.
2026-07-28 19:35:43 +02:00
ffa2b986ae feat(progression): Playthrough aggregate (slice 3)
no LoseLife (ADR-0005). SettleDeath / SettleCompletion defer to the
Attempt's terminal outcome, so both are atomic and idempotent.
SettleCompletion branches on HasCleared itself - a Replay cannot bank
or move campaign position backwards (ADR-0003).

Campaign value object holds authored level order; ReachableLevels is
derived, replacing the stored UnlockedLevels. Coins.IsAtLeast driven
out by cross-scope affordability.

29 tests. CONTEXT.md: Campaign, Settle.
2026-07-28 18:52:20 +02:00
40bd5c1d86 feat(progression): Attempt ledger with terminal-outcome guard (slice 2)
Attempt carries its LevelId so settlement decides First Clear vs Replay
without trusting the caller. Outcome is terminal and refuses to change:
one death costs one life, one completion banks once.

Coins.Zero/Add driven out by the ledger rather than added up front.
21 tests. ADR-0005: Playthrough settles Attempts, has no LoseLife.
2026-07-28 18:40:20 +02:00
313a5315b1 feat(progression): Coins, LevelTime, SkillLevel core invariants (slice 1)
three bug-encoding invariants, one red/green cycle each:
- Coins.TrySubtract fails instead of clamping
- LevelTime rejects zero (continued-run zero best-times)
- SkillLevel has no zero (unowned is absence, not Level=1)

plan: drop signed NetCoins; add Attempt outcome as idempotency guard
2026-07-28 18:22:46 +02:00
c3bbf3282a chore: scaffold progression domain + test projects (slice 0)
net8.0 classlib, no engine ref, EnableDynamicLoading; xunit test project
referencing domain only; excluded from Godot's **/*.cs glob; .gdignore both
2026-07-28 18:14:24 +02:00
dd113af786 docs: progression CONTEXT, ADRs 0001-0004, phase A plan
ignore .idea/ .superpowers/ bin/ obj/; drop 3 identical csproj backups
2026-07-28 18:11:01 +02:00