"""Add identity_persons.manager_external_id (HRIS-declared managerId). Revision ID: 270 Revises: 269 Create Date: 2026-06-09 Why this exists --------------- The HRIS sync resolves ``manager_person_id`` from SF ``EmpJob.managerId`` and *clears it on a miss* (a stale pointer to a former manager is worse than a brief NULL gap — Round-20 audit). But nothing re-linked the subordinate once the declared manager finally onboarded into Helix, so a person whose manager was synced *after* them kept ``manager_person_id = NULL`` forever — surfacing as a false ``missing_manager`` data-quality finding even though HRIS clearly carried a managerId (prod 2026-06-09: 10 of 13 "缺汇报对象" findings were this, not a real HRIS gap). Persisting the raw declared id here lets ``identity.identity_reconcile.backfill_manager_links`` close the gap on the next sync, and lets the data-quality scanner distinguish a genuine HRIS "no manager" (NULL → org-apex / real gap) from a Helix link failure (non-NULL + NULL ``manager_person_id`` → resolvable). Pure additive nullable column — fully online on TiDB, no data migration. Population happens on the next sync (both sync paths now write it) and via a one-off backfill of the declared id from the latest staged event. String(128) matches ``hris_person_id`` so any managerId fits. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "270" down_revision = "269" branch_labels = None depends_on = None def upgrade() -> None: op.add_column( "identity_persons", sa.Column("manager_external_id", sa.String(length=128), nullable=True), ) def downgrade() -> None: op.drop_column("identity_persons", "manager_external_id")