fix(eq): resolve base-speaker preset live instead of pinning a stale copy
Build & Deploy PluriWave / Análisis de código (push) Successful in 36s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m30s

_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.
This commit is contained in:
2026-07-10 23:54:01 +02:00
parent bfa95a1e57
commit 8f7ca8059b
10 changed files with 1026 additions and 2 deletions
@@ -0,0 +1,193 @@
# 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 exclude `altavozInterno` (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.1D.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) and `test/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 15, review workload forecast (Low risk, single PR) |
| **Apply Progress** | `sdd/eq-device-disconnect-revert/apply-progress` | #2323 | 2026-07-10 19:02:32 | Phases 14 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 15 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 — the `esBase` guard 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.md` was 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')` is `false` — 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.1D.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 calls `audio.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 `cambiarPresetPrincipal` to push through `_resolverPresetActivo()` for hierarchy consistency
---
## Review Workload Impact
| Metric | Value |
|--------|-------|
| Estimated changed lines (from task forecast) | 130160 |
| 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 14 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:
1.**Explore** — Investigated device-event handling and revert semantics
2.**Propose** — Defined scope and approach
3.**Spec** — Formal 5-requirement specification with 6 scenarios
4.**Design** — Architecture decisions and bootstrap guard detail
5.**Tasks** — Breakdown with phases, forecast, and completeness tracking
6.**Apply** — Implemented with Strict TDD (15/16 tasks automated, 1/16 manual gate)
7.**Verify** — PASS WITH WARNINGS (43/43 tests, 0 CRITICAL, 1 WARNING resolved)
8.**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)
---
**Archived by**: SDD Archive Phase (haiku model)
**Date**: 2026-07-10 (ISO format)
**Project**: pluriwave
**Mode**: Hybrid (Engram + OpenSpec filesystem)