_onDispositivoCambiado() bootstrapped a device-level preset entry for every never-seen device id, including the built-in speaker. That persistent level-3 entry masked later global-preset edits (level 3 beats level 4 on every resolution), so disconnecting a BT device or cold-starting without one could leave the EQ stuck on an outdated copy instead of the current global preset. The base speaker is now excluded from the first-seen bootstrap: disconnect and cold start always resolve through the live hierarchy. BT/wired/USB devices keep their bootstrap behavior unchanged.
9.6 KiB
Archive Report: EQ Device Disconnect / Cold-Start Revert
Change: eq-device-disconnect-revert
Archive Date: 2026-07-10
Artifact Store Mode: hybrid
Status: ARCHIVED
Verification Verdict
PASS WITH WARNINGS
- Critical Issues: 0
- Warnings: 1
- Suggestions: 3
- Tests Passed: 43/43 (target file), 68/68 (target + regression suite)
- Tasks Complete: 15/16 (Phase 5.1 intentionally pending as non-blocking manual gate)
Change Summary
Scope: EQ device disconnect handling and cold-start resolution guarantee
What was changed:
- Added first-seen bootstrap guard in
_onDispositivoCambiado()to excludealtavozInterno(base speaker) from device-preset caching, ensuring the base device always resolves live through the 4-level hierarchy (matrix → station → device → global) - Added 5 new test cases (D.1–D.5) covering disconnect revert, cold-start guarantees, connect-disconnect-reconnect cycles, station/matrix override interaction, and toggle-off invariance
- All changes isolated to
lib/estado/estado_ecualizador.dart(~9 lines modified) andtest/estado/estado_ecualizador_test.dart(~214 lines added)
Why it matters:
- Fixes a correctness gap: disconnect and cold-start events now explicitly re-resolve and apply the EQ preset, not coincidentally
- Closes a L3-masks-L4 bug: base speaker can no longer be pinned by a stale device-level entry from the old bootstrap
- Maintains full byte-for-byte compatibility when multi-device EQ is disabled
Engram Artifacts (Observation IDs for Traceability)
All SDD artifacts persisted to Engram project pluriwave for cross-session recovery and audit trail:
| Artifact | Topic Key | Observation ID | Created | Details |
|---|---|---|---|---|
| Proposal | sdd/eq-device-disconnect-revert/proposal |
#2301 | 2026-07-10 17:53:45 | Intent, scope, approach, risks, rollback plan |
| Spec (Delta) | sdd/eq-device-disconnect-revert/spec |
#2306 | 2026-07-10 17:59:15 | 5 formal requirements, 6 scenarios; no prior main spec existed |
| Design | sdd/eq-device-disconnect-revert/design |
#2303 | 2026-07-10 17:58:01 | 6 architecture decisions, bootstrap guard fix, testing strategy |
| Tasks | sdd/eq-device-disconnect-revert/tasks |
#2315 | 2026-07-10 18:11:25 | Phases 1–5, review workload forecast (Low risk, single PR) |
| Apply Progress | sdd/eq-device-disconnect-revert/apply-progress |
#2323 | 2026-07-10 19:02:32 | Phases 1–4 complete (15 tasks), TDD cycle evidence, deviations log |
| Verify Report | sdd/eq-device-disconnect-revert/verify-report |
#2325 | 2026-07-10 23:38:59 | Completeness, spec compliance, coherence, TDD compliance, assertions, issues found |
This Archive Report will be persisted to Engram as:
- Topic Key:
sdd/eq-device-disconnect-revert/archive-report - Type: architecture
- Project: pluriwave
Spec Merge Status
Delta Spec → Main Spec
| Action | File | Result |
|---|---|---|
| Create | openspec/specs/multi-device-eq/spec.md |
✅ Created (no prior spec existed; delta copied as full spec) |
Content merged: 5 ADDED Requirements with 6 scenarios (no MODIFIED or REMOVED entries). All requirements cover disconnect/cold-start revert behavior within the 4-level EQ hierarchy. On-disk delta spec at openspec/changes/eq-device-disconnect-revert/specs/multi-device-eq/spec.md was used as authoritative source (post-verify refinement applied by orchestrator to resolve WARNING-1 wording drift).
Filesystem Archive Structure
Move completed: openspec/changes/eq-device-disconnect-revert/ → openspec/changes/archive/2026-07-10-eq-device-disconnect-revert/
Contents preserved:
- ✅
proposal.md— Intent and approach - ✅
design.md— Architecture decisions and bootstrap guard fix - ✅
tasks.md— Phases 1–5 with task checklist - ✅
specs/multi-device-eq/spec.md— Full delta spec (5 requirements) - ✅
verify-report.md— Completeness, spec compliance, TDD compliance - ✅
state.yaml— DAG state (archived status recorded) - ✅
archive-report.md— This document
Artifacts NOT in openspec/:
- Engram artifacts remain in Engram at topic keys listed above (not moved; persisted independently)
Issue Tracking and Resolutions
Verification WARNING (1)
WARNING-1: Spec Text / Implementation Divergence on Requirement 2
- Description: Spec scenario literally states
presetsDispositivo['builtin_speaker']is bootstrapped to the global preset with the implication the entry is created. Implementation (matching Design Decision #2) NEVER creates that entry — theesBaseguard unconditionally skips the bootstrap block. - Status: ✅ RESOLVED (post-verify spec refinement)
- Resolution: The on-disk spec file at
openspec/changes/eq-device-disconnect-revert/specs/multi-device-eq/spec.mdwas edited by the orchestrator post-verify to correct the THEN clause: now states no entry is ever created and resolution always falls through to the hierarchy. This is functionally correct and safer than the literal wording. - Proof: Test D.2 asserts
presetsDispositivo.containsKey('builtin_speaker')isfalse— proves no entry exists, and the edit aligns the spec with this proven behavior.
Verification SUGGESTIONS (3)
SUGGESTION-1: Reconcile spec text per WARNING-1 resolution (already done in on-disk file; no action needed).
SUGGESTION-2: Apply-progress TDD Cycle Evidence table uses 3-column format (RED/GREEN/REFACTOR) instead of full 5-column strict-TDD template. Substance is present; format nitpick for future runs.
SUGGESTION-3: Pre-existing cambiarPresetPrincipal() hierarchy-bypass (applies raw global instead of re-resolving) observed during apply, noted as tracked tech debt. Out of scope for this change; recommend a follow-up ticket.
Non-Blocking Items
Task 5.1: On-Device Manual Sanity Check — PENDING
- Description: Connect BT/USB device with own preset, disconnect (verify revert to base), reconnect (verify return to device preset)
- Status: Intentionally unchecked
- Reason: Non-automatable human gate requiring real hardware; verified via automated unit tests (D.1–D.5) to be theoretically sound
- Blocking the release?: No. Can be executed anytime on real hardware as a confidence check; not required for PR merge.
Tech Debt Carried Forward
Pre-existing cambiarPresetPrincipal() Bypass
- Description: The
cambiarPresetPrincipal()method immediately callsaudio.aplicarPresetActivo(preset), bypassing_resolverPresetActivo()and applying the raw global preset directly without re-resolving the hierarchy. This could allow a station or matrix override to be transiently bypassed for one apply call. - Scope: Out of scope for this change; pre-existing behavior unrelated to disconnect/cold-start revert
- Recommendation: Follow-up ticket to refactor
cambiarPresetPrincipalto push through_resolverPresetActivo()for hierarchy consistency
Review Workload Impact
| Metric | Value |
|---|---|
| Estimated changed lines (from task forecast) | 130–160 |
| Actual changed lines (via git) | ~221 (9 lib + 214 test) |
| 400-line budget risk | Low |
| Chained PRs recommended | No |
| Delivery strategy applied | ask-on-risk → single PR (no split needed) |
Completeness Checklist
| Item | Status | Notes |
|---|---|---|
| Proposal read and logged | ✅ | #2301 |
| Spec read and merged | ✅ | #2306 → openspec/specs/multi-device-eq/spec.md |
| Design read and verified | ✅ | #2303, all 6 decisions followed |
| Tasks read and tracked | ✅ | #2315, 15/16 complete |
| Apply progress read | ✅ | #2323, Phases 1–4 complete |
| Verify report read and resolved | ✅ | #2325, PASS WITH WARNINGS, WARNING resolved in spec |
| All artifacts moved to archive | ✅ | Filesystem and Engram copies established |
| State recorded (archived) | ✅ | state.yaml written with status and notes |
| Archive report created | ✅ | This document (both filesystem and Engram) |
SDD Cycle Complete
This change has successfully completed all phases:
- ✅ Explore — Investigated device-event handling and revert semantics
- ✅ Propose — Defined scope and approach
- ✅ Spec — Formal 5-requirement specification with 6 scenarios
- ✅ Design — Architecture decisions and bootstrap guard detail
- ✅ Tasks — Breakdown with phases, forecast, and completeness tracking
- ✅ Apply — Implemented with Strict TDD (15/16 tasks automated, 1/16 manual gate)
- ✅ Verify — PASS WITH WARNINGS (43/43 tests, 0 CRITICAL, 1 WARNING resolved)
- ✅ Archive — All artifacts consolidated, spec merged, change moved to archive
Ready for: Next change or release planning
Artifact Links
- Main spec:
openspec/specs/multi-device-eq/spec.md - Archived change folder:
openspec/changes/archive/2026-07-10-eq-device-disconnect-revert/ - Engram topic keys (full content via mem_get_observation):
- Proposal:
sdd/eq-device-disconnect-revert/proposal(#2301) - Spec:
sdd/eq-device-disconnect-revert/spec(#2306) - Design:
sdd/eq-device-disconnect-revert/design(#2303) - Tasks:
sdd/eq-device-disconnect-revert/tasks(#2315) - Apply Progress:
sdd/eq-device-disconnect-revert/apply-progress(#2323) - Verify Report:
sdd/eq-device-disconnect-revert/verify-report(#2325) - Archive Report:
sdd/eq-device-disconnect-revert/archive-report(this document)
- Proposal:
Archived by: SDD Archive Phase (haiku model)
Date: 2026-07-10 (ISO format)
Project: pluriwave
Mode: Hybrid (Engram + OpenSpec filesystem)