chore(adr-076): remove dead base64 dep and AudioAction::Duck variant#413
Merged
chore(adr-076): remove dead base64 dep and AudioAction::Duck variant#413
Conversation
- Cargo.toml: drop base64 = "0.22" (zero uses in src/ — legacy TTS chunk encoding)
- music_director.rs: delete AudioAction::Duck variant and its Display arm.
Verified dead: transition_action() never returns Duck, no match arms
reference it, zero constructors in the workspace. Its only remaining
mention was the Display formatter.
AudioAction::Restore is the matched pair ("Restore volume after speech")
and is also dead, but the handoff only called out Duck — leaving Restore
for a separate minimalist pass rather than widening scope mid-PR.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two pre-existing test failures that the ADR-076 sweep surfaced once the duck-field cleanup unblocked the test suite past its earlier halt points. ## creature_core::apply_hp_delta — restore WatcherEventBuilder emission Story 28-2 originally instrumented apply_hp_delta with WatcherEventBuilder so the GM panel could verify HP mutations on the broadcast channel. Story 28-12 added a parallel tracing::info_span! for log/jaeger visibility, and somewhere in the rebase the WatcherEventBuilder emission was dropped — only the tracing span survived. The hp_delta test expectations in otel_structured_encounter_story_28_2_tests subscribe to the broadcast channel, so they were silently failing on develop until cargo test reached this binary. Restored the WatcherEventBuilder.send() with the same field shape the test expects (name, old_hp, new_hp, delta, max_hp, clamped). Kept the tracing span — the two channels serve different consumers and CLAUDE.md's OTEL principle calls for both. ## otel_structured_encounter test helper — poison-recoverable mutex lock The fresh_subscriber() helper acquires a TELEMETRY_LOCK mutex to serialize tests against the global telemetry channel. When the FIRST broken test in the binary panicked while holding the guard, Rust's Mutex went into the poisoned state, and every subsequent test calling lock().unwrap() then panicked on the poison error — turning 1 root-cause failure into 20 cascading failures. The mutex guards () (no shared state to be in an inconsistent state), so unwrap_or_else to recover from poison is safe and correct. Stops single-test panics from masking the real story across the rest of the binary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What started as a narrow ADR-076 code-residue cleanup expanded into a tech-debt paydown PR after
cargo test --workspacesurfaced multiple pre-existing failures the previous CI runs had been masking. Total scope:Sibling PR: slabgorb/sidequest-content#58 (already merged) — drops
duck_amount_dbfrom 11 genre pack audio.yaml files.ADR-076 code residue
base64 = "0.22"dep from sidequest-game/Cargo.tomlAudioAction::DuckandAudioAction::Restorevariants + Display armsduck_music_for_voiceandduck_amount_dbfields fromMixerConfigAudioConfig::empty()andtest_audio_config()helpersPre-existing test failures fixed
All five were failing on develop tip (190b0b2) before this PR touched anything. Verified independently.
1. builder_produces_confirmation_message
Was calling
to_scene_message()in Confirmation phase, which now panics by design — confirmation rendering moved tosidequest_server::dispatch::chargen_summary::render_confirmation_summary(post-2026-04-09 Thessa playtest bug). The game crate cannot depend on the server crate, so the test was rewritten asbuilder_reaches_confirmation_state_after_full_walkand now asserts on builder state directly.2. standard_array_produces_valid_stats
Test expected raw
[8,10,12,13,14,15]but production at builder.rs:1332-1361 applies derived differentiation whenstat_bonusesis empty: race_hint→first stat +3, class_hint→third stat +2. Dwarf+Fighter choices yield[8,10,12,14,15,18]. Updated assertion to match production with explanatory comment.3. old_chase_state_json_deserializes_as_encounter — REAL BACKWARD COMPAT BUG
Story 28-9 deleted
StructuredEncounter::from_chase_state()because new encounters are built from ConfrontationDef or apply_beat() at runtime. That's true for new encounters, but it never addressed the load-old-save path. Real user save files on disk from before story 16-2 still carry achase: { ... }block — loading them now producedencounter = Noneand silently lost mid-chase state. AddedLegacyChaseStatedeserialization helper in state.rs and a migration arm inFrom<GameSnapshotRaw>that falls back to chase→encounter conversion.4. merchant_transaction_otel_span_emitted
Test used
tracing::subscriber::with_defaultfor thread-local span capture, raced under cargo's parallel execution against other test threads. Replaced withOnceLock+set_global_defaultfor a process-global SpanCapture. The test now finds any merchant.transaction span and verifies its field shape — race-free.5. otel_structured_encounter_story_28_2_tests — 20 of 22 tests in this binary
Two compounding bugs:
Root cause #1:
creature_core::apply_hp_deltawas usingtracing::info_span!instead ofWatcherEventBuilder. Story 28-2 originally instrumented it with WatcherEventBuilder for the GM panel broadcast channel. Story 28-12 added a parallel tracing span for log/jaeger, and somewhere in the rebase the WatcherEventBuilder emission was dropped — only the tracing span survived. Restored the WatcherEventBuilder emission with all six expected fields (name, old_hp, new_hp, delta, max_hp, clamped) and kept the tracing span — both channels stay because they serve different consumers per CLAUDE.md OTEL principle.Root cause #2: lock-poison cascade. Test helper acquired
TELEMETRY_LOCKmutex vialock().unwrap(). When the first broken test panicked while holding the guard, Rust's mutex went into the poisoned state, and every subsequent test callinglock().unwrap()then panicked on the poison error — turning 1 root-cause failure into 20 cascading failures. Fix:lock().unwrap_or_else(|p| p.into_inner()). The mutex guards()so unwrapping past poison is safe and correct.Remaining work (out of scope, tracked as follow-up)
The full workspace test surfaced two more pre-existing failures the previous halts had masked:
equipment_generation_story_31_3_tests::watcher_channel_receives_chargen_equipment_composed_event_on_successful_rolland anotherotel_tests::merchant_context_injected_otel_span_emittedin a separate binary. Both are mechanical fixes following patterns this PR already proved out, but they're separate code paths.Verification
cargo build --workspace --tests: clean🤖 Generated with Claude Code