{"record":{"id":"af9846db19b7fa27","repo":"ZhuLinsen/daily_stock_analysis","slug":"guardrail-blocked","errorCode":"guardrail_blocked","errorMessage":"actionable_signal_blocked_by_guardrail","messagePattern":"actionable_signal_blocked_by_guardrail","errorType":"http","errorClass":"DecisionSignalReassessGuardrailBlockedError","httpStatus":400,"severity":"warning","filePath":"src/services/decision_signal_reassess_service.py","lineNumber":127,"sourceCode":"            \"target_price\": preview_candidate.target_price,\n            \"invalidation\": preview_candidate.invalidation,\n            \"reason\": preview_candidate.reason,\n            \"risk_summary\": preview_candidate.risk_summary,\n            \"watch_conditions\": preview_candidate.watch_conditions,\n            \"metadata\": metadata,\n        }\n        if not persist:\n            return {\n                \"preview\": preview,\n                \"item\": None,\n                \"created\": False,\n                \"persist_status\": None,\n                \"warnings\": policy.warnings,\n                \"blocked_reason\": policy.blocked_reason,\n            }\n\n        if not policy.guardrail_result.passed:\n            raise DecisionSignalReassessGuardrailBlockedError(\n                blocked_reason=policy.blocked_reason or \"actionable_signal_blocked_by_guardrail\",\n                warnings=policy.warnings,\n            )\n\n        payload = _build_persist_payload(\n            record,\n            raw_result=raw_result,\n            decision_profile=decision_profile_norm,\n            candidate=preview_candidate,\n            metadata=metadata,\n        )\n        market_phase_summary = _as_mapping(context_snapshot.get(\"market_phase_summary\"))\n        if not market_phase_summary:\n            market_phase_summary = _as_mapping(raw_result.get(\"market_phase_summary\"))\n        try:\n            outcome = self.signal_service.create_history_bound_signal_with_outcome(\n                payload,\n                history_created_at=getattr(record, \"created_at\", None),","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/decision_signal_reassess_service.py#L109-L145","documentation":"When persist=True, the reassess flow first runs the decision policy guardrail; if policy.guardrail_result.passed is False it raises DecisionSignalReassessGuardrailBlockedError with blocked_reason (defaulting to 'actionable_signal_blocked_by_guardrail') and warnings. This prevents persisting signals that violate actionable-signal policy (e.g. insufficient confidence/data quality).","triggerScenarios":"POST reassess with persist=true on a report whose policy evaluation fails the guardrail — low score, missing data-quality prerequisites, or profile-specific rules; preview-only calls (persist=false) return blocked_reason instead of raising.","commonSituations":"Trying to materialize signals from weak/ambiguous reports; changing guardrail policy config so previously persistable reports now fail; batch-reassessing old reports under a stricter profile.","solutions":["Call with persist=false first and inspect preview + blocked_reason/warnings to see which guardrail failed.","Choose a different decision_profile whose rules the report satisfies, or fix the underlying data-quality issue in the report.","Do not persist blocked candidates; treat the exception as the intended policy outcome."],"exampleFix":"# before\nresult = service.reassess(source_report_id=rid, decision_profile=\"aggressive\", persist=True)\n\n# after\npreview = service.reassess(source_report_id=rid, decision_profile=\"aggressive\", persist=False)\nprint(preview[\"blocked_reason\"], preview[\"warnings\"])\n# fix inputs/profile, then persist=True","handlingStrategy":"try-catch","validationCode":"preview = service.reassess(source_report_id=rid, decision_profile=profile, persist=False)\nif preview.get(\"blocked_reason\"):\n    return JSONResponse(status_code=422, content={\"error\": \"guardrail_blocked\", \"blocked_reason\": preview[\"blocked_reason\"], \"warnings\": preview[\"warnings\"]})\nresult = service.reassess(source_report_id=rid, decision_profile=profile, persist=True)","typeGuard":null,"tryCatchPattern":"from src.services.decision_signal_reassess_service import DecisionSignalReassessGuardrailBlockedError\n\ntry:\n    result = service.reassess(source_report_id=rid, decision_profile=profile, persist=True)\nexcept DecisionSignalReassessGuardrailBlockedError as exc:\n    return JSONResponse(status_code=422, content={\"error\": \"guardrail_blocked\", \"blocked_reason\": exc.blocked_reason, \"warnings\": exc.warnings})","preventionTips":["Always run persist=false preview first and check blocked_reason before persisting.","Treat guardrail blocks as policy outcomes, not bugs — never retry with persist=true unchanged.","Keep guardrail policy config under test so profile changes that block reports are caught early."],"tags":["decision-signal","reassess","guardrail","policy"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}