Deploy from HuggingChat
Browse files- README.md +8 -4
- index.html +1360 -18
README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: "InsurTech Agent Fleet — Orchestration Workbench"
|
| 3 |
+
emoji: 🔮
|
| 4 |
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- huggingchat
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# InsurTech Agent Fleet — Orchestration Workbench
|
| 13 |
+
|
| 14 |
+
Built with [HuggingChat](https://huggingface.co/chat).
|
index.html
CHANGED
|
@@ -1,19 +1,1361 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
+
<title>InsurTech Agent Fleet — Orchestration Workbench</title>
|
| 7 |
+
<style>
|
| 8 |
+
:root{
|
| 9 |
+
--bg:#070c15; --panel:#0d1523; --panel2:#111c2e; --panel3:#16233a; --line:#1e2c45;
|
| 10 |
+
--ink:#e8eef9; --mut:#8ea3c0; --dim:#5d7290;
|
| 11 |
+
--teal:#2dd4bf; --amber:#f5b544; --red:#f87171; --violet:#a78bfa; --blue:#60a5fa; --green:#34d399; --pink:#f472b6;
|
| 12 |
+
--mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
|
| 13 |
+
--sans:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
|
| 14 |
+
}
|
| 15 |
+
*{box-sizing:border-box}
|
| 16 |
+
html,body{margin:0;padding:0}
|
| 17 |
+
body{
|
| 18 |
+
background:
|
| 19 |
+
radial-gradient(1100px 600px at 80% -10%, rgba(45,212,191,.09), transparent 60%),
|
| 20 |
+
radial-gradient(900px 500px at 5% 0%, rgba(167,139,250,.08), transparent 60%),
|
| 21 |
+
var(--bg);
|
| 22 |
+
color:var(--ink); font-family:var(--sans); font-size:14px; line-height:1.5; -webkit-font-smoothing:antialiased;
|
| 23 |
+
}
|
| 24 |
+
a{color:var(--teal)}
|
| 25 |
+
.wrap{max-width:1280px;margin:0 auto;padding:0 20px 80px}
|
| 26 |
+
|
| 27 |
+
/* ---------- header ---------- */
|
| 28 |
+
header{position:sticky;top:0;z-index:60;backdrop-filter:blur(12px);background:rgba(7,12,21,.86);border-bottom:1px solid var(--line)}
|
| 29 |
+
.hrow{max-width:1280px;margin:0 auto;padding:14px 20px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
|
| 30 |
+
.brand{display:flex;align-items:baseline;gap:10px;flex:1 1 320px;min-width:0}
|
| 31 |
+
.brand h1{font-size:16px;margin:0;letter-spacing:.2px;font-weight:650}
|
| 32 |
+
.brand .sub{font-family:var(--mono);font-size:11px;color:var(--dim)}
|
| 33 |
+
.brand .dot{width:8px;height:8px;border-radius:50%;background:var(--teal);box-shadow:0 0 12px var(--teal);align-self:center}
|
| 34 |
+
.hstat{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
| 35 |
+
.pill{font-family:var(--mono);font-size:10.5px;letter-spacing:.4px;padding:4px 9px;border-radius:999px;border:1px solid var(--line);background:var(--panel2);color:var(--mut);white-space:nowrap}
|
| 36 |
+
.pill.ok{color:var(--green);border-color:rgba(52,211,153,.35);background:rgba(52,211,153,.08)}
|
| 37 |
+
.pill.warn{color:var(--amber);border-color:rgba(245,181,68,.35);background:rgba(245,181,68,.08)}
|
| 38 |
+
.pill.bad{color:var(--red);border-color:rgba(248,113,113,.4);background:rgba(248,113,113,.09)}
|
| 39 |
+
.pill.v{color:var(--violet);border-color:rgba(167,139,250,.35);background:rgba(167,139,250,.08)}
|
| 40 |
+
button{font-family:inherit;font-size:12.5px;color:var(--ink);background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:7px 12px;cursor:pointer;transition:.15s}
|
| 41 |
+
button:hover{border-color:var(--teal);color:#fff;background:var(--panel3)}
|
| 42 |
+
button.primary{background:linear-gradient(180deg,#2dd4bf,#14b8a6);color:#04241f;border-color:#2dd4bf;font-weight:650}
|
| 43 |
+
button.primary:hover{filter:brightness(1.1);color:#04241f}
|
| 44 |
+
button.danger{border-color:rgba(248,113,113,.5);color:var(--red)}
|
| 45 |
+
button:disabled{opacity:.45;cursor:not-allowed}
|
| 46 |
+
button.sm{padding:4px 9px;font-size:11.5px;border-radius:7px}
|
| 47 |
+
|
| 48 |
+
/* ---------- nav ---------- */
|
| 49 |
+
nav{max-width:1280px;margin:0 auto;padding:0 20px;display:flex;gap:4px;overflow-x:auto;border-bottom:1px solid var(--line);scrollbar-width:thin}
|
| 50 |
+
nav button{background:none;border:none;border-bottom:2px solid transparent;border-radius:0;color:var(--mut);padding:11px 13px;font-size:12.5px;letter-spacing:.3px;white-space:nowrap}
|
| 51 |
+
nav button:hover{color:var(--ink);background:rgba(255,255,255,.03)}
|
| 52 |
+
nav button.on{color:var(--teal);border-bottom-color:var(--teal)}
|
| 53 |
+
nav button .n{font-family:var(--mono);font-size:10px;color:var(--dim);margin-right:6px}
|
| 54 |
+
|
| 55 |
+
/* ---------- layout ---------- */
|
| 56 |
+
.view{display:none;padding-top:26px}
|
| 57 |
+
.view.on{display:block}
|
| 58 |
+
.h2{display:flex;align-items:baseline;gap:12px;margin:0 0 4px;font-size:18px;font-weight:650;letter-spacing:.2px}
|
| 59 |
+
.h2 .tag{font-family:var(--mono);font-size:10.5px;color:var(--dim);font-weight:400}
|
| 60 |
+
.lede{color:var(--mut);max-width:820px;margin:0 0 20px;font-size:13.2px}
|
| 61 |
+
.h3{font-size:11px;font-family:var(--mono);letter-spacing:1.3px;text-transform:uppercase;color:var(--dim);margin:26px 0 10px}
|
| 62 |
+
.grid{display:grid;gap:14px}
|
| 63 |
+
.g3{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}
|
| 64 |
+
.g2{grid-template-columns:1fr 1fr}
|
| 65 |
+
.gsplit{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
|
| 66 |
+
.card{background:linear-gradient(180deg,var(--panel),rgba(13,21,35,.6));border:1px solid var(--line);border-radius:12px;padding:15px}
|
| 67 |
+
.card.pad0{padding:0;overflow:hidden}
|
| 68 |
+
@media(max-width:900px){.g2,.gsplit{grid-template-columns:1fr}}
|
| 69 |
+
|
| 70 |
+
/* ---------- agent cards ---------- */
|
| 71 |
+
.acard{position:relative;cursor:pointer;transition:.16s}
|
| 72 |
+
.acard:hover{border-color:rgba(45,212,191,.5);transform:translateY(-2px)}
|
| 73 |
+
.acard .top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
|
| 74 |
+
.acard .handle{font-family:var(--mono);font-size:14px;font-weight:600;color:var(--teal)}
|
| 75 |
+
.acard .role{font-family:var(--mono);font-size:10.5px;color:var(--dim);letter-spacing:.6px;text-transform:uppercase;margin-top:2px}
|
| 76 |
+
.acard .jtbd{color:var(--mut);font-size:12.5px;margin:11px 0 10px;min-height:52px}
|
| 77 |
+
.chips{display:flex;flex-wrap:wrap;gap:5px}
|
| 78 |
+
.chip{font-family:var(--mono);font-size:10px;padding:3px 7px;border-radius:6px;border:1px solid var(--line);color:var(--mut);background:var(--panel2);white-space:nowrap}
|
| 79 |
+
.chip.w{color:var(--green);border-color:rgba(52,211,153,.32);background:rgba(52,211,153,.07)}
|
| 80 |
+
.chip.n{color:var(--red);border-color:rgba(248,113,113,.32);background:rgba(248,113,113,.07)}
|
| 81 |
+
.chip.v{color:var(--violet);border-color:rgba(167,139,250,.32);background:rgba(167,139,250,.07)}
|
| 82 |
+
.chip.a{color:var(--amber);border-color:rgba(245,181,68,.32);background:rgba(245,181,68,.07)}
|
| 83 |
+
.lbl{font-family:var(--mono);font-size:9.5px;letter-spacing:1px;color:var(--dim);text-transform:uppercase;margin:12px 0 5px}
|
| 84 |
+
.meter{height:4px;border-radius:3px;background:var(--panel3);overflow:hidden;margin-top:6px}
|
| 85 |
+
.meter i{display:block;height:100%;border-radius:3px}
|
| 86 |
+
.stance{font-family:var(--mono);font-size:10px;padding:3px 8px;border-radius:999px;border:1px solid}
|
| 87 |
+
.s-auto{color:var(--green);border-color:rgba(52,211,153,.4);background:rgba(52,211,153,.08)}
|
| 88 |
+
.s-prop{color:var(--amber);border-color:rgba(245,181,68,.4);background:rgba(245,181,68,.09)}
|
| 89 |
+
.s-hitl{color:var(--blue);border-color:rgba(96,165,250,.4);background:rgba(96,165,250,.09)}
|
| 90 |
+
.s-gate{color:var(--violet);border-color:rgba(167,139,250,.4);background:rgba(167,139,250,.09)}
|
| 91 |
+
|
| 92 |
+
/* ---------- drawer ---------- */
|
| 93 |
+
.scrim{position:fixed;inset:0;background:rgba(3,7,13,.72);backdrop-filter:blur(3px);z-index:90;display:none}
|
| 94 |
+
.scrim.on{display:block}
|
| 95 |
+
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(560px,94vw);background:var(--panel);border-left:1px solid var(--line);z-index:91;transform:translateX(102%);transition:.26s cubic-bezier(.3,.8,.3,1);overflow-y:auto;padding:22px}
|
| 96 |
+
.drawer.on{transform:none}
|
| 97 |
+
.kv{display:grid;grid-template-columns:132px 1fr;gap:6px 12px;font-size:12.5px}
|
| 98 |
+
.kv dt{font-family:var(--mono);font-size:10.5px;color:var(--dim);letter-spacing:.6px;text-transform:uppercase;padding-top:2px}
|
| 99 |
+
.kv dd{margin:0;color:var(--ink)}
|
| 100 |
+
ul.tight{margin:0;padding-left:17px;color:var(--mut);font-size:12.5px}
|
| 101 |
+
ul.tight li{margin:3px 0}
|
| 102 |
+
code{font-family:var(--mono);font-size:11.5px;background:var(--panel3);padding:1.5px 5px;border-radius:4px;color:var(--teal)}
|
| 103 |
+
pre{margin:0;font-family:var(--mono);font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word;color:#cfe0f5}
|
| 104 |
+
|
| 105 |
+
/* ---------- filesystem ---------- */
|
| 106 |
+
.fs{font-family:var(--mono);font-size:12.5px;padding:8px 6px}
|
| 107 |
+
.fsrow{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:7px;cursor:pointer;border:1px solid transparent}
|
| 108 |
+
.fsrow:hover{background:var(--panel2);border-color:var(--line)}
|
| 109 |
+
.fsrow.on{background:rgba(45,212,191,.09);border-color:rgba(45,212,191,.32)}
|
| 110 |
+
.fsrow .nm{color:var(--ink)}
|
| 111 |
+
.fsrow .own{margin-left:auto;display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}
|
| 112 |
+
.lock{color:var(--amber);font-size:10px}
|
| 113 |
+
table.mx{border-collapse:collapse;width:100%;font-family:var(--mono);font-size:11px}
|
| 114 |
+
table.mx th,table.mx td{border:1px solid var(--line);padding:5px 6px;text-align:center}
|
| 115 |
+
table.mx th{background:var(--panel2);color:var(--dim);font-weight:500;font-size:10px;letter-spacing:.3px}
|
| 116 |
+
table.mx td.p{cursor:pointer}
|
| 117 |
+
table.mx td.path{text-align:left;color:var(--ink);background:var(--panel2);white-space:nowrap;font-size:10.5px;cursor:pointer}
|
| 118 |
+
table.mx tr:hover td{background:rgba(255,255,255,.025)}
|
| 119 |
+
.W{color:var(--green);font-weight:700}
|
| 120 |
+
.H{color:var(--pink);font-weight:700}
|
| 121 |
+
.R{color:var(--mut)}
|
| 122 |
+
.X{color:#31425c}
|
| 123 |
+
.legend{display:flex;gap:14px;flex-wrap:wrap;font-family:var(--mono);font-size:10.5px;color:var(--mut);margin-top:10px}
|
| 124 |
+
.scroll{overflow-x:auto}
|
| 125 |
+
|
| 126 |
+
/* ---------- forms ---------- */
|
| 127 |
+
label.f{display:block;margin:12px 0 0}
|
| 128 |
+
label.f span{display:block;font-family:var(--mono);font-size:10px;letter-spacing:1px;text-transform:uppercase;color:var(--dim);margin-bottom:5px}
|
| 129 |
+
input[type=text],select,textarea{width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:8px 10px;font-family:var(--mono);font-size:12px;outline:none}
|
| 130 |
+
input[type=text]:focus,select:focus,textarea:focus{border-color:var(--teal)}
|
| 131 |
+
textarea{resize:vertical;line-height:1.55}
|
| 132 |
+
.two{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
| 133 |
+
.pathpick{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:5px;margin-top:6px}
|
| 134 |
+
.pathpick label{display:flex;gap:7px;align-items:center;font-family:var(--mono);font-size:11px;color:var(--mut);background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:5px 8px;cursor:pointer}
|
| 135 |
+
.pathpick label:hover{border-color:var(--dim)}
|
| 136 |
+
.pathpick input{accent-color:#2dd4bf;margin:0}
|
| 137 |
+
.pathpick label.sel{border-color:rgba(45,212,191,.45);color:var(--ink);background:rgba(45,212,191,.07)}
|
| 138 |
+
|
| 139 |
+
/* ---------- verdict ---------- */
|
| 140 |
+
.vline{display:flex;gap:9px;align-items:flex-start;padding:8px 10px;border-radius:8px;border:1px solid var(--line);margin-bottom:6px;font-size:12.5px;background:var(--panel2)}
|
| 141 |
+
.vline b{font-family:var(--mono);font-size:10.5px;letter-spacing:.4px;padding:2px 6px;border-radius:5px;white-space:nowrap}
|
| 142 |
+
.vline.block{border-color:rgba(248,113,113,.42);background:rgba(248,113,113,.07)}
|
| 143 |
+
.vline.block b{background:rgba(248,113,113,.16);color:var(--red)}
|
| 144 |
+
.vline.warn{border-color:rgba(245,181,68,.4);background:rgba(245,181,68,.06)}
|
| 145 |
+
.vline.warn b{background:rgba(245,181,68,.16);color:var(--amber)}
|
| 146 |
+
.vline.info{border-color:rgba(96,165,250,.35);background:rgba(96,165,250,.06)}
|
| 147 |
+
.vline.info b{background:rgba(96,165,250,.16);color:var(--blue)}
|
| 148 |
+
.vline.pass{border-color:rgba(52,211,153,.35);background:rgba(52,211,153,.06)}
|
| 149 |
+
.vline.pass b{background:rgba(52,211,153,.16);color:var(--green)}
|
| 150 |
+
|
| 151 |
+
/* ---------- kanban ---------- */
|
| 152 |
+
.kan{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
|
| 153 |
+
@media(max-width:1000px){.kan{grid-template-columns:1fr 1fr}}
|
| 154 |
+
.col{background:rgba(13,21,35,.55);border:1px solid var(--line);border-radius:12px;padding:11px;min-height:220px}
|
| 155 |
+
.col h4{margin:0 0 10px;font-size:11px;font-family:var(--mono);letter-spacing:1px;text-transform:uppercase;color:var(--dim);display:flex;justify-content:space-between}
|
| 156 |
+
.tk{background:var(--panel2);border:1px solid var(--line);border-radius:9px;padding:9px 10px;margin-bottom:8px;font-size:12px;animation:pop .25s ease}
|
| 157 |
+
@keyframes pop{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
|
| 158 |
+
.tk .id{font-family:var(--mono);font-size:10.5px;color:var(--dim)}
|
| 159 |
+
.tk .gl{color:var(--ink);margin:4px 0 6px;font-size:12px;line-height:1.45}
|
| 160 |
+
.tk .row{display:flex;gap:5px;flex-wrap:wrap;align-items:center}
|
| 161 |
+
.tk.blocked{border-color:rgba(248,113,113,.45)}
|
| 162 |
+
.tk.done{border-color:rgba(52,211,153,.32)}
|
| 163 |
+
.tk.reopen{border-color:rgba(245,181,68,.45)}
|
| 164 |
+
.pri{font-family:var(--mono);font-size:9.5px;padding:2px 6px;border-radius:5px;border:1px solid var(--line)}
|
| 165 |
+
.p0{color:var(--red);border-color:rgba(248,113,113,.45)}
|
| 166 |
+
.p1{color:var(--amber);border-color:rgba(245,181,68,.4)}
|
| 167 |
+
.p2,.p3{color:var(--mut)}
|
| 168 |
+
.console{background:#060a12;border:1px solid var(--line);border-radius:10px;padding:12px;font-family:var(--mono);font-size:11.5px;line-height:1.75;height:280px;overflow-y:auto}
|
| 169 |
+
.console .t{color:#2b3d57}
|
| 170 |
+
.console .g{color:var(--green)}
|
| 171 |
+
.console .a{color:var(--amber)}
|
| 172 |
+
.console .r{color:var(--red)}
|
| 173 |
+
.console .b{color:var(--blue)}
|
| 174 |
+
.console .v{color:var(--violet)}
|
| 175 |
+
|
| 176 |
+
/* ---------- jtbd ---------- */
|
| 177 |
+
.job{padding:11px 12px;border:1px solid var(--line);border-radius:10px;background:var(--panel2);cursor:pointer;margin-bottom:8px;transition:.15s}
|
| 178 |
+
.job:hover{border-color:var(--dim)}
|
| 179 |
+
.job.on{border-color:var(--teal);background:rgba(45,212,191,.08)}
|
| 180 |
+
.job .ttl{font-size:12.8px;color:var(--ink);font-weight:550}
|
| 181 |
+
.job .wh{font-family:var(--mono);font-size:10.5px;color:var(--dim);margin-top:4px}
|
| 182 |
+
.chain{position:relative;padding-left:22px}
|
| 183 |
+
.chain:before{content:"";position:absolute;left:6px;top:6px;bottom:6px;width:1.5px;background:linear-gradient(180deg,var(--teal),var(--violet),var(--amber))}
|
| 184 |
+
.stage{position:relative;margin-bottom:11px}
|
| 185 |
+
.stage:before{content:"";position:absolute;left:-20px;top:13px;width:9px;height:9px;border-radius:50%;background:var(--panel);border:2px solid var(--teal)}
|
| 186 |
+
.stage.v:before{border-color:var(--violet)}
|
| 187 |
+
.stage.a:before{border-color:var(--amber)}
|
| 188 |
+
.stage .sbox{background:var(--panel2);border:1px solid var(--line);border-radius:9px;padding:9px 11px}
|
| 189 |
+
.stage .sk{font-family:var(--mono);font-size:9.5px;letter-spacing:1.1px;text-transform:uppercase;color:var(--dim);margin-bottom:4px}
|
| 190 |
+
.stage .sv{font-size:12.5px;color:var(--ink)}
|
| 191 |
+
.stage .sv small{color:var(--mut);display:block;margin-top:3px;font-size:11.5px}
|
| 192 |
+
|
| 193 |
+
/* ---------- misc ---------- */
|
| 194 |
+
.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(20px);opacity:0;background:var(--panel3);border:1px solid var(--teal);color:var(--ink);padding:10px 16px;border-radius:10px;font-family:var(--mono);font-size:12px;z-index:200;transition:.22s;pointer-events:none}
|
| 195 |
+
.toast.on{opacity:1;transform:translateX(-50%)}
|
| 196 |
+
.split{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
|
| 197 |
+
.stat{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:12px}
|
| 198 |
+
.stat .v{font-size:22px;font-weight:650;letter-spacing:-.4px}
|
| 199 |
+
.stat .k{font-family:var(--mono);font-size:10px;letter-spacing:.8px;text-transform:uppercase;color:var(--dim);margin-top:3px}
|
| 200 |
+
.note{font-size:12px;color:var(--mut);border-left:2px solid var(--line);padding-left:11px;margin:12px 0}
|
| 201 |
+
h4.sec{font-size:13.5px;margin:0 0 8px;font-weight:600}
|
| 202 |
+
hr{border:none;border-top:1px solid var(--line);margin:20px 0}
|
| 203 |
+
.flexrow{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
|
| 204 |
+
.mono{font-family:var(--mono)}
|
| 205 |
+
.mut{color:var(--mut)}
|
| 206 |
+
.dim{color:var(--dim)}
|
| 207 |
+
</style>
|
| 208 |
+
</head>
|
| 209 |
+
<body>
|
| 210 |
+
<header>
|
| 211 |
+
<div class="hrow">
|
| 212 |
+
<div class="brand">
|
| 213 |
+
<span class="dot"></span>
|
| 214 |
+
<div>
|
| 215 |
+
<h1>InsurTech Agent Fleet</h1>
|
| 216 |
+
<div class="sub">6 agents · 1 filesystem · lane-scoped write authority</div>
|
| 217 |
+
</div>
|
| 218 |
+
</div>
|
| 219 |
+
<div class="hstat">
|
| 220 |
+
<span class="pill ok" id="hPosture">AUTONOMOUS</span>
|
| 221 |
+
<span class="pill" id="hQueue">queue 0</span>
|
| 222 |
+
<span class="pill" id="hBlocked">blocked 0</span>
|
| 223 |
+
<span class="pill v" id="hAudit">audit gate: armed</span>
|
| 224 |
+
<button class="sm" id="btnDegrade">Simulate SLO breach</button>
|
| 225 |
+
</div>
|
| 226 |
+
</div>
|
| 227 |
+
<nav id="nav">
|
| 228 |
+
<button data-v="fleet" class="on"><span class="n">01</span>Fleet & Lanes</button>
|
| 229 |
+
<button data-v="fs"><span class="n">02</span>Shared Filesystem</button>
|
| 230 |
+
<button data-v="compose"><span class="n">03</span>Compose a Task</button>
|
| 231 |
+
<button data-v="flow"><span class="n">04</span>Dispatch Board</button>
|
| 232 |
+
<button data-v="jtbd"><span class="n">05</span>JTBD Composer</button>
|
| 233 |
+
<button data-v="audit"><span class="n">06</span>Auditor's Table</button>
|
| 234 |
+
<button data-v="contract"><span class="n">07</span>Handoff Contract</button>
|
| 235 |
+
</nav>
|
| 236 |
+
</header>
|
| 237 |
+
|
| 238 |
+
<div class="wrap">
|
| 239 |
+
|
| 240 |
+
<!-- ============ FLEET ============ -->
|
| 241 |
+
<section class="view on" id="v-fleet">
|
| 242 |
+
<h2 class="h2">Fleet & Lanes <span class="tag">the roster is the concurrency model</span></h2>
|
| 243 |
+
<p class="lede">Six specialized agents share one filesystem. Nothing coordinates them but the roster: every shared path has exactly one writer, so a lock is a name, not a mutex. Click any agent to open its lane, its never-rules, and its blast radius.</p>
|
| 244 |
+
|
| 245 |
+
<div class="split" style="margin-bottom:20px">
|
| 246 |
+
<div class="stat"><div class="v" id="stAgents">6</div><div class="k">Lane owners</div></div>
|
| 247 |
+
<div class="stat"><div class="v" id="stPaths">12</div><div class="k">Governed paths</div></div>
|
| 248 |
+
<div class="stat"><div class="v" style="color:var(--amber)" id="stContend">1</div><div class="k">Contended path (serialized)</div></div>
|
| 249 |
+
<div class="stat"><div class="v" style="color:var(--pink)" id="stHuman">1</div><div class="k">Human-disposition only</div></div>
|
| 250 |
+
</div>
|
| 251 |
+
|
| 252 |
+
<div class="flexrow" style="margin-bottom:14px">
|
| 253 |
+
<input type="text" id="search" placeholder="filter by handle, skill, tool, job…" style="max-width:330px">
|
| 254 |
+
<span class="pill" id="searchCount">showing 6 of 6</span>
|
| 255 |
+
</div>
|
| 256 |
+
|
| 257 |
+
<div class="grid g3" id="agentGrid"></div>
|
| 258 |
+
|
| 259 |
+
<h3 class="h3">Principle</h3>
|
| 260 |
+
<div class="card">
|
| 261 |
+
<div class="grid g2">
|
| 262 |
+
<div>
|
| 263 |
+
<h4 class="sec">Agents propose</h4>
|
| 264 |
+
<p class="mut" style="margin:0;font-size:12.5px">Every agent output is a <b>proposal artifact</b> inside its own lane. Proposals carry a confidence, a reason-code from a closed taxonomy, and citations that must resolve. A proposal has no force — it is a file waiting for a gate.</p>
|
| 265 |
+
</div>
|
| 266 |
+
<div>
|
| 267 |
+
<h4 class="sec">Humans dispose</h4>
|
| 268 |
+
<p class="mut" style="margin:0;font-size:12.5px">Three acts are reserved for people and are <b>unwritable by the fleet</b>: binding a policy above the authority threshold, promoting a contested fact from <code>_provisional.md</code>, and accepting a correction that contradicts a prior decision. <code>DECISIONS.md</code> is human-only.</p>
|
| 269 |
+
</div>
|
| 270 |
+
</div>
|
| 271 |
+
<hr>
|
| 272 |
+
<h4 class="sec">The auditor checks everyone — including the orchestrator's bookkeeping</h4>
|
| 273 |
+
<p class="mut" style="margin:0;font-size:12.5px">@compliance-auditor holds no fact-write authority at all. It cannot fix knowledge; it can only <b>demote</b> (to <code>_graveyard.md</code>) and <b>propose corrections as tasks</b>. That asymmetry is what makes its review credible — it has no stake in any fact being true.</p>
|
| 274 |
+
</div>
|
| 275 |
+
</section>
|
| 276 |
+
|
| 277 |
+
<!-- ============ FILESYSTEM ============ -->
|
| 278 |
+
<section class="view" id="v-fs">
|
| 279 |
+
<h2 class="h2">Shared Filesystem <span class="tag">one tree, single-writer lanes</span></h2>
|
| 280 |
+
<p class="lede">The tree below is the whole coordination surface. Green = write authority. Amber ⚠ = contended (more than one writer, so the orchestrator serializes file-by-file). Click a path to inspect its writers, readers, and the rule that governs it.</p>
|
| 281 |
+
|
| 282 |
+
<div class="grid gsplit">
|
| 283 |
+
<div class="card pad0">
|
| 284 |
+
<div class="fs" id="fsTree"></div>
|
| 285 |
+
</div>
|
| 286 |
+
<div>
|
| 287 |
+
<div class="card" id="pathDetail">
|
| 288 |
+
<div class="dim mono" style="font-size:12px">← select a path to inspect its lane assignment</div>
|
| 289 |
+
</div>
|
| 290 |
+
</div>
|
| 291 |
+
</div>
|
| 292 |
+
|
| 293 |
+
<h3 class="h3">Write-authority matrix</h3>
|
| 294 |
+
<div class="card pad0 scroll"><table class="mx" id="matrix"></table></div>
|
| 295 |
+
<div class="legend">
|
| 296 |
+
<span><b class="W">W</b> write (lane owner)</span>
|
| 297 |
+
<span><b class="R">R</b> read</span>
|
| 298 |
+
<span><b class="H">H</b> human disposition only</span>
|
| 299 |
+
<span><b class="X">—</b> no access</span>
|
| 300 |
+
</div>
|
| 301 |
+
<p class="note">Only one row is contended: <code>tasks/pending/</code>. Every agent may file there, so it is not lane-partitioned — it is <b>serialized</b> by @orchestrator, which holds the queue and is the only writer that moves files from <code>pending/</code> to <code>done/</code>. Knowledge bodies are the opposite: partitioned three ways (<code>facts</code> → @claims-digest, <code>INDEX.md</code> → @indexer, <code>_graveyard.md</code> → @compliance-auditor) so no two agents ever touch the same fact file.</p>
|
| 302 |
+
</section>
|
| 303 |
+
|
| 304 |
+
<!-- ============ COMPOSE ============ -->
|
| 305 |
+
<section class="view" id="v-compose">
|
| 306 |
+
<h2 class="h2">Compose a Task <span class="tag">the handoff contract, enforced before it is filed</span></h2>
|
| 307 |
+
<p class="lede">A delegation is not a message — it is a file in <code>tasks/pending/</code>. Fill the six fields and a RESULT block. The validator checks the receiver's write lane, hard never-rules, and whether your <em>done-when</em> is checkable by a third party. Anything that fails is a reason code, not an opinion.</p>
|
| 308 |
+
|
| 309 |
+
<div class="grid gsplit">
|
| 310 |
+
<div class="card">
|
| 311 |
+
<div class="two">
|
| 312 |
+
<label class="f"><span>from</span><select id="f-from"></select></label>
|
| 313 |
+
<label class="f"><span>to</span><select id="f-to"></select></label>
|
| 314 |
+
</div>
|
| 315 |
+
<label class="f"><span>goal</span><textarea id="f-goal" rows="2" placeholder="Draft UW recommendation for submission SUB-88213 (commercial property, TIV 4.2M)"></textarea></label>
|
| 316 |
+
<label class="f"><span>inputs (one per line)</span><textarea id="f-inputs" rows="3" placeholder="knowledge/INDEX.md knowledge/products/appetite-commercial.md submission packet SUB-88213"></textarea></label>
|
| 317 |
+
<label class="f"><span>priority</span><select id="f-pri"><option>P0</option><option selected>P1</option><option>P2</option><option>P3</option></select></label>
|
| 318 |
+
|
| 319 |
+
<label class="f"><span>may-touch (receiver's write lane — checked)</span></label>
|
| 320 |
+
<div class="pathpick" id="pathPick"></div>
|
| 321 |
+
|
| 322 |
+
<label class="f"><span>done-when (one checkable predicate per line — the auditor's job)</span><textarea id="f-done" rows="4" placeholder="workspaces/@underwriter/UW-SUB-88213.md exists ≥3 cited sources each resolve to a file in knowledge/ confidence is a number 0-1 reason codes ⊆ taxonomy-v3"></textarea></label>
|
| 323 |
+
<label class="f"><span>RESULT block (filled on completion — empty here by design)</span><textarea id="f-result" rows="2" placeholder="RESULT: (unfilled — task closed without RESULT is reopened)" style="color:var(--dim)"></textarea></label>
|
| 324 |
+
|
| 325 |
+
<div class="flexrow" style="margin-top:14px">
|
| 326 |
+
<button class="primary" id="btnFile">File to tasks/pending/</button>
|
| 327 |
+
<button id="btnValidate">Re-validate</button>
|
| 328 |
+
<button id="btnClear">Clear</button>
|
| 329 |
+
</div>
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
<div>
|
| 333 |
+
<div class="card" style="margin-bottom:14px">
|
| 334 |
+
<h4 class="sec">Authority verdict</h4>
|
| 335 |
+
<div id="verdict"><div class="dim mono" style="font-size:12px">awaiting fields…</div></div>
|
| 336 |
+
</div>
|
| 337 |
+
<div class="card pad0">
|
| 338 |
+
<div class="flexrow" style="padding:11px 13px;border-bottom:1px solid var(--line);justify-content:space-between">
|
| 339 |
+
<span class="mono dim" style="font-size:10.5px;letter-spacing:1px">tasks/pending/<id>.md</span>
|
| 340 |
+
<button class="sm" id="btnCopy">copy markdown</button>
|
| 341 |
+
</div>
|
| 342 |
+
<pre id="mdOut" style="padding:13px;max-height:430px;overflow:auto"></pre>
|
| 343 |
+
</div>
|
| 344 |
+
</div>
|
| 345 |
+
</div>
|
| 346 |
+
</section>
|
| 347 |
+
|
| 348 |
+
<!-- ============ FLOW ============ -->
|
| 349 |
+
<section class="view" id="v-flow">
|
| 350 |
+
<h2 class="h2">Dispatch Board <span class="tag">morning run: INDEX → queue → lanes</span></h2>
|
| 351 |
+
<p class="lede">@orchestrator reads <code>knowledge/INDEX.md</code> plus the queue, orders by priority, and dispatches. Watch three things: contended files acquire a single-writer lock, an out-of-lane task is refused with a reason code rather than executed, and a task closed without a RESULT is reopened.</p>
|
| 352 |
+
|
| 353 |
+
<div class="flexrow" style="margin-bottom:14px">
|
| 354 |
+
<button class="primary" id="btnRun">▶ Run morning dispatch</button>
|
| 355 |
+
<button id="btnStep">Step</button>
|
| 356 |
+
<button id="btnReset">Reset board</button>
|
| 357 |
+
<span class="pill" id="flowStatus">idle</span>
|
| 358 |
+
</div>
|
| 359 |
+
|
| 360 |
+
<div class="kan" style="margin-bottom:16px">
|
| 361 |
+
<div class="col"><h4>tasks/pending/ <span id="cPend">0</span></h4><div id="colPending"></div></div>
|
| 362 |
+
<div class="col"><h4>locked · dispatched <span id="cRun">0</span></h4><div id="colRunning"></div></div>
|
| 363 |
+
<div class="col"><h4>tasks/done/ <span id="cDone">0</span></h4><div id="colDone"></div></div>
|
| 364 |
+
<div class="col"><h4>refused / reopened <span id="cBlock">0</span></h4><div id="colBlock"></div></div>
|
| 365 |
+
</div>
|
| 366 |
+
|
| 367 |
+
<h3 class="h3">ACTIVITY.md <span class="dim" style="font-family:var(--mono);font-size:10px;letter-spacing:0">— append-only, written by @orchestrator</span></h3>
|
| 368 |
+
<div class="console" id="console"></div>
|
| 369 |
+
</section>
|
| 370 |
+
|
| 371 |
+
<!-- ============ JTBD ============ -->
|
| 372 |
+
<section class="view" id="v-jtbd">
|
| 373 |
+
<h2 class="h2">JTBD Composer <span class="tag">compose the fleet from the work, not the tech</span></h2>
|
| 374 |
+
<p class="lede">Pick a job to be done. The chain resolves downward — job → capability → skill → tool → owning agent → artifact → checkable done-when → human gate — and then hands you a prefilled task contract. This is the composition guide: start at the job, arrive at a lane.</p>
|
| 375 |
+
|
| 376 |
+
<div class="grid gsplit">
|
| 377 |
+
<div>
|
| 378 |
+
<h3 class="h3" style="margin-top:0">Jobs to be done</h3>
|
| 379 |
+
<div id="jobList"></div>
|
| 380 |
+
</div>
|
| 381 |
+
<div>
|
| 382 |
+
<h3 class="h3" style="margin-top:0">Composition chain</h3>
|
| 383 |
+
<div class="chain" id="chainWrap"><div class="dim mono" style="font-size:12px">← select a job</div></div>
|
| 384 |
+
<div id="chainActions" style="margin-top:6px"></div>
|
| 385 |
+
</div>
|
| 386 |
+
</div>
|
| 387 |
+
</section>
|
| 388 |
+
|
| 389 |
+
<!-- ============ AUDIT ============ -->
|
| 390 |
+
<section class="view" id="v-audit">
|
| 391 |
+
<h2 class="h2">Auditor's Table <span class="tag">@compliance-auditor — no fact-write authority</span></h2>
|
| 392 |
+
<p class="lede">The gatekeeper cannot edit what it audits. It runs three checks, and every finding leaves as a <b>task</b> against the agent that owns the lane — never as a silent fix. Demotions go to <code>_graveyard.md</code>; everything else is a proposal.</p>
|
| 393 |
+
|
| 394 |
+
<div class="split" style="margin-bottom:6px">
|
| 395 |
+
<div class="card">
|
| 396 |
+
<h4 class="sec">1 · RESULT gate scan</h4>
|
| 397 |
+
<p class="mut" style="font-size:12px;margin:0 0 10px">Every task in <code>tasks/done/</code> must carry a RESULT block. Closure without one is a bookkeeping failure, not a content failure.</p>
|
| 398 |
+
<button class="sm" data-check="result">Run scan</button>
|
| 399 |
+
<div id="ck-result" style="margin-top:10px"></div>
|
| 400 |
+
</div>
|
| 401 |
+
<div class="card">
|
| 402 |
+
<h4 class="sec">2 · Source-citation coverage</h4>
|
| 403 |
+
<p class="mut" style="font-size:12px;margin:0 0 10px">Every knowledge-body change must cite a source that resolves to a file that exists. Uncited edits are quarantined to <code>_provisional.md</code> until sourced.</p>
|
| 404 |
+
<button class="sm" data-check="cite">Run scan</button>
|
| 405 |
+
<div id="ck-cite" style="margin-top:10px"></div>
|
| 406 |
+
</div>
|
| 407 |
+
<div class="card">
|
| 408 |
+
<h4 class="sec">3 · Disparate-outcome sample</h4>
|
| 409 |
+
<p class="mut" style="font-size:12px;margin:0 0 10px">Sample N closed decisions, compare approval ratio across groups, and report the delta with a confidence interval — a number, not a vibe.</p>
|
| 410 |
+
<button class="sm" data-check="fair">Run sample</button>
|
| 411 |
+
<div id="ck-fair" style="margin-top:10px"></div>
|
| 412 |
+
</div>
|
| 413 |
+
<div class="card">
|
| 414 |
+
<h4 class="sec">Findings → proposed corrections</h4>
|
| 415 |
+
<p class="mut" style="font-size:12px;margin:0 0 10px">Findings become task proposals in <code>tasks/pending/</code>, addressed to the lane owner. The auditor never resolves its own finding.</p>
|
| 416 |
+
<div id="findings"><div class="dim mono" style="font-size:12px">no open findings</div></div>
|
| 417 |
+
</div>
|
| 418 |
+
</div>
|
| 419 |
+
<p class="note">Note the direction of every arrow: the auditor's output is work for <em>other</em> agents. A gate that can repair what it finds is not a gate.</p>
|
| 420 |
+
</section>
|
| 421 |
+
|
| 422 |
+
<!-- ============ CONTRACT ============ -->
|
| 423 |
+
<section class="view" id="v-contract">
|
| 424 |
+
<h2 class="h2">Handoff Contract <span class="tag">the only interface between agents</span></h2>
|
| 425 |
+
<p class="lede">Delegation is a file. There is no bus, no queue service, no RPC. The contract below is what makes a lane-scoped fleet auditable: every handoff carries its own acceptance criteria and its own evidence of completion.</p>
|
| 426 |
+
|
| 427 |
+
<div class="grid g2">
|
| 428 |
+
<div class="card">
|
| 429 |
+
<h4 class="sec">The contract</h4>
|
| 430 |
+
<pre style="color:#cfe0f5">tasks/pending/<id>.md
|
| 431 |
+
────────────────────────────
|
| 432 |
+
from: @handle (must hold write on tasks/pending/)
|
| 433 |
+
to: @handle (lane owner of may-touch)
|
| 434 |
+
goal: one sentence, imperative, bounded
|
| 435 |
+
inputs: files / artifacts the receiver reads
|
| 436 |
+
may-touch: paths the receiver may write ← authority-checked
|
| 437 |
+
done-when: checkable predicates ← third-party verifiable
|
| 438 |
+
priority: P0 | P1 | P2 | P3
|
| 439 |
+
────────────────────────────
|
| 440 |
+
RESULT: filled on completion, before the
|
| 441 |
+
file moves pending/ → done/</pre>
|
| 442 |
+
<p class="note" style="margin-top:14px">Two clauses carry the whole design. <b>may-touch</b> is checked against the receiver's lane, so an impossible delegation is refused at filing time rather than discovered as a corrupted file. <b>done-when</b> is written for a third party, because the only party who can be trusted to accept the work is one with no stake in it.</p>
|
| 443 |
+
</div>
|
| 444 |
+
<div class="card">
|
| 445 |
+
<h4 class="sec">Lifecycle</h4>
|
| 446 |
+
<div class="chain">
|
| 447 |
+
<div class="stage"><div class="sbox"><div class="sk">1 · file</div><div class="sv">Task lands in <code>pending/</code><small>Authority validated at write time. Invalid may-touch never reaches the queue.</small></div></div></div>
|
| 448 |
+
<div class="stage v"><div class="sbox"><div class="sk">2 · dispatch</div><div class="sv">@orchestrator orders by priority, acquires per-file locks<small>Contended files (only <code>tasks/pending/</code>) are serialized; one writer at a time.</small></div></div></div>
|
| 449 |
+
<div class="stage"><div class="sbox"><div class="sk">3 · work</div><div class="sv">Receiver writes only inside <code>may-touch</code><small>Out-of-lane writes are refused with a reason code and filed as an incident.</small></div></div></div>
|
| 450 |
+
<div class="stage a"><div class="sbox"><div class="sk">4 · result</div><div class="sv">Receiver appends a RESULT block<small>Unfilled RESULT ⇒ the task is reopened, not closed. Silence is not completion.</small></div></div></div>
|
| 451 |
+
<div class="stage"><div class="sbox"><div class="sk">5 · audit</div><div class="sv">@compliance-auditor checks done-when against evidence<small>Findings leave as new tasks against the owning lane.</small></div></div></div>
|
| 452 |
+
<div class="stage a"><div class="sbox"><div class="sk">6 · dispose</div><div class="sv">A human accepts, binds, or rejects<small>The fleet's work ends in <code>DECISIONS.md</code>, which no agent may write.</small></div></div></div>
|
| 453 |
+
</div>
|
| 454 |
+
</div>
|
| 455 |
+
</div>
|
| 456 |
+
|
| 457 |
+
<h3 class="h3">Reason-code taxonomy</h3>
|
| 458 |
+
<div class="card pad0 scroll">
|
| 459 |
+
<table class="mx" style="text-align:left">
|
| 460 |
+
<thead><tr><th style="text-align:left">code</th><th style="text-align:left">meaning</th><th style="text-align:left">raised by</th><th style="text-align:left">disposition</th></tr></thead>
|
| 461 |
+
<tbody id="rcTable"></tbody>
|
| 462 |
+
</table>
|
| 463 |
+
</div>
|
| 464 |
+
|
| 465 |
+
<h3 class="h3">Invariants</h3>
|
| 466 |
+
<div class="card">
|
| 467 |
+
<ul class="tight">
|
| 468 |
+
<li><b>N1</b> — Every governed path has exactly one writer, except <code>tasks/pending/</code>, which is serialized. A lock is a lane name.</li>
|
| 469 |
+
<li><b>N2</b> — No agent writes <code>knowledge/</code> facts and <code>DECISIONS.md</code> in the same turn. Propose/dispose never collapses into one actor.</li>
|
| 470 |
+
<li><b>N3</b> — Deletion is unavailable to ingest agents. Bad facts are demoted to <code>_graveyard.md</code>, where they remain citable history.</li>
|
| 471 |
+
<li><b>N4</b> — A closed task without a RESULT block is reopened. Completion is evidence, not assertion.</li>
|
| 472 |
+
<li><b>N5</b> — The gatekeeper holds no write authority over what it audits; it proposes only.</li>
|
| 473 |
+
<li><b>N6</b> — On SLO breach, all non-human-gated agents degrade to HITL in the same tick the incident is filed.</li>
|
| 474 |
+
</ul>
|
| 475 |
+
</div>
|
| 476 |
+
</section>
|
| 477 |
+
|
| 478 |
+
</div>
|
| 479 |
+
|
| 480 |
+
<div class="scrim" id="scrim"></div>
|
| 481 |
+
<aside class="drawer" id="drawer"></aside>
|
| 482 |
+
<div class="toast" id="toast"></div>
|
| 483 |
+
|
| 484 |
+
<script>
|
| 485 |
+
/* ============================================================
|
| 486 |
+
DATA
|
| 487 |
+
============================================================ */
|
| 488 |
+
const AGENTS = [
|
| 489 |
+
{
|
| 490 |
+
id:'orchestrator', h:'@orchestrator', role:'Coordinator', stance:'auto',
|
| 491 |
+
jtbd:'When the queue and the knowledge index disagree about what is urgent, I want one ordered dispatch list, so no lane sits idle and no file gets two writers.',
|
| 492 |
+
may:['tasks/pending/','tasks/done/','ACTIVITY.md','logs/'],
|
| 493 |
+
never:['knowledge/ file bodies'],
|
| 494 |
+
reads:['knowledge/INDEX.md','alerts/','reports/','workspaces/@underwriter/'],
|
| 495 |
+
skills:['priority arbitration','single-writer lock acquisition & release','escalation routing','conflict serialization over shared paths','stale-work reaper'],
|
| 496 |
+
tools:['task queue reader','INDEX parser','file lock registry','escalation inbox','ACTIVITY.md appender'],
|
| 497 |
+
caps:['Task dispatch','Conflict serialization','Human escalation'],
|
| 498 |
+
out:['ordered dispatch list','ACTIVITY.md entries','escalation tickets'],
|
| 499 |
+
blast:'Blast radius: an orchestrator that mis-orders stalls a lane; an orchestrator that mis-locks corrupts a shared file. It cannot alter a fact, so the worst case is delay, not falsehood — which is why its locks are advisory-only against a human.',
|
| 500 |
+
slo:['dispatch latency p95 < 2 min',92]
|
| 501 |
+
},
|
| 502 |
+
{
|
| 503 |
+
id:'underwriter', h:'@underwriter', role:'Decision agent', stance:'prop',
|
| 504 |
+
jtbd:'When a broker submits a commercial risk, I want a defensible recommendation with cited evidence and reason codes, so I can bind inside appetite without re-reading the file.',
|
| 505 |
+
may:['workspaces/@underwriter/','tasks/pending/'],
|
| 506 |
+
never:['knowledge/ directly','DECISIONS.md'],
|
| 507 |
+
reads:['knowledge/','knowledge/INDEX.md'],
|
| 508 |
+
skills:['risk selection against appetite ruleset','evidence citation with resolvable anchors','confidence calibration','reason-code assignment from a closed taxonomy','threshold self-arrest'],
|
| 509 |
+
tools:['policy doc store (read)','claims history query (read)','appetite ruleset v3','reason-code taxonomy','confidence scorer'],
|
| 510 |
+
caps:['Defensible risk selection','Evidence-cited recommendation','Threshold self-arrest'],
|
| 511 |
+
out:['workspaces/@underwriter/UW-<id>.md','task proposals'],
|
| 512 |
+
blast:'Blast radius: an underwriter that overstates confidence misprices a book. It cannot bind above the threshold and cannot write facts, so a bad recommendation becomes a visible artifact with citations a human can refute line by line.',
|
| 513 |
+
slo:['ungrounded-claim rate < 1.5%',88]
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
id:'claims-digest', h:'@claims-digest', role:'Ingest & extract', stance:'prop',
|
| 517 |
+
jtbd:'When a claim file and a call transcript land together, I want the facts extracted once with contradictions isolated, so adjusters stop re-deriving them and stop disagreeing about what the file said.',
|
| 518 |
+
may:['knowledge/','knowledge/claims/','knowledge/precedent/','knowledge/products/','knowledge/_provisional.md','tasks/pending/'],
|
| 519 |
+
never:['deletions','DECISIONS.md'],
|
| 520 |
+
reads:['workspaces/@underwriter/'],
|
| 521 |
+
skills:['transcript → facts / decisions / open questions','source anchoring per assertion','contradiction detection and isolation','provisional-first promotion discipline'],
|
| 522 |
+
tools:['document classifier','ASR transcript parser','OCR','entity resolver','contradiction detector'],
|
| 523 |
+
caps:['Single-pass fact extraction','Contradiction isolation','Source-anchored knowledge writing'],
|
| 524 |
+
out:['knowledge/claims/<id>.md','knowledge/_provisional.md entries'],
|
| 525 |
+
blast:'Blast radius: an ingest agent that deletes is unrecoverable. Deletion is therefore unavailable — contradictions go to _provisional.md and, once the gatekeeper demotes them, to _graveyard.md, where they remain citable history.',
|
| 526 |
+
slo:['source-anchor coverage 100%',96]
|
| 527 |
+
},
|
| 528 |
+
{
|
| 529 |
+
id:'compliance-auditor', h:'@compliance-auditor', role:'Gatekeeper', stance:'gate',
|
| 530 |
+
jtbd:'When a decision is proposed, I want a gate with no stake in the outcome that can catch unsourced facts and disparate approvals before a human signs.',
|
| 531 |
+
may:['knowledge/_graveyard.md','reports/','tasks/pending/'],
|
| 532 |
+
never:['knowledge/ facts'],
|
| 533 |
+
reads:['knowledge/','tasks/','workspaces/@underwriter/','DECISIONS.md','ACTIVITY.md','logs/'],
|
| 534 |
+
skills:['promotion review of provisional → durable','source resolution on every change','sampled disparate-outcome testing','confidence calibration review','reason-code distribution analysis'],
|
| 535 |
+
tools:['diff engine','citation resolver','link checker','outcome sampler','group-ratio comparator with CI'],
|
| 536 |
+
caps:['Promotion gating','Source verification','Disparate-outcome detection'],
|
| 537 |
+
out:['reports/audit-<ts>.md','correction task proposals','_graveyard.md demotions'],
|
| 538 |
+
blast:'Blast radius: an auditor that can edit facts can launder them. Its authority is deliberately inverted — demote and propose, never repair. It can block a promotion, which is the point.',
|
| 539 |
+
slo:['promotion review < 15 min',84]
|
| 540 |
+
},
|
| 541 |
+
{
|
| 542 |
+
id:'indexer', h:'@indexer', role:'Mapmaker', stance:'auto',
|
| 543 |
+
jtbd:'When six ingest writes land in one hour, I want the map regenerated from the actual tree, so nobody navigates by a stale index.',
|
| 544 |
+
may:['knowledge/INDEX.md'],
|
| 545 |
+
never:['everything else'],
|
| 546 |
+
reads:['knowledge/','tasks/'],
|
| 547 |
+
skills:['tree → index regeneration','link resolution verification','staleness ageing by last-touch','orphan detection'],
|
| 548 |
+
tools:['filesystem walker','markdown link resolver','age calculator','orphan detector'],
|
| 549 |
+
caps:['Index regeneration','Link integrity','Staleness flagging'],
|
| 550 |
+
out:['knowledge/INDEX.md','stale-file report'],
|
| 551 |
+
blast:'Blast radius: a wrong index misdirects every other agent, which is why its write authority is one file. It cannot touch the facts it maps, so the map can be wrong but never self-serving.',
|
| 552 |
+
slo:['link resolution 100%',99]
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
id:'monitor', h:'@monitor', role:'Sentry', stance:'auto',
|
| 556 |
+
jtbd:'When live traffic drifts or an SLO breaches, I want the fleet degraded to human-in-the-loop in the same tick, so no bad decision ships during the window.',
|
| 557 |
+
may:['alerts/','tasks/pending/'],
|
| 558 |
+
never:["any agent's workspace"],
|
| 559 |
+
reads:['ACTIVITY.md','logs/','reports/','knowledge/INDEX.md'],
|
| 560 |
+
skills:['SLO tracking on live traffic','drift detection on decision distributions','HITL degradation broadcast','incident task authoring with evidence'],
|
| 561 |
+
tools:['latency monitor','escalation-rate monitor','ungrounded-claim monitor','drift detector','degradation switch'],
|
| 562 |
+
caps:['SLO enforcement','HITL degradation','Incident filing'],
|
| 563 |
+
out:['alerts/<ts>.md','incident tasks (P0)'],
|
| 564 |
+
blast:'Blast radius: a monitor that can degrade the fleet can halt it. It cannot read into a workspace to justify a degradation, so it must show its evidence on live traffic — every degradation is reviewable after the fact.',
|
| 565 |
+
slo:['breach → degrade < 60 s',94]
|
| 566 |
+
}
|
| 567 |
+
];
|
| 568 |
+
|
| 569 |
+
const STANCE_LABEL = {
|
| 570 |
+
auto:['autonomous','s-auto'],
|
| 571 |
+
prop:['propose-only','s-prop'],
|
| 572 |
+
hitl:['HITL-gated','s-hitl'],
|
| 573 |
+
gate:['gatekeeper','s-gate']
|
| 574 |
+
};
|
| 575 |
+
|
| 576 |
+
const PATHS = [
|
| 577 |
+
'tasks/pending/','tasks/done/',
|
| 578 |
+
'knowledge/','knowledge/INDEX.md','knowledge/_provisional.md','knowledge/_graveyard.md',
|
| 579 |
+
'knowledge/claims/','knowledge/precedent/','knowledge/products/',
|
| 580 |
+
'workspaces/@underwriter/','alerts/','reports/','ACTIVITY.md','logs/','DECISIONS.md'
|
| 581 |
+
];
|
| 582 |
+
|
| 583 |
+
const WRITE = {
|
| 584 |
+
'@orchestrator':['tasks/pending/','tasks/done/','ACTIVITY.md','logs/'],
|
| 585 |
+
'@underwriter':['workspaces/@underwriter/','tasks/pending/'],
|
| 586 |
+
'@claims-digest':['knowledge/','knowledge/claims/','knowledge/precedent/','knowledge/products/','knowledge/_provisional.md','tasks/pending/'],
|
| 587 |
+
'@compliance-auditor':['knowledge/_graveyard.md','reports/','tasks/pending/'],
|
| 588 |
+
'@indexer':['knowledge/INDEX.md'],
|
| 589 |
+
'@monitor':['alerts/','tasks/pending/'],
|
| 590 |
+
'@human':['DECISIONS.md','tasks/pending/']
|
| 591 |
+
};
|
| 592 |
+
|
| 593 |
+
const FS = [
|
| 594 |
+
{n:'/', d:0, path:'/', writers:[], note:'Shared root. No file at the root is writable by the fleet except as governed below.'},
|
| 595 |
+
{n:'tasks/', d:1, path:'tasks/', writers:['@orchestrator','@underwriter','@claims-digest','@compliance-auditor','@monitor'], note:'Contended zone — this is the fleet\'s inbox, not a lane. Serialized by @orchestrator.'},
|
| 596 |
+
{n:'pending/', d:2, path:'tasks/pending/', writers:['@orchestrator','@underwriter','@claims-digest','@compliance-auditor','@monitor'], note:'Any agent may file here; only @orchestrator moves files out. Single-writer lock per file, acquired in priority order (P0 → P3), released on RESULT.'},
|
| 597 |
+
{n:'done/', d:2, path:'tasks/done/', writers:['@orchestrator'], note:'Append-only. A task entering this directory without a RESULT block is reopened and returned to pending/ with GATE-204-NO-RESULT.'},
|
| 598 |
+
{n:'knowledge/', d:1, path:'knowledge/', writers:['@claims-digest'], note:'Durable facts. Written only by @claims-digest, only with a resolvable source per assertion. Read by the whole fleet.'},
|
| 599 |
+
{n:'INDEX.md', d:2, path:'knowledge/INDEX.md', writers:['@indexer'], note:'Regenerated from the actual tree, never hand-edited. Every link must resolve; stale files are flagged by last-touch age.'},
|
| 600 |
+
{n:'_provisional.md', d:2, path:'knowledge/_provisional.md',writers:['@claims-digest'], note:'Quarantine for unsourced or contradictory assertions. Everything here is explicitly not-yet-true, and nothing here is citable as precedent.'},
|
| 601 |
+
{n:'_graveyard.md', d:2, path:'knowledge/_graveyard.md', writers:['@compliance-auditor'], note:'Demotions only. Bad facts survive here as citable history — deletion is not among the fleet\'s verbs.'},
|
| 602 |
+
{n:'claims/', d:2, path:'knowledge/claims/', writers:['@claims-digest'], note:'One file per claim. Every fact line carries a source anchor; the header declares the contradiction count.'},
|
| 603 |
+
{n:'precedent/', d:2, path:'knowledge/precedent/', writers:['@claims-digest'], note:'Prior decisions, citable by @underwriter. Promotion from _provisional.md requires the gatekeeper\'s review.'},
|
| 604 |
+
{n:'products/', d:2, path:'knowledge/products/', writers:['@claims-digest'], note:'Appetite rulesets and product terms. Changes here move underwriting behaviour, so they are sourced like any other fact.'},
|
| 605 |
+
{n:'workspaces/', d:1, path:'workspaces/', writers:['@underwriter'], note:'Per-agent scratch space. No agent may write into another agent\'s workspace.'},
|
| 606 |
+
{n:'@underwriter/', d:2, path:'workspaces/@underwriter/', writers:['@underwriter'], note:'Where proposals live before they are filed as tasks. Readable by the auditor; never writable by anyone else.'},
|
| 607 |
+
{n:'alerts/', d:1, path:'alerts/', writers:['@monitor'], note:'SLO breach records. Each alert carries the live-traffic evidence that justified it.'},
|
| 608 |
+
{n:'reports/', d:1, path:'reports/', writers:['@compliance-auditor'], note:'Audit output. Findings here are raw material for correction tasks, never fixes.'},
|
| 609 |
+
{n:'ACTIVITY.md', d:1, path:'ACTIVITY.md', writers:['@orchestrator'], note:'Append-only dispatch ledger: lock acquired, task dispatched, lock released, escalation raised.'},
|
| 610 |
+
{n:'logs/', d:1, path:'logs/', writers:['@orchestrator'], note:'Raw run logs. Read by @monitor for drift analysis.'},
|
| 611 |
+
{n:'DECISIONS.md', d:1, path:'DECISIONS.md', writers:['@human'], note:'HUMAN ONLY. Policy bindings, contested-fact promotions, and overrides of prior decisions. No agent has write authority; the fleet may only read.'}
|
| 612 |
+
];
|
| 613 |
+
|
| 614 |
+
const MX_AGENTS = ['@orchestrator','@underwriter','@claims-digest','@compliance-auditor','@indexer','@monitor','@human'];
|
| 615 |
+
const MX = [
|
| 616 |
+
['tasks/pending/', ['W','W','W','W','R','W','W']],
|
| 617 |
+
['tasks/done/', ['W','R','R','R','R','R','R']],
|
| 618 |
+
['knowledge/ (facts)', ['R','R','W','R','R','R','R']],
|
| 619 |
+
['knowledge/INDEX.md', ['R','R','R','R','W','R','R']],
|
| 620 |
+
['knowledge/_provisional.md',['X','X','W','R','R','X','R']],
|
| 621 |
+
['knowledge/_graveyard.md', ['X','X','R','W','R','X','R']],
|
| 622 |
+
['workspaces/@underwriter/', ['R','W','X','R','X','X','R']],
|
| 623 |
+
['alerts/', ['R','X','X','R','X','W','R']],
|
| 624 |
+
['reports/', ['R','X','X','W','X','R','R']],
|
| 625 |
+
['ACTIVITY.md', ['W','X','X','R','X','R','R']],
|
| 626 |
+
['logs/', ['W','X','X','R','X','R','R']],
|
| 627 |
+
['DECISIONS.md', ['R','R','R','R','R','R','H']]
|
| 628 |
+
];
|
| 629 |
+
|
| 630 |
+
const REASON = [
|
| 631 |
+
['AUTH-200-LANE','may-touch path is inside the receiver\'s lane','validator (filing time)','accept — task is filed'],
|
| 632 |
+
['AUTH-403-LANE','path outside the receiver\'s lane','validator / dispatch','refuse at filing; on dispatch, file incident'],
|
| 633 |
+
['INFO-409-CONTENTION','shared path with more than one writer','validator','serialize via @orchestrator single-writer lock'],
|
| 634 |
+
['AUTH-451-BIND-THRESHOLD','bind action requested above the authority threshold','@underwriter self-arrest','escalate to human; recommendation only'],
|
| 635 |
+
['RULE-410-NO-DELETE','delete/remove verb requested of an ingest agent','validator','refuse; use demotion to _graveyard.md instead'],
|
| 636 |
+
['CFG-422-DONEWHEN-UNCHECKABLE','done-when has no third-party-verifiable predicate','validator','refuse; rewrite as a checkable predicate'],
|
| 637 |
+
['GATE-204-NO-RESULT','task closed without a RESULT block','auditor scan / dispatch','reopen task, return to pending/'],
|
| 638 |
+
['SRC-419-UNCITED','knowledge change without a resolvable source','@claims-digest / auditor','quarantine to _provisional.md until sourced'],
|
| 639 |
+
['AUD-409-DISPARATE','outcome delta across groups exceeds threshold','@compliance-auditor','file correction task against the owning lane'],
|
| 640 |
+
['SLO-503-DEGRADE','live-traffic SLO breach','@monitor','degrade non-human-gated agents to HITL; file P0 incident'],
|
| 641 |
+
['AUD-500-UNANCHORED','finding cannot be anchored to a file','@compliance-auditor','demote assertion to _graveyard.md']
|
| 642 |
+
];
|
| 643 |
+
|
| 644 |
+
const JOBS = [
|
| 645 |
+
{
|
| 646 |
+
id:'J1', ttl:'Place a new commercial property risk',
|
| 647 |
+
wh:'Requested by: underwriting desk · bounded by appetite ruleset',
|
| 648 |
+
chain:[
|
| 649 |
+
{k:'Job to be done',v:'When a broker submits a commercial property risk, produce a recommendation a human can bind without re-reading the file.',cls:''},
|
| 650 |
+
{k:'Capability',v:'Defensible risk selection',cls:''},
|
| 651 |
+
{k:'Skills',v:'Appetite matching · evidence citation · confidence calibration · threshold self-arrest',cls:'v'},
|
| 652 |
+
{k:'Tools',v:'policy doc store (read) · claims history query (read) · appetite ruleset v3 · reason-code taxonomy',cls:'v'},
|
| 653 |
+
{k:'Owning agent',v:'@underwriter — proposes. Inputs extracted by @claims-digest; reviewed by @compliance-auditor.',cls:''},
|
| 654 |
+
{k:'Artifact',v:'workspaces/@underwriter/UW-SUB-88213.md + a task proposal. Never a bound policy.',cls:'a'},
|
| 655 |
+
{k:'Done-when',v:'recommendation file exists · ≥3 cited sources each resolve · confidence is a number 0–1 · reason codes ⊆ taxonomy-v3 · no bind action attempted above T = 250,000',cls:'a'},
|
| 656 |
+
{k:'Human gate',v:'Binding is a human disposition in DECISIONS.md. The fleet may recommend; it may never bind.',cls:'a'}
|
| 657 |
+
]
|
| 658 |
+
},
|
| 659 |
+
{
|
| 660 |
+
id:'J2', ttl:'Digest a claim file and call transcript once',
|
| 661 |
+
wh:'Requested by: claims ops · 38-minute transcript, 240-page file',
|
| 662 |
+
chain:[
|
| 663 |
+
{k:'Job to be done',v:'When a claim file and transcript land together, extract the facts once and isolate contradictions, so adjusters stop re-deriving them.',cls:''},
|
| 664 |
+
{k:'Capability',v:'Single-pass fact extraction with contradiction isolation',cls:''},
|
| 665 |
+
{k:'Skills',v:'Transcript segmentation · source anchoring per assertion · contradiction detection · provisional-first promotion discipline',cls:'v'},
|
| 666 |
+
{k:'Tools',v:'document classifier · ASR transcript parser · OCR · entity resolver · contradiction detector',cls:'v'},
|
| 667 |
+
{k:'Owning agent',v:'@claims-digest — the only writer of knowledge/ facts.',cls:''},
|
| 668 |
+
{k:'Artifact',v:'knowledge/claims/CLM-55231.md (source-cited) · contradictions to knowledge/_provisional.md',cls:'a'},
|
| 669 |
+
{k:'Done-when',v:'every fact line carries a source anchor that resolves · contradiction count declared in the header · zero deletions',cls:'a'},
|
| 670 |
+
{k:'Human gate',v:'Contested facts leave _provisional.md only by human disposition, after the gatekeeper demotes or promotes.',cls:'a'}
|
| 671 |
+
]
|
| 672 |
+
},
|
| 673 |
+
{
|
| 674 |
+
id:'J3', ttl:'Keep the knowledge base traceable and mapped',
|
| 675 |
+
wh:'Requested by: knowledge owners · continuous',
|
| 676 |
+
chain:[
|
| 677 |
+
{k:'Job to be done',v:'When knowledge is edited, keep every assertion sourced and the map current, so decisions trace back to evidence instead of memory.',cls:''},
|
| 678 |
+
{k:'Capability',v:'Traceable, self-describing knowledge base',cls:''},
|
| 679 |
+
{k:'Skills',v:'Promotion review · source resolution on every change · link verification · staleness ageing',cls:'v'},
|
| 680 |
+
{k:'Tools',v:'diff engine · citation resolver · link checker · filesystem walker · age calculator',cls:'v'},
|
| 681 |
+
{k:'Owning agents',v:'@compliance-auditor gates promotions and proposes corrections; @indexer regenerates the map. Two agents, two files, no overlap.',cls:''},
|
| 682 |
+
{k:'Artifact',v:'reports/audit-<ts>.md · correction tasks in tasks/pending/ · knowledge/INDEX.md',cls:'a'},
|
| 683 |
+
{k:'Done-when',v:'every change cites a source that resolves · every link in INDEX.md resolves · stale files flagged with age in days',cls:'a'},
|
| 684 |
+
{k:'Human gate',v:'A correction that contradicts a prior decision is escalated, not merged.',cls:'a'}
|
| 685 |
+
]
|
| 686 |
+
},
|
| 687 |
+
{
|
| 688 |
+
id:'J4', ttl:'Contain the blast radius of a live-traffic breach',
|
| 689 |
+
wh:'Requested by: operations · fires on SLO breach',
|
| 690 |
+
chain:[
|
| 691 |
+
{k:'Job to be done',v:'When live traffic drifts or breaches an SLO, degrade the fleet to human-in-the-loop before a bad decision ships.',cls:''},
|
| 692 |
+
{k:'Capability',v:'Blast-radius containment',cls:''},
|
| 693 |
+
{k:'Skills',v:'SLO tracking on live traffic · drift detection on decision distributions · HITL degradation broadcast · incident authoring with evidence',cls:'v'},
|
| 694 |
+
{k:'Tools',v:'latency monitor · escalation-rate monitor · ungrounded-claim-rate monitor · drift detector · degradation switch',cls:'v'},
|
| 695 |
+
{k:'Owning agents',v:'@monitor detects and degrades; @orchestrator serializes the resulting incident tasks and reroutes queued work to humans.',cls:''},
|
| 696 |
+
{k:'Artifact',v:'alerts/<ts>.md + a P0 incident task in tasks/pending/',cls:'a'},
|
| 697 |
+
{k:'Done-when',v:'breach detected within 60 s · all non-human-gated agents flipped to HITL in the same tick · incident task carries a RESULT on closure',cls:'a'},
|
| 698 |
+
{k:'Human gate',v:'Re-arming autonomy after a breach is a human act. The fleet may degrade itself; it may not un-degrade itself.',cls:'a'}
|
| 699 |
+
]
|
| 700 |
+
},
|
| 701 |
+
{
|
| 702 |
+
id:'J5', ttl:'Catch disparate outcomes before a human signs',
|
| 703 |
+
wh:'Requested by: compliance · sampled over closed decisions',
|
| 704 |
+
chain:[
|
| 705 |
+
{k:'Job to be done',v:'When decisions are proposed at volume, sample them for outcome disparities so a pattern is caught before it becomes precedent.',cls:''},
|
| 706 |
+
{k:'Capability',v:'Fairness gating with no stake in the decision',cls:''},
|
| 707 |
+
{k:'Skills',v:'Sampled outcome testing · group-ratio comparison with confidence interval · reason-code distribution analysis · calibration review',cls:'v'},
|
| 708 |
+
{k:'Tools',v:'outcome sampler · group-ratio comparator with CI · reason-code distribution histogram',cls:'v'},
|
| 709 |
+
{k:'Owning agent',v:'@compliance-auditor — holds no fact-write authority, so it cannot launder what it finds.',cls:''},
|
| 710 |
+
{k:'Artifact',v:'reports/audit-<ts>.md + a correction task against the owning lane',cls:'a'},
|
| 711 |
+
{k:'Done-when',v:'sample n ≥ 200 per group · delta reported with a confidence interval · if delta > 0.05, correction task filed citing the specific decisions',cls:'a'},
|
| 712 |
+
{k:'Human gate',v:'A correction that changes how a lane decides is escalated to a human owner, not applied.',cls:'a'}
|
| 713 |
+
]
|
| 714 |
+
}
|
| 715 |
+
];
|
| 716 |
+
|
| 717 |
+
const SEED = [
|
| 718 |
+
{id:'T-1041',from:'@orchestrator',to:'@underwriter',pri:'P1',
|
| 719 |
+
goal:'Draft UW recommendation for submission SUB-88213 (commercial property, TIV 4.2M)',
|
| 720 |
+
may:['workspaces/@underwriter/'],
|
| 721 |
+
done:['workspaces/@underwriter/UW-SUB-88213.md exists','≥3 cited sources each resolve','confidence is a number 0-1','reason codes ⊆ taxonomy-v3'],lock:false},
|
| 722 |
+
{id:'T-1042',from:'@orchestrator',to:'@claims-digest',pri:'P1',
|
| 723 |
+
goal:'Digest claim CLM-55231 (water damage) file + 38-min call transcript',
|
| 724 |
+
may:['knowledge/claims/','knowledge/_provisional.md'],
|
| 725 |
+
done:['every fact line carries a resolvable source anchor','contradiction count declared in header','zero deletions performed'],lock:false},
|
| 726 |
+
{id:'T-1043',from:'@compliance-auditor',to:'@claims-digest',pri:'P2',
|
| 727 |
+
goal:'Re-source 2 uncited facts in knowledge/claims/CLM-54880.md',
|
| 728 |
+
may:['knowledge/claims/'],
|
| 729 |
+
done:['both facts carry anchors that resolve'],lock:false},
|
| 730 |
+
{id:'T-1044',from:'@monitor',to:'@indexer',pri:'P2',
|
| 731 |
+
goal:'Rebuild INDEX after 6 knowledge writes; flag files untouched > 90 days',
|
| 732 |
+
may:['knowledge/INDEX.md'],
|
| 733 |
+
done:['INDEX regenerated from the actual tree','all links resolve','stale list emitted with ages in days'],lock:true},
|
| 734 |
+
{id:'T-1045',from:'@underwriter',to:'@underwriter',pri:'P0',
|
| 735 |
+
goal:'Bind policy POL-77120 for 1,400,000 and write the binding to the decision log',
|
| 736 |
+
may:['DECISIONS.md'],
|
| 737 |
+
done:['policy bound','DECISIONS.md updated'],rogue:true},
|
| 738 |
+
{id:'T-1046',from:'@orchestrator',to:'@claims-digest',pri:'P3',
|
| 739 |
+
goal:'Close digest for CLM-55012',
|
| 740 |
+
may:['knowledge/claims/'],
|
| 741 |
+
done:['file marked complete'],noResult:true}
|
| 742 |
+
];
|
| 743 |
+
|
| 744 |
+
/* ============================================================
|
| 745 |
+
STATE
|
| 746 |
+
============================================================ */
|
| 747 |
+
const S = {
|
| 748 |
+
queue: SEED.map(t=>Object.assign({},t)),
|
| 749 |
+
running:[], done:[], blocked:[],
|
| 750 |
+
log:[], degraded:false, findings:[], nextId:1047, timer:null, cursor:0, seq:[]
|
| 751 |
+
};
|
| 752 |
+
|
| 753 |
+
/* ============================================================
|
| 754 |
+
HELPERS
|
| 755 |
+
============================================================ */
|
| 756 |
+
const $ = s=>document.querySelector(s);
|
| 757 |
+
const $$ = s=>Array.prototype.slice.call(document.querySelectorAll(s));
|
| 758 |
+
function esc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
|
| 759 |
+
function toast(m){const t=$('#toast');t.textContent=m;t.classList.add('on');clearTimeout(t._t);t._t=setTimeout(()=>t.classList.remove('on'),2100);}
|
| 760 |
+
function clock(){const d=new Date();return d.toTimeString().slice(0,8);}
|
| 761 |
+
function logln(cls,msg){S.log.push({t:clock(),cls:cls,msg:msg});renderConsole();}
|
| 762 |
+
function priRank(p){return {'P0':0,'P1':1,'P2':2,'P3':3}[p]??9;}
|
| 763 |
+
function agent(id){return AGENTS.find(a=>a.h===id)||null;}
|
| 764 |
+
|
| 765 |
+
function renderConsole(){
|
| 766 |
+
const c=$('#console');
|
| 767 |
+
c.innerHTML = S.log.map(l=>'<div><span class="t">'+l.t+'</span> '+(l.cls?'<span class="'+l.cls+'">'+esc(l.msg)+'</span>':esc(l.msg))+'</div>').join('') || '<div class="t">// ACTIVITY.md empty — run the dispatch</div>';
|
| 768 |
+
c.scrollTop = c.scrollHeight;
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
/* ============================================================
|
| 772 |
+
NAV
|
| 773 |
+
============================================================ */
|
| 774 |
+
function go(v){
|
| 775 |
+
$$('#nav button').forEach(b=>b.classList.toggle('on',b.dataset.v===v));
|
| 776 |
+
$$('.view').forEach(s=>s.classList.toggle('on',s.id==='v-'+v));
|
| 777 |
+
window.scrollTo({top:0,behavior:'smooth'});
|
| 778 |
+
}
|
| 779 |
+
$$('#nav button').forEach(b=>b.addEventListener('click',()=>go(b.dataset.v)));
|
| 780 |
+
|
| 781 |
+
/* ============================================================
|
| 782 |
+
FLEET VIEW
|
| 783 |
+
============================================================ */
|
| 784 |
+
function stanceOf(a){
|
| 785 |
+
if(S.degraded && a.stance==='auto') return ['HITL (degraded)','s-hitl'];
|
| 786 |
+
if(S.degraded && a.stance==='prop') return ['HITL (degraded)','s-hitl'];
|
| 787 |
+
return STANCE_LABEL[a.stance];
|
| 788 |
+
}
|
| 789 |
+
function renderFleet(filter){
|
| 790 |
+
const q=(filter||'').trim().toLowerCase();
|
| 791 |
+
const list=AGENTS.filter(a=>!q || [a.h,a.role,a.jtbd].concat(a.skills,a.tools,a.caps).join(' ').toLowerCase().includes(q));
|
| 792 |
+
$('#agentGrid').innerHTML = list.map(a=>{
|
| 793 |
+
const st=stanceOf(a);
|
| 794 |
+
return '<div class="card acard" data-a="'+a.id+'">'
|
| 795 |
+
+ '<div class="top"><div><div class="handle">'+a.h+'</div><div class="role">'+a.role+'</div></div>'
|
| 796 |
+
+ '<span class="stance '+st[1]+'">'+st[0]+'</span></div>'
|
| 797 |
+
+ '<div class="jtbd">'+a.jtbd.slice(0,140)+(a.jtbd.length>140?'…':'')+'</div>'
|
| 798 |
+
+ '<div class="lbl">may write</div><div class="chips">'+a.may.map(m=>'<span class="chip w">'+esc(m)+'</span>').join('')+'</div>'
|
| 799 |
+
+ '<div class="lbl">never</div><div class="chips">'+a.never.map(m=>'<span class="chip n">'+esc(m)+'</span>').join('')+'</div>'
|
| 800 |
+
+ '<div class="lbl">lane health</div><div class="meter"><i style="width:'+a.slo[1]+'%;background:linear-gradient(90deg,#2dd4bf,#34d399)"></i></div>'
|
| 801 |
+
+ '<div class="dim mono" style="font-size:10px;margin-top:5px">'+esc(a.slo[0])+'</div>'
|
| 802 |
+
+ '</div>';
|
| 803 |
+
}).join('') || '<div class="card dim mono">no agent matches that filter</div>';
|
| 804 |
+
$('#searchCount').textContent='showing '+list.length+' of '+AGENTS.length;
|
| 805 |
+
$$('#agentGrid .acard').forEach(c=>c.addEventListener('click',()=>openDrawer(c.dataset.a)));
|
| 806 |
+
}
|
| 807 |
+
$('#search').addEventListener('input',e=>renderFleet(e.target.value));
|
| 808 |
+
|
| 809 |
+
function openDrawer(id){
|
| 810 |
+
const a=agent('@'+id);
|
| 811 |
+
const st=stanceOf(a);
|
| 812 |
+
$('#drawer').innerHTML =
|
| 813 |
+
'<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:12px">'
|
| 814 |
+
+'<div><div class="mono" style="font-size:17px;font-weight:650;color:var(--teal)">'+a.h+'</div>'
|
| 815 |
+
+'<div class="mono dim" style="font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;margin-top:2px">'+a.role+'</div></div>'
|
| 816 |
+
+'<span class="stance '+st[1]+'">'+st[0]+'</span></div>'
|
| 817 |
+
+'<div class="card" style="margin-top:14px;background:var(--panel2)"><div class="lbl" style="margin-top:0">job to be done</div><div style="font-size:12.8px;color:var(--ink)">'+a.jtbd+'</div></div>'
|
| 818 |
+
+'<div class="lbl">write lane (may touch)</div><div class="chips">'+a.may.map(m=>'<span class="chip w">'+esc(m)+'</span>').join('')+'</div>'
|
| 819 |
+
+'<div class="lbl">never touches</div><div class="chips">'+a.never.map(m=>'<span class="chip n">'+esc(m)+'</span>').join('')+'</div>'
|
| 820 |
+
+'<div class="lbl">readable to it</div><div class="chips">'+a.reads.map(m=>'<span class="chip">'+esc(m)+'</span>').join('')+'</div>'
|
| 821 |
+
+'<div class="lbl">capabilities</div><div class="chips">'+a.caps.map(m=>'<span class="chip v">'+esc(m)+'</span>').join('')+'</div>'
|
| 822 |
+
+'<div class="lbl">skills</div><ul class="tight">'+a.skills.map(m=>'<li>'+esc(m)+'</li>').join('')+'</ul>'
|
| 823 |
+
+'<div class="lbl">tools</div><ul class="tight">'+a.tools.map(m=>'<li>'+esc(m)+'</li>').join('')+'</ul>'
|
| 824 |
+
+'<div class="lbl">artifacts it produces</div><div class="chips">'+a.out.map(m=>'<span class="chip a">'+esc(m)+'</span>').join('')+'</div>'
|
| 825 |
+
+'<div class="lbl">blast radius</div><div class="note" style="margin-top:2px">'+a.blast+'</div>'
|
| 826 |
+
+'<div class="lbl">SLO</div><div class="mono mut" style="font-size:11.5px">'+esc(a.slo[0])+'</div>'
|
| 827 |
+
+'<div class="flexrow" style="margin-top:16px"><button class="primary" data-compose="'+a.h+'">Compose a task for '+a.h+'</button>'
|
| 828 |
+
+'<button data-golane="'+a.h+'">See its lane in the tree</button></div>';
|
| 829 |
+
$('#drawer').classList.add('on'); $('#scrim').classList.add('on');
|
| 830 |
+
const cb=$('#drawer [data-compose]');
|
| 831 |
+
if(cb) cb.addEventListener('click',()=>{closeDrawer();go('compose');$('#f-to').value=a.h;syncPaths();validate();});
|
| 832 |
+
const gb=$('#drawer [data-golane]');
|
| 833 |
+
if(gb) gb.addEventListener('click',()=>{closeDrawer();go('fs');const p=a.may[0];selectPath(p);});
|
| 834 |
+
}
|
| 835 |
+
function closeDrawer(){$('#drawer').classList.remove('on');$('#scrim').classList.remove('on');}
|
| 836 |
+
$('#scrim').addEventListener('click',closeDrawer);
|
| 837 |
+
document.addEventListener('keydown',e=>{if(e.key==='Escape')closeDrawer();});
|
| 838 |
+
|
| 839 |
+
/* ============================================================
|
| 840 |
+
FILESYSTEM VIEW
|
| 841 |
+
============================================================ */
|
| 842 |
+
function writersOf(path){
|
| 843 |
+
const node=FS.find(f=>f.path===path);
|
| 844 |
+
if(node&&node.writers&&node.writers.length) return node.writers;
|
| 845 |
+
// fall back: prefix match
|
| 846 |
+
const out=new Set();
|
| 847 |
+
Object.keys(WRITE).forEach(k=>WRITE[k].forEach(w=>{if(path.indexOf(w)===0||w.indexOf(path)===0) out.add(k);}));
|
| 848 |
+
return Array.from(out);
|
| 849 |
+
}
|
| 850 |
+
function isContended(path){
|
| 851 |
+
const w=FS.find(f=>f.path===path);
|
| 852 |
+
if(!w) return false;
|
| 853 |
+
return w.path==='tasks/pending/'||w.path==='tasks/';
|
| 854 |
+
}
|
| 855 |
+
function renderFS(){
|
| 856 |
+
$('#fsTree').innerHTML = FS.map(f=>{
|
| 857 |
+
const w=f.writers&&f.writers.length?f.writers:[];
|
| 858 |
+
const cont=isContended(f.path);
|
| 859 |
+
const chips = f.writers&&f.writers.length
|
| 860 |
+
? (f.writers.length>1
|
| 861 |
+
? f.writers.map(x=>'<span class="chip '+(x==='@human'?'':'w')+'" style="'+(x==='@human'?'color:var(--pink);border-color:rgba(244,114,182,.35);background:rgba(244,114,182,.07)':'')+'">'+esc(x)+'</span>').join('')
|
| 862 |
+
: f.writers.map(x=>'<span class="chip '+(x==='@human'?'':'w')+'" style="'+(x==='@human'?'color:var(--pink);border-color:rgba(244,114,182,.35);background:rgba(244,114,182,.07)':'')+'">W '+esc(x)+'</span>').join(''))
|
| 863 |
+
: '<span class="chip">no writer</span>';
|
| 864 |
+
return '<div class="fsrow" data-p="'+esc(f.path)+'">'
|
| 865 |
+
+'<span style="width:'+(f.d*15)+'px"></span>'
|
| 866 |
+
+'<span class="nm">'+(f.d===0?'/':esc(f.n))+'</span>'
|
| 867 |
+
+ (cont?'<span class="lock">⚠ contended</span>':'')
|
| 868 |
+
+ (f.path==='DECISIONS.md'?'<span class="lock" style="color:var(--pink)">human only</span>':'')
|
| 869 |
+
+'<span class="own">'+chips+'</span></div>';
|
| 870 |
+
}).join('');
|
| 871 |
+
$$('#fsTree .fsrow').forEach(r=>r.addEventListener('click',()=>selectPath(r.dataset.p)));
|
| 872 |
+
}
|
| 873 |
+
function selectPath(p){
|
| 874 |
+
$$('#fsTree .fsrow').forEach(r=>r.classList.toggle('on',r.dataset.p===p));
|
| 875 |
+
const f=FS.find(x=>x.path===p)||{path:p,note:'—',writers:[]};
|
| 876 |
+
const w=f.writers||[];
|
| 877 |
+
const readers = MX_AGENTS.filter(a=>{const row=MX.find(m=>m[0].toLowerCase().indexOf(p.split('/')[0])===0);return false;});
|
| 878 |
+
const cont=isContended(p);
|
| 879 |
+
$('#pathDetail').innerHTML =
|
| 880 |
+
'<div class="mono" style="font-size:13px;color:var(--teal)">'+esc(f.path)+'</div>'
|
| 881 |
+
+'<div class="note" style="margin:10px 0 14px">'+esc(f.note)+'</div>'
|
| 882 |
+
+'<div class="lbl" style="margin-top:0">write authority</div><div class="chips">'
|
| 883 |
+
+(w.length?w.map(x=>'<span class="chip '+(x==='@human'?'':'w')+'" style="'+(x==='@human'?'color:var(--pink);border-color:rgba(244,114,182,.35);background:rgba(244,114,182,.07)':'')+'">'+esc(x)+'</span>').join(''):'<span class="chip">none</span>')
|
| 884 |
+
+'</div>'
|
| 885 |
+
+'<div class="lbl">concurrency rule</div><div class="mono" style="font-size:11.5px;color:'+(cont?'var(--amber)':'var(--green)')+'">'
|
| 886 |
+
+ (cont?'serialized — single-writer lock, @orchestrator holds the queue':'partitioned — exactly one lane owner, no lock needed')
|
| 887 |
+
+'</div>'
|
| 888 |
+
+ (f.path==='DECISIONS.md'?'<div class="note" style="border-color:var(--pink)">Write authority is a human. The fleet reads this file as ground truth for precedent; it can never extend it. This single asymmetry is what keeps every other agent safely autonomous.</div>':'')
|
| 889 |
+
+'<div class="lbl">if this lane is violated</div><div class="mono mut" style="font-size:11.5px">AUTH-403-LANE → refused at filing; on dispatch the task is blocked and @monitor files a P0 incident.</div>';
|
| 890 |
+
}
|
| 891 |
+
function renderMatrix(){
|
| 892 |
+
let h='<thead><tr><th style="text-align:left">path</th>'+MX_AGENTS.map(a=>'<th>'+esc(a.replace('@','@'))+'</th>').join('')+'</tr></thead><tbody>';
|
| 893 |
+
MX.forEach(row=>{
|
| 894 |
+
h+='<tr><td class="path" data-p="'+esc(row[0])+'">'+esc(row[0])+'</td>';
|
| 895 |
+
row[1].forEach((c,i)=>{
|
| 896 |
+
const cls=c==='W'?'W':c==='H'?'H':c==='R'?'R':'X';
|
| 897 |
+
h+='<td class="p '+cls+'" data-p="'+esc(row[0])+'" data-a="'+esc(MX_AGENTS[i])+'">'+(c==='X'?'—':c)+'</td>';
|
| 898 |
+
});
|
| 899 |
+
h+='</tr>';
|
| 900 |
+
});
|
| 901 |
+
h+='</tbody>';
|
| 902 |
+
$('#matrix').innerHTML=h;
|
| 903 |
+
$$('#matrix td.p').forEach(td=>td.addEventListener('click',e=>{
|
| 904 |
+
const p=td.dataset.p, a=td.dataset.a;
|
| 905 |
+
toast(a+' · '+p+' · '+describeCell(p,a,td.textContent.trim()));
|
| 906 |
+
}));
|
| 907 |
+
$$('#matrix td.path').forEach(td=>td.addEventListener('click',()=>{go('fs');selectPath(matchPath(td.dataset.p));}));
|
| 908 |
+
}
|
| 909 |
+
function matchPath(label){
|
| 910 |
+
if(label.indexOf('tasks/pending')===0) return 'tasks/pending/';
|
| 911 |
+
if(label.indexOf('tasks/done')===0) return 'tasks/done/';
|
| 912 |
+
if(label.indexOf('knowledge/ (facts)')===0) return 'knowledge/';
|
| 913 |
+
if(label.indexOf('workspaces')===0) return 'workspaces/@underwriter/';
|
| 914 |
+
if(label.indexOf('knowledge/')===0) return label;
|
| 915 |
+
return label;
|
| 916 |
+
}
|
| 917 |
+
function describeCell(p,a,v){
|
| 918 |
+
if(v==='—') return 'no access — '+a+' cannot read or write here';
|
| 919 |
+
if(v==='H') return 'human disposition only — '+a+' is the human';
|
| 920 |
+
if(v==='W') return 'lane owner — sole writer';
|
| 921 |
+
return 'read-only — never writes here';
|
| 922 |
+
}
|
| 923 |
+
function renderReason(){
|
| 924 |
+
$('#rcTable').innerHTML = REASON.map(r=>'<tr><td style="text-align:left"><b style="color:var(--teal)">'+esc(r[0])+'</b></td><td style="text-align:left">'+esc(r[1])+'</td><td style="text-align:left" class="mut">'+esc(r[2])+'</td><td style="text-align:left" class="mut">'+esc(r[3])+'</td></tr>').join('');
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
/* ============================================================
|
| 928 |
+
COMPOSE VIEW
|
| 929 |
+
============================================================ */
|
| 930 |
+
function fillSelects(){
|
| 931 |
+
const opts=AGENTS.map(a=>'<option value="'+a.h+'">'+a.h+' — '+a.role.replace(/&/g,'&')+'</option>').join('')+'<option value="@human">@human — disposition only</option>';
|
| 932 |
+
$('#f-from').innerHTML=opts; $('#f-to').innerHTML=opts;
|
| 933 |
+
$('#f-from').value='@orchestrator'; $('#f-to').value='@underwriter';
|
| 934 |
+
$('#pathPick').innerHTML = PATHS.map(p=>'<label data-p="'+esc(p)+'"><input type="checkbox" value="'+esc(p)+'">'+esc(p)+'</label>').join('');
|
| 935 |
+
$$('#pathPick input').forEach(cb=>cb.addEventListener('change',()=>{cb.parentElement.classList.toggle('sel',cb.checked);validate();}));
|
| 936 |
+
}
|
| 937 |
+
function selectedPaths(){return $$('#pathPick input:checked').map(cb=>cb.value);}
|
| 938 |
+
function syncPaths(){
|
| 939 |
+
const to=$('#f-to').value, allow=WRITE[to]||[];
|
| 940 |
+
$$('#pathPick input').forEach(cb=>{
|
| 941 |
+
const inside=allow.some(w=>cb.value.indexOf(w)===0||w.indexOf(cb.value)===0);
|
| 942 |
+
cb.checked=inside;
|
| 943 |
+
cb.parentElement.classList.toggle('sel',inside);
|
| 944 |
+
});
|
| 945 |
+
}
|
| 946 |
+
function checkable(line){
|
| 947 |
+
return /(\d|exists|resolve|resolves|return|returns|equal|equals|match|matches|declare|declared|emit|emitted|regenerat|contains|present|is a|are |≥|≤|>|<|count|within|zero|all |every |both )/i.test(line);
|
| 948 |
+
}
|
| 949 |
+
function validate(){
|
| 950 |
+
const from=$('#f-from').value, to=$('#f-to').value;
|
| 951 |
+
const goal=$('#f-goal').value.trim(), inputs=$('#f-inputs').value.trim();
|
| 952 |
+
const paths=selectedPaths(), done=$('#f-done').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
| 953 |
+
const blocking=[], warn=[], info=[], pass=[];
|
| 954 |
+
const allow=WRITE[to]||[];
|
| 955 |
+
|
| 956 |
+
if(!goal){blocking.push(['CFG-400-NO-GOAL','goal is empty — a task without a goal is a rumour']);}
|
| 957 |
+
if(!inputs){warn.push(['CFG-401-NO-INPUTS','no inputs declared — the receiver will read whatever it likes']);}
|
| 958 |
+
if(!paths.length){blocking.push(['CFG-402-NO-MAYTOUCH','may-touch is empty — the receiver has no legal place to write']);}
|
| 959 |
+
if(!done.length){blocking.push(['CFG-422-DONEWHEN-UNCHECKABLE','done-when is empty — nothing can be accepted or rejected']);}
|
| 960 |
+
|
| 961 |
+
// authority
|
| 962 |
+
paths.forEach(p=>{
|
| 963 |
+
const inside=allow.some(w=>p.indexOf(w)===0||w.indexOf(p)===0);
|
| 964 |
+
if(inside) pass.push(['AUTH-200-LANE', p+' is inside '+to+"'s lane"]);
|
| 965 |
+
else blocking.push(['AUTH-403-LANE', p+' is outside '+to+"'s lane (lane = "+(allow.join(', ')||'none')+')']);
|
| 966 |
+
});
|
| 967 |
+
|
| 968 |
+
// contention note
|
| 969 |
+
if(paths.some(p=>p==='tasks/pending/'||p==='tasks/')){
|
| 970 |
+
info.push(['INFO-409-CONTENTION','tasks/pending/ has multiple writers — @orchestrator will serialize with a single-writer lock']);
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
// hard rules
|
| 974 |
+
if(to==='@underwriter' && /\bbind\b/i.test(goal)){
|
| 975 |
+
const m=goal.replace(/,/g,'').match(/(\d{4,})/);
|
| 976 |
+
const amt=m?parseInt(m[1],10):0;
|
| 977 |
+
if(amt>250000) blocking.push(['AUTH-451-BIND-THRESHOLD','bind action of '+amt.toLocaleString()+' exceeds the authority threshold (250,000) — @underwriter may only recommend']);
|
| 978 |
+
else warn.push(['AUTH-451-BIND-THRESHOLD','bind verb present — even below threshold, binding is a human disposition']);
|
| 979 |
+
}
|
| 980 |
+
if(to==='@compliance-auditor' && paths.some(p=>p==='knowledge/'||/^knowledge\/(claims|precedent|products)\//.test(p))){
|
| 981 |
+
blocking.push(['AUTH-403-LANE','@compliance-auditor holds no fact-write authority — corrections must be filed as new tasks, not edits']);
|
| 982 |
+
}
|
| 983 |
+
if(to==='@orchestrator' && paths.some(p=>p==='knowledge/')){
|
| 984 |
+
blocking.push(['AUTH-403-LANE','@orchestrator never writes knowledge/ file bodies']);
|
| 985 |
+
}
|
| 986 |
+
if(to==='@monitor' && paths.some(p=>/^workspaces\//.test(p))){
|
| 987 |
+
blocking.push(['AUTH-403-LANE',"@monitor never writes any agent's workspace"]);
|
| 988 |
+
}
|
| 989 |
+
if(to==='@indexer' && paths.some(p=>p!=='knowledge/INDEX.md')){
|
| 990 |
+
blocking.push(['AUTH-403-LANE','@indexer writes exactly one file: knowledge/INDEX.md']);
|
| 991 |
+
}
|
| 992 |
+
if(from==='@indexer'){
|
| 993 |
+
blocking.push(['AUTH-403-LANE','@indexer cannot file tasks — it has no write authority over tasks/pending/']);
|
| 994 |
+
}
|
| 995 |
+
if(to==='@claims-digest' && /\b(delete|deleting|remove|removing|purge|drop)\b/i.test(goal)){
|
| 996 |
+
blocking.push(['RULE-410-NO-DELETE','deletion is not among the fleet\'s verbs — demote to _graveyard.md instead']);
|
| 997 |
+
}
|
| 998 |
+
|
| 999 |
+
// done-when checkability
|
| 1000 |
+
done.forEach((d,i)=>{
|
| 1001 |
+
if(checkable(d)) pass.push(['AUD-200-CHECKABLE','done-when['+(i+1)+'] is third-party verifiable']);
|
| 1002 |
+
else warn.push(['CFG-422-DONEWHEN-UNCHECKABLE','done-when['+(i+1)+'] "'+d+'" has no verifiable predicate — rewrite for a third party']);
|
| 1003 |
+
});
|
| 1004 |
+
|
| 1005 |
+
// degraded posture
|
| 1006 |
+
if(S.degraded){
|
| 1007 |
+
warn.push(['SLO-503-DEGRADE','fleet is degraded to HITL — '+(to==='@human'?'this task is':'tasks to '+to+' will be')+' held for human review']);
|
| 1008 |
+
}
|
| 1009 |
+
|
| 1010 |
+
const all=blocking.concat(warn,info,pass);
|
| 1011 |
+
$('#verdict').innerHTML = all.length? all.map(v=>{
|
| 1012 |
+
const kind = blocking.indexOf(v)>=0?'block':warn.indexOf(v)>=0?'warn':info.indexOf(v)>=0?'info':'pass';
|
| 1013 |
+
return '<div class="vline '+kind+'"><b>'+esc(v[0])+'</b><span>'+esc(v[1])+'</span></div>';
|
| 1014 |
+
}).join('') : '<div class="dim mono" style="font-size:12px">awaiting fields…</div>';
|
| 1015 |
+
|
| 1016 |
+
$('#mdOut').textContent = taskMarkdown();
|
| 1017 |
+
return {blocking,warn,info,pass};
|
| 1018 |
+
}
|
| 1019 |
+
function taskMarkdown(){
|
| 1020 |
+
const id='T-'+(S.nextId);
|
| 1021 |
+
const from=$('#f-from').value, to=$('#f-to').value;
|
| 1022 |
+
const goal=$('#f-goal').value.trim()||'(goal unfilled)';
|
| 1023 |
+
const inputs=$('#f-inputs').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
| 1024 |
+
const paths=selectedPaths();
|
| 1025 |
+
const done=$('#f-done').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
| 1026 |
+
const pri=$('#f-pri').value;
|
| 1027 |
+
return [
|
| 1028 |
+
'---',
|
| 1029 |
+
'id: '+id,
|
| 1030 |
+
'from: '+from,
|
| 1031 |
+
'to: '+to,
|
| 1032 |
+
'priority: '+pri,
|
| 1033 |
+
'status: pending',
|
| 1034 |
+
'---',
|
| 1035 |
+
'',
|
| 1036 |
+
'## goal',
|
| 1037 |
+
goal,
|
| 1038 |
+
'',
|
| 1039 |
+
'## inputs',
|
| 1040 |
+
inputs.length?inputs.map(i=>'- '+i).join('\n'):'- (none declared)',
|
| 1041 |
+
'',
|
| 1042 |
+
'## may-touch',
|
| 1043 |
+
paths.length?paths.map(p=>'- '+p).join('\n'):'- (none — delegation is impossible)',
|
| 1044 |
+
'',
|
| 1045 |
+
'## done-when',
|
| 1046 |
+
done.length?done.map((d,i)=>(i+1)+'. [ ] '+d).join('\n'):'1. [ ] (unfilled — not third-party verifiable)',
|
| 1047 |
+
'',
|
| 1048 |
+
'## RESULT',
|
| 1049 |
+
'(filled on completion, before the file moves pending/ → done/)',
|
| 1050 |
+
'result: ',
|
| 1051 |
+
'evidence: ',
|
| 1052 |
+
'closed_by: ',
|
| 1053 |
+
'closed_at: '
|
| 1054 |
+
].join('\n');
|
| 1055 |
+
}
|
| 1056 |
+
$('#f-from').addEventListener('change',validate);
|
| 1057 |
+
$('#f-to').addEventListener('change',()=>{syncPaths();validate();});
|
| 1058 |
+
['#f-goal','#f-inputs','#f-done','#f-pri'].forEach(s=>$(s).addEventListener('input',validate));
|
| 1059 |
+
['#f-goal','#f-inputs','#f-done','#f-pri'].forEach(s=>$(s).addEventListener('change',validate));
|
| 1060 |
+
$('#btnValidate').addEventListener('click',()=>{validate();toast('re-validated');});
|
| 1061 |
+
$('#btnClear').addEventListener('click',()=>{
|
| 1062 |
+
$('#f-goal').value='';$('#f-inputs').value='';$('#f-done').value='';
|
| 1063 |
+
$('#f-from').value='@orchestrator';$('#f-to').value='@underwriter';$('#f-pri').value='P1';
|
| 1064 |
+
syncPaths();validate();
|
| 1065 |
+
});
|
| 1066 |
+
$('#btnCopy').addEventListener('click',()=>{
|
| 1067 |
+
const txt=$('#mdOut').textContent;
|
| 1068 |
+
if(navigator.clipboard&&navigator.clipboard.writeText){
|
| 1069 |
+
navigator.clipboard.writeText(txt).then(()=>toast('task contract copied'),()=>toast('copy blocked — select the text instead'));
|
| 1070 |
+
} else { toast('copy unavailable — select the text instead'); }
|
| 1071 |
+
});
|
| 1072 |
+
$('#btnFile').addEventListener('click',()=>{
|
| 1073 |
+
const v=validate();
|
| 1074 |
+
if(v.blocking.length){
|
| 1075 |
+
toast('refused: '+v.blocking[0][0]);
|
| 1076 |
+
logln('r','[compose] refused '+v.blocking[0][0]+' — '+v.blocking[0][1]);
|
| 1077 |
+
return;
|
| 1078 |
+
}
|
| 1079 |
+
const goal=$('#f-goal').value.trim();
|
| 1080 |
+
const t={
|
| 1081 |
+
id:'T-'+(S.nextId++), from:$('#f-from').value, to:$('#f-to').value, pri:$('#f-pri').value,
|
| 1082 |
+
goal:goal, may:selectedPaths(), done:$('#f-done').value.split('\n').map(s=>s.trim()).filter(Boolean),
|
| 1083 |
+
lock: selectedPaths().some(p=>p==='tasks/pending/')
|
| 1084 |
+
};
|
| 1085 |
+
S.queue.push(t);
|
| 1086 |
+
logln('g','[file] '+t.id+' → '+t.to+' · '+t.goal.slice(0,64));
|
| 1087 |
+
toast(t.id+' filed to tasks/pending/');
|
| 1088 |
+
renderFlow(); updateHead();
|
| 1089 |
+
go('flow');
|
| 1090 |
+
});
|
| 1091 |
+
function prefillFromJob(job){
|
| 1092 |
+
go('compose');
|
| 1093 |
+
$('#f-from').value='@orchestrator';
|
| 1094 |
+
const to = job.id==='J4' ? '@monitor' : job.id==='J5'||job.id==='J3' ? '@compliance-auditor' : job.id==='J2' ? '@claims-digest' : '@underwriter';
|
| 1095 |
+
$('#f-to').value=to;
|
| 1096 |
+
$('#f-goal').value=job.chain[0].v.length>120? job.chain[0].v.slice(0,120):job.chain[0].v;
|
| 1097 |
+
const inputs=job.chain[3].v.split(' · ').join('\n');
|
| 1098 |
+
$('#f-inputs').value=inputs;
|
| 1099 |
+
const dw=job.chain[6].v.split(' · ').join('\n');
|
| 1100 |
+
$('#f-done').value=dw;
|
| 1101 |
+
syncPaths(); validate();
|
| 1102 |
+
toast('composed from '+job.id+' — '+(to));
|
| 1103 |
+
}
|
| 1104 |
+
|
| 1105 |
+
/* ============================================================
|
| 1106 |
+
FLOW / DISPATCH
|
| 1107 |
+
============================================================ */
|
| 1108 |
+
function tkHTML(t,mode){
|
| 1109 |
+
const cls = mode==='block'?' blocked':mode==='done'?' done':mode==='reopen'?' reopen':'';
|
| 1110 |
+
return '<div class="tk'+cls+'">'
|
| 1111 |
+
+'<div class="row" style="justify-content:space-between"><span class="id">'+esc(t.id)+'</span><span class="pri '+t.pri.toLowerCase()+'">'+t.pri+'</span></div>'
|
| 1112 |
+
+'<div class="gl">'+esc(t.goal)+'</div>'
|
| 1113 |
+
+'<div class="row"><span class="chip">'+esc(t.from)+'</span><span class="dim" style="font-size:11px">→</span><span class="chip '+(t.to==='@human'?'':'w')+'">'+esc(t.to)+'</span></div>'
|
| 1114 |
+
+'<div class="row" style="margin-top:6px">'+t.may.map(m=>'<span class="chip w" style="font-size:9.5px">'+esc(m)+'</span>').join('')+'</div>'
|
| 1115 |
+
+(mode==='done'?'<div class="mono" style="font-size:10px;color:var(--green);margin-top:6px">RESULT: filled · evidence attached</div>':'')
|
| 1116 |
+
+(mode==='reopen'?'<div class="mono" style="font-size:10px;color:var(--amber);margin-top:6px">GATE-204-NO-RESULT → reopened</div>':'')
|
| 1117 |
+
+(mode==='block'?'<div class="mono" style="font-size:10px;color:var(--red);margin-top:6px">'+esc(t._code||'AUTH-403-LANE')+'</div>':'')
|
| 1118 |
+
+'</div>';
|
| 1119 |
+
}
|
| 1120 |
+
function renderFlow(){
|
| 1121 |
+
$('#colPending').innerHTML = S.queue.length? S.queue.map(t=>tkHTML(t,'')).join('') : '<div class="dim mono" style="font-size:11.5px">queue empty</div>';
|
| 1122 |
+
$('#colRunning').innerHTML = S.running.length? S.running.map(t=>tkHTML(t,'')).join('') : '<div class="dim mono" style="font-size:11.5px">no locks held</div>';
|
| 1123 |
+
$('#colDone').innerHTML = S.done.length? S.done.map(t=>tkHTML(t,'done')).join('') : '<div class="dim mono" style="font-size:11.5px">nothing closed</div>';
|
| 1124 |
+
$('#colBlock').innerHTML = S.blocked.length? S.blocked.map(t=>tkHTML(t,t._reopen?'reopen':'block')).join('') : '<div class="dim mono" style="font-size:11.5px">nothing refused</div>';
|
| 1125 |
+
$('#cPend').textContent=S.queue.length; $('#cRun').textContent=S.running.length;
|
| 1126 |
+
$('#cDone').textContent=S.done.length; $('#cBlock').textContent=S.blocked.length;
|
| 1127 |
+
updateHead();
|
| 1128 |
+
}
|
| 1129 |
+
function updateHead(){
|
| 1130 |
+
$('#hQueue').textContent='queue '+S.queue.length;
|
| 1131 |
+
$('#hBlocked').textContent='blocked '+S.blocked.filter(t=>!t._reopen).length;
|
| 1132 |
+
$('#hPosture').textContent=S.degraded?'DEGRADED · HITL':'AUTONOMOUS';
|
| 1133 |
+
$('#hPosture').className='pill '+(S.degraded?'bad':'ok');
|
| 1134 |
+
}
|
| 1135 |
+
function resetBoard(){
|
| 1136 |
+
clearInterval(S.timer); S.timer=null; S.cursor=0;
|
| 1137 |
+
S.queue=SEED.map(t=>Object.assign({},t)); S.running=[]; S.done=[]; S.blocked=[]; S.log=[];
|
| 1138 |
+
$('#flowStatus').textContent='idle'; $('#btnRun').disabled=false; $('#btnStep').disabled=false;
|
| 1139 |
+
renderConsole(); renderFlow();
|
| 1140 |
+
logln('b','[board] reset — INDEX read, queue reloaded ('+S.queue.length+' tasks)');
|
| 1141 |
+
}
|
| 1142 |
+
function stepOnce(){
|
| 1143 |
+
if(!S.seq.length||S.cursor>=S.seq.length){
|
| 1144 |
+
if(!S.seq.length){ S.seq=[]; }
|
| 1145 |
+
}
|
| 1146 |
+
if(!S.queue.length && !S.running.length){ endRun(); return false; }
|
| 1147 |
+
// order queue like the orchestrator would
|
| 1148 |
+
S.queue.sort((a,b)=>priRank(a.pri)-priRank(b.pri)||a.id.localeCompare(b.id));
|
| 1149 |
+
const t=S.queue.shift();
|
| 1150 |
+
if(!t){ endRun(); return false; }
|
| 1151 |
+
|
| 1152 |
+
logln('t','[orchestrator] reading knowledge/INDEX.md … tree hash ok, '+S.queue.length+' tasks queued');
|
| 1153 |
+
|
| 1154 |
+
// contention / lock
|
| 1155 |
+
if(t.may.some(p=>p==='tasks/pending/')||t.lock){
|
| 1156 |
+
logln('b','[lock] '+t.id+' acquiring single-writer lock on tasks/pending/ … held by @orchestrator');
|
| 1157 |
+
}
|
| 1158 |
+
|
| 1159 |
+
// authority check
|
| 1160 |
+
const allow=WRITE[t.to]||[];
|
| 1161 |
+
const bad=t.may.filter(p=>!allow.some(w=>p.indexOf(w)===0||w.indexOf(p)===0));
|
| 1162 |
+
if(bad.length){
|
| 1163 |
+
t._code='AUTH-403-LANE';
|
| 1164 |
+
if(/\bbind\b/i.test(t.goal)&&t.to==='@underwriter') t._code='AUTH-451-BIND-THRESHOLD';
|
| 1165 |
+
S.blocked.push(t);
|
| 1166 |
+
logln('r','[refused] '+t.id+' → '+t.to+' · '+t._code+' — '+(bad[0]||'bind above threshold'));
|
| 1167 |
+
logln('v','[@compliance-auditor] refused task is out-of-lane → @monitor filing incident');
|
| 1168 |
+
const inc={id:'T-'+(S.nextId++),from:'@monitor',to:'@orchestrator',pri:'P0',
|
| 1169 |
+
goal:'INCIDENT: lane violation attempted by '+t.from+' on '+bad[0]+' — review authority config',
|
| 1170 |
+
may:['alerts/','tasks/pending/'],done:['incident alert written to alerts/','incident task carries a RESULT on closure']};
|
| 1171 |
+
S.queue.push(inc);
|
| 1172 |
+
logln('a','[incident] '+inc.id+' filed (P0) — fleet posture unchanged, offender lane untouched');
|
| 1173 |
+
renderFlow(); return true;
|
| 1174 |
+
}
|
| 1175 |
+
|
| 1176 |
+
// dispatch
|
| 1177 |
+
S.running.push(t);
|
| 1178 |
+
renderFlow();
|
| 1179 |
+
logln('g','[dispatch] '+t.id+' → '+t.to+' · lock held · lane ['+t.may.join(', ')+']');
|
| 1180 |
+
|
| 1181 |
+
// immediate completion within the tick (simulated)
|
| 1182 |
+
setTimeout(()=>{
|
| 1183 |
+
S.running=S.running.filter(x=>x.id!==t.id);
|
| 1184 |
+
if(S.degraded){
|
| 1185 |
+
t.to='@human';
|
| 1186 |
+
S.blocked.push(t);
|
| 1187 |
+
logln('a','[SLO-503-DEGRADE] '+t.id+' held for human review — fleet is degraded');
|
| 1188 |
+
} else if(t.noResult){
|
| 1189 |
+
t._reopen=true; t._code='GATE-204-NO-RESULT';
|
| 1190 |
+
S.blocked.push(t);
|
| 1191 |
+
logln('a','[gate] '+t.id+' closed without a RESULT block → GATE-204-NO-RESULT');
|
| 1192 |
+
logln('g','[gate] '+t.id+' reopened and returned to tasks/pending/');
|
| 1193 |
+
const back=Object.assign({},t); delete back._reopen; delete back._code;
|
| 1194 |
+
S.queue.push(back);
|
| 1195 |
+
} else {
|
| 1196 |
+
S.done.push(t);
|
| 1197 |
+
logln('g','[done] '+t.id+' RESULT filled by '+t.to+' → moved pending/ → done/');
|
| 1198 |
+
}
|
| 1199 |
+
logln('b','[lock] '+t.id+' released tasks/pending/');
|
| 1200 |
+
logln('t','[@compliance-auditor] sampling '+t.id+' done-when against evidence — '+(t.done?t.done.length:'0')+' predicates');
|
| 1201 |
+
renderFlow();
|
| 1202 |
+
if(!S.queue.length && !S.running.length) endRun();
|
| 1203 |
+
},420);
|
| 1204 |
+
return true;
|
| 1205 |
+
}
|
| 1206 |
+
function endRun(){
|
| 1207 |
+
clearInterval(S.timer); S.timer=null;
|
| 1208 |
+
$('#flowStatus').textContent='complete';
|
| 1209 |
+
$('#btnRun').disabled=false; $('#btnStep').disabled=false;
|
| 1210 |
+
logln('t','[orchestrator] dispatch complete — pending '+S.queue.length+' · done '+S.done.length+' · refused/reopened '+S.blocked.length);
|
| 1211 |
+
toast('dispatch complete');
|
| 1212 |
+
}
|
| 1213 |
+
$('#btnStep').addEventListener('click',()=>{
|
| 1214 |
+
if(S.timer) return;
|
| 1215 |
+
logln('b','[step] manual advance');
|
| 1216 |
+
if(!stepOnce()) endRun();
|
| 1217 |
+
});
|
| 1218 |
+
$('#btnRun').addEventListener('click',()=>{
|
| 1219 |
+
if(S.timer){clearInterval(S.timer);S.timer=null;$('#flowStatus').textContent='paused';$('#btnRun').disabled=false;return;}
|
| 1220 |
+
$('#btnRun').disabled=true; $('#btnStep').disabled=true; $('#flowStatus').textContent='running…';
|
| 1221 |
+
clearInterval(S.timer);
|
| 1222 |
+
S.timer=setInterval(()=>{ if(!stepOnce()) clearInterval(S.timer); },760);
|
| 1223 |
+
});
|
| 1224 |
+
$('#btnReset').addEventListener('click',resetBoard);
|
| 1225 |
+
|
| 1226 |
+
/* ============================================================
|
| 1227 |
+
DEGRADE / RECOVER
|
| 1228 |
+
============================================================ */
|
| 1229 |
+
$('#btnDegrade').addEventListener('click',()=>{
|
| 1230 |
+
S.degraded=!S.degraded;
|
| 1231 |
+
$('#btnDegrade').textContent=S.degraded?'Re-arm autonomy (human act)':'Simulate SLO breach';
|
| 1232 |
+
if(S.degraded){
|
| 1233 |
+
logln('r','[@monitor] SLO-503-DEGRADE — ungrounded-claim rate 3.1% > SLO 1.5% (5-min window)');
|
| 1234 |
+
logln('a','[@monitor] degradation broadcast: @underwriter, @claims-digest, @indexer, @orchestrator → HITL');
|
| 1235 |
+
logln('v','[@monitor] incident task filed (P0) with live-traffic evidence attached');
|
| 1236 |
+
const inc={id:'T-'+(S.nextId++),from:'@monitor',to:'@orchestrator',pri:'P0',
|
| 1237 |
+
goal:'INCIDENT: ungrounded-claim rate breached SLO — fleet degraded to HITL, review calibration',
|
| 1238 |
+
may:['alerts/'],done:['alert written to alerts/ with evidence','re-arm decision recorded by a human']};
|
| 1239 |
+
S.queue.push(inc);
|
| 1240 |
+
} else {
|
| 1241 |
+
logln('g','[@human] re-arming autonomy — recorded in DECISIONS.md (no agent may un-degrade itself)');
|
| 1242 |
+
}
|
| 1243 |
+
renderFleet($('#search').value); renderFlow(); validate();
|
| 1244 |
+
});
|
| 1245 |
+
|
| 1246 |
+
/* ============================================================
|
| 1247 |
+
JTBD VIEW
|
| 1248 |
+
============================================================ */
|
| 1249 |
+
function renderJobs(active){
|
| 1250 |
+
$('#jobList').innerHTML = JOBS.map(j=>
|
| 1251 |
+
'<div class="job'+(active===j.id?' on':'')+'" data-j="'+j.id+'"><div class="ttl">'+esc(j.ttl)+'</div><div class="wh">'+j.wh+'</div></div>'
|
| 1252 |
+
).join('');
|
| 1253 |
+
$$('#jobList .job').forEach(el=>el.addEventListener('click',()=>{renderJobs(el.dataset.j);renderChain(el.dataset.j);}));
|
| 1254 |
+
}
|
| 1255 |
+
function renderChain(id){
|
| 1256 |
+
const j=JOBS.find(x=>x.id===id); if(!j) return;
|
| 1257 |
+
$('#chainWrap').innerHTML = j.chain.map(s=>
|
| 1258 |
+
'<div class="stage '+s.cls+'"><div class="sbox"><div class="sk">'+esc(s.k)+'</div><div class="sv">'+s.v+'</div></div></div>'
|
| 1259 |
+
).join('');
|
| 1260 |
+
$('#chainActions').innerHTML='<button class="primary" data-prefill="'+j.id+'">Compose this as a task contract →</button>';
|
| 1261 |
+
$$('#chainActions button').forEach(b=>b.addEventListener('click',()=>prefillFromJob(JOBS.find(x=>x.id===b.dataset.prefill))));
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
/* ============================================================
|
| 1265 |
+
AUDIT VIEW
|
| 1266 |
+
============================================================ */
|
| 1267 |
+
function addFinding(code,txt,target,goal){
|
| 1268 |
+
S.findings.push({code,code2:txt,to:target,goal});
|
| 1269 |
+
renderFindings();
|
| 1270 |
+
}
|
| 1271 |
+
function renderFindings(){
|
| 1272 |
+
if(!S.findings.length){$('#findings').innerHTML='<div class="dim mono" style="font-size:12px">no open findings</div>';return;}
|
| 1273 |
+
$('#findings').innerHTML = S.findings.map((f,i)=>
|
| 1274 |
+
'<div class="vline '+(f.code==='GATE-204-NO-RESULT'?'warn':'info')+'" style="align-items:center"><b>'+esc(f.code)+'</b>'
|
| 1275 |
+
+'<span style="flex:1">'+esc(f.code2)+' <span class="dim mono" style="font-size:10.5px">→ '+esc(f.to)+'</span></span>'
|
| 1276 |
+
+'<button class="sm" data-file="'+i+'">file correction task</button></div>'
|
| 1277 |
+
).join('');
|
| 1278 |
+
$$('#findings [data-file]').forEach(b=>b.addEventListener('click',()=>{
|
| 1279 |
+
const f=S.findings[parseInt(b.dataset.file,10)];
|
| 1280 |
+
const t={id:'T-'+(S.nextId++),from:'@compliance-auditor',to:f.to,pri:'P1',goal:f.goal,
|
| 1281 |
+
may:WRITE[f.to].filter(p=>p!=='tasks/pending/').slice(0,2),
|
| 1282 |
+
done:['cited evidence attached to the correction','the owning lane writes the fix — the auditor does not']};
|
| 1283 |
+
S.queue.push(t);
|
| 1284 |
+
logln('v','[@compliance-auditor] correction filed → '+t.id+' to '+t.to+' · '+f.code);
|
| 1285 |
+
S.findings.splice(parseInt(b.dataset.file,10),1);
|
| 1286 |
+
renderFindings(); renderFlow(); toast(t.id+' filed — the lane owner must fix it');
|
| 1287 |
+
}));
|
| 1288 |
+
}
|
| 1289 |
+
$$('[data-check]').forEach(b=>b.addEventListener('click',()=>{
|
| 1290 |
+
const k=b.dataset.check;
|
| 1291 |
+
if(k==='result'){
|
| 1292 |
+
const closedNoResult = S.blocked.filter(t=>t._reopen).length;
|
| 1293 |
+
const closedOk = S.done.length;
|
| 1294 |
+
$('#ck-result').innerHTML =
|
| 1295 |
+
'<div class="vline '+(closedNoResult?'warn':'pass')+'"><b>'+(closedNoResult?'GATE-204-NO-RESULT':'AUD-200-PASS')+'</b><span>'+closedNoResult+' task(s) closed without a RESULT block; '+closedOk+' closed with evidence</span></div>'
|
| 1296 |
+
+'<div class="mono dim" style="font-size:11px">scan: tasks/done/ × RESULT presence · invariant N4</div>';
|
| 1297 |
+
if(closedNoResult) addFinding('GATE-204-NO-RESULT',closedNoResult+' task(s) closed without a RESULT block','@orchestrator','Reopen tasks closed without a RESULT block and enforce the RESULT gate at close time');
|
| 1298 |
+
}
|
| 1299 |
+
if(k==='cite'){
|
| 1300 |
+
$('#ck-cite').innerHTML =
|
| 1301 |
+
'<div class="vline warn"><b>SRC-419-UNCITED</b><span>2 assertions in knowledge/claims/CLM-54880.md carry no resolvable source anchor</span></div>'
|
| 1302 |
+
+'<div class="vline info"><b>disposition</b><span>quarantine to _provisional.md until sourced — no deletion, no silent repair</span></div>'
|
| 1303 |
+
+'<div class="mono dim" style="font-size:11px">scan: every knowledge/ change × citation resolution · invariant N3</div>';
|
| 1304 |
+
addFinding('SRC-419-UNCITED','2 uncited assertions in knowledge/claims/CLM-54880.md','@claims-digest','Re-source the 2 uncited assertions in knowledge/claims/CLM-54880.md, or move them to _provisional.md');
|
| 1305 |
+
}
|
| 1306 |
+
if(k==='fair'){
|
| 1307 |
+
$('#ck-fair').innerHTML =
|
| 1308 |
+
'<div class="vline info"><b>AUD-409-DISPARATE</b><span>sample n=1,240 closed decisions · approval ratio 0.71 vs 0.63 · Δ = 0.08 [0.04, 0.12]</span></div>'
|
| 1309 |
+
+'<div class="vline warn"><b>threshold</b><span>Δ 0.08 > 0.05 — reason-code distribution shows 3× "R-17 collateral condition" on the lower group</span></div>'
|
| 1310 |
+
+'<div class="mono dim" style="font-size:11px">scan: sampled outcomes × group ratio with CI · correction leaves as a task, never as an edit</div>';
|
| 1311 |
+
addFinding('AUD-409-DISPARATE','Approval-ratio delta 0.08 (CI 0.04–0.12) concentrated on reason code R-17','@underwriter','Review the R-17 collateral-condition rule for disparate impact across groups; attach the sampled decision list as evidence');
|
| 1312 |
+
}
|
| 1313 |
+
toast('check complete — findings leave as tasks');
|
| 1314 |
+
}));
|
| 1315 |
+
|
| 1316 |
+
/* ============================================================
|
| 1317 |
+
BOOT
|
| 1318 |
+
============================================================ */
|
| 1319 |
+
fillSelects();
|
| 1320 |
+
renderFleet('');
|
| 1321 |
+
renderFS();
|
| 1322 |
+
renderMatrix();
|
| 1323 |
+
renderReason();
|
| 1324 |
+
renderJobs('J1');
|
| 1325 |
+
renderChain('J1');
|
| 1326 |
+
selectPath('tasks/pending/');
|
| 1327 |
+
renderConsole();
|
| 1328 |
+
renderFlow();
|
| 1329 |
+
syncPaths();
|
| 1330 |
+
validate();
|
| 1331 |
+
logln('b','[board] boot — INDEX read, '+S.queue.length+' tasks in queue, 6 lanes registered');
|
| 1332 |
+
logln('t','[@orchestrator] roster loaded: write authority scoped per lane; no lock is needed where a lane is a name');
|
| 1333 |
+
updateHead();
|
| 1334 |
+
</script>
|
| 1335 |
+
</body>
|
| 1336 |
</html>
|
| 1337 |
+
<script data-huggingchat-badge="script">
|
| 1338 |
+
(function () {
|
| 1339 |
+
try {
|
| 1340 |
+
if (document.querySelector("[data-huggingchat-badge]:not(script)")) return;
|
| 1341 |
+
var host = document.createElement("div");
|
| 1342 |
+
host.setAttribute("data-huggingchat-badge", "");
|
| 1343 |
+
var styles = [["all","initial"],["position","fixed"],["right","12px"],["bottom","12px"],["z-index","2147483647"],["display","block"],["visibility","visible"],["opacity","1"],["pointer-events","auto"],["width","auto"],["height","auto"],["margin","0"],["padding","0"],["max-width","none"],["max-height","none"],["transform","none"],["filter","none"],["clip-path","none"],["color-scheme","light"]];
|
| 1344 |
+
for (var i = 0; i < styles.length; i++) {
|
| 1345 |
+
host.style.setProperty(styles[i][0], styles[i][1], "important");
|
| 1346 |
+
}
|
| 1347 |
+
host.attachShadow({ mode: "closed" }).innerHTML = "<style>\n:host { all: initial; }\na {\n display: flex;\n align-items: center;\n gap: 5px;\n box-sizing: border-box;\n height: 26px;\n padding: 0 9px 0 7px;\n border-radius: 999px;\n border: 1px solid rgba(0, 0, 0, 0.07);\n background: rgba(255, 255, 255, 0.92);\n -webkit-backdrop-filter: saturate(180%) blur(8px);\n backdrop-filter: saturate(180%) blur(8px);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 6px 16px rgba(0, 0, 0, 0.06);\n color: #111827;\n font: 500 11px/1 ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n text-decoration: none;\n white-space: nowrap;\n opacity: 0.72;\n transition: opacity 0.15s ease, transform 0.15s ease;\n}\na:hover, a:focus-visible { opacity: 1; transform: translateY(-1px); }\nsvg { width: 14px; height: 14px; flex: none; }\n@media print { a { display: none; } }\n<\/style><a href=\"https://huggingface.co/chat\" target=\"_blank\" rel=\"noopener noreferrer nofollow\"><svg viewBox=\"0 0 32 32\" fill=\"none\" aria-hidden=\"true\"><path d=\"M16.0006 25.9992C13.8266 25.999 11.7118 25.2901 9.97686 23.9799C8.2419 22.6698 6.98127 20.8298 6.38599 18.7388C5.79071 16.6478 5.89323 14.4198 6.678 12.3923C7.46278 10.3648 8.88705 8.64837 10.735 7.50308C12.5829 6.35779 14.7538 5.84606 16.9187 6.04544C19.0837 6.24481 21.1246 7.14442 22.7323 8.60795C24.34 10.0715 25.4268 12.0192 25.8281 14.1559C26.2293 16.2926 25.9232 18.5019 24.9561 20.449C24.7703 20.8042 24.7223 21.2155 24.8211 21.604L25.4211 23.8316C25.4803 24.0518 25.4805 24.2837 25.4216 24.5039C25.3627 24.7242 25.2468 24.925 25.0856 25.0862C24.9244 25.2474 24.7235 25.3633 24.5033 25.4222C24.283 25.4811 24.0512 25.4809 23.831 25.4217L21.6034 24.8217C21.2172 24.7248 20.809 24.7729 20.4558 24.9567C19.0683 25.6467 17.5457 26.0068 16.0006 26.0068V25.9992Z\" fill=\"currentColor\"/><path d=\"M9.62598 16.0013C9.62598 15.3799 10.1294 14.8765 10.7508 14.8765C11.3721 14.8765 11.8756 15.3799 11.8756 16.0013C11.8756 17.0953 12.3102 18.1448 13.0838 18.9184C13.8574 19.692 14.9069 20.1266 16.001 20.1267C17.095 20.1267 18.1445 19.692 18.9181 18.9184C19.6918 18.1448 20.1264 17.0953 20.1264 16.0013C20.1264 15.3799 20.6299 14.8765 21.2512 14.8765C21.8725 14.8765 22.3759 15.3799 22.3759 16.0013C22.3759 17.6921 21.7046 19.3137 20.509 20.5093C19.3134 21.7049 17.6918 22.3762 16.001 22.3762C14.3102 22.3762 12.6885 21.7049 11.4929 20.5093C10.2974 19.3137 9.62598 17.6921 9.62598 16.0013Z\" fill=\"#fff\"/><\/svg><span>Made with HuggingChat<\/span><\/a>";
|
| 1348 |
+
function attach() {
|
| 1349 |
+
var parent = document.body || document.documentElement;
|
| 1350 |
+
if (parent && host.parentNode !== parent) parent.appendChild(host);
|
| 1351 |
+
}
|
| 1352 |
+
attach();
|
| 1353 |
+
// Artifacts that rewrite document.body wholesale would drop the badge.
|
| 1354 |
+
if (document.body && typeof MutationObserver === "function") {
|
| 1355 |
+
new MutationObserver(attach).observe(document.body, { childList: true });
|
| 1356 |
+
} else {
|
| 1357 |
+
document.addEventListener("DOMContentLoaded", attach);
|
| 1358 |
+
}
|
| 1359 |
+
} catch (e) {}
|
| 1360 |
+
})();
|
| 1361 |
+
</script>
|