Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
85a8f6d
[SUBTASK] Code Implementation: Add Audio Feedback to Difficulty Pipel…
ikostan Jun 4, 2026
62716ad
[SUBTASK] Test Plan: Difficulty Slider Audio Verification Suite (GUT …
ikostan Jun 4, 2026
d809940
Add milestone docs: CI updates and audio design
ikostan Jun 4, 2026
9ef9f0f
Update PART_3_Update_Godot_export_action_pin_and_configure_Codecov_to…
ikostan Jun 4, 2026
354a48d
Update files/docs/milestones/19/PART_4_gameplay_settings_audio_intera…
ikostan Jun 4, 2026
b0bc9bb
Update files/docs/milestones/19/PART_4_gameplay_settings_audio_intera…
ikostan Jun 4, 2026
f3f288e
Update files/docs/milestones/19/PART_3_Update_Godot_export_action_pin…
ikostan Jun 4, 2026
b7276fa
Merge branch 'audio-feedback-for-difficulty-slider-interaction' of ht…
ikostan Jun 4, 2026
1a8e69a
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 4, 2026
451c87b
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 4, 2026
eae870f
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 4, 2026
3b23da1
Add DummyAudioManager and strengthen audio tests
ikostan Jun 5, 2026
8042f0c
Expose SFX pool API and update tests
ikostan Jun 5, 2026
d15f57d
Update files/docs/milestones/19/PART_3_Update_Godot_export_action_pin…
ikostan Jun 5, 2026
7bab478
Update files/docs/milestones/19/PART_4_gameplay_settings_audio_intera…
ikostan Jun 5, 2026
c01783d
Update files/docs/milestones/19/PART_4_gameplay_settings_audio_intera…
ikostan Jun 5, 2026
0b58952
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 5, 2026
3a42329
Merge branch 'audio-feedback-for-difficulty-slider-interaction' of ht…
ikostan Jun 5, 2026
3ee8a3d
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 5, 2026
cb0f614
Update PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md
ikostan Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Update Godot export action pin and configure Codecov token

## Summary

Update CI workflows to use the latest pinned Godot export action and
ensure test reports upload correctly to Codecov.

### CI

- Bump the pinned SHA of the firebelley/godot-export GitHub Action
across browser tests, CodeQL analysis, and itch.io deployment workflows.
- Set the Codecov upload step in GUT tests workflow to use the
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
`CODECOV_TOKEN` secret for authenticated report uploads.

### Chores

- Updated build and export automation dependencies to maintain
compatibility and reliability.
- Enhanced CI/CD pipeline security by properly configuring token access
for automated code coverage reporting.

---

## Reviewer's Guide

Updates CI workflows to use a newer pinned revision of the
firebelley/godot-export GitHub Action and ensures the Codecov upload step
has the required token set via environment variables.


### File-Level Changes

<!-- markdownlint-disable MD013 MD033 table-column-style -->
| Change | Details | Files |
|-------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| Bump the pinned firebelley/godot-export GitHub Action SHA across workflows to a newer revision. | <ul><li>Update the godot-export action reference in the browser_test workflow to the new commit SHA while keeping Godot 4.5 download URLs unchanged.</li><li>Update the godot-export action reference in the codeql workflow to the new commit SHA, preserving existing Godot build URLs and comments.</li><li>Update the godot-export action reference in the deploy_to_itch workflow to the new commit SHA, keeping export configuration intact.</li></ul> | `.github/workflows/browser_test.yml`<br/>`.github/workflows/codeql.yml`<br/>`.github/workflows/deploy_to_itch.yml` |
| Fix Codecov upload configuration so reports are sent with the explicit token from repository secrets. | <ul><li>Set CODECOV_TOKEN environment variable for the Codecov upload step in the gut_tests workflow, sourcing it from GitHub Actions secrets.</li><li>Leave the rest of the test report discovery and upload logic unchanged.</li></ul> | `.github/workflows/gut_tests.yml` |
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
<!-- markdownlint-enable MD013 MD033 table-column-style -->

---

## Bots/AI Contributions Summary for PR #736

This PR focuses on CI/CD maintenance: updating the pinned SHA for the
`firebelley/godot-export` GitHub Action across multiple workflows and
configuring the `CODECOV_TOKEN` for authenticated coverage uploads.
It received valuable support from automated bots and AI tools for dependency
management, summarization, and code quality review.

### Automated Bots & AI Tools

Check failure on line 51 in files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md:51:81 MD013/line-length Line length [Expected: 80; Actual: 293] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
- **@dependabot[bot]**: Initiated and managed the major version bump of `firebelley/godot-export` from 7.0.0 to 8.0.0, including the automated commit and PR creation for the dependency update. This ensured the workflows stayed current with the latest action features and security improvements.

Check failure on line 52 in files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md:52:81 MD013/line-length Line length [Expected: 80; Actual: 227] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
- **@sourcery-ai**: Generated a clear PR summary and reviewer's guide, highlighting the action version bump across workflows and the Codecov token configuration. Also assisted with title generation and overall review structure.

Check failure on line 53 in files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md:53:81 MD013/line-length Line length [Expected: 80; Actual: 188] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
- **@coderabbitai**: Provided a focused summary emphasizing CI/CD reliability improvements, security enhancements through proper token handling, and maintenance of build/export automation.

Check failure on line 54 in files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_3_Update_Godot_export_action_pin_and_configure_Codecov_token.md:54:81 MD013/line-length Line length [Expected: 80; Actual: 248] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
- **@deepsource-io**: Conducted automated static code analysis and code review on the workflow changes. Provided an overall grade across Security, Reliability, Complexity, and Hygiene categories, along with inline comments and a full review report.

These tools contributed to better documentation, reviewer guidance,
dependency security, and code health validation.

### Human Maintainers

- **@ikostan**: Primary contributor and PR author. Coordinated the changes,
updated the pinned commit SHAs for the Godot export action in `browser_test.yml`,
`codeql.yml`, and `deploy_to_itch.yml`, configured the `CODECOV_TOKEN`
environment variable in `gut_tests.yml`, added a detailed reviewer's guide with
Mermaid flowchart, and integrated the updates into the project milestone.

---
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# 📝 Gameplay Settings Audio Interaction & Asset Tracking Architecture

This technical document records the architecture, behavioral boundaries,
and runtime asset dependencies introduced by the focus-gated audio
feedback system within the Gameplay Settings menu. This log ensures
long-term system maintainability and guards critical assets against
automated cleanup or build pruning tools.

---

## 🚀 1. UI Architecture & Design Principles

The difficulty adjustment pipeline within `gameplay_settings.gd` utilizes
real-time interactive audio feedback to improve player responsiveness
across native and web-exported platforms. To align with the architectural
design patterns established within the Audio Settings menu, the
implementation operates under a strict **Mute Signal Isolation and
Decoupling Pattern**.

### Core Architectural Axioms:

* **Focus-Gated Control:** Audio playback is strictly decoupled from the low-level data engine layer. Sound effects are never permitted to fire automatically from generic value mutation listeners.

Check failure on line 22 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:22:81 MD013/line-length Line length [Expected: 80; Actual: 196] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
* **Gated Pathway Verification:** Audio execution triggers only when an explicit, user-driven interaction vector is authenticated via the viewport focus system or a verified external API token.

Check failure on line 23 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:23:81 MD013/line-length Line length [Expected: 80; Actual: 193] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
* **Pipeline Parity:** External interaction vectors (such as HTML5 browser overlays via JavaScript) do not duplicate or independently mutate state; they route safely into the native internal interaction handling pipeline to maintain identical validation rules.

Check failure on line 24 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:24:81 MD013/line-length Line length [Expected: 80; Actual: 260] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md

---

## 🔄 2. Interaction Pipelines: Behavioral Division

To maintain deterministic execution states during tests, configuration restoration, and real-time gameplay updates, the system enforces an absolute separation between **Interactive Pathways** (audible) and **Silent Pathways** (programmatic).

Check failure on line 30 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:30:81 MD013/line-length Line length [Expected: 80; Actual: 241] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md

### 🟢 Interactive Pathways (Audible Feedback)

The following operations represent intentional human interactions. Each discrete event must invoke exactly one audio playback event via `AudioManager.play_sfx("slider")`:

Check failure on line 34 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:34:81 MD013/line-length Line length [Expected: 80; Actual: 170] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md

1. **Mouse Interaction:** Dragging or clicking the physical `DifficultyHSlider` node bar while the control captures active mouse input.

Check failure on line 36 in files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md

View workflow job for this annotation

GitHub Actions / Markdown Lint / lint (3.x)

Line length

files/docs/milestones/19/PART_4_gameplay_settings_audio_interaction_and_asset_tracking.md:36:81 MD013/line-length Line length [Expected: 80; Actual: 135] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
2. **Keyboard & Controller Navigation:** Utilizing the D-Pad, arrow keys, or analog controls to shift slider increments while the node possesses viewport layout focus (`has_focus()`).
3. **Gameplay Reset Button:** Pressing the layout `ResetButton` control element. This bypasses localized focus restrictions by explicitly passing an interactive intent flag to reset variables back to default states (`1.0`).
4. **Verified JS Overlay Interactions:** Incoming signals from the web-assembly runtime browser layout (`_on_change_difficulty_js()`). These bypass localized viewport check gates using an explicit parameter token override since external DOM nodes cannot hold local Godot UI focus.
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved

### 🔴 Silent Pathways (Absolute Silence)

The following operations represent programmatic synchronization, lifecycle state management, or automated testing loops. These blocks **must remain completely silent** and are protected against audio leakage:

1. **Menu Initialization:** Instantiating the scene container and executing `_ready()` loops to synchronize variables with global configuration singletons.
2. **Save & Configuration Synchronization:** Real-time data updates loading from or saving to disk using the `Globals.settings` configuration serialization layer.
3. **External Observer Reactivity:** When the underlying settings resource broadcasts a `setting_changed` signal, the UI reacting inside `_on_external_setting_changed()` hooks updates layout positions silently.
4. **Recursive Loop Mitigation:** Programmatic updates applied to UI controls utilize Godot’s native `set_value_no_signal()` method rather than direct property modification, ensuring that layout changes do not trigger duplicate handlers or audio signals.
5. **Automated Setup Flows:** Headless test runner executions (such as automated GUT unit suites) mocking environment profiles.

---

## 📦 3. Explicit Runtime Asset Dependency Registration

To prevent automated pruning tools, resource optimization scripts, or export exclusion whitelists from accidentally dropping required audio assets during project compilation, the explicit relationship mapping below is formally registered:

### Dependency Mapping Matrix

```text
[Dependent UI Script Component]
res://scripts/ui/menus/gameplay_settings.gd

└── Refers to Runtime Identifier: "slider"

[Target Live Audio Asset Resource]
res://files/sounds/sfx/slider.wav

```

### Resource Metadata Definitions:

* **Asset Path:** `res://files/sounds/sfx/slider.wav`
* **Import Profile Configuration:** Controlled via tracking metadata at `res://files/sounds/sfx/slider.wav.import`.
* **Runtime Deployment Target:** Mapped to the `AudioConstants.BUS_SFX_MENU` mixer channel backend through the centralized pool allocation routing configuration.

---

## 🛡️ 4. Asset Protection & Pruning Safeguards

The sound asset `slider.wav` is flagged as an **actively referenced runtime gameplay UI dependency**.

### Maintenance Directives for Future Contributors:

* **Exclusion from Optimization Sweets:** This file **is unsafe to remove** or exclude during asset compression passes, engine pruning commands, or build export optimization cycles.
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
* **No Direct File Tracing Checks:** Pruning tools checking files strictly via direct script `load()` or `preload()` paths will miss this asset, as it is requested dynamically through an abstraction layer string identifier (`"slider"`). Do not delete this asset based solely on a lack of static reference lines inside the codebase.
* **Deprecation Protection:** If the Gameplay Settings menu layout is altered in future refactors, this asset must remain preserved in storage unless all focus-gated slider workflows across the option menus are completely eliminated.

---

## ⚠️ 5. Regression Prevention Notes

When engineering updates or extending features under this layout ecosystem, future developers must respect these defensive constraints to prevent breaking system stability:

1. **Why Generic `value_changed` Signals Cannot Play Audio:**
Attaching an audio hook directly to a standard slider signal creates an immediate architectural loop vulnerability. Because code modifications to a slider's layout re-trigger its `value_changed` signal, programmatic setups (like reading a save file) will cause sound effects to blast during initialization or lock the loop into infinite recursion.
2. **Why JS Overlays Require Explicit Intent Passing:**
When a game export is displayed in a browser canvas, clicking an HTML overlay button interacts directly with the page DOM, meaning Godot's localized viewport focus tracking returns `false`. By adding `is_interactive: bool = false` parameters, the web overlay can cleanly override the focus gate token, ensuring identical state behavior without splitting the pipeline into separate logic wrappers.
3. **Why Headless Audio Isolation Matters:**
Automated unit tests running inside headless CI/CD systems run without physical audio server drivers or sound hardware cards. Isolating audio calls into guarded blocks checking for a valid `AudioManager` prevents testing environments from crashing due to null pointer engine executions.

---

### 📝 Acceptance Criteria Verification Status

* [x] Gameplay Settings audio interaction behavior is documented.
* [x] Focus-gated interaction architecture is documented.
* [x] Silent synchronization behavior is documented.
* [x] JS overlay interaction routing behavior is documented.
* [x] Explicit dependency mapping to `slider.wav` is recorded.
* [x] Asset pruning protection notes are added.
* [x] Documentation reflects actual runtime implementation behavior.
* [x] Future contributors can identify the dependency relationship without code tracing.

---
44 changes: 35 additions & 9 deletions scripts/ui/menus/gameplay_settings.gd
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ func _unset_gameplay_settings_window_callbacks() -> void:
## Handles Gameplay Settings reset button press.
func _on_gameplay_reset_button_pressed() -> void:
Globals.log_message("Gameplay Settings reset pressed.", Globals.LogLevel.DEBUG)
_on_difficulty_value_changed(_default_difficulty)
# Route through standard handler with explicit interaction override set to true
_on_difficulty_value_changed(_default_difficulty, true)


func _on_gameplay_reset_js(_args: Array) -> void:
Expand Down Expand Up @@ -284,19 +285,19 @@ func _on_gameplay_back_button_pressed_js(args: Array) -> void:


# Change: Separate handler for signal (float value)
func _on_difficulty_value_changed(value: float) -> void:
func _on_difficulty_value_changed(value: float, is_interactive: bool = false) -> void:
## Handles changes to the difficulty slider from the signal.
##
## Updates global difficulty, label text, logs the change, and saves settings.
## Gates slider.wav playback behind UI focus verification or explicit external
## interaction overrides.
##
## :param value: The new slider value.
## :type value: float
## :param is_interactive: True if the event was triggered by a verified external human
## interaction vector.
## :type is_interactive: bool
## :rtype: void
# Update the resource first (this triggers clamping in the setter)
#Globals.settings.difficulty = value
# Update the UI components using the ALREADY CLAMPED value from the resource
#difficulty_slider.value = Globals.settings.difficulty
#difficulty_label.text = "{" + str(Globals.settings.difficulty) + "}"
var settings_res := Globals.settings if is_instance_valid(Globals) else null

# FIX: Use the local reference exclusively
Expand All @@ -307,12 +308,23 @@ func _on_difficulty_value_changed(value: float) -> void:
)
return

