"""service_seen — delete the roster rows the fixed code can no longer write. Operator, 2026-09-23: *"clean up the stale service_seen rows"*. They were not stale. They were PHANTOMS, written on purpose by code that identified a celery worker from the queues it was consuming. A lane at cap 0 has its consumers cancelled, so it answers `active_queues()` with an empty list. The roster grouped on that empty set, wrote it under the key `celery:` and rendered `role_display_name(())` as the display name — a row called **`Worker ()`**, reported as running, beside the real lane's row going stale because nothing updated it any more. `worker_lanes.lane_for_node` fixes the cause: a worker is attributed by its NODE NAME, which survives having no consumers. Nothing will write `celery:` again. ## Why a migration and not a retention sweep Lesson #4202: a guard that refuses to produce a bad value does not undo the bad value already stored. The row is the thing that has to change. And it must be deleted rather than aged out, because the roster deliberately NEVER forgets — *"anything that has run at least once stays listed, that is what lets a stopped one be noticed rather than simply vanishing"*. A row that merely goes quiet is exactly what the roster is for. Only a row that cannot correspond to anything real is safe to remove, and `celery:` is precisely that: the empty queue set, which no correctly-attributed worker can produce. ## What is deliberately NOT deleted **Celery rows with a real but unmatched queue set.** A deployment slicing `CELERY_QUEUES` differently is supported and its rows are true. It is not this migration's business to decide that somebody else's worker is obsolete. **Agent rows, including a possible `agent:agent` from a build that omitted `agent_id`.** Nothing here can tell an abandoned agent id from a second agent that is currently down, and deleting a real one would hide a genuinely dead GPU agent — the one thing the roster exists to show. If such a row is present it needs a person to look at it, not a migration guessing. Revision ID: 0106 Revises: 0105 Create Date: 2026-09-23 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0106" down_revision: Union[str, None] = "0105" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # Exactly the one key the empty queue set produced. Matched literally # rather than by a LIKE or a prefix: `celery:` with nothing after it is # the phantom, and `celery:ml` is a real lane. op.execute( sa.text("DELETE FROM service_seen WHERE key = :key").bindparams(key="celery:") ) def downgrade() -> None: # Nothing. The row carried no information — an empty queue set and a # timestamp — and the roster re-learns anything real on its next refresh. # Re-creating it would put a phantom back. pass