Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion orchestrator/routes/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1048,9 +1048,10 @@ def populate_contract(pipeline_id: str) -> tuple[Response, int]:
)
except Exception as e:
logger.error(
"Failed to populate contract",
"contract_populate_endpoint_failed",
pipeline_id=pipeline_id,
error=str(e),
exc_info=True,
)
return make_error_response(
f"Failed to populate contract: {e}",
Expand Down
51 changes: 42 additions & 9 deletions orchestrator/routes/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -10997,9 +10997,12 @@ def _populate_contract_from_plan_safe(
_populate_contract_from_plan(repo_path, pipeline_id, pipeline_mode, issue_number)
except Exception as pop_err:
logger.warning(
"Failed to populate contract from plan (continuing)",
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="unexpected_exception",
source="safe_wrapper",
error=str(pop_err),
exc_info=True,
)


Expand All @@ -11017,25 +11020,41 @@ def _populate_contract_from_plan(
try:
from egg_contracts.loader import load_contract, save_contract
except ImportError:
logger.warning("egg_contracts not available, skipping contract population")
logger.warning(
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="egg_contracts_unavailable",
)
return

# Resolve draft path
draft_rel = _get_draft_path("plan", issue_number=issue_number, pipeline_id=pipeline_id)
if not draft_rel:
logger.warning("No draft path for plan phase", pipeline_id=pipeline_id)
logger.warning(
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="no_draft_path",
)
return

plan_path = repo_path / draft_rel
if not plan_path.exists():
logger.warning("Plan draft not found, skipping contract population", path=str(plan_path))
logger.warning(
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="plan_draft_missing",
path=str(plan_path),
)
return

try:
contract = load_contract(pipeline_id, repo_path)
except Exception:
except Exception as load_err:
logger.warning(
"Contract not found for pipeline, skipping population", pipeline_id=pipeline_id
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="contract_load_failed",
error=str(load_err),
)
return

Expand All @@ -11047,8 +11066,9 @@ def _populate_contract_from_plan(

if not result.success:
logger.warning(
"Plan parsing failed, skipping contract population",
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="parse_failed",
error=result.error,
)
return
Expand Down Expand Up @@ -11084,18 +11104,31 @@ def _populate_contract_from_plan(
save_contract(contract, repo_path)
task_count = sum(len(p.tasks) for p in contract.phases)
logger.info(
"Contract populated from plan",
"contract_phases_populated",
pipeline_id=pipeline_id,
phase_count=len(contract.phases),
task_count=task_count,
has_pr_metadata=contract.pr is not None,
)
else:
# Parse succeeded but yielded neither phases nor PR metadata —
# this is the #1931 failure mode (empty contract with no error).
# Emit a discriminator so the gap is visible in audit logs.
logger.warning(
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="empty_result",
warning_count=len(result.warnings),
)

except Exception as e:
logger.warning(
"Failed to populate contract from plan",
"contract_phases_ingest_failed",
pipeline_id=pipeline_id,
reason="unexpected_exception",
source="parse_save",
error=str(e),
exc_info=True,
)


Expand Down
Loading
Loading