pub async fn object_set_storage_class(
profile_id: ProfileId,
targets: Vec<ObjectRef>,
new_storage_class: String,
confirmed_diff_id: DiffId,
store: State<'_, ProfileStoreHandle>,
pool: State<'_, S3ClientPoolHandle>,
locks: State<'_, LockRegistryHandle>,
cache: State<'_, CacheHandle>,
channel: AppHandle,
diff_store: State<'_, DiffStoreHandle>,
) -> Result<Vec<PutResult>, AppError>Expand description
Change the storage class of one or more objects.
§Safety gate (diff framework)
This command requires a confirmed_diff_id that was previously created via
diff_preview_create. The id is consumed atomically on entry:
- If the diff does not exist, was cancelled, or expired →
Validationerror. - If the diff was already consumed (double-confirm rejection) →
Validationerror. - If the diff payload does not match the requested targets/class →
Validationerror.
This is the single authoritative enforce point for the “no blind storage class change” invariant from Decision D2.
§Decision D2 (optimistic boundary)
Storage class change is explicitly NOT subject to optimistic updates.
The command emits objects:updated per target on success, which allows the
frontend’s event-driven path to refresh the listing. No optimistic.ts
helper exists for this operation (asserted in
storage_class_change_does_not_use_optimistic_path).
§Event emission (round-1 finding #14)
objects:updated { profileId, bucket, prefix } is emitted for each
successfully changed object’s parent prefix.