htmlgraph 0.9.3__py3-none-any.whl → 0.27.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +173 -17
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +127 -0
  7. htmlgraph/agent_registry.py +45 -30
  8. htmlgraph/agents.py +160 -107
  9. htmlgraph/analytics/__init__.py +9 -2
  10. htmlgraph/analytics/cli.py +190 -51
  11. htmlgraph/analytics/cost_analyzer.py +391 -0
  12. htmlgraph/analytics/cost_monitor.py +664 -0
  13. htmlgraph/analytics/cost_reporter.py +675 -0
  14. htmlgraph/analytics/cross_session.py +617 -0
  15. htmlgraph/analytics/dependency.py +192 -100
  16. htmlgraph/analytics/pattern_learning.py +771 -0
  17. htmlgraph/analytics/session_graph.py +707 -0
  18. htmlgraph/analytics/strategic/__init__.py +80 -0
  19. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  20. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  21. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  22. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  23. htmlgraph/analytics/work_type.py +190 -14
  24. htmlgraph/analytics_index.py +135 -51
  25. htmlgraph/api/__init__.py +3 -0
  26. htmlgraph/api/cost_alerts_websocket.py +416 -0
  27. htmlgraph/api/main.py +2498 -0
  28. htmlgraph/api/static/htmx.min.js +1 -0
  29. htmlgraph/api/static/style-redesign.css +1344 -0
  30. htmlgraph/api/static/style.css +1079 -0
  31. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  32. htmlgraph/api/templates/dashboard.html +794 -0
  33. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  34. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  35. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  36. htmlgraph/api/templates/partials/agents.html +317 -0
  37. htmlgraph/api/templates/partials/event-traces.html +373 -0
  38. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  39. htmlgraph/api/templates/partials/features.html +578 -0
  40. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  41. htmlgraph/api/templates/partials/metrics.html +346 -0
  42. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  43. htmlgraph/api/templates/partials/orchestration.html +198 -0
  44. htmlgraph/api/templates/partials/spawners.html +375 -0
  45. htmlgraph/api/templates/partials/work-items.html +613 -0
  46. htmlgraph/api/websocket.py +538 -0
  47. htmlgraph/archive/__init__.py +24 -0
  48. htmlgraph/archive/bloom.py +234 -0
  49. htmlgraph/archive/fts.py +297 -0
  50. htmlgraph/archive/manager.py +583 -0
  51. htmlgraph/archive/search.py +244 -0
  52. htmlgraph/atomic_ops.py +560 -0
  53. htmlgraph/attribute_index.py +208 -0
  54. htmlgraph/bounded_paths.py +539 -0
  55. htmlgraph/builders/__init__.py +14 -0
  56. htmlgraph/builders/base.py +118 -29
  57. htmlgraph/builders/bug.py +150 -0
  58. htmlgraph/builders/chore.py +119 -0
  59. htmlgraph/builders/epic.py +150 -0
  60. htmlgraph/builders/feature.py +31 -6
  61. htmlgraph/builders/insight.py +195 -0
  62. htmlgraph/builders/metric.py +217 -0
  63. htmlgraph/builders/pattern.py +202 -0
  64. htmlgraph/builders/phase.py +162 -0
  65. htmlgraph/builders/spike.py +52 -19
  66. htmlgraph/builders/track.py +148 -72
  67. htmlgraph/cigs/__init__.py +81 -0
  68. htmlgraph/cigs/autonomy.py +385 -0
  69. htmlgraph/cigs/cost.py +475 -0
  70. htmlgraph/cigs/messages_basic.py +472 -0
  71. htmlgraph/cigs/messaging.py +365 -0
  72. htmlgraph/cigs/models.py +771 -0
  73. htmlgraph/cigs/pattern_storage.py +427 -0
  74. htmlgraph/cigs/patterns.py +503 -0
  75. htmlgraph/cigs/posttool_analyzer.py +234 -0
  76. htmlgraph/cigs/reporter.py +818 -0
  77. htmlgraph/cigs/tracker.py +317 -0
  78. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  79. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  80. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  81. htmlgraph/cli/__init__.py +42 -0
  82. htmlgraph/cli/__main__.py +6 -0
  83. htmlgraph/cli/analytics.py +1424 -0
  84. htmlgraph/cli/base.py +685 -0
  85. htmlgraph/cli/constants.py +206 -0
  86. htmlgraph/cli/core.py +954 -0
  87. htmlgraph/cli/main.py +147 -0
  88. htmlgraph/cli/models.py +475 -0
  89. htmlgraph/cli/templates/__init__.py +1 -0
  90. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  91. htmlgraph/cli/work/__init__.py +239 -0
  92. htmlgraph/cli/work/browse.py +115 -0
  93. htmlgraph/cli/work/features.py +568 -0
  94. htmlgraph/cli/work/orchestration.py +676 -0
  95. htmlgraph/cli/work/report.py +728 -0
  96. htmlgraph/cli/work/sessions.py +466 -0
  97. htmlgraph/cli/work/snapshot.py +559 -0
  98. htmlgraph/cli/work/tracks.py +486 -0
  99. htmlgraph/cli_commands/__init__.py +1 -0
  100. htmlgraph/cli_commands/feature.py +195 -0
  101. htmlgraph/cli_framework.py +115 -0
  102. htmlgraph/collections/__init__.py +18 -0
  103. htmlgraph/collections/base.py +415 -98
  104. htmlgraph/collections/bug.py +53 -0
  105. htmlgraph/collections/chore.py +53 -0
  106. htmlgraph/collections/epic.py +53 -0
  107. htmlgraph/collections/feature.py +12 -26
  108. htmlgraph/collections/insight.py +100 -0
  109. htmlgraph/collections/metric.py +92 -0
  110. htmlgraph/collections/pattern.py +97 -0
  111. htmlgraph/collections/phase.py +53 -0
  112. htmlgraph/collections/session.py +194 -0
  113. htmlgraph/collections/spike.py +56 -16
  114. htmlgraph/collections/task_delegation.py +241 -0
  115. htmlgraph/collections/todo.py +511 -0
  116. htmlgraph/collections/traces.py +487 -0
  117. htmlgraph/config/cost_models.json +56 -0
  118. htmlgraph/config.py +190 -0
  119. htmlgraph/context_analytics.py +344 -0
  120. htmlgraph/converter.py +216 -28
  121. htmlgraph/cost_analysis/__init__.py +5 -0
  122. htmlgraph/cost_analysis/analyzer.py +438 -0
  123. htmlgraph/dashboard.html +2406 -307
  124. htmlgraph/dashboard.html.backup +6592 -0
  125. htmlgraph/dashboard.html.bak +7181 -0
  126. htmlgraph/dashboard.html.bak2 +7231 -0
  127. htmlgraph/dashboard.html.bak3 +7232 -0
  128. htmlgraph/db/__init__.py +38 -0
  129. htmlgraph/db/queries.py +790 -0
  130. htmlgraph/db/schema.py +1788 -0
  131. htmlgraph/decorators.py +317 -0
  132. htmlgraph/dependency_models.py +19 -2
  133. htmlgraph/deploy.py +142 -125
  134. htmlgraph/deployment_models.py +474 -0
  135. htmlgraph/docs/API_REFERENCE.md +841 -0
  136. htmlgraph/docs/HTTP_API.md +750 -0
  137. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  138. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  139. htmlgraph/docs/README.md +532 -0
  140. htmlgraph/docs/__init__.py +77 -0
  141. htmlgraph/docs/docs_version.py +55 -0
  142. htmlgraph/docs/metadata.py +93 -0
  143. htmlgraph/docs/migrations.py +232 -0
  144. htmlgraph/docs/template_engine.py +143 -0
  145. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  146. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  147. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  148. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  149. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  150. htmlgraph/docs/version_check.py +163 -0
  151. htmlgraph/edge_index.py +182 -27
  152. htmlgraph/error_handler.py +544 -0
  153. htmlgraph/event_log.py +100 -52
  154. htmlgraph/event_migration.py +13 -4
  155. htmlgraph/exceptions.py +49 -0
  156. htmlgraph/file_watcher.py +101 -28
  157. htmlgraph/find_api.py +75 -63
  158. htmlgraph/git_events.py +145 -63
  159. htmlgraph/graph.py +1122 -106
  160. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  161. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  162. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  163. htmlgraph/hooks/__init__.py +45 -0
  164. htmlgraph/hooks/bootstrap.py +169 -0
  165. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  166. htmlgraph/hooks/concurrent_sessions.py +208 -0
  167. htmlgraph/hooks/context.py +350 -0
  168. htmlgraph/hooks/drift_handler.py +525 -0
  169. htmlgraph/hooks/event_tracker.py +1314 -0
  170. htmlgraph/hooks/git_commands.py +175 -0
  171. htmlgraph/hooks/hooks-config.example.json +12 -0
  172. htmlgraph/hooks/installer.py +343 -0
  173. htmlgraph/hooks/orchestrator.py +674 -0
  174. htmlgraph/hooks/orchestrator_reflector.py +223 -0
  175. htmlgraph/hooks/post-checkout.sh +28 -0
  176. htmlgraph/hooks/post-commit.sh +24 -0
  177. htmlgraph/hooks/post-merge.sh +26 -0
  178. htmlgraph/hooks/post_tool_use_failure.py +273 -0
  179. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  180. htmlgraph/hooks/posttooluse.py +408 -0
  181. htmlgraph/hooks/pre-commit.sh +94 -0
  182. htmlgraph/hooks/pre-push.sh +28 -0
  183. htmlgraph/hooks/pretooluse.py +819 -0
  184. htmlgraph/hooks/prompt_analyzer.py +637 -0
  185. htmlgraph/hooks/session_handler.py +668 -0
  186. htmlgraph/hooks/session_summary.py +395 -0
  187. htmlgraph/hooks/state_manager.py +504 -0
  188. htmlgraph/hooks/subagent_detection.py +202 -0
  189. htmlgraph/hooks/subagent_stop.py +369 -0
  190. htmlgraph/hooks/task_enforcer.py +255 -0
  191. htmlgraph/hooks/task_validator.py +177 -0
  192. htmlgraph/hooks/validator.py +628 -0
  193. htmlgraph/ids.py +41 -27
  194. htmlgraph/index.d.ts +286 -0
  195. htmlgraph/learning.py +767 -0
  196. htmlgraph/mcp_server.py +69 -23
  197. htmlgraph/models.py +1586 -87
  198. htmlgraph/operations/README.md +62 -0
  199. htmlgraph/operations/__init__.py +79 -0
  200. htmlgraph/operations/analytics.py +339 -0
  201. htmlgraph/operations/bootstrap.py +289 -0
  202. htmlgraph/operations/events.py +244 -0
  203. htmlgraph/operations/fastapi_server.py +231 -0
  204. htmlgraph/operations/hooks.py +350 -0
  205. htmlgraph/operations/initialization.py +597 -0
  206. htmlgraph/operations/initialization.py.backup +228 -0
  207. htmlgraph/operations/server.py +303 -0
  208. htmlgraph/orchestration/__init__.py +58 -0
  209. htmlgraph/orchestration/claude_launcher.py +179 -0
  210. htmlgraph/orchestration/command_builder.py +72 -0
  211. htmlgraph/orchestration/headless_spawner.py +281 -0
  212. htmlgraph/orchestration/live_events.py +377 -0
  213. htmlgraph/orchestration/model_selection.py +327 -0
  214. htmlgraph/orchestration/plugin_manager.py +140 -0
  215. htmlgraph/orchestration/prompts.py +137 -0
  216. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  217. htmlgraph/orchestration/spawners/__init__.py +16 -0
  218. htmlgraph/orchestration/spawners/base.py +194 -0
  219. htmlgraph/orchestration/spawners/claude.py +173 -0
  220. htmlgraph/orchestration/spawners/codex.py +435 -0
  221. htmlgraph/orchestration/spawners/copilot.py +294 -0
  222. htmlgraph/orchestration/spawners/gemini.py +471 -0
  223. htmlgraph/orchestration/subprocess_runner.py +36 -0
  224. htmlgraph/orchestration/task_coordination.py +343 -0
  225. htmlgraph/orchestration.md +563 -0
  226. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  227. htmlgraph/orchestrator.py +669 -0
  228. htmlgraph/orchestrator_config.py +357 -0
  229. htmlgraph/orchestrator_mode.py +328 -0
  230. htmlgraph/orchestrator_validator.py +133 -0
  231. htmlgraph/parallel.py +646 -0
  232. htmlgraph/parser.py +160 -35
  233. htmlgraph/path_query.py +608 -0
  234. htmlgraph/pattern_matcher.py +636 -0
  235. htmlgraph/planning.py +147 -52
  236. htmlgraph/pydantic_models.py +476 -0
  237. htmlgraph/quality_gates.py +350 -0
  238. htmlgraph/query_builder.py +109 -72
  239. htmlgraph/query_composer.py +509 -0
  240. htmlgraph/reflection.py +443 -0
  241. htmlgraph/refs.py +344 -0
  242. htmlgraph/repo_hash.py +512 -0
  243. htmlgraph/repositories/__init__.py +292 -0
  244. htmlgraph/repositories/analytics_repository.py +455 -0
  245. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  246. htmlgraph/repositories/feature_repository.py +581 -0
  247. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  248. htmlgraph/repositories/feature_repository_memory.py +607 -0
  249. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  250. htmlgraph/repositories/filter_service.py +620 -0
  251. htmlgraph/repositories/filter_service_standard.py +445 -0
  252. htmlgraph/repositories/shared_cache.py +621 -0
  253. htmlgraph/repositories/shared_cache_memory.py +395 -0
  254. htmlgraph/repositories/track_repository.py +552 -0
  255. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  256. htmlgraph/repositories/track_repository_memory.py +508 -0
  257. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  258. htmlgraph/routing.py +8 -19
  259. htmlgraph/scripts/deploy.py +1 -2
  260. htmlgraph/sdk/__init__.py +398 -0
  261. htmlgraph/sdk/__init__.pyi +14 -0
  262. htmlgraph/sdk/analytics/__init__.py +19 -0
  263. htmlgraph/sdk/analytics/engine.py +155 -0
  264. htmlgraph/sdk/analytics/helpers.py +178 -0
  265. htmlgraph/sdk/analytics/registry.py +109 -0
  266. htmlgraph/sdk/base.py +484 -0
  267. htmlgraph/sdk/constants.py +216 -0
  268. htmlgraph/sdk/core.pyi +308 -0
  269. htmlgraph/sdk/discovery.py +120 -0
  270. htmlgraph/sdk/help/__init__.py +12 -0
  271. htmlgraph/sdk/help/mixin.py +699 -0
  272. htmlgraph/sdk/mixins/__init__.py +15 -0
  273. htmlgraph/sdk/mixins/attribution.py +113 -0
  274. htmlgraph/sdk/mixins/mixin.py +410 -0
  275. htmlgraph/sdk/operations/__init__.py +12 -0
  276. htmlgraph/sdk/operations/mixin.py +427 -0
  277. htmlgraph/sdk/orchestration/__init__.py +17 -0
  278. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  279. htmlgraph/sdk/orchestration/spawner.py +204 -0
  280. htmlgraph/sdk/planning/__init__.py +19 -0
  281. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  282. htmlgraph/sdk/planning/mixin.py +211 -0
  283. htmlgraph/sdk/planning/parallel.py +186 -0
  284. htmlgraph/sdk/planning/queue.py +210 -0
  285. htmlgraph/sdk/planning/recommendations.py +87 -0
  286. htmlgraph/sdk/planning/smart_planning.py +319 -0
  287. htmlgraph/sdk/session/__init__.py +19 -0
  288. htmlgraph/sdk/session/continuity.py +57 -0
  289. htmlgraph/sdk/session/handoff.py +110 -0
  290. htmlgraph/sdk/session/info.py +309 -0
  291. htmlgraph/sdk/session/manager.py +103 -0
  292. htmlgraph/sdk/strategic/__init__.py +26 -0
  293. htmlgraph/sdk/strategic/mixin.py +563 -0
  294. htmlgraph/server.py +685 -180
  295. htmlgraph/services/__init__.py +10 -0
  296. htmlgraph/services/claiming.py +199 -0
  297. htmlgraph/session_hooks.py +300 -0
  298. htmlgraph/session_manager.py +1392 -175
  299. htmlgraph/session_registry.py +587 -0
  300. htmlgraph/session_state.py +436 -0
  301. htmlgraph/session_warning.py +201 -0
  302. htmlgraph/sessions/__init__.py +23 -0
  303. htmlgraph/sessions/handoff.py +756 -0
  304. htmlgraph/setup.py +34 -17
  305. htmlgraph/spike_index.py +143 -0
  306. htmlgraph/sync_docs.py +12 -15
  307. htmlgraph/system_prompts.py +450 -0
  308. htmlgraph/templates/AGENTS.md.template +366 -0
  309. htmlgraph/templates/CLAUDE.md.template +97 -0
  310. htmlgraph/templates/GEMINI.md.template +87 -0
  311. htmlgraph/templates/orchestration-view.html +350 -0
  312. htmlgraph/track_builder.py +146 -15
  313. htmlgraph/track_manager.py +69 -21
  314. htmlgraph/transcript.py +890 -0
  315. htmlgraph/transcript_analytics.py +699 -0
  316. htmlgraph/types.py +323 -0
  317. htmlgraph/validation.py +115 -0
  318. htmlgraph/watch.py +8 -5
  319. htmlgraph/work_type_utils.py +3 -2
  320. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
  321. htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
  322. htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
  323. htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
  324. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
  325. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  326. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  327. htmlgraph/cli.py +0 -2688
  328. htmlgraph/sdk.py +0 -709
  329. htmlgraph-0.9.3.dist-info/RECORD +0 -61
  330. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  331. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,818 @@
