psikosen commited on
Commit
7a54ec2
·
verified ·
1 Parent(s): 3ed2078

Update to v3: Hybrid Input Protocol, 2x browser acceleration, and visual logging

Browse files
Files changed (24) hide show
  1. .gitattributes +1 -0
  2. README.md +20 -8
  3. miniswardbower/artifacts/complex_chains/chain1_ecommerce_receipt.png +0 -0
  4. miniswardbower/artifacts/complex_chains/chain2_etl_dispatched.png +0 -0
  5. miniswardbower/artifacts/complex_chains/chain3_spatial_approved.png +0 -0
  6. miniswardbower/artifacts/complex_chains_report.json +35 -0
  7. miniswardbower/artifacts/extended_browser_suite_report.json +110 -110
  8. miniswardbower/artifacts/frontier_experiments_report.json +30 -0
  9. miniswardbower/artifacts/live_web_report.json +14 -0
  10. miniswardbower/artifacts/live_web_screenshots/live_hackernews_audit.png +3 -0
  11. miniswardbower/artifacts/trajectories/20260905_201655/index.html +207 -0
  12. miniswardbower/artifacts/trajectories/20260905_201655/step_01_01_goto.png +0 -0
  13. miniswardbower/artifacts/trajectories/20260905_201655/step_02_01_type.png +0 -0
  14. miniswardbower/artifacts/trajectories/20260905_201655/step_02_02_type.png +0 -0
  15. miniswardbower/artifacts/trajectories/20260905_201655/step_02_03_type.png +0 -0
  16. miniswardbower/artifacts/trajectories/20260905_201655/step_02_04_click.png +0 -0
  17. miniswardbower/artifacts/v3_capabilities_report.json +5 -5
  18. miniswardbower/artifacts/v3_screenshots/step_01_open_modal.png +0 -0
  19. miniswardbower/evals/experiment_next_frontier.py +230 -0
  20. miniswardbower/evals/test_chained_complex_actions.py +305 -0
  21. miniswardbower/evals/test_live_web.py +161 -0
  22. miniswardbower/miniswardbower/browser/action_executor.py +32 -0
  23. miniswardbower/miniswardbower/browser/controller.py +65 -0
  24. miniswardbower/miniswardbower/evals/mock_web_env.py +271 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ miniswardbower/artifacts/live_web_screenshots/live_hackernews_audit.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -51,14 +51,26 @@ v3 introduces the **Hybrid Input Protocol** and **Event-Driven DOM Synchronizati
51
 
52
  | Test Scenario | Modality | v2 Latency | v3 Latency | Latency Reduction | Speedup |
53
  | :--- | :--- | :---: | :---: | :---: | :---: |
54
- | **1. Dropdowns & Multi-Select** | 3 Selects + 1 Button Click | 434.6 ms | **418.0 ms** | -16.6 ms | **1.04x** |
55
- | **2. Modal Dialog Overlays** | Open Modal + Email Entry + Save | 1,893.8 ms | **563.9 ms** | -1,329.9 ms | **3.36x** |
56
- | **3. Paginated Data Tables** | Next Page + Row Approve Action | 499.6 ms | **434.4 ms** | -65.2 ms | **1.15x** |
57
- | **4. Infinite Scroll Hydration** | Wheel Scroll + Checkpoint Ack | 1,484.0 ms | **1,016.7 ms** | -467.3 ms | **1.46x** |
58
- | **5. Radio & Checkbox Toggles** | Radio Sel + Webhook Check + Save | 935.7 ms | **766.1 ms** | -169.6 ms | **1.22x** |
59
- | **6. Autocomplete & Typeahead** | Stream Search + Suggestion Click | 715.6 ms | **465.1 ms** | -250.5 ms | **1.54x** |
60
- | **7. Multi-Step Form Wizard** | 2-Stage Multi-Field Flow + Finish | 2,381.4 ms | **466.1 ms** | -1,915.3 ms | **5.11x (500%+)** |
61
- | **Cumulative Battery Total** | **7 Scenarios / 20 Actions** | **8,344.6 ms** | **4,130.3 ms** | **-4,214.3 ms** | **2.02x FASTER** |
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  ---
64
 
 
51
 
52
  | Test Scenario | Modality | v2 Latency | v3 Latency | Latency Reduction | Speedup |
53
  | :--- | :--- | :---: | :---: | :---: | :---: |
54
+ | **1. Dropdowns & Multi-Select** | 3 Selects + 1 Button Click | 434.6 ms | **375.0 ms** | -59.6 ms | **1.16x** |
55
+ | **2. Modal Dialog Overlays** | Open Modal + Email Entry + Save | 1,893.8 ms | **497.1 ms** | -1,396.7 ms | **3.81x** |
56
+ | **3. Paginated Data Tables** | Next Page + Row Approve Action | 499.6 ms | **433.1 ms** | -66.5 ms | **1.15x** |
57
+ | **4. Infinite Scroll Hydration** | Wheel Scroll + Checkpoint Ack | 1,484.0 ms | **984.1 ms** | -499.9 ms | **1.51x** |
58
+ | **5. Radio & Checkbox Toggles** | Radio Sel + Webhook Check + Save | 935.7 ms | **749.9 ms** | -185.8 ms | **1.25x** |
59
+ | **6. Autocomplete & Typeahead** | Stream Search + Suggestion Click | 715.6 ms | **465.6 ms** | -250.0 ms | **1.54x** |
60
+ | **7. Multi-Step Form Wizard** | 2-Stage Multi-Field Flow + Finish | 2,381.4 ms | **433.3 ms** | -1,948.1 ms | **5.50x (550%+)** |
61
+ | **Cumulative Battery Total** | **7 Scenarios / 20 Actions** | **8,344.6 ms** | **3,938.1 ms** | **-4,406.5 ms** | **2.12x FASTER** |
62
+
63
+ ---
64
+
65
+ ## Complex Chained Actions Benchmark (Multi-Stage Orchestration)
66
+
67
+ | Chained Complex Action Scenario | Total Actions | Execution Latency | Verdict |
68
+ | :--- | :---: | :---: | :---: |
69
+ | **Chain 1: E-Commerce Multi-Stage Cart & Checkout** | 12 actions across 3 stages | **1,774.4 ms** | **✓ PASS** |
70
+ | **Chain 2: ETL Bulk Filter & Modal Dispatch** | 7 actions | **1,313.8 ms** | **✓ PASS** |
71
+ | **Chain 3: Spatial Grounding & Dynamic Extraction** | 4 actions | **453.0 ms** | **✓ PASS** |
72
+ | **Live Public Web Navigation (Hacker News)** | Real Network | **577.7 ms** | **✓ PASS** |
73
+ | **Speculative Action Chunking Speedup** | Multi-Field Form | **1.50x Faster (224 ms vs 336 ms)** | **✓ PASS** |
74
 
75
  ---
76
 
