Skip to content

fix(#614): game total score exceeding max (level1 + levelTemp double-count)#615

Merged
atlas-apex merged 1 commit into
devfrom
fix/GH-614-game-score
Jun 9, 2026
Merged

fix(#614): game total score exceeding max (level1 + levelTemp double-count)#615
atlas-apex merged 1 commit into
devfrom
fix/GH-614-game-score

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes the game total score exceeding the max (you caught it: the share text read "1188 / 1100", and the breakdown summed to 922, not the shared total).
  • Root cause — two levels called addScore() per round (so state.score got the sum of the rounds) while recording only the average in state.levelScores (what the results breakdown shows):
    • level1 (Token splitter) — 3 rounds × per-round addScore(rs), recorded avg. Over-added ~200.
    • levelTemp (Temperature dial) — per-round addScore(pts), recorded avg. Over-added ~67. Plus a double-division bug: pts = rs/3 and then avg = totalScore/SCEN.length, which capped the level at ~33/100 even on a perfect play (why it showed 33).
    • 200 + 67 ≈ the 266 gap between 1188 (state.score) and 922 (Σ levelScores).
  • Fix — drop the per-round addScore; call addScore(avg) once at each level's finish (after levelScores is set), so every level contributes exactly its recorded 0–100 (the pattern level6 already uses). In levelTemp, accumulate totalScore += rs (not rs/3) so the average is true and a perfect run scores 100. Net: total maxes at 1100 and matches the breakdown.

Testing

  1. node --check on the inline script — clean; LEVELS still 11; addScore is now called once per level (11 calls + the definition).
  2. No per-round addScore(rs|pts|roundScore) remain; the pts double-division variable is removed.
  3. Play-through: total can no longer exceed 1100; Temperature scores up to 100 on a correct/in-band answer.

Closes #614


Glossary

Term Definition
state.score The running total shown in the score pill + share text.
state.levelScores[] Per-level scores in the results breakdown (last value per level).
Over-count state.score receiving more additions than the per-level scores sum to.

state.score could exceed the 1100 max (observed share text "1188/1100") and
didn't match the per-level breakdown. Two levels called addScore() per round
(summing into state.score) but recorded only the average in levelScores:

- level1 (Token splitter): drop the per-round addScore(rs); call addScore(avg)
  once at finish, after levelScores is set — so the level contributes its
  recorded 0-100 exactly once (matching every other level / level6's pattern).
- levelTemp (Temperature dial): same per-round fix, plus fix a double-division
  (pts = rs/3 then avg = totalScore/SCEN.length capped the level at ~33 even on
  a perfect play). Now accumulate totalScore += rs so avg is the true average
  and a perfect run scores 100.

Result: every level adds exactly its 0-100 to state.score once; total maxes at
1100 and matches the breakdown. node --check clean; LEVELS still 11.

Closes #614

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #615

Commit: 3bf04a434a1a4d08441fa6b5f30872278cf96682

Summary

Fixes a scoring bug in site/game.html where the game total could exceed the 1100 max (share text showed "1188/1100") and didn't match the per-level breakdown. Two levels called addScore() per round (summing rounds into state.score) while recording only the average in state.levelScores. The fix drops the per-round adds and calls addScore(avg) once at each level's finish — the pattern the other 9 levels already use. levelTemp also had a double-division (pts = rs/3 then avg = totalScore/SCEN.length) that capped the level at ~33 on a perfect play; now totalScore += rs so the average is true. Diff: +3/-5, single file.

Verification

  • node --check on the inline script: clean. One inline <script> block; parses without error.
  • LEVELS still 11 — render entries: level1, level2, levelTemp, level3, levelCutoff, level4, level5, level6, level7, levelCost, levelLoop.
  • The invariant holds across all 11 levels. Every state.levelScores[state.level] = X write is immediately followed by addScore(X) with the identical variable — verified by pairing all 11 sites:
    • level1@1273 avg → addScore@1274 avg
    • level2@1360 sc@1361 sc
    • levelTemp@2245 avg@2246 avg
    • level3@1522 sc@1523 sc
    • levelCutoff@1704 sc@1705 sc
    • level4@1803 sc@1804 sc
    • level5@2090 sc@2091 sc
    • level6@1930 totalScore@1931 totalScore (legitimately once = its levelScores; fine)
    • level7@2343 sc@2344 sc
    • levelCost@2475 sc@2476 sc
    • levelLoop@2600 sc@2601 sc
    • No level adds per-round or adds a value different from what it records. addScore does a bare state.score += n (no clamp), so state.score === Σ levelScores, max = 11 × 100 = 1100. Defect fixed.
  • levelTemp: pts fully removed (the only remaining pts is the literal UI string 'SKIP? (0 pts)', not the variable — no dangling reference). totalScore += rs correct; rs declared in the lock handler and in scope where used. Perfect in-band play → every round rs=100avg = Math.round(totalScore/SCEN.length) = 100 (no longer 33). addScore(avg) is in the finish branch.
  • level1: rs still computed (Math.round((correct/real.size)*100 - wrong*15 - missed*12), clamped 0–100) and totalScore += rs per round retained — the removed line was only addScore(rs). rs still used for the per-round comparison display. avg = Math.round(totalScore / ROUNDS.length) unchanged. addScore(avg) is in the finish else branch, not per round.
  • No other behavior changed; diff matches the stated +3/-5.

Checklist Results

  • ✅ Architecture & Design: Pass (static single-file change, no layering concern)
  • ✅ Code Quality: Pass (minimal, surgical, removes the double-division dead path)
  • ✅ Testing: Pass (node --check is the project's gate for this static site; clean. No test suite by design)
  • ✅ Security: Pass (no auth/secrets/user-data; pure client-side scoring)
  • ✅ Performance: Pass (no hot-path or query changes)
  • ✅ PR Description & Glossary: Pass (Summary + Testing + Glossary all present; narrative bullets)
  • ✅ Summary Bullet Narrative: Pass (each bullet states what + why)
  • ✅ Technical Decisions (AgDR): N/A (bug fix, no library/architecture/pattern decision)
  • ✅ Adopter Handbooks: N/A (no architecture/general/language violations triggered)

Issues Found

None.

Handbook Findings

  • Migration Safety (blocking): not triggered — no migration files in the diff.
  • Clean Architecture Layers (advisory): N/A — single static HTML file, no cross-layer imports.
  • Commit Message Quality (advisory): Pass — commit 3bf04a4 has a descriptive WHY-bearing subject and a body explaining problem, root cause, the two fixes with rationale, result, and verification. Single Closes #614, co-authorship line present.

Suggestions

None blocking. (Optional, for a future PR: the per-level scoring pattern is now uniform — a one-line console.assert(state.score === state.levelScores.reduce(...)) dev-only guard could lock the invariant in if the game grows past 11 levels. Not needed for this fix.)

Verdict

APPROVED

PR body has Summary + Testing + Glossary; Closes #614 (issue OPEN); commit SHA matches HEAD (3bf04a4...). Base is dev, single file, +3/-5.


🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: 3bf04a434a1a4d08441fa6b5f30872278cf96682

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #615

Commit: 3bf04a434a1a4d08441fa6b5f30872278cf96682

Summary

Fixes a scoring bug in site/game.html where the game total could exceed the 1100 max (share text showed "1188/1100") and didn't match the per-level breakdown. Two levels called addScore() per round (summing rounds into state.score) while recording only the average in state.levelScores. The fix drops the per-round adds and calls addScore(avg) once at each level's finish — the pattern the other 9 levels already use. levelTemp also had a double-division (pts = rs/3 then avg = totalScore/SCEN.length) that capped the level at ~33 on a perfect play; now totalScore += rs so the average is true. Diff: +3/-5, single file.

Verification

  • node --check on the inline script: clean. One inline <script> block; parses without error.
  • LEVELS still 11 — render entries: level1, level2, levelTemp, level3, levelCutoff, level4, level5, level6, level7, levelCost, levelLoop.
  • The invariant holds across all 11 levels. Every state.levelScores[state.level] = X write is immediately followed by addScore(X) with the identical variable — verified by pairing all 11 sites:
    • level1@1273 avg → addScore@1274 avg
    • level2@1360 sc@1361 sc
    • levelTemp@2245 avg@2246 avg
    • level3@1522 sc@1523 sc
    • levelCutoff@1704 sc@1705 sc
    • level4@1803 sc@1804 sc
    • level5@2090 sc@2091 sc
    • level6@1930 totalScore@1931 totalScore (legitimately once = its levelScores; fine)
    • level7@2343 sc@2344 sc
    • levelCost@2475 sc@2476 sc
    • levelLoop@2600 sc@2601 sc
    • No level adds per-round or adds a value different from what it records. addScore does a bare state.score += n (no clamp), so state.score === Σ levelScores, max = 11 × 100 = 1100. Defect fixed.
  • levelTemp: pts fully removed (the only remaining pts is the literal UI string 'SKIP? (0 pts)', not the variable — no dangling reference). totalScore += rs correct; rs declared in the lock handler and in scope where used. Perfect in-band play → every round rs=100avg = Math.round(totalScore/SCEN.length) = 100 (no longer 33). addScore(avg) is in the finish branch.
  • level1: rs still computed (Math.round((correct/real.size)*100 - wrong*15 - missed*12), clamped 0–100) and totalScore += rs per round retained — the removed line was only addScore(rs). rs still used for the per-round comparison display. avg = Math.round(totalScore / ROUNDS.length) unchanged. addScore(avg) is in the finish else branch, not per round.
  • No other behavior changed; diff matches the stated +3/-5.

Checklist Results

  • ✅ Architecture & Design: Pass (static single-file change, no layering concern)
  • ✅ Code Quality: Pass (minimal, surgical, removes the double-division dead path)
  • ✅ Testing: Pass (node --check is the project's gate for this static site; clean. No test suite by design)
  • ✅ Security: Pass (no auth/secrets/user-data; pure client-side scoring)
  • ✅ Performance: Pass (no hot-path or query changes)
  • ✅ PR Description & Glossary: Pass (Summary + Testing + Glossary all present; narrative bullets)
  • ✅ Summary Bullet Narrative: Pass (each bullet states what + why)
  • ✅ Technical Decisions (AgDR): N/A (bug fix, no library/architecture/pattern decision)
  • ✅ Adopter Handbooks: N/A (no architecture/general/language violations triggered)

Issues Found

None.

Handbook Findings

  • Migration Safety (blocking): not triggered — no migration files in the diff.
  • Clean Architecture Layers (advisory): N/A — single static HTML file, no cross-layer imports.
  • Commit Message Quality (advisory): Pass — commit 3bf04a4 has a descriptive WHY-bearing subject and a body explaining problem, root cause, the two fixes with rationale, result, and verification. Single Closes #614, co-authorship line present.

Suggestions

None blocking. (Optional, for a future PR: the per-level scoring pattern is now uniform — a one-line console.assert(state.score === state.levelScores.reduce(...)) dev-only guard could lock the invariant in if the game grows past 11 levels. Not needed for this fix.)

Verdict

APPROVED

PR body has Summary + Testing + Glossary; Closes #614 (issue OPEN); commit SHA matches HEAD (3bf04a4...). Base is dev, single file, +3/-5.


🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: 3bf04a434a1a4d08441fa6b5f30872278cf96682

@atlas-apex atlas-apex merged commit 2224a53 into dev Jun 9, 2026
7 checks passed
@atlas-apex atlas-apex deleted the fix/GH-614-game-score branch June 9, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants