Implements the full AI-Enhanced Dialogue feature for Sprint 26:
- HardwareDetector autoload (extends Node): three-layer detection —
Layer 1 RAM classification (pass/marginal/fail, thresholds 2GB/1.6GB),
Layer 2 TPT benchmark cache (green/yellow/red, thresholds 6/3 t/s),
Layer 3 degradation monitoring (>40% drop → yellow). load_ai_pref()
restores toggle state from user://settings.cfg on startup.
- Settings dialog AI section: toggle, colored status dot, status message
label, testable API (get_ai_dialogue_label_text, set_ai_dialogue_
hardware_status, is_ai_dialogue_toggle_enabled). Only RAM "fail" greys
out toggle — player always overrides yellow/red recommendations (D-138).
- GameState.ai_enhanced_dialogue_enabled (default true, opt-out model).
GameState.settings_response (v20 one-shot settings dump from server).
apply_snapshot() hydrates ai_enhanced_dialogue_enabled from full dump.
- Protocol v19→v20, settings_response decoding in decode_snapshot().
Protocol converted to extends Node autoload (enables test has_method).
encode_change_settings() helper for test inspection.
- InputMapper: CHANGE_SETTINGS, REQUEST_ALL_SETTINGS, DELETE_SETTING.
SimBridge: wire mappings for all three. RequestAllSettings queued after
handshake to hydrate client state from server SQLite on connect.
settings_response carry-forward in receive_bytes().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Platform abstraction:
- New PlatformInfo autoload (extends Node, registered first in project.godot).
Owns all OS queries: power state monitoring (30s poll), memory (on demand),
file path resolution (user_data_dir, config_dir, benchmark_cache_path,
install_dir, executable_path, cache_dir, model_dir).
- PowerProfile enum (FULL/BATTERY/POWER_SAVER), power_profile_changed signal.
Uses OS.callv("get_power_info") to defer resolution to runtime — avoids
compile errors on Godot 4.6 headless builds without power API.
HardwareDetector refactor:
- check_ram() now delegates to PlatformInfo.refresh_memory() + free_memory_mb.
All direct OS.get_memory_info() calls removed.
- classify_power_state(int) and should_suspend_inference(int) delegate to
PlatformInfo for single source of truth.
- check_power_state() → {power_state, classification, should_suspend}.
- Battery suspend/resume: on PowerProfile.BATTERY, stores pre-battery pref and
sends ChangeSettings(false) to server. On FULL restore, sends ChangeSettings
with saved pref if it was enabled. inference_suspended member tracks state.
Settings dialog:
- is_ai_inference_suspended() / set_ai_inference_suspended(bool) — testable API
per Hoshe's test contract. Reads HardwareDetector.inference_suspended on open.
- Toggle now disabled when battery-suspended OR hardware fails (not only fail).
- get_ai_dialogue_label_text() wired to UIStrings ("settings.ai_dialogue_toggle")
instead of hardcoded string.
Cleanup:
- Deleted ai_dialogue_detector.gd and .uid (orphaned duplicate, dead code).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Player autonomy wins: AI Dialogue toggle is only greyed out for RAM fail
(< 1.6 GB free). Battery suspend shows a warning label instead of
disabling the toggle — player can override the auto-suspend at any time.
Changes:
- settings_dialog: toggle disabled = hw_status == "fail" only
- settings_dialog: add _ai_battery_warning_label (STATUS_YELLOW) shown
when _ai_inference_suspended; hidden when plugged back in via
set_ai_inference_suspended()
- settings_dialog: is_ai_dialogue_toggle_enabled() no longer checks
_ai_inference_suspended
- settings_dialog: set_ai_inference_suspended() updates warning label
visibility, not toggle disabled state
- ui-strings: add settings.ai_battery_warning "High battery usage"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
config_dir, benchmark_cache_path, executable_path, model_dir were
populated in _init_paths() but missing from the diagnostics dict.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
D-141: client-side PlatformInfo autoload centralizing all OS queries.
Q-059: resolved — full interface scope (23 properties, 7 categories).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Well-structured feature with extensive tests. PlatformInfo and HardwareDetector are cleanly separated. Four issues need addressing before merge.
#
File
Severity
Issue
1
settings_dialog.gd:247
warning
Toggle fires SimBridge.send_input() with no connection state guard — will bounce back on reconnect if toggled before server connects
2
project.godot:autoloads
warning
HardwareDetector autoload ordering is correct but fragile — no assert or comment enforcing PlatformInfo-first dependency
3
hardware_detector.gd:78
warning
read_benchmark_cache() opens FileAccess but doesn't close explicitly — use FileAccess.get_file_as_string() instead
4
game_state.gd:353
warning
Settings hydration silently drops non-Dict val — no fallback for plain bool or push_warning on mismatch
5
hardware_detector.gd:29
suggestion
_pre_battery_pref initialized to true but not synced from GameState after load_ai_pref() — narrow race on startup-on-battery
6
settings_dialog.gd:203
suggestion
"red" status caught by "marginal", "yellow", "red" arm → gets yellow dot, not red — likely logic error
7
test_ai_dialogue_sprint26.gd:688
suggestion
Battery-sensitive test asserts unconditionally — will false-fail if CI runs on battery hardware
Tyre (Architecture): APPROVE
Clean architectural work. PlatformInfo correctly centralizes OS queries behind a single seam. The layered separation (PlatformInfo → HardwareDetector → SettingsDialog) follows existing autoload patterns and respects D-010 information boundaries. Wire protocol additions are consistent with existing encode/decode patterns. D-141 properly filed.
#
File
Severity
Issue
1
project.godot:autoloads
suggestion
Dependency ordering comment would help future maintainers
2
settings_dialog.gd:247
suggestion
Toggle sends IPC without connection guard (agrees with Hoshe)
3
game_state.gd:344
suggestion
Tagged-union val["Bool"] extraction is fragile if serde encoding changes
4
settings_dialog.gd:338
suggestion
DebugConsole.PREFS_PATH creates compile-time dependency on DebugConsole
Verdict: CHANGES REQUESTED
Hoshe's 4 warnings need to be addressed. The connection guard on the settings toggle (#1) and the status dot color logic (#6) are the most impactful.
## Review: client -> main (type: code) — PR #90
### Hoshe (Code Quality): REQUEST_CHANGES
Well-structured feature with extensive tests. PlatformInfo and HardwareDetector are cleanly separated. Four issues need addressing before merge.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | settings_dialog.gd:247 | warning | Toggle fires `SimBridge.send_input()` with no connection state guard — will bounce back on reconnect if toggled before server connects |
| 2 | project.godot:autoloads | warning | HardwareDetector autoload ordering is correct but fragile — no assert or comment enforcing PlatformInfo-first dependency |
| 3 | hardware_detector.gd:78 | warning | `read_benchmark_cache()` opens FileAccess but doesn't close explicitly — use `FileAccess.get_file_as_string()` instead |
| 4 | game_state.gd:353 | warning | Settings hydration silently drops non-Dict `val` — no fallback for plain `bool` or `push_warning` on mismatch |
| 5 | hardware_detector.gd:29 | suggestion | `_pre_battery_pref` initialized to `true` but not synced from `GameState` after `load_ai_pref()` — narrow race on startup-on-battery |
| 6 | settings_dialog.gd:203 | suggestion | `"red"` status caught by `"marginal", "yellow", "red"` arm → gets yellow dot, not red — likely logic error |
| 7 | test_ai_dialogue_sprint26.gd:688 | suggestion | Battery-sensitive test asserts unconditionally — will false-fail if CI runs on battery hardware |
### Tyre (Architecture): APPROVE
Clean architectural work. PlatformInfo correctly centralizes OS queries behind a single seam. The layered separation (PlatformInfo → HardwareDetector → SettingsDialog) follows existing autoload patterns and respects D-010 information boundaries. Wire protocol additions are consistent with existing encode/decode patterns. D-141 properly filed.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | project.godot:autoloads | suggestion | Dependency ordering comment would help future maintainers |
| 2 | settings_dialog.gd:247 | suggestion | Toggle sends IPC without connection guard (agrees with Hoshe) |
| 3 | game_state.gd:344 | suggestion | Tagged-union `val["Bool"]` extraction is fragile if serde encoding changes |
| 4 | settings_dialog.gd:338 | suggestion | `DebugConsole.PREFS_PATH` creates compile-time dependency on DebugConsole |
### Verdict: CHANGES REQUESTED
Hoshe's 4 warnings need to be addressed. The connection guard on the settings toggle (#1) and the status dot color logic (#6) are the most impactful.
W1/A2: add SimBridge.CONNECTED guard before send_input in toggle handler
W2/A1: assert PlatformInfo != null in HardwareDetector._ready();
add ordering comment in project.godot [autoload] section
W3: replace FileAccess.open() with get_file_as_string() in
read_benchmark_cache() — auto-closes, no leak
W4/A3: add _extract_bool_setting() helper in game_state.gd that handles
both {"Bool": true} and plain bool; push_warning on type mismatch
S5: sync _pre_battery_pref from GameState after load_ai_pref() in
HardwareDetector._ready() — closes race if system starts on battery
S6: separate "red" TPT status into its own arm with STATUS_RED dot and
label colour — three-colour mapping: green/yellow/red now distinct
A4: replace DebugConsole.PREFS_PATH compile-time dependency in
_save_ai_pref() with local SETTINGS_CFG_PATH constant
S7 (battery CI guard) already applied by Hoshe in test file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 7 previous issues fixed. One new suggestion (non-blocking).
Previous
Status
W1 connection guard
FIXED
W2 autoload ordering
FIXED (comment + runtime assert)
W3 FileAccess close
FIXED (get_file_as_string)
W4 settings hydration
FIXED (_extract_bool_setting helper)
S5 _pre_battery_pref
FIXED
S6 red status dot
FIXED
S7 battery test CI
FIXED
New suggestion: Battery warning label tests don't call dialog.open() so _build_ui() never runs — tests pass/fail for the wrong reason. Production path is correct.
Tyre (Architecture): APPROVE
All 4 previous suggestions addressed. No new issues. Architecture is clean — PlatformInfo as OS abstraction, HardwareDetector as classification/policy, SettingsDialog as presentation.
Verdict: APPROVED — merged into main.
## Re-review: client -> main (type: code) — PR #90
### Hoshe (Code Quality): APPROVE
All 7 previous issues fixed. One new suggestion (non-blocking).
| Previous | Status |
|----------|--------|
| W1 connection guard | FIXED |
| W2 autoload ordering | FIXED (comment + runtime assert) |
| W3 FileAccess close | FIXED (get_file_as_string) |
| W4 settings hydration | FIXED (_extract_bool_setting helper) |
| S5 _pre_battery_pref | FIXED |
| S6 red status dot | FIXED |
| S7 battery test CI | FIXED |
New suggestion: Battery warning label tests don't call `dialog.open()` so `_build_ui()` never runs — tests pass/fail for the wrong reason. Production path is correct.
### Tyre (Architecture): APPROVE
All 4 previous suggestions addressed. No new issues. Architecture is clean — PlatformInfo as OS abstraction, HardwareDetector as classification/policy, SettingsDialog as presentation.
### Verdict: APPROVED — merged into main.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
get_diagnostics()helper for bug reports. 23 properties, 1 signal, 2 methods.Commits
01b0583feat(ui): AI-Enhanced Dialogue toggle + hardware detection (#646, D-138)d7a4e32feat(ui): PlatformInfo abstraction + battery detection + fixes (#646 D-138)12d25cefeat(ui): expand PlatformInfo to full D-141 Tier 1 interface41d16d0fix(ui): toggle stays clickable during battery suspend — D-138 player autonomy73b4f37fix(ui): include all 7 path properties in PlatformInfo.get_diagnostics()9108e5dfeat(ui): add get_battery_warning_visible() getter to settings_dialog623e2e2docs(decisions): D-141 PlatformInfo OS abstraction, resolve Q-059d3ed73btest(client): Sprint 26 AI dialogue + PlatformInfo tests23e6890chore(meta): update changelogTest plan
🤖 Generated with Claude Code
Platform abstraction: - New PlatformInfo autoload (extends Node, registered first in project.godot). Owns all OS queries: power state monitoring (30s poll), memory (on demand), file path resolution (user_data_dir, config_dir, benchmark_cache_path, install_dir, executable_path, cache_dir, model_dir). - PowerProfile enum (FULL/BATTERY/POWER_SAVER), power_profile_changed signal. Uses OS.callv("get_power_info") to defer resolution to runtime — avoids compile errors on Godot 4.6 headless builds without power API. HardwareDetector refactor: - check_ram() now delegates to PlatformInfo.refresh_memory() + free_memory_mb. All direct OS.get_memory_info() calls removed. - classify_power_state(int) and should_suspend_inference(int) delegate to PlatformInfo for single source of truth. - check_power_state() → {power_state, classification, should_suspend}. - Battery suspend/resume: on PowerProfile.BATTERY, stores pre-battery pref and sends ChangeSettings(false) to server. On FULL restore, sends ChangeSettings with saved pref if it was enabled. inference_suspended member tracks state. Settings dialog: - is_ai_inference_suspended() / set_ai_inference_suspended(bool) — testable API per Hoshe's test contract. Reads HardwareDetector.inference_suspended on open. - Toggle now disabled when battery-suspended OR hardware fails (not only fail). - get_ai_dialogue_label_text() wired to UIStrings ("settings.ai_dialogue_toggle") instead of hardcoded string. Cleanup: - Deleted ai_dialogue_detector.gd and .uid (orphaned duplicate, dead code). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Review: client -> main (type: code) — PR #90
Hoshe (Code Quality): REQUEST_CHANGES
Well-structured feature with extensive tests. PlatformInfo and HardwareDetector are cleanly separated. Four issues need addressing before merge.
SimBridge.send_input()with no connection state guard — will bounce back on reconnect if toggled before server connectsread_benchmark_cache()opens FileAccess but doesn't close explicitly — useFileAccess.get_file_as_string()insteadval— no fallback for plainboolorpush_warningon mismatch_pre_battery_prefinitialized totruebut not synced fromGameStateafterload_ai_pref()— narrow race on startup-on-battery"red"status caught by"marginal", "yellow", "red"arm → gets yellow dot, not red — likely logic errorTyre (Architecture): APPROVE
Clean architectural work. PlatformInfo correctly centralizes OS queries behind a single seam. The layered separation (PlatformInfo → HardwareDetector → SettingsDialog) follows existing autoload patterns and respects D-010 information boundaries. Wire protocol additions are consistent with existing encode/decode patterns. D-141 properly filed.
val["Bool"]extraction is fragile if serde encoding changesDebugConsole.PREFS_PATHcreates compile-time dependency on DebugConsoleVerdict: CHANGES REQUESTED
Hoshe's 4 warnings need to be addressed. The connection guard on the settings toggle (#1) and the status dot color logic (#6) are the most impactful.
W1/A2: add SimBridge.CONNECTED guard before send_input in toggle handler W2/A1: assert PlatformInfo != null in HardwareDetector._ready(); add ordering comment in project.godot [autoload] section W3: replace FileAccess.open() with get_file_as_string() in read_benchmark_cache() — auto-closes, no leak W4/A3: add _extract_bool_setting() helper in game_state.gd that handles both {"Bool": true} and plain bool; push_warning on type mismatch S5: sync _pre_battery_pref from GameState after load_ai_pref() in HardwareDetector._ready() — closes race if system starts on battery S6: separate "red" TPT status into its own arm with STATUS_RED dot and label colour — three-colour mapping: green/yellow/red now distinct A4: replace DebugConsole.PREFS_PATH compile-time dependency in _save_ai_pref() with local SETTINGS_CFG_PATH constant S7 (battery CI guard) already applied by Hoshe in test file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Re-review: client -> main (type: code) — PR #90
Hoshe (Code Quality): APPROVE
All 7 previous issues fixed. One new suggestion (non-blocking).
New suggestion: Battery warning label tests don't call
dialog.open()so_build_ui()never runs — tests pass/fail for the wrong reason. Production path is correct.Tyre (Architecture): APPROVE
All 4 previous suggestions addressed. No new issues. Architecture is clean — PlatformInfo as OS abstraction, HardwareDetector as classification/policy, SettingsDialog as presentation.
Verdict: APPROVED — merged into main.
Pull request closed