miniswardbower/artifacts/complex_chains/chain1_ecommerce_receipt.png ADDED
miniswardbower/artifacts/complex_chains/chain2_etl_dispatched.png ADDED
miniswardbower/artifacts/complex_chains/chain3_spatial_approved.png ADDED
miniswardbower/artifacts/complex_chains_report.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "Chain 1: E-Commerce Multi-Stage Cart & Checkout",
4
+ "passed": true,
5
+ "total_ms": 1774.41,
6
+ "stages": [
7
+ [
8
+ "Stage 1: Configure & Add to Cart",
9
+ 383.6338601540774
10
+ ],
11
+ [
12
+ "Stage 2: Voucher & Checkout Open",
13
+ 676.8952731508762
14
+ ],
15
+ [
16
+ "Stage 3: Pipelined Form Submission",
17
+ 544.9664250481874
18
+ ]
19
+ ],
20
+ "order_id": "CANOPY-ORD-508829",
21
+ "screenshot": "/home/psikosen/canopy/miniswardbower/artifacts/complex_chains/chain1_ecommerce_receipt.png"
22
+ },
23
+ {
24
+ "name": "Chain 2: ETL Bulk Filter & Modal Dispatch",
25
+ "passed": true,
26
+ "total_ms": 1313.81,
27
+ "screenshot": "/home/psikosen/canopy/miniswardbower/artifacts/complex_chains/chain2_etl_dispatched.png"
28
+ },
29
+ {
30
+ "name": "Chain 3: Spatial Grounding & Table Extraction",
31
+ "passed": true,
32
+ "total_ms": 452.98,
33
+ "screenshot": "/home/psikosen/canopy/miniswardbower/artifacts/complex_chains/chain3_spatial_approved.png"
34
+ }
35
+ ]
miniswardbower/artifacts/extended_browser_suite_report.json CHANGED
@@ -1,56 +1,56 @@
1
  {
2
- "timestamp": "2026-09-05 19:02:39",
3
  "total_scenarios": 7,
4
  "passed_scenarios": 7,
5
- "cumulative_battery_time_ms": 4130.32,
6
  "scenarios": [
7
  {
8
  "scenario": "1. Dynamic Dropdowns & Selects",
9
  "passed": true,
10
- "total_time_ms": 418.03,
11
- "exec_ms": 374.54,
12
- "distill_ms": 10.9,
13
- "verify_ms": 15.49,
14
  "bottleneck": "Execution (Kinematics)",
15
  "step_count": 4,
16
  "steps": [
17
  {
18
  "op": "select",
19
  "target": "@e1",
20
- "total_ms": 31.02,
21
- "exec_ms": 24.27,
22
- "distill_ms": 2.6,
23
- "verify_ms": 4.15,
24
  "status": "success",
25
  "summary": "Executed action select"
26
  },
27
  {
28
  "op": "select",
29
  "target": "@e2",
30
- "total_ms": 9.57,
31
- "exec_ms": 2.44,
32
- "distill_ms": 1.86,
33
- "verify_ms": 5.27,
34
  "status": "success",
35
  "summary": "Executed action select"
36
  },
37
  {
38
  "op": "select",
39
  "target": "@e3",
40
- "total_ms": 9.3,
41
- "exec_ms": 2.5,
42
- "distill_ms": 3.99,
43
- "verify_ms": 2.8,
44
  "status": "success",
45
  "summary": "Executed action select"
46
  },
47
  {
48
  "op": "click",
49
  "target": "@e4",
50
- "total_ms": 351.05,
51
- "exec_ms": 345.33,
52
- "distill_ms": 2.45,
53
- "verify_ms": 3.27,
54
  "status": "success",
55
  "summary": "Executed click on @e4; URL changed: False"
56
  }
@@ -59,40 +59,40 @@
59
  {
60
  "scenario": "2. Modal Dialogs & Focus Trapping",
61
  "passed": true,
62
- "total_time_ms": 563.91,
63
- "exec_ms": 533.97,
64
- "distill_ms": 6.38,
65
- "verify_ms": 13.15,
66
  "bottleneck": "Execution (Kinematics)",
67
  "step_count": 3,
68
  "steps": [
69
  {
70
  "op": "click",
71
  "target": "@e1",
72
- "total_ms": 223.74,
73
- "exec_ms": 216.33,
74
- "distill_ms": 2.24,
75
- "verify_ms": 5.16,
76
  "status": "success",
77
  "summary": "Executed click on @e1; URL changed: False"
78
  },
79
  {
80
  "op": "type",
81
  "target": "@e2",
82
- "total_ms": 19.58,
83
- "exec_ms": 13.01,
84
- "distill_ms": 2.15,
85
- "verify_ms": 4.42,
86
  "status": "success",
87
  "summary": "Typed text into @e2"
88
  },
89
  {
90
  "op": "click",
91
  "target": "@e4",
92
- "total_ms": 310.2,
93
- "exec_ms": 304.63,
94
- "distill_ms": 1.99,
95
- "verify_ms": 3.57,
96
  "status": "success",
97
  "summary": "Executed click on @e4; URL changed: False"
98
  }
@@ -101,30 +101,30 @@
101
  {
102
  "scenario": "3. Paginated Data Tables & Actions",
103
  "passed": true,
104
- "total_time_ms": 434.37,
105
- "exec_ms": 406.83,
106
- "distill_ms": 5.34,
107
- "verify_ms": 7.89,
108
  "bottleneck": "Execution (Kinematics)",
109
  "step_count": 2,
110
  "steps": [
111
  {
112
  "op": "click",
113
  "target": "@e3",
114
- "total_ms": 221.68,
115
- "exec_ms": 215.25,
116
- "distill_ms": 2.4,
117
- "verify_ms": 4.02,
118
  "status": "success",
119
  "summary": "Executed click on @e3; URL changed: False"
120
  },
121
  {
122
  "op": "click",
123
  "target": "@e1",
124
- "total_ms": 198.4,
125
- "exec_ms": 191.58,
126
- "distill_ms": 2.94,
127
- "verify_ms": 3.87,
128
  "status": "success",
129
  "summary": "Executed click on @e1; URL changed: False"
130
  }
@@ -133,30 +133,30 @@
133
  {
134
  "scenario": "4. Infinite Scroll & Dynamic Hydration",
135
  "passed": true,
136
- "total_time_ms": 1016.67,
137
- "exec_ms": 470.56,
138
- "distill_ms": 4.5,
139
- "verify_ms": 22.12,
140
  "bottleneck": "Execution (Kinematics)",
141
  "step_count": 2,
142
  "steps": [
143
  {
144
  "op": "scroll",
145
  "target": "down",
146
- "total_ms": 146.84,
147
- "exec_ms": 126.56,
148
- "distill_ms": 2.6,
149
- "verify_ms": 17.67,
150
  "status": "success",
151
  "summary": "Executed action scroll"
152
  },
153
  {
154
  "op": "click",
155
  "target": "@e1",
156
- "total_ms": 350.35,
157
- "exec_ms": 344.0,
158
- "distill_ms": 1.9,
159
- "verify_ms": 4.45,
160
  "status": "success",
161
  "summary": "Executed click on @e1; URL changed: False"
162
  }
@@ -165,40 +165,40 @@
165
  {
166
  "scenario": "5. Radio Groups & Checkbox Toggles",
167
  "passed": true,
168
- "total_time_ms": 766.11,
169
- "exec_ms": 731.23,
170
- "distill_ms": 8.27,
171
- "verify_ms": 10.8,
172
  "bottleneck": "Execution (Kinematics)",
173
  "step_count": 3,
174
  "steps": [
175
  {
176
  "op": "click",
177
  "target": "@e2",
178
- "total_ms": 350.8,
179
- "exec_ms": 344.46,
180
- "distill_ms": 2.75,
181
- "verify_ms": 3.59,
182
  "status": "success",
183
  "summary": "Executed click on @e2; URL changed: False"
184
  },
185
  {
186
  "op": "click",
187
  "target": "@e5",
188
- "total_ms": 199.24,
189
- "exec_ms": 192.63,
190
- "distill_ms": 2.82,
191
- "verify_ms": 3.79,
192
  "status": "success",
193
  "summary": "Executed click on @e5; URL changed: False"
194
  },
195
  {
196
  "op": "click",
197
  "target": "@e7",
198
- "total_ms": 200.27,
199
- "exec_ms": 194.14,
200
- "distill_ms": 2.7,
201
- "verify_ms": 3.42,
202
  "status": "success",
203
  "summary": "Executed click on @e7; URL changed: False"
204
  }
@@ -207,30 +207,30 @@
207
  {
208
  "scenario": "6. Autocomplete & Typeahead Search",
209
  "passed": true,
210
- "total_time_ms": 465.15,
211
- "exec_ms": 236.85,
212
- "distill_ms": 3.95,
213
- "verify_ms": 7.84,
214
  "bottleneck": "Execution (Kinematics)",
215
  "step_count": 2,
216
  "steps": [
217
  {
218
  "op": "type",
219
  "target": "@e1",
220
- "total_ms": 38.73,
221
- "exec_ms": 31.76,
222
- "distill_ms": 2.31,
223
- "verify_ms": 4.66,
224
  "status": "success",
225
  "summary": "Typed text into @e1"
226
  },
227
  {
228
  "op": "click",
229
  "target": "@e2",
230
- "total_ms": 209.92,
231
- "exec_ms": 205.09,
232
- "distill_ms": 1.64,
233
- "verify_ms": 3.18,
234
  "status": "success",
235
  "summary": "Executed click on @e2; URL changed: False"
236
  }
@@ -239,50 +239,50 @@
239
  {
240
  "scenario": "7. Multi-Step Onboarding Wizard",
241
  "passed": true,
242
- "total_time_ms": 466.08,
243
- "exec_ms": 427.74,
244
- "distill_ms": 7.6,
245
- "verify_ms": 16.72,
246
  "bottleneck": "Execution (Kinematics)",
247
  "step_count": 4,
248
  "steps": [
249
  {
250
  "op": "type",
251
  "target": "@e1",
252
- "total_ms": 40.34,
253
- "exec_ms": 33.38,
254
- "distill_ms": 2.1,
255
- "verify_ms": 4.84,
256
  "status": "success",
257
  "summary": "Typed text into @e1"
258
  },
259
  {
260
  "op": "click",
261
  "target": "@e2",
262
- "total_ms": 196.88,
263
- "exec_ms": 191.05,
264
- "distill_ms": 2.05,
265
- "verify_ms": 3.78,
266
  "status": "success",
267
  "summary": "Executed click on @e2; URL changed: False"
268
  },
269
  {
270
  "op": "type",
271
  "target": "@e1",
272
- "total_ms": 15.25,
273
- "exec_ms": 8.6,
274
- "distill_ms": 1.93,
275
- "verify_ms": 4.72,
276
  "status": "success",
277
  "summary": "Typed text into @e1"
278
  },
279
  {
280
  "op": "click",
281
  "target": "@e2",
282
- "total_ms": 199.61,
283
- "exec_ms": 194.71,
284
- "distill_ms": 1.52,
285
- "verify_ms": 3.38,
286
  "status": "success",
287
  "summary": "Executed click on @e2; URL changed: False"
288
  }
 
1
  {
2
+ "timestamp": "2026-09-05 20:16:47",
3
  "total_scenarios": 7,
4
  "passed_scenarios": 7,
5
+ "cumulative_battery_time_ms": 3938.09,
6
  "scenarios": [
7
  {
8
  "scenario": "1. Dynamic Dropdowns & Selects",
9
  "passed": true,
10
+ "total_time_ms": 375.0,
11
+ "exec_ms": 316.12,
12
+ "distill_ms": 8.79,
13
+ "verify_ms": 18.9,
14
  "bottleneck": "Execution (Kinematics)",
15
  "step_count": 4,
16
  "steps": [
17
  {
18
  "op": "select",
19
  "target": "@e1",
20
+ "total_ms": 37.57,
21
+ "exec_ms": 28.79,
22
+ "distill_ms": 2.5,
23
+ "verify_ms": 6.27,
24
  "status": "success",
25
  "summary": "Executed action select"
26
  },
27
  {
28
  "op": "select",
29
  "target": "@e2",
30
+ "total_ms": 12.48,
31
+ "exec_ms": 3.17,
32
+ "distill_ms": 2.36,
33
+ "verify_ms": 6.95,
34
  "status": "success",
35
  "summary": "Executed action select"
36
  },
37
  {
38
  "op": "select",
39
  "target": "@e3",
40
+ "total_ms": 14.03,
41
+ "exec_ms": 8.41,
42
+ "distill_ms": 2.35,
43
+ "verify_ms": 3.26,
44
  "status": "success",
45
  "summary": "Executed action select"
46
  },
47
  {
48
  "op": "click",
49
  "target": "@e4",
50
+ "total_ms": 279.76,
51
+ "exec_ms": 275.75,
52
+ "distill_ms": 1.58,
53
+ "verify_ms": 2.42,
54
  "status": "success",
55
  "summary": "Executed click on @e4; URL changed: False"
56
  }
 
59
  {
60
  "scenario": "2. Modal Dialogs & Focus Trapping",
61
  "passed": true,
62
+ "total_time_ms": 497.15,
63
+ "exec_ms": 475.36,
64
+ "distill_ms": 4.27,
65
+ "verify_ms": 8.23,
66
  "bottleneck": "Execution (Kinematics)",
67
  "step_count": 3,
68
  "steps": [
69
  {
70
  "op": "click",
71
  "target": "@e1",
72
+ "total_ms": 223.02,
73
+ "exec_ms": 218.49,
74
+ "distill_ms": 1.65,
75
+ "verify_ms": 2.88,
76
  "status": "success",
77
  "summary": "Executed click on @e1; URL changed: False"
78
  },
79
  {
80
  "op": "type",
81
  "target": "@e2",
82
+ "total_ms": 12.09,
83
+ "exec_ms": 7.74,
84
+ "distill_ms": 1.26,
85
+ "verify_ms": 3.09,
86
  "status": "success",
87
  "summary": "Typed text into @e2"
88
  },
89
  {
90
  "op": "click",
91
  "target": "@e4",
92
+ "total_ms": 252.75,
93
+ "exec_ms": 249.13,
94
+ "distill_ms": 1.36,
95
+ "verify_ms": 2.26,
96
  "status": "success",
97
  "summary": "Executed click on @e4; URL changed: False"
98
  }
 
101
  {
102
  "scenario": "3. Paginated Data Tables & Actions",
103
  "passed": true,
104
+ "total_time_ms": 433.09,
105
+ "exec_ms": 415.12,
106
+ "distill_ms": 2.98,
107
+ "verify_ms": 4.1,
108
  "bottleneck": "Execution (Kinematics)",
109
  "step_count": 2,
110
  "steps": [
111
  {
112
  "op": "click",
113
  "target": "@e3",
114
+ "total_ms": 222.24,
115
+ "exec_ms": 218.83,
116
+ "distill_ms": 1.34,
117
+ "verify_ms": 2.07,
118
  "status": "success",
119
  "summary": "Executed click on @e3; URL changed: False"
120
  },
121
  {
122
  "op": "click",
123
  "target": "@e1",
124
+ "total_ms": 199.96,
125
+ "exec_ms": 196.29,
126
+ "distill_ms": 1.64,
127
+ "verify_ms": 2.03,
128
  "status": "success",
129
  "summary": "Executed click on @e1; URL changed: False"
130
  }
 
133
  {
134
  "scenario": "4. Infinite Scroll & Dynamic Hydration",
135
  "passed": true,
136
+ "total_time_ms": 984.12,
137
+ "exec_ms": 452.22,
138
+ "distill_ms": 3.79,
139
+ "verify_ms": 12.36,
140
  "bottleneck": "Execution (Kinematics)",
141
  "step_count": 2,
142
  "steps": [
143
  {
144
  "op": "scroll",
145
  "target": "down",
146
+ "total_ms": 130.38,
147
+ "exec_ms": 118.06,
148
+ "distill_ms": 2.32,
149
+ "verify_ms": 10.0,
150
  "status": "success",
151
  "summary": "Executed action scroll"
152
  },
153
  {
154
  "op": "click",
155
  "target": "@e1",
156
+ "total_ms": 338.0,
157
+ "exec_ms": 334.16,
158
+ "distill_ms": 1.47,
159
+ "verify_ms": 2.36,
160
  "status": "success",
161
  "summary": "Executed click on @e1; URL changed: False"
162
  }
 
165
  {
166
  "scenario": "5. Radio Groups & Checkbox Toggles",
167
  "passed": true,
168
+ "total_time_ms": 749.88,
169
+ "exec_ms": 728.32,
170
+ "distill_ms": 5.35,
171
+ "verify_ms": 6.28,
172
  "bottleneck": "Execution (Kinematics)",
173
  "step_count": 3,
174
  "steps": [
175
  {
176
  "op": "click",
177
  "target": "@e2",
178
+ "total_ms": 339.32,
179
+ "exec_ms": 335.54,
180
+ "distill_ms": 1.8,
181
+ "verify_ms": 1.98,
182
  "status": "success",
183
  "summary": "Executed click on @e2; URL changed: False"
184
  },
185
  {
186
  "op": "click",
187
  "target": "@e5",
188
+ "total_ms": 199.36,
189
+ "exec_ms": 195.85,
190
+ "distill_ms": 1.63,
191
+ "verify_ms": 1.88,
192
  "status": "success",
193
  "summary": "Executed click on @e5; URL changed: False"
194
  },
195
  {
196
  "op": "click",
197
  "target": "@e7",
198
+ "total_ms": 201.28,
199
+ "exec_ms": 196.93,
200
+ "distill_ms": 1.92,
201
+ "verify_ms": 2.42,
202
  "status": "success",
203
  "summary": "Executed click on @e7; URL changed: False"
204
  }
 
207
  {
208
  "scenario": "6. Autocomplete & Typeahead Search",
209
  "passed": true,
210
+ "total_time_ms": 465.55,
211
+ "exec_ms": 243.84,
212
+ "distill_ms": 2.52,
213
+ "verify_ms": 4.6,
214
  "bottleneck": "Execution (Kinematics)",
215
  "step_count": 2,
216
  "steps": [
217
  {
218
  "op": "type",
219
  "target": "@e1",
220
+ "total_ms": 24.32,
221
+ "exec_ms": 20.23,
222
+ "distill_ms": 1.35,
223
+ "verify_ms": 2.74,
224
  "status": "success",
225
  "summary": "Typed text into @e1"
226
  },
227
  {
228
  "op": "click",
229
  "target": "@e2",
230
+ "total_ms": 226.65,
231
+ "exec_ms": 223.61,
232
+ "distill_ms": 1.17,
233
+ "verify_ms": 1.86,
234
  "status": "success",
235
  "summary": "Executed click on @e2; URL changed: False"
236
  }
 
239
  {
240
  "scenario": "7. Multi-Step Onboarding Wizard",
241
  "passed": true,
242
+ "total_time_ms": 433.3,
243
+ "exec_ms": 411.47,
244
+ "distill_ms": 4.51,
245
+ "verify_ms": 8.41,
246
  "bottleneck": "Execution (Kinematics)",
247
  "step_count": 4,
248
  "steps": [
249
  {
250
  "op": "type",
251
  "target": "@e1",
252
+ "total_ms": 23.98,
253
+ "exec_ms": 20.41,
254
+ "distill_ms": 1.15,
255
+ "verify_ms": 2.42,
256
  "status": "success",
257
  "summary": "Typed text into @e1"
258
  },
259
  {
260
  "op": "click",
261
  "target": "@e2",
262
+ "total_ms": 200.23,
263
+ "exec_ms": 197.34,
264
+ "distill_ms": 1.23,
265
+ "verify_ms": 1.66,
266
  "status": "success",
267
  "summary": "Executed click on @e2; URL changed: False"
268
  },
269
  {
270
  "op": "type",
271
  "target": "@e1",
272
+ "total_ms": 7.38,
273
+ "exec_ms": 4.47,
274
+ "distill_ms": 0.96,
275
+ "verify_ms": 1.96,
276
  "status": "success",
277
  "summary": "Typed text into @e1"
278
  },
279
  {
280
  "op": "click",
281
  "target": "@e2",
282
+ "total_ms": 192.79,
283
+ "exec_ms": 189.25,
284
+ "distill_ms": 1.17,
285
+ "verify_ms": 2.37,
286
  "status": "success",
287
  "summary": "Executed click on @e2; URL changed: False"
288
  }
miniswardbower/artifacts/frontier_experiments_report.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "experiment": "Speculative Action Chunking",
4
+ "step_by_step_ms": 336.12,
5
+ "chunked_ms": 224.45,
6
+ "speedup": 1.5,
7
+ "success": true
8
+ },
9
+ {
10
+ "experiment": "Stealth Fingerprint Profile",
11
+ "fingerprint": {
12
+ "webdriver": null,
13
+ "plugins_count": 3,
14
+ "languages": [
15
+ "en-US",
16
+ "en"
17
+ ],
18
+ "has_chrome": true,
19
+ "device_memory": 8,
20
+ "hardware_concurrency": 24
21
+ },
22
+ "is_stealthy": true
23
+ },
24
+ {
25
+ "experiment": "Adaptive Recurrent Inference",
26
+ "baseline_tok_per_sec": 50.8,
27
+ "adaptive_tok_per_sec_projected": 63.3,
28
+ "potential_speedup": 1.25
29
+ }
30
+ ]
miniswardbower/artifacts/live_web_report.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "network_headers": {
3
+ "passed": true,
4
+ "rtt_ms": 340.35,
5
+ "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
6
+ "accept_language": "en-US"
7
+ },
8
+ "live_scraping": {
9
+ "passed": true,
10
+ "stories_count": 5,
11
+ "sample_title": "Private German rocket makes history, reaches orbit from European soil",
12
+ "screenshot": "/home/psikosen/canopy/miniswardbower/artifacts/live_web_screenshots/live_hackernews_audit.png"
13
+ }
14
+ }
miniswardbower/artifacts/live_web_screenshots/live_hackernews_audit.png ADDED

Git LFS Details

  • SHA256: f8654f374011c5076a3a5086a0e4dc7968c8abdf3326af7bdca36956c69ee779
  • Pointer size: 131 Bytes
  • Size of remote file: 361 kB
miniswardbower/artifacts/trajectories/20260905_201655/index.html ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.0">
6
+ <title>Visual Audit Trail - miniswardbower</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #0f172a;
10
+ --card-bg: #1e293b;
11
+ --text-main: #f8fafc;
12
+ --text-dim: #94a3b8;
13
+ --border-color: #334155;
14
+ --accent-cyan: #38bdf8;
15
+ --accent-emerald: #10b981;
16
+ }
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
19
+ background: var(--bg-color);
20
+ color: var(--text-main);
21
+ margin: 0;
22
+ padding: 30px 20px;
23
+ }
24
+ .container { max-width: 1200px; margin: 0 auto; }
25
+ header {
26
+ background: var(--card-bg);
27
+ border: 1px solid var(--border-color);
28
+ border-radius: 12px;
29
+ padding: 24px 30px;
30
+ margin-bottom: 30px;
31
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.5);
32
+ }
33
+ .status-pill {
34
+ display: inline-block;
35
+ background: #10b98125;
36
+ color: #10b981;
37
+ border: 1px solid #10b981;
38
+ font-weight: 700;
39
+ font-size: 13px;
40
+ padding: 4px 12px;
41
+ border-radius: 9999px;
42
+ text-transform: uppercase;
43
+ letter-spacing: 0.05em;
44
+ }
45
+ h1 { margin: 12px 0 8px 0; font-size: 26px; }
46
+ .objective-text { font-size: 16px; color: var(--text-dim); margin-bottom: 16px; }
47
+ .metrics-bar {
48
+ display: flex;
49
+ gap: 24px;
50
+ border-top: 1px solid var(--border-color);
51
+ padding-top: 16px;
52
+ font-size: 14px;
53
+ }
54
+ .metric-item span { color: var(--accent-cyan); font-weight: 700; }
55
+ .gallery-grid {
56
+ display: grid;
57
+ grid-template-columns: repeat(auto-fit, minmax(540px, 1fr));
58
+ gap: 24px;
59
+ }
60
+ .step-card {
61
+ background: var(--card-bg);
62
+ border: 1px solid var(--border-color);
63
+ border-radius: 10px;
64
+ overflow: hidden;
65
+ box-shadow: 0 4px 15px rgba(0,0,0,0.3);
66
+ display: flex;
67
+ flex-direction: column;
68
+ }
69
+ .card-header {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 12px;
73
+ padding: 12px 18px;
74
+ background: #182234;
75
+ border-bottom: 1px solid var(--border-color);
76
+ }
77
+ .step-badge {
78
+ background: var(--accent-cyan);
79
+ color: #0f172a;
80
+ font-weight: 800;
81
+ font-size: 12px;
82
+ padding: 2px 8px;
83
+ border-radius: 6px;
84
+ }
85
+ .action-title { font-weight: 600; font-size: 14px; flex-grow: 1; }
86
+ .coords-badge { font-size: 12px; color: var(--text-dim); }
87
+ .img-container {
88
+ position: relative;
89
+ background: #000;
90
+ width: 100%;
91
+ overflow: hidden;
92
+ }
93
+ .img-container img {
94
+ width: 100%;
95
+ height: auto;
96
+ display: block;
97
+ transition: transform 0.2s ease;
98
+ }
99
+ .card-footer {
100
+ padding: 14px 18px;
101
+ font-size: 13px;
102
+ color: var(--text-dim);
103
+ background: #182234;
104
+ border-top: 1px solid var(--border-color);
105
+ }
106
+ .outcome-text { margin: 0; }
107
+ pre.extracted-box {
108
+ background: #090d16;
109
+ padding: 14px;
110
+ border-radius: 8px;
111
+ border: 1px solid var(--border-color);
112
+ color: #38bdf8;
113
+ overflow-x: auto;
114
+ font-size: 12px;
115
+ }
116
+ </style>
117
+ </head>
118
+ <body>
119
+ <div class="container">
120
+ <header>
121
+ <span class="status-pill">VERIFIED SUCCESS</span>
122
+ <h1>🌐 miniswardbower Visual Audit Replay</h1>
123
+ <p class="objective-text"><strong>Objective:</strong> Navigate to http://127.0.0.1:8994/form and fill the authorized representative form with client info and submit</p>
124
+ <div class="metrics-bar">
125
+ <div class="metric-item">Total Time: <span>12.14s</span></div>
126
+ <div class="metric-item">Avg Step Latency: <span>3522.0ms</span></div>
127
+ <div class="metric-item">Tokens Saved: <span>3,514</span></div>
128
+ <div class="metric-item">Steps: <span>5</span></div>
129
+ </div>
130
+ </header>
131
+
132
+ <main class="gallery-grid">
133
+
134
+ <div class="step-card">
135
+ <div class="card-header">
136
+ <span class="step-badge">Step 1</span>
137
+ <span class="action-title">goto( )</span>
138
+ <span class="coords-badge">Targeted Selector</span>
139
+ </div>
140
+ <div class="img-container">
141
+ <img src="step_01_01_goto.png" alt="Step 1" loading="lazy"/>
142
+ </div>
143
+ <div class="card-footer">
144
+ <p class="outcome-text"><strong>Outcome:</strong> Navigated successfully to http://127.0.0.1:8994/form</p>
145
+ </div>
146
+ </div>
147
+
148
+ <div class="step-card">
149
+ <div class="card-header">
150
+ <span class="step-badge">Step 2</span>
151
+ <span class="action-title">type(@e1 Jane Doe)</span>
152
+ <span class="coords-badge">Targeted Selector</span>
153
+ </div>
154
+ <div class="img-container">
155
+ <img src="step_02_01_type.png" alt="Step 2" loading="lazy"/>
156
+ </div>
157
+ <div class="card-footer">
158
+ <p class="outcome-text"><strong>Outcome:</strong> Typed text into @e1</p>
159
+ </div>
160
+ </div>
161
+
162
+ <div class="step-card">
163
+ <div class="card-header">
164
+ <span class="step-badge">Step 2</span>
165
+ <span class="action-title">type(@e2 Sample Text)</span>
166
+ <span class="coords-badge">Targeted Selector</span>
167
+ </div>
168
+ <div class="img-container">
169
+ <img src="step_02_02_type.png" alt="Step 2" loading="lazy"/>
170
+ </div>
171
+ <div class="card-footer">
172
+ <p class="outcome-text"><strong>Outcome:</strong> Typed text into @e2</p>
173
+ </div>
174
+ </div>
175
+
176
+ <div class="step-card">
177
+ <div class="card-header">
178
+ <span class="step-badge">Step 2</span>
179
+ <span class="action-title">type(@e3 jane.doe@example.com)</span>
180
+ <span class="coords-badge">Targeted Selector</span>
181
+ </div>
182
+ <div class="img-container">
183
+ <img src="step_02_03_type.png" alt="Step 2" loading="lazy"/>
184
+ </div>
185
+ <div class="card-footer">
186
+ <p class="outcome-text"><strong>Outcome:</strong> Typed text into @e3</p>
187
+ </div>
188
+ </div>
189
+
190
+ <div class="step-card">
191
+ <div class="card-header">
192
+ <span class="step-badge">Step 2</span>
193
+ <span class="action-title">click(@e4 )</span>
194
+ <span class="coords-badge">Click Target: (411.7, 452.2)</span>
195
+ </div>
196
+ <div class="img-container">
197
+ <img src="step_02_04_click.png" alt="Step 2" loading="lazy"/>
198
+ </div>
199
+ <div class="card-footer">
200
+ <p class="outcome-text"><strong>Outcome:</strong> Executed click on @e4; URL changed: False</p>
201
+ </div>
202
+ </div>
203
+
204
+ </main>
205
+ </div>
206
+ </body>
207
+ </html>
miniswardbower/artifacts/trajectories/20260905_201655/step_01_01_goto.png ADDED
miniswardbower/artifacts/trajectories/20260905_201655/step_02_01_type.png ADDED
miniswardbower/artifacts/trajectories/20260905_201655/step_02_02_type.png ADDED
miniswardbower/artifacts/trajectories/20260905_201655/step_02_03_type.png ADDED
miniswardbower/artifacts/trajectories/20260905_201655/step_02_04_click.png ADDED
miniswardbower/artifacts/v3_capabilities_report.json CHANGED
@@ -2,16 +2,16 @@
2
  {
3
  "name": "Hybrid Input Protocol",
4
  "passed": true,
5
- "static_ms": 38.12,
6
- "stream_ms": 114.14,
7
  "stream_reactive_success": true
8
  },
9
  {
10
  "name": "Click Locations & Coordinate Grounding",
11
  "passed": true,
12
  "mark_click": [
13
- 365.11272975333145,
14
- 385.7683168073327
15
  ],
16
  "coord_click": [
17
  412.9765625,
@@ -39,6 +39,6 @@
39
  {
40
  "name": "Multi-Step Instruction Following",
41
  "passed": true,
42
- "total_ms": 236.26
43
  }
44
  ]
 
2
  {
3
  "name": "Hybrid Input Protocol",
4
  "passed": true,
5
+ "static_ms": 35.19,
6
+ "stream_ms": 132.88,
7
  "stream_reactive_success": true
8
  },
9
  {
10
  "name": "Click Locations & Coordinate Grounding",
11
  "passed": true,
12
  "mark_click": [
13
+ 364.8726939352632,
14
+ 386.64688392732313
15
  ],
16
  "coord_click": [
17
  412.9765625,
 
39
  {
40
  "name": "Multi-Step Instruction Following",
41
  "passed": true,
42
+ "total_ms": 233.5
43
  }
44
  ]
miniswardbower/artifacts/v3_screenshots/step_01_open_modal.png CHANGED
miniswardbower/evals/experiment_next_frontier.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Canopy & MiniswardBower: Frontier Exploration & Experimentation Suite.
4
+
5
+ Explores beyond v3 to answer: "Have we hit a ceiling, or can we get even better?"
6
+ Runs 3 concrete experiments:
7
+ 1. Speculative Action Chunking (Pipelined multi-action burst vs step-by-step)
8
+ 2. Anti-Bot Telemetry & Stealth Context Profile (Browser fingerprint analysis)
9
+ 3. Adaptive Recurrent Inference Early Exit (Profiling Canopy-258M token generation speedup)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import asyncio
15
+ import json
16
+ import math
17
+ import os
18
+ import sys
19
+ import time
20
+ from pathlib import Path
21
+ from typing import Any, Dict, List
22
+
23
+ CANOPY_ROOT = Path("/home/psikosen/canopy")
24
+ MINISWARD_ROOT = CANOPY_ROOT / "miniswardbower"
25
+ sys.path.insert(0, str(CANOPY_ROOT))
26
+ sys.path.insert(0, str(MINISWARD_ROOT))
27
+
28
+ import torch
29
+ from miniswardbower.browser.controller import BrowserController
30
+ from miniswardbower.core.config import BrowserConfig
31
+ from miniswardbower.core.schemas import ActionBatch, BrowserAction, BrowserActionType
32
+ from miniswardbower.evals.mock_web_env import MockWebEnvironment
33
+
34
+
35
+ async def experiment_speculative_action_chunking(mock_env: MockWebEnvironment, controller: BrowserController) -> Dict[str, Any]:
36
+ """Experiment 1: Measures latency of Speculative Action Chunking vs step-by-step execution."""
37
+ print("\n" + "=" * 75)
38
+ print("🔬 EXPERIMENT 1: Speculative Action Chunking (AsyncWebRL 2026)")
39
+ print("=" * 75)
40
+
41
+ # Multi-Step Form Benchmark: Contact Info & Submission
42
+ await controller.goto(mock_env.form_url)
43
+ tree = await controller.get_pruned_tree()
44
+
45
+ name_elem = next(e for e in tree.elements if "client_name" in e.selector)
46
+ id_elem = next(e for e in tree.elements if "client_id" in e.selector)
47
+ email_elem = next(e for e in tree.elements if "email" in e.selector)
48
+ submit_btn = next(e for e in tree.elements if "submit" in e.selector or e.tag == "button")
49
+
50
+ # Mode A: Step-by-Step with intermediate tree extraction (v3 Baseline)
51
+ t0 = time.perf_counter()
52
+ await controller.execute_action(BrowserAction(op=BrowserActionType.TYPE, target=name_elem.id, text="Bruce Wayne", stream_input=False), tree)
53
+ t_tree1 = await controller.get_pruned_tree()
54
+ await controller.execute_action(BrowserAction(op=BrowserActionType.TYPE, target=id_elem.id, text="881920", stream_input=False), t_tree1)
55
+ t_tree2 = await controller.get_pruned_tree()
56
+ await controller.execute_action(BrowserAction(op=BrowserActionType.TYPE, target=email_elem.id, text="bruce@wayne-enterprises.com", stream_input=False), t_tree2)
57
+ t_tree3 = await controller.get_pruned_tree()
58
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=submit_btn.id), t_tree3)
59
+ step_by_step_ms = (time.perf_counter() - t0) * 1000
60
+
61
+ # Reset page for Mode B
62
+ await controller.goto(mock_env.form_url)
63
+ tree_b = await controller.get_pruned_tree()
64
+
65
+ # Mode B: Pipelined Speculative Action Chunk (Executed in a single atomic pipelined burst)
66
+ chunk = [
67
+ BrowserAction(op=BrowserActionType.TYPE, target="input#client_name", text="Bruce Wayne", stream_input=False),
68
+ BrowserAction(op=BrowserActionType.TYPE, target="input#client_id", text="881920", stream_input=False),
69
+ BrowserAction(op=BrowserActionType.TYPE, target="input#email", text="bruce@wayne-enterprises.com", stream_input=False),
70
+ BrowserAction(op=BrowserActionType.CLICK, target="button#submit-btn"),
71
+ ]
72
+
73
+ t1 = time.perf_counter()
74
+ # Pipelined execution without artificial inter-step sleep or redundant DOM re-scans
75
+ for act in chunk:
76
+ await controller.execute_action(act)
77
+ chunked_ms = (time.perf_counter() - t1) * 1000
78
+
79
+ page_text = await controller.page.inner_text("body")
80
+ success = "Confirmation Received!" in page_text and "Bruce Wayne" in page_text
81
+
82
+ speedup = step_by_step_ms / (chunked_ms + 1e-6)
83
+ print(f" Step-by-Step Roundtrip Latency : {step_by_step_ms:6.1f} ms")
84
+ print(f" Speculative Action Chunk Latency: {chunked_ms:6.1f} ms")
85
+ print(f" Chunking Speedup Factor : {speedup:6.2f}x ({round((1 - chunked_ms / step_by_step_ms) * 100, 1)}% faster)")
86
+ print(f" Task Success Verified : {success}")
87
+
88
+ return {
89
+ "experiment": "Speculative Action Chunking",
90
+ "step_by_step_ms": round(step_by_step_ms, 2),
91
+ "chunked_ms": round(chunked_ms, 2),
92
+ "speedup": round(speedup, 2),
93
+ "success": success,
94
+ }
95
+
96
+
97
+ async def experiment_stealth_fingerprinting(controller: BrowserController) -> Dict[str, Any]:
98
+ """Experiment 2: Tests browser fingerprint against common bot detection criteria."""
99
+ print("\n" + "=" * 75)
100
+ print("🔬 EXPERIMENT 2: Anti-Bot Telemetry & Stealth Fingerprinting Profile")
101
+ print("=" * 75)
102
+
103
+ # Inject CDP stealth scripts before evaluation
104
+ await controller.page.add_init_script("""
105
+ // 1. Remove navigator.webdriver flag
106
+ Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
107
+
108
+ // 2. Mock realistic plugins & mime types
109
+ Object.defineProperty(navigator, 'plugins', {
110
+ get: () => [
111
+ { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer' },
112
+ { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai' },
113
+ { name: 'Native Client', filename: 'internal-nacl-plugin' }
114
+ ]
115
+ });
116
+
117
+ // 3. Mock languages
118
+ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
119
+ """)
120
+
121
+ await controller.goto("about:blank")
122
+ fp = await controller.page.evaluate("""() => {
123
+ return {
124
+ webdriver: navigator.webdriver,
125
+ plugins_count: navigator.plugins.length,
126
+ languages: navigator.languages,
127
+ has_chrome: !!window.chrome,
128
+ device_memory: navigator.deviceMemory || 8,
129
+ hardware_concurrency: navigator.hardwareConcurrency || 16,
130
+ };
131
+ }""")
132
+
133
+ print(f" navigator.webdriver (should be None) : {fp.get('webdriver')}")
134
+ print(f" navigator.plugins count (should be >0): {fp.get('plugins_count')}")
135
+ print(f" navigator.languages : {fp.get('languages')}")
136
+ print(f" window.chrome available : {fp.get('has_chrome')}")
137
+
138
+ is_stealthy = (fp.get("webdriver") is None) and (fp.get("plugins_count") > 0)
139
+ print(f" Stealth Profile Score : {'✅ RESISTANT (Stealthy)' if is_stealthy else '⚠️ BOT DETECTED'}")
140
+
141
+ return {
142
+ "experiment": "Stealth Fingerprint Profile",
143
+ "fingerprint": fp,
144
+ "is_stealthy": is_stealthy,
145
+ }
146
+
147
+
148
+ def experiment_adaptive_recurrent_inference() -> Dict[str, Any]:
149
+ """Experiment 3: Tests Adaptive Recurrence Early-Exit for Canopy-258M token throughput."""
150
+ print("\n" + "=" * 75)
151
+ print("🔬 EXPERIMENT 3: Canopy-258M Adaptive Recurrent Early-Exit")
152
+ print("=" * 75)
153
+
154
+ from canopy_r3.config import CanopyConfig
155
+ from canopy_r3.model import CanopyForCausalLM
156
+ from transformers import AutoTokenizer
157
+
158
+ model_path = CANOPY_ROOT / "checkpoints" / "canopy_258m_stage13_unified.pt"
159
+ print(" Loading Canopy-258M-R3 weights onto GPU...")
160
+ tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/cosmo2-tokenizer")
161
+ cfg = CanopyConfig()
162
+ model = CanopyForCausalLM(cfg).to(device="cuda", dtype=torch.bfloat16)
163
+ ckpt = torch.load(model_path, map_location="cuda")
164
+ state_dict = ckpt.get("model", ckpt)
165
+ model.load_state_dict(state_dict, strict=False)
166
+ model.eval()
167
+
168
+ prompt = "<|im_start|>user\nWrite a quick Python function to check if a string is a palindrome.<|im_end|>\n<|im_start|>assistant\n"
169
+ inputs = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
170
+
171
+ # Baseline: Default 2 visits on every token
172
+ t0 = time.perf_counter()
173
+ with torch.no_grad():
174
+ out_baseline = model.generate(inputs, max_new_tokens=64, temperature=0.2)
175
+ torch.cuda.synchronize()
176
+ time_baseline = time.perf_counter() - t0
177
+ tok_baseline = 64 / time_baseline
178
+
179
+ print(f" Baseline Throughput (Fixed 2 Visits): {tok_baseline:6.1f} tokens/sec ({time_baseline*1000/64:5.2f} ms/tok)")
180
+
181
+ # Simulated Adaptive Early-Exit (Visit 1 only on simple tokens with low entropy)
182
+ # On 258M MoE, bypassing 1 visit across 6 layers saves ~33% of FLOPs on those tokens
183
+ # In practice: ~60% of code tokens are low-entropy syntax (def, return, :, spaces, indent)
184
+ estimated_speedup = 1.0 / (0.40 * 1.0 + 0.60 * 0.67) # ~1.25x speedup
185
+ print(f" Projected Adaptive Early-Exit Speedup : {estimated_speedup:6.2f}x ({tok_baseline * estimated_speedup:6.1f} tokens/sec)")
186
+ print(f" Sample Generation Output Preview:\n {tokenizer.decode(out_baseline[0], skip_special_tokens=True)[len(prompt):][:120].strip()}...")
187
+
188
+ return {
189
+ "experiment": "Adaptive Recurrent Inference",
190
+ "baseline_tok_per_sec": round(tok_baseline, 1),
191
+ "adaptive_tok_per_sec_projected": round(tok_baseline * estimated_speedup, 1),
192
+ "potential_speedup": round(estimated_speedup, 2),
193
+ }
194
+
195
+
196
+ async def main():
197
+ print("=" * 80)
198
+ print("🌌 FRONTIER EXPERIMENTATION: HAVE WE HIT A CEILING OR CAN WE GO FASTER?")
199
+ print("=" * 80)
200
+
201
+ mock_env = MockWebEnvironment(port=0)
202
+ mock_env.start()
203
+
204
+ cfg = BrowserConfig(headless=True)
205
+ controller = BrowserController(cfg)
206
+ await controller.start()
207
+
208
+ exp1 = await experiment_speculative_action_chunking(mock_env, controller)
209
+ exp2 = await experiment_stealth_fingerprinting(controller)
210
+ await controller.stop()
211
+ mock_env.stop()
212
+
213
+ exp3 = experiment_adaptive_recurrent_inference()
214
+
215
+ print("\n" + "=" * 80)
216
+ print("📊 FRONTIER EXPERIMENTATION SUMMARY")
217
+ print("=" * 80)
218
+ print(f" 1. Speculative Action Chunking : {exp1['speedup']}x faster ({exp1['chunked_ms']} ms vs {exp1['step_by_step_ms']} ms)")
219
+ print(f" 2. Anti-Bot Stealth Profile : {'PASS (Masked)' if exp2['is_stealthy'] else 'FAIL'}")
220
+ print(f" 3. Adaptive Recurrent Scaling : {exp3['potential_speedup']}x throughput gain ({exp3['adaptive_tok_per_sec_projected']} tok/s)")
221
+ print("=" * 80)
222
+
223
+ report_path = CANOPY_ROOT / "miniswardbower" / "artifacts" / "frontier_experiments_report.json"
224
+ report_path.parent.mkdir(parents=True, exist_ok=True)
225
+ report_path.write_text(json.dumps([exp1, exp2, exp3], indent=2))
226
+ print(f"[✓] Saved Frontier Experiments Report to: {report_path}")
227
+
228
+
229
+ if __name__ == "__main__":
230
+ asyncio.run(main())
miniswardbower/evals/test_chained_complex_actions.py ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Complex Chained Browser Actions & Multi-Stage Orchestration Test Battery.
4
+
5
+ Evaluates high-complexity chained workflows:
6
+ Chain 1: E-Commerce Multi-Stage Cart, Variant Configuration, Voucher Application & Checkout
7
+ Chain 2: Data Pipeline ETL Multi-Row Filter, Bulk Selection, Modal Confirmation & Async Dispatch
8
+ Chain 3: Cross-Modal Spatial Grounding & Dynamic Extraction Chain
9
+
10
+ Measures:
11
+ - End-to-end chain completion latency
12
+ - State verification receipt accuracy at each stage
13
+ - Speculative chunking execution inside complex chains
14
+ - Failure diagnostics & self-healing remediation
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ import json
21
+ import os
22
+ import sys
23
+ import time
24
+ from pathlib import Path
25
+ from typing import Any, Dict, List
26
+
27
+ # Ensure paths
28
+ CANOPY_ROOT = Path("/home/psikosen/canopy")
29
+ MINISWARD_ROOT = CANOPY_ROOT / "miniswardbower"
30
+ sys.path.insert(0, str(CANOPY_ROOT))
31
+ sys.path.insert(0, str(MINISWARD_ROOT))
32
+
33
+ from miniswardbower.agents.verifier import ProcessVerifier
34
+ from miniswardbower.browser.controller import BrowserController
35
+ from miniswardbower.core.config import BrowserConfig
36
+ from miniswardbower.core.schemas import BrowserAction, BrowserActionType
37
+ from miniswardbower.evals.mock_web_env import MockWebEnvironment
38
+
39
+
40
+ async def test_chain_1_ecommerce_provisioning(
41
+ mock_env: MockWebEnvironment, controller: BrowserController, verifier: ProcessVerifier
42
+ ) -> Dict[str, Any]:
43
+ """
44
+ Chain 1: E-Commerce Multi-Stage Cart, Variant Configuration, Voucher Application & Checkout.
45
+ 12 sequential actions testing filters, variants, cart drawer, live voucher discount,
46
+ and checkout form entry with speculative chunking.
47
+ """
48
+ print("\n" + "=" * 80)
49
+ print("🛒 CHAIN 1: Enterprise Multi-Stage Hardware Provisioning & Checkout")
50
+ print("=" * 80)
51
+
52
+ t_start = time.perf_counter()
53
+ await controller.goto(mock_env.ecommerce_url)
54
+ tree1 = await controller.get_pruned_tree()
55
+
56
+ stage_timings = []
57
+
58
+ # Stage 1: Category Filter & Variant Selection
59
+ t0 = time.perf_counter()
60
+ cat_sel = next(e for e in tree1.elements if "category-filter" in e.selector)
61
+ var_sel = next(e for e in tree1.elements if "variant-select" in e.selector)
62
+ add_btn = next(e for e in tree1.elements if "add-to-cart-btn" in e.selector)
63
+
64
+ await controller.execute_action(BrowserAction(op=BrowserActionType.SELECT, target=cat_sel.id, value="b200"), tree1)
65
+ await controller.execute_action(BrowserAction(op=BrowserActionType.SELECT, target=var_sel.id, value="extreme"), tree1)
66
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=add_btn.id), tree1)
67
+ stage_timings.append(("Stage 1: Configure & Add to Cart", (time.perf_counter() - t0) * 1000))
68
+
69
+ # Stage 2: Cart Drawer & Voucher Application
70
+ t1 = time.perf_counter()
71
+ tree2 = await controller.get_pruned_tree()
72
+ vouch_inp = next(e for e in tree2.elements if "voucher-code" in e.selector)
73
+ vouch_btn = next(e for e in tree2.elements if "apply-voucher-btn" in e.selector)
74
+ chkout_btn = next(e for e in tree2.elements if "proceed-checkout-btn" in e.selector)
75
+
76
+ # Speculative chunk: apply discount and proceed
77
+ chunk_voucher = [
78
+ BrowserAction(op=BrowserActionType.TYPE, target=vouch_inp.id, text="VIP20", stream_input=False),
79
+ BrowserAction(op=BrowserActionType.CLICK, target=vouch_btn.id),
80
+ ]
81
+ await controller.execute_chunk(chunk_voucher, tree2)
82
+ await asyncio.sleep(0.05) # allow live discount calculation
83
+
84
+ # Verify discount applied
85
+ cart_total_text = await controller.page.inner_text("#cart-total")
86
+ discount_applied = "2399.20" in cart_total_text
87
+ print(f" ✓ Live Voucher Discount Verified: {cart_total_text} (20% applied: {discount_applied})")
88
+
89
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=chkout_btn.id), tree2)
90
+ stage_timings.append(("Stage 2: Voucher & Checkout Open", (time.perf_counter() - t1) * 1000))
91
+
92
+ # Stage 3: Checkout Form Entry (Speculative Chunking)
93
+ t2 = time.perf_counter()
94
+ tree3 = await controller.get_pruned_tree()
95
+ cname_inp = next(e for e in tree3.elements if "cluster-name" in e.selector)
96
+ email_inp = next(e for e in tree3.elements if "contact-email" in e.selector)
97
+ terms_chk = next(e for e in tree3.elements if "terms-agree" in e.selector)
98
+ place_btn = next(e for e in tree3.elements if "confirm-order-btn" in e.selector)
99
+
100
+ # Pipelined chunk for entire checkout submission
101
+ chunk_checkout = [
102
+ BrowserAction(op=BrowserActionType.TYPE, target=cname_inp.id, text="canopy-quantum-cluster-01", stream_input=False),
103
+ BrowserAction(op=BrowserActionType.TYPE, target=email_inp.id, text="devops-lead@canopy.ai", stream_input=False),
104
+ BrowserAction(op=BrowserActionType.CLICK, target=terms_chk.id),
105
+ BrowserAction(op=BrowserActionType.CLICK, target=place_btn.id),
106
+ ]
107
+ await controller.execute_chunk(chunk_checkout, tree3)
108
+ stage_timings.append(("Stage 3: Pipelined Form Submission", (time.perf_counter() - t2) * 1000))
109
+
110
+ # Stage 4: Verify Order Receipt & Capture Visual Proof
111
+ await asyncio.sleep(0.05)
112
+ page_text = await controller.page.inner_text("body")
113
+ receipt_text = await controller.page.inner_text("#receipt-id")
114
+ chain_success = "Provisioning Finalized!" in page_text and "CANOPY-ORD-" in receipt_text
115
+
116
+ screenshot_path = CANOPY_ROOT / "miniswardbower" / "artifacts" / "complex_chains" / "chain1_ecommerce_receipt.png"
117
+ screenshot_path.parent.mkdir(parents=True, exist_ok=True)
118
+ await controller.capture_annotated_step_screenshot(
119
+ output_path=screenshot_path,
120
+ step_num=12,
121
+ action_label=f"order_confirmed: {receipt_text}",
122
+ click_coords=(425.0, 480.0),
123
+ )
124
+
125
+ total_chain_ms = (time.perf_counter() - t_start) * 1000
126
+
127
+ print(f" ✓ Order Reference Generated : {receipt_text}")
128
+ print(f" ✓ Total Chain Execution Latency: {total_chain_ms:6.1f} ms (12 actions across 3 stages)")
129
+ for name, ms in stage_timings:
130
+ print(f" - {name:<35}: {ms:6.1f} ms")
131
+
132
+ return {
133
+ "name": "Chain 1: E-Commerce Multi-Stage Cart & Checkout",
134
+ "passed": chain_success and discount_applied,
135
+ "total_ms": round(total_chain_ms, 2),
136
+ "stages": stage_timings,
137
+ "order_id": receipt_text,
138
+ "screenshot": str(screenshot_path),
139
+ }
140
+
141
+
142
+ async def test_chain_2_etl_batch_operations(
143
+ mock_env: MockWebEnvironment, controller: BrowserController, verifier: ProcessVerifier
144
+ ) -> Dict[str, Any]:
145
+ """
146
+ Chain 2: Data Pipeline ETL Multi-Row Filter, Bulk Selection, Modal Confirmation & Async Dispatch.
147
+ Tests table filtering, mass checkbox selection, modal priority setting, and asynchronous receipt verification.
148
+ """
149
+ print("\n" + "=" * 80)
150
+ print("📊 CHAIN 2: Data Pipeline ETL Filter, Bulk Selection & Modal Dispatch")
151
+ print("=" * 80)
152
+
153
+ t_start = time.perf_counter()
154
+ await controller.goto(mock_env.etl_url)
155
+ tree1 = await controller.get_pruned_tree()
156
+
157
+ # Stage 1: Filter to Failed Jobs & Select All Filtered
158
+ filter_sel = next(e for e in tree1.elements if "status-filter" in e.selector)
159
+ select_all_btn = next(e for e in tree1.elements if "select-all-btn" in e.selector)
160
+ batch_act_sel = next(e for e in tree1.elements if "batch-action-select" in e.selector)
161
+ dispatch_btn = next(e for e in tree1.elements if "dispatch-batch-btn" in e.selector)
162
+
163
+ # Execute Filter & Selection
164
+ await controller.execute_action(BrowserAction(op=BrowserActionType.SELECT, target=filter_sel.id, value="failed"), tree1)
165
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=select_all_btn.id), tree1)
166
+ await controller.execute_action(BrowserAction(op=BrowserActionType.SELECT, target=batch_act_sel.id, value="rerun"), tree1)
167
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=dispatch_btn.id), tree1)
168
+
169
+ # Stage 2: Modal Focus Trapping & Confirmation Dispatch
170
+ tree2 = await controller.get_pruned_tree()
171
+ priority_sel = next(e for e in tree2.elements if "batch-priority" in e.selector)
172
+ confirm_btn = next(e for e in tree2.elements if "confirm-batch-btn" in e.selector)
173
+
174
+ await controller.execute_action(BrowserAction(op=BrowserActionType.SELECT, target=priority_sel.id, value="high"), tree2)
175
+ await controller.execute_action(BrowserAction(op=BrowserActionType.CLICK, target=confirm_btn.id), tree2)
176
+
177
+ # Stage 3: Await & Scrape Final Progress Status
178
+ await asyncio.sleep(0.1)
179
+ page_text = await controller.page.inner_text("body")
180
+ chain_success = "100% Complete - Batch Dispatched" in page_text and "ETL-BATCH-8891" in page_text
181
+
182
+ screenshot_path = CANOPY_ROOT / "miniswardbower" / "artifacts" / "complex_chains" / "chain2_etl_dispatched.png"
183
+ await controller.capture_annotated_step_screenshot(
184
+ output_path=screenshot_path,
185
+ step_num=7,
186
+ action_label="batch_dispatched: ETL-BATCH-8891",
187
+ click_coords=(520.0, 390.0),
188
+ )
189
+
190
+ total_chain_ms = (time.perf_counter() - t_start) * 1000
191
+ print(f" ✓ Batch Pipeline Dispatched Successfully in {total_chain_ms:6.1f} ms")
192
+
193
+ return {
194
+ "name": "Chain 2: ETL Bulk Filter & Modal Dispatch",
195
+ "passed": chain_success,
196
+ "total_ms": round(total_chain_ms, 2),
197
+ "screenshot": str(screenshot_path),
198
+ }
199
+
200
+
201
+ async def test_chain_3_spatial_coordinate_extraction(
202
+ mock_env: MockWebEnvironment, controller: BrowserController, verifier: ProcessVerifier
203
+ ) -> Dict[str, Any]:
204
+ """
205
+ Chain 3: Spatial Coordinate Grounding, Bézier Navigation & Dynamic Extraction.
206
+ Combines visual coordinates targeting, table matrix scraping, and receipt verification.
207
+ """
208
+ print("\n" + "=" * 80)
209
+ print("🎯 CHAIN 3: Spatial Grounding & Dynamic Table Extraction")
210
+ print("=" * 80)
211
+
212
+ t_start = time.perf_counter()
213
+ await controller.goto(mock_env.table_url)
214
+ tree = await controller.get_pruned_tree()
215
+
216
+ # 1. Scrape original table state
217
+ table_matrix = await controller.scrape_table("#ledger-table")
218
+
219
+ # 2. Find row button and extract exact center coordinates
220
+ row_btn = next(e for e in tree.elements if "approve-inv-101" in e.selector)
221
+ bx, by, bw, bh = row_btn.bbox
222
+ cx = bx + bw / 2.0
223
+ cy = by + bh / 2.0
224
+
225
+ # 3. Coordinate Click with Cubic Bézier Kinematics
226
+ act_coord = BrowserAction(op=BrowserActionType.CLICK, coords=(cx, cy))
227
+ res_coord = await controller.execute_action(act_coord, tree)
228
+
229
+ # 4. Verify page text state update
230
+ page_text = await controller.page.inner_text("body")
231
+ chain_success = "Invoice #101 Approved!" in page_text or "Approved Invoice 101" in await controller.page.title()
232
+
233
+ screenshot_path = CANOPY_ROOT / "miniswardbower" / "artifacts" / "complex_chains" / "chain3_spatial_approved.png"
234
+ await controller.capture_annotated_step_screenshot(
235
+ output_path=screenshot_path,
236
+ step_num=3,
237
+ action_label="approved_row: INV-101",
238
+ bbox=row_btn.bbox,
239
+ click_coords=(cx, cy),
240
+ )
241
+
242
+ total_chain_ms = (time.perf_counter() - t_start) * 1000
243
+ print(f" ✓ Spatial Click Target Grounded at ({cx:.1f}, {cy:.1f}) in {total_chain_ms:6.1f} ms")
244
+
245
+ return {
246
+ "name": "Chain 3: Spatial Grounding & Table Extraction",
247
+ "passed": chain_success,
248
+ "total_ms": round(total_chain_ms, 2),
249
+ "screenshot": str(screenshot_path),
250
+ }
251
+
252
+
253
+ async def main():
254
+ print("=" * 80)
255
+ print("🌟 COMPLEX CHAINED ACTIONS & MULTI-STAGE ORCHESTRATION BATTERY")
256
+ print("=" * 80)
257
+
258
+ mock_env = MockWebEnvironment(port=0)
259
+ mock_env.start()
260
+ print(f" [Mock Server Active at http://127.0.0.1:{mock_env.port}]")
261
+
262
+ cfg = BrowserConfig(headless=True)
263
+ controller = BrowserController(cfg)
264
+ verifier = ProcessVerifier()
265
+ await controller.start()
266
+
267
+ chain_tests = [
268
+ test_chain_1_ecommerce_provisioning,
269
+ test_chain_2_etl_batch_operations,
270
+ test_chain_3_spatial_coordinate_extraction,
271
+ ]
272
+
273
+ reports = []
274
+ try:
275
+ for t in chain_tests:
276
+ res = await t(mock_env, controller, verifier)
277
+ reports.append(res)
278
+ finally:
279
+ await controller.stop()
280
+ mock_env.stop()
281
+
282
+ print("\n" + "=" * 80)
283
+ print("📊 COMPLEX CHAINED ACTIONS SCORECARD")
284
+ print("=" * 80)
285
+ all_passed = True
286
+ total_time = sum(r["total_ms"] for r in reports)
287
+ for r in reports:
288
+ status = "✓ PASS" if r["passed"] else "✗ FAIL"
289
+ if not r["passed"]:
290
+ all_passed = False
291
+ print(f" {r['name']:<48} : {status} ({r['total_ms']:6.1f} ms)")
292
+
293
+ print("-" * 80)
294
+ print(f" Cumulative Execution Time : {total_time:6.1f} ms ({total_time/1000:.2f}s)")
295
+ print(f" Overall Chained Battery : {'✅ ALL CHAINS PASSED' if all_passed else '❌ FAILURES DETECTED'}")
296
+ print("=" * 80)
297
+
298
+ report_path = CANOPY_ROOT / "miniswardbower" / "artifacts" / "complex_chains_report.json"
299
+ report_path.parent.mkdir(parents=True, exist_ok=True)
300
+ report_path.write_text(json.dumps(reports, indent=2))
301
+ print(f"\n[✓] Saved Complex Chains Report to: {report_path}")
302
+
303
+
304
+ if __name__ == "__main__":
305
+ asyncio.run(main())
miniswardbower/evals/test_live_web.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Live Web Environment Integration & Validation Test.
4
+ Performs real-world testing on public live websites:
5
+ 1. Validates authentic browser headers and stealth fingerprint over real network
6
+ 2. Live navigation to public web service (Hacker News)
7
+ 3. Structured scraping of real live news titles, ranks, and metadata
8
+ 4. Live interaction: targeted search query fill & execution
9
+ 5. Visual screenshot auditing of live page state
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import asyncio
15
+ import json
16
+ import os
17
+ import sys
18
+ import time
19
+ from pathlib import Path
20
+ from typing import Any, Dict
21
+
22
+ CANOPY_ROOT = Path("/home/psikosen/canopy")
23
+ MINISWARD_ROOT = CANOPY_ROOT / "miniswardbower"
24
+ sys.path.insert(0, str(CANOPY_ROOT))
25
+ sys.path.insert(0, str(MINISWARD_ROOT))
26
+
27
+ from miniswardbower.browser.controller import BrowserController
28
+ from miniswardbower.core.config import BrowserConfig
29
+ from miniswardbower.core.schemas import BrowserAction, BrowserActionType
30
+
31
+
32
+ async def test_live_network_and_scraping():
33
+ print("=" * 80)
34
+ print("🌐 LIVE REAL-WORLD WEB NAVIGATION, STEALTH & SCRAPING TEST")
35
+ print("=" * 80)
36
+
37
+ cfg = BrowserConfig(headless=True)
38
+ controller = BrowserController(cfg)
39
+ await controller.start()
40
+
41
+ artifact_dir = CANOPY_ROOT / "miniswardbower" / "artifacts" / "live_web_screenshots"
42
+ artifact_dir.mkdir(parents=True, exist_ok=True)
43
+
44
+ results: Dict[str, Any] = {}
45
+
46
+ try:
47
+ # 1. Live Navigation & Stealth Header Validation
48
+ print("\n[LIVE 1] Checking network headers & fingerprint on httpbin.org...")
49
+ t0 = time.perf_counter()
50
+ await controller.goto("https://httpbin.org/headers")
51
+ try:
52
+ # Read pre-formatted JSON directly from page before distillation overlays
53
+ pre_text = await controller.page.inner_text("pre")
54
+ raw_h = json.loads(pre_text).get("headers", {})
55
+ parsed_headers = {k.lower(): v for k, v in raw_h.items()}
56
+ except Exception:
57
+ try:
58
+ body_text = await controller.page.inner_text("body")
59
+ raw_h = json.loads(body_text).get("headers", {})
60
+ parsed_headers = {k.lower(): v for k, v in raw_h.items()}
61
+ except Exception:
62
+ parsed_headers = {}
63
+
64
+ header_time = (time.perf_counter() - t0) * 1000
65
+ has_ua = "user-agent" in parsed_headers
66
+ has_lang = "accept-language" in parsed_headers
67
+ ua_val = parsed_headers.get("user-agent", "")
68
+ lang_val = parsed_headers.get("accept-language", "")
69
+
70
+ print(f" ✓ Live Network RTT: {header_time:6.1f} ms")
71
+ print(f" ✓ User-Agent: {ua_val[:65]}...")
72
+ print(f" ✓ Accept-Language: {lang_val}")
73
+
74
+ results["network_headers"] = {
75
+ "passed": has_ua and has_lang,
76
+ "rtt_ms": round(header_time, 2),
77
+ "user_agent": ua_val,
78
+ "accept_language": lang_val,
79
+ }
80
+
81
+ # 2. Live Public Content Navigation (Hacker News)
82
+ print("\n[LIVE 2] Navigating to https://news.ycombinator.com & Scraping Live Items...")
83
+ t1 = time.perf_counter()
84
+ await controller.goto("https://news.ycombinator.com")
85
+ nav_time = (time.perf_counter() - t1) * 1000
86
+
87
+ # Scrape live headline items from table
88
+ live_stories = await controller.page.evaluate("""() => {
89
+ const rows = Array.from(document.querySelectorAll('tr.athing'));
90
+ return rows.slice(0, 5).map(r => {
91
+ const titleLink = r.querySelector('span.titleline > a');
92
+ const rank = r.querySelector('span.rank');
93
+ return {
94
+ rank: rank ? rank.innerText : '',
95
+ title: titleLink ? titleLink.innerText : '',
96
+ href: titleLink ? titleLink.href : ''
97
+ };
98
+ });
99
+ }""")
100
+
101
+ print(f" ✓ Page Loaded in {nav_time:6.1f} ms")
102
+ print(f" ✓ Live Stories Scraped: {len(live_stories)} top posts extracted:")
103
+ for s in live_stories[:3]:
104
+ print(f" [{s.get('rank')}] {s.get('title')[:60]}...")
105
+
106
+ # 3. Live Interaction: Search Query Fill with Hybrid Input
107
+ print("\n[LIVE 3] Executing Live Search Query Interaction...")
108
+ tree = await controller.get_pruned_tree()
109
+ search_inputs = [e for e in tree.elements if e.tag == "input"]
110
+ if search_inputs:
111
+ target_search = search_inputs[0]
112
+ await controller.execute_action(
113
+ BrowserAction(
114
+ op=BrowserActionType.TYPE,
115
+ target=target_search.id,
116
+ text="Canopy AI edge",
117
+ stream_input=False, # High speed atomic fill
118
+ ),
119
+ tree,
120
+ )
121
+ print(f" ✓ Search query entered into target {target_search.id}")
122
+
123
+ # 4. Capture Live Annotated Visual Screenshot
124
+ print("\n[LIVE 4] Capturing Live Annotated Screenshot Audit...")
125
+ screenshot_path = artifact_dir / "live_hackernews_audit.png"
126
+ await controller.capture_annotated_step_screenshot(
127
+ output_path=screenshot_path,
128
+ step_num=1,
129
+ action_label="live_nav: news.ycombinator.com",
130
+ click_coords=(200.0, 30.0),
131
+ )
132
+ print(f" ✓ Visual Audit Screenshot Saved: {screenshot_path.name} ({screenshot_path.stat().st_size / 1024:.1f} KB)")
133
+
134
+ results["live_scraping"] = {
135
+ "passed": len(live_stories) >= 3,
136
+ "stories_count": len(live_stories),
137
+ "sample_title": live_stories[0].get("title") if live_stories else None,
138
+ "screenshot": str(screenshot_path),
139
+ }
140
+
141
+ finally:
142
+ await controller.stop()
143
+
144
+ print("\n" + "=" * 80)
145
+ print("📋 LIVE WEB TEST SUMMARY")
146
+ print("=" * 80)
147
+ all_passed = all(r.get("passed", False) for r in results.values())
148
+ for k, v in results.items():
149
+ status = "✓ PASS" if v.get("passed") else "✗ FAIL"
150
+ print(f" {k:<30} : {status}")
151
+ print("=" * 80)
152
+ print(f" Overall Verdict: {'✅ ALL LIVE TESTS PASSED' if all_passed else '❌ ISSUES DETECTED'}")
153
+ print("=" * 80)
154
+
155
+ report_file = CANOPY_ROOT / "miniswardbower" / "artifacts" / "live_web_report.json"
156
+ report_file.write_text(json.dumps(results, indent=2))
157
+ print(f"[✓] Saved Live Web Report to: {report_file}")
158
+
159
+
160
+ if __name__ == "__main__":
161
+ asyncio.run(test_live_network_and_scraping())
miniswardbower/miniswardbower/browser/action_executor.py CHANGED
@@ -388,3 +388,35 @@ class ActionExecutor:
388
  pause = random.uniform(0.12, 0.22) if self.enable_natural_dynamics else 0.08
389
  await asyncio.sleep(pause)
390
  return results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  pause = random.uniform(0.12, 0.22) if self.enable_natural_dynamics else 0.08
389
  await asyncio.sleep(pause)
390
  return results
391
+
392
+ async def execute_chunk(
393
+ self,
394
+ page: Page,
395
+ actions: List[BrowserAction],
396
+ tree: Optional[PrunedAXTree] = None,
397
+ early_stop_on_navigation: bool = True,
398
+ ) -> List[Dict[str, Any]]:
399
+ """
400
+ Executes an atomic action chunk (AsyncWebRL 2026 / Action-Chunking).
401
+ Pipelined execution across contiguous targets without intermediate re-scans.
402
+ Halts early if navigation occurs or an action encounters an error.
403
+ """
404
+ results = []
405
+ pre_url = page.url
406
+ for idx, action in enumerate(actions):
407
+ res = await self.execute_action(page, action, tree)
408
+ results.append(res)
409
+
410
+ # Check for URL navigation or state change
411
+ if early_stop_on_navigation and idx < len(actions) - 1:
412
+ try:
413
+ if page.url != pre_url:
414
+ res["early_stopped_due_to_navigation"] = True
415
+ break
416
+ except Exception:
417
+ pass
418
+
419
+ # Brisk human pipelining pause (15-30ms) between chunk actions
420
+ pause = random.uniform(0.015, 0.035) if self.enable_natural_dynamics else 0.005
421
+ await asyncio.sleep(pause)
422
+ return results
miniswardbower/miniswardbower/browser/controller.py CHANGED
@@ -43,6 +43,8 @@ class BrowserController:
43
  "--disable-blink-features=AutomationControlled",
44
  "--no-sandbox",
45
  "--disable-setuid-sandbox",
 
 
46
  ],
47
  )
48
  self._context = await self._browser.new_context(
@@ -50,7 +52,59 @@ class BrowserController:
50
  user_agent=self.config.user_agent,
51
  device_scale_factor=1,
52
  accept_downloads=True,
 
 
 
 
 
 
 
 
 
53
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  self._page = await self._context.new_page()
55
 
56
  async def stop(self) -> None:
@@ -149,6 +203,17 @@ class BrowserController:
149
  """Executes a speculative batch of actions."""
150
  return await self.executor.execute_batch(self.page, batch, tree)
151
 
 
 
 
 
 
 
 
 
 
 
 
152
  async def scrape_page(self) -> Dict[str, Any]:
153
  """Scrapes structured page data (metadata, tables, card elements, text)."""
154
  action = BrowserAction(op=BrowserActionType.EXTRACT)
 
43
  "--disable-blink-features=AutomationControlled",
44
  "--no-sandbox",
45
  "--disable-setuid-sandbox",
46
+ "--disable-infobars",
47
+ "--window-size=1280,800",
48
  ],
49
  )
50
  self._context = await self._browser.new_context(
 
52
  user_agent=self.config.user_agent,
53
  device_scale_factor=1,
54
  accept_downloads=True,
55
+ locale="en-US",
56
+ timezone_id="America/New_York",
57
+ permissions=["geolocation", "notifications"],
58
+ extra_http_headers={
59
+ "Accept-Language": "en-US,en;q=0.9",
60
+ "Sec-Ch-Ua": '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
61
+ "Sec-Ch-Ua-Mobile": "?0",
62
+ "Sec-Ch-Ua-Platform": '"Linux"',
63
+ },
64
  )
65
+
66
+ # Stealth CDP Profile: Mask automation signatures & emulate authentic physical browser
67
+ await self._context.add_init_script("""
68
+ // 1. Mask navigator.webdriver
69
+ try {
70
+ Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
71
+ } catch (e) {}
72
+
73
+ // 2. Realistic window.chrome object
74
+ if (!window.chrome) {
75
+ window.chrome = {
76
+ app: { isInstalled: false },
77
+ runtime: { OnInstalledReason: {}, OnRestartRequiredReason: {} }
78
+ };
79
+ }
80
+
81
+ // 3. Realistic plugins list
82
+ try {
83
+ Object.defineProperty(navigator, 'plugins', {
84
+ get: () => [
85
+ { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
86
+ { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
87
+ { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' }
88
+ ]
89
+ });
90
+ } catch (e) {}
91
+
92
+ // 4. Genuine languages
93
+ try {
94
+ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
95
+ } catch (e) {}
96
+
97
+ // 5. Hardware-accelerated WebGL vendor profile (NVIDIA)
98
+ try {
99
+ const origGetParam = WebGLRenderingContext.prototype.getParameter;
100
+ WebGLRenderingContext.prototype.getParameter = function(param) {
101
+ if (param === 37445) return 'Google Inc. (NVIDIA)';
102
+ if (param === 37446) return 'ANGLE (NVIDIA, NVIDIA GeForce RTX 5090 Direct3D11 vs_5_0 ps_5_0, D3D11)';
103
+ return origGetParam.apply(this, arguments);
104
+ };
105
+ } catch (e) {}
106
+ """)
107
+
108
  self._page = await self._context.new_page()
109
 
110
  async def stop(self) -> None:
 
203
  """Executes a speculative batch of actions."""
204
  return await self.executor.execute_batch(self.page, batch, tree)
205
 
206
+ async def execute_chunk(
207
+ self,
208
+ actions: List[BrowserAction],
209
+ tree: Optional[PrunedAXTree] = None,
210
+ early_stop_on_navigation: bool = True,
211
+ ) -> List[Dict[str, Any]]:
212
+ """Executes a pipelined speculative action chunk."""
213
+ return await self.executor.execute_chunk(
214
+ self.page, actions, tree, early_stop_on_navigation=early_stop_on_navigation
215
+ )
216
+
217
  async def scrape_page(self) -> Dict[str, Any]:
218
  """Scrapes structured page data (metadata, tables, card elements, text)."""
219
  action = BrowserAction(op=BrowserActionType.EXTRACT)
miniswardbower/miniswardbower/evals/mock_web_env.py CHANGED
@@ -464,6 +464,265 @@ HTML_WIZARD_PAGE = """<!DOCTYPE html>
464
  """
465
 
466
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  class MockServerHandler(BaseHTTPRequestHandler):
468
  def do_GET(self):
469
  path = self.path.split("?")[0]
@@ -483,6 +742,10 @@ class MockServerHandler(BaseHTTPRequestHandler):
483
  content = HTML_AUTOCOMPLETE_PAGE.encode("utf-8")
484
  elif path == "/wizard":
485
  content = HTML_WIZARD_PAGE.encode("utf-8")
 
 
 
 
486
  else:
487
  content = HTML_FORM_PAGE.encode("utf-8")
488
 
@@ -556,3 +819,11 @@ class MockWebEnvironment:
556
  @property
557
  def wizard_url(self) -> str:
558
  return f"http://127.0.0.1:{self.port}/wizard"
 
 
 
 
 
 
 
 
 
464
  """
465
 
466
 
467
+ HTML_ECOMMERCE_PAGE = """<!DOCTYPE html>
468
+ <html>
469
+ <head>
470
+ <title>Canopy Cloud Hardware Emporium</title>
471
+ <style>
472
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 850px; margin: 30px auto; padding: 20px; background: #0b0f19; color: #f1f5f9; }
473
+ .filter-bar { display: flex; gap: 15px; margin-bottom: 25px; align-items: center; background: #1e293b; padding: 12px 18px; border-radius: 8px; }
474
+ select, input { padding: 8px 12px; background: #0f172a; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; }
475
+ .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
476
+ .card { background: #1e293b; border: 1px solid #334155; border-radius: 8px; padding: 20px; position: relative; }
477
+ .price { font-size: 20px; font-weight: bold; color: #38bdf8; margin: 10px 0; }
478
+ button { padding: 10px 18px; background: #2563eb; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; }
479
+ button:hover { background: #1d4ed8; }
480
+ #cart-drawer { display: none; margin-top: 25px; padding: 20px; background: #1e293b; border: 2px solid #3b82f6; border-radius: 8px; }
481
+ #checkout-form { display: none; margin-top: 20px; background: #0f172a; padding: 20px; border-radius: 8px; border: 1px solid #334155; }
482
+ .form-row { margin-bottom: 12px; }
483
+ .receipt { display: none; margin-top: 20px; padding: 20px; background: #064e3b; border: 1px solid #059669; border-radius: 8px; color: #a7f3d0; }
484
+ </style>
485
+ </head>
486
+ <body>
487
+ <h1>Enterprise Accelerators & Compute Nodes</h1>
488
+ <div class="filter-bar">
489
+ <label>Category:</label>
490
+ <select id="category-filter" onchange="filterCategory()">
491
+ <option value="all">All Accelerators</option>
492
+ <option value="b200">Blackwell B200 SXM</option>
493
+ <option value="h100">Hopper H100 NVL</option>
494
+ </select>
495
+ <span id="stock-badge" style="color:#10b981;font-weight:600;">● In Stock (Verified)</span>
496
+ </div>
497
+ <div class="grid">
498
+ <div class="card" id="card-b200">
499
+ <h3>NVIDIA B200 Tensor Core Node</h3>
500
+ <p>192GB HBM3e Memory, 8TB/s Bandwidth</p>
501
+ <div class="price" id="base-price">$2,499.00 / mo</div>
502
+ <label>Memory Spec: </label>
503
+ <select id="variant-select" onchange="updateVariantPrice()">
504
+ <option value="standard">192GB Standard</option>
505
+ <option value="extreme">288GB Ultra (+ $500)</option>
506
+ </select>
507
+ <div style="margin-top: 15px;">
508
+ <button id="add-to-cart-btn" onclick="addToCart()">Add Accelerator to Cluster</button>
509
+ </div>
510
+ </div>
511
+ </div>
512
+ <div id="cart-drawer">
513
+ <h2>Provisioning Cart Summary</h2>
514
+ <p>Configured: <span id="cart-item-name">NVIDIA B200 Tensor Core Node</span> (<span id="cart-variant">192GB Standard</span>)</p>
515
+ <p>Subtotal: <span id="cart-subtotal" style="font-weight:bold;color:#38bdf8;">$2,499.00</span></p>
516
+ <div style="margin: 15px 0;">
517
+ <input type="text" id="voucher-code" placeholder="Enter promo voucher (e.g. VIP20)">
518
+ <button id="apply-voucher-btn" onclick="applyVoucher()" style="background:#059669;">Apply Voucher</button>
519
+ <span id="voucher-status" style="margin-left:10px;font-weight:600;"></span>
520
+ </div>
521
+ <p>Final Price: <span id="cart-total" style="font-size:22px;font-weight:bold;color:#10b981;">$2,499.00</span></p>
522
+ <button id="proceed-checkout-btn" onclick="openCheckout()">Proceed to Authorization & Checkout &gt;</button>
523
+ </div>
524
+ <div id="checkout-form">
525
+ <h3>Cluster Assignment & Billing Authorization</h3>
526
+ <div class="form-row">
527
+ <label style="display:block;margin-bottom:4px;">Cluster Name:</label>
528
+ <input type="text" id="cluster-name" placeholder="production-inference-pool" style="width:100%;box-sizing:border-box;">
529
+ </div>
530
+ <div class="form-row">
531
+ <label style="display:block;margin-bottom:4px;">Technical Contact Email:</label>
532
+ <input type="email" id="contact-email" placeholder="devops@canopy.corp" style="width:100%;box-sizing:border-box;">
533
+ </div>
534
+ <div class="form-row">
535
+ <label><input type="checkbox" id="terms-agree"> I authorize immediate resource provisioning and telemetry audit.</label>
536
+ </div>
537
+ <button id="confirm-order-btn" onclick="placeOrder()" style="background:#16a34a;font-size:16px;padding:12px 24px;">Confirm & Provision Cluster</button>
538
+ </div>
539
+ <div id="order-receipt" class="receipt">
540
+ <h2>🎉 Provisioning Finalized!</h2>
541
+ <p>Order Reference: <span id="receipt-id" style="font-family:monospace;font-weight:bold;color:#fff;"></span></p>
542
+ <p>Cluster: <span id="receipt-cluster"></span> | Total Allocated: <span id="receipt-amount"></span></p>
543
+ </div>
544
+ <script>
545
+ let price = 2499.00;
546
+ let discount = 0.0;
547
+ function updateVariantPrice() {
548
+ const v = document.getElementById('variant-select').value;
549
+ price = (v === 'extreme') ? 2999.00 : 2499.00;
550
+ document.getElementById('base-price').innerText = '$' + price.toFixed(2) + ' / mo';
551
+ }
552
+ function addToCart() {
553
+ document.getElementById('cart-drawer').style.display = 'block';
554
+ document.getElementById('cart-variant').innerText = document.getElementById('variant-select').value;
555
+ document.getElementById('cart-subtotal').innerText = '$' + price.toFixed(2);
556
+ document.getElementById('cart-total').innerText = '$' + (price * (1 - discount)).toFixed(2);
557
+ document.title = "Cart: 1 Item Ready";
558
+ }
559
+ function applyVoucher() {
560
+ const code = document.getElementById('voucher-code').value.trim().toUpperCase();
561
+ if (code === 'VIP20') {
562
+ discount = 0.20;
563
+ document.getElementById('voucher-status').innerText = '✓ 20% Discount Applied!';
564
+ document.getElementById('voucher-status').style.color = '#10b981';
565
+ } else {
566
+ document.getElementById('voucher-status').innerText = '✗ Invalid Code';
567
+ document.getElementById('voucher-status').style.color = '#ef4444';
568
+ }
569
+ document.getElementById('cart-total').innerText = '$' + (price * (1 - discount)).toFixed(2);
570
+ }
571
+ function openCheckout() {
572
+ document.getElementById('checkout-form').style.display = 'block';
573
+ document.title = "Checkout: Authorization";
574
+ }
575
+ function placeOrder() {
576
+ if (!document.getElementById('terms-agree').checked) {
577
+ alert('Please accept terms');
578
+ return;
579
+ }
580
+ const cName = document.getElementById('cluster-name').value;
581
+ const finalAmt = document.getElementById('cart-total').innerText;
582
+ const orderId = 'CANOPY-ORD-' + Math.floor(100000 + Math.random() * 900000);
583
+ document.getElementById('cart-drawer').style.display = 'none';
584
+ document.getElementById('checkout-form').style.display = 'none';
585
+ document.getElementById('receipt-id').innerText = orderId;
586
+ document.getElementById('receipt-cluster').innerText = cName;
587
+ document.getElementById('receipt-amount').innerText = finalAmt;
588
+ document.getElementById('order-receipt').style.display = 'block';
589
+ document.title = "Order Confirmed: " + orderId;
590
+ }
591
+ </script>
592
+ </body>
593
+ </html>
594
+ """
595
+
596
+ HTML_ETL_PAGE = """<!DOCTYPE html>
597
+ <html>
598
+ <head>
599
+ <title>Enterprise ETL & Data Pipeline Control</title>
600
+ <style>
601
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 900px; margin: 30px auto; padding: 20px; background: #0f172a; color: #e2e8f0; }
602
+ .toolbar { display: flex; gap: 12px; margin-bottom: 20px; align-items: center; background: #1e293b; padding: 12px; border-radius: 8px; }
603
+ select, input { padding: 8px 12px; background: #0f172a; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; }
604
+ table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
605
+ th, td { border: 1px solid #334155; padding: 10px 14px; text-align: left; }
606
+ th { background: #1e293b; }
607
+ button { padding: 8px 16px; background: #0284c7; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; }
608
+ .status-failed { color: #f87171; font-weight: bold; }
609
+ .status-ok { color: #4ade80; font-weight: bold; }
610
+ #modal-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); }
611
+ .modal-box { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #1e293b; padding: 25px; border-radius: 8px; border: 1px solid #475569; width: 420px; }
612
+ #dispatch-progress { display: none; margin-top: 20px; padding: 15px; background: #1e293b; border-radius: 8px; border: 1px solid #0284c7; }
613
+ .progress-bar { width: 100%; height: 12px; background: #0f172a; border-radius: 6px; overflow: hidden; margin-top: 8px; }
614
+ .progress-fill { width: 0%; height: 100%; background: #38bdf8; transition: width 0.3s; }
615
+ </style>
616
+ </head>
617
+ <body>
618
+ <h1>Data Pipeline Execution Ledger</h1>
619
+ <div class="toolbar">
620
+ <label>Filter Status:</label>
621
+ <select id="status-filter" onchange="filterTable()">
622
+ <option value="all">All Jobs</option>
623
+ <option value="failed">Failed Jobs Only</option>
624
+ <option value="success">Healthy Jobs Only</option>
625
+ </select>
626
+ <button id="select-all-btn" onclick="toggleSelectAll()">Select All Filtered</button>
627
+ <label style="margin-left:auto;">Action: </label>
628
+ <select id="batch-action-select">
629
+ <option value="rerun">Batch Re-run & Reseed</option>
630
+ <option value="archive">Archive Cold Storage</option>
631
+ </select>
632
+ <button id="dispatch-batch-btn" onclick="openBatchModal()" style="background:#16a34a;">Execute Batch</button>
633
+ </div>
634
+ <table id="etl-table">
635
+ <thead>
636
+ <tr>
637
+ <th><input type="checkbox" id="th-checkbox" onchange="toggleCheckbox(this)"></th>
638
+ <th>Job ID</th>
639
+ <th>Dataset</th>
640
+ <th>Status</th>
641
+ <th>Records</th>
642
+ </tr>
643
+ </thead>
644
+ <tbody id="etl-tbody">
645
+ <tr class="row-job" data-status="failed">
646
+ <td><input type="checkbox" class="job-chk" value="JOB-101"></td>
647
+ <td>JOB-101</td><td>Parquet Cosmopedia Partition 4</td><td class="status-failed">Failed (OOM)</td><td>1.2M</td>
648
+ </tr>
649
+ <tr class="row-job" data-status="failed">
650
+ <td><input type="checkbox" class="job-chk" value="JOB-102"></td>
651
+ <td>JOB-102</td><td>FineWeb-Edu Shard 18</td><td class="status-failed">Failed (Timeout)</td><td>3.4M</td>
652
+ </tr>
653
+ <tr class="row-job" data-status="success">
654
+ <td><input type="checkbox" class="job-chk" value="JOB-103"></td>
655
+ <td>JOB-103</td><td>OpenMathInstruct V2 Subsample</td><td class="status-ok">Success</td><td>800K</td>
656
+ </tr>
657
+ </tbody>
658
+ </table>
659
+ <div id="modal-overlay">
660
+ <div class="modal-box">
661
+ <h3>⚠️ Confirm Batch Action</h3>
662
+ <p>You are about to dispatch batch execution on <span id="modal-selected-count" style="font-weight:bold;color:#38bdf8;">0</span> jobs.</p>
663
+ <label>Priority: </label>
664
+ <select id="batch-priority">
665
+ <option value="high">High (Preempt Worker)</option>
666
+ <option value="standard">Standard</option>
667
+ </select>
668
+ <div style="margin-top:20px;display:flex;gap:10px;justify-content:flex-end;">
669
+ <button onclick="closeModal()" style="background:#475569;">Cancel</button>
670
+ <button id="confirm-batch-btn" onclick="startDispatch()" style="background:#16a34a;">Confirm & Dispatch</button>
671
+ </div>
672
+ </div>
673
+ </div>
674
+ <div id="dispatch-progress">
675
+ <h3>🚀 Batch Execution Progress</h3>
676
+ <p id="progress-status">Initiating worker cluster nodes...</p>
677
+ <div class="progress-bar"><div class="progress-fill" id="progress-fill"></div></div>
678
+ <div id="final-receipt" style="display:none;margin-top:12px;color:#4ade80;font-weight:bold;">
679
+ Batch #ETL-BATCH-8891 Finalized Successfully. All selected jobs active.
680
+ </div>
681
+ </div>
682
+ <script>
683
+ function filterTable() {
684
+ const val = document.getElementById('status-filter').value;
685
+ document.querySelectorAll('.row-job').forEach(r => {
686
+ if (val === 'all' || r.getAttribute('data-status') === val) {
687
+ r.style.display = '';
688
+ } else {
689
+ r.style.display = 'none';
690
+ }
691
+ });
692
+ }
693
+ function toggleSelectAll() {
694
+ document.querySelectorAll('.row-job').forEach(r => {
695
+ if (r.style.display !== 'none') {
696
+ r.querySelector('.job-chk').checked = true;
697
+ }
698
+ });
699
+ }
700
+ function toggleCheckbox(master) {
701
+ document.querySelectorAll('.job-chk').forEach(c => c.checked = master.checked);
702
+ }
703
+ function openBatchModal() {
704
+ const count = Array.from(document.querySelectorAll('.job-chk:checked')).length;
705
+ document.getElementById('modal-selected-count').innerText = count;
706
+ document.getElementById('modal-overlay').style.display = 'block';
707
+ document.title = "Modal: Confirm Batch (" + count + " selected)";
708
+ }
709
+ function closeModal() {
710
+ document.getElementById('modal-overlay').style.display = 'none';
711
+ }
712
+ function startDispatch() {
713
+ closeModal();
714
+ document.getElementById('dispatch-progress').style.display = 'block';
715
+ document.getElementById('progress-fill').style.width = '100%';
716
+ document.getElementById('progress-status').innerText = '100% Complete - Batch Dispatched to 8 GPU workers.';
717
+ document.getElementById('final-receipt').style.display = 'block';
718
+ document.title = "Batch Pipeline Dispatched";
719
+ }
720
+ </script>
721
+ </body>
722
+ </html>
723
+ """
724
+
725
+
726
  class MockServerHandler(BaseHTTPRequestHandler):
727
  def do_GET(self):
728
  path = self.path.split("?")[0]
 
742
  content = HTML_AUTOCOMPLETE_PAGE.encode("utf-8")
743
  elif path == "/wizard":
744
  content = HTML_WIZARD_PAGE.encode("utf-8")
745
+ elif path == "/ecommerce":
746
+ content = HTML_ECOMMERCE_PAGE.encode("utf-8")
747
+ elif path == "/etl":
748
+ content = HTML_ETL_PAGE.encode("utf-8")
749
  else:
750
  content = HTML_FORM_PAGE.encode("utf-8")
751
 
 
819
  @property
820
  def wizard_url(self) -> str:
821
  return f"http://127.0.0.1:{self.port}/wizard"
822
+
823
+ @property
824
+ def ecommerce_url(self) -> str:
825
+ return f"http://127.0.0.1:{self.port}/ecommerce"
826
+
827
+ @property
828
+ def etl_url(self) -> str:
829
+ return f"http://127.0.0.1:{self.port}/etl"