Skip to content

refactor(server): dedupe award handlers and mutate-then-report response tail#158

Merged
QMalcolm merged 2 commits into
mainfrom
qmalcolm--refactor-dedupe-award-response-tail
Jul 21, 2026
Merged

refactor(server): dedupe award handlers and mutate-then-report response tail#158
QMalcolm merged 2 commits into
mainfrom
qmalcolm--refactor-dedupe-award-response-tail

Conversation

@QMalcolm

@QMalcolm QMalcolm commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Closes #130.

What

Two commits, one per dedupe target from the issue:

  1. Shared response tail — the resolved_statepending_choicesserialize_characterMap.put(:pending_choices, ...) sequence was repeated at five handler tails (build_finish, both award clauses, both resolve_choice clauses), four of them calling parse_display_mode(msg) twice. character_with_choices_response/4 now owns the sequence and parses the display mode exactly once per request. (build_finish had already drifted into a differently-shaped copy of the same logic — now it's the same call as everyone else.)

  2. One award handler — the two characters.award clauses merged into one that branches on Map.fetch(msg, "value"). The branch returns {value, response_extras} so the value source and its :awarded_xp enrichment stay paired: the key appears only when the server computed the amount, preserving response shapes exactly.

Notes

  • Map.fetch rather than Map.get preserves an edge case of the old pattern-match dispatch: an explicit JSON null value still takes the explicit-value path (failing in apply_award!) instead of being reinterpreted as a computed award.
  • Net −35 lines across the two commits.

No behavior change; all 389 tests pass unchanged, credo and dialyzer clean.

Summary by Bito

  • Refactored character response generation into a new helper function `character_with_choices_response` to reduce code duplication across multiple handlers.
  • Removed redundant `handle` function for `characters.award` that accepted a specific value, consolidating logic into the main award handler.
  • Updated `characters.award` handler to dynamically compute award values when not provided, returning the computed amount in the response.
  • Standardized response structure for character mutation commands (award, decision, etc.) using the new helper.

QMalcolm added 2 commits July 20, 2026 20:21
Part of #130.

The resolved_state -> pending_choices -> serialize_character ->
Map.put(:pending_choices, ...) sequence was repeated at five handler
tails (build_finish, both award clauses, both resolve_choice clauses).
Four of the five also called parse_display_mode(msg) twice in the same
pipeline — harmless today because the parse is pure, but a trap if
display-mode resolution ever grows side effects or cost, and a source
of drift if one site's copy is updated and the others are not
(build_finish had already drifted into a differently-shaped copy of
the same logic).

character_with_choices_response/4 now owns the sequence, parses the
display mode exactly once per request, and lives with the other
response helpers. The award handler's :awarded_xp enrichment stays at
its call site via Map.put on the returned map, since it is specific to
that command rather than part of the shared shape.
Closes #130.

The explicit-value and computed-value award handlers were ~90%
identical: same load/lookup/apply_award!/compute_pending_choice_slots/
save/respond sequence, differing only in where the value came from
(the request vs compute_next_level_xp!) and the :awarded_xp key on the
computed-value response.

One clause now handles both, branching on Map.fetch(msg, "value").
The branch returns {value, response_extras} so the value source and
its response enrichment stay paired in one place — :awarded_xp only
appears when the server computed the amount, which preserves the
response shapes exactly.

Map.fetch (not Map.get) keeps an edge case identical to the old
pattern-match dispatch: a request carrying an explicit null value
matched the explicit-value clause before, and still takes the
explicit-value branch now, failing in apply_award! rather than being
reinterpreted as a computed award.
@QMalcolm
QMalcolm merged commit b1f5af0 into main Jul 21, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(server): dedupe award handlers and mutate-then-report response tail

1 participant