# Evaluate focus validation before updating UI structures
var slider_has_focus: bool = false
if is_instance_valid(difficulty_slider):
slider_has_focus = difficulty_slider.has_focus()

# Gate audio playback on explicit intent token or validated UI focus
var should_play_audio: bool = is_interactive or slider_has_focus

settings_res.difficulty = value
if is_instance_valid(difficulty_slider):
difficulty_slider.set_value_no_signal(settings_res.difficulty)
if is_instance_valid(difficulty_label):
difficulty_label.text = "{" + str(settings_res.difficulty) + "}"

if should_play_audio:
_play_slider_sfx()


# New: JS-specific callback (exactly one Array arg, no default)
func _on_change_difficulty_js(args: Array) -> void:
Expand Down Expand Up @@ -376,8 +388,8 @@ func _on_change_difficulty_js(args: Array) -> void:
"JS difficulty callback called with valid value: " + str(value), Globals.LogLevel.DEBUG
)

# Pass the validated value to the standard handler
_on_difficulty_value_changed(value)
# Pass the validated value to the standard handler with the interactive flag explicitly overridden
_on_difficulty_value_changed(value, true)


## GS-JS: Helper to extract a potential value from diverse JS bridge payloads.
Expand Down Expand Up @@ -430,3 +442,17 @@ func _grab_initial_focus() -> void:
[difficulty_slider, gameplay_back_button, gameplay_reset_button],
"Gameplay Settings Menu"
)


## Helper to cleanly trigger interactive feedback via the global AudioManager
## Prevents engine-level environment execution faults during headless unit testing pipelines.
##
## :rtype: void
func _play_slider_sfx() -> void:
if is_instance_valid(AudioManager) and AudioManager.has_method("play_sfx"):
AudioManager.play_sfx("slider")
elif is_instance_valid(Globals):
Globals.log_message(
"Gameplay Settings: AudioManager unavailable or missing play_sfx method.",
Globals.LogLevel.DEBUG
)
Loading
Loading