Route every current_package_state status change through one transitionStatus
path: read the observed status, validate against PackageStatusTransitions,
run a status-guarded UPDATE, record terminal history. Replaces ten raw-SQL
transition functions whose WHERE guards validated nothing and silently
no-op'd on an illegal state. ApproveUpdate, the Reject/Install/Set* family,
BulkApprove and UpdatePackageStatus now share the core; illegal moves return
a named from->to error instead of a silent miss, and concurrent callers are
caught by the guarded row count.
Migration 047 renames the terminal success state updated -> installed in
current_package_state and update_version_history, realigning both CHECK
constraints with the Go PackageStatus/HistoryStatus constants.
UpdateStats updated_updates -> installed_updates to match.
UpdateCurrentStateInTx documents its reconcile CASE as the SQL twin of
models.ReconcileFromScan so the two stay in lockstep.
Dashboard: vulnerable-package count surfaced in AttentionPanel, plus a
Vulnerable quick-filter on the Updates view.