# Persist dedicated topology when the cache differs

## Background

The prior dedicated-topology conversion change makes `MgmtClusterToModel`
produce the correct topology from active dedicated components. A stale record
can still remain unchanged because the normal update path only compares update
time, delete time, and status. The management conversion currently leaves the
update time unset, so an active cluster whose status is unchanged can bypass
the database update even when its newly derived topology differs.

## Goal and contract

Persist a refreshed topology only when the incoming conversion explicitly
provides a non-nil topology and it differs from the cached value. A missing
incoming topology is not evidence that the cached topology should be cleared.

## Scope

- Root Go module packages: `pkg/datasource/utils` and `pkg/datasource/model`.
- Runtime owner: Clinic API (`cmd/server/main.go`), including its normal
  management-cluster synchronization paths.
- Produced image: `clinic`.
- Required Clinic CD component: `clinic`.
- App-delivery application and workload: `clinic-api` / Clinic Deployment.
- Target environment for validation: staging. Production release is excluded.

## Implementation

1. Add a topology-specific synchronization predicate that returns true only
   when the desired topology is non-nil and differs from the persisted value.
2. Include that predicate in the existing cloud and next-generation cluster
   update decisions, without changing their existing status/delete/update-time
   checks or the GORM update column selection.
3. Add table-driven unit tests covering unchanged topology, a missing desired
   topology, a missing cached topology, and a changed replica count.
4. Run the focused package test and inspect the diff before requesting PR
   publication authorization.

## Exclusions and compatibility

- Do not restore `Select("*")` or introduce a full-row overwrite.
- Do not make an unset management-service update time force every row to be
  rewritten.
- Do not change synchronization semantics for unrelated fields or backfill all
  historical records.
- Existing API shapes remain unchanged; a dedicated cluster updates its cached
  topology on its next normal synchronization only when its derived topology
  is different.

## Validation and release boundary

Run `go test ./pkg/datasource/utils` from the repository root. If a PR is
authorized, staging validation requires Clinic CD from the feature branch with
`environment=staging` and `components=clinic`, then the normal app-delivery
and GitOps rollout checks. Merge and production release require separate
authorization.
