Update ui/components.py
Browse files- ui/components.py +289 -0
ui/components.py
CHANGED
|
@@ -647,7 +647,296 @@ def create_tab5_learning_engine() -> tuple:
|
|
| 647 |
|
| 648 |
return (learning_graph, graph_type, show_labels, search_query, search_btn,
|
| 649 |
clear_btn_search, search_results, stats_display, patterns_display, performance_display)
|
|
|
|
|
|
|
| 650 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 651 |
# -----------------------------
|
| 652 |
# Footer
|
| 653 |
# -----------------------------
|
|
|
|
| 647 |
|
| 648 |
return (learning_graph, graph_type, show_labels, search_query, search_btn,
|
| 649 |
clear_btn_search, search_results, stats_display, patterns_display, performance_display)
|
| 650 |
+
|
| 651 |
+
# Add this function to ui/components.py (new component)
|
| 652 |
|
| 653 |
+
def create_realism_panel(scenario_data: Dict, scenario_name: str) -> gr.HTML:
|
| 654 |
+
"""
|
| 655 |
+
Create a realism panel showing ranked actions, risks, and uncertainty.
|
| 656 |
+
This makes ARF look cautious, opinionated, and enterprise-seasoned.
|
| 657 |
+
"""
|
| 658 |
+
realism = scenario_data.get("realism", {})
|
| 659 |
+
ranked_actions = realism.get("ranked_actions", [])
|
| 660 |
+
|
| 661 |
+
# Build ranked actions HTML
|
| 662 |
+
actions_html = ""
|
| 663 |
+
for action in ranked_actions:
|
| 664 |
+
rank_color = "#10b981" if action["rank"] == 1 else "#f59e0b" if action["rank"] == 2 else "#ef4444"
|
| 665 |
+
status = "✅ RECOMMENDED" if action["rank"] == 1 else "🟡 SECONDARY" if action["rank"] == 2 else "🔴 REJECTED"
|
| 666 |
+
|
| 667 |
+
actions_html += f"""
|
| 668 |
+
<div style="border: 2px solid {rank_color}; border-radius: 12px; padding: 16px;
|
| 669 |
+
background: {rank_color}10; margin-bottom: 12px;">
|
| 670 |
+
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 10px;">
|
| 671 |
+
<div>
|
| 672 |
+
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 5px;">
|
| 673 |
+
<div style="width: 24px; height: 24px; background: {rank_color};
|
| 674 |
+
color: white; border-radius: 50%; display: flex; align-items: center;
|
| 675 |
+
justify-content: center; font-size: 12px; font-weight: bold;">
|
| 676 |
+
{action['rank']}
|
| 677 |
+
</div>
|
| 678 |
+
<span style="font-size: 14px; font-weight: 600; color: #1e293b;">
|
| 679 |
+
{status} • {action['confidence']}% confidence
|
| 680 |
+
</span>
|
| 681 |
+
</div>
|
| 682 |
+
<p style="font-size: 14px; color: #475569; margin: 8px 0; font-weight: 500;">
|
| 683 |
+
{action['action']}
|
| 684 |
+
</p>
|
| 685 |
+
</div>
|
| 686 |
+
<div style="padding: 6px 12px; background: {rank_color}20; border-radius: 20px;
|
| 687 |
+
font-size: 12px; font-weight: bold; color: {rank_color};">
|
| 688 |
+
{action['confidence']}%
|
| 689 |
+
</div>
|
| 690 |
+
</div>
|
| 691 |
+
|
| 692 |
+
<div style="font-size: 13px; color: #64748b; margin: 8px 0; line-height: 1.5;">
|
| 693 |
+
<strong>Rationale:</strong> {action.get('rationale', 'No rationale provided')}
|
| 694 |
+
</div>
|
| 695 |
+
|
| 696 |
+
{"<div style='font-size: 13px; color: #dc2626; margin: 8px 0; padding: 8px; background: #fef2f2; border-radius: 6px; border-left: 3px solid #dc2626;'><strong>⚠️ Risk:</strong> " + action['risk'] + "</div>" if action.get('risk') else ""}
|
| 697 |
+
|
| 698 |
+
{"<div style='font-size: 13px; color: #92400e; margin: 8px 0; padding: 8px; background: #fffbeb; border-radius: 6px; border-left: 3px solid #f59e0b;'><strong>🔄 Trade-off:</strong> " + action['tradeoff'] + "</div>" if action.get('tradeoff') else ""}
|
| 699 |
+
|
| 700 |
+
{"<div style='font-size: 13px; color: #b45309; margin: 8px 0; padding: 8px; background: #fef3c7; border-radius: 6px; border-left: 3px solid #f59e0b;'><strong>⏱️ Execution:</strong> " + action['execution_time'] + "</div>" if action.get('execution_time') else ""}
|
| 701 |
+
|
| 702 |
+
{"<div style='font-size: 13px; color: #b91c1c; margin: 8px 0; padding: 8px; background: #fee2e2; border-radius: 6px; border-left: 3px solid #ef4444;'><strong>🚫 Rejected:</strong> " + action['rejection_reason'] + "</div>" if action.get('rejection_reason') else ""}
|
| 703 |
+
|
| 704 |
+
{"<div style='font-size: 13px; color: #7c3aed; margin: 8px 0; padding: 8px; background: #f5f3ff; border-radius: 6px; border-left: 3px solid #8b5cf6;'><strong>🛡️ Safety:</strong> " + action['safety_override'] + "</div>" if action.get('safety_override') else ""}
|
| 705 |
+
</div>
|
| 706 |
+
"""
|
| 707 |
+
|
| 708 |
+
# Build competing hypotheses (for Network Partition scenario)
|
| 709 |
+
hypotheses_html = ""
|
| 710 |
+
if realism.get("competing_hypotheses"):
|
| 711 |
+
hypotheses_html = """
|
| 712 |
+
<div style="margin-top: 20px; padding-top: 20px; border-top: 2px solid #e2e8f0;">
|
| 713 |
+
<div style="font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 15px;">
|
| 714 |
+
🧠 Competing Hypotheses
|
| 715 |
+
</div>
|
| 716 |
+
"""
|
| 717 |
+
for hypo in realism["competing_hypotheses"]:
|
| 718 |
+
hypotheses_html += f"""
|
| 719 |
+
<div style="display: flex; align-items: center; gap: 15px; margin-bottom: 12px; padding: 12px;
|
| 720 |
+
background: #f8fafc; border-radius: 8px;">
|
| 721 |
+
<div style="font-size: 24px; color: #3b82f6;">?</div>
|
| 722 |
+
<div style="flex: 1;">
|
| 723 |
+
<div style="font-size: 14px; font-weight: 500; color: #1e293b; margin-bottom: 4px;">
|
| 724 |
+
{hypo['cause']} ({hypo['confidence']}%)
|
| 725 |
+
</div>
|
| 726 |
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">
|
| 727 |
+
{hypo['evidence']}
|
| 728 |
+
</div>
|
| 729 |
+
<div style="font-size: 11px; color: #475569; font-weight: 500;">
|
| 730 |
+
Investigation: {hypo['investigation_path']}
|
| 731 |
+
</div>
|
| 732 |
+
</div>
|
| 733 |
+
<div style="width: 60px; height: 60px; background: conic-gradient(#3b82f6 0% {hypo['confidence']}%, #e2e8f0 {hypo['confidence']}% 100%);
|
| 734 |
+
border-radius: 50%; display: flex; align-items: center; justify-content: center;">
|
| 735 |
+
<div style="width: 50px; height: 50px; background: white; border-radius: 50%;
|
| 736 |
+
display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: bold; color: #1e293b;">
|
| 737 |
+
{hypo['confidence']}%
|
| 738 |
+
</div>
|
| 739 |
+
</div>
|
| 740 |
+
</div>
|
| 741 |
+
"""
|
| 742 |
+
hypotheses_html += "</div>"
|
| 743 |
+
|
| 744 |
+
# Build risk assessment panel
|
| 745 |
+
risk_html = ""
|
| 746 |
+
if realism.get("risk_assessment"):
|
| 747 |
+
risk_html = """
|
| 748 |
+
<div style="margin-top: 20px; padding-top: 20px; border-top: 2px solid #e2e8f0;">
|
| 749 |
+
<div style="font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 15px;">
|
| 750 |
+
⚠️ Risk Assessment
|
| 751 |
+
</div>
|
| 752 |
+
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;">
|
| 753 |
+
"""
|
| 754 |
+
for key, value in realism["risk_assessment"].items():
|
| 755 |
+
risk_html += f"""
|
| 756 |
+
<div style="padding: 12px; background: #f8fafc; border-radius: 8px; border-left: 4px solid #f59e0b;">
|
| 757 |
+
<div style="font-size: 12px; color: #64748b; text-transform: uppercase; margin-bottom: 4px;">
|
| 758 |
+
{key.replace('_', ' ').title()}
|
| 759 |
+
</div>
|
| 760 |
+
<div style="font-size: 14px; font-weight: 600; color: #92400e;">
|
| 761 |
+
{value}
|
| 762 |
+
</div>
|
| 763 |
+
</div>
|
| 764 |
+
"""
|
| 765 |
+
risk_html += "</div></div>"
|
| 766 |
+
|
| 767 |
+
# Build confidence degradation panel
|
| 768 |
+
confidence_html = ""
|
| 769 |
+
if realism.get("confidence_degradation"):
|
| 770 |
+
conf = realism["confidence_degradation"]
|
| 771 |
+
confidence_html = f"""
|
| 772 |
+
<div style="margin-top: 20px; padding-top: 20px; border-top: 2px solid #e2e8f0;">
|
| 773 |
+
<div style="font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 15px;">
|
| 774 |
+
⏱️ Confidence Degradation Over Time
|
| 775 |
+
</div>
|
| 776 |
+
<div style="background: #f8fafc; border-radius: 10px; padding: 20px;">
|
| 777 |
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
| 778 |
+
<div style="text-align: center;">
|
| 779 |
+
<div style="font-size: 28px; font-weight: 700; color: #10b981;">{conf['initial']}%</div>
|
| 780 |
+
<div style="font-size: 12px; color: #64748b;">Initial Confidence</div>
|
| 781 |
+
</div>
|
| 782 |
+
<div style="font-size: 24px; color: #94a3b8;">→</div>
|
| 783 |
+
<div style="text-align: center;">
|
| 784 |
+
<div style="font-size: 28px; font-weight: 700; color: #f59e0b;">{conf['after_8_min']}%</div>
|
| 785 |
+
<div style="font-size: 12px; color: #64748b;">After 8 minutes</div>
|
| 786 |
+
</div>
|
| 787 |
+
<div style="font-size: 24px; color: #94a3b8;">→</div>
|
| 788 |
+
<div style="text-align: center;">
|
| 789 |
+
<div style="font-size: 28px; font-weight: 700; color: #ef4444;">{conf['after_15_min']}%</div>
|
| 790 |
+
<div style="font-size: 12px; color: #64748b;">After 15 minutes</div>
|
| 791 |
+
</div>
|
| 792 |
+
</div>
|
| 793 |
+
|
| 794 |
+
<div style="height: 10px; background: #e2e8f0; border-radius: 5px; margin: 20px 0; position: relative;">
|
| 795 |
+
<div style="position: absolute; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, #10b981, #f59e0b, #ef4444); border-radius: 5px;"></div>
|
| 796 |
+
<div style="position: absolute; left: {conf['escalation_threshold']}%; top: -5px; width: 2px; height: 20px; background: #1e293b;"></div>
|
| 797 |
+
<div style="position: absolute; left: {conf['escalation_threshold']}%; top: 25px; font-size: 11px; color: #64748b; transform: translateX(-50%);">
|
| 798 |
+
Escalation at {conf['escalation_threshold']}%
|
| 799 |
+
</div>
|
| 800 |
+
</div>
|
| 801 |
+
|
| 802 |
+
<div style="padding: 12px; background: #fef3c7; border-radius: 8px; border-left: 4px solid #f59e0b;">
|
| 803 |
+
<div style="font-size: 13px; color: #92400e; font-weight: 500;">
|
| 804 |
+
⚠️ ARF escalates to human operators when confidence drops below {conf['escalation_threshold']}%
|
| 805 |
+
</div>
|
| 806 |
+
<div style="font-size: 12px; color: #b45309; margin-top: 5px;">
|
| 807 |
+
This prevents autonomous execution in high-uncertainty scenarios
|
| 808 |
+
</div>
|
| 809 |
+
</div>
|
| 810 |
+
</div>
|
| 811 |
+
</div>
|
| 812 |
+
"""
|
| 813 |
+
|
| 814 |
+
# Build "What ARF Will NOT Do" panel (global)
|
| 815 |
+
wont_do_html = """
|
| 816 |
+
<div style="margin-top: 20px; padding-top: 20px; border-top: 2px solid #e2e8f0;">
|
| 817 |
+
<div style="font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 15px;">
|
| 818 |
+
🚫 What ARF Will NOT Do (Safety Boundaries)
|
| 819 |
+
</div>
|
| 820 |
+
<div style="background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
|
| 821 |
+
border: 2px solid #ef4444; border-radius: 12px; padding: 20px;">
|
| 822 |
+
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;">
|
| 823 |
+
<div style="display: flex; align-items: flex-start; gap: 10px;">
|
| 824 |
+
<div style="font-size: 20px; color: #ef4444;">⛔</div>
|
| 825 |
+
<div>
|
| 826 |
+
<div style="font-size: 14px; font-weight: 600; color: #7f1d1d;">Restart stateful leaders</div>
|
| 827 |
+
<div style="font-size: 12px; color: #b91c1c;">During peak traffic or elections</div>
|
| 828 |
+
</div>
|
| 829 |
+
</div>
|
| 830 |
+
<div style="display: flex; align-items: flex-start; gap: 10px;">
|
| 831 |
+
<div style="font-size: 20px; color: #ef4444;">⛔</div>
|
| 832 |
+
<div>
|
| 833 |
+
<div style="font-size: 14px; font-weight: 600; color: #7f1d1d;">Apply schema changes</div>
|
| 834 |
+
<div style="font-size: 12px; color: #b91c1c;">To production databases autonomously</div>
|
| 835 |
+
</div>
|
| 836 |
+
</div>
|
| 837 |
+
<div style="display: flex; align-items: flex-start; gap: 10px;">
|
| 838 |
+
<div style="font-size: 20px; color: #ef4444;">⛔</div>
|
| 839 |
+
<div>
|
| 840 |
+
<div style="font-size: 14px; font-weight: 600; color: #7f1d1d;">Exceed API limits</div>
|
| 841 |
+
<div style="font-size: 12px; color: #b91c1c;">Contractual or rate limits</div>
|
| 842 |
+
</div>
|
| 843 |
+
</div>
|
| 844 |
+
<div style="display: flex; align-items: flex-start; gap: 10px;">
|
| 845 |
+
<div style="font-size: 20px; color: #ef4444;">⛔</div>
|
| 846 |
+
<div>
|
| 847 |
+
<div style="font-size: 14px; font-weight: 600; color: #7f1d1d;">Modify ACLs/RBAC</div>
|
| 848 |
+
<div style="font-size: 12px; color: #b91c1c;">Security permissions autonomously</div>
|
| 849 |
+
</div>
|
| 850 |
+
</div>
|
| 851 |
+
</div>
|
| 852 |
+
<div style="margin-top: 15px; padding: 12px; background: rgba(255, 255, 255, 0.7);
|
| 853 |
+
border-radius: 8px; border-left: 4px solid #dc2626;">
|
| 854 |
+
<div style="font-size: 13px; color: #7f1d1d; font-weight: 500;">
|
| 855 |
+
These boundaries ensure ARF operates within safe, reversible limits.
|
| 856 |
+
Enterprise edition adds approval workflows for edge cases.
|
| 857 |
+
</div>
|
| 858 |
+
</div>
|
| 859 |
+
</div>
|
| 860 |
+
</div>
|
| 861 |
+
"""
|
| 862 |
+
|
| 863 |
+
# Combine all panels
|
| 864 |
+
full_html = f"""
|
| 865 |
+
<div style="border: 2px solid #3b82f6; border-radius: 16px; padding: 25px;
|
| 866 |
+
background: linear-gradient(135deg, #f0f9ff 0%, #ffffff 100%);">
|
| 867 |
+
|
| 868 |
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
| 869 |
+
<div>
|
| 870 |
+
<h3 style="margin: 0 0 8px 0; font-size: 18px; color: #1e293b; font-weight: 700;">
|
| 871 |
+
🎯 Ranked Healing Intents
|
| 872 |
+
</h3>
|
| 873 |
+
<p style="margin: 0; font-size: 13px; color: #64748b;">
|
| 874 |
+
ARF evaluates multiple options with confidence scores and risk assessments
|
| 875 |
+
</p>
|
| 876 |
+
</div>
|
| 877 |
+
<div style="padding: 8px 16px; background: #dbeafe; color: #1e40af;
|
| 878 |
+
border-radius: 20px; font-size: 12px; font-weight: bold;">
|
| 879 |
+
REALISM UPGRADE v3.3.9+
|
| 880 |
+
</div>
|
| 881 |
+
</div>
|
| 882 |
+
|
| 883 |
+
{actions_html}
|
| 884 |
+
{hypotheses_html}
|
| 885 |
+
{risk_html}
|
| 886 |
+
{confidence_html}
|
| 887 |
+
{wont_do_html}
|
| 888 |
+
|
| 889 |
+
<!-- ROI as Ranges -->
|
| 890 |
+
<div style="margin-top: 20px; padding-top: 20px; border-top: 2px solid #e2e8f0;">
|
| 891 |
+
<div style="font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 15px;">
|
| 892 |
+
📈 Realistic ROI Estimates (Ranges)
|
| 893 |
+
</div>
|
| 894 |
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px;">
|
| 895 |
+
<div style="text-align: center; padding: 15px; background: #f8fafc; border-radius: 10px;">
|
| 896 |
+
<div style="font-size: 16px; font-weight: 700; color: #10b981;">$5.8K – $7.2K</div>
|
| 897 |
+
<div style="font-size: 12px; color: #64748b;">Cost Avoided</div>
|
| 898 |
+
<div style="font-size: 11px; color: #94a3b8; margin-top: 5px;">Estimated range</div>
|
| 899 |
+
</div>
|
| 900 |
+
<div style="text-align: center; padding: 15px; background: #f8fafc; border-radius: 10px;">
|
| 901 |
+
<div style="font-size: 16px; font-weight: 700; color: #10b981;">4.8× – 5.6×</div>
|
| 902 |
+
<div style="font-size: 12px; color: #64748b;">ROI Multiplier</div>
|
| 903 |
+
<div style="font-size: 11px; color: #94a3b8; margin-top: 5px;">Confidence interval</div>
|
| 904 |
+
</div>
|
| 905 |
+
<div style="text-align: center; padding: 15px; background: #f8fafc; border-radius: 10px;">
|
| 906 |
+
<div style="font-size: 16px; font-weight: 700; color: #10b981;">68% – 87%</div>
|
| 907 |
+
<div style="font-size: 12px; color: #64748b;">Success Rate</div>
|
| 908 |
+
<div style="font-size: 11px; color: #94a3b8; margin-top: 5px;">Based on similar incidents</div>
|
| 909 |
+
</div>
|
| 910 |
+
</div>
|
| 911 |
+
<div style="margin-top: 15px; padding: 12px; background: #f0fdf4; border-radius: 8px;">
|
| 912 |
+
<div style="font-size: 13px; color: #065f46; text-align: center; font-weight: 500;">
|
| 913 |
+
📊 Real systems have ranges, not single-point estimates. ARF shows uncertainty honestly.
|
| 914 |
+
</div>
|
| 915 |
+
</div>
|
| 916 |
+
</div>
|
| 917 |
+
|
| 918 |
+
<!-- Engineering Insight -->
|
| 919 |
+
<div style="margin-top: 20px; padding: 20px; background: #f8fafc; border-radius: 12px;
|
| 920 |
+
border-left: 4px solid #3b82f6;">
|
| 921 |
+
<div style="display: flex; align-items: flex-start; gap: 15px;">
|
| 922 |
+
<div style="font-size: 32px;">🎭</div>
|
| 923 |
+
<div>
|
| 924 |
+
<div style="font-size: 14px; font-weight: 600; color: #1e293b; margin-bottom: 8px;">
|
| 925 |
+
What Senior SREs Expect at 3 a.m.
|
| 926 |
+
</div>
|
| 927 |
+
<div style="font-size: 13px; color: #475569; line-height: 1.6;">
|
| 928 |
+
"Real systems hesitate. Real systems explain risk. Real systems earn trust.
|
| 929 |
+
ARF shows multiple options with confidence scores because in production,
|
| 930 |
+
there's never a single perfect answer—just trade-offs managed carefully."
|
| 931 |
+
</div>
|
| 932 |
+
</div>
|
| 933 |
+
</div>
|
| 934 |
+
</div>
|
| 935 |
+
</div>
|
| 936 |
+
"""
|
| 937 |
+
|
| 938 |
+
return gr.HTML(full_html)
|
| 939 |
+
|
| 940 |
# -----------------------------
|
| 941 |
# Footer
|
| 942 |
# -----------------------------
|