Flamehaven commited on
Commit
7728d35
·
verified ·
1 Parent(s): 115d72c

release: v1.8.2 ICH M15 citation alignment

Browse files
Files changed (1) hide show
  1. stem_ai/render_html.py +32 -11
stem_ai/render_html.py CHANGED
@@ -218,14 +218,17 @@ def _code_integrity_summary(integrity: dict[str, Any]) -> tuple[list[tuple[str,
218
 
219
 
220
  def _section1(result: dict[str, Any], final: int, tc: str,
221
- s1: int, s2: int, s3: int, s4: int, t0: bool) -> str:
 
222
  score = result["score"]
223
  calibration = result.get("calibration_profile", {})
 
224
  freshness = result.get("audit_freshness", {})
225
  policy_name = xt(str(calibration.get("profile_name", "unknown")))
226
  policy_status = xt(str(calibration.get("profile_status", "unknown")))
227
  policy_mode = xt(str(calibration.get("profile_read_mode", "unknown")))
228
  calibration_note = _calibration_effect_note(calibration)
 
229
 
230
  stats = "".join(
231
  f'<div class="metric-card">'
@@ -244,13 +247,23 @@ def _section1(result: dict[str, Any], final: int, tc: str,
244
  positives = result.get("notable_positive_evidence", [])[:4]
245
  stage2_focus = _select_focus_rows(result.get("stage_2r_rubric", {}), negatives_first=True, limit=3)
246
  stage3_focus = _select_focus_rows(result.get("stage_3_rubric", {}), negatives_first=False, limit=3)
247
- alert = (
248
- f'<div class="alert-t0">'
249
- f'T0 hard floor triggered: direct clinical framing without an explicit boundary declaration. '
250
- f'Score capped at {final}/100.'
251
- f'</div>'
252
- if t0 else ""
253
- )
 
 
 
 
 
 
 
 
 
 
254
  risk_list = "".join(f'<li>{xt(str(r))}</li>' for r in risks) or "<li>No notable risks surfaced.</li>"
255
  positive_list = "".join(f'<li>{xt(str(p))}</li>' for p in positives) or "<li>No notable positive evidence surfaced.</li>"
256
  return (
@@ -303,6 +316,10 @@ def _section1(result: dict[str, Any], final: int, tc: str,
303
  f'<div class="eyebrow">Policy Boundary</div>'
304
  f'<h3>How to read this artifact</h3>'
305
  f'<p class="memo-text">{xt(calibration_note) if calibration_note else "Authoritative scoring and surfaced policy metadata are aligned in this release line."}</p>'
 
 
 
 
306
  f'</article>'
307
  f'</div>'
308
  f'</section>'
@@ -357,6 +374,8 @@ def _section2(result: dict[str, Any], s1: int, s2: int, s3: int, s4: int) -> str
357
  stage2_focus = _select_focus_rows(result.get("stage_2r_rubric", {}), negatives_first=True, limit=4)
358
  stage3_focus = _select_focus_rows(result.get("stage_3_rubric", {}), negatives_first=False, limit=4)
359
  stage4_focus = _select_focus_rows(result.get("stage_4_rubric", {}), negatives_first=False, limit=4)
 
 
360
  cards = "".join([
361
  _stage_card(
362
  "Stage 1 — README Intent",
@@ -380,7 +399,7 @@ def _section2(result: dict[str, Any], s1: int, s2: int, s3: int, s4: int) -> str
380
  _C["slate"],
381
  _STAGE_TIPS[2],
382
  stage3_focus,
383
- "Engineering accountability, provenance, and reviewable responsibility surfaces.",
384
  ),
385
  _stage_card(
386
  "Stage 4 — Replication",
@@ -625,11 +644,13 @@ def render_html(result: dict[str, Any]) -> str:
625
  s2 = int(score.get("stage_2_repo_local_consistency", 0))
626
  s3 = int(score.get("stage_3_code_bio", 0))
627
  s4 = int(result.get("replication_score", 0))
628
- t0 = result.get("classification", {}).get("t0_hard_floor", False)
 
 
629
 
630
  css = build_css(tc)
631
  hero = _hero(score, final, tier, tc, target, date)
632
- sec1 = _section1(result, final, tc, s1, s2, s3, s4, t0)
633
  sec2 = _section2(result, s1, s2, s3, s4)
634
  sec3 = _section3(result.get("code_integrity", {}), result.get("code_contract", {}))
635
  sec4 = _section4(result.get("airi_risk_coverage", {}))
 
218
 
219
 
220
  def _section1(result: dict[str, Any], final: int, tc: str,
221
+ s1: int, s2: int, s3: int, s4: int, t0: bool,
222
+ score_cap: int | None = None) -> str:
223
  score = result["score"]
224
  calibration = result.get("calibration_profile", {})
225
+ cls = result.get("classification", {})
226
  freshness = result.get("audit_freshness", {})
227
  policy_name = xt(str(calibration.get("profile_name", "unknown")))
228
  policy_status = xt(str(calibration.get("profile_status", "unknown")))
229
  policy_mode = xt(str(calibration.get("profile_read_mode", "unknown")))
230
  calibration_note = _calibration_effect_note(calibration)
231
+ ca_severity = cls.get("ca_severity", "none")
232
 
233
  stats = "".join(
234
  f'<div class="metric-card">'
 
247
  positives = result.get("notable_positive_evidence", [])[:4]
248
  stage2_focus = _select_focus_rows(result.get("stage_2r_rubric", {}), negatives_first=True, limit=3)
249
  stage3_focus = _select_focus_rows(result.get("stage_3_rubric", {}), negatives_first=False, limit=3)
250
+ if t0:
251
+ alert = (
252
+ f'<div class="alert-t0">'
253
+ f'<strong>Tier Lock [T0-FLOOR]:</strong> Direct clinical framing without an explicit boundary declaration. '
254
+ f'Score ceiling at 39. Resolving this condition is required before any tier advancement.'
255
+ f'</div>'
256
+ )
257
+ elif score_cap is not None:
258
+ alert = (
259
+ f'<div class="alert-t0" style="background:#fff3cd;border-color:#ffc107;color:#856404;">'
260
+ f'<strong>Tier Lock [CA-CAP]:</strong> Clinical-adjacent surface detected without explicit non-clinical boundary. '
261
+ f'Score ceiling at {score_cap} (T2 maximum). '
262
+ f'Adding a non-diagnostic disclaimer resolves this lock.'
263
+ f'</div>'
264
+ )
265
+ else:
266
+ alert = ""
267
  risk_list = "".join(f'<li>{xt(str(r))}</li>' for r in risks) or "<li>No notable risks surfaced.</li>"
268
  positive_list = "".join(f'<li>{xt(str(p))}</li>' for p in positives) or "<li>No notable positive evidence surfaced.</li>"
269
  return (
 
316
  f'<div class="eyebrow">Policy Boundary</div>'
317
  f'<h3>How to read this artifact</h3>'
318
  f'<p class="memo-text">{xt(calibration_note) if calibration_note else "Authoritative scoring and surfaced policy metadata are aligned in this release line."}</p>'
319
+ f'<p class="memo-note"><strong>Classification applied:</strong> '
320
+ f'ca_severity={xt(ca_severity)} | '
321
+ f'score_cap={xt(str(score_cap)) if score_cap is not None else "none"} | '
322
+ f't0_floor={"active" if t0 else "clear"}</p>'
323
  f'</article>'
324
  f'</div>'
325
  f'</section>'
 
374
  stage2_focus = _select_focus_rows(result.get("stage_2r_rubric", {}), negatives_first=True, limit=4)
375
  stage3_focus = _select_focus_rows(result.get("stage_3_rubric", {}), negatives_first=False, limit=4)
376
  stage4_focus = _select_focus_rows(result.get("stage_4_rubric", {}), negatives_first=False, limit=4)
377
+ _s3r = result.get("stage_3_rubric", {}).get("stage_3_raw_total", {})
378
+ _s3_formula = f" (raw: {_s3r['score']}/{_s3r['max']})" if _s3r.get("score") is not None and _s3r.get("max") else ""
379
  cards = "".join([
380
  _stage_card(
381
  "Stage 1 — README Intent",
 
399
  _C["slate"],
400
  _STAGE_TIPS[2],
401
  stage3_focus,
402
+ f"Engineering accountability, provenance, and reviewable responsibility surfaces.{_s3_formula}",
403
  ),
404
  _stage_card(
405
  "Stage 4 — Replication",
 
644
  s2 = int(score.get("stage_2_repo_local_consistency", 0))
645
  s3 = int(score.get("stage_3_code_bio", 0))
646
  s4 = int(result.get("replication_score", 0))
647
+ cls = result.get("classification", {})
648
+ t0 = cls.get("t0_hard_floor", False)
649
+ score_cap = cls.get("score_cap")
650
 
651
  css = build_css(tc)
652
  hero = _hero(score, final, tier, tc, target, date)
653
+ sec1 = _section1(result, final, tc, s1, s2, s3, s4, t0, score_cap)
654
  sec2 = _section2(result, s1, s2, s3, s4)
655
  sec3 = _section3(result.get("code_integrity", {}), result.get("code_contract", {}))
656
  sec4 = _section4(result.get("airi_risk_coverage", {}))