apartment_mapping.json now supplies clean penthouse codes (PH1E, PH1W, PH2E, PH2W) with floor: null. seed_units() inserts those clean rows when absent. The self-heal then looks for legacy dashed rows (PH1E- etc.) and tries to rename them — but skips when the clean code already exists. Result: both legacy and clean rows remain, yielding 8 penthouse rows in the picker instead of 4. Floors are only set on actively renamed legacy rows, so newly inserted clean rows keep floor: null.
Fix
In seed_units() self-heal: when both legacy and clean rows exist for the same penthouse code:
Keep the clean-code row as the canonical survivor
Re-point all tickets referencing the legacy row to the clean row
Delete the legacy row
Ensure the clean row has a floor from _PENTHOUSE_FLOORS
Legacy-only path (rename in place) is unchanged and remains idempotent.
Fixed missing comma in pyproject.toml (unclosed array after sqlalchemy[asyncio])
Tests
Added test_penthouse_consolidation_when_both_forms_exist to tests/test_wahab_directives_20260928.py:
Seeds clean penthouse rows via existing fixture
Inserts legacy malformed rows (PH1E-, PH1W-, PH2E-, PH2W-) with floor=None
Creates a ticket referencing legacy PH1E- unit
Re-runs seed_units()
Asserts: exactly 4 penthouse units in picker, no trailing dash, all floors set, ticket re-pointed to clean PH1E
Full suite: 119 passed
## Root cause
`apartment_mapping.json` now supplies clean penthouse codes (PH1E, PH1W, PH2E, PH2W) with `floor: null`. `seed_units()` inserts those clean rows when absent. The self-heal then looks for legacy dashed rows (PH1E- etc.) and tries to rename them — but skips when the clean code already exists. Result: both legacy and clean rows remain, yielding 8 penthouse rows in the picker instead of 4. Floors are only set on actively renamed legacy rows, so newly inserted clean rows keep `floor: null`.
## Fix
In `seed_units()` self-heal: when both legacy and clean rows exist for the same penthouse code:
1. Keep the clean-code row as the canonical survivor
2. Re-point all tickets referencing the legacy row to the clean row
3. Delete the legacy row
4. Ensure the clean row has a floor from `_PENTHOUSE_FLOORS`
Legacy-only path (rename in place) is unchanged and remains idempotent.
## Also
- Fixed unawaited `await db.delete(legacy_row)` (was missing `await`)
- Fixed missing comma in `pyproject.toml` (unclosed array after `sqlalchemy[asyncio]`)
## Tests
Added `test_penthouse_consolidation_when_both_forms_exist` to `tests/test_wahab_directives_20260928.py`:
- Seeds clean penthouse rows via existing fixture
- Inserts legacy malformed rows (PH1E-, PH1W-, PH2E-, PH2W-) with floor=None
- Creates a ticket referencing legacy PH1E- unit
- Re-runs `seed_units()`
- Asserts: exactly 4 penthouse units in picker, no trailing dash, all floors set, ticket re-pointed to clean PH1E
Full suite: **119 passed**
When the mapping file was cleaned (PH1E- → PH1E) but the legacy dashed
rows were never removed from the live DB, seed_units inserted the clean
rows AND left the legacy rows as inert aliases — yielding 8 penthouse
rows instead of 4, all with floor=null.
The self-heal now handles the 'both forms exist' case by consolidating
to exactly one row per unit: the clean-code row is the canonical
survivor, any tickets referencing the legacy row are re-pointed to it,
and the legacy row is removed. The operation is idempotent.
Also fixes a missing comma in pyproject.toml (TOML parse error).
Adds regression test test_penthouse_consolidation_when_both_forms_exist
that reproduces the live condition and fails pre-fix.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Root cause
apartment_mapping.jsonnow supplies clean penthouse codes (PH1E, PH1W, PH2E, PH2W) withfloor: null.seed_units()inserts those clean rows when absent. The self-heal then looks for legacy dashed rows (PH1E- etc.) and tries to rename them — but skips when the clean code already exists. Result: both legacy and clean rows remain, yielding 8 penthouse rows in the picker instead of 4. Floors are only set on actively renamed legacy rows, so newly inserted clean rows keepfloor: null.Fix
In
seed_units()self-heal: when both legacy and clean rows exist for the same penthouse code:_PENTHOUSE_FLOORSLegacy-only path (rename in place) is unchanged and remains idempotent.
Also
await db.delete(legacy_row)(was missingawait)pyproject.toml(unclosed array aftersqlalchemy[asyncio])Tests
Added
test_penthouse_consolidation_when_both_forms_existtotests/test_wahab_directives_20260928.py:seed_units()Full suite: 119 passed