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>
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>
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>
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>
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>
tea-comment now accepts @/path/to/file.md syntax to read comment body
from a file, avoiding $() subshells that break permission matching.
Updated pr-review skill and tea-cli rules with the new pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Must-fix: protocol version comment now references PROTOCOL_VERSION
(no hardcoded number), settings delete is idempotent no-op.
Suggestions addressed: BehaviorModifier dedup claim dropped, hash
collision safety documented, FK pragma in test store, columns_to_value
consolidated, modifier_hint mismatch logging, OffDuty test coverage,
batching tradeoff documented, unknown value_type warning, occluded
text risk documented, dead child respawn in voice worker, INJECT
block ambiguity documented.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- line_pool.rs: add trace! when active_situations is empty (Layer 2
will silently filter all lines — important for content debugging)
- knowledge_grant.rs: document serde(untagged) ambiguity hazard; add
KnowledgeGrant::validate() for load-time field validation
- monologue.rs: annotate trigger_monologue as schedule ordering anchor;
fix stale "periodic trigger cooldown tracking" doc reference in
trigger_event_monologue (COOLDOWN_TICKS removed in #655)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These permissions are only needed by the main worktree for PR reviews,
not by team worktrees. Moved from shared settings.json to local.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds Read permissions for all team worktree directories so review
agents spawned from main can read source files directly instead of
falling back to git diff.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-player settings via rusqlite (bundled, zero runtime dep). Server
owns the settings DB; client sends ChangeSettings commands over IPC.
Extensible key-value with typed columns (String/Int/Float/Bool).
Protocol bumped to v20 with settings_response in ObserverSnapshot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ContentType::Factual bypasses LLM for fact-bearing lines (numbers,
denials). Observer enrichment systems rewrite dialogue/conversation
text with voiced versions before snapshot assembly. Friendly and
RoutineDeviation tells get concrete surface-pattern examples.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete the hand-authored YAML content pipeline (server/src/content/) superseded
by the v0.2 generator-first approach (D-122, D-128). Runtime ECS types that were
co-located with content loading have been extracted to dedicated simulation modules:
- simulation/triangle.rs: TriangleState, TriangleCrisisEventQueue, tick/resolve systems
- simulation/line_pool.rs: LinePoolIndex, AccessTier, TrustTier, Mood, LinePoolIndexResource
- simulation/knowledge_grant.rs: KnowledgeGrant, Prerequisites
Monologue systems (trigger_monologue, trigger_recognition_monologue,
trigger_event_monologue) now use hardcoded fallback lines only; the
ContentStoreResource branch and select_pool_line function are removed.
Deleted: content/{loader,types,line_pool,hot_reload,spawn,instantiation,entanglement,mod}.rs
Deleted: tests/{content_loading,content_runtime,content_scaling,template_instantiation,template_schema}.rs
Deleted: bin/line_preview.rs (v0.1 tool)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Points auto-memory to ~/Projects/settled-reach/.memory so all
worktrees share a single memory root outside the git tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prerequisite for #646 (AI-Enhanced Dialogue toggle). Updated server
and client briefings with dependency chain and integration notes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 tickets across server (5), copy (6), client (1), planning (1).
Sprint goal: ship voice pipeline to production via observer integration,
remove v0.1 dead weight, stabilize codebase. #648 cancelled as duplicate
of #658.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Spike 2 amendments: stdio IPC (not HTTP, Gemma 2 T&C compliance),
tell differentiation results (3/5 at 2B capacity), double-prompt
technique, ContentType::Factual for LLM bypass, all negative
injectors moved from universal RULES to per-culture voice_persona.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes:
- Pause mechanism: workers now hold requests during pause instead of
dropping them. Queue and worker pool share the same AtomicBool flag
via VoiceQueue::paused_flag(). Submit() rejects while paused.
- Seed type: sr-voice accepts u64 seeds over IPC (explicit u32 truncation
for llama.cpp sampler, documented).
Warning fixes:
- HashMap → BTreeMap in cache.rs and worker.rs (D-010 determinism mandate).
Added Ord derives to CacheKey, ContentType, TellCategory.
- VoicePipe::generate() watchdog kills child after 120s timeout to prevent
indefinite blocking on read_line.
- VoiceCacheStore Drop impl calls save_all() on shutdown.
- trait-modifiers.ron: fixed 3 wrong trait names (Impulsive→Compassionate,
Methodical→Incurious, Stubborn→Ruthless) to match PersonalityTrait enum.
Suggestion fixes:
- Worker spawn: log error + reduce pool instead of panic on thread failure.
- on_battery(): added macOS detection via pmset.
- Epistemic markers: lowercased constants, removed redundant to_lowercase().
- cache.rs: documented non-atomic write tradeoff.
- queue.rs: reprioritize() bypasses pause check (it runs during pause).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10 trait modifiers targeting distinct speech dimensions (delivery force,
word selection, sentence shape, framing, cadence, volume, texture,
position) so they stack without conflict. Used by prompt_builder.rs
to modify NPC speech style based on personality traits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemma 2 T&C compliance: exposed HTTP ports allow mods or external code
to reach the model, complicating license enforcement. Switch to piped
stdin/stdout (JSONL protocol) so the model is only reachable through
the game server's internal queue.
- worker.rs: VoicePipe owns Child + piped stdin/stdout, VoiceProcessConfig
replaces port-based config, workers spawn their own sr-voice child
- hardware.rs: remove VoiceInstanceManager (port/process lifecycle),
replace with evaluate_scaling() free function + HardwareProbe::voice_config()
- sr-voice: add --stdio flag to serve command, new stdio.rs JSONL mode
- Remove ureq dependency from server crate (no longer needed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add lookup.rs with voiced_behavior() — ready to wire into a behavior-serving
system once one exists (Q-058). Tell behaviors always passthrough (never
re-voiced). Cache miss returns base text (graceful degradation).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MessagePack voice cache with per-zone persistence and version invalidation.
Priority work queue with crossbeam bounded channel, backpressure, pause/resume,
and zone-change reprioritization. Inference worker pool with empty output guard
and graceful degradation to base text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tell-variant caching: 6→length-gated (short=neutral only, medium=3,
long=6). 2B model produces identical output across tell states on
short lines — confirmed across two test rounds.
- Composition-engine occasional injections: oath vocabulary, faith
expressions etc. controlled by prompt generator frequency, not model.
Systemic pattern for any culture marker that should appear occasionally.
- NI-1/NI-5 culture-gated: religious language and Earth-origin markers
are per-culture injector constraints, not universal bans. Cultural
heritage from colonization history is intentional. Earth is not lost.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reference document from Gemini design sparring session covering
re-voicing compliance and implementation considerations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Between rounds: mandatory AskUserQuestion checkpoint before next round launches
- Wrap-up: user explicitly controls team dismissal
- Hard requirements before close: D-records filed, discussion captured, tickets created
- User reviews workshop-outcomes.md before finalization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workshop to decide content generation architecture: hand-authored pools,
composable primitives, or LLM re-voicing with progressive enhancement.
Includes proposed-llm-voice.md (Gemini/Jeroen design session) and
Gemini project review (GEMINI-SCAN.md).
Key design: base text serves triple duty — LLM prompt seed, graceful
fallback, and LLM-off experience. Baked content for hubs, lazy
pre-voicing for exploration, same pattern as world generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open question for decomposing hand-authored behavior pools into
composable primitives (role actions + culture modifiers + context tags).
Part of Sprint 25 PoC spike. Server ticket #633, copy ticket #634.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four generator spike improvements in one pass:
- #628: Fix name pool first-pick bias. build_name_pool now derives a
zone+culture-specific ChaCha20 RNG via FNV-1a mixing of (seed,
zone_type, culture_id), isolating name ordering from main RNG
consumption. Different zone types with the same seed now produce
different first names.
- #629: Behavior dedup within a zone run. build_behavior_pools
pre-shuffles each role's behavior list; gen_behaviors draws without
replacement. Falls back to random repeat with warning when pool
exhausts.
- #631: Relationship-to-behavior pipeline. Third generation pass
(~50% chance) replaces primary behavior with relationship-revealing
action — rivals talk past each other, friends drift together,
subordinates defer.
- #632: Want/State layer. NpcWant enum (Neutral/Bored/Alert/Suspicious/
AvoidingSomeone/LookingForInfo) biased by traits and role. Fourth
generation pass produces observable tells that leak internal state
through behavior. AvoidingSomeone resolves against negative-valence
relationships for named targets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Name pool fixes:
- Remove "Korr" from given_names (duplicate with family_names), replace with "Tork"
- Replace "Narek" with "Sorek" (real-world Armenian name, IP concern)
- Replace soft "-ael" endings (Vael→Vrek, Rael→Rask) to match naming rules
- Update comment: "no soft endings" → "hard endings preferred"
- Add 2 family names (Tollek, Dass) to balance pool ratio (now 40/18)
Voice fixes:
- Replace "same drill" (not an exclamation) with "cold vacuum"
- Rewrite 3 trader behaviors as observable stage directions
- Add 2 foreman off-duty behaviors (person beneath the role)
- Add break room behaviors to dock_worker, technician, foreman
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove "Narek" from family_names (duplicate with given_names), replace with "Morek"
- Rewrite rural farmer behaviors to be location-agnostic (no sky/weather assumptions)
- Add heritage root overlay comments (D-104/D-105) to both zone specs
- Add insert/lattice tech behavior to industrial technician role
- Rewrite 2 security behaviors with Krenn cultural texture (D-121)
- Replace generic exclamations with Krenn-specific oaths ("void's sake", "same drill")
- Replace soft greeting "you okay?" with "all in one piece?"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Insert A1b retrospective step between sprint close and version bump.
Covers: what shipped, what didn't, what we learned, process notes.
Process improvements are optional — only proposed when something was
actually broken.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zone specs need a location_context field (surface/station/vessel) so
the generator can filter environment-specific behaviors. Raised during
PR #88 review — rural zone had sky/weather references that only make
sense on a planet surface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>