crca 1.4.0__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 (501) hide show
  1. .github/ISSUE_TEMPLATE/bug_report.md +65 -0
  2. .github/ISSUE_TEMPLATE/feature_request.md +41 -0
  3. .github/PULL_REQUEST_TEMPLATE.md +20 -0
  4. .github/workflows/publish-manual.yml +61 -0
  5. .github/workflows/publish.yml +64 -0
  6. .gitignore +214 -0
  7. CRCA.py +4156 -0
  8. LICENSE +201 -0
  9. MANIFEST.in +43 -0
  10. PKG-INFO +5035 -0
  11. README.md +4959 -0
  12. __init__.py +17 -0
  13. branches/CRCA-Q.py +2728 -0
  14. branches/crca_cg/corposwarm.py +9065 -0
  15. branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
  16. branches/crca_cg/package.json +5 -0
  17. branches/crca_cg/test_bolt_integration.py +446 -0
  18. branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
  19. branches/crca_cg/test_new_features.py +163 -0
  20. branches/crca_sd/__init__.py +149 -0
  21. branches/crca_sd/crca_sd_core.py +770 -0
  22. branches/crca_sd/crca_sd_governance.py +1325 -0
  23. branches/crca_sd/crca_sd_mpc.py +1130 -0
  24. branches/crca_sd/crca_sd_realtime.py +1844 -0
  25. branches/crca_sd/crca_sd_tui.py +1133 -0
  26. crca-1.4.0.dist-info/METADATA +5035 -0
  27. crca-1.4.0.dist-info/RECORD +501 -0
  28. crca-1.4.0.dist-info/WHEEL +4 -0
  29. crca-1.4.0.dist-info/licenses/LICENSE +201 -0
  30. docs/CRCA-Q.md +2333 -0
  31. examples/config.yaml.example +25 -0
  32. examples/crca_sd_example.py +513 -0
  33. examples/data_broker_example.py +294 -0
  34. examples/logistics_corporation.py +861 -0
  35. examples/palantir_example.py +299 -0
  36. examples/policy_bench.py +934 -0
  37. examples/pridnestrovia-sd.py +705 -0
  38. examples/pridnestrovia_realtime.py +1902 -0
  39. prompts/__init__.py +10 -0
  40. prompts/default_crca.py +101 -0
  41. pyproject.toml +151 -0
  42. requirements.txt +76 -0
  43. schemas/__init__.py +43 -0
  44. schemas/mcpSchemas.py +51 -0
  45. schemas/policy.py +458 -0
  46. templates/__init__.py +38 -0
  47. templates/base_specialized_agent.py +195 -0
  48. templates/drift_detection.py +325 -0
  49. templates/examples/causal_agent_template.py +309 -0
  50. templates/examples/drag_drop_example.py +213 -0
  51. templates/examples/logistics_agent_template.py +207 -0
  52. templates/examples/trading_agent_template.py +206 -0
  53. templates/feature_mixins.py +253 -0
  54. templates/graph_management.py +442 -0
  55. templates/llm_integration.py +194 -0
  56. templates/module_registry.py +276 -0
  57. templates/mpc_planner.py +280 -0
  58. templates/policy_loop.py +1168 -0
  59. templates/prediction_framework.py +448 -0
  60. templates/statistical_methods.py +778 -0
  61. tests/sanity.yml +31 -0
  62. tests/sanity_check +406 -0
  63. tests/test_core.py +47 -0
  64. tests/test_crca_excel.py +166 -0
  65. tests/test_crca_sd.py +780 -0
  66. tests/test_data_broker.py +424 -0
  67. tests/test_palantir.py +349 -0
  68. tools/__init__.py +38 -0
  69. tools/actuators.py +437 -0
  70. tools/bolt.diy/Dockerfile +103 -0
  71. tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
  72. tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
  73. tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
  74. tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
  75. tools/bolt.diy/app/components/@settings/index.ts +12 -0
  76. tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
  77. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
  78. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
  79. tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
  80. tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
  81. tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
  82. tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
  83. tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
  84. tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
  85. tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
  86. tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
  87. tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
  88. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
  89. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
  90. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
  91. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
  92. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
  93. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
  94. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
  95. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
  96. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
  97. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
  98. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
  99. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
  100. tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
  101. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
  102. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
  103. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
  104. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
  105. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
  106. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
  107. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
  108. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
  109. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
  110. tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
  111. tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
  112. tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
  113. tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
  114. tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
  115. tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
  116. tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
  117. tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
  118. tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
  119. tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
  120. tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
  121. tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
  122. tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
  123. tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
  124. tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
  125. tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
  126. tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
  127. tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
  128. tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
  129. tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
  130. tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
  131. tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
  132. tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
  133. tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
  134. tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
  135. tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
  136. tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
  137. tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
  138. tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
  139. tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
  140. tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
  141. tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
  142. tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
  143. tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
  144. tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
  145. tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
  146. tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
  147. tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
  148. tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
  149. tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
  150. tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
  151. tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
  152. tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
  153. tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
  154. tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
  155. tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
  156. tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
  157. tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
  158. tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
  159. tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
  160. tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
  161. tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
  162. tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
  163. tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
  164. tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
  165. tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
  166. tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
  167. tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
  168. tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
  169. tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
  170. tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
  171. tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
  172. tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
  173. tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
  174. tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
  175. tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
  176. tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
  177. tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
  178. tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
  179. tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
  180. tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
  181. tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
  182. tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
  183. tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
  184. tools/bolt.diy/app/components/header/Header.tsx +42 -0
  185. tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
  186. tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
  187. tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
  188. tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
  189. tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
  190. tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
  191. tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
  192. tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
  193. tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
  194. tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
  195. tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
  196. tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
  197. tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
  198. tools/bolt.diy/app/components/txt +1 -0
  199. tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
  200. tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
  201. tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
  202. tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
  203. tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
  204. tools/bolt.diy/app/components/ui/Button.tsx +46 -0
  205. tools/bolt.diy/app/components/ui/Card.tsx +55 -0
  206. tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
  207. tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
  208. tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
  209. tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
  210. tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
  211. tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
  212. tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
  213. tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
  214. tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
  215. tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
  216. tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
  217. tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
  218. tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
  219. tools/bolt.diy/app/components/ui/Input.tsx +22 -0
  220. tools/bolt.diy/app/components/ui/Label.tsx +20 -0
  221. tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
  222. tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
  223. tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
  224. tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
  225. tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
  226. tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
  227. tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
  228. tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
  229. tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
  230. tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
  231. tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
  232. tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
  233. tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
  234. tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
  235. tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
  236. tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
  237. tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
  238. tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
  239. tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
  240. tools/bolt.diy/app/components/ui/index.ts +38 -0
  241. tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
  242. tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
  243. tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
  244. tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
  245. tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
  246. tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
  247. tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
  248. tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
  249. tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
  250. tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
  251. tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
  252. tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
  253. tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
  254. tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
  255. tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
  256. tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
  257. tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
  258. tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
  259. tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
  260. tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
  261. tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
  262. tools/bolt.diy/app/entry.client.tsx +7 -0
  263. tools/bolt.diy/app/entry.server.tsx +80 -0
  264. tools/bolt.diy/app/root.tsx +156 -0
  265. tools/bolt.diy/app/routes/_index.tsx +175 -0
  266. tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
  267. tools/bolt.diy/app/routes/api.chat.ts +463 -0
  268. tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
  269. tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
  270. tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
  271. tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
  272. tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
  273. tools/bolt.diy/app/routes/api.git-info.ts +69 -0
  274. tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
  275. tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
  276. tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
  277. tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
  278. tools/bolt.diy/app/routes/api.github-template.ts +242 -0
  279. tools/bolt.diy/app/routes/api.github-user.ts +287 -0
  280. tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
  281. tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
  282. tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
  283. tools/bolt.diy/app/routes/api.health.ts +8 -0
  284. tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
  285. tools/bolt.diy/app/routes/api.mandate.ts +351 -0
  286. tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
  287. tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
  288. tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
  289. tools/bolt.diy/app/routes/api.models.ts +90 -0
  290. tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
  291. tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
  292. tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
  293. tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
  294. tools/bolt.diy/app/routes/api.supabase.ts +56 -0
  295. tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
  296. tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
  297. tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
  298. tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
  299. tools/bolt.diy/app/routes/api.update.ts +21 -0
  300. tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
  301. tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
  302. tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
  303. tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
  304. tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
  305. tools/bolt.diy/app/routes/git.tsx +25 -0
  306. tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
  307. tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
  308. tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
  309. tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
  310. tools/bolt.diy/app/styles/animations.scss +49 -0
  311. tools/bolt.diy/app/styles/components/code.scss +9 -0
  312. tools/bolt.diy/app/styles/components/editor.scss +135 -0
  313. tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
  314. tools/bolt.diy/app/styles/components/terminal.scss +3 -0
  315. tools/bolt.diy/app/styles/components/toast.scss +23 -0
  316. tools/bolt.diy/app/styles/diff-view.css +72 -0
  317. tools/bolt.diy/app/styles/index.scss +73 -0
  318. tools/bolt.diy/app/styles/variables.scss +255 -0
  319. tools/bolt.diy/app/styles/z-index.scss +37 -0
  320. tools/bolt.diy/app/types/GitHub.ts +182 -0
  321. tools/bolt.diy/app/types/GitLab.ts +103 -0
  322. tools/bolt.diy/app/types/actions.ts +85 -0
  323. tools/bolt.diy/app/types/artifact.ts +5 -0
  324. tools/bolt.diy/app/types/context.ts +26 -0
  325. tools/bolt.diy/app/types/design-scheme.ts +93 -0
  326. tools/bolt.diy/app/types/global.d.ts +13 -0
  327. tools/bolt.diy/app/types/mandate.ts +333 -0
  328. tools/bolt.diy/app/types/model.ts +25 -0
  329. tools/bolt.diy/app/types/netlify.ts +94 -0
  330. tools/bolt.diy/app/types/supabase.ts +54 -0
  331. tools/bolt.diy/app/types/template.ts +8 -0
  332. tools/bolt.diy/app/types/terminal.ts +9 -0
  333. tools/bolt.diy/app/types/theme.ts +1 -0
  334. tools/bolt.diy/app/types/vercel.ts +67 -0
  335. tools/bolt.diy/app/utils/buffer.ts +29 -0
  336. tools/bolt.diy/app/utils/classNames.ts +65 -0
  337. tools/bolt.diy/app/utils/constants.ts +147 -0
  338. tools/bolt.diy/app/utils/debounce.ts +13 -0
  339. tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
  340. tools/bolt.diy/app/utils/diff.spec.ts +11 -0
  341. tools/bolt.diy/app/utils/diff.ts +117 -0
  342. tools/bolt.diy/app/utils/easings.ts +3 -0
  343. tools/bolt.diy/app/utils/fileLocks.ts +96 -0
  344. tools/bolt.diy/app/utils/fileUtils.ts +121 -0
  345. tools/bolt.diy/app/utils/folderImport.ts +73 -0
  346. tools/bolt.diy/app/utils/formatSize.ts +12 -0
  347. tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
  348. tools/bolt.diy/app/utils/githubStats.ts +9 -0
  349. tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
  350. tools/bolt.diy/app/utils/logger.ts +162 -0
  351. tools/bolt.diy/app/utils/markdown.ts +155 -0
  352. tools/bolt.diy/app/utils/mobile.ts +4 -0
  353. tools/bolt.diy/app/utils/os.ts +4 -0
  354. tools/bolt.diy/app/utils/path.ts +19 -0
  355. tools/bolt.diy/app/utils/projectCommands.ts +197 -0
  356. tools/bolt.diy/app/utils/promises.ts +19 -0
  357. tools/bolt.diy/app/utils/react.ts +6 -0
  358. tools/bolt.diy/app/utils/sampler.ts +49 -0
  359. tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
  360. tools/bolt.diy/app/utils/shell.ts +384 -0
  361. tools/bolt.diy/app/utils/stacktrace.ts +27 -0
  362. tools/bolt.diy/app/utils/stripIndent.ts +23 -0
  363. tools/bolt.diy/app/utils/terminal.ts +11 -0
  364. tools/bolt.diy/app/utils/unreachable.ts +3 -0
  365. tools/bolt.diy/app/vite-env.d.ts +2 -0
  366. tools/bolt.diy/assets/entitlements.mac.plist +25 -0
  367. tools/bolt.diy/assets/icons/icon.icns +0 -0
  368. tools/bolt.diy/assets/icons/icon.ico +0 -0
  369. tools/bolt.diy/assets/icons/icon.png +0 -0
  370. tools/bolt.diy/bindings.js +78 -0
  371. tools/bolt.diy/bindings.sh +33 -0
  372. tools/bolt.diy/docker-compose.yaml +145 -0
  373. tools/bolt.diy/electron/main/index.ts +201 -0
  374. tools/bolt.diy/electron/main/tsconfig.json +30 -0
  375. tools/bolt.diy/electron/main/ui/menu.ts +29 -0
  376. tools/bolt.diy/electron/main/ui/window.ts +54 -0
  377. tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
  378. tools/bolt.diy/electron/main/utils/constants.ts +4 -0
  379. tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
  380. tools/bolt.diy/electron/main/utils/reload.ts +35 -0
  381. tools/bolt.diy/electron/main/utils/serve.ts +71 -0
  382. tools/bolt.diy/electron/main/utils/store.ts +3 -0
  383. tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
  384. tools/bolt.diy/electron/main/vite.config.ts +44 -0
  385. tools/bolt.diy/electron/preload/index.ts +22 -0
  386. tools/bolt.diy/electron/preload/tsconfig.json +7 -0
  387. tools/bolt.diy/electron/preload/vite.config.ts +31 -0
  388. tools/bolt.diy/electron-builder.yml +64 -0
  389. tools/bolt.diy/electron-update.yml +4 -0
  390. tools/bolt.diy/eslint.config.mjs +57 -0
  391. tools/bolt.diy/functions/[[path]].ts +12 -0
  392. tools/bolt.diy/icons/angular.svg +1 -0
  393. tools/bolt.diy/icons/astro.svg +8 -0
  394. tools/bolt.diy/icons/chat.svg +1 -0
  395. tools/bolt.diy/icons/expo-brand.svg +1 -0
  396. tools/bolt.diy/icons/expo.svg +4 -0
  397. tools/bolt.diy/icons/logo-text.svg +1 -0
  398. tools/bolt.diy/icons/logo.svg +4 -0
  399. tools/bolt.diy/icons/mcp.svg +1 -0
  400. tools/bolt.diy/icons/nativescript.svg +1 -0
  401. tools/bolt.diy/icons/netlify.svg +10 -0
  402. tools/bolt.diy/icons/nextjs.svg +1 -0
  403. tools/bolt.diy/icons/nuxt.svg +1 -0
  404. tools/bolt.diy/icons/qwik.svg +1 -0
  405. tools/bolt.diy/icons/react.svg +1 -0
  406. tools/bolt.diy/icons/remix.svg +24 -0
  407. tools/bolt.diy/icons/remotion.svg +1 -0
  408. tools/bolt.diy/icons/shadcn.svg +21 -0
  409. tools/bolt.diy/icons/slidev.svg +60 -0
  410. tools/bolt.diy/icons/solidjs.svg +1 -0
  411. tools/bolt.diy/icons/stars.svg +1 -0
  412. tools/bolt.diy/icons/svelte.svg +1 -0
  413. tools/bolt.diy/icons/typescript.svg +1 -0
  414. tools/bolt.diy/icons/vite.svg +1 -0
  415. tools/bolt.diy/icons/vue.svg +1 -0
  416. tools/bolt.diy/load-context.ts +9 -0
  417. tools/bolt.diy/notarize.cjs +31 -0
  418. tools/bolt.diy/package.json +218 -0
  419. tools/bolt.diy/playwright.config.preview.ts +35 -0
  420. tools/bolt.diy/pre-start.cjs +26 -0
  421. tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
  422. tools/bolt.diy/public/apple-touch-icon.png +0 -0
  423. tools/bolt.diy/public/favicon.ico +0 -0
  424. tools/bolt.diy/public/favicon.svg +4 -0
  425. tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
  426. tools/bolt.diy/public/icons/Anthropic.svg +4 -0
  427. tools/bolt.diy/public/icons/Cohere.svg +4 -0
  428. tools/bolt.diy/public/icons/Deepseek.svg +5 -0
  429. tools/bolt.diy/public/icons/Default.svg +4 -0
  430. tools/bolt.diy/public/icons/Google.svg +4 -0
  431. tools/bolt.diy/public/icons/Groq.svg +4 -0
  432. tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
  433. tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
  434. tools/bolt.diy/public/icons/LMStudio.svg +5 -0
  435. tools/bolt.diy/public/icons/Mistral.svg +4 -0
  436. tools/bolt.diy/public/icons/Ollama.svg +4 -0
  437. tools/bolt.diy/public/icons/OpenAI.svg +4 -0
  438. tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
  439. tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
  440. tools/bolt.diy/public/icons/Perplexity.svg +4 -0
  441. tools/bolt.diy/public/icons/Together.svg +4 -0
  442. tools/bolt.diy/public/icons/xAI.svg +5 -0
  443. tools/bolt.diy/public/inspector-script.js +292 -0
  444. tools/bolt.diy/public/logo-dark-styled.png +0 -0
  445. tools/bolt.diy/public/logo-dark.png +0 -0
  446. tools/bolt.diy/public/logo-light-styled.png +0 -0
  447. tools/bolt.diy/public/logo-light.png +0 -0
  448. tools/bolt.diy/public/logo.svg +15 -0
  449. tools/bolt.diy/public/social_preview_index.jpg +0 -0
  450. tools/bolt.diy/scripts/clean.js +45 -0
  451. tools/bolt.diy/scripts/electron-dev.mjs +181 -0
  452. tools/bolt.diy/scripts/setup-env.sh +41 -0
  453. tools/bolt.diy/scripts/update-imports.sh +7 -0
  454. tools/bolt.diy/scripts/update.sh +52 -0
  455. tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
  456. tools/bolt.diy/services/execution-governor/config.ts +42 -0
  457. tools/bolt.diy/services/execution-governor/index.ts +683 -0
  458. tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
  459. tools/bolt.diy/services/execution-governor/package.json +31 -0
  460. tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
  461. tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
  462. tools/bolt.diy/services/execution-governor/types.ts +145 -0
  463. tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
  464. tools/bolt.diy/services/headless-executor/executor.ts +210 -0
  465. tools/bolt.diy/services/headless-executor/index.ts +323 -0
  466. tools/bolt.diy/services/headless-executor/package.json +27 -0
  467. tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
  468. tools/bolt.diy/services/headless-executor/types.ts +38 -0
  469. tools/bolt.diy/test-workflows.sh +240 -0
  470. tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
  471. tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
  472. tools/bolt.diy/tests/mandates/complex.json +53 -0
  473. tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
  474. tools/bolt.diy/tests/mandates/simple.json +35 -0
  475. tools/bolt.diy/tsconfig.json +37 -0
  476. tools/bolt.diy/types/istextorbinary.d.ts +15 -0
  477. tools/bolt.diy/uno.config.ts +279 -0
  478. tools/bolt.diy/vite-electron.config.ts +76 -0
  479. tools/bolt.diy/vite.config.ts +112 -0
  480. tools/bolt.diy/worker-configuration.d.ts +22 -0
  481. tools/bolt.diy/wrangler.toml +6 -0
  482. tools/code_generator.py +461 -0
  483. tools/file_operations.py +465 -0
  484. tools/mandate_generator.py +337 -0
  485. tools/mcpClientUtils.py +1216 -0
  486. tools/sensors.py +285 -0
  487. utils/Agent_types.py +15 -0
  488. utils/AnyToStr.py +0 -0
  489. utils/HHCS.py +277 -0
  490. utils/__init__.py +30 -0
  491. utils/agent.py +3627 -0
  492. utils/aop.py +2948 -0
  493. utils/canonical.py +143 -0
  494. utils/conversation.py +1195 -0
  495. utils/doctrine_versioning +230 -0
  496. utils/formatter.py +474 -0
  497. utils/ledger.py +311 -0
  498. utils/out_types.py +16 -0
  499. utils/rollback.py +339 -0
  500. utils/router.py +929 -0
  501. utils/tui.py +1908 -0
