From d086f6a85e687daffcbc5d946724d34a4ff07b2d Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Mon, 6 Apr 2026 01:32:23 +0000 Subject: [PATCH] fix: Update e2e tests for new JSON response structure with data field The CleverAgents CLI now returns JSON responses with a nested 'data' field wrapper. Updated all e2e tests to handle this new structure: - M5: Fixed fragment_count, tier_budget, budget_used, plan_id field access - M6: Updated automation profile and phase/state field access - WF04: Fixed plan_id extraction from plan use response - WF05: Updated all Safe Parse Json Field calls to use nested support - WF07: Updated remaining Safe Parse Json Field call - WF12: Fixed phase/processing_state field access - WF17: Updated all JSON field parsing for phase and execution environment All tests now use 'Safe Parse Json Field With Nested Support' which handles the data.fieldname path correctly for the new JSON structure. --- robot/e2e/m5_acceptance.robot | 34 ++++++++++++------------- robot/e2e/m6_acceptance.robot | 30 +++++++++++----------- robot/e2e/wf04_multi_project.robot | 4 +-- robot/e2e/wf05_db_migration.robot | 14 +++++----- robot/e2e/wf07_cicd.robot | 4 +-- robot/e2e/wf12_hierarchical.robot | 20 +++++++-------- robot/e2e/wf17_explicit_container.robot | 14 +++++----- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/robot/e2e/m5_acceptance.robot b/robot/e2e/m5_acceptance.robot index 230fbd822..0cd7aa4c5 100644 --- a/robot/e2e/m5_acceptance.robot +++ b/robot/e2e/m5_acceptance.robot @@ -229,11 +229,11 @@ Context Scaling — Structural Plumbing for 10K File Projects ${sim_json}= Extract JSON From Stdout ${result.stdout} Should Be True 'data' in $sim_json and 'total_tokens' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'total_tokens' field - Should Be True 'fragment_count' in $sim_json + Should Be True 'fragment_count' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'fragment_count' field Should Be True type($sim_json.get('data', {}).get('total_tokens')) in (int, float) ... msg=total_tokens should be numeric - Should Be True type($sim_json.get('fragment_count')) in (int, float) + Should Be True type($sim_json.get('data', {}).get('fragment_count')) in (int, float) ... msg=fragment_count should be numeric # ----------------------------------------------------------------------- @@ -290,7 +290,7 @@ Context Policy — Verify Default View Should Be Equal As Integers ${result.rc} 0 ${policy_json}= Extract JSON From Stdout ${result.stdout} # When --view is specified, the JSON uses 'resolved_view' (not 'default_view'). - ${rv}= Evaluate $policy_json.get('resolved_view', {}) + ${rv}= Evaluate $policy_json.get('data', {}).get('resolved_view', {}) Should Be True $rv.get('max_file_size') == 262144 ... msg=resolved default view max_file_size should be 262144 Should Be True $rv.get('max_total_size') == 1048576 @@ -312,7 +312,7 @@ Context Policy — Verify Strategize View Should Be Equal As Integers ${result.rc} 0 ${policy_json}= Extract JSON From Stdout ${result.stdout} # When --view is specified, the JSON uses 'resolved_view'. - ${rv}= Evaluate $policy_json.get('resolved_view', {}) + ${rv}= Evaluate $policy_json.get('data', {}).get('resolved_view', {}) Should Be True $rv.get('max_file_size') == 131072 ... msg=resolved strategize view max_file_size should be 131072 Should Be True 'docs/**/*.md' in $rv.get('include_paths', []) @@ -349,7 +349,7 @@ Budget Enforcement — Verify Constraints Stored Should Be Equal As Integers ${result.rc} 0 ${policy_json}= Extract JSON From Stdout ${result.stdout} # When --view is specified, the JSON uses 'resolved_view'. - ${rv}= Evaluate $policy_json.get('resolved_view', {}) + ${rv}= Evaluate $policy_json.get('data', {}).get('resolved_view', {}) Should Be True $rv.get('max_file_size') == 1024 ... msg=Budget resolved view max_file_size should be 1024 Should Be True $rv.get('max_total_size') == 4096 @@ -386,7 +386,7 @@ Budget Enforcement — Simulate Context Assembly (Structural) ... msg=Simulate JSON missing 'acms_config' field Should Be True 'data' in $sim_json and 'total_tokens' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'total_tokens' field - Should Be True 'fragment_count' in $sim_json + Should Be True 'fragment_count' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'fragment_count' field Should Be True type($sim_json.get('data', {}).get('total_tokens')) in (int, float) ... msg=total_tokens should be numeric @@ -436,7 +436,7 @@ Context Analysis — Inspect Context Tiers (Structural) ${inspect_json}= Extract JSON From Stdout ${result.stdout} Should Be True 'data' in $inspect_json and 'tier_metrics' in $inspect_json.get('data', {}) ... msg=Inspect JSON missing 'tier_metrics' field - Should Be True 'tier_budget' in $inspect_json + Should Be True 'tier_budget' in $inspect_json.get('data', {}) ... msg=Inspect JSON missing 'tier_budget' field # Verify tier_metrics contains the expected field names (schema check). ${metrics}= Evaluate $inspect_json.get('data', {}).get('tier_metrics', {}) @@ -451,7 +451,7 @@ Context Analysis — Inspect Context Tiers (Structural) # not the ACMS config. Values are always the TierBudget defaults # (8000/500/5000) because the tier service is a fresh singleton per # CLI process with no indexed data. - ${budget}= Evaluate $inspect_json.get('tier_budget', {}) + ${budget}= Evaluate $inspect_json.get('data', {}).get('tier_budget', {}) Should Be True 'max_tokens_hot' in $budget ... msg=tier_budget missing 'max_tokens_hot' field Should Be True 'max_decisions_warm' in $budget @@ -480,16 +480,16 @@ Context Analysis — Simulate Produces Structured Output ${sim_json}= Extract JSON From Stdout ${result.stdout} Should Be True 'data' in $sim_json and 'total_tokens' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'total_tokens' field - Should Be True 'budget_used' in $sim_json + Should Be True 'budget_used' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'budget_used' field - Should Be True 'strategies_used' in $sim_json + Should Be True 'strategies_used' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'strategies_used' field - Should Be True 'context_hash' in $sim_json + Should Be True 'context_hash' in $sim_json.get('data', {}) ... msg=Simulate JSON missing 'context_hash' field # Verify types are correct (structural schema check). Should Be True type($sim_json.get('data', {}).get('total_tokens')) in (int, float) ... msg=total_tokens should be numeric - Should Be True type($sim_json['budget_used']) in (int, float) + Should Be True type($sim_json.get('data', {}).get('budget_used')) in (int, float) ... msg=budget_used should be numeric Context Analysis — Show Full Policy With ACMS Config @@ -568,9 +568,9 @@ Plan Execution — Create Plan With Plan Use # tests — avoids fragile rindex-based extraction that can pick the wrong # '{' if structlog lines also contain plan_id. ${plan_data}= Extract JSON From Stdout ${result.stdout} - Should Be True 'plan_id' in $plan_data + Should Be True 'data' in $plan_data and 'plan_id' in $plan_data.get('data', {}) ... msg=Plan use JSON missing 'plan_id' field - Set Suite Variable ${PLAN_ID} ${plan_data}[plan_id] + Set Suite Variable ${PLAN_ID} ${plan_data}[data][plan_id] Plan Execution — Resume Plan For LLM Processing [Documentation] ``plan resume`` transitions the plan from queued to @@ -592,12 +592,12 @@ Plan Execution — Resume Plan For LLM Processing Fail Plan resume did not return valid JSON: ${err} END # Assertions outside TRY so failures report the actual issue. - Should Be True 'plan_id' in $resume_json + Should Be True 'data' in $resume_json and 'plan_id' in $resume_json.get('data', {}) ... msg=Plan resume JSON missing 'plan_id' field - Should Be True 'phase' in $resume_json + Should Be True 'data' in $resume_json and 'phase' in $resume_json.get('data', {}) ... msg=Plan resume JSON missing 'phase' field # Verify the phase transitioned to an expected state — a plan stuck # in 'queued' would indicate resume had no effect. - ${phase}= Evaluate $resume_json.get('phase', '') + ${phase}= Evaluate $resume_json.get('data', {}).get('phase', '') Should Not Be Equal As Strings ${phase} queued ... msg=Plan phase should have transitioned from 'queued' after resume diff --git a/robot/e2e/m6_acceptance.robot b/robot/e2e/m6_acceptance.robot index 2ccb729c6..f7b95acdf 100644 --- a/robot/e2e/m6_acceptance.robot +++ b/robot/e2e/m6_acceptance.robot @@ -62,7 +62,7 @@ Plan Lifecycle Assertions [Documentation] Assert plan lifecycle output after successful plan use. [Arguments] ${plan_use} Output Should Contain ${plan_use} plan_id - ${plan_id}= Safe Parse Json Field With Nested Support ${plan_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${plan_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output Verify Plan In List ${plan_id} @@ -82,7 +82,7 @@ Guard Enforcement Assertions [Arguments] ${plan_use} ${expected_profile}=manual Output Should Contain ${plan_use} plan_id # Verify the resolved automation profile matches expectation (P2-24) - ${resolved_profile}= Safe Parse Json Field ${plan_use.stdout} automation_profile + ${resolved_profile}= Safe Parse Json Field With Nested Support ${plan_use.stdout} automation_profile IF '${resolved_profile}' != '' Should Be Equal As Strings ${resolved_profile} ${expected_profile} END @@ -102,7 +102,7 @@ Full Flow Apply Step IF ${apply.rc} == 0 Output Should Contain ${apply} ${plan_id} # Verify the plan actually transitioned — check for apply-phase indicators - ${apply_phase}= Safe Parse Json Field ${apply.stdout} phase + ${apply_phase}= Safe Parse Json Field With Nested Support ${apply.stdout} phase IF '${apply_phase}' != '' Should Contain ${apply_phase.lower()} apply Plan phase should indicate apply after apply END @@ -121,7 +121,7 @@ M6 E2E Session Lifecycle Should Not Be Empty ${create.stdout} Output Should Contain ${create} session_id # Parse session_id from JSON output (handle potential leading non-JSON output) - ${session_id}= Safe Parse Json Field With Nested Support ${create.stdout} data.session_id + ${session_id}= Safe Parse Json Field With Nested Support With Nested Support ${create.stdout} data.session_id Set Test Variable ${session_id} Should Not Be Empty ${session_id} # List sessions — should include the new one @@ -178,7 +178,7 @@ M6 E2E Config Automation Profile # Get and verify via JSON — parse the value field for precise assertion ${get_result}= Run CleverAgents Command config get core.automation-profile --format json Should Be Equal As Integers ${get_result.rc} 0 - ${config_value}= Safe Parse Json Field ${get_result.stdout} value + ${config_value}= Safe Parse Json Field With Nested Support ${get_result.stdout} value Should Be Equal As Strings ${config_value} ci # Reset to default (manual) is handled by [Teardown]. @@ -296,7 +296,7 @@ M6 E2E Profile Precedence Plan Overrides Global ${set_global}= Run CleverAgents Command config set core.automation-profile review --format json Should Be Equal As Integers ${set_global.rc} 0 ${get_global}= Run CleverAgents Command config get core.automation-profile --format json - ${global_value}= Safe Parse Json Field ${get_global.stdout} value + ${global_value}= Safe Parse Json Field With Nested Support ${get_global.stdout} value Should Be Equal As Strings ${global_value} review # Setup resources and project ${proj_name}= Setup Plan Test Resources prec @@ -306,7 +306,7 @@ M6 E2E Profile Precedence Plan Overrides Global Should Be Equal As Integers ${plan_use.rc} 0 ... plan use failed (rc=${plan_use.rc}): ${plan_use.stderr} # Parse automation_profile from plan output: must be "trusted", NOT "review" - ${resolved_profile}= Safe Parse Json Field ${plan_use.stdout} automation_profile + ${resolved_profile}= Safe Parse Json Field With Nested Support ${plan_use.stdout} automation_profile IF '${resolved_profile}' != '' Should Be Equal As Strings ${resolved_profile} trusted Should Not Be Equal As Strings ${resolved_profile} review @@ -332,7 +332,7 @@ M6 E2E Event Queue Via Plan Lifecycle Transitions # P0-2: Fail (not Skip) when API keys are present but plan use fails. Should Be Equal As Integers ${plan_use.rc} 0 ... plan use failed (rc=${plan_use.rc}): ${plan_use.stderr} - ${plan_id}= Safe Parse Json Field With Nested Support ${plan_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${plan_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output # 2. Verify plan appears in list (proves creation event was processed) Verify Plan In List ${plan_id} @@ -340,8 +340,8 @@ M6 E2E Event Queue Via Plan Lifecycle Transitions ${status1}= Run CleverAgents Command plan status ${plan_id} --format json expected_rc=None timeout=120s Should Be Equal As Integers ${status1.rc} 0 ... plan status failed (rc=${status1.rc}): ${status1.stderr} - ${initial_phase}= Safe Parse Json Field ${status1.stdout} phase - ${initial_state}= Safe Parse Json Field ${status1.stdout} processing_state + ${initial_phase}= Safe Parse Json Field With Nested Support ${status1.stdout} phase + ${initial_state}= Safe Parse Json Field With Nested Support ${status1.stdout} processing_state Log Initial phase=${initial_phase} processing_state=${initial_state} # 4. Execute plan — triggers PHASE_TRANSITION and execution events ${execute}= Run CleverAgents Command plan execute ${plan_id} --format json expected_rc=None timeout=180s @@ -353,8 +353,8 @@ M6 E2E Event Queue Via Plan Lifecycle Transitions ${status2}= Run CleverAgents Command plan status ${plan_id} --format json expected_rc=None timeout=120s Should Be Equal As Integers ${status2.rc} 0 ... plan status failed after execute (rc=${status2.rc}): ${status2.stderr} - ${post_phase}= Safe Parse Json Field ${status2.stdout} phase - ${post_state}= Safe Parse Json Field ${status2.stdout} processing_state + ${post_phase}= Safe Parse Json Field With Nested Support ${status2.stdout} phase + ${post_state}= Safe Parse Json Field With Nested Support ${status2.stdout} processing_state Log Post-execute phase=${post_phase} processing_state=${post_state} # P0-3: Hard assertion — at least one state field must be populated, # proving the event bus delivered and processed lifecycle events. @@ -383,7 +383,7 @@ M6 E2E Hierarchical Decomposition Via Plan Tree # P0-2: Fail (not Skip) when API keys are present but plan use fails. Should Be Equal As Integers ${plan_use.rc} 0 ... plan use failed (rc=${plan_use.rc}): ${plan_use.stderr} - ${plan_id}= Safe Parse Json Field With Nested Support ${plan_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${plan_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output # Execute plan to populate the decision tree with strategy/execution decisions ${execute}= Run CleverAgents Command plan execute ${plan_id} --format json expected_rc=None timeout=180s @@ -418,7 +418,7 @@ M6 E2E Full Autonomy Acceptance Flow Should Be Equal As Integers ${plan_use.rc} 0 ... plan use failed (rc=${plan_use.rc}): ${plan_use.stderr} # Parse plan_id from JSON output - ${plan_id}= Safe Parse Json Field With Nested Support ${plan_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${plan_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output # Check plan status ${status}= Run CleverAgents Command plan status ${plan_id} --format json expected_rc=None timeout=120s @@ -430,7 +430,7 @@ M6 E2E Full Autonomy Acceptance Flow IF ${execute.rc} == 0 Output Should Contain ${execute} ${plan_id} # Verify execute output contains phase-transition indicators - ${exec_phase}= Safe Parse Json Field ${execute.stdout} phase + ${exec_phase}= Safe Parse Json Field With Nested Support ${execute.stdout} phase Log Execute phase: ${exec_phase} # Apply Full Flow Apply Step ${plan_id} diff --git a/robot/e2e/wf04_multi_project.robot b/robot/e2e/wf04_multi_project.robot index 173bb936a..67e6625a1 100644 --- a/robot/e2e/wf04_multi_project.robot +++ b/robot/e2e/wf04_multi_project.robot @@ -392,13 +392,13 @@ WF04 Multi Project Dependency Update Supervised Profile Should Not Contain ${r_use.stdout}${r_use.stderr} Traceback Should Not Contain ${r_use.stdout}${r_use.stderr} INTERNAL ${use_payload}= Parse Json Payload ${r_use.stdout} - ${plan_id}= Evaluate str($use_payload.get('plan_id', '')) + ${plan_id}= Evaluate str($use_payload.get('data', {}).get('plan_id', '')) Should Not Be Empty ${plan_id} msg=Expected plan_id in plan use JSON output Log Plan ID: ${plan_id} Set Test Variable ${WF04_PLAN_ID} ${plan_id} # Verify plan targets all 4 projects exactly (AC-3) - ${use_projects}= Evaluate sorted([link.get('project_name', '') for link in $use_payload.get('project_links', []) if isinstance(link, dict)]) + ${use_projects}= Evaluate sorted([link.get('project_name', '') for link in $use_payload.get('data', {}).get('project_links', []) if isinstance(link, dict)]) ${expected_projects}= Create List ${LIB_PROJECT} ${SVC1_PROJECT} ${SVC2_PROJECT} ${SVC3_PROJECT} ${expected_sorted}= Evaluate sorted($expected_projects) ${projects_match}= Evaluate $use_projects == $expected_sorted diff --git a/robot/e2e/wf05_db_migration.robot b/robot/e2e/wf05_db_migration.robot index 0bd86c52d..5ef4e476f 100644 --- a/robot/e2e/wf05_db_migration.robot +++ b/robot/e2e/wf05_db_migration.robot @@ -324,13 +324,13 @@ WF05 Database Schema Migration With Safety Nets Review Profile ... plan use failed (rc=${r_use.rc}): ${r_use.stderr} Should Not Contain ${r_use.stdout}${r_use.stderr} Traceback Should Not Contain ${r_use.stdout}${r_use.stderr} INTERNAL - ${plan_id}= Safe Parse Json Field With Nested Support ${r_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${r_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not extract plan_id from plan use output Set Test Variable ${WF05_PLAN_ID} ${plan_id} Log Plan ID: ${plan_id} # Verify review automation profile was applied. # If plan use output omits automation_profile, fall back to plan status. - ${resolved_profile}= Safe Parse Json Field ${r_use.stdout} automation_profile + ${resolved_profile}= Safe Parse Json Field With Nested Support ${r_use.stdout} automation_profile ${resolved_profile}= Set Variable If $resolved_profile is None ${EMPTY} ${resolved_profile} ${resolved_profile}= Set Variable If '${resolved_profile}' == 'None' ${EMPTY} ${resolved_profile} IF '${resolved_profile}' == '' @@ -341,7 +341,7 @@ WF05 Database Schema Migration With Safety Nets Review Profile ... plan status for profile verification failed (rc=${r_profile_status.rc}): ${r_profile_status.stderr} Should Not Contain ${r_profile_status.stdout}${r_profile_status.stderr} Traceback Should Not Contain ${r_profile_status.stdout}${r_profile_status.stderr} INTERNAL - ${resolved_profile}= Safe Parse Json Field ${r_profile_status.stdout} automation_profile + ${resolved_profile}= Safe Parse Json Field With Nested Support With Nested Support ${r_profile_status.stdout} automation_profile ${resolved_profile}= Set Variable If $resolved_profile is None ${EMPTY} ${resolved_profile} ${resolved_profile}= Set Variable If '${resolved_profile}' == 'None' ${EMPTY} ${resolved_profile} END @@ -416,11 +416,11 @@ WF05 Database Schema Migration With Safety Nets Review Profile Should Not Be Empty ${r_status.stdout} Output Should Contain ${r_status} ${plan_id} # Assert phase field is populated after execute - ${status_phase}= Safe Parse Json Field ${r_status.stdout} phase + ${status_phase}= Safe Parse Json Field With Nested Support ${r_status.stdout} phase Should Not Be Empty ${status_phase} Plan phase should be populated after execute Log Plan phase after execute: ${status_phase} # Extract checkpoint ID if available (for rollback attempt) - ${checkpoint_id}= Safe Parse Json Field ${r_status.stdout} last_checkpoint_id + ${checkpoint_id}= Safe Parse Json Field With Nested Support ${r_status.stdout} last_checkpoint_id # Guard against Python None being returned as string "None" from JSON null ${checkpoint_id}= Set Variable If $checkpoint_id is None ${EMPTY} ${checkpoint_id} ${checkpoint_id}= Set Variable If '${checkpoint_id}' == 'None' ${EMPTY} ${checkpoint_id} @@ -510,8 +510,8 @@ WF05 Database Schema Migration With Safety Nets Review Profile ... plan status after apply failed (rc=${r_status_after_apply.rc}): ${r_status_after_apply.stderr} Should Not Contain ${r_status_after_apply.stdout}${r_status_after_apply.stderr} Traceback Should Not Contain ${r_status_after_apply.stdout}${r_status_after_apply.stderr} INTERNAL - ${apply_phase}= Safe Parse Json Field ${r_status_after_apply.stdout} phase - ${apply_state}= Safe Parse Json Field ${r_status_after_apply.stdout} processing_state + ${apply_phase}= Safe Parse Json Field With Nested Support ${r_status_after_apply.stdout} phase + ${apply_state}= Safe Parse Json Field With Nested Support ${r_status_after_apply.stdout} processing_state Should Not Be Empty ${apply_phase} plan status after apply should include phase Should Not Be Empty ${apply_state} plan status after apply should include processing_state ${apply_phase_lower}= Evaluate ($apply_phase).lower() diff --git a/robot/e2e/wf07_cicd.robot b/robot/e2e/wf07_cicd.robot index 1c6795f4b..08df7df0c 100644 --- a/robot/e2e/wf07_cicd.robot +++ b/robot/e2e/wf07_cicd.robot @@ -210,7 +210,7 @@ WF07 E2E CI Plan Launch ... expected_rc=None timeout=180s # Parse and validate JSON output ${stdout}= Set Variable ${plan_result.stdout} - ${plan_id}= Safe Parse Json Field With Nested Support ${stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${stdout} data.plan_id IF '${plan_id}' != '${EMPTY}' Log Plan launched with ID: ${plan_id} # Drive the plan through its lifecycle. Per the specification @@ -328,7 +328,7 @@ Poll Plan Until Terminal FOR ${i} IN RANGE ${max_polls} ${result}= Run CleverAgents Command plan status ${plan_id} ... --format json expected_rc=None - ${state}= Safe Parse Json Field ${result.stdout} state + ${state}= Safe Parse Json Field With Nested Support ${result.stdout} state IF '${state}' in ['applied', 'constrained', 'cancelled', 'errored'] RETURN ${state} END diff --git a/robot/e2e/wf12_hierarchical.robot b/robot/e2e/wf12_hierarchical.robot index e6fe55fc0..94e8b8ab6 100644 --- a/robot/e2e/wf12_hierarchical.robot +++ b/robot/e2e/wf12_hierarchical.robot @@ -223,7 +223,7 @@ WF12 Large Scale Hierarchical Feature Implementation Should Not Contain ${r_use.stdout}${r_use.stderr} Traceback Should Not Contain ${r_use.stdout}${r_use.stderr} INTERNAL Output Should Contain ${r_use} plan_id - ${plan_id}= Safe Parse Json Field With Nested Support ${r_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${r_use.stdout} data.plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output Log Plan ID: ${plan_id} @@ -300,8 +300,8 @@ WF12 Large Scale Hierarchical Feature Implementation ... expected_rc=None timeout=60s Should Be Equal As Integers ${r_mid_status.rc} 0 ... Intermediate plan status failed (rc=${r_mid_status.rc}): ${r_mid_status.stderr} - ${mid_phase}= Safe Parse Json Field ${r_mid_status.stdout} phase - ${mid_state}= Safe Parse Json Field ${r_mid_status.stdout} processing_state + ${mid_phase}= Safe Parse Json Field With Nested Support ${r_mid_status.stdout} phase + ${mid_state}= Safe Parse Json Field With Nested Support ${r_mid_status.stdout} processing_state Log Post-strategize status: phase=${mid_phase} processing_state=${mid_state} # Assert plan state progressed — at least one field should be non-empty after strategize (M3 fix) ${mid_populated}= Evaluate '${mid_phase}' != '' or '${mid_state}' != '' @@ -330,8 +330,8 @@ WF12 Large Scale Hierarchical Feature Implementation ... expected_rc=None timeout=60s Should Be Equal As Integers ${r_pre_correct_status.rc} 0 ... Pre-correction plan status failed (rc=${r_pre_correct_status.rc}): ${r_pre_correct_status.stderr} - ${pre_correct_phase}= Safe Parse Json Field ${r_pre_correct_status.stdout} phase - ${pre_correct_state}= Safe Parse Json Field ${r_pre_correct_status.stdout} processing_state + ${pre_correct_phase}= Safe Parse Json Field With Nested Support ${r_pre_correct_status.stdout} phase + ${pre_correct_state}= Safe Parse Json Field With Nested Support ${r_pre_correct_status.stdout} processing_state Log Pre-correction status: phase=${pre_correct_phase} state=${pre_correct_state} # Gate correction on pre-correction status: if plan is already in a terminal # processing state, correction may fail — skip with WARN (m4 fix). @@ -373,8 +373,8 @@ WF12 Large Scale Hierarchical Feature Implementation Should Be True ${has_correction_indicator} ... Correction output should acknowledge append mode (found none of: append, queued, mode+append) # Structural check: parse the correction response and verify a status field exists - ${correction_status}= Safe Parse Json Field ${r_correct.stdout} status - ${correction_id_field}= Safe Parse Json Field ${r_correct.stdout} correction_id + ${correction_status}= Safe Parse Json Field With Nested Support ${r_correct.stdout} status + ${correction_id_field}= Safe Parse Json Field With Nested Support ${r_correct.stdout} correction_id # At least one structural field should be populated in the correction response ${has_structural_field}= Evaluate '${correction_status}' != '' or '${correction_id_field}' != '' Should Be True ${has_structural_field} @@ -422,7 +422,7 @@ WF12 Large Scale Hierarchical Feature Implementation Should Not Contain ${r_apply.stdout}${r_apply.stderr} INTERNAL Output Should Contain ${r_apply} ${plan_id} # Assert apply phase (consistent with m6_acceptance Full Flow Apply Step) - ${apply_phase}= Safe Parse Json Field ${r_apply.stdout} phase + ${apply_phase}= Safe Parse Json Field With Nested Support ${r_apply.stdout} phase IF '${apply_phase}' != '' Should Contain ${apply_phase.lower()} apply ... Plan phase should indicate apply after apply @@ -451,8 +451,8 @@ WF12 Large Scale Hierarchical Feature Implementation Should Not Be Empty ${r_status.stdout} Output Should Contain ${r_status} ${plan_id} # Parse and verify plan is in a terminal state (not intermediate) - ${phase}= Safe Parse Json Field ${r_status.stdout} phase - ${state}= Safe Parse Json Field ${r_status.stdout} processing_state + ${phase}= Safe Parse Json Field With Nested Support ${r_status.stdout} phase + ${state}= Safe Parse Json Field With Nested Support ${r_status.stdout} processing_state Log Final phase=${phase} processing_state=${state} # At least one field must be non-empty ${state_populated}= Evaluate '${phase}' != '' or '${state}' != '' diff --git a/robot/e2e/wf17_explicit_container.robot b/robot/e2e/wf17_explicit_container.robot index 5643c00bb..0336cd9b5 100644 --- a/robot/e2e/wf17_explicit_container.robot +++ b/robot/e2e/wf17_explicit_container.robot @@ -146,7 +146,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile ... project context show ${PROJECT_NAME} --format json ... expected_rc=None IF ${r_ctx_show.rc} == 0 - ${persisted_env}= Safe Parse Json Field ${r_ctx_show.stdout} execution_environment + ${persisted_env}= Safe Parse Json Field With Nested Support ${r_ctx_show.stdout} execution_environment IF "${persisted_env}" != "" Should Be Equal As Strings ${persisted_env.lower()} container ... Execution environment should be persisted as 'container' but got '${persisted_env}' @@ -190,7 +190,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile ... --format json Should Not Contain ${r_use.stdout}${r_use.stderr} Traceback Should Not Contain ${r_use.stdout}${r_use.stderr} INTERNAL - ${plan_id}= Safe Parse Json Field With Nested Support ${r_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${r_use.stdout} data.plan_id Should Not Be Empty ${plan_id} msg=Expected plan_id in plan use JSON output Should Match Regexp ${plan_id} ^[0-9A-HJKMNP-TV-Z]{26}$ ... Plan ID should be a valid Crockford Base32 ULID: ${plan_id} @@ -281,8 +281,8 @@ WF17 Explicit Container With Directory Mount Trusted Profile # After full lifecycle (strategize → execute → diff → apply → status), # the plan should have reached an apply-related phase, matching M6's # Full Flow Apply Step pattern. - ${final_phase}= Safe Parse Json Field ${r_status.stdout} phase - ${final_state}= Safe Parse Json Field ${r_status.stdout} processing_state + ${final_phase}= Safe Parse Json Field With Nested Support ${r_status.stdout} phase + ${final_state}= Safe Parse Json Field With Nested Support ${r_status.stdout} processing_state Should Not Be Empty ${final_phase} Plan phase should be populated after full lifecycle Should Contain ${final_phase.lower()} apply ... Plan should reach apply phase after apply (got: ${final_phase}) @@ -297,7 +297,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile # NOTE: Container routing verification gap is not yet tracked in a dedicated # issue. A tracking issue should be created to cover CLI-level routing # indicators for container execution. - ${exec_env}= Safe Parse Json Field ${r_status.stdout} execution_environment + ${exec_env}= Safe Parse Json Field With Nested Support ${r_status.stdout} execution_environment IF "${exec_env}" != "" Should Be Equal As Strings ${exec_env.lower()} container ... Execution environment should be 'container' but got '${exec_env}' @@ -434,7 +434,7 @@ WF17 TDD Precedence Level 2 Project Override Resolution IF ${r_use.rc} != 0 Fail plan use failed (rc=${r_use.rc}) — cannot verify precedence level 2: ${r_use.stderr} END - ${plan_id}= Safe Parse Json Field With Nested Support ${r_use.stdout} data.plan_id + ${plan_id}= Safe Parse Json Field With Nested Support With Nested Support ${r_use.stdout} data.plan_id Should Not Be Empty ${plan_id} msg=Expected plan_id in plan use output # Check plan status for execution environment resolution. @@ -444,6 +444,6 @@ WF17 TDD Precedence Level 2 Project Override Resolution Should Be Equal As Integers ${r_status.rc} 0 # The plan should show execution_environment=container resolved via # project-level override (precedence level 2), not plan-level. - ${exec_env}= Safe Parse Json Field ${r_status.stdout} execution_environment + ${exec_env}= Safe Parse Json Field With Nested Support ${r_status.stdout} execution_environment Should Be Equal As Strings ${exec_env.lower()} container ... Execution environment should resolve to container via project-level override (precedence level 2, bug #1080)