Background
BA-5963 fixed the immediate symptom where the API response could expose the deploying revision id under current_revision_id during a rolling update. The underlying structural problem remains: _convert_deployment_info_to_data is a fragile bridge between two domain types that were never aligned for the API path.
DeploymentInfo is a sokovan/lifecycle-oriented projection. It carries model_revisions filtered down to {current, deploying} only, with no preserved ordering. ModelDeploymentData is the API/DTO-oriented type. The current code path is EndpointRow -> to_deployment_info -> DeploymentInfo -> _convert_deployment_info_to_data -> ModelDeploymentData -> _deployment_data_to_dto -> DeploymentNode. Each hop drops or re-derives fields and the conversion is easy to break (current_revision_id was being re-derived from revision[0].id; revision_history_ids has been reduced to a single-element list; replica_ids and scaling_rule_ids are forced to []; default_deployment_strategy is hardcoded to ROLLING).
Conceptually the API simply needs a ModelDeploymentData read straight from the EndpointRow. The DeploymentInfo intermediate adds risk without value for this path.
Proposal
Add a dedicated method on DeploymentRepository (e.g. get_model_deployment_data(deployment_id) and a batch search variant) that loads the EndpointRow with the eager loads required for ModelDeploymentData and returns ModelDeploymentData directly. Migrate the API-facing service methods to use it; keep DeploymentInfo only for the sokovan/lifecycle/scheduling callers it was designed for.
Scope
- New repo method(s): get_model_deployment_data(deployment_id) and a batch/search variant covering the call sites currently using _convert_deployment_info_to_data in services/deployment/service.py.
- New row-level conversion lives next to the EndpointRow (not as a service helper) so eager-load requirements stay co-located with the SQL.
- Migrate all API/service code paths that produce ModelDeploymentData (get, search, create response, update response, activate_revision response, etc.) to the new method.
- Delete _convert_deployment_info_to_data once no caller remains, or keep it only for explicitly documented non-API callers.
- Adapter._deployment_data_to_dto stops re-deriving current_revision_id from revision (already cleaned up by BA-5963; verify nothing regresses).
Acceptance Criteria
- DeploymentRepository exposes a method returning ModelDeploymentData without going through DeploymentInfo.
- All API/service call sites that previously produced ModelDeploymentData via _convert_deployment_info_to_data now use the new repo method.
- Response correctness: current_revision_id and deploying_revision_id reflect the DB columns directly under all orderings of the underlying revisions relationship (verified by a unit test that reverses the loaded revisions list).
- Dangling-reference safety: when endpoints.current_revision points to a missing deployment_revisions row, the API still returns the column value (not null) and surfaces a structured warning, matching the safety net introduced by BA-5963.
- No new N+1 queries; eager loads are co-located with the new repo method.
- Existing tests pass; new tests cover the reorder and dangling-reference cases.
Out of Scope
- Refactoring DeploymentInfo or its sokovan/lifecycle consumers.
- Adding a database-level FK on endpoints.current_revision / endpoints.deploying_revision (track separately if desired).
Related
JIRA Issue: BA-5979
Background
BA-5963 fixed the immediate symptom where the API response could expose the deploying revision id under current_revision_id during a rolling update. The underlying structural problem remains: _convert_deployment_info_to_data is a fragile bridge between two domain types that were never aligned for the API path.
DeploymentInfo is a sokovan/lifecycle-oriented projection. It carries model_revisions filtered down to {current, deploying} only, with no preserved ordering. ModelDeploymentData is the API/DTO-oriented type. The current code path is EndpointRow -> to_deployment_info -> DeploymentInfo -> _convert_deployment_info_to_data -> ModelDeploymentData -> _deployment_data_to_dto -> DeploymentNode. Each hop drops or re-derives fields and the conversion is easy to break (current_revision_id was being re-derived from revision[0].id; revision_history_ids has been reduced to a single-element list; replica_ids and scaling_rule_ids are forced to []; default_deployment_strategy is hardcoded to ROLLING).
Conceptually the API simply needs a ModelDeploymentData read straight from the EndpointRow. The DeploymentInfo intermediate adds risk without value for this path.
Proposal
Add a dedicated method on DeploymentRepository (e.g. get_model_deployment_data(deployment_id) and a batch search variant) that loads the EndpointRow with the eager loads required for ModelDeploymentData and returns ModelDeploymentData directly. Migrate the API-facing service methods to use it; keep DeploymentInfo only for the sokovan/lifecycle/scheduling callers it was designed for.
Scope
Acceptance Criteria
Out of Scope
Related
JIRA Issue: BA-5979