2d03f2d507
The artifact apply (DeploymentManagerActor.HandleDeployArtifacts) was upsert-only, so deleting an external system (or shared script, DB connection, data connection) centrally never removed the site's SQLite row — a deleted external system stayed callable from site scripts forever. Central always ships the COMPLETE set of each artifact class (ArtifactDeploymentService GetAll* snapshots; the wire's presence-tracking wrapper lists preserve null-vs-empty), so the site now applies upsert-then-reconcile: after storing the incoming set, SiteStorageService.DeleteRowsExceptAsync removes any stored row absent from it, per artifact table. A null list still means 'field not shipped' and touches nothing. Runtime cleanup rides along: a reconciled-away shared script is unregistered from the compiled SharedScriptLibrary (a stale delegate would stay callable until restart), and a removed data connection is evicted from the DCL hash cache and its live connection actor stopped via the previously-caller-less RemoveConnectionCommand — both on the actor thread via the extended ApplyArtifactDataConnectionsToDcl message. All four tables are RegisterReplicated, so the deletes reach the standby as ordinary CDC row tombstones. Tests: storage-level reconcile per table (incl. empty-set-deletes-all and idempotency) in ArtifactStorageTests; actor-level pins in DeploymentManagerActorTests (orphan delete, null-set no-op, library unregistration, DCL stop for the removed connection only). Docs: Component-DeploymentManager + Component-SiteRuntime record the full-set/reconcile semantics.