Legal-i commited on
Commit
a6bb9b0
·
verified ·
1 Parent(s): f1ea47c

Stage 188: escalation recommendation + urgency boost

Browse files
Files changed (2) hide show
  1. core/decisions.py +48 -0
  2. core/pipeline.py +14 -1
core/decisions.py CHANGED
@@ -17,8 +17,39 @@ class DecisionItem:
17
  status: str = "open"
18
 
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def recommendation_for_issue(entity_type: str, evidence: List[Dict]) -> str:
 
 
 
 
 
 
 
 
 
 
 
21
  labels = {e.get("label") for e in evidence}
 
 
 
22
  if "inventory_availability_drop" in labels:
23
  return "Audit inventory replenishment and check local stock allocation within 7 days."
24
  if "backlog_increase" in labels:
@@ -26,3 +57,20 @@ def recommendation_for_issue(entity_type: str, evidence: List[Dict]) -> str:
26
  if "sla_response_increase" in labels:
27
  return "Review service team workload and escalation policy within 72 hours."
28
  return "Assign an operations owner to review the detected drift and validate root cause."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  status: str = "open"
18
 
19
 
20
+ # --- recommendation tiers --------------------------------------------
21
+ #
22
+ # Stage 188 — when the α (acceleration) signal fires, the recommendation
23
+ # is a different KIND of action, not a louder version of the same
24
+ # action. A steady decliner needs to be reviewed in the next planning
25
+ # cycle; an accelerating decliner needs escalation to a senior owner
26
+ # THIS WEEK or the trajectory gets unrecoverable. So `acceleration`
27
+ # in the evidence trail short-circuits the metric-specific suggestion
28
+ # and returns the escalation tier instead.
29
+
30
+ _ESCALATION_RECOMMENDATION = (
31
+ "Escalate to a senior owner now: the rate of degradation is itself "
32
+ "accelerating. Schedule a same-week intervention; do not defer "
33
+ "to the next planning cycle."
34
+ )
35
+
36
+
37
  def recommendation_for_issue(entity_type: str, evidence: List[Dict]) -> str:
38
+ """Produce a recommendation string for the issue based on its
39
+ evidence trail. The text is English-only; the dashboard's
40
+ i18n.translateRecommendation maps it to Hebrew at render time.
41
+
42
+ Stage 188: when the ``acceleration`` evidence label is present,
43
+ the escalation-tier text takes precedence over any metric-
44
+ specific recommendation. This applies regardless of the metric
45
+ that's accelerating — the engine math doesn't know which metric
46
+ triggered α, only that the second derivative crossed the
47
+ threshold.
48
+ """
49
  labels = {e.get("label") for e in evidence}
50
+ # Acceleration trumps everything — the "kind" of action differs.
51
+ if "acceleration" in labels:
52
+ return _ESCALATION_RECOMMENDATION
53
  if "inventory_availability_drop" in labels:
54
  return "Audit inventory replenishment and check local stock allocation within 7 days."
55
  if "backlog_increase" in labels:
 
57
  if "sla_response_increase" in labels:
58
  return "Review service team workload and escalation policy within 72 hours."
59
  return "Assign an operations owner to review the detected drift and validate root cause."
60
+
61
+
62
+ def is_escalation(decision_or_evidence) -> bool:
63
+ """Return True if the given evidence trail (or DecisionItem)
64
+ contains the acceleration label — i.e. this is the escalation
65
+ tier. Used by the dashboard to render an "escalation required"
66
+ badge without having to re-parse the recommendation string."""
67
+ if isinstance(decision_or_evidence, DecisionItem):
68
+ evidence = decision_or_evidence.evidence
69
+ else:
70
+ evidence = decision_or_evidence
71
+ if not evidence:
72
+ return False
73
+ for e in evidence:
74
+ if e.get("label") == "acceleration":
75
+ return True
76
+ return False
core/pipeline.py CHANGED
@@ -304,13 +304,26 @@ def run_pipeline(observations: List[Observation],
304
  evidence=evidence,
305
  )
306
  result.issues.append(issue)
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  result.decisions.append(DecisionItem(
308
  decision_id=f"decision_{idx}",
309
  issue_id=issue.issue_id,
310
  entity_id=state["entity_id"],
311
  created_at=state["day"],
312
  title=f"Review {state['entity_id']} drift",
313
- urgency=round(min(1.0, state["drift_score"] * 1.25), 4),
314
  recommendation=recommendation_for_issue(state["entity_type"], evidence),
315
  confidence=state["confidence"],
316
  evidence=evidence,
 
304
  evidence=evidence,
305
  )
306
  result.issues.append(issue)
307
+ # Stage 188 — α-flagged issues are escalation-tier. Their
308
+ # urgency gets boosted so they sort to the top of the queue
309
+ # ahead of equal-severity steady decliners. Multiplier 1.5
310
+ # (vs 1.25 for non-accelerating) keeps it bounded in [0,1]
311
+ # while making the ordering decisive. An entity with
312
+ # drift_score 0.6 + α evidence (urgency 0.9) outranks an
313
+ # entity with drift_score 0.7 + no acceleration (urgency
314
+ # 0.875) — which mirrors the human intuition that an
315
+ # accelerating decliner deserves attention before a steadier
316
+ # but slightly-worse one.
317
+ alpha_value = state["signals"].get("alpha", 0.0)
318
+ alpha_boost = 1.5 if alpha_value >= 0.5 else 1.25
319
+ urgency = round(min(1.0, state["drift_score"] * alpha_boost), 4)
320
  result.decisions.append(DecisionItem(
321
  decision_id=f"decision_{idx}",
322
  issue_id=issue.issue_id,
323
  entity_id=state["entity_id"],
324
  created_at=state["day"],
325
  title=f"Review {state['entity_id']} drift",
326
+ urgency=urgency,
327
  recommendation=recommendation_for_issue(state["entity_type"], evidence),
328
  confidence=state["confidence"],
329
  evidence=evidence,