The current test `test_rootless_after_close_does_not_crash` in `tests/test_midi_writer.py` only asserts `len(result.resolved[1]["midi"]) == 3` — a smoke check that nothing crashes. Flagged in the Task 7 code review as too weak: would pass even if the algorithm produced `[60, 60, 60]`.
Suggested: add an assertion on the bass pitch class. For `ii7` rootless in C (D-F-A-C → drop D → F-A-C), the bass should be F (pc 5) at root inversion. This catches a regression where rootless silently dropped a different voice.
```python
After the existing length check
bass_pc = min(result.resolved[1]["midi"]) % 12
assert bass_pc == 5 # F, the 3rd of ii7 (root D was dropped)
```
Context: review notes from docs/superpowers/plans/2026-04-28-voice-leading.md (Task 7 review, ticket #1).
The current test `test_rootless_after_close_does_not_crash` in `tests/test_midi_writer.py` only asserts `len(result.resolved[1]["midi"]) == 3` — a smoke check that nothing crashes. Flagged in the Task 7 code review as too weak: would pass even if the algorithm produced `[60, 60, 60]`.
Suggested: add an assertion on the bass pitch class. For `ii7` rootless in C (D-F-A-C → drop D → F-A-C), the bass should be F (pc 5) at root inversion. This catches a regression where rootless silently dropped a different voice.
```python
After the existing length check
bass_pc = min(result.resolved[1]["midi"]) % 12
assert bass_pc == 5 # F, the 3rd of ii7 (root D was dropped)
```
Context: review notes from
docs/superpowers/plans/2026-04-28-voice-leading.md(Task 7 review, ticket #1).