11from __future__ import annotations
22
3+ import copy
4+
5+ import pytest
6+
7+ from loopx .control_plane .quota .cli_projection import compact_quota_should_run_cli_payload
8+ from loopx .control_plane .quota .turn_envelope import (
9+ build_turn_envelope , quota_action_signature_document ,
10+ turn_envelope_action_signature_document ,
11+ )
12+ from loopx .control_plane .testing .control_plane_composition_scenarios import (
13+ _required_vision_replan_source ,
14+ )
15+
316from loopx .control_plane .scheduler .execution_context import (
417 GENERIC_CLI_OUTER_CONTROLLER_SCHEDULER_CONTEXT ,
518)
@@ -114,7 +127,8 @@ def test_quota_delivers_coverage_context_and_minimal_replan_action() -> None:
114127 "delivered_by" : "quota_host_projection" ,
115128 }
116129 assert context ["coverage_ledger" ][0 ]["surface_id" ] == "surface-existing"
117- assert action == {
130+ assert len (action ["planning_guidance" ]) == 2
131+ assert {key : value for key , value in action .items () if key != "planning_guidance" } == {
118132 "schema_version" : "replan_action_packet_v0" ,
119133 "decision" : "replan_required" ,
120134 "obligation_id" : obligation ["obligation_id" ],
@@ -138,3 +152,37 @@ def test_manual_evidence_read_receipt_cannot_close_replan() -> None:
138152 assert payload ["decision" ] == "autonomous_replan_required"
139153 assert payload ["autonomous_replan_obligation" ]["required" ] is True
140154 assert payload .get ("replan_ack_feedback" ) is None
155+
156+
157+ @pytest .mark .parametrize ("vision_gap" , [False , True ])
158+ def test_replan_guidance_survives_cli_and_host_compaction_without_new_authority (vision_gap : bool ) -> None :
159+ source = (_required_vision_replan_source (goal_id = GOAL_ID , agent_id = AGENT_ID )
160+ if vision_gap else _quota_payload ())
161+ guidance = source ["replan_action_packet" ]["planning_guidance" ]
162+ # These are delivery assertions, not a claim that a model follows the advice.
163+ assert len (guidance ) == 2
164+ assert "Never shrink requested goals" in guidance [0 ]
165+ assert "honor user scope, authority, budget and stops" in guidance [0 ]
166+ assert "current authoritative evidence for every requirement" in guidance [1 ]
167+ assert "unproven" in guidance [1 ]
168+ assert "blocked/exhausted/superseded is not achieved" in guidance [1 ]
169+ compact = compact_quota_should_run_cli_payload (source )
170+ envelope = build_turn_envelope (source )
171+ for packet in (compact , envelope ):
172+ assert packet ["replan_action_packet" ]["planning_guidance" ] == guidance
173+
174+ baseline = copy .deepcopy (source )
175+ baseline ["replan_action_packet" ].pop ("planning_guidance" )
176+ old_envelope = build_turn_envelope (baseline )
177+ # Prompt advice cannot change executable actions, authority or settlement.
178+ assert envelope ["action" ] == old_envelope ["action" ]
179+ signature = quota_action_signature_document (source )
180+ assert turn_envelope_action_signature_document (envelope ) == signature
181+ signature ["replan_action_packet" ].pop ("planning_guidance" )
182+ assert signature == quota_action_signature_document (baseline )
183+ # Preserve an existing budget warning; bounded advice adds no more than 360 bytes.
184+ assert envelope ["compaction" ]["within_budget" ] == old_envelope ["compaction" ]["within_budget" ]
185+ assert (envelope ["compaction" ]["envelope_json_bytes" ]
186+ - old_envelope ["compaction" ]["envelope_json_bytes" ]) <= 360
187+ envelope ["replan_action_packet" ].pop ("planning_guidance" )
188+ assert envelope ["replan_action_packet" ] == old_envelope ["replan_action_packet" ]
0 commit comments