Matriz de rastreabilidade — v3¶
Uma linha por critério de aceitação de requirements.md, ligando o
requisito à seção de design.md que o resolve, à task de
tasks.md que o implementa e ao(s) teste(s) que o comprovam.
O documento é vigiado por tests/test_traceability.py, que falha o build quando um critério
de aceitação não aparece aqui ou quando esta matriz referencia um teste inexistente (R32.2,
R32.3). É o que impede a matriz de envelhecer em silêncio.
Completa até a task 82. Todo critério
R1.1–R36.3derequirements.mdtem uma linha. Para os critérios cuja task implementadora ainda está pendente nesta versão (tasks 72–73 — build do APK em aparelho real e registro dos números medidos), a coluna Testes fica em branco: citar um teste ali seria inventar uma referência quetests/test_traceability.pyrejeitaria. Critérios cuja implementação (tasks 65, 66, 69, 71) já existe mas não tem um teste dedicado — o gate é o próprioruff/mkdocs build --strict/pytest-cov, ou o critério é sobre o conteúdo doREADME.mdem si — também ficam em branco pelo mesmo motivo. Critérios que só um aparelho Android real comprova, sem nenhum caminho automatizável no desktop, usam o marcadormanual, seguindo o quetasks.mdjá separa em "Requer aparelho Android real".
| Critério | Design | Task | Testes |
|---|---|---|---|
| R1.1 | 5 | 3 | test_bird.py::test_flap_sets_impulse_and_upward_angle, test_input.py::test_mouse_and_touch_at_the_same_physical_point_agree |
| R1.2 | 5 | 3 | test_bird.py::test_gravity_accumulates_each_frame |
| R1.3 | 5 | 3 | test_bird.py::test_flap_sets_impulse_and_upward_angle, test_bird.py::test_angle_interpolates_down_while_falling, test_bird.py::test_angle_never_exceeds_max_down |
| R1.4 | 5 | 3 | test_bird.py::test_top_of_screen_clamps_position_without_negative_velocity |
| R2.1 | 6 | 4 | test_pipes.py::test_spawns_new_pipe_at_fixed_spacing |
| R2.2 | 6 | 4 | test_pipes.py::test_gap_is_within_safe_margins, test_pipes.py::test_new_pipe_freezes_current_gap_size_and_textures |
| R2.3 | 6 | 4 | test_pipes.py::test_update_moves_pipes_left_by_speed |
| R2.4 | 6 | 4 | test_pipes.py::test_pipe_removed_once_fully_off_screen |
| R2.5 | 6, 34 | 4, 54 | test_pipes.py::test_the_strips_draw_exactly_what_the_v2_loop_drew, test_pipes.py::test_a_pipe_of_another_biome_gets_its_own_pair_of_strips |
| R3.1 | 6, 16 | 5 | test_game.py::test_collision_with_ground_ends_round |
| R3.2 | 9 | 10 | test_game.py::test_collision_with_ground_ends_round |
| R3.3 | 3, 12 | 6 | test_ui_layout.py::test_game_over_screen_texts_do_not_overlap |
| R3.4 | 3 | 6 | test_game.py::test_flap_in_game_over_resets_to_pronto |
| R3.5 | 6, 16 | 5, 14 | test_bird.py::test_hitbox_is_scaled_and_centered_on_sprite |
| R3.6 | 6 | 82 | test_game.py::test_collides_requires_the_minimum_overlap_in_both_axes, test_game.py::test_a_shallow_corner_graze_does_not_end_the_round, test_game.py::test_an_overlap_past_the_corner_tolerance_still_ends_the_round |
| R4.1 | 8 | 7 | test_game.py::test_score_increments_once_per_pipe |
| R4.2 | 8, 12 | 7 | test_ui_layout.py::test_hud_score_text_in_bounds |
| R4.3 | 8, 36 | 22, 60 | test_score.py::test_save_and_load_roundtrip, test_game.py::test_reaching_game_over_writes_the_record |
| R4.4 | 8 | 7 | test_score.py::test_missing_file_falls_back_to_zero, test_score.py::test_corrupted_json_falls_back_to_zero, test_score.py::test_missing_key_falls_back_to_zero, test_score.py::test_wrong_type_falls_back_to_zero |
| R4.5 | 23 | 22, 33 | test_storage.py::test_save_dir_desktop_is_project_root, test_storage.py::test_save_dir_frozen_desktop_uses_executable_dir, test_storage.py::test_save_dir_android_uses_app_storage_path |
| R5.1 | 7 | 8 | test_biome.py::test_starts_on_overworld, test_biome.py::test_threshold_10_activates_cave, test_biome.py::test_threshold_25_activates_nether |
| R5.2 | 7 | 8 | test_pipes.py::test_new_pipe_uses_new_biome_params |
| R5.3 | 7 | 12 | test_pipes.py::test_new_pipe_freezes_current_gap_size_and_textures |
| R5.4 | 7 | 8 | test_biome.py::test_the_biome_fade_uses_image_alpha |
| R6.1 | 3, 12 | 6 | test_game.py::test_starts_in_pronto_state, test_ui_layout.py::test_ready_screen_texts_do_not_overlap |
| R6.2 | 3 | 6 | test_game.py::test_flap_in_pronto_transitions_to_jogando |
| R6.3 | 3, 12 | 6 | test_game.py::test_pause_toggle_freezes_physics, test_ui_layout.py::test_paused_overlay_texts_do_not_overlap |
| R6.4 | 3 | 6 | test_game.py::test_bare_tv_remote_reaches_every_state |
| R7.1 | 10 | 2 | test_render.py::test_every_generated_texture_is_converted |
| R7.2 | 5, 10 | 2, 3 | test_render.py::test_the_bee_texture_survives_the_conversion_with_its_transparency, test_bird_sprites.py::test_precompute_builds_every_combination_once |
| R7.3 | 16, 34 | 5, 53 | test_ground.py::test_the_ground_covers_the_canvas_from_edge_to_edge, test_ground.py::test_a_ground_frame_is_a_single_draw_call |
| R7.4 | 17, 34 | 9, 55 | test_decor.py::test_a_parallax_frame_takes_at_most_four_draw_calls, test_decor.py::test_the_strip_draws_exactly_what_the_v2_loop_drew |
| R7.5 | 12, 19 | 6, 20 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap |
| R7.6 | 19 | 20 | test_render.py::test_the_font_cache_is_filled_with_converted_surfaces, test_perf.py::test_lines_usa_apenas_glifos_existentes |
| R8.1 | 11 | 11 | |
| R8.2 | 11 | 11 | |
| R8.3 | 11, 12 | 11 | test_game.py::test_tap_on_mute_icon_toggles_mute_without_side_effects |
| R8.4 | 11, 14 | 11 | test_sounds.py::test_audio_that_cannot_be_opened_leaves_the_game_playable |
| R9.1 | 20 | 41 | test_game.py::test_renderer_uses_the_computed_canvas, test_scale.py::test_matching_aspect_gives_scale_one_no_offset |
| R9.2 | 2.1 | 26 | |
| R9.3 | 2.1 | 1 | |
| R9.4 | 13, 37 | 1, 63 | test_game.py::test_sixty_fps_reproduces_the_v2_frame_loop_exactly |
| R9.5 | 30 | 30 | manual |
| R10.1 | 13 | 11b | manual |
| R10.2 | 13 | 11b | manual |
| R10.3 | 13 | 11b | manual |
| R10.4 | 13 | 11b | manual |
| R10.5 | 13 | 11b | manual |
| R11.1 | 12 | 16 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap |
| R11.2 | 12 | 16 | |
| R12.1 | 12 | 17 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap |
| R12.2 | 12 | 17 | test_score.py::test_missing_file_falls_back_to_zero |
| R13.1 | 18 | 18 | manual |
| R13.2 | 18 | 19 | manual |
| R13.3 | 18, 24.3 | 29 | manual |
| R14.1 | 24.2 | 27 | test_packaging.py::test_the_android_api_range_is_the_one_the_project_promises |
| R14.2 | 24.2, 40 | 27, 62 | test_packaging.py::test_every_real_device_still_has_an_architecture |
| R14.3 | 20, 32 | 41, 45 | test_viewport.py::test_canvas_keeps_the_real_aspect_ratio, test_viewport.py::test_play_area_is_always_the_same_world_column |
| R14.4 | 24.2, 32.7, 40 | 27, 41, 48, 62 | test_packaging.py::test_the_orientation_stays_locked_in_portrait, test_resize.py::test_portrait_orientation_hint_is_set |
| R14.5 | 19 | 20 | test_render.py::test_the_font_cache_is_filled_with_converted_surfaces |
| R14.6 | 11, 14 | 30 | test_sounds.py::test_audio_that_cannot_be_opened_leaves_the_game_playable |
| R15.1 | 32.8 | 51 | test_input.py::test_tap_on_a_decorative_band_flaps, test_input.py::test_finger_tap_in_game_area_flaps |
| R15.2 | 21.2 | 23 | test_game.py::test_back_in_jogando_pauses_without_quitting |
| R15.3 | 21.2 | 23 | test_game.py::test_back_in_pronto_quits, test_game.py::test_back_in_pausado_quits, test_game.py::test_back_in_game_over_quits |
| R15.4 | 21.1, 21.3 | 23, 25 | test_input.py::test_finger_tap_on_mute_icon_mutes_not_flaps, test_input.py::test_mouse_click_on_mute_icon_mutes_not_flaps, test_game.py::test_dpad_left_right_toggle_mute_only_when_pausado |
| R15.5 | 21.3, 13 | 25 | test_game.py::test_bare_tv_remote_reaches_every_state, test_input.py::test_mouse_and_touch_at_the_same_physical_point_agree |
| R16.1 | 22 | 24 | test_game.py::test_focus_lost_pauses_during_jogando, test_game.py::test_app_background_events_also_pause |
| R16.2 | 22 | 24 | test_game.py::test_focus_lost_does_not_auto_resume |
| R16.3 | 23 | 22 | test_storage.py::test_save_dir_android_uses_app_storage_path |
| R16.4 | 36 | 60 | test_game.py::test_going_to_the_background_writes_a_pending_record, test_game.py::test_going_to_the_background_while_paused_still_writes |
| R17.1 | 24.1, 24.2 | 27, 28 | test_packaging.py::test_the_spec_is_well_formed_ini_with_the_sections_buildozer_expects |
| R17.2 | 24.3 | 29 | manual |
| R17.3 | 24.2 | 27 | test_packaging.py::test_the_orientation_stays_locked_in_portrait |
| R18.1 | 26 | 31 | |
| R18.2 | 26 | 31 | |
| R18.3 | 26 | 31 | |
| R18.4 | 26 | 31 | |
| R18.5 | 26 | 31 | |
| R18.6 | 26 | 31 | |
| R19.1 | 27 | 32 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap, test_ui_layout.py::test_paused_overlay_texts_do_not_overlap, test_ui_layout.py::test_game_over_screen_texts_do_not_overlap, test_ui_layout.py::test_hud_score_text_in_bounds |
| R19.2 | 27 | 32 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap, test_ui_layout.py::test_hud_score_text_in_bounds |
| R19.3 | 27 | 32 | test_ui_layout.py::test_game_over_screen_texts_do_not_overlap |
| R19.4 | 27 | 32 | test_ui_layout.py::test_paused_overlay_texts_do_not_overlap |
| R19.5 | 27 | 32 | test_ui_layout.py::test_ready_screen_texts_do_not_overlap, test_ui_layout.py::test_paused_overlay_texts_do_not_overlap, test_ui_layout.py::test_game_over_screen_texts_do_not_overlap |
| R20.1 | 28 | 34 | |
| R20.2 | 28 | 34 | |
| R20.3 | 28 | 34 | |
| R20.4 | 28 | 34 | |
| R20.5 | 28 | 34 | |
| R20.6 | 28 | 34 | |
| R20.7 | 28 | 34 | |
| R21.1 | 29.1 | 36 | test_generate_app_icon.py::test_foreground_bee_fits_within_safe_zone, test_generate_app_icon.py::test_composed_icon_has_requested_size |
| R21.2 | 29.3 | 36 | test_assets.py::test_asset_path_source_run_resolves_project_root, test_assets.py::test_asset_path_frozen_resolves_meipass |
| R21.3 | 29.3 | 36 | manual |
| R21.4 | 29.4 | 37 | test_generate_app_icon.py::test_foreground_bee_fits_within_safe_zone, test_generate_app_icon.py::test_background_layer_has_no_alpha_channel |
| R21.5 | 29.1, 29.4 | 37 | test_generate_app_icon.py::test_foreground_bee_fits_within_safe_zone |
| R21.6 | 29.1, 29.4 | 37 | test_generate_app_icon.py::test_composed_icon_has_requested_size |
| R21.7 | 29.1, 29.2 | 36 | test_generate_app_icon.py::test_build_ico_contains_all_sizes_and_round_trips |
| R22.1 | 31 | 42 | test_packaging.py::test_the_app_is_named_blocky_bee |
| R22.2 | 31 | 42 | test_packaging.py::test_the_app_is_named_blocky_bee |
| R22.3 | 31 | 42 | test_score.py::test_missing_file_falls_back_to_zero |
| R22.4 | 31 | 42 | manual |
| R23.1 | 32.2, 32.3 | 45 | test_viewport.py::test_bands_tile_the_canvas_without_losing_a_pixel |
| R23.2 | 32.2 | 45 | test_viewport.py::test_play_area_is_always_the_same_world_column |
| R23.3 | 32.7 | 45 | test_game.py::test_android_display_is_fullscreen_at_native_resolution |
| R23.4 | 32.3, 32.4 | 45, 46 | test_viewport.py::test_canvas_matches_the_design_table, test_viewport.py::test_canvas_keeps_the_real_aspect_ratio |
| R23.5 | 32.7, 40 | 48 | test_resize.py::test_portrait_orientation_hint_is_set, test_packaging.py::test_the_orientation_stays_locked_in_portrait |
| R23.6 | 32.7 | 48 | test_resize.py::test_resize_recomputes_the_canvas_and_keeps_the_play_area |
| R23.7 | 32.7 | 45 | test_viewport.py::test_desktop_screen_size_is_wider_than_the_play_area |
| R24.1 | 32.2, 32.4 | 45, 46 | test_viewport.py::test_play_area_is_always_the_same_world_column |
| R24.2 | 32.2 | 45, 46 | test_bands.py::test_fall_is_identical_in_both_canvases |
| R24.3 | 32.4 | 47 | test_bands.py::test_pipe_spawns_at_the_play_right_edge, test_bands.py::test_time_from_spawn_to_bird_is_the_same_in_both_canvases |
| R24.4 | 32.5 | 47 | test_bands.py::test_side_bands_hide_a_pipe_that_has_not_entered_the_play_area, test_bands.py::test_the_pipe_under_the_band_is_drawn_before_it |
| R24.5 | 32.4 | 46 | test_bands.py::test_bird_ceiling_is_the_play_top_not_the_canvas_top, test_bands.py::test_ground_line_sits_on_the_play_bottom_not_the_canvas_bottom |
| R25.1 | 32.3, 32.5 | 46, 80 | test_bands.py::test_the_phone_canvas_really_has_both_bands, test_bands.py::test_ground_fills_the_decorative_band_below_the_play_area |
| R25.2 | 32.5 | 47 | test_bands.py::test_side_band_is_opaque_over_its_whole_height, test_bands.py::test_band_ground_line_matches_the_play_ground_line |
| R25.3 | 35 | 57 | test_mobs.py::test_each_biome_has_three_varieties_and_none_repeats_across_biomes, test_mobs.py::test_every_field_carries_the_three_varieties_of_its_biome |
| R25.4 | 35 | 57 | test_mobs.py::test_the_whole_simulation_is_identical_with_and_without_mobs, test_mobs.py::test_a_mob_over_the_bird_does_not_collide, test_mobs.py::test_mobs_module_imports_nothing_from_the_game |
| R25.5 | 32.6 | 47 | test_bands.py::test_sky_parallax_and_ground_span_the_whole_canvas_width |
| R25.6 | 32.8 | 46, 51 | test_input.py::test_tap_on_a_decorative_band_flaps, test_input.py::test_tap_on_the_mute_icon_inside_the_sky_band_still_mutes |
| R25.7 | 32.5 | 46 | test_bands.py::test_hud_score_moves_into_the_sky_band, test_bands.py::test_mute_icon_sits_in_the_sky_band_when_it_fits |
| R26.1 | 33.2, 33.3 | 49 | test_render.py::test_first_level_is_the_accelerated_renderer |
| R26.2 | 33.3 | 49 | test_render.py::test_cascade_falls_to_the_sdl_chosen_renderer |
| R26.3 | 33.3, 33.4 | 49 | test_render.py::test_cascade_falls_to_the_surface_path, test_render.py::test_cascade_never_raises_to_the_caller |
| R26.4 | 33.1, 33.5 | 49, 50 | test_render.py::test_both_backends_draw_the_same_frame |
| R26.5 | 33.3, 39 | 49, 50, 43 | test_render.py::test_every_fallback_is_logged, test_perf.py::test_draw_overlay_mostra_o_backend_de_render, test_perf.py::test_game_informa_o_backend_ao_profiler |
| R26.6 | 33.2 | 49 | test_render.py::test_accelerated_renderer_is_asked_for_vsync |
| R26.7 | 33.2, 40 | 49, 61 | test_render.py::test_nearest_neighbour_scaling_is_requested |
| R27.1 | 30 | 72 | manual |
| R27.2 | 34 | 53, 54, 55, 56 | test_ground.py::test_a_ground_frame_is_a_single_draw_call, test_pipes.py::test_a_pipe_is_two_draw_calls, test_decor.py::test_a_parallax_frame_takes_at_most_four_draw_calls, test_bird_sprites.py::test_a_bird_frame_is_a_single_draw_call |
| R27.3 | 36 | 58, 59, 55 | test_alloc.py::test_a_playing_frame_stays_within_the_rect_budget, test_decor.py::test_no_random_generator_is_created_while_drawing, test_alloc.py::test_the_pipe_list_is_never_rebuilt |
| R27.4 | 34 | 52 | test_render.py::test_opaque_surface_is_converted_to_the_display_format, test_render.py::test_every_generated_texture_is_converted |
| R27.5 | 36 | 60 | test_game.py::test_beating_the_record_while_playing_does_not_touch_the_disk, test_game.py::test_no_disk_write_happens_during_a_whole_played_round, test_game.py::test_reaching_game_over_writes_the_record |
| R27.6 | 40 | 61 | test_input.py::test_the_continuous_motion_events_are_blocked, test_input.py::test_a_blocked_event_never_becomes_a_python_object |
| R27.7 | 34 | 54 | test_pipes.py::test_the_pipe_born_at_the_play_edge_is_not_drawn_on_a_2_3_canvas, test_pipes.py::test_visibility_is_decided_by_the_canvas_edges |
| R28.1 | 37 | 63 | test_game.py::test_a_sixty_fps_frame_advances_exactly_one_step |
| R28.2 | 37 | 63 | test_game.py::test_a_thirty_fps_frame_advances_two_steps, test_game.py::test_the_number_of_steps_per_frame_has_a_ceiling |
| R28.3 | 37 | 63 | test_game.py::test_a_long_stall_is_clamped_instead_of_becoming_a_leap, test_game.py::test_the_two_defences_are_consistent_and_the_inner_one_binds_first |
| R28.4 | 37 | 63 | test_game.py::test_sixty_fps_reproduces_the_v2_frame_loop_exactly |
| R29.1 | 38 | 64 | test_quality.py::test_frames_outside_playing_are_not_measured, test_quality.py::test_the_level_is_measured_and_dropped_while_playing |
| R29.2 | 38 | 64 | test_quality.py::test_sustained_low_frame_rate_drops_a_level, test_quality.py::test_each_level_turns_off_more_decoration_than_the_one_above |
| R29.3 | 38 | 64 | test_quality.py::test_the_rules_are_identical_at_every_quality_level |
| R29.4 | 38 | 64 | test_quality.py::test_the_rise_needs_a_longer_window_than_the_drop, test_quality.py::test_a_device_on_the_edge_settles_instead_of_bouncing |
| R29.5 | 38 | 64 | test_quality.py::test_the_level_survives_between_sessions, test_quality.py::test_the_file_is_written_next_to_the_highscore |
| R29.6 | 38 | 64 | test_quality.py::test_a_missing_file_means_full_quality, test_quality.py::test_a_corrupted_file_means_full_quality |
| R30.1 | 39 | 43 | test_perf.py::test_draw_overlay_mostra_o_backend_de_render, test_perf.py::test_end_update_e_end_draw_medem_intervalos_separados |
| R30.2 | 39 | 43 | test_perf.py::test_enabled_desligado_por_padrao, test_perf.py::test_game_sem_profiler_por_padrao |
| R30.3 | 39 | 44 | test_benchmark.py::test_result_formata_linha_de_tabela_markdown |
| R30.4 | 39 | 44 | test_benchmark.py::test_percentile_p95_pega_a_cauda, test_benchmark.py::test_result_formata_linha_de_tabela_markdown |
| R30.5 | 30 | 73 | |
| R31.1 | 41 | 65 | |
| R31.2 | 41 | 65 | |
| R31.3 | 41 | 65 | |
| R31.4 | 41 | 66 | |
| R31.5 | 41 | 66 | |
| R32.1 | 42 | 67 | |
| R32.2 | 42 | 68 | test_traceability.py::test_every_acceptance_criterion_is_in_the_matrix |
| R32.3 | 42 | 68 | test_traceability.py::test_every_test_reference_in_the_matrix_resolves_to_a_real_function |
| R32.4 | 42 | 69 | |
| R33.1 | 43 | 71 | |
| R33.2 | 43 | 71 | |
| R33.3 | 43 | 71 | |
| R33.4 | 43 | 71 | |
| R33.5 | 43 | 71 | |
| R34.1 | 32.8 | 51 | test_input.py::test_tap_on_a_decorative_band_flaps |
| R34.2 | 32.8 | 51 | test_input.py::test_mouse_and_touch_at_the_same_physical_point_agree |
| R34.3 | 32.8 | 51 | test_input.py::test_finger_tap_outside_the_canvas_is_ignored |
| R34.4 | 32.8 | 51 | test_input.py::test_tap_on_a_band_starts_and_restarts_the_match |
| R34.5 | 32.8 | 51 | test_mobs.py::test_the_whole_simulation_is_identical_with_and_without_mobs, test_input.py::test_tap_on_a_decorative_band_flaps |
| R35.1 | 44 | 74 | test_repo_hygiene.py::test_the_license_file_is_mit_with_the_current_copyright_holder, test_repo_hygiene.py::test_readme_references_the_license_and_disclaims_the_minecraft_trademark |
| R35.2 | 44 | 74 | test_repo_hygiene.py::test_pyproject_declares_the_same_license_as_the_license_file |
| R35.3 | 44 | 77 | test_repo_hygiene.py::test_contributing_documents_the_branch_naming_convention, test_repo_hygiene.py::test_contributing_documents_commit_and_tag_conventions_and_the_hook_install_command |
| R35.4 | 44 | 78 | test_repo_hygiene.py::test_changelog_follows_keep_a_changelog_with_an_unreleased_section, test_repo_hygiene.py::test_changelog_does_not_rewrite_pre_v3_history |
| R35.5 | 44 | 76 | test_repo_hygiene.py::test_pre_commit_mirrors_the_ci_lint_and_type_gate, test_repo_hygiene.py::test_pre_commit_has_the_hygiene_hooks_ruff_and_ty_do_not_cover |
| R35.6 | 44 | 76 | test_repo_hygiene.py::test_ci_also_runs_the_pre_commit_hooks |
| R35.7 | 44 | 75 | test_repo_hygiene.py::test_editorconfig_is_root_and_normalizes_whitespace, test_repo_hygiene.py::test_gitattributes_normalizes_line_endings_and_marks_known_binaries |
| R35.8 | 44 | 79 | test_repo_hygiene.py::test_dependabot_covers_uv_and_github_actions |
| R35.9 | 44 | 79 | test_repo_hygiene.py::test_every_workflow_declares_least_privilege_permissions |
| R35.10 | 44 | 79 | test_repo_hygiene.py::test_pull_request_template_points_back_to_the_sdd_workflow |
| R36.1 | 12 | 81 | test_game.py::test_last_score_is_captured_when_returning_from_game_over, test_ui_layout.py::test_ready_screen_with_last_score_texts_do_not_overlap |
| R36.2 | 12 | 81 | test_game.py::test_starts_with_no_last_score, test_ui_layout.py::test_ready_screen_omits_last_score_line_when_none |
| R36.3 | 12 | 81 | test_game.py::test_last_score_does_not_survive_a_fresh_game_instance |