@@ -0,0 +1,1325 @@
1
+ """
2
+ CRCA-SD Governance: Boards, Logistics, Visualization, Config, Metrics
3
+
4
+ This module implements:
5
+ - Board-of-agents governance (adapted from CorporateSwarm)
6
+ - Multi-board arbitration with weighted voting
7
+ - Logistics network optimization
8
+ - Visualization and dashboard
9
+ - Configuration management (Pydantic + YAML)
10
+ - Risk assessment
11
+ - Metrics collection
12
+
13
+ Incorporates patterns from CorporateSwarm for board structure, voting, and config management.
14
+ """
15
+
16
+ from typing import Dict, List, Optional, Tuple, Any, Union
17
+ import numpy as np
18
+ from dataclasses import dataclass, field
19
+ from enum import Enum
20
+ from functools import lru_cache
21
+ import time
22
+ import uuid
23
+ import os
24
+ from datetime import datetime
25
+ from loguru import logger
26
+
27
+ try:
28
+ import yaml
29
+ YAML_AVAILABLE = True
30
+ except ImportError:
31
+ YAML_AVAILABLE = False
32
+ logger.warning("yaml not available, config file loading disabled")
33
+
34
+ try:
35
+ from pydantic import BaseModel, Field
36
+ PYDANTIC_AVAILABLE = True
37
+ except ImportError:
38
+ PYDANTIC_AVAILABLE = False
39
+ logger.warning("pydantic not available, using dataclass fallback")
40
+
41
+ try:
42
+ import cvxpy as cp
43
+ import networkx as nx
44
+ CVXPY_AVAILABLE = True
45
+ NETWORKX_AVAILABLE = True
46
+ except ImportError:
47
+ CVXPY_AVAILABLE = False
48
+ NETWORKX_AVAILABLE = False
49
+ logger.warning("cvxpy/networkx not available, logistics optimization limited")
50
+
51
+ from crca_sd.crca_sd_core import StateVector, ControlVector
52
+ from crca_sd.crca_sd_mpc import ObjectiveVector
53
+
54
+
55
+ def _generate_uuid() -> str:
56
+ """Generate a new UUID string."""
57
+ return str(uuid.uuid4())
58
+
59
+
60
+ class BoardType(str, Enum):
61
+ """Types of governance boards."""
62
+ GROWTH = "growth"
63
+ WELFARE = "welfare"
64
+ SUSTAINABILITY = "sustainability"
65
+ STABILITY = "stability"
66
+
67
+
68
+ class VoteResult(str, Enum):
69
+ """Voting result outcomes (from CorporateSwarm pattern)."""
70
+ APPROVED = "approved"
71
+ REJECTED = "rejected"
72
+ TABLED = "tabled"
73
+ FAILED = "failed"
74
+ UNANIMOUS = "unanimous"
75
+ MAJORITY = "majority"
76
+ MINORITY = "minority"
77
+ ABSTAINED = "abstained"
78
+
79
+
80
+ # BoardMember: Adapted from CorporateMember (lines 353-369 in CorporateSwarm)
81
+ if PYDANTIC_AVAILABLE:
82
+ class BoardMember(BaseModel):
83
+ """Board member with role, expertise, and objective preferences."""
84
+
85
+ member_id: str = Field(default_factory=_generate_uuid)
86
+ name: str = Field(default="")
87
+ board_type: BoardType = Field(default=BoardType.GROWTH)
88
+ expertise_areas: List[str] = Field(default_factory=list)
89
+ voting_weight: float = Field(default=1.0, ge=0.0, le=5.0)
90
+ preferences: Dict[str, float] = Field(default_factory=dict) # Objective weights
91
+ independence_status: bool = Field(default=False)
92
+ metadata: Dict[str, Any] = Field(default_factory=dict)
93
+ else:
94
+ @dataclass
95
+ class BoardMember:
96
+ """Board member with role, expertise, and objective preferences."""
97
+ member_id: str = field(default_factory=_generate_uuid)
98
+ name: str = ""
99
+ board_type: BoardType = BoardType.GROWTH
100
+ expertise_areas: List[str] = field(default_factory=list)
101
+ voting_weight: float = 1.0
102
+ preferences: Dict[str, float] = field(default_factory=dict)
103
+ independence_status: bool = False
104
+ metadata: Dict[str, Any] = field(default_factory=dict)
105
+
106
+
107
+ class Board:
108
+ """
109
+ Governance board with members and objective priorities.
110
+
111
+ Inspired by CorporateSwarm board structure.
112
+ Each board type has different objective priorities:
113
+ - Growth: Prioritizes Y (output), then U (unemployment)
114
+ - Welfare: Prioritizes U (unemployment), inequality, literacy
115
+ - Sustainability: Prioritizes C (ecological damage), long-term resilience
116
+ - Stability: Prioritizes low variance, low CVaR
117
+
118
+ Args:
119
+ board_id: Unique board identifier
120
+ board_type: Type of board
121
+ members: List of board members
122
+ """
123
+
124
+ def __init__(
125
+ self,
126
+ board_id: str,
127
+ board_type: BoardType,
128
+ members: List[BoardMember]
129
+ ) -> None:
130
+ """Initialize board."""
131
+ self.board_id = board_id
132
+ self.board_type = board_type
133
+ self.members = members
134
+
135
+ def get_preference_weights(self) -> Dict[str, float]:
136
+ """
137
+ Get objective weight vector for this board type.
138
+
139
+ Returns:
140
+ Dict[str, float]: Mapping from objective names to weights
141
+ """
142
+ if self.board_type == BoardType.GROWTH:
143
+ return {
144
+ "J_U": 0.2, # Unemployment
145
+ "J_ℓ": 0.1, # Literacy
146
+ "J_Y": 0.5, # Output (high priority)
147
+ "J_ineq": 0.1, # Inequality
148
+ "J_C": 0.05, # Ecological damage
149
+ "J_risk": 0.05, # Risk
150
+ }
151
+ elif self.board_type == BoardType.WELFARE:
152
+ return {
153
+ "J_U": 0.4, # Unemployment (high priority)
154
+ "J_ℓ": 0.3, # Literacy (high priority)
155
+ "J_Y": 0.1, # Output
156
+ "J_ineq": 0.15, # Inequality (high priority)
157
+ "J_C": 0.03, # Ecological damage
158
+ "J_risk": 0.02, # Risk
159
+ }
160
+ elif self.board_type == BoardType.SUSTAINABILITY:
161
+ return {
162
+ "J_U": 0.1, # Unemployment
163
+ "J_ℓ": 0.1, # Literacy
164
+ "J_Y": 0.1, # Output
165
+ "J_ineq": 0.1, # Inequality
166
+ "J_C": 0.5, # Ecological damage (high priority)
167
+ "J_risk": 0.1, # Risk
168
+ }
169
+ elif self.board_type == BoardType.STABILITY:
170
+ return {
171
+ "J_U": 0.2, # Unemployment
172
+ "J_ℓ": 0.1, # Literacy
173
+ "J_Y": 0.1, # Output
174
+ "J_ineq": 0.1, # Inequality
175
+ "J_C": 0.1, # Ecological damage
176
+ "J_risk": 0.4, # Risk (high priority)
177
+ }
178
+ else:
179
+ # Default: equal weights
180
+ return {f"J_{i}": 1.0/6 for i in ["U", "ℓ", "Y", "ineq", "C", "risk"]}
181
+
182
+ def evaluate_policies(
183
+ self,
184
+ policies: List[ControlVector],
185
+ objectives: np.ndarray
186
+ ) -> List[Tuple[ControlVector, float]]:
187
+ """
188
+ Rank policies by board's objective priorities.
189
+
190
+ Args:
191
+ policies: List of candidate policies
192
+ objectives: Objective matrix (n_policies x n_objectives)
193
+
194
+ Returns:
195
+ List[Tuple[ControlVector, float]]: Ranked policies with scores
196
+ """
197
+ if len(policies) == 0:
198
+ return []
199
+
200
+ if objectives.ndim == 1:
201
+ objectives = objectives.reshape(1, -1)
202
+
203
+ # Get board preference weights
204
+ weights = self.get_preference_weights()
205
+ weight_vec = np.array([
206
+ weights.get("J_U", 0.0),
207
+ weights.get("J_ℓ", 0.0),
208
+ weights.get("J_Y", 0.0),
209
+ weights.get("J_ineq", 0.0),
210
+ weights.get("J_C", 0.0),
211
+ weights.get("J_risk", 0.0),
212
+ ])
213
+
214
+ # Normalize weights
215
+ if weight_vec.sum() > 0:
216
+ weight_vec = weight_vec / weight_vec.sum()
217
+
218
+ # Compute weighted scores
219
+ scores = objectives @ weight_vec
220
+
221
+ # Rank policies (lower score = better for minimization)
222
+ ranked = list(zip(policies, scores))
223
+ ranked.sort(key=lambda x: x[1])
224
+
225
+ return ranked
226
+
227
+
228
+ class Arbitration:
229
+ """
230
+ Multi-board arbitration using weighted voting.
231
+
232
+ Adapted from CorporateSwarm's _analyze_vote_results pattern (lines 2026-2062).
233
+ Implements multiple arbitration methods:
234
+ - Pareto intersection
235
+ - Minimax regret
236
+ - Borda voting
237
+ - Weighted voting
238
+ """
239
+
240
+ @staticmethod
241
+ def pareto_intersection(
242
+ boards: List[Board],
243
+ policies: List[ControlVector],
244
+ objectives: np.ndarray
245
+ ) -> List[ControlVector]:
246
+ """
247
+ Find policies that are non-dominated under all boards.
248
+
249
+ Args:
250
+ boards: List of boards
251
+ policies: Candidate policies
252
+ objectives: Objective matrix
253
+
254
+ Returns:
255
+ List[ControlVector]: Consensus policies
256
+ """
257
+ if not boards or not policies:
258
+ return []
259
+
260
+ # Get Pareto-efficient policies for each board
261
+ board_pareto_sets = []
262
+ for board in boards:
263
+ ranked = board.evaluate_policies(policies, objectives)
264
+ # Take top 50% as "preferred"
265
+ n_top = max(1, len(ranked) // 2)
266
+ top_policies = [p for p, _ in ranked[:n_top]]
267
+ board_pareto_sets.append(set(id(p) for p in top_policies))
268
+
269
+ # Intersection: policies preferred by all boards
270
+ consensus_ids = set.intersection(*board_pareto_sets) if board_pareto_sets else set()
271
+ consensus_policies = [p for p in policies if id(p) in consensus_ids]
272
+
273
+ return consensus_policies
274
+
275
+ @staticmethod
276
+ def minimax_regret(
277
+ boards: List[Board],
278
+ policies: List[ControlVector],
279
+ objectives: np.ndarray
280
+ ) -> Optional[ControlVector]:
281
+ """
282
+ Minimize worst-case regret across boards.
283
+
284
+ Args:
285
+ boards: List of boards
286
+ policies: Candidate policies
287
+ objectives: Objective matrix
288
+
289
+ Returns:
290
+ Optional[ControlVector]: Optimal policy
291
+ """
292
+ if not boards or not policies:
293
+ return None
294
+
295
+ # For each board, find best policy
296
+ board_best_scores = []
297
+ for board in boards:
298
+ ranked = board.evaluate_policies(policies, objectives)
299
+ if ranked:
300
+ best_score = ranked[0][1] # Best score for this board
301
+ board_best_scores.append(best_score)
302
+
303
+ # For each policy, compute maximum regret
304
+ max_regrets = []
305
+ for i, policy in enumerate(policies):
306
+ regrets = []
307
+ for j, board in enumerate(boards):
308
+ ranked = board.evaluate_policies(policies, objectives)
309
+ policy_score = next((s for p, s in ranked if p is policy), float('inf'))
310
+ regret = policy_score - board_best_scores[j]
311
+ regrets.append(regret)
312
+ max_regrets.append(max(regrets))
313
+
314
+ # Policy with minimum maximum regret
315
+ min_regret_idx = np.argmin(max_regrets)
316
+ return policies[min_regret_idx]
317
+
318
+ @staticmethod
319
+ def borda_vote(
320
+ boards: List[Board],
321
+ policies: List[ControlVector],
322
+ objectives: np.ndarray
323
+ ) -> Optional[ControlVector]:
324
+ """
325
+ Borda count aggregation across boards.
326
+
327
+ Args:
328
+ boards: List of boards
329
+ policies: Candidate policies
330
+ objectives: Objective matrix
331
+
332
+ Returns:
333
+ Optional[ControlVector]: Selected policy
334
+ """
335
+ if not boards or not policies:
336
+ return None
337
+
338
+ # Borda scores: rank 0 gets n-1 points, rank 1 gets n-2, etc.
339
+ borda_scores = {id(p): 0.0 for p in policies}
340
+
341
+ for board in boards:
342
+ ranked = board.evaluate_policies(policies, objectives)
343
+ n = len(ranked)
344
+ for rank, (policy, _) in enumerate(ranked):
345
+ borda_scores[id(policy)] += (n - rank - 1) * board.members[0].voting_weight if board.members else (n - rank - 1)
346
+
347
+ # Policy with highest Borda score
348
+ best_policy_id = max(borda_scores, key=borda_scores.get)
349
+ return next(p for p in policies if id(p) == best_policy_id)
350
+
351
+ @staticmethod
352
+ def weighted_vote(
353
+ boards: List[Board],
354
+ policies: List[ControlVector],
355
+ objectives: np.ndarray
356
+ ) -> Optional[ControlVector]:
357
+ """
358
+ Weighted voting using CorporateSwarm's _analyze_vote_results pattern.
359
+
360
+ Adapted from CorporateSwarm lines 2026-2062.
361
+
362
+ Args:
363
+ boards: List of boards
364
+ policies: Candidate policies
365
+ objectives: Objective matrix
366
+
367
+ Returns:
368
+ Optional[ControlVector]: Selected policy
369
+ """
370
+ if not boards or not policies:
371
+ return None
372
+
373
+ # Collect individual "votes" from each board
374
+ individual_votes: Dict[str, Dict[str, Any]] = {}
375
+
376
+ for board in boards:
377
+ ranked = board.evaluate_policies(policies, objectives)
378
+ if not ranked:
379
+ continue
380
+
381
+ # Board votes for top policy
382
+ top_policy, top_score = ranked[0]
383
+
384
+ # Compute board voting weight (sum of member weights)
385
+ board_weight = sum(m.voting_weight for m in board.members)
386
+
387
+ individual_votes[board.board_id] = {
388
+ "vote": "APPROVE" if top_score < float('inf') else "REJECT",
389
+ "policy": top_policy,
390
+ "score": top_score,
391
+ "voting_weight": board_weight,
392
+ "board_type": board.board_type.value,
393
+ }
394
+
395
+ if not individual_votes:
396
+ return None
397
+
398
+ # Aggregate votes by policy (weighted)
399
+ policy_scores: Dict[int, float] = {} # policy_id -> weighted score
400
+
401
+ for vote_data in individual_votes.values():
402
+ policy = vote_data["policy"]
403
+ weight = vote_data["voting_weight"]
404
+ score = vote_data["score"]
405
+
406
+ policy_id = id(policy)
407
+ if policy_id not in policy_scores:
408
+ policy_scores[policy_id] = 0.0
409
+
410
+ # Lower score is better, so we use negative for voting
411
+ policy_scores[policy_id] += weight / (1.0 + abs(score))
412
+
413
+ # Policy with highest weighted score
414
+ if not policy_scores:
415
+ return None
416
+
417
+ best_policy_id = max(policy_scores, key=policy_scores.get)
418
+ return next(p for p in policies if id(p) == best_policy_id)
419
+
420
+
421
+ class GovernanceSystem:
422
+ """
423
+ Governance system orchestrating boards and arbitration.
424
+
425
+ Pattern similar to CorporateSwarm's conduct_corporate_vote (lines 1035-1057).
426
+
427
+ Args:
428
+ boards: List of governance boards
429
+ arbitration_method: Method for policy selection
430
+ """
431
+
432
+ def __init__(
433
+ self,
434
+ boards: List[Board],
435
+ arbitration_method: str = "weighted_vote",
436
+ major_change_threshold: float = 0.10, # 10% = major change
437
+ ) -> None:
438
+ """Initialize governance system."""
439
+ self.boards = boards
440
+ self.arbitration_method = arbitration_method
441
+ self.major_change_threshold = major_change_threshold
442
+ self.pending_approvals: Dict[str, Dict[str, Any]] = {}
443
+ self.approval_history: List[Dict[str, Any]] = []
444
+ self.emergency_stop_active = False
445
+
446
+ def select_policy(
447
+ self,
448
+ candidate_policies: List[ControlVector],
449
+ objectives: np.ndarray
450
+ ) -> Optional[ControlVector]:
451
+ """
452
+ Select final policy using arbitration method.
453
+
454
+ Args:
455
+ candidate_policies: List of candidate policies
456
+ objectives: Objective matrix
457
+
458
+ Returns:
459
+ Optional[ControlVector]: Selected policy
460
+ """
461
+ if not candidate_policies:
462
+ return None
463
+
464
+ if self.arbitration_method == "pareto_intersection":
465
+ consensus = Arbitration.pareto_intersection(self.boards, candidate_policies, objectives)
466
+ return consensus[0] if consensus else None
467
+
468
+ elif self.arbitration_method == "minimax_regret":
469
+ return Arbitration.minimax_regret(self.boards, candidate_policies, objectives)
470
+
471
+ elif self.arbitration_method == "borda":
472
+ return Arbitration.borda_vote(self.boards, candidate_policies, objectives)
473
+
474
+ elif self.arbitration_method == "weighted_vote":
475
+ return Arbitration.weighted_vote(self.boards, candidate_policies, objectives)
476
+
477
+ else:
478
+ logger.warning(f"Unknown arbitration method: {self.arbitration_method}, using weighted_vote")
479
+ return Arbitration.weighted_vote(self.boards, candidate_policies, objectives)
480
+
481
+ def requires_approval(
482
+ self,
483
+ policy: ControlVector,
484
+ previous_policy: Optional[ControlVector]
485
+ ) -> Tuple[bool, str]:
486
+ """
487
+ Check if policy requires human approval (major change > 10%).
488
+
489
+ Args:
490
+ policy: Proposed policy
491
+ previous_policy: Previous policy (None if first)
492
+
493
+ Returns:
494
+ Tuple[bool, str]: (requires_approval, reason)
495
+ """
496
+ if self.emergency_stop_active:
497
+ return True, "Emergency stop active"
498
+
499
+ if previous_policy is None:
500
+ return True, "First policy requires approval"
501
+
502
+ # Check if major change (> 10% in any category)
503
+ for cat in set(list(policy.budget_shares.keys()) + list(previous_policy.budget_shares.keys())):
504
+ prev_val = previous_policy.budget_shares.get(cat, 0.0)
505
+ curr_val = policy.budget_shares.get(cat, 0.0)
506
+ change = abs(curr_val - prev_val)
507
+
508
+ if change > self.major_change_threshold:
509
+ return True, f"Major change in {cat}: {change:.1%} > {self.major_change_threshold:.1%}"
510
+
511
+ return False, "Minor change, automated execution allowed"
512
+
513
+ def request_approval(
514
+ self,
515
+ policy: ControlVector,
516
+ reason: str,
517
+ user_id: str,
518
+ objectives: Optional[np.ndarray] = None
519
+ ) -> str:
520
+ """
521
+ Request human approval for a policy.
522
+
523
+ Args:
524
+ policy: Policy requiring approval
525
+ reason: Reason for approval request
526
+ user_id: User requesting approval
527
+ objectives: Optional objective values for context
528
+
529
+ Returns:
530
+ str: Approval request ID
531
+ """
532
+ approval_id = str(uuid.uuid4())
533
+
534
+ self.pending_approvals[approval_id] = {
535
+ "approval_id": approval_id,
536
+ "policy": policy,
537
+ "reason": reason,
538
+ "requested_by": user_id,
539
+ "objectives": objectives.tolist() if objectives is not None else None,
540
+ "timestamp": time.time(),
541
+ "status": "pending",
542
+ "approved_by": [],
543
+ }
544
+
545
+ logger.info(f"Approval requested: {approval_id} by {user_id} - {reason}")
546
+
547
+ return approval_id
548
+
549
+ def approve_policy(
550
+ self,
551
+ approval_id: str,
552
+ user_id: str,
553
+ comment: Optional[str] = None
554
+ ) -> Tuple[bool, str]:
555
+ """
556
+ Approve a pending policy.
557
+
558
+ Args:
559
+ approval_id: Approval request ID
560
+ user_id: User approving
561
+ comment: Optional comment
562
+
563
+ Returns:
564
+ Tuple[bool, str]: (success, message)
565
+ """
566
+ if approval_id not in self.pending_approvals:
567
+ return False, "Approval request not found"
568
+
569
+ approval = self.pending_approvals[approval_id]
570
+
571
+ if approval["status"] != "pending":
572
+ return False, f"Approval already {approval['status']}"
573
+
574
+ approval["approved_by"].append(user_id)
575
+ approval["status"] = "approved"
576
+ approval["approval_comment"] = comment
577
+
578
+ # Move to history
579
+ self.approval_history.append(approval.copy())
580
+ del self.pending_approvals[approval_id]
581
+
582
+ logger.info(f"Policy approved: {approval_id} by {user_id}")
583
+
584
+ return True, "Policy approved"
585
+
586
+ def reject_policy(
587
+ self,
588
+ approval_id: str,
589
+ user_id: str,
590
+ reason: str
591
+ ) -> Tuple[bool, str]:
592
+ """
593
+ Reject a pending policy.
594
+
595
+ Args:
596
+ approval_id: Approval request ID
597
+ user_id: User rejecting
598
+ reason: Rejection reason
599
+
600
+ Returns:
601
+ Tuple[bool, str]: (success, message)
602
+ """
603
+ if approval_id not in self.pending_approvals:
604
+ return False, "Approval request not found"
605
+
606
+ approval = self.pending_approvals[approval_id]
607
+ approval["status"] = "rejected"
608
+ approval["rejected_by"] = user_id
609
+ approval["rejection_reason"] = reason
610
+
611
+ # Move to history
612
+ self.approval_history.append(approval.copy())
613
+ del self.pending_approvals[approval_id]
614
+
615
+ logger.info(f"Policy rejected: {approval_id} by {user_id} - {reason}")
616
+
617
+ return True, "Policy rejected"
618
+
619
+ def override_policy(
620
+ self,
621
+ policy: ControlVector,
622
+ user_id: str,
623
+ reason: str
624
+ ) -> Tuple[bool, str]:
625
+ """
626
+ Override automated decision with manual policy.
627
+
628
+ Args:
629
+ policy: Override policy
630
+ user_id: User overriding
631
+ reason: Reason for override
632
+
633
+ Returns:
634
+ Tuple[bool, str]: (success, message)
635
+ """
636
+ override_id = str(uuid.uuid4())
637
+
638
+ override_entry = {
639
+ "override_id": override_id,
640
+ "policy": policy,
641
+ "user_id": user_id,
642
+ "reason": reason,
643
+ "timestamp": time.time(),
644
+ }
645
+
646
+ self.approval_history.append(override_entry)
647
+
648
+ logger.warning(f"Policy override: {override_id} by {user_id} - {reason}")
649
+
650
+ return True, f"Override executed: {override_id}"
651
+
652
+ def emergency_stop(self, user_id: str, reason: str) -> None:
653
+ """
654
+ Activate emergency stop (halt all automation).
655
+
656
+ Args:
657
+ user_id: User activating emergency stop
658
+ reason: Reason for emergency stop
659
+ """
660
+ self.emergency_stop_active = True
661
+
662
+ logger.critical(f"EMERGENCY STOP activated by {user_id}: {reason}")
663
+
664
+ def resume_operations(self, user_id: str) -> None:
665
+ """
666
+ Resume operations after emergency stop.
667
+
668
+ Args:
669
+ user_id: User resuming operations
670
+ """
671
+ self.emergency_stop_active = False
672
+
673
+ logger.info(f"Operations resumed by {user_id}")
674
+
675
+ def get_pending_approvals(self) -> List[Dict[str, Any]]:
676
+ """Get list of pending approvals."""
677
+ return list(self.pending_approvals.values())
678
+
679
+
680
+ # RiskAssessment: Adapted from CorporateSwarm (lines 427-440)
681
+ if PYDANTIC_AVAILABLE:
682
+ class RiskAssessment(BaseModel):
683
+ """Risk assessment model for constraint violations."""
684
+
685
+ risk_id: str = Field(default_factory=_generate_uuid)
686
+ risk_category: str = Field(default="constraint_violation")
687
+ risk_level: str = Field(default="medium")
688
+ probability: float = Field(default=0.5, ge=0.0, le=1.0)
689
+ impact: float = Field(default=0.5, ge=0.0, le=1.0)
690
+ risk_score: float = Field(default=0.25, ge=0.0, le=1.0)
691
+ mitigation_strategies: List[str] = Field(default_factory=list)
692
+ owner: str = Field(default="")
693
+ status: str = Field(default="active")
694
+ last_reviewed: float = Field(default_factory=time.time)
695
+ else:
696
+ @dataclass
697
+ class RiskAssessment:
698
+ """Risk assessment model for constraint violations."""
699
+ risk_id: str = field(default_factory=_generate_uuid)
700
+ risk_category: str = "constraint_violation"
701
+ risk_level: str = "medium"
702
+ probability: float = 0.5
703
+ impact: float = 0.5
704
+ risk_score: float = 0.25
705
+ mitigation_strategies: List[str] = field(default_factory=list)
706
+ owner: str = ""
707
+ status: str = "active"
708
+ last_reviewed: float = field(default_factory=time.time)
709
+
710
+
711
+ class LogisticsNetwork:
712
+ """
713
+ Multi-commodity flow optimization network.
714
+
715
+ Graph G=(V,E) with nodes (regions, ports, warehouses) and edges (transport links).
716
+ Solves linear program for optimal flow allocation.
717
+
718
+ Args:
719
+ nodes: List of node identifiers
720
+ edges: List of (source, target) edge tuples
721
+ capacities: Dictionary mapping edges to capacities
722
+ costs: Dictionary mapping edges to transport costs
723
+ """
724
+
725
+ def __init__(
726
+ self,
727
+ nodes: List[str],
728
+ edges: List[Tuple[str, str]],
729
+ capacities: Optional[Dict[Tuple[str, str], float]] = None,
730
+ costs: Optional[Dict[Tuple[str, str], float]] = None,
731
+ ) -> None:
732
+ """Initialize logistics network."""
733
+ self.nodes = nodes
734
+ self.edges = edges
735
+ self.capacities = capacities or {}
736
+ self.costs = costs or {}
737
+
738
+ if NETWORKX_AVAILABLE:
739
+ self.graph = nx.DiGraph()
740
+ self.graph.add_nodes_from(nodes)
741
+ self.graph.add_edges_from(edges)
742
+
743
+ def solve_flow_problem(
744
+ self,
745
+ demands: Dict[str, Dict[str, float]], # node -> commodity -> demand
746
+ commodities: List[str],
747
+ capacities: Optional[Dict[Tuple[str, str], float]] = None,
748
+ costs: Optional[Dict[Tuple[str, str], float]] = None
749
+ ) -> Dict[Tuple[str, str, str], float]:
750
+ """
751
+ Solve multi-commodity flow optimization problem.
752
+
753
+ Args:
754
+ demands: Node demands by commodity
755
+ commodities: List of commodity types
756
+ capacities: Edge capacities (default: use instance)
757
+ costs: Edge costs (default: use instance)
758
+
759
+ Returns:
760
+ Dict[Tuple[str, str, str], float]: Flow values (source, target, commodity) -> flow
761
+ """
762
+ if not CVXPY_AVAILABLE:
763
+ logger.warning("cvxpy not available, using heuristic flow allocation")
764
+ return self._heuristic_flow(demands, commodities)
765
+
766
+ capacities = capacities or self.capacities
767
+ costs = costs or self.costs
768
+
769
+ # Decision variables: flow[e, q] for each edge and commodity
770
+ flows = {}
771
+ for edge in self.edges:
772
+ for commodity in commodities:
773
+ flows[(edge[0], edge[1], commodity)] = cp.Variable(nonneg=True)
774
+
775
+ # Objective: minimize total cost
776
+ objective = cp.Minimize(
777
+ sum(
778
+ costs.get((edge[0], edge[1]), 1.0) * flows[(edge[0], edge[1], commodity)]
779
+ for edge in self.edges
780
+ for commodity in commodities
781
+ )
782
+ )
783
+
784
+ # Constraints
785
+ constraints = []
786
+
787
+ # Flow capacity per edge
788
+ for edge in self.edges:
789
+ total_flow = sum(flows[(edge[0], edge[1], q)] for q in commodities)
790
+ cap = capacities.get(edge, float('inf'))
791
+ constraints.append(total_flow <= cap)
792
+
793
+ # Flow balance per node and commodity
794
+ for node in self.nodes:
795
+ for commodity in commodities:
796
+ inflow = sum(
797
+ flows.get((src, node, commodity), 0)
798
+ for src in self.nodes
799
+ if (src, node) in self.edges
800
+ )
801
+ outflow = sum(
802
+ flows.get((node, tgt, commodity), 0)
803
+ for tgt in self.nodes
804
+ if (node, tgt) in self.edges
805
+ )
806
+ demand = demands.get(node, {}).get(commodity, 0.0)
807
+ constraints.append(inflow - outflow >= demand)
808
+
809
+ # Solve
810
+ problem = cp.Problem(objective, constraints)
811
+ try:
812
+ problem.solve(solver=cp.ECOS if hasattr(cp, 'ECOS') else cp.SCS)
813
+
814
+ if problem.status not in ["optimal", "optimal_inaccurate"]:
815
+ logger.warning(f"Flow problem status: {problem.status}, using heuristic")
816
+ return self._heuristic_flow(demands, commodities)
817
+
818
+ # Extract solution
819
+ solution = {}
820
+ for key, var in flows.items():
821
+ solution[key] = float(var.value) if var.value is not None else 0.0
822
+
823
+ return solution
824
+
825
+ except Exception as e:
826
+ logger.error(f"Flow optimization failed: {e}, using heuristic")
827
+ return self._heuristic_flow(demands, commodities)
828
+
829
+ def _heuristic_flow(
830
+ self,
831
+ demands: Dict[str, Dict[str, float]],
832
+ commodities: List[str]
833
+ ) -> Dict[Tuple[str, str, str], float]:
834
+ """Heuristic flow allocation (fallback)."""
835
+ flows = {}
836
+ for edge in self.edges:
837
+ for commodity in commodities:
838
+ # Simple heuristic: allocate based on demand
839
+ source_demand = demands.get(edge[0], {}).get(commodity, 0.0)
840
+ flows[(edge[0], edge[1], commodity)] = source_demand * 0.1 # 10% flow
841
+ return flows
842
+
843
+ def compute_shadow_prices(self) -> Dict[Tuple[str, str], float]:
844
+ """
845
+ Compute shadow prices (dual variables) for bottleneck analysis.
846
+
847
+ Returns:
848
+ Dict[Tuple[str, str], float]: Edge -> shadow price
849
+ """
850
+ # Placeholder: would extract dual variables from LP solution
851
+ logger.warning("Shadow price computation requires solved LP, returning zeros")
852
+ return {edge: 0.0 for edge in self.edges}
853
+
854
+
855
+ class Visualization:
856
+ """
857
+ Visualization and dashboard components.
858
+
859
+ Provides:
860
+ - State dashboard
861
+ - Pareto frontier plots
862
+ - Constraint violation maps
863
+ - Bottleneck analysis
864
+
865
+ Can use Formatter from utils for enhanced rich formatting.
866
+ """
867
+
868
+ _formatter: Optional[Any] = None
869
+
870
+ @classmethod
871
+ def _get_formatter(cls) -> Optional[Any]:
872
+ """Get Formatter instance from utils if available."""
873
+ if cls._formatter is None:
874
+ try:
875
+ from utils.formatter import Formatter
876
+ cls._formatter = Formatter(md=True)
877
+ except ImportError:
878
+ cls._formatter = None
879
+ return cls._formatter
880
+
881
+ @staticmethod
882
+ def state_dashboard(x_t: StateVector) -> str:
883
+ """
884
+ Generate text dashboard for state vector.
885
+
886
+ Args:
887
+ x_t: State vector
888
+
889
+ Returns:
890
+ str: Formatted dashboard string
891
+ """
892
+ dashboard = f"""
893
+ === CRCA-SD State Dashboard ===
894
+ Population (P): {x_t.P:,.0f}
895
+ Labor Force (L): {x_t.L:,.0f}
896
+ Unemployment (U): {x_t.U:.1%}
897
+ Wage (W): {x_t.W:.2f}
898
+ Stability (S): {x_t.S:.1%}
899
+ Literacy: {x_t.literacy:.1%}
900
+ Education Capacity: {x_t.Ecap:,.0f}
901
+ Healthcare Capacity: {x_t.Hcap:,.0f}
902
+ Capital Stock (K): {x_t.K:,.0f}
903
+ Infrastructure (I): {x_t.I:.1%}
904
+ Transport Capacity: {x_t.Tcap:,.0f}
905
+ Energy Stock: {x_t.E_stock:,.0f}
906
+ Food Stock: {x_t.F_stock:,.0f}
907
+ Materials Stock: {x_t.M_stock:,.0f}
908
+ Ecological Damage (C): {x_t.C:,.0f}
909
+ Output (Y): {x_t.Y:,.0f}
910
+ ===============================
911
+ """
912
+ return dashboard
913
+
914
+ @staticmethod
915
+ def pareto_visualizer(
916
+ policies: List[ControlVector],
917
+ objectives: np.ndarray,
918
+ objective_names: Optional[List[str]] = None
919
+ ) -> str:
920
+ """
921
+ Generate text visualization of Pareto frontier.
922
+
923
+ Args:
924
+ policies: List of policies
925
+ objectives: Objective matrix
926
+ objective_names: Names of objectives (default: J_U, J_ℓ, etc.)
927
+
928
+ Returns:
929
+ str: Formatted visualization string
930
+ """
931
+ if objective_names is None:
932
+ objective_names = ["J_U", "J_ℓ", "J_Y", "J_ineq", "J_C", "J_risk"]
933
+
934
+ if objectives.ndim == 1:
935
+ objectives = objectives.reshape(1, -1)
936
+
937
+ viz = "=== Pareto Frontier ===\n"
938
+ viz += f"Policies: {len(policies)}\n"
939
+ viz += f"Objectives: {', '.join(objective_names)}\n\n"
940
+
941
+ for i, (policy, obj_vec) in enumerate(zip(policies, objectives)):
942
+ viz += f"Policy {i+1}:\n"
943
+ for name, value in zip(objective_names, obj_vec):
944
+ viz += f" {name}: {value:.4f}\n"
945
+ viz += "\n"
946
+
947
+ return viz
948
+
949
+ @staticmethod
950
+ def constraint_map(
951
+ violations: List[str],
952
+ x_t: StateVector
953
+ ) -> str:
954
+ """
955
+ Generate constraint violation map.
956
+
957
+ Args:
958
+ violations: List of violation messages
959
+ x_t: State vector
960
+
961
+ Returns:
962
+ str: Formatted violation map
963
+ """
964
+ map_str = "=== Constraint Violation Map ===\n"
965
+ if not violations:
966
+ map_str += "✓ All constraints satisfied\n"
967
+ else:
968
+ map_str += f"✗ {len(violations)} violations:\n"
969
+ for violation in violations:
970
+ map_str += f" - {violation}\n"
971
+ return map_str
972
+
973
+ @staticmethod
974
+ def realtime_dashboard(
975
+ x_t: StateVector,
976
+ execution_status: Optional[Dict[str, Any]] = None,
977
+ violations: Optional[List[str]] = None,
978
+ pending_approvals: Optional[List[Dict[str, Any]]] = None,
979
+ system_health: Optional[Dict[str, Any]] = None
980
+ ) -> str:
981
+ """
982
+ Generate real-time dashboard with execution status and monitoring.
983
+
984
+ Args:
985
+ x_t: Current state vector
986
+ execution_status: Policy execution status
987
+ violations: Constraint violations
988
+ pending_approvals: Pending approval requests
989
+ system_health: System health status
990
+
991
+ Returns:
992
+ str: Formatted real-time dashboard
993
+ """
994
+ dashboard = "=== CRCA-SD Real-Time Dashboard ===\n"
995
+ dashboard += f"Last Update: {datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')}\n\n"
996
+
997
+ # State section
998
+ dashboard += "--- Current State ---\n"
999
+ dashboard += Visualization.state_dashboard(x_t)
1000
+ dashboard += "\n"
1001
+
1002
+ # Execution status
1003
+ if execution_status:
1004
+ dashboard += "--- Execution Status ---\n"
1005
+ status = execution_status.get("status", "unknown")
1006
+ dashboard += f"Status: {status}\n"
1007
+ if "execution_id" in execution_status:
1008
+ dashboard += f"Execution ID: {execution_status['execution_id']}\n"
1009
+ if "requires_approval" in execution_status:
1010
+ dashboard += f"Requires Approval: {execution_status['requires_approval']}\n"
1011
+ dashboard += "\n"
1012
+
1013
+ # Violations
1014
+ if violations:
1015
+ dashboard += "--- Constraint Violations ---\n"
1016
+ dashboard += Visualization.constraint_map(violations, x_t)
1017
+ dashboard += "\n"
1018
+
1019
+ # Pending approvals
1020
+ if pending_approvals:
1021
+ dashboard += "--- Pending Approvals ---\n"
1022
+ dashboard += f"Count: {len(pending_approvals)}\n"
1023
+ for approval in pending_approvals[:5]: # Show first 5
1024
+ dashboard += f" - {approval.get('approval_id', 'unknown')}: {approval.get('reason', 'N/A')}\n"
1025
+ dashboard += "\n"
1026
+
1027
+ # System health
1028
+ if system_health:
1029
+ dashboard += "--- System Health ---\n"
1030
+ dashboard += f"Status: {system_health.get('status', 'unknown')}\n"
1031
+ dashboard += f"Violations (24h): {system_health.get('n_violations_24h', 0)}\n"
1032
+ dashboard += "\n"
1033
+
1034
+ dashboard += "===============================\n"
1035
+
1036
+ return dashboard
1037
+
1038
+ @staticmethod
1039
+ def execution_history_visualization(
1040
+ execution_history: List[Dict[str, Any]],
1041
+ n_recent: int = 10
1042
+ ) -> str:
1043
+ """
1044
+ Visualize execution history.
1045
+
1046
+ Args:
1047
+ execution_history: List of execution records
1048
+ n_recent: Number of recent executions to show
1049
+
1050
+ Returns:
1051
+ str: Formatted visualization
1052
+ """
1053
+ viz = "=== Execution History ===\n"
1054
+
1055
+ recent = execution_history[-n_recent:] if len(execution_history) > n_recent else execution_history
1056
+
1057
+ for exec_record in recent:
1058
+ exec_id = exec_record.get("execution_id", "unknown")
1059
+ status = exec_record.get("status", "unknown")
1060
+ timestamp = exec_record.get("timestamp", 0)
1061
+ time_str = datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M') if timestamp > 0 else "N/A"
1062
+
1063
+ viz += f"{time_str} | {exec_id[:8]}... | {status}\n"
1064
+
1065
+ return viz
1066
+
1067
+ @staticmethod
1068
+ def policy_comparison_visualization(
1069
+ policies: List[ControlVector],
1070
+ policy_names: Optional[List[str]] = None
1071
+ ) -> str:
1072
+ """
1073
+ Visualize comparison of multiple policies.
1074
+
1075
+ Args:
1076
+ policies: List of policies to compare
1077
+ policy_names: Optional names for policies
1078
+
1079
+ Returns:
1080
+ str: Formatted comparison
1081
+ """
1082
+ if policy_names is None:
1083
+ policy_names = [f"Policy {i+1}" for i in range(len(policies))]
1084
+
1085
+ viz = "=== Policy Comparison ===\n"
1086
+
1087
+ # Get all budget categories
1088
+ all_categories = set()
1089
+ for policy in policies:
1090
+ all_categories.update(policy.budget_shares.keys())
1091
+
1092
+ # Header
1093
+ viz += "Category".ljust(20)
1094
+ for name in policy_names:
1095
+ viz += name[:15].ljust(18)
1096
+ viz += "\n"
1097
+ viz += "-" * (20 + 18 * len(policy_names)) + "\n"
1098
+
1099
+ # Rows
1100
+ for cat in sorted(all_categories):
1101
+ viz += cat[:19].ljust(20)
1102
+ for policy in policies:
1103
+ value = policy.budget_shares.get(cat, 0.0)
1104
+ viz += f"{value:.1%}".ljust(18)
1105
+ viz += "\n"
1106
+
1107
+ return viz
1108
+
1109
+
1110
+ # Config: Using CorporateSwarm CorporateConfigModel pattern (lines 75-158)
1111
+ if PYDANTIC_AVAILABLE:
1112
+ class CRCA_SD_ConfigModel(BaseModel):
1113
+ """Configuration model for CRCA-SD (Pydantic)."""
1114
+
1115
+ # State bounds
1116
+ U_max: float = Field(default=0.2, ge=0.0, le=1.0)
1117
+ S_min: float = Field(default=0.3, ge=0.0, le=1.0)
1118
+ c_min: float = Field(default=0.02, ge=0.0)
1119
+
1120
+ # Dynamics parameters
1121
+ delta_K: float = Field(default=0.05, ge=0.0, le=1.0)
1122
+ delta_I: float = Field(default=0.02, ge=0.0, le=1.0)
1123
+ alpha: float = Field(default=0.3, ge=0.0, le=1.0)
1124
+ kappa_K: float = Field(default=0.8, ge=0.0)
1125
+ kappa_I: float = Field(default=0.7, ge=0.0)
1126
+ kappa_literacy: float = Field(default=0.1, ge=0.0)
1127
+
1128
+ # MPC parameters
1129
+ horizon: int = Field(default=10, ge=1, le=50)
1130
+ n_scenarios: int = Field(default=10, ge=1, le=100)
1131
+ objective_weights: List[float] = Field(default_factory=lambda: [1.0/6] * 6)
1132
+
1133
+ # Stability parameters
1134
+ max_budget_change: float = Field(default=0.2, ge=0.0, le=1.0)
1135
+ investment_smoothing: float = Field(default=0.7, ge=0.0, le=1.0)
1136
+
1137
+ # Board parameters
1138
+ n_boards: int = Field(default=4, ge=1, le=10)
1139
+ arbitration_method: str = Field(default="weighted_vote")
1140
+
1141
+ # Logistics parameters
1142
+ default_transport_capacity: float = Field(default=10000.0, ge=0.0)
1143
+
1144
+ # Risk parameters
1145
+ cvar_alpha: float = Field(default=0.05, ge=0.0, le=1.0)
1146
+ else:
1147
+ @dataclass
1148
+ class CRCA_SD_ConfigModel:
1149
+ """Configuration model for CRCA-SD (dataclass fallback)."""
1150
+ U_max: float = 0.2
1151
+ S_min: float = 0.3
1152
+ c_min: float = 0.02
1153
+ delta_K: float = 0.05
1154
+ delta_I: float = 0.02
1155
+ alpha: float = 0.3
1156
+ kappa_K: float = 0.8
1157
+ kappa_I: float = 0.7
1158
+ kappa_literacy: float = 0.1
1159
+ horizon: int = 10
1160
+ n_scenarios: int = 10
1161
+ objective_weights: List[float] = field(default_factory=lambda: [1.0/6] * 6)
1162
+ max_budget_change: float = 0.2
1163
+ investment_smoothing: float = 0.7
1164
+ n_boards: int = 4
1165
+ arbitration_method: str = "weighted_vote"
1166
+ default_transport_capacity: float = 10000.0
1167
+ cvar_alpha: float = 0.05
1168
+
1169
+
1170
+ @dataclass
1171
+ class CRCA_SD_Config:
1172
+ """Configuration manager (pattern from CorporateSwarm lines 160-227)."""
1173
+
1174
+ config_file_path: Optional[str] = None
1175
+ config_data: Optional[Dict[str, Any]] = None
1176
+ config: CRCA_SD_ConfigModel = field(init=False)
1177
+
1178
+ def __post_init__(self) -> None:
1179
+ """Load configuration."""
1180
+ self._load_config()
1181
+
1182
+ def _load_config(self) -> None:
1183
+ """Load configuration with priority: explicit data > file > defaults."""
1184
+ try:
1185
+ self.config = CRCA_SD_ConfigModel()
1186
+ if self.config_file_path and os.path.exists(self.config_file_path):
1187
+ self._load_from_file()
1188
+ if self.config_data:
1189
+ self._load_from_dict(self.config_data)
1190
+ except Exception as e:
1191
+ logger.error(f"Configuration loading failed: {e}")
1192
+ raise ValueError(f"Configuration loading failed: {e}") from e
1193
+
1194
+ def _load_from_file(self) -> None:
1195
+ """Load configuration from YAML file."""
1196
+ if not YAML_AVAILABLE:
1197
+ logger.warning("YAML not available, cannot load config file")
1198
+ return
1199
+
1200
+ try:
1201
+ with open(self.config_file_path, "r") as f:
1202
+ self._load_from_dict(yaml.safe_load(f))
1203
+ logger.info(f"Loaded config from: {self.config_file_path}")
1204
+ except Exception as e:
1205
+ logger.warning(f"File loading failed {self.config_file_path}: {e}")
1206
+ raise ValueError(f"Configuration file loading failed: {e}") from e
1207
+
1208
+ def _load_from_dict(self, config_dict: Dict[str, Any]) -> None:
1209
+ """Load configuration from dictionary."""
1210
+ for key, value in config_dict.items():
1211
+ if hasattr(self.config, key):
1212
+ try:
1213
+ setattr(self.config, key, value)
1214
+ except (ValueError, TypeError) as e:
1215
+ logger.warning(f"Config {key} failed: {e}")
1216
+ raise ValueError(f"Invalid configuration value for {key}: {e}") from e
1217
+
1218
+ def get_config(self) -> CRCA_SD_ConfigModel:
1219
+ """Get configuration model."""
1220
+ return self.config
1221
+
1222
+
1223
+ # Global config cache (pattern from CorporateSwarm lines 233-239)
1224
+ _crca_sd_config: Optional[CRCA_SD_Config] = None
1225
+
1226
+ @lru_cache(maxsize=1)
1227
+ def get_crca_sd_config(config_file_path: Optional[str] = None) -> CRCA_SD_Config:
1228
+ """Get global CRCA-SD configuration instance."""
1229
+ global _crca_sd_config
1230
+ if _crca_sd_config is None:
1231
+ _crca_sd_config = CRCA_SD_Config(config_file_path=config_file_path)
1232
+ return _crca_sd_config
1233
+
1234
+
1235
+ class MetricsCollector:
1236
+ """
1237
+ Metrics collector for feasibility, stability, robustness.
1238
+
1239
+ Tracks:
1240
+ - Feasibility: scenario feasibility rate, minimum slack
1241
+ - Stability: variance of U_t, Y_t, C_t, oscillation frequency, control effort
1242
+ - Robustness: worst-case performance, CVaR at different α
1243
+ - Bottleneck causality: which constraints bind most often
1244
+ """
1245
+
1246
+ def __init__(self) -> None:
1247
+ """Initialize metrics collector."""
1248
+ self.metrics_history: List[Dict[str, Any]] = []
1249
+
1250
+ def compute_all_metrics(
1251
+ self,
1252
+ trajectories: List[List[StateVector]],
1253
+ policies: List[ControlVector]
1254
+ ) -> Dict[str, Any]:
1255
+ """
1256
+ Compute all metrics from trajectories and policies.
1257
+
1258
+ Args:
1259
+ trajectories: List of state trajectories
1260
+ policies: List of control policies
1261
+
1262
+ Returns:
1263
+ Dict[str, Any]: Metrics dictionary
1264
+ """
1265
+ metrics = {}
1266
+
1267
+ # Feasibility metrics
1268
+ n_feasible = sum(1 for traj in trajectories if len(traj) > 1)
1269
+ metrics["feasibility_rate"] = n_feasible / len(trajectories) if trajectories else 0.0
1270
+
1271
+ # Stability metrics (variance)
1272
+ if trajectories:
1273
+ U_values = [x.U for traj in trajectories for x in traj[1:]]
1274
+ Y_values = [x.Y for traj in trajectories for x in traj[1:]]
1275
+ C_values = [x.C for traj in trajectories for x in traj[1:]]
1276
+
1277
+ metrics["U_variance"] = float(np.var(U_values)) if U_values else 0.0
1278
+ metrics["Y_variance"] = float(np.var(Y_values)) if Y_values else 0.0
1279
+ metrics["C_variance"] = float(np.var(C_values)) if C_values else 0.0
1280
+
1281
+ # Control effort (sum of changes)
1282
+ if len(policies) > 1:
1283
+ effort = 0.0
1284
+ for i in range(1, len(policies)):
1285
+ prev_shares = policies[i-1].budget_shares
1286
+ curr_shares = policies[i].budget_shares
1287
+ change = sum(abs(curr_shares.get(k, 0) - prev_shares.get(k, 0)) for k in set(list(prev_shares.keys()) + list(curr_shares.keys())))
1288
+ effort += change
1289
+ metrics["control_effort"] = effort
1290
+ else:
1291
+ metrics["control_effort"] = 0.0
1292
+
1293
+ # Robustness (worst-case)
1294
+ if trajectories:
1295
+ final_states = [traj[-1] for traj in trajectories if traj]
1296
+ worst_U = max((x.U for x in final_states), default=0.0)
1297
+ worst_S = min((x.S for x in final_states), default=1.0)
1298
+ metrics["worst_case_U"] = float(worst_U)
1299
+ metrics["worst_case_S"] = float(worst_S)
1300
+
1301
+ self.metrics_history.append(metrics)
1302
+ return metrics
1303
+
1304
+ def generate_report(self) -> str:
1305
+ """
1306
+ Generate formatted metrics report.
1307
+
1308
+ Returns:
1309
+ str: Formatted report string
1310
+ """
1311
+ if not self.metrics_history:
1312
+ return "No metrics collected yet."
1313
+
1314
+ latest = self.metrics_history[-1]
1315
+ report = "=== CRCA-SD Metrics Report ===\n"
1316
+ report += f"Feasibility Rate: {latest.get('feasibility_rate', 0.0):.1%}\n"
1317
+ report += f"Unemployment Variance: {latest.get('U_variance', 0.0):.4f}\n"
1318
+ report += f"Output Variance: {latest.get('Y_variance', 0.0):.2f}\n"
1319
+ report += f"Control Effort: {latest.get('control_effort', 0.0):.4f}\n"
1320
+ report += f"Worst Case Unemployment: {latest.get('worst_case_U', 0.0):.1%}\n"
1321
+ report += f"Worst Case Stability: {latest.get('worst_case_S', 0.0):.1%}\n"
1322
+ report += "============================\n"
1323
+
1324
+ return report
1325
+