2525from habitat_local_eaios .shared_world import SharedEmosStage2Runtime # noqa: E402
2626from habitat_local_eaios .spatial_feasibility import ( # noqa: E402
2727 FloorTransitionProfile ,
28+ _digest ,
2829 assess_spatial_feasibility ,
2930 build_spatial_profile_snapshot ,
3031 load_spatial_profile_snapshot ,
32+ verify_spatial_profile_sources ,
3133)
3234
3335_ROOT = Path (__file__ ).parents [3 ]
@@ -127,6 +129,7 @@ def test_exact_node_registration_snapshot_round_trip_and_source_change(tmp_path:
127129 profiles = load_spatial_profile_snapshot (snapshot )
128130 assert [profile .node_id for profile in profiles ] == ["e1-shared-node-a" , "e1-shared-node-b" ]
129131 assert [profile .support_for ("mobility.move@v1" ) for profile in profiles ] == [True , False ]
132+ verify_spatial_profile_sources (snapshot , ((0 , a ), (1 , b )))
130133 tampered = json .loads (snapshot .read_text (encoding = "utf-8" ))
131134 tampered ["agents" ][1 ]["operation_support" ]["mobility.move@v1" ] = True
132135 snapshot .write_text (json .dumps (tampered ), encoding = "utf-8" )
@@ -141,6 +144,34 @@ def test_exact_node_registration_snapshot_round_trip_and_source_change(tmp_path:
141144 load_spatial_profile_snapshot (snapshot )
142145
143146
147+ @pytest .mark .parametrize ("field" , ["operation_support" , "node_id" , "agent_id" ])
148+ def test_resealed_spatial_profile_cannot_replace_node_source_facts (
149+ tmp_path : Path , field : str
150+ ) -> None :
151+ """A fresh digest cannot replace exact Node capability or endpoint declarations."""
152+ source = _ROOT / "scenarios/e1-shared-world-episode-51"
153+ a = tmp_path / "a.toml"
154+ b = tmp_path / "b.toml"
155+ a .write_bytes ((source / "node-a.toml" ).read_bytes ())
156+ b .write_bytes ((source / "node-b.toml" ).read_bytes ())
157+ snapshot = tmp_path / "profile.json"
158+ document = build_spatial_profile_snapshot (((0 , a ), (1 , b )))
159+ second = cast (dict [str , Any ], cast (list [Any ], document ["agents" ])[1 ])
160+ if field == "operation_support" :
161+ support = cast (dict [str , bool ], second ["operation_support" ])
162+ support ["mobility.move@v1" ] = True
163+ elif field == "node_id" :
164+ second ["node_id" ] = "substituted-node"
165+ else :
166+ second ["agent_id" ] = 2
167+ body = {key : value for key , value in document .items () if key != "digest" }
168+ document ["digest" ] = _digest (body )
169+ snapshot .write_text (json .dumps (document ), encoding = "utf-8" )
170+ load_spatial_profile_snapshot (snapshot )
171+ with pytest .raises (IntegrationError , match = "differs from configured Node sources" ):
172+ verify_spatial_profile_sources (snapshot , ((0 , a ), (1 , b )))
173+
174+
144175@pytest .mark .parametrize (
145176 ("support" , "expected" ),
146177 [(False , "incompatible" ), (True , "compatible" ), (None , "unknown" )],
0 commit comments