diff --git a/src/cosmosmesh_privacy_preserving_federated/catopt_bridge.py b/src/cosmosmesh_privacy_preserving_federated/catopt_bridge.py index 1b28b7a..26e3711 100644 --- a/src/cosmosmesh_privacy_preserving_federated/catopt_bridge.py +++ b/src/cosmosmesh_privacy_preserving_federated/catopt_bridge.py @@ -137,6 +137,38 @@ class CatOptBridge: "Version": "0.1", } + def bundle_with_signals( + self, + lp: LocalProblem, + shared: List[SharedVariables], + duals: List[DualVariables], + plan_deltas: Optional[List[PlanDelta]] = None, + ) -> Dict[str, Any]: + """Create a complete CatOpt-like bundle consisting of: + - LocalProblem under Objects + - SharedVariables / DualVariables under Morphisms + - PlanDelta entries under Objects as a list + This is a convenience helper for tests and adapters that need the + full payload in one structure for transport or auditing. + """ + bundle: Dict[str, Any] = {"Version": "0.1"} + bundle["Objects"] = { + "LocalProblem": lp.to_dict(), + } + # Morphisms: collect both shared and dual variables + morphisms: List[Dict[str, Any]] = [] + for s in shared: + morphisms.append(self.map_shared_variables(s)) + for d in duals: + morphisms.append(self.map_dual_variables(d)) + if morphisms: + bundle["Morphisms"] = morphisms + + # Plan deltas as additional objects if provided + if plan_deltas: + bundle["Objects"]["PlanDeltas"] = [pd.to_dict() for pd in plan_deltas] + return bundle + @classmethod def build_round_trip( cls,