1
+ """
2
+ CostReporter for CIGS Dashboard Generation
3
+
4
+ Generates interactive HTML dashboards showing cost analysis, violation tracking,
5
+ and savings potential from proper delegation.
6
+
7
+ Features:
8
+ - Professional HTML5 dashboard with responsive design
9
+ - Cost visualization using Chart.js
10
+ - Violation metrics and compliance statistics
11
+ - Recommendations for cost optimization
12
+ - Dark theme matching HtmlGraph visual style
13
+
14
+ Usage:
15
+ from htmlgraph.cigs.reporter import CostReporter
16
+ from htmlgraph.cigs.tracker import ViolationTracker
17
+
18
+ tracker = ViolationTracker()
19
+ reporter = CostReporter()
20
+ html = reporter.generate_dashboard(tracker)
21
+ reporter.save_dashboard(html, "dashboard.html")
22
+ """
23
+
24
+ import json
25
+ from datetime import datetime
26
+ from pathlib import Path
27
+ from typing import Any
28
+
29
+ from htmlgraph.cigs.models import SessionViolationSummary
30
+
31
+
32
+ class CostReporter:
33
+ """
34
+ Generate interactive HTML dashboards from cost analysis data.
35
+
36
+ Transforms ViolationTracker and cost data into professional HTML
37
+ visualizations with charts, tables, and recommendations.
38
+ """
39
+
40
+ # Design theme
41
+ THEME = {
42
+ "bg_primary": "#1a1a2e",
43
+ "bg_secondary": "#16213e",
44
+ "text_primary": "#e0e0e0",
45
+ "text_secondary": "#b0b0b0",
46
+ "accent_primary": "#0f3460",
47
+ "accent_secondary": "#e94560",
48
+ "success": "#4caf50",
49
+ "warning": "#ff9800",
50
+ "error": "#f44336",
51
+ }
52
+
53
+ def __init__(self) -> None:
54
+ """Initialize CostReporter."""
55
+ self.generated_at = datetime.now()
56
+
57
+ def generate_dashboard(
58
+ self, violation_summary: SessionViolationSummary | None = None
59
+ ) -> str:
60
+ """
61
+ Generate complete interactive HTML dashboard.
62
+
63
+ Args:
64
+ violation_summary: SessionViolationSummary with violation data
65
+
66
+ Returns:
67
+ Complete HTML document as string
68
+ """
69
+ if violation_summary is None:
70
+ violation_summary = self._create_empty_summary()
71
+
72
+ # Build dashboard components
73
+ html_parts = [
74
+ self._html_header(),
75
+ self._html_styles(),
76
+ self._html_body_open(),
77
+ self._html_header_section(violation_summary),
78
+ self._html_summary_cards(violation_summary),
79
+ self._html_charts_section(violation_summary),
80
+ self._html_violations_table(violation_summary),
81
+ self._html_insights_section(violation_summary),
82
+ self._html_footer_section(),
83
+ self._html_body_close(),
84
+ self._html_scripts(),
85
+ ]
86
+
87
+ return "\n".join(html_parts)
88
+
89
+ def save_dashboard(self, html: str, path: str | Path) -> None:
90
+ """
91
+ Save HTML dashboard to file.
92
+
93
+ Args:
94
+ html: HTML content to save
95
+ path: File path to save to
96
+
97
+ Raises:
98
+ IOError: If file cannot be written
99
+ """
100
+ path = Path(path)
101
+ path.parent.mkdir(parents=True, exist_ok=True)
102
+ path.write_text(html, encoding="utf-8")
103
+
104
+ def generate_summary_metrics(
105
+ self, violation_summary: SessionViolationSummary
106
+ ) -> dict[str, Any]:
107
+ """
108
+ Extract aggregated metrics from violation summary.
109
+
110
+ Args:
111
+ violation_summary: Session violation data
112
+
113
+ Returns:
114
+ Dictionary with summary metrics
115
+ """
116
+ total_violations = violation_summary.total_violations
117
+ total_waste = violation_summary.total_waste_tokens
118
+ compliance_rate = violation_summary.compliance_rate
119
+
120
+ # Calculate metrics
121
+ avg_waste_per_violation = (
122
+ int(total_waste / total_violations) if total_violations > 0 else 0
123
+ )
124
+
125
+ # Estimate direct vs delegated costs
126
+ direct_cost_estimate = total_waste
127
+ delegated_cost_estimate = int(direct_cost_estimate * 0.3) # ~70% savings
128
+ savings_potential = max(0, direct_cost_estimate - delegated_cost_estimate)
129
+
130
+ return {
131
+ "total_violations": total_violations,
132
+ "total_waste_tokens": total_waste,
133
+ "avg_waste_per_violation": avg_waste_per_violation,
134
+ "compliance_rate": compliance_rate,
135
+ "circuit_breaker_triggered": violation_summary.circuit_breaker_triggered,
136
+ "direct_cost_estimate": direct_cost_estimate,
137
+ "delegated_cost_estimate": delegated_cost_estimate,
138
+ "savings_potential": savings_potential,
139
+ "savings_percentage": (
140
+ (savings_potential / direct_cost_estimate * 100)
141
+ if direct_cost_estimate > 0
142
+ else 0
143
+ ),
144
+ }
145
+
146
+ def generate_cost_breakdown_by_type(
147
+ self, violation_summary: SessionViolationSummary
148
+ ) -> dict[str, int]:
149
+ """
150
+ Generate cost breakdown by violation type.
151
+
152
+ Args:
153
+ violation_summary: Session violation data
154
+
155
+ Returns:
156
+ Dictionary mapping violation types to waste tokens
157
+ """
158
+ breakdown: dict[str, int] = {}
159
+
160
+ for violation in violation_summary.violations:
161
+ vtype = str(violation.violation_type)
162
+ breakdown[vtype] = breakdown.get(vtype, 0) + violation.waste_tokens
163
+
164
+ return breakdown
165
+
166
+ def generate_cost_breakdown_by_tool(
167
+ self, violation_summary: SessionViolationSummary
168
+ ) -> dict[str, int]:
169
+ """
170
+ Generate cost breakdown by tool used.
171
+
172
+ Args:
173
+ violation_summary: Session violation data
174
+
175
+ Returns:
176
+ Dictionary mapping tool names to waste tokens
177
+ """
178
+ breakdown: dict[str, int] = {}
179
+
180
+ for violation in violation_summary.violations:
181
+ tool = violation.tool
182
+ breakdown[tool] = breakdown.get(tool, 0) + violation.waste_tokens
183
+
184
+ return breakdown
185
+
186
+ # ===== HTML Generation Methods =====
187
+
188
+ def _html_header(self) -> str:
189
+ """Generate HTML document header."""
190
+ return """<!DOCTYPE html>
191
+ <html lang="en">
192
+ <head>
193
+ <meta charset="UTF-8">
194
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
195
+ <title>Cost Attribution Dashboard - HtmlGraph</title>
196
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
197
+ </head>"""
198
+
199
+ def _html_styles(self) -> str:
200
+ """Generate CSS styles."""
201
+ return f"""<style>
202
+ * {{
203
+ margin: 0;
204
+ padding: 0;
205
+ box-sizing: border-box;
206
+ }}
207
+
208
+ body {{
209
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
210
+ background-color: {self.THEME["bg_primary"]};
211
+ color: {self.THEME["text_primary"]};
212
+ line-height: 1.6;
213
+ }}
214
+
215
+ a {{
216
+ color: {self.THEME["accent_secondary"]};
217
+ text-decoration: none;
218
+ }}
219
+
220
+ a:hover {{
221
+ text-decoration: underline;
222
+ }}
223
+
224
+ /* Layout */
225
+ .container {{
226
+ max-width: 1400px;
227
+ margin: 0 auto;
228
+ padding: 20px;
229
+ }}
230
+
231
+ /* Header */
232
+ .header {{
233
+ border-bottom: 2px solid {self.THEME["accent_primary"]};
234
+ padding-bottom: 20px;
235
+ margin-bottom: 30px;
236
+ }}
237
+
238
+ .header h1 {{
239
+ font-size: 2.5em;
240
+ margin-bottom: 10px;
241
+ color: {self.THEME["text_primary"]};
242
+ }}
243
+
244
+ .header .subtitle {{
245
+ color: {self.THEME["text_secondary"]};
246
+ font-size: 0.95em;
247
+ }}
248
+
249
+ .header-meta {{
250
+ margin-top: 15px;
251
+ display: flex;
252
+ gap: 20px;
253
+ flex-wrap: wrap;
254
+ font-size: 0.9em;
255
+ color: {self.THEME["text_secondary"]};
256
+ }}
257
+
258
+ /* Summary Cards */
259
+ .cards {{
260
+ display: grid;
261
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
262
+ gap: 20px;
263
+ margin-bottom: 40px;
264
+ }}
265
+
266
+ .card {{
267
+ background-color: {self.THEME["bg_secondary"]};
268
+ border: 1px solid {self.THEME["accent_primary"]};
269
+ border-radius: 8px;
270
+ padding: 25px;
271
+ transition: all 0.3s ease;
272
+ }}
273
+
274
+ .card:hover {{
275
+ border-color: {self.THEME["accent_secondary"]};
276
+ transform: translateY(-5px);
277
+ box-shadow: 0 10px 30px rgba(233, 69, 96, 0.2);
278
+ }}
279
+
280
+ .card-label {{
281
+ color: {self.THEME["text_secondary"]};
282
+ font-size: 0.85em;
283
+ text-transform: uppercase;
284
+ letter-spacing: 0.5px;
285
+ margin-bottom: 10px;
286
+ }}
287
+
288
+ .card-value {{
289
+ font-size: 2.5em;
290
+ font-weight: bold;
291
+ margin-bottom: 8px;
292
+ color: {self.THEME["text_primary"]};
293
+ }}
294
+
295
+ .card-unit {{
296
+ color: {self.THEME["text_secondary"]};
297
+ font-size: 0.9em;
298
+ font-weight: normal;
299
+ }}
300
+
301
+ .card-meta {{
302
+ color: {self.THEME["text_secondary"]};
303
+ font-size: 0.85em;
304
+ margin-top: 12px;
305
+ padding-top: 12px;
306
+ border-top: 1px solid {self.THEME["accent_primary"]};
307
+ }}
308
+
309
+ /* Status indicators */
310
+ .status-good {{
311
+ color: {self.THEME["success"]};
312
+ }}
313
+
314
+ .status-warning {{
315
+ color: {self.THEME["warning"]};
316
+ }}
317
+
318
+ .status-error {{
319
+ color: {self.THEME["error"]};
320
+ }}
321
+
322
+ /* Charts */
323
+ .charts {{
324
+ display: grid;
325
+ grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
326
+ gap: 30px;
327
+ margin-bottom: 40px;
328
+ }}
329
+
330
+ .chart-container {{
331
+ background-color: {self.THEME["bg_secondary"]};
332
+ border: 1px solid {self.THEME["accent_primary"]};
333
+ border-radius: 8px;
334
+ padding: 20px;
335
+ }}
336
+
337
+ .chart-title {{
338
+ font-size: 1.3em;
339
+ font-weight: 600;
340
+ margin-bottom: 20px;
341
+ color: {self.THEME["text_primary"]};
342
+ }}
343
+
344
+ .chart-canvas {{
345
+ max-height: 400px;
346
+ }}
347
+
348
+ /* Table */
349
+ .table-section {{
350
+ margin-bottom: 40px;
351
+ }}
352
+
353
+ .table-section h2 {{
354
+ font-size: 1.5em;
355
+ margin-bottom: 20px;
356
+ color: {self.THEME["text_primary"]};
357
+ }}
358
+
359
+ .table-wrapper {{
360
+ overflow-x: auto;
361
+ background-color: {self.THEME["bg_secondary"]};
362
+ border: 1px solid {self.THEME["accent_primary"]};
363
+ border-radius: 8px;
364
+ }}
365
+
366
+ table {{
367
+ width: 100%;
368
+ border-collapse: collapse;
369
+ }}
370
+
371
+ th {{
372
+ background-color: {self.THEME["accent_primary"]};
373
+ padding: 15px;
374
+ text-align: left;
375
+ font-weight: 600;
376
+ color: {self.THEME["text_primary"]};
377
+ border-bottom: 2px solid {self.THEME["accent_secondary"]};
378
+ }}
379
+
380
+ td {{
381
+ padding: 12px 15px;
382
+ border-bottom: 1px solid {self.THEME["accent_primary"]};
383
+ color: {self.THEME["text_primary"]};
384
+ }}
385
+
386
+ tr:hover {{
387
+ background-color: {self.THEME["accent_primary"]};
388
+ }}
389
+
390
+ /* Insights */
391
+ .insights {{
392
+ background-color: {self.THEME["bg_secondary"]};
393
+ border: 1px solid {self.THEME["accent_primary"]};
394
+ border-radius: 8px;
395
+ padding: 25px;
396
+ margin-bottom: 40px;
397
+ }}
398
+
399
+ .insights h2 {{
400
+ font-size: 1.5em;
401
+ margin-bottom: 20px;
402
+ color: {self.THEME["text_primary"]};
403
+ }}
404
+
405
+ .insight {{
406
+ margin-bottom: 20px;
407
+ padding: 15px;
408
+ background-color: {self.THEME["bg_primary"]};
409
+ border-left: 4px solid {self.THEME["accent_secondary"]};
410
+ border-radius: 4px;
411
+ }}
412
+
413
+ .insight-title {{
414
+ font-weight: 600;
415
+ color: {self.THEME["accent_secondary"]};
416
+ margin-bottom: 8px;
417
+ }}
418
+
419
+ .insight-text {{
420
+ color: {self.THEME["text_secondary"]};
421
+ line-height: 1.6;
422
+ }}
423
+
424
+ /* Footer */
425
+ .footer {{
426
+ text-align: center;
427
+ padding-top: 20px;
428
+ border-top: 1px solid {self.THEME["accent_primary"]};
429
+ color: {self.THEME["text_secondary"]};
430
+ font-size: 0.85em;
431
+ }}
432
+
433
+ /* Responsive */
434
+ @media (max-width: 768px) {{
435
+ .charts {{
436
+ grid-template-columns: 1fr;
437
+ }}
438
+
439
+ .header h1 {{
440
+ font-size: 1.8em;
441
+ }}
442
+
443
+ .card-value {{
444
+ font-size: 2em;
445
+ }}
446
+
447
+ table {{
448
+ font-size: 0.9em;
449
+ }}
450
+
451
+ th, td {{
452
+ padding: 10px;
453
+ }}
454
+ }}
455
+ </style>"""
456
+
457
+ def _html_body_open(self) -> str:
458
+ """Generate opening body tag."""
459
+ return "<body>"
460
+
461
+ def _html_body_close(self) -> str:
462
+ """Generate closing body tag."""
463
+ return "</body></html>"
464
+
465
+ def _html_header_section(self, violation_summary: SessionViolationSummary) -> str:
466
+ """Generate dashboard header section."""
467
+ generated_at = self.generated_at.strftime("%Y-%m-%d %H:%M:%S")
468
+ circuit_status = (
469
+ "YES - Circuit Breaker Triggered"
470
+ if violation_summary.circuit_breaker_triggered
471
+ else "No"
472
+ )
473
+
474
+ return f"""<div class="container">
475
+ <div class="header">
476
+ <h1>Cost Attribution Dashboard</h1>
477
+ <p class="subtitle">Phase 1 MVP - HtmlGraph Delegation Cost Analysis</p>
478
+ <div class="header-meta">
479
+ <span>Session ID: <strong>{violation_summary.session_id}</strong></span>
480
+ <span>Generated: <strong>{generated_at}</strong></span>
481
+ <span>Circuit Breaker: <strong class="status-{"error" if violation_summary.circuit_breaker_triggered else "good"}">{circuit_status}</strong></span>
482
+ </div>
483
+ </div>
484
+ """
485
+
486
+ def _html_summary_cards(self, violation_summary: SessionViolationSummary) -> str:
487
+ """Generate summary metric cards."""
488
+ metrics = self.generate_summary_metrics(violation_summary)
489
+
490
+ compliance_status = (
491
+ "status-good"
492
+ if metrics["compliance_rate"] >= 0.8
493
+ else "status-warning"
494
+ if metrics["compliance_rate"] >= 0.5
495
+ else "status-error"
496
+ )
497
+
498
+ return f"""<div class="cards">
499
+ <div class="card">
500
+ <div class="card-label">Total Violations</div>
501
+ <div class="card-value">{metrics["total_violations"]}</div>
502
+ <div class="card-meta">Direct execution violations detected</div>
503
+ </div>
504
+
505
+ <div class="card">
506
+ <div class="card-label">Total Waste</div>
507
+ <div class="card-value">{metrics["total_waste_tokens"]:,}<span class="card-unit"> tokens</span></div>
508
+ <div class="card-meta">Avg: {metrics["avg_waste_per_violation"]:,} per violation</div>
509
+ </div>
510
+
511
+ <div class="card">
512
+ <div class="card-label">Compliance Rate</div>
513
+ <div class="card-value"><span class="{compliance_status}">{metrics["compliance_rate"]:.0%}</span></div>
514
+ <div class="card-meta">Delegation adherence across session</div>
515
+ </div>
516
+
517
+ <div class="card">
518
+ <div class="card-label">Potential Savings</div>
519
+ <div class="card-value">{metrics["savings_potential"]:,}<span class="card-unit"> tokens</span></div>
520
+ <div class="card-meta"><span class="status-good">{metrics["savings_percentage"]:.0f}% reduction</span></div>
521
+ </div>
522
+ </div>
523
+ """
524
+
525
+ def _html_charts_section(self, violation_summary: SessionViolationSummary) -> str:
526
+ """Generate charts section with visualizations."""
527
+ breakdown_by_type = self.generate_cost_breakdown_by_type(violation_summary)
528
+ breakdown_by_tool = self.generate_cost_breakdown_by_tool(violation_summary)
529
+
530
+ # Prepare data for charts
531
+ type_labels = list(breakdown_by_type.keys())
532
+ type_data = list(breakdown_by_type.values())
533
+
534
+ tool_labels = list(breakdown_by_tool.keys())
535
+ tool_data = list(breakdown_by_tool.values())
536
+
537
+ # Embed data as JSON for JavaScript
538
+ type_data_json = json.dumps(type_labels)
539
+ type_values_json = json.dumps(type_data)
540
+ tool_data_json = json.dumps(tool_labels)
541
+ tool_values_json = json.dumps(tool_data)
542
+
543
+ return f"""<div class="charts">
544
+ <div class="chart-container">
545
+ <div class="chart-title">Cost by Violation Type</div>
546
+ <canvas id="chartByType" class="chart-canvas"></canvas>
547
+ </div>
548
+
549
+ <div class="chart-container">
550
+ <div class="chart-title">Cost by Tool</div>
551
+ <canvas id="chartByTool" class="chart-canvas"></canvas>
552
+ </div>
553
+ </div>
554
+
555
+ <script>
556
+ // Chart.js configuration
557
+ const chartConfig = {{
558
+ type_labels: {type_data_json},
559
+ type_data: {type_values_json},
560
+ tool_labels: {tool_data_json},
561
+ tool_data: {tool_values_json}
562
+ }};
563
+ </script>
564
+ """
565
+
566
+ def _html_violations_table(self, violation_summary: SessionViolationSummary) -> str:
567
+ """Generate detailed violations table."""
568
+ table_rows = ""
569
+
570
+ for i, violation in enumerate(violation_summary.violations, 1):
571
+ vtype = str(violation.violation_type)
572
+ warning_indicator = "⚠️" if violation.was_warned else ""
573
+
574
+ table_rows += f""" <tr>
575
+ <td>{i}</td>
576
+ <td>{violation.timestamp.strftime("%H:%M:%S")}</td>
577
+ <td><strong>{violation.tool}</strong></td>
578
+ <td>{vtype}</td>
579
+ <td>{violation.actual_cost_tokens:,}</td>
580
+ <td>{violation.optimal_cost_tokens:,}</td>
581
+ <td><span class="status-error">{violation.waste_tokens:,}</span></td>
582
+ <td>{violation.should_have_delegated_to}</td>
583
+ <td>{warning_indicator}</td>
584
+ </tr>
585
+ """
586
+
587
+ return f"""<div class="table-section">
588
+ <h2>Violation Details</h2>
589
+ <div class="table-wrapper">
590
+ <table>
591
+ <thead>
592
+ <tr>
593
+ <th>#</th>
594
+ <th>Time</th>
595
+ <th>Tool</th>
596
+ <th>Violation Type</th>
597
+ <th>Actual Cost</th>
598
+ <th>Optimal Cost</th>
599
+ <th>Waste</th>
600
+ <th>Should Delegate To</th>
601
+ <th>Warned</th>
602
+ </tr>
603
+ </thead>
604
+ <tbody>
605
+ {table_rows} </tbody>
606
+ </table>
607
+ </div>
608
+ </div>
609
+ """
610
+
611
+ def _html_insights_section(self, violation_summary: SessionViolationSummary) -> str:
612
+ """Generate insights and recommendations."""
613
+ metrics = self.generate_summary_metrics(violation_summary)
614
+ breakdown_by_type = self.generate_cost_breakdown_by_type(violation_summary)
615
+
616
+ insights = []
617
+
618
+ # Insight 1: Compliance
619
+ if metrics["compliance_rate"] >= 0.8:
620
+ insights.append(
621
+ (
622
+ "Excellent Delegation Compliance",
623
+ "Your delegation adherence is excellent. Continue following the delegation "
624
+ "patterns you've established.",
625
+ )
626
+ )
627
+ elif metrics["compliance_rate"] >= 0.5:
628
+ insights.append(
629
+ (
630
+ "Moderate Compliance",
631
+ f"Improve delegation by {(1 - metrics['compliance_rate']) * 100:.0f}%. Focus on "
632
+ "delegating exploration and implementation work.",
633
+ )
634
+ )
635
+ else:
636
+ insights.append(
637
+ (
638
+ "Low Delegation Compliance",
639
+ "Significant opportunity for improvement. Consider using Task() and spawn_* "
640
+ "functions for major work categories.",
641
+ )
642
+ )
643
+
644
+ # Insight 2: Savings potential
645
+ if metrics["savings_potential"] > 0:
646
+ insights.append(
647
+ (
648
+ "Significant Savings Opportunity",
649
+ f"By properly delegating all violations, you could save approximately "
650
+ f"{metrics['savings_potential']:,} tokens ({metrics['savings_percentage']:.0f}% reduction).",
651
+ )
652
+ )
653
+
654
+ # Insight 3: Most costly violation type
655
+ if breakdown_by_type:
656
+ top_violation = max(breakdown_by_type.items(), key=lambda x: x[1])
657
+ insights.append(
658
+ (
659
+ f"Highest Cost: {top_violation[0]}",
660
+ f"This violation type accounts for {top_violation[1]:,} tokens. "
661
+ "Consider this area for immediate improvement.",
662
+ )
663
+ )
664
+
665
+ # Insight 4: Circuit breaker
666
+ if violation_summary.circuit_breaker_triggered:
667
+ insights.append(
668
+ (
669
+ "Circuit Breaker Triggered",
670
+ "You have exceeded 3 violations in this session. Please adopt proper delegation "
671
+ "practices to prevent future circuit breaker activation.",
672
+ )
673
+ )
674
+
675
+ insights_html = ""
676
+ for title, text in insights:
677
+ insights_html += f""" <div class="insight">
678
+ <div class="insight-title">{title}</div>
679
+ <div class="insight-text">{text}</div>
680
+ </div>
681
+ """
682
+
683
+ return f"""<div class="insights">
684
+ <h2>Insights & Recommendations</h2>
685
+ {insights_html} </div>
686
+ """
687
+
688
+ def _html_footer_section(self) -> str:
689
+ """Generate footer section."""
690
+ return """ <div class="footer">
691
+ <p>HtmlGraph Cost Attribution Dashboard | Phase 1 MVP | <a href="https://code.claude.com">Claude Code</a></p>
692
+ </div>
693
+ </div>"""
694
+
695
+ def _html_scripts(self) -> str:
696
+ """Generate JavaScript for interactive charts."""
697
+ return """<script>
698
+ // Initialize charts when DOM is ready
699
+ document.addEventListener('DOMContentLoaded', function() {
700
+ const config = window.chartConfig || {
701
+ type_labels: [],
702
+ type_data: [],
703
+ tool_labels: [],
704
+ tool_data: []
705
+ };
706
+
707
+ // Chart.js configuration
708
+ const chartOptions = {
709
+ responsive: true,
710
+ maintainAspectRatio: true,
711
+ plugins: {
712
+ legend: {
713
+ labels: {
714
+ color: '#e0e0e0',
715
+ font: { size: 12 }
716
+ }
717
+ },
718
+ tooltip: {
719
+ backgroundColor: 'rgba(26, 26, 46, 0.8)',
720
+ titleColor: '#e0e0e0',
721
+ bodyColor: '#b0b0b0',
722
+ borderColor: '#0f3460',
723
+ borderWidth: 1
724
+ }
725
+ },
726
+ scales: {
727
+ y: {
728
+ ticks: { color: '#b0b0b0' },
729
+ grid: { color: '#16213e' }
730
+ },
731
+ x: {
732
+ ticks: { color: '#b0b0b0' },
733
+ grid: { color: '#16213e' }
734
+ }
735
+ }
736
+ };
737
+
738
+ // Pie chart - Cost by Violation Type
739
+ if (config.type_labels.length > 0) {
740
+ const ctxType = document.getElementById('chartByType');
741
+ if (ctxType) {
742
+ new Chart(ctxType, {
743
+ type: 'doughnut',
744
+ data: {
745
+ labels: config.type_labels,
746
+ datasets: [{
747
+ label: 'Waste Tokens',
748
+ data: config.type_data,
749
+ backgroundColor: [
750
+ '#e94560',
751
+ '#ff9800',
752
+ '#ff6f00',
753
+ '#d84315',
754
+ '#c62828'
755
+ ],
756
+ borderColor: '#1a1a2e',
757
+ borderWidth: 2
758
+ }]
759
+ },
760
+ options: {
761
+ ...chartOptions,
762
+ plugins: {
763
+ ...chartOptions.plugins,
764
+ legend: {
765
+ ...chartOptions.plugins.legend,
766
+ position: 'bottom'
767
+ }
768
+ }
769
+ }
770
+ });
771
+ }
772
+ }
773
+
774
+ // Bar chart - Cost by Tool
775
+ if (config.tool_labels.length > 0) {
776
+ const ctxTool = document.getElementById('chartByTool');
777
+ if (ctxTool) {
778
+ new Chart(ctxTool, {
779
+ type: 'bar',
780
+ data: {
781
+ labels: config.tool_labels,
782
+ datasets: [{
783
+ label: 'Waste Tokens',
784
+ data: config.tool_data,
785
+ backgroundColor: '#0f3460',
786
+ borderColor: '#e94560',
787
+ borderWidth: 2,
788
+ borderRadius: 4
789
+ }]
790
+ },
791
+ options: {
792
+ ...chartOptions,
793
+ indexAxis: 'y',
794
+ plugins: {
795
+ ...chartOptions.plugins,
796
+ legend: {
797
+ ...chartOptions.plugins.legend,
798
+ display: true
799
+ }
800
+ }
801
+ }
802
+ });
803
+ }
804
+ }
805
+ });
806
+ </script>"""
807
+
808
+ def _create_empty_summary(self) -> SessionViolationSummary:
809
+ """Create an empty violation summary for dashboard initialization."""
810
+ return SessionViolationSummary(
811
+ session_id="demo-session",
812
+ total_violations=0,
813
+ violations_by_type={},
814
+ total_waste_tokens=0,
815
+ circuit_breaker_triggered=False,
816
+ compliance_rate=1.0,
817
+ violations=[],
818
+ )