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.
- .github/ISSUE_TEMPLATE/bug_report.md +65 -0
- .github/ISSUE_TEMPLATE/feature_request.md +41 -0
- .github/PULL_REQUEST_TEMPLATE.md +20 -0
- .github/workflows/publish-manual.yml +61 -0
- .github/workflows/publish.yml +64 -0
- .gitignore +214 -0
- CRCA.py +4156 -0
- LICENSE +201 -0
- MANIFEST.in +43 -0
- PKG-INFO +5035 -0
- README.md +4959 -0
- __init__.py +17 -0
- branches/CRCA-Q.py +2728 -0
- branches/crca_cg/corposwarm.py +9065 -0
- branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
- branches/crca_cg/package.json +5 -0
- branches/crca_cg/test_bolt_integration.py +446 -0
- branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
- branches/crca_cg/test_new_features.py +163 -0
- branches/crca_sd/__init__.py +149 -0
- branches/crca_sd/crca_sd_core.py +770 -0
- branches/crca_sd/crca_sd_governance.py +1325 -0
- branches/crca_sd/crca_sd_mpc.py +1130 -0
- branches/crca_sd/crca_sd_realtime.py +1844 -0
- branches/crca_sd/crca_sd_tui.py +1133 -0
- crca-1.4.0.dist-info/METADATA +5035 -0
- crca-1.4.0.dist-info/RECORD +501 -0
- crca-1.4.0.dist-info/WHEEL +4 -0
- crca-1.4.0.dist-info/licenses/LICENSE +201 -0
- docs/CRCA-Q.md +2333 -0
- examples/config.yaml.example +25 -0
- examples/crca_sd_example.py +513 -0
- examples/data_broker_example.py +294 -0
- examples/logistics_corporation.py +861 -0
- examples/palantir_example.py +299 -0
- examples/policy_bench.py +934 -0
- examples/pridnestrovia-sd.py +705 -0
- examples/pridnestrovia_realtime.py +1902 -0
- prompts/__init__.py +10 -0
- prompts/default_crca.py +101 -0
- pyproject.toml +151 -0
- requirements.txt +76 -0
- schemas/__init__.py +43 -0
- schemas/mcpSchemas.py +51 -0
- schemas/policy.py +458 -0
- templates/__init__.py +38 -0
- templates/base_specialized_agent.py +195 -0
- templates/drift_detection.py +325 -0
- templates/examples/causal_agent_template.py +309 -0
- templates/examples/drag_drop_example.py +213 -0
- templates/examples/logistics_agent_template.py +207 -0
- templates/examples/trading_agent_template.py +206 -0
- templates/feature_mixins.py +253 -0
- templates/graph_management.py +442 -0
- templates/llm_integration.py +194 -0
- templates/module_registry.py +276 -0
- templates/mpc_planner.py +280 -0
- templates/policy_loop.py +1168 -0
- templates/prediction_framework.py +448 -0
- templates/statistical_methods.py +778 -0
- tests/sanity.yml +31 -0
- tests/sanity_check +406 -0
- tests/test_core.py +47 -0
- tests/test_crca_excel.py +166 -0
- tests/test_crca_sd.py +780 -0
- tests/test_data_broker.py +424 -0
- tests/test_palantir.py +349 -0
- tools/__init__.py +38 -0
- tools/actuators.py +437 -0
- tools/bolt.diy/Dockerfile +103 -0
- tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
- tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
- tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
- tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
- tools/bolt.diy/app/components/@settings/index.ts +12 -0
- tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
- tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
- tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
- tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
- tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
- tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
- tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
- tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
- tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
- tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
- tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
- tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
- tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
- tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
- tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
- tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
- tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
- tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
- tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
- tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
- tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
- tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
- tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
- tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
- tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
- tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
- tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
- tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
- tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
- tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
- tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
- tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
- tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
- tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
- tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
- tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
- tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
- tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
- tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
- tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
- tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
- tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
- tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
- tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
- tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
- tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
- tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
- tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
- tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
- tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
- tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
- tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
- tools/bolt.diy/app/components/header/Header.tsx +42 -0
- tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
- tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
- tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
- tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
- tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
- tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
- tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
- tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
- tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
- tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
- tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
- tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
- tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
- tools/bolt.diy/app/components/txt +1 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
- tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
- tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
- tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
- tools/bolt.diy/app/components/ui/Button.tsx +46 -0
- tools/bolt.diy/app/components/ui/Card.tsx +55 -0
- tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
- tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
- tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
- tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
- tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
- tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
- tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
- tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
- tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
- tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
- tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
- tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
- tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
- tools/bolt.diy/app/components/ui/Input.tsx +22 -0
- tools/bolt.diy/app/components/ui/Label.tsx +20 -0
- tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
- tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
- tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
- tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
- tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
- tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
- tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
- tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
- tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
- tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
- tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
- tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
- tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
- tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
- tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
- tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
- tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
- tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
- tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
- tools/bolt.diy/app/components/ui/index.ts +38 -0
- tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
- tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
- tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
- tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
- tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
- tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
- tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
- tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
- tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
- tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
- tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
- tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
- tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
- tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
- tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
- tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
- tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
- tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
- tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
- tools/bolt.diy/app/entry.client.tsx +7 -0
- tools/bolt.diy/app/entry.server.tsx +80 -0
- tools/bolt.diy/app/root.tsx +156 -0
- tools/bolt.diy/app/routes/_index.tsx +175 -0
- tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
- tools/bolt.diy/app/routes/api.chat.ts +463 -0
- tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
- tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
- tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
- tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
- tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
- tools/bolt.diy/app/routes/api.git-info.ts +69 -0
- tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
- tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
- tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
- tools/bolt.diy/app/routes/api.github-template.ts +242 -0
- tools/bolt.diy/app/routes/api.github-user.ts +287 -0
- tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
- tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
- tools/bolt.diy/app/routes/api.health.ts +8 -0
- tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
- tools/bolt.diy/app/routes/api.mandate.ts +351 -0
- tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
- tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
- tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
- tools/bolt.diy/app/routes/api.models.ts +90 -0
- tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
- tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
- tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
- tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
- tools/bolt.diy/app/routes/api.supabase.ts +56 -0
- tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
- tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
- tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
- tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
- tools/bolt.diy/app/routes/api.update.ts +21 -0
- tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
- tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
- tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
- tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
- tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
- tools/bolt.diy/app/routes/git.tsx +25 -0
- tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
- tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
- tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
- tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
- tools/bolt.diy/app/styles/animations.scss +49 -0
- tools/bolt.diy/app/styles/components/code.scss +9 -0
- tools/bolt.diy/app/styles/components/editor.scss +135 -0
- tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
- tools/bolt.diy/app/styles/components/terminal.scss +3 -0
- tools/bolt.diy/app/styles/components/toast.scss +23 -0
- tools/bolt.diy/app/styles/diff-view.css +72 -0
- tools/bolt.diy/app/styles/index.scss +73 -0
- tools/bolt.diy/app/styles/variables.scss +255 -0
- tools/bolt.diy/app/styles/z-index.scss +37 -0
- tools/bolt.diy/app/types/GitHub.ts +182 -0
- tools/bolt.diy/app/types/GitLab.ts +103 -0
- tools/bolt.diy/app/types/actions.ts +85 -0
- tools/bolt.diy/app/types/artifact.ts +5 -0
- tools/bolt.diy/app/types/context.ts +26 -0
- tools/bolt.diy/app/types/design-scheme.ts +93 -0
- tools/bolt.diy/app/types/global.d.ts +13 -0
- tools/bolt.diy/app/types/mandate.ts +333 -0
- tools/bolt.diy/app/types/model.ts +25 -0
- tools/bolt.diy/app/types/netlify.ts +94 -0
- tools/bolt.diy/app/types/supabase.ts +54 -0
- tools/bolt.diy/app/types/template.ts +8 -0
- tools/bolt.diy/app/types/terminal.ts +9 -0
- tools/bolt.diy/app/types/theme.ts +1 -0
- tools/bolt.diy/app/types/vercel.ts +67 -0
- tools/bolt.diy/app/utils/buffer.ts +29 -0
- tools/bolt.diy/app/utils/classNames.ts +65 -0
- tools/bolt.diy/app/utils/constants.ts +147 -0
- tools/bolt.diy/app/utils/debounce.ts +13 -0
- tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
- tools/bolt.diy/app/utils/diff.spec.ts +11 -0
- tools/bolt.diy/app/utils/diff.ts +117 -0
- tools/bolt.diy/app/utils/easings.ts +3 -0
- tools/bolt.diy/app/utils/fileLocks.ts +96 -0
- tools/bolt.diy/app/utils/fileUtils.ts +121 -0
- tools/bolt.diy/app/utils/folderImport.ts +73 -0
- tools/bolt.diy/app/utils/formatSize.ts +12 -0
- tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
- tools/bolt.diy/app/utils/githubStats.ts +9 -0
- tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
- tools/bolt.diy/app/utils/logger.ts +162 -0
- tools/bolt.diy/app/utils/markdown.ts +155 -0
- tools/bolt.diy/app/utils/mobile.ts +4 -0
- tools/bolt.diy/app/utils/os.ts +4 -0
- tools/bolt.diy/app/utils/path.ts +19 -0
- tools/bolt.diy/app/utils/projectCommands.ts +197 -0
- tools/bolt.diy/app/utils/promises.ts +19 -0
- tools/bolt.diy/app/utils/react.ts +6 -0
- tools/bolt.diy/app/utils/sampler.ts +49 -0
- tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
- tools/bolt.diy/app/utils/shell.ts +384 -0
- tools/bolt.diy/app/utils/stacktrace.ts +27 -0
- tools/bolt.diy/app/utils/stripIndent.ts +23 -0
- tools/bolt.diy/app/utils/terminal.ts +11 -0
- tools/bolt.diy/app/utils/unreachable.ts +3 -0
- tools/bolt.diy/app/vite-env.d.ts +2 -0
- tools/bolt.diy/assets/entitlements.mac.plist +25 -0
- tools/bolt.diy/assets/icons/icon.icns +0 -0
- tools/bolt.diy/assets/icons/icon.ico +0 -0
- tools/bolt.diy/assets/icons/icon.png +0 -0
- tools/bolt.diy/bindings.js +78 -0
- tools/bolt.diy/bindings.sh +33 -0
- tools/bolt.diy/docker-compose.yaml +145 -0
- tools/bolt.diy/electron/main/index.ts +201 -0
- tools/bolt.diy/electron/main/tsconfig.json +30 -0
- tools/bolt.diy/electron/main/ui/menu.ts +29 -0
- tools/bolt.diy/electron/main/ui/window.ts +54 -0
- tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
- tools/bolt.diy/electron/main/utils/constants.ts +4 -0
- tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
- tools/bolt.diy/electron/main/utils/reload.ts +35 -0
- tools/bolt.diy/electron/main/utils/serve.ts +71 -0
- tools/bolt.diy/electron/main/utils/store.ts +3 -0
- tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
- tools/bolt.diy/electron/main/vite.config.ts +44 -0
- tools/bolt.diy/electron/preload/index.ts +22 -0
- tools/bolt.diy/electron/preload/tsconfig.json +7 -0
- tools/bolt.diy/electron/preload/vite.config.ts +31 -0
- tools/bolt.diy/electron-builder.yml +64 -0
- tools/bolt.diy/electron-update.yml +4 -0
- tools/bolt.diy/eslint.config.mjs +57 -0
- tools/bolt.diy/functions/[[path]].ts +12 -0
- tools/bolt.diy/icons/angular.svg +1 -0
- tools/bolt.diy/icons/astro.svg +8 -0
- tools/bolt.diy/icons/chat.svg +1 -0
- tools/bolt.diy/icons/expo-brand.svg +1 -0
- tools/bolt.diy/icons/expo.svg +4 -0
- tools/bolt.diy/icons/logo-text.svg +1 -0
- tools/bolt.diy/icons/logo.svg +4 -0
- tools/bolt.diy/icons/mcp.svg +1 -0
- tools/bolt.diy/icons/nativescript.svg +1 -0
- tools/bolt.diy/icons/netlify.svg +10 -0
- tools/bolt.diy/icons/nextjs.svg +1 -0
- tools/bolt.diy/icons/nuxt.svg +1 -0
- tools/bolt.diy/icons/qwik.svg +1 -0
- tools/bolt.diy/icons/react.svg +1 -0
- tools/bolt.diy/icons/remix.svg +24 -0
- tools/bolt.diy/icons/remotion.svg +1 -0
- tools/bolt.diy/icons/shadcn.svg +21 -0
- tools/bolt.diy/icons/slidev.svg +60 -0
- tools/bolt.diy/icons/solidjs.svg +1 -0
- tools/bolt.diy/icons/stars.svg +1 -0
- tools/bolt.diy/icons/svelte.svg +1 -0
- tools/bolt.diy/icons/typescript.svg +1 -0
- tools/bolt.diy/icons/vite.svg +1 -0
- tools/bolt.diy/icons/vue.svg +1 -0
- tools/bolt.diy/load-context.ts +9 -0
- tools/bolt.diy/notarize.cjs +31 -0
- tools/bolt.diy/package.json +218 -0
- tools/bolt.diy/playwright.config.preview.ts +35 -0
- tools/bolt.diy/pre-start.cjs +26 -0
- tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
- tools/bolt.diy/public/apple-touch-icon.png +0 -0
- tools/bolt.diy/public/favicon.ico +0 -0
- tools/bolt.diy/public/favicon.svg +4 -0
- tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
- tools/bolt.diy/public/icons/Anthropic.svg +4 -0
- tools/bolt.diy/public/icons/Cohere.svg +4 -0
- tools/bolt.diy/public/icons/Deepseek.svg +5 -0
- tools/bolt.diy/public/icons/Default.svg +4 -0
- tools/bolt.diy/public/icons/Google.svg +4 -0
- tools/bolt.diy/public/icons/Groq.svg +4 -0
- tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
- tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
- tools/bolt.diy/public/icons/LMStudio.svg +5 -0
- tools/bolt.diy/public/icons/Mistral.svg +4 -0
- tools/bolt.diy/public/icons/Ollama.svg +4 -0
- tools/bolt.diy/public/icons/OpenAI.svg +4 -0
- tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
- tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
- tools/bolt.diy/public/icons/Perplexity.svg +4 -0
- tools/bolt.diy/public/icons/Together.svg +4 -0
- tools/bolt.diy/public/icons/xAI.svg +5 -0
- tools/bolt.diy/public/inspector-script.js +292 -0
- tools/bolt.diy/public/logo-dark-styled.png +0 -0
- tools/bolt.diy/public/logo-dark.png +0 -0
- tools/bolt.diy/public/logo-light-styled.png +0 -0
- tools/bolt.diy/public/logo-light.png +0 -0
- tools/bolt.diy/public/logo.svg +15 -0
- tools/bolt.diy/public/social_preview_index.jpg +0 -0
- tools/bolt.diy/scripts/clean.js +45 -0
- tools/bolt.diy/scripts/electron-dev.mjs +181 -0
- tools/bolt.diy/scripts/setup-env.sh +41 -0
- tools/bolt.diy/scripts/update-imports.sh +7 -0
- tools/bolt.diy/scripts/update.sh +52 -0
- tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
- tools/bolt.diy/services/execution-governor/config.ts +42 -0
- tools/bolt.diy/services/execution-governor/index.ts +683 -0
- tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
- tools/bolt.diy/services/execution-governor/package.json +31 -0
- tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
- tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
- tools/bolt.diy/services/execution-governor/types.ts +145 -0
- tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
- tools/bolt.diy/services/headless-executor/executor.ts +210 -0
- tools/bolt.diy/services/headless-executor/index.ts +323 -0
- tools/bolt.diy/services/headless-executor/package.json +27 -0
- tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
- tools/bolt.diy/services/headless-executor/types.ts +38 -0
- tools/bolt.diy/test-workflows.sh +240 -0
- tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
- tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
- tools/bolt.diy/tests/mandates/complex.json +53 -0
- tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
- tools/bolt.diy/tests/mandates/simple.json +35 -0
- tools/bolt.diy/tsconfig.json +37 -0
- tools/bolt.diy/types/istextorbinary.d.ts +15 -0
- tools/bolt.diy/uno.config.ts +279 -0
- tools/bolt.diy/vite-electron.config.ts +76 -0
- tools/bolt.diy/vite.config.ts +112 -0
- tools/bolt.diy/worker-configuration.d.ts +22 -0
- tools/bolt.diy/wrangler.toml +6 -0
- tools/code_generator.py +461 -0
- tools/file_operations.py +465 -0
- tools/mandate_generator.py +337 -0
- tools/mcpClientUtils.py +1216 -0
- tools/sensors.py +285 -0
- utils/Agent_types.py +15 -0
- utils/AnyToStr.py +0 -0
- utils/HHCS.py +277 -0
- utils/__init__.py +30 -0
- utils/agent.py +3627 -0
- utils/aop.py +2948 -0
- utils/canonical.py +143 -0
- utils/conversation.py +1195 -0
- utils/doctrine_versioning +230 -0
- utils/formatter.py +474 -0
- utils/ledger.py +311 -0
- utils/out_types.py +16 -0
- utils/rollback.py +339 -0
- utils/router.py +929 -0
- utils/tui.py +1908 -0
|
@@ -0,0 +1,1902 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pridnestrovia Real-Time Control System
|
|
3
|
+
|
|
4
|
+
FULL PRODUCTION IMPLEMENTATION - Real-time economic control for Pridnestrovia.
|
|
5
|
+
|
|
6
|
+
This is a production-ready real-time control system that:
|
|
7
|
+
- Continuously monitors Pridnestrovia's economy via government APIs
|
|
8
|
+
- Updates state estimates daily from real data sources
|
|
9
|
+
- Optimizes policy decisions using MPC
|
|
10
|
+
- Automatically executes minor policy changes (< 10%)
|
|
11
|
+
- Requires human approval for major changes (> 10%)
|
|
12
|
+
- Maintains full audit trails and compliance
|
|
13
|
+
- Provides 7-day rollback capability
|
|
14
|
+
- Operates 24/7 with real-time monitoring and alerting
|
|
15
|
+
|
|
16
|
+
System Status: PRODUCTION
|
|
17
|
+
Last Updated: December 20, 2025
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import List, Dict, Optional, Any
|
|
21
|
+
import numpy as np
|
|
22
|
+
import time
|
|
23
|
+
import threading
|
|
24
|
+
import sys
|
|
25
|
+
import os
|
|
26
|
+
from datetime import datetime, timedelta
|
|
27
|
+
from loguru import logger
|
|
28
|
+
|
|
29
|
+
# Add parent directory to path so we can import crca_sd
|
|
30
|
+
# This allows running the script from examples/ directory
|
|
31
|
+
_script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
32
|
+
_parent_dir = os.path.dirname(_script_dir)
|
|
33
|
+
if _parent_dir not in sys.path:
|
|
34
|
+
sys.path.insert(0, _parent_dir)
|
|
35
|
+
|
|
36
|
+
# Import CRCA-SD components
|
|
37
|
+
from crca_sd.crca_sd_core import (
|
|
38
|
+
StateVector,
|
|
39
|
+
ControlVector,
|
|
40
|
+
DynamicsModel,
|
|
41
|
+
ConstraintChecker,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
from crca_sd.crca_sd_mpc import (
|
|
45
|
+
ObjectiveVector,
|
|
46
|
+
MPCSolver,
|
|
47
|
+
ScenarioGenerator,
|
|
48
|
+
StateEstimator,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from crca_sd.crca_sd_governance import (
|
|
52
|
+
BoardMember,
|
|
53
|
+
Board,
|
|
54
|
+
BoardType,
|
|
55
|
+
GovernanceSystem,
|
|
56
|
+
Visualization,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Import TUI
|
|
60
|
+
try:
|
|
61
|
+
from crca_sd.crca_sd_tui import CRCA_SD_TUI
|
|
62
|
+
TUI_AVAILABLE = True
|
|
63
|
+
except ImportError:
|
|
64
|
+
CRCA_SD_TUI = None
|
|
65
|
+
TUI_AVAILABLE = False
|
|
66
|
+
logger.warning("TUI not available - install rich: pip install rich")
|
|
67
|
+
|
|
68
|
+
# Import Formatter from utils
|
|
69
|
+
try:
|
|
70
|
+
from utils.formatter import Formatter, formatter
|
|
71
|
+
FORMATTER_AVAILABLE = True
|
|
72
|
+
except ImportError:
|
|
73
|
+
Formatter = None
|
|
74
|
+
formatter = None
|
|
75
|
+
FORMATTER_AVAILABLE = False
|
|
76
|
+
logger.debug("Formatter from utils not available")
|
|
77
|
+
|
|
78
|
+
# Import real-time components
|
|
79
|
+
from crca_sd.crca_sd_realtime import (
|
|
80
|
+
DataAcquisition,
|
|
81
|
+
DataPipeline,
|
|
82
|
+
RealTimeStateEstimator,
|
|
83
|
+
RealTimeMonitor,
|
|
84
|
+
PolicyExecutor,
|
|
85
|
+
SafetyInterlocks,
|
|
86
|
+
ControlInterface,
|
|
87
|
+
AlertingSystem,
|
|
88
|
+
AlertLevel,
|
|
89
|
+
ComplianceSystem,
|
|
90
|
+
AccountabilitySystem,
|
|
91
|
+
RollbackSystem,
|
|
92
|
+
ModelAdaptation,
|
|
93
|
+
PerformanceFeedback,
|
|
94
|
+
FaultTolerance,
|
|
95
|
+
DataSourceType,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Import CRCA from core module (Causal Reasoning and Counterfactual Analysis)
|
|
99
|
+
from crca_sd import get_crca_agent, CRCA_AVAILABLE
|
|
100
|
+
|
|
101
|
+
# Import initialization functions from original example
|
|
102
|
+
import importlib.util
|
|
103
|
+
|
|
104
|
+
# Load pridnestrovia-sd.py (with hyphen)
|
|
105
|
+
# Handle both running from project root and examples/ directory
|
|
106
|
+
_pridnestrovia_sd_path = os.path.join(_script_dir, "pridnestrovia-sd.py")
|
|
107
|
+
if not os.path.exists(_pridnestrovia_sd_path):
|
|
108
|
+
# Try from project root
|
|
109
|
+
_pridnestrovia_sd_path = os.path.join(_parent_dir, "examples", "pridnestrovia-sd.py")
|
|
110
|
+
|
|
111
|
+
spec = importlib.util.spec_from_file_location("pridnestrovia_sd", _pridnestrovia_sd_path)
|
|
112
|
+
pridnestrovia_sd_module = importlib.util.module_from_spec(spec)
|
|
113
|
+
sys.modules["pridnestrovia_sd"] = pridnestrovia_sd_module
|
|
114
|
+
spec.loader.exec_module(pridnestrovia_sd_module)
|
|
115
|
+
|
|
116
|
+
initialize_pridnestrovia_state = pridnestrovia_sd_module.initialize_pridnestrovia_state
|
|
117
|
+
create_pridnestrovia_dynamics = pridnestrovia_sd_module.create_pridnestrovia_dynamics
|
|
118
|
+
create_pridnestrovia_boards = pridnestrovia_sd_module.create_pridnestrovia_boards
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class PridnestroviaRealtimeController:
|
|
122
|
+
"""
|
|
123
|
+
Production real-time controller for Pridnestrovia economy.
|
|
124
|
+
|
|
125
|
+
Operates continuously, monitoring and controlling the economy in real-time.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(self, config_file: Optional[str] = None):
|
|
129
|
+
"""
|
|
130
|
+
Initialize production real-time controller.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
config_file: Optional configuration file path
|
|
134
|
+
"""
|
|
135
|
+
logger.info("=== Initializing Pridnestrovia Real-Time Control System ===")
|
|
136
|
+
logger.info("Mode: PRODUCTION")
|
|
137
|
+
logger.info(f"Start Time: {datetime.now().isoformat()}")
|
|
138
|
+
|
|
139
|
+
# Load configuration
|
|
140
|
+
self.config = self._load_config(config_file)
|
|
141
|
+
|
|
142
|
+
# Initialize core components
|
|
143
|
+
self.x_current = initialize_pridnestrovia_state()
|
|
144
|
+
self.dynamics = create_pridnestrovia_dynamics()
|
|
145
|
+
self.checker = ConstraintChecker(U_max=0.15, S_min=0.50)
|
|
146
|
+
self.obj_computer = ObjectiveVector(horizon=12)
|
|
147
|
+
self.solver = MPCSolver(self.dynamics, self.checker, self.obj_computer, horizon=12)
|
|
148
|
+
|
|
149
|
+
# Real-time data acquisition (government systems priority)
|
|
150
|
+
self.data_acq = DataAcquisition(update_frequency=86400.0) # Daily
|
|
151
|
+
|
|
152
|
+
# Connect to REAL government APIs
|
|
153
|
+
self.government_config = {
|
|
154
|
+
"treasury": {
|
|
155
|
+
"base_url": self.config.get("treasury_api_url", "https://api.pridnestrovia.gov/treasury"),
|
|
156
|
+
"auth": {
|
|
157
|
+
"api_key": self.config.get("treasury_api_key"),
|
|
158
|
+
"auth_type": "bearer"
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
"ministries": {
|
|
162
|
+
"base_url": self.config.get("ministries_api_url", "https://api.pridnestrovia.gov/ministries"),
|
|
163
|
+
"auth": {
|
|
164
|
+
"api_key": self.config.get("ministries_api_key"),
|
|
165
|
+
"auth_type": "bearer"
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
"central_bank": {
|
|
169
|
+
"base_url": self.config.get("central_bank_api_url", "https://api.pridnestrovia.gov/centralbank"),
|
|
170
|
+
"auth": {
|
|
171
|
+
"api_key": self.config.get("central_bank_api_key"),
|
|
172
|
+
"auth_type": "bearer"
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Connect to government APIs (REAL connections)
|
|
178
|
+
for api_name, config in self.government_config.items():
|
|
179
|
+
success = self.data_acq.connect_government_api(
|
|
180
|
+
api_name,
|
|
181
|
+
config["base_url"],
|
|
182
|
+
config["auth"]
|
|
183
|
+
)
|
|
184
|
+
if success:
|
|
185
|
+
logger.info(f"✓ Connected to {api_name} API")
|
|
186
|
+
else:
|
|
187
|
+
logger.error(f"✗ Failed to connect to {api_name} API")
|
|
188
|
+
|
|
189
|
+
# Data pipeline
|
|
190
|
+
self.data_pipeline = DataPipeline()
|
|
191
|
+
|
|
192
|
+
# Real-time state estimator
|
|
193
|
+
self.state_estimator = RealTimeStateEstimator(
|
|
194
|
+
self.dynamics,
|
|
195
|
+
update_frequency=30.0 # 30 second updates
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Real-time monitor
|
|
199
|
+
self.monitor = RealTimeMonitor(self.checker, update_frequency=30.0)
|
|
200
|
+
|
|
201
|
+
# Policy executor (REAL execution via government APIs)
|
|
202
|
+
self.policy_executor = PolicyExecutor(self.government_config)
|
|
203
|
+
|
|
204
|
+
# Safety interlocks
|
|
205
|
+
# Lower confidence threshold for public API data (0.85 instead of 0.95)
|
|
206
|
+
# Public APIs are less reliable than government APIs
|
|
207
|
+
self.safety = SafetyInterlocks(
|
|
208
|
+
max_budget_change=0.20,
|
|
209
|
+
major_change_threshold=0.10, # 10% = major change
|
|
210
|
+
confidence_threshold=0.85, # Lowered for public API compatibility
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Control interface
|
|
214
|
+
self.control_interface = ControlInterface()
|
|
215
|
+
|
|
216
|
+
# Alerting system
|
|
217
|
+
self.alerting = AlertingSystem()
|
|
218
|
+
|
|
219
|
+
# Compliance system
|
|
220
|
+
self.compliance = ComplianceSystem(retention_days=2555) # 7 years
|
|
221
|
+
|
|
222
|
+
# Accountability system
|
|
223
|
+
self.accountability = AccountabilitySystem()
|
|
224
|
+
|
|
225
|
+
# Rollback system (7-day window)
|
|
226
|
+
self.rollback = RollbackSystem(rollback_window_days=7)
|
|
227
|
+
|
|
228
|
+
# Model adaptation
|
|
229
|
+
self.model_adaptation = ModelAdaptation(self.dynamics)
|
|
230
|
+
|
|
231
|
+
# Performance feedback
|
|
232
|
+
self.feedback = PerformanceFeedback()
|
|
233
|
+
|
|
234
|
+
# Fault tolerance
|
|
235
|
+
self.fault_tolerance = FaultTolerance()
|
|
236
|
+
self.fault_tolerance.register_system("data_acquisition", is_primary=True)
|
|
237
|
+
self.fault_tolerance.register_system("policy_executor", is_primary=True)
|
|
238
|
+
|
|
239
|
+
# Governance system with human approval
|
|
240
|
+
self.boards = create_pridnestrovia_boards()
|
|
241
|
+
self.governance = GovernanceSystem(self.boards, major_change_threshold=0.10)
|
|
242
|
+
|
|
243
|
+
# CRCA: Causal Reasoning and Counterfactual Analysis (from core module)
|
|
244
|
+
self.crca_agent: Optional[Any] = None
|
|
245
|
+
if CRCA_AVAILABLE:
|
|
246
|
+
try:
|
|
247
|
+
# Initialize CRCAAgent with socioeconomic variables using core module
|
|
248
|
+
state_vars = ["P", "L", "U", "W", "S", "Y", "K", "I", "literacy", "Ecap", "Hcap"]
|
|
249
|
+
self.crca_agent = get_crca_agent(
|
|
250
|
+
variables=state_vars,
|
|
251
|
+
agent_name="pridnestrovia-causal-reasoning",
|
|
252
|
+
agent_description="Causal reasoning for Pridnestrovia socioeconomic dynamics",
|
|
253
|
+
model_name="gpt-4o-mini", # Use cheaper model for real-time
|
|
254
|
+
max_loops=2, # Quick causal analysis
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if self.crca_agent is not None:
|
|
258
|
+
# Build causal graph for socioeconomic system
|
|
259
|
+
self._build_socioeconomic_causal_graph()
|
|
260
|
+
logger.info("✓ CRCAAgent initialized - causal reasoning enabled")
|
|
261
|
+
else:
|
|
262
|
+
logger.info("⚠ CRCAAgent not available - running without causal reasoning")
|
|
263
|
+
except Exception as e:
|
|
264
|
+
logger.warning(f"Failed to initialize CRCAAgent: {e}")
|
|
265
|
+
self.crca_agent = None
|
|
266
|
+
else:
|
|
267
|
+
logger.info("⚠ CRCAAgent not available - running without causal reasoning")
|
|
268
|
+
|
|
269
|
+
# Runtime state
|
|
270
|
+
self.is_running = False
|
|
271
|
+
self.control_thread: Optional[threading.Thread] = None
|
|
272
|
+
self.previous_policy: Optional[ControlVector] = None
|
|
273
|
+
self.state_history: List[StateVector] = [self.x_current.copy()]
|
|
274
|
+
self.execution_history: List[Dict[str, Any]] = []
|
|
275
|
+
|
|
276
|
+
logger.info("✓ Real-time control system initialized")
|
|
277
|
+
logger.info("✓ All components ready for production operation")
|
|
278
|
+
|
|
279
|
+
def _build_socioeconomic_causal_graph(self) -> None:
|
|
280
|
+
"""
|
|
281
|
+
Build causal graph for Pridnestrovia socioeconomic system.
|
|
282
|
+
|
|
283
|
+
Defines causal relationships:
|
|
284
|
+
- Education → Literacy → Labor productivity → GDP
|
|
285
|
+
- Infrastructure → Transport capacity → Economic activity → GDP
|
|
286
|
+
- GDP → Wages → Stability
|
|
287
|
+
- Unemployment → Stability (negative)
|
|
288
|
+
- Capital investment → GDP growth
|
|
289
|
+
"""
|
|
290
|
+
if self.crca_agent is None:
|
|
291
|
+
return
|
|
292
|
+
|
|
293
|
+
# Core causal relationships for socioeconomic dynamics
|
|
294
|
+
causal_edges = [
|
|
295
|
+
# Education and human capital
|
|
296
|
+
("Ecap", "literacy", 0.3), # Education capacity → literacy
|
|
297
|
+
("literacy", "L", 0.4), # Literacy → labor force participation
|
|
298
|
+
("L", "Y", 0.5), # Labor → GDP
|
|
299
|
+
|
|
300
|
+
# Infrastructure and capital
|
|
301
|
+
("I", "Tcap", 0.6), # Infrastructure → transport capacity
|
|
302
|
+
("Tcap", "Y", 0.3), # Transport → GDP
|
|
303
|
+
("K", "Y", 0.7), # Capital → GDP (strong)
|
|
304
|
+
|
|
305
|
+
# Economic feedback loops
|
|
306
|
+
("Y", "W", 0.4), # GDP → wages
|
|
307
|
+
("W", "S", 0.5), # Wages → stability
|
|
308
|
+
("U", "S", -0.6), # Unemployment → stability (negative, strong)
|
|
309
|
+
|
|
310
|
+
# Resource constraints
|
|
311
|
+
("Ecap", "Y", 0.2), # Energy → GDP (using Ecap as proxy)
|
|
312
|
+
("Hcap", "S", 0.3), # Healthcare → stability
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
for source, target, strength in causal_edges:
|
|
316
|
+
try:
|
|
317
|
+
self.crca_agent.add_causal_relationship(source, target, strength=strength)
|
|
318
|
+
except Exception as e:
|
|
319
|
+
logger.debug(f"Could not add causal edge {source}→{target}: {e}")
|
|
320
|
+
|
|
321
|
+
logger.info(f"Built causal graph with {len(causal_edges)} relationships")
|
|
322
|
+
|
|
323
|
+
def _load_config(self, config_file: Optional[str]) -> Dict[str, Any]:
|
|
324
|
+
"""
|
|
325
|
+
Load configuration from file or environment.
|
|
326
|
+
|
|
327
|
+
Configuration can be provided via:
|
|
328
|
+
1. YAML config file (recommended for production)
|
|
329
|
+
2. Environment variables (see API_SETUP.md)
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
config_file: Path to YAML configuration file
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
Dict[str, Any]: Configuration dictionary
|
|
336
|
+
"""
|
|
337
|
+
config = {}
|
|
338
|
+
|
|
339
|
+
if config_file:
|
|
340
|
+
try:
|
|
341
|
+
import yaml
|
|
342
|
+
with open(config_file, 'r') as f:
|
|
343
|
+
config = yaml.safe_load(f)
|
|
344
|
+
logger.info(f"Loaded config from {config_file}")
|
|
345
|
+
except Exception as e:
|
|
346
|
+
logger.warning(f"Could not load config file: {e}")
|
|
347
|
+
|
|
348
|
+
# Environment variables as fallback
|
|
349
|
+
import os
|
|
350
|
+
config.setdefault("treasury_api_key", os.getenv("PRIDNESTROVIA_TREASURY_API_KEY"))
|
|
351
|
+
config.setdefault("ministries_api_key", os.getenv("PRIDNESTROVIA_MINISTRIES_API_KEY"))
|
|
352
|
+
config.setdefault("central_bank_api_key", os.getenv("PRIDNESTROVIA_CENTRAL_BANK_API_KEY"))
|
|
353
|
+
|
|
354
|
+
# Warn if no API keys found
|
|
355
|
+
if not any([
|
|
356
|
+
config.get("treasury_api_key"),
|
|
357
|
+
config.get("ministries_api_key"),
|
|
358
|
+
config.get("central_bank_api_key")
|
|
359
|
+
]):
|
|
360
|
+
logger.warning("⚠ No API keys found!")
|
|
361
|
+
logger.warning("Set environment variables or provide config file.")
|
|
362
|
+
logger.warning("See examples/API_SETUP.md for instructions.")
|
|
363
|
+
logger.warning("System will use mock data until API keys are configured.")
|
|
364
|
+
|
|
365
|
+
return config
|
|
366
|
+
|
|
367
|
+
def start(self) -> None:
|
|
368
|
+
"""Start the real-time control system."""
|
|
369
|
+
if self.is_running:
|
|
370
|
+
logger.warning("Control system already running")
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
self.is_running = True
|
|
374
|
+
self.control_thread = threading.Thread(target=self._control_loop, daemon=True)
|
|
375
|
+
self.control_thread.start()
|
|
376
|
+
|
|
377
|
+
logger.info("🚀 Real-time control system STARTED")
|
|
378
|
+
logger.info("System is now actively monitoring and controlling Pridnestrovia economy")
|
|
379
|
+
|
|
380
|
+
def stop(self) -> None:
|
|
381
|
+
"""Stop the real-time control system."""
|
|
382
|
+
self.is_running = False
|
|
383
|
+
if self.control_thread:
|
|
384
|
+
self.control_thread.join(timeout=10.0)
|
|
385
|
+
|
|
386
|
+
logger.info("⏹ Real-time control system STOPPED")
|
|
387
|
+
|
|
388
|
+
def _control_loop(self) -> None:
|
|
389
|
+
"""
|
|
390
|
+
Main control loop - runs continuously in REAL-TIME.
|
|
391
|
+
|
|
392
|
+
This is the core real-time control loop that:
|
|
393
|
+
1. Acquires real data from government systems and keyless APIs
|
|
394
|
+
2. Updates state estimates continuously
|
|
395
|
+
3. Monitors constraints in real-time
|
|
396
|
+
4. Optimizes policies via MPC towards successful republic vision
|
|
397
|
+
5. Executes policies (automated or with approval)
|
|
398
|
+
6. Tracks performance and adapts continuously
|
|
399
|
+
|
|
400
|
+
Goal: Navigate Pridnestrovia to a successful, prosperous republic.
|
|
401
|
+
"""
|
|
402
|
+
logger.info("Control loop started - running continuously in REAL-TIME")
|
|
403
|
+
logger.info("🎯 Mission: Navigate Pridnestrovia to a successful republic")
|
|
404
|
+
|
|
405
|
+
iteration = 0
|
|
406
|
+
last_data_update = 0.0
|
|
407
|
+
last_optimization = 0.0
|
|
408
|
+
|
|
409
|
+
# Real-time update frequencies (from config or defaults)
|
|
410
|
+
data_update_freq = 30.0 # 30 seconds (user configured)
|
|
411
|
+
optimization_freq = 60.0 # Optimize every 60 seconds
|
|
412
|
+
|
|
413
|
+
while self.is_running:
|
|
414
|
+
try:
|
|
415
|
+
iteration += 1
|
|
416
|
+
current_time = time.time()
|
|
417
|
+
|
|
418
|
+
# Real-time data acquisition and state update
|
|
419
|
+
if current_time - last_data_update >= data_update_freq:
|
|
420
|
+
logger.info(f"\n{'='*60}")
|
|
421
|
+
logger.info(f"Real-Time Update Cycle - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
422
|
+
logger.info(f"{'='*60}")
|
|
423
|
+
|
|
424
|
+
self._realtime_update_cycle()
|
|
425
|
+
last_data_update = current_time
|
|
426
|
+
|
|
427
|
+
# Continuous optimization towards successful republic
|
|
428
|
+
if current_time - last_optimization >= optimization_freq:
|
|
429
|
+
logger.info("🎯 Optimizing policy towards successful republic vision...")
|
|
430
|
+
self._optimize_towards_vision()
|
|
431
|
+
last_optimization = current_time
|
|
432
|
+
|
|
433
|
+
# Continuous monitoring (every cycle)
|
|
434
|
+
self._monitoring_cycle()
|
|
435
|
+
|
|
436
|
+
# Check for pending approvals
|
|
437
|
+
self._process_pending_approvals()
|
|
438
|
+
|
|
439
|
+
# Sleep for 1 second before next iteration
|
|
440
|
+
time.sleep(1.0)
|
|
441
|
+
|
|
442
|
+
except Exception as e:
|
|
443
|
+
logger.error(f"Error in control loop: {e}", exc_info=True)
|
|
444
|
+
self.alerting.create_alert(
|
|
445
|
+
AlertLevel.CRITICAL,
|
|
446
|
+
f"Control loop error: {str(e)}",
|
|
447
|
+
"control_loop"
|
|
448
|
+
)
|
|
449
|
+
time.sleep(10.0) # Wait before retrying
|
|
450
|
+
|
|
451
|
+
def _get_successful_republic_vision(self) -> StateVector:
|
|
452
|
+
"""
|
|
453
|
+
Define the vision: A successful, prosperous Pridnestrovia republic.
|
|
454
|
+
|
|
455
|
+
Target state for a successful republic:
|
|
456
|
+
- Low unemployment (< 5%)
|
|
457
|
+
- High GDP per capita
|
|
458
|
+
- High stability (> 80%)
|
|
459
|
+
- High literacy (99%+)
|
|
460
|
+
- Strong infrastructure (> 80%)
|
|
461
|
+
- Sustainable ecological balance
|
|
462
|
+
- Growing economy
|
|
463
|
+
|
|
464
|
+
Returns:
|
|
465
|
+
StateVector: Target vision state
|
|
466
|
+
"""
|
|
467
|
+
# Start from current state and scale up to vision
|
|
468
|
+
current = self.x_current
|
|
469
|
+
|
|
470
|
+
# Vision targets (scaled appropriately)
|
|
471
|
+
vision = StateVector(
|
|
472
|
+
P=current.P, # Population grows naturally
|
|
473
|
+
L=current.P * 0.55, # 55% labor force participation (healthy)
|
|
474
|
+
U=0.04, # 4% unemployment (full employment target)
|
|
475
|
+
W=current.W * 1.5, # 50% wage increase
|
|
476
|
+
S=0.85, # 85% stability (high confidence)
|
|
477
|
+
literacy=0.99, # 99% literacy (maintain excellence)
|
|
478
|
+
Ecap=current.P * 0.20, # 20% education capacity
|
|
479
|
+
Hcap=current.P * 0.01, # 1% healthcare capacity (10 beds/1000)
|
|
480
|
+
K=current.Y * 4.0, # 4x capital-output ratio (developed economy)
|
|
481
|
+
I=0.85, # 85% infrastructure health
|
|
482
|
+
Tcap=current.Tcap * 2.0, # 2x transport capacity
|
|
483
|
+
E_stock=current.E_stock * 1.5, # Energy security
|
|
484
|
+
F_stock=current.F_stock * 1.5, # Food security
|
|
485
|
+
M_stock=current.M_stock * 1.5, # Materials security
|
|
486
|
+
C=min(current.C, current.C * 0.9), # Reduce ecological damage
|
|
487
|
+
Y=current.Y * 2.0, # 2x GDP (double the economy)
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
return vision
|
|
491
|
+
|
|
492
|
+
def _compute_progress_towards_vision(self) -> Dict[str, float]:
|
|
493
|
+
"""
|
|
494
|
+
Compute progress towards successful republic vision.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
Dict[str, float]: Progress metrics (0-1, where 1 = vision achieved)
|
|
498
|
+
"""
|
|
499
|
+
current = self.x_current
|
|
500
|
+
vision = self._get_successful_republic_vision()
|
|
501
|
+
|
|
502
|
+
progress = {
|
|
503
|
+
"unemployment": max(0, 1.0 - (current.U / vision.U)) if vision.U > 0 else 0.0,
|
|
504
|
+
"gdp": min(1.0, current.Y / vision.Y) if vision.Y > 0 else 0.0,
|
|
505
|
+
"stability": current.S / vision.S if vision.S > 0 else 0.0,
|
|
506
|
+
"infrastructure": current.I / vision.I if vision.I > 0 else 0.0,
|
|
507
|
+
"literacy": current.literacy / vision.literacy if vision.literacy > 0 else 0.0,
|
|
508
|
+
"overall": 0.0,
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
# Overall progress (weighted average)
|
|
512
|
+
progress["overall"] = (
|
|
513
|
+
progress["unemployment"] * 0.25 +
|
|
514
|
+
progress["gdp"] * 0.25 +
|
|
515
|
+
progress["stability"] * 0.20 +
|
|
516
|
+
progress["infrastructure"] * 0.15 +
|
|
517
|
+
progress["literacy"] * 0.15
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
return progress
|
|
521
|
+
|
|
522
|
+
def _realtime_update_cycle(self) -> None:
|
|
523
|
+
"""
|
|
524
|
+
Real-time update cycle: data acquisition and state estimation.
|
|
525
|
+
Runs every 30 seconds (or configured frequency).
|
|
526
|
+
"""
|
|
527
|
+
logger.info("--- Real-Time Update Cycle ---")
|
|
528
|
+
|
|
529
|
+
# 1. Acquire real data from APIs (keyless or government)
|
|
530
|
+
logger.info("Step 1: Acquiring real-time data...")
|
|
531
|
+
data_points = self._acquire_real_data()
|
|
532
|
+
|
|
533
|
+
if not data_points:
|
|
534
|
+
logger.warning("No data acquired - using last known state")
|
|
535
|
+
return
|
|
536
|
+
|
|
537
|
+
# 2. Process data through pipeline (no normalization - use raw values)
|
|
538
|
+
logger.info(f"Step 2: Processing {len(data_points)} data points...")
|
|
539
|
+
processed_data = self.data_pipeline.process_data_points(data_points, normalize=False)
|
|
540
|
+
|
|
541
|
+
# 3. Update state estimate in real-time
|
|
542
|
+
logger.info("Step 3: Updating state estimate...")
|
|
543
|
+
if self.previous_policy is None:
|
|
544
|
+
u_current = ControlVector.sample_budget_simplex([
|
|
545
|
+
"energy", "food", "infrastructure", "education",
|
|
546
|
+
"healthcare", "R&D", "welfare"
|
|
547
|
+
])
|
|
548
|
+
else:
|
|
549
|
+
u_current = self.previous_policy
|
|
550
|
+
|
|
551
|
+
x_estimated = self.state_estimator.update_with_data_points(processed_data, u_current)
|
|
552
|
+
self.x_current = x_estimated
|
|
553
|
+
self.state_history.append(x_estimated.copy())
|
|
554
|
+
|
|
555
|
+
# Compute progress towards vision
|
|
556
|
+
progress = self._compute_progress_towards_vision()
|
|
557
|
+
|
|
558
|
+
logger.info(f"State updated: P={x_estimated.P:,.0f}, U={x_estimated.U:.1%}, "
|
|
559
|
+
f"Y=${x_estimated.Y/1e9:.2f}B, S={x_estimated.S:.1%}")
|
|
560
|
+
logger.info(f"🎯 Progress towards successful republic: {progress['overall']:.1%}")
|
|
561
|
+
|
|
562
|
+
# 4. Monitor constraints
|
|
563
|
+
logger.info("Step 4: Monitoring constraints...")
|
|
564
|
+
is_feasible, violations, metrics = self.monitor.check_state(self.x_current, u_current)
|
|
565
|
+
|
|
566
|
+
if violations:
|
|
567
|
+
logger.warning(f"Constraint violations detected: {len(violations)}")
|
|
568
|
+
self.alerting.create_alert(
|
|
569
|
+
AlertLevel.WARNING,
|
|
570
|
+
f"Constraint violations: {', '.join(violations[:3])}",
|
|
571
|
+
"monitor",
|
|
572
|
+
{"violations": violations}
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
def _optimize_towards_vision(self) -> None:
|
|
576
|
+
"""
|
|
577
|
+
Continuously optimize policy towards successful republic vision.
|
|
578
|
+
Runs every 60 seconds (or configured frequency).
|
|
579
|
+
"""
|
|
580
|
+
# 5. Optimize policy via MPC (goal-oriented towards vision)
|
|
581
|
+
logger.info("Step 5: Optimizing policy towards successful republic vision...")
|
|
582
|
+
policy = self._optimize_policy_towards_vision()
|
|
583
|
+
|
|
584
|
+
if policy is None:
|
|
585
|
+
logger.warning("MPC optimization failed - no policy generated")
|
|
586
|
+
return
|
|
587
|
+
|
|
588
|
+
# 6. Check safety and approval requirements
|
|
589
|
+
logger.info("Step 6: Checking safety and approval requirements...")
|
|
590
|
+
state_confidence = self.state_estimator.get_confidence()
|
|
591
|
+
is_safe, reason, requires_approval = self.safety.check_policy_safety(
|
|
592
|
+
policy,
|
|
593
|
+
self.previous_policy,
|
|
594
|
+
state_confidence
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
if not is_safe:
|
|
598
|
+
logger.error(f"Policy unsafe: {reason}")
|
|
599
|
+
self.alerting.create_alert(
|
|
600
|
+
AlertLevel.CRITICAL,
|
|
601
|
+
f"Unsafe policy blocked: {reason}",
|
|
602
|
+
"safety_interlocks"
|
|
603
|
+
)
|
|
604
|
+
return
|
|
605
|
+
|
|
606
|
+
# 7. Execute or request approval
|
|
607
|
+
if requires_approval:
|
|
608
|
+
logger.info(f"Major change detected - requesting human approval: {reason}")
|
|
609
|
+
self._request_approval(policy, reason)
|
|
610
|
+
else:
|
|
611
|
+
logger.info("Minor change - executing automatically to advance towards vision")
|
|
612
|
+
self._execute_policy(policy, automated=True)
|
|
613
|
+
|
|
614
|
+
# 8. Create snapshot for rollback
|
|
615
|
+
self.rollback.create_snapshot(self.x_current)
|
|
616
|
+
|
|
617
|
+
logger.info("✓ Optimization cycle complete")
|
|
618
|
+
|
|
619
|
+
def _optimize_policy_towards_vision(self) -> Optional[ControlVector]:
|
|
620
|
+
"""
|
|
621
|
+
Optimize policy using MPC with goal-oriented objectives + CRCA causal reasoning.
|
|
622
|
+
|
|
623
|
+
Uses CRCA for:
|
|
624
|
+
1. Causal scenario generation (not just random)
|
|
625
|
+
2. Understanding why policies work (causal validation)
|
|
626
|
+
3. Counterfactual analysis (what-if scenarios)
|
|
627
|
+
4. Causal policy recommendations
|
|
628
|
+
|
|
629
|
+
Objectives weighted towards successful republic vision:
|
|
630
|
+
- Maximize GDP growth
|
|
631
|
+
- Minimize unemployment
|
|
632
|
+
- Maximize stability
|
|
633
|
+
- Maintain high literacy
|
|
634
|
+
- Build infrastructure
|
|
635
|
+
- Ensure sustainability
|
|
636
|
+
|
|
637
|
+
Returns:
|
|
638
|
+
Optional[ControlVector]: Optimized policy or None if failed
|
|
639
|
+
"""
|
|
640
|
+
# Generate scenarios (use CRCA for causal scenarios if available)
|
|
641
|
+
scenarios = self._generate_causal_scenarios()
|
|
642
|
+
|
|
643
|
+
# Get vision for goal-oriented optimization
|
|
644
|
+
vision = self._get_successful_republic_vision()
|
|
645
|
+
progress = self._compute_progress_towards_vision()
|
|
646
|
+
|
|
647
|
+
# Use CRCA to understand causal relationships and get recommendations
|
|
648
|
+
if self.crca_agent is not None:
|
|
649
|
+
causal_insights = self._get_causal_insights()
|
|
650
|
+
if causal_insights:
|
|
651
|
+
logger.info("🔍 CRCA: Using causal reasoning to guide optimization")
|
|
652
|
+
|
|
653
|
+
# Adjust objective weights based on progress
|
|
654
|
+
objective_weights = np.array([
|
|
655
|
+
0.25 if progress["unemployment"] < 0.8 else 0.15, # J_U: High priority if unemployment high
|
|
656
|
+
0.10, # J_ℓ: Literacy (maintain)
|
|
657
|
+
0.30 if progress["gdp"] < 0.7 else 0.20, # J_Y: High priority if GDP low
|
|
658
|
+
0.10, # J_ineq: Inequality
|
|
659
|
+
0.10, # J_C: Ecological (sustainability)
|
|
660
|
+
0.15, # J_risk: Risk management
|
|
661
|
+
])
|
|
662
|
+
objective_weights = objective_weights / objective_weights.sum() # Normalize
|
|
663
|
+
|
|
664
|
+
# Solve MPC with vision-oriented weights
|
|
665
|
+
try:
|
|
666
|
+
policy, solver_info = self.solver.solve(
|
|
667
|
+
self.x_current,
|
|
668
|
+
scenarios,
|
|
669
|
+
objective_weights=objective_weights,
|
|
670
|
+
u_prev=self.previous_policy
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
# Use CRCA to validate policy causally
|
|
674
|
+
if self.crca_agent is not None:
|
|
675
|
+
policy_validated = self._validate_policy_causally(policy)
|
|
676
|
+
if not policy_validated:
|
|
677
|
+
logger.warning("CRCA: Policy failed causal validation, but allowing anyway")
|
|
678
|
+
|
|
679
|
+
# Evaluate policy against vision
|
|
680
|
+
from crca_sd.crca_sd_core import ForwardSimulator
|
|
681
|
+
simulator = ForwardSimulator(self.dynamics, self.checker)
|
|
682
|
+
traj, _, _ = simulator.simulate_scenario(
|
|
683
|
+
self.x_current,
|
|
684
|
+
policy,
|
|
685
|
+
scenarios[0] if scenarios else [],
|
|
686
|
+
horizon=12
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
# Check if policy moves towards vision
|
|
690
|
+
if traj:
|
|
691
|
+
final_state = traj[-1]
|
|
692
|
+
vision_progress = self._compute_progress_towards_vision()
|
|
693
|
+
|
|
694
|
+
logger.info(f"MPC solved: best_score={solver_info.get('best_score', 'N/A'):.4f}")
|
|
695
|
+
logger.info(f"🎯 Policy moves towards vision: {vision_progress['overall']:.1%} progress")
|
|
696
|
+
logger.debug(f"Policy: {policy.budget_shares}")
|
|
697
|
+
|
|
698
|
+
return policy
|
|
699
|
+
|
|
700
|
+
except Exception as e:
|
|
701
|
+
logger.error(f"MPC optimization failed: {e}")
|
|
702
|
+
return None
|
|
703
|
+
|
|
704
|
+
return None
|
|
705
|
+
|
|
706
|
+
def _generate_causal_scenarios(self) -> List[List[Dict[str, float]]]:
|
|
707
|
+
"""
|
|
708
|
+
Generate scenarios using CRCA causal reasoning (via core module).
|
|
709
|
+
|
|
710
|
+
Uses ScenarioGenerator.generate_causal_scenarios() from crca_sd core module.
|
|
711
|
+
|
|
712
|
+
Returns:
|
|
713
|
+
List[List[Dict[str, float]]]: Causal scenarios
|
|
714
|
+
"""
|
|
715
|
+
# Use ScenarioGenerator with CRCA agent (from core module)
|
|
716
|
+
scenario_gen = ScenarioGenerator(crca_agent=self.crca_agent)
|
|
717
|
+
|
|
718
|
+
# Use core module's generate_causal_scenarios() method
|
|
719
|
+
try:
|
|
720
|
+
scenarios = scenario_gen.generate_causal_scenarios(
|
|
721
|
+
n_scenarios=10,
|
|
722
|
+
horizon=12,
|
|
723
|
+
current_state=self.x_current,
|
|
724
|
+
target_variables=["Y", "U", "S"] # Focus on GDP, unemployment, stability
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
if scenarios:
|
|
728
|
+
logger.info(f"🔍 CRCA: Generated {len(scenarios)} causal scenarios via core module")
|
|
729
|
+
return scenarios
|
|
730
|
+
else:
|
|
731
|
+
# Fallback to Gaussian
|
|
732
|
+
logger.debug("No causal scenarios generated, using Gaussian fallback")
|
|
733
|
+
return scenario_gen.generate_gaussian(n_scenarios=10, horizon=12)
|
|
734
|
+
|
|
735
|
+
except Exception as e:
|
|
736
|
+
logger.warning(f"CRCA scenario generation failed: {e}, using random scenarios")
|
|
737
|
+
return scenario_gen.generate_gaussian(n_scenarios=10, horizon=12)
|
|
738
|
+
|
|
739
|
+
def _get_causal_insights(self) -> Optional[Dict[str, Any]]:
|
|
740
|
+
"""
|
|
741
|
+
Get causal insights from CRCA about current state and policy recommendations.
|
|
742
|
+
|
|
743
|
+
Returns:
|
|
744
|
+
Optional[Dict[str, Any]]: Causal insights and recommendations
|
|
745
|
+
"""
|
|
746
|
+
if self.crca_agent is None:
|
|
747
|
+
return None
|
|
748
|
+
|
|
749
|
+
try:
|
|
750
|
+
# Ask CRCA for causal analysis (text-based, LLM mode)
|
|
751
|
+
task = (
|
|
752
|
+
f"Analyze the causal relationships in Pridnestrovia's economy. "
|
|
753
|
+
f"Current state: GDP=${self.x_current.Y/1e9:.2f}B, "
|
|
754
|
+
f"Unemployment={self.x_current.U:.1%}, Stability={self.x_current.S:.1%}. "
|
|
755
|
+
f"What are the key causal factors affecting economic growth and stability?"
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
result = self.crca_agent.run(task=task)
|
|
759
|
+
|
|
760
|
+
causal_analysis = result.get("causal_analysis", "")
|
|
761
|
+
|
|
762
|
+
if causal_analysis:
|
|
763
|
+
logger.debug(f"CRCA analysis: {causal_analysis[:200]}...")
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
"analysis": causal_analysis,
|
|
767
|
+
"counterfactuals": result.get("counterfactual_scenarios", []),
|
|
768
|
+
"graph_info": result.get("causal_graph_info", {}),
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
except Exception as e:
|
|
772
|
+
logger.debug(f"CRCA causal analysis failed: {e}")
|
|
773
|
+
return None
|
|
774
|
+
|
|
775
|
+
def _validate_policy_causally(self, policy: ControlVector) -> bool:
|
|
776
|
+
"""
|
|
777
|
+
Validate policy using causal reasoning.
|
|
778
|
+
|
|
779
|
+
Uses CRCA to check if policy makes causal sense.
|
|
780
|
+
|
|
781
|
+
Args:
|
|
782
|
+
policy: Policy to validate
|
|
783
|
+
|
|
784
|
+
Returns:
|
|
785
|
+
bool: True if policy is causally valid
|
|
786
|
+
"""
|
|
787
|
+
if self.crca_agent is None:
|
|
788
|
+
return True # No validation if CRCA not available
|
|
789
|
+
|
|
790
|
+
try:
|
|
791
|
+
# Convert policy to interventions
|
|
792
|
+
current_state_dict = {
|
|
793
|
+
"P": self.x_current.P,
|
|
794
|
+
"L": self.x_current.L,
|
|
795
|
+
"U": self.x_current.U,
|
|
796
|
+
"W": self.x_current.W,
|
|
797
|
+
"S": self.x_current.S,
|
|
798
|
+
"Y": self.x_current.Y,
|
|
799
|
+
"K": self.x_current.K,
|
|
800
|
+
"I": self.x_current.I,
|
|
801
|
+
"literacy": self.x_current.literacy,
|
|
802
|
+
"Ecap": self.x_current.Ecap,
|
|
803
|
+
"Hcap": self.x_current.Hcap,
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
# Map budget shares to causal interventions
|
|
807
|
+
interventions = {}
|
|
808
|
+
for category, share in policy.budget_shares.items():
|
|
809
|
+
# Map budget categories to state variables
|
|
810
|
+
if category == "education":
|
|
811
|
+
interventions["Ecap"] = current_state_dict.get("Ecap", 0) * (1 + share * 0.1)
|
|
812
|
+
elif category == "infrastructure":
|
|
813
|
+
interventions["I"] = min(1.0, current_state_dict.get("I", 0) + share * 0.05)
|
|
814
|
+
elif category == "R&D":
|
|
815
|
+
interventions["K"] = current_state_dict.get("K", 0) * (1 + share * 0.1)
|
|
816
|
+
|
|
817
|
+
# Use CRCA to predict outcomes
|
|
818
|
+
predicted = self.crca_agent._predict_outcomes(current_state_dict, interventions)
|
|
819
|
+
|
|
820
|
+
# Check if predicted outcomes move towards vision
|
|
821
|
+
y_increase = predicted.get("Y", current_state_dict.get("Y", 0)) > current_state_dict.get("Y", 0)
|
|
822
|
+
u_decrease = predicted.get("U", current_state_dict.get("U", 1)) < current_state_dict.get("U", 1)
|
|
823
|
+
|
|
824
|
+
if y_increase and u_decrease:
|
|
825
|
+
logger.debug("✓ CRCA: Policy causally validated")
|
|
826
|
+
return True
|
|
827
|
+
else:
|
|
828
|
+
logger.debug("⚠ CRCA: Policy may not achieve desired causal outcomes")
|
|
829
|
+
return True # Still allow, but warn
|
|
830
|
+
|
|
831
|
+
except Exception as e:
|
|
832
|
+
logger.debug(f"CRCA validation failed: {e}")
|
|
833
|
+
return True # Default to allowing policy
|
|
834
|
+
|
|
835
|
+
def _daily_update_cycle(self) -> None:
|
|
836
|
+
"""Execute daily update cycle: data acquisition, state estimation, policy optimization."""
|
|
837
|
+
logger.info("--- Daily Update Cycle ---")
|
|
838
|
+
|
|
839
|
+
# 1. Acquire real data from government systems
|
|
840
|
+
logger.info("Step 1: Acquiring data from government systems...")
|
|
841
|
+
data_points = self._acquire_real_data()
|
|
842
|
+
|
|
843
|
+
if not data_points:
|
|
844
|
+
logger.warning("No data acquired - using last known state")
|
|
845
|
+
self.alerting.create_alert(
|
|
846
|
+
AlertLevel.WARNING,
|
|
847
|
+
"Data acquisition failed - no new data available",
|
|
848
|
+
"data_acquisition"
|
|
849
|
+
)
|
|
850
|
+
return
|
|
851
|
+
|
|
852
|
+
# 2. Process data through pipeline
|
|
853
|
+
logger.info(f"Step 2: Processing {len(data_points)} data points...")
|
|
854
|
+
processed_data = self.data_pipeline.process_data_points(data_points)
|
|
855
|
+
|
|
856
|
+
# 3. Update state estimate
|
|
857
|
+
logger.info("Step 3: Updating state estimate...")
|
|
858
|
+
# Use previous policy or create default valid control vector
|
|
859
|
+
if self.previous_policy is None:
|
|
860
|
+
u_current = ControlVector.sample_budget_simplex([
|
|
861
|
+
"energy", "food", "infrastructure", "education",
|
|
862
|
+
"healthcare", "R&D", "welfare"
|
|
863
|
+
])
|
|
864
|
+
else:
|
|
865
|
+
u_current = self.previous_policy
|
|
866
|
+
x_estimated = self.state_estimator.update_with_data_points(processed_data, u_current)
|
|
867
|
+
self.x_current = x_estimated
|
|
868
|
+
self.state_history.append(x_estimated.copy())
|
|
869
|
+
|
|
870
|
+
logger.info(f"State updated: P={x_estimated.P:,.0f}, U={x_estimated.U:.1%}, "
|
|
871
|
+
f"Y=${x_estimated.Y/1e9:.2f}B, S={x_estimated.S:.1%}")
|
|
872
|
+
|
|
873
|
+
# 4. Monitor constraints
|
|
874
|
+
logger.info("Step 4: Monitoring constraints...")
|
|
875
|
+
is_feasible, violations, metrics = self.monitor.check_state(self.x_current, u_current)
|
|
876
|
+
|
|
877
|
+
if violations:
|
|
878
|
+
logger.warning(f"Constraint violations detected: {len(violations)}")
|
|
879
|
+
self.alerting.create_alert(
|
|
880
|
+
AlertLevel.WARNING,
|
|
881
|
+
f"Constraint violations: {', '.join(violations[:3])}",
|
|
882
|
+
"monitor",
|
|
883
|
+
{"violations": violations}
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
# 5. Optimize policy via MPC
|
|
887
|
+
logger.info("Step 5: Optimizing policy via MPC...")
|
|
888
|
+
policy = self._optimize_policy()
|
|
889
|
+
|
|
890
|
+
if policy is None:
|
|
891
|
+
logger.warning("MPC optimization failed - no policy generated")
|
|
892
|
+
return
|
|
893
|
+
|
|
894
|
+
# 6. Check safety and approval requirements
|
|
895
|
+
logger.info("Step 6: Checking safety and approval requirements...")
|
|
896
|
+
state_confidence = self.state_estimator.get_confidence()
|
|
897
|
+
is_safe, reason, requires_approval = self.safety.check_policy_safety(
|
|
898
|
+
policy,
|
|
899
|
+
self.previous_policy,
|
|
900
|
+
state_confidence
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
if not is_safe:
|
|
904
|
+
logger.error(f"Policy unsafe: {reason}")
|
|
905
|
+
self.alerting.create_alert(
|
|
906
|
+
AlertLevel.CRITICAL,
|
|
907
|
+
f"Unsafe policy blocked: {reason}",
|
|
908
|
+
"safety_interlocks"
|
|
909
|
+
)
|
|
910
|
+
return
|
|
911
|
+
|
|
912
|
+
# 7. Execute or request approval
|
|
913
|
+
if requires_approval:
|
|
914
|
+
logger.info(f"Major change detected - requesting human approval: {reason}")
|
|
915
|
+
self._request_approval(policy, reason)
|
|
916
|
+
else:
|
|
917
|
+
logger.info("Minor change - executing automatically")
|
|
918
|
+
self._execute_policy(policy, automated=True)
|
|
919
|
+
|
|
920
|
+
# 8. Create snapshot for rollback
|
|
921
|
+
self.rollback.create_snapshot(self.x_current)
|
|
922
|
+
|
|
923
|
+
logger.info("✓ Daily update cycle complete")
|
|
924
|
+
|
|
925
|
+
def _acquire_real_data(self) -> List:
|
|
926
|
+
"""
|
|
927
|
+
Acquire REAL data from government systems and keyless public APIs.
|
|
928
|
+
|
|
929
|
+
Priority:
|
|
930
|
+
1. Government APIs (if API keys available)
|
|
931
|
+
2. Keyless public APIs (World Bank, REST Countries, etc.)
|
|
932
|
+
3. Fallback to mock data
|
|
933
|
+
|
|
934
|
+
Returns:
|
|
935
|
+
List[DataPoint]: Real data points from APIs
|
|
936
|
+
"""
|
|
937
|
+
all_data_points = []
|
|
938
|
+
|
|
939
|
+
# Try government APIs first (if keys available)
|
|
940
|
+
has_government_keys = any([
|
|
941
|
+
self.config.get("treasury_api_key"),
|
|
942
|
+
self.config.get("ministries_api_key"),
|
|
943
|
+
self.config.get("central_bank_api_key")
|
|
944
|
+
])
|
|
945
|
+
|
|
946
|
+
if has_government_keys:
|
|
947
|
+
# Treasury API - budget, spending, revenue
|
|
948
|
+
if self.data_acq.should_update("treasury"):
|
|
949
|
+
treasury_data = self.data_acq.fetch_government_data(
|
|
950
|
+
"treasury",
|
|
951
|
+
"v1/current_budget",
|
|
952
|
+
["Y", "E_stock", "F_stock", "M_stock"] # GDP, energy, food, materials
|
|
953
|
+
)
|
|
954
|
+
all_data_points.extend(treasury_data)
|
|
955
|
+
logger.debug(f"Acquired {len(treasury_data)} data points from treasury")
|
|
956
|
+
|
|
957
|
+
# Ministries API - population, labor, unemployment, education, healthcare
|
|
958
|
+
if self.data_acq.should_update("ministries"):
|
|
959
|
+
ministries_data = self.data_acq.fetch_government_data(
|
|
960
|
+
"ministries",
|
|
961
|
+
"v1/demographics",
|
|
962
|
+
["P", "L", "U", "literacy", "Ecap", "Hcap"]
|
|
963
|
+
)
|
|
964
|
+
all_data_points.extend(ministries_data)
|
|
965
|
+
logger.debug(f"Acquired {len(ministries_data)} data points from ministries")
|
|
966
|
+
|
|
967
|
+
# Central Bank API - monetary policy, exchange rates, inflation
|
|
968
|
+
if self.data_acq.should_update("central_bank"):
|
|
969
|
+
central_bank_data = self.data_acq.fetch_government_data(
|
|
970
|
+
"central_bank",
|
|
971
|
+
"v1/economic_indicators",
|
|
972
|
+
["Y", "W", "S", "I", "Tcap"] # GDP, wage, stability, infrastructure, transport
|
|
973
|
+
)
|
|
974
|
+
all_data_points.extend(central_bank_data)
|
|
975
|
+
logger.debug(f"Acquired {len(central_bank_data)} data points from central bank")
|
|
976
|
+
|
|
977
|
+
# Fallback to keyless public APIs if no government keys
|
|
978
|
+
if not has_government_keys or len(all_data_points) == 0:
|
|
979
|
+
logger.info("Using keyless public APIs (World Bank, REST Countries)")
|
|
980
|
+
|
|
981
|
+
# World Bank API (keyless, free)
|
|
982
|
+
# Use Moldova as proxy (Pridnestrovia is part of Moldova region)
|
|
983
|
+
world_bank_indicators = {
|
|
984
|
+
"Y": "NY.GDP.MKTP.CD", # GDP (current US$)
|
|
985
|
+
"P": "SP.POP.TOTL", # Population, total
|
|
986
|
+
"U": "SL.UEM.TOTL.ZS", # Unemployment, total (% of total labor force)
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
wb_data = self.data_acq.fetch_world_bank_data("MD", world_bank_indicators)
|
|
990
|
+
all_data_points.extend(wb_data)
|
|
991
|
+
logger.info(f"Acquired {len(wb_data)} data points from World Bank API")
|
|
992
|
+
|
|
993
|
+
# REST Countries API (keyless, free)
|
|
994
|
+
# Get population and basic demographics
|
|
995
|
+
rest_data = self.data_acq.fetch_restcountries_data("Moldova", ["P"])
|
|
996
|
+
all_data_points.extend(rest_data)
|
|
997
|
+
logger.info(f"Acquired {len(rest_data)} data points from REST Countries API")
|
|
998
|
+
|
|
999
|
+
# If still no data, use mock (but log warning)
|
|
1000
|
+
if len(all_data_points) == 0:
|
|
1001
|
+
logger.warning("No data acquired from any source, using mock data")
|
|
1002
|
+
# Generate mock data as fallback
|
|
1003
|
+
mock_data = self.data_acq._generate_mock_data(
|
|
1004
|
+
["P", "U", "Y", "E_stock", "F_stock"],
|
|
1005
|
+
DataSourceType.PUBLIC_API,
|
|
1006
|
+
"mock_fallback"
|
|
1007
|
+
)
|
|
1008
|
+
all_data_points.extend(mock_data)
|
|
1009
|
+
|
|
1010
|
+
return all_data_points
|
|
1011
|
+
|
|
1012
|
+
def _optimize_policy(self) -> Optional[ControlVector]:
|
|
1013
|
+
"""
|
|
1014
|
+
Optimize policy using MPC.
|
|
1015
|
+
|
|
1016
|
+
Returns:
|
|
1017
|
+
Optional[ControlVector]: Optimized policy or None if failed
|
|
1018
|
+
"""
|
|
1019
|
+
# Generate scenarios (use CRCA if available)
|
|
1020
|
+
scenario_gen = ScenarioGenerator(crca_agent=self.crca_agent)
|
|
1021
|
+
if self.crca_agent is not None:
|
|
1022
|
+
try:
|
|
1023
|
+
scenarios = scenario_gen.generate_causal_scenarios(
|
|
1024
|
+
n_scenarios=10,
|
|
1025
|
+
horizon=12,
|
|
1026
|
+
current_state=self.x_current
|
|
1027
|
+
)
|
|
1028
|
+
except Exception:
|
|
1029
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=10, horizon=12)
|
|
1030
|
+
else:
|
|
1031
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=10, horizon=12)
|
|
1032
|
+
|
|
1033
|
+
# Solve MPC
|
|
1034
|
+
try:
|
|
1035
|
+
policy, solver_info = self.solver.solve(
|
|
1036
|
+
self.x_current,
|
|
1037
|
+
scenarios,
|
|
1038
|
+
u_prev=self.previous_policy
|
|
1039
|
+
)
|
|
1040
|
+
|
|
1041
|
+
logger.info(f"MPC solved: best_score={solver_info.get('best_score', 'N/A'):.4f}")
|
|
1042
|
+
logger.debug(f"Policy: {policy.budget_shares}")
|
|
1043
|
+
|
|
1044
|
+
return policy
|
|
1045
|
+
|
|
1046
|
+
except Exception as e:
|
|
1047
|
+
logger.error(f"MPC optimization failed: {e}")
|
|
1048
|
+
return None
|
|
1049
|
+
|
|
1050
|
+
def _request_approval(self, policy: ControlVector, reason: str) -> None:
|
|
1051
|
+
"""
|
|
1052
|
+
Request human approval for major policy change.
|
|
1053
|
+
|
|
1054
|
+
Args:
|
|
1055
|
+
policy: Policy requiring approval
|
|
1056
|
+
reason: Reason for approval
|
|
1057
|
+
"""
|
|
1058
|
+
# Compute objectives for context
|
|
1059
|
+
from crca_sd.crca_sd_core import ForwardSimulator
|
|
1060
|
+
simulator = ForwardSimulator(self.dynamics, self.checker)
|
|
1061
|
+
scenario_gen = ScenarioGenerator(crca_agent=self.crca_agent)
|
|
1062
|
+
if self.crca_agent is not None:
|
|
1063
|
+
try:
|
|
1064
|
+
scenarios = scenario_gen.generate_causal_scenarios(
|
|
1065
|
+
n_scenarios=3,
|
|
1066
|
+
horizon=12,
|
|
1067
|
+
current_state=self.x_current
|
|
1068
|
+
)
|
|
1069
|
+
except Exception:
|
|
1070
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=3, horizon=12)
|
|
1071
|
+
else:
|
|
1072
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=3, horizon=12)
|
|
1073
|
+
|
|
1074
|
+
traj, _, _ = simulator.simulate_scenario(self.x_current, policy, scenarios[0], horizon=12)
|
|
1075
|
+
objectives = self.obj_computer.compute(traj, [policy] * 12)
|
|
1076
|
+
|
|
1077
|
+
# Request approval
|
|
1078
|
+
approval_id = self.governance.request_approval(
|
|
1079
|
+
policy,
|
|
1080
|
+
reason,
|
|
1081
|
+
"system",
|
|
1082
|
+
objectives=objectives
|
|
1083
|
+
)
|
|
1084
|
+
|
|
1085
|
+
logger.info(f"Approval requested: {approval_id}")
|
|
1086
|
+
logger.info(f"Reason: {reason}")
|
|
1087
|
+
logger.info(f"Pending approvals: {len(self.governance.get_pending_approvals())}")
|
|
1088
|
+
|
|
1089
|
+
# Log for compliance
|
|
1090
|
+
self.compliance.log_decision(
|
|
1091
|
+
"approval_request",
|
|
1092
|
+
policy.to_dict(),
|
|
1093
|
+
"system",
|
|
1094
|
+
reason,
|
|
1095
|
+
approved_by=[]
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
# Alert human operators
|
|
1099
|
+
self.alerting.create_alert(
|
|
1100
|
+
AlertLevel.WARNING,
|
|
1101
|
+
f"Policy approval required: {reason}",
|
|
1102
|
+
"governance",
|
|
1103
|
+
{"approval_id": approval_id, "policy": policy.to_dict()}
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
def _execute_policy(self, policy: ControlVector, automated: bool = True) -> bool:
|
|
1107
|
+
"""
|
|
1108
|
+
Execute policy via government API (REAL execution).
|
|
1109
|
+
|
|
1110
|
+
Args:
|
|
1111
|
+
policy: Policy to execute
|
|
1112
|
+
automated: Whether this is automated execution
|
|
1113
|
+
|
|
1114
|
+
Returns:
|
|
1115
|
+
bool: True if execution successful
|
|
1116
|
+
"""
|
|
1117
|
+
logger.info("Executing policy via government API...")
|
|
1118
|
+
|
|
1119
|
+
# Execute via PolicyExecutor (REAL API calls)
|
|
1120
|
+
success, message, exec_info = self.policy_executor.execute_policy(
|
|
1121
|
+
policy,
|
|
1122
|
+
require_approval=False
|
|
1123
|
+
)
|
|
1124
|
+
|
|
1125
|
+
if success:
|
|
1126
|
+
execution_id = exec_info.get("execution_id", "unknown")
|
|
1127
|
+
|
|
1128
|
+
# Record in rollback system
|
|
1129
|
+
self.rollback.record_policy_execution(policy, execution_id)
|
|
1130
|
+
|
|
1131
|
+
# Log for compliance
|
|
1132
|
+
self.compliance.log_decision(
|
|
1133
|
+
"policy_execution",
|
|
1134
|
+
policy.to_dict(),
|
|
1135
|
+
"system" if automated else "human_operator",
|
|
1136
|
+
"Automated execution" if automated else "Manual execution",
|
|
1137
|
+
approved_by=["system"] if automated else []
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
# Track accountability
|
|
1141
|
+
self.accountability.attribute_decision(
|
|
1142
|
+
execution_id,
|
|
1143
|
+
policy,
|
|
1144
|
+
["system"] if automated else ["human_operator"],
|
|
1145
|
+
)
|
|
1146
|
+
|
|
1147
|
+
# Update state (simulate forward)
|
|
1148
|
+
x_next = self.dynamics.step(self.x_current, policy)
|
|
1149
|
+
self.x_current = x_next
|
|
1150
|
+
|
|
1151
|
+
# Record execution
|
|
1152
|
+
self.execution_history.append({
|
|
1153
|
+
"timestamp": time.time(),
|
|
1154
|
+
"execution_id": execution_id,
|
|
1155
|
+
"policy": policy.to_dict(),
|
|
1156
|
+
"status": "executed",
|
|
1157
|
+
"automated": automated,
|
|
1158
|
+
})
|
|
1159
|
+
|
|
1160
|
+
self.previous_policy = policy
|
|
1161
|
+
|
|
1162
|
+
logger.info(f"✓ Policy executed successfully: {execution_id}")
|
|
1163
|
+
logger.info(f"New state: U={self.x_current.U:.1%}, Y=${self.x_current.Y/1e9:.2f}B")
|
|
1164
|
+
|
|
1165
|
+
return True
|
|
1166
|
+
else:
|
|
1167
|
+
logger.error(f"✗ Policy execution failed: {message}")
|
|
1168
|
+
self.alerting.create_alert(
|
|
1169
|
+
AlertLevel.CRITICAL,
|
|
1170
|
+
f"Policy execution failed: {message}",
|
|
1171
|
+
"policy_executor"
|
|
1172
|
+
)
|
|
1173
|
+
return False
|
|
1174
|
+
|
|
1175
|
+
def _monitoring_cycle(self) -> None:
|
|
1176
|
+
"""Continuous monitoring cycle (runs every 5 minutes)."""
|
|
1177
|
+
# Check system health
|
|
1178
|
+
health = self.monitor.get_health_status()
|
|
1179
|
+
|
|
1180
|
+
if health["status"] != "healthy":
|
|
1181
|
+
self.alerting.create_alert(
|
|
1182
|
+
AlertLevel.WARNING,
|
|
1183
|
+
f"System health: {health['status']}",
|
|
1184
|
+
"monitor"
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
# Check for unacknowledged alerts
|
|
1188
|
+
unack_alerts = self.alerting.get_unacknowledged_alerts()
|
|
1189
|
+
critical_alerts = [a for a in unack_alerts if a["level"] == "critical"]
|
|
1190
|
+
|
|
1191
|
+
if critical_alerts:
|
|
1192
|
+
logger.warning(f"{len(critical_alerts)} unacknowledged critical alerts")
|
|
1193
|
+
|
|
1194
|
+
def _process_pending_approvals(self) -> None:
|
|
1195
|
+
"""Process approved policies from pending approvals."""
|
|
1196
|
+
pending = self.governance.get_pending_approvals()
|
|
1197
|
+
|
|
1198
|
+
for approval in pending:
|
|
1199
|
+
if approval["status"] == "approved":
|
|
1200
|
+
# Execute approved policy
|
|
1201
|
+
policy = approval["policy"]
|
|
1202
|
+
logger.info(f"Executing approved policy: {approval['approval_id']}")
|
|
1203
|
+
self._execute_policy(policy, automated=False)
|
|
1204
|
+
|
|
1205
|
+
def get_status(self) -> Dict[str, Any]:
|
|
1206
|
+
"""Get current system status."""
|
|
1207
|
+
return {
|
|
1208
|
+
"is_running": self.is_running,
|
|
1209
|
+
"current_state": self.x_current.to_dict(),
|
|
1210
|
+
"state_confidence": self.state_estimator.get_confidence(),
|
|
1211
|
+
"n_executions": len(self.execution_history),
|
|
1212
|
+
"n_pending_approvals": len(self.governance.get_pending_approvals()),
|
|
1213
|
+
"system_health": self.monitor.get_health_status(),
|
|
1214
|
+
"last_update": self.state_history[-1].to_dict() if self.state_history else None,
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
def approve_policy(self, approval_id: str, user_id: str, comment: str) -> bool:
|
|
1218
|
+
"""
|
|
1219
|
+
Approve a pending policy (human operator interface).
|
|
1220
|
+
|
|
1221
|
+
Args:
|
|
1222
|
+
approval_id: Approval request ID
|
|
1223
|
+
user_id: User ID approving
|
|
1224
|
+
comment: Approval comment
|
|
1225
|
+
|
|
1226
|
+
Returns:
|
|
1227
|
+
bool: True if approval successful
|
|
1228
|
+
"""
|
|
1229
|
+
success, message = self.governance.approve_policy(approval_id, user_id, comment)
|
|
1230
|
+
|
|
1231
|
+
if success:
|
|
1232
|
+
logger.info(f"Policy approved by {user_id}: {approval_id}")
|
|
1233
|
+
|
|
1234
|
+
# Log approval
|
|
1235
|
+
self.compliance.log_decision(
|
|
1236
|
+
"policy_approval",
|
|
1237
|
+
{"approval_id": approval_id},
|
|
1238
|
+
user_id,
|
|
1239
|
+
comment,
|
|
1240
|
+
approved_by=[user_id]
|
|
1241
|
+
)
|
|
1242
|
+
|
|
1243
|
+
return success
|
|
1244
|
+
|
|
1245
|
+
def emergency_stop(self, user_id: str, reason: str) -> None:
|
|
1246
|
+
"""
|
|
1247
|
+
Emergency stop - halt all automation.
|
|
1248
|
+
|
|
1249
|
+
Args:
|
|
1250
|
+
user_id: User activating emergency stop
|
|
1251
|
+
reason: Reason for emergency stop
|
|
1252
|
+
"""
|
|
1253
|
+
self.governance.emergency_stop(user_id, reason)
|
|
1254
|
+
self.safety.emergency_stop()
|
|
1255
|
+
|
|
1256
|
+
logger.critical(f"EMERGENCY STOP activated by {user_id}: {reason}")
|
|
1257
|
+
|
|
1258
|
+
self.alerting.create_alert(
|
|
1259
|
+
AlertLevel.CRITICAL,
|
|
1260
|
+
f"EMERGENCY STOP: {reason}",
|
|
1261
|
+
"emergency",
|
|
1262
|
+
{"user_id": user_id}
|
|
1263
|
+
)
|
|
1264
|
+
|
|
1265
|
+
def rollback_last_policy(self, n_policies: int = 1) -> List[str]:
|
|
1266
|
+
"""
|
|
1267
|
+
Rollback last N policies.
|
|
1268
|
+
|
|
1269
|
+
Args:
|
|
1270
|
+
n_policies: Number of policies to rollback
|
|
1271
|
+
|
|
1272
|
+
Returns:
|
|
1273
|
+
List[str]: Execution IDs rolled back
|
|
1274
|
+
"""
|
|
1275
|
+
rolled_back = self.rollback.rollback_policies(n_policies)
|
|
1276
|
+
|
|
1277
|
+
if rolled_back:
|
|
1278
|
+
logger.warning(f"Rolled back {len(rolled_back)} policies: {rolled_back}")
|
|
1279
|
+
|
|
1280
|
+
# Restore state
|
|
1281
|
+
restored_state = self.rollback.restore_state()
|
|
1282
|
+
if restored_state:
|
|
1283
|
+
self.x_current = restored_state
|
|
1284
|
+
logger.info("State restored from snapshot")
|
|
1285
|
+
|
|
1286
|
+
return rolled_back
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
def run_production_system(config_file: Optional[str] = None) -> PridnestroviaRealtimeController:
|
|
1290
|
+
"""
|
|
1291
|
+
Run production real-time control system.
|
|
1292
|
+
|
|
1293
|
+
This starts the actual production system that runs continuously.
|
|
1294
|
+
|
|
1295
|
+
Args:
|
|
1296
|
+
config_file: Optional configuration file path
|
|
1297
|
+
|
|
1298
|
+
Returns:
|
|
1299
|
+
PridnestroviaRealtimeController: Running controller instance
|
|
1300
|
+
"""
|
|
1301
|
+
# Initialize controller
|
|
1302
|
+
controller = PridnestroviaRealtimeController(config_file)
|
|
1303
|
+
|
|
1304
|
+
# Start the system
|
|
1305
|
+
controller.start()
|
|
1306
|
+
|
|
1307
|
+
logger.info("=" * 60)
|
|
1308
|
+
logger.info("PRIDNESTROVIA REAL-TIME CONTROL SYSTEM")
|
|
1309
|
+
logger.info("Status: RUNNING")
|
|
1310
|
+
logger.info("=" * 60)
|
|
1311
|
+
logger.info("System is now actively controlling Pridnestrovia economy")
|
|
1312
|
+
logger.info("Press Ctrl+C to stop")
|
|
1313
|
+
|
|
1314
|
+
return controller
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
def _legacy_realtime_control_loop(system: Dict[str, Any], n_days: int = 7) -> Dict[str, Any]:
|
|
1318
|
+
"""
|
|
1319
|
+
Run real-time control loop for N days.
|
|
1320
|
+
|
|
1321
|
+
Demonstrates:
|
|
1322
|
+
- Daily data acquisition and state estimation
|
|
1323
|
+
- MPC optimization
|
|
1324
|
+
- Automated execution (minor changes) vs approval (major changes)
|
|
1325
|
+
- Monitoring and alerting
|
|
1326
|
+
- Rollback capabilities
|
|
1327
|
+
|
|
1328
|
+
Args:
|
|
1329
|
+
system: System components
|
|
1330
|
+
n_days: Number of days to simulate
|
|
1331
|
+
|
|
1332
|
+
Returns:
|
|
1333
|
+
Dict[str, Any]: Results and history
|
|
1334
|
+
"""
|
|
1335
|
+
logger.info(f"=== Starting Real-Time Control Loop ({n_days} days) ===")
|
|
1336
|
+
|
|
1337
|
+
# Extract components
|
|
1338
|
+
x_current = system["initial_state"]
|
|
1339
|
+
data_acq = system["data_acquisition"]
|
|
1340
|
+
data_pipeline = system["data_pipeline"]
|
|
1341
|
+
state_estimator = system["state_estimator"]
|
|
1342
|
+
monitor = system["monitor"]
|
|
1343
|
+
solver = system["solver"]
|
|
1344
|
+
policy_executor = system["policy_executor"]
|
|
1345
|
+
safety = system["safety"]
|
|
1346
|
+
governance = system["governance"]
|
|
1347
|
+
rollback = system["rollback"]
|
|
1348
|
+
compliance = system["compliance"]
|
|
1349
|
+
alerting = system["alerting"]
|
|
1350
|
+
|
|
1351
|
+
# History
|
|
1352
|
+
state_history = [x_current.copy()]
|
|
1353
|
+
policy_history = []
|
|
1354
|
+
execution_history = []
|
|
1355
|
+
approval_history = []
|
|
1356
|
+
|
|
1357
|
+
previous_policy: Optional[ControlVector] = None
|
|
1358
|
+
|
|
1359
|
+
for day in range(n_days):
|
|
1360
|
+
logger.info(f"\n--- Day {day + 1} ---")
|
|
1361
|
+
|
|
1362
|
+
# 1. Data acquisition (daily)
|
|
1363
|
+
if data_acq.should_update("government"):
|
|
1364
|
+
logger.info("Acquiring data from government systems...")
|
|
1365
|
+
|
|
1366
|
+
# Fetch from government APIs
|
|
1367
|
+
data_points = []
|
|
1368
|
+
for api_name in ["treasury", "ministries", "central_bank"]:
|
|
1369
|
+
if data_acq.should_update(api_name):
|
|
1370
|
+
gov_data = data_acq.fetch_government_data(
|
|
1371
|
+
api_name,
|
|
1372
|
+
"current_state",
|
|
1373
|
+
["P", "L", "U", "Y", "E_stock", "F_stock"]
|
|
1374
|
+
)
|
|
1375
|
+
data_points.extend(gov_data)
|
|
1376
|
+
|
|
1377
|
+
# Process through pipeline
|
|
1378
|
+
processed_data = data_pipeline.process_data_points(data_points)
|
|
1379
|
+
|
|
1380
|
+
# Update state estimate
|
|
1381
|
+
if state_estimator.should_update():
|
|
1382
|
+
if previous_policy is None:
|
|
1383
|
+
u_current = ControlVector.sample_budget_simplex([
|
|
1384
|
+
"energy", "food", "infrastructure", "education",
|
|
1385
|
+
"healthcare", "R&D", "welfare"
|
|
1386
|
+
])
|
|
1387
|
+
else:
|
|
1388
|
+
u_current = previous_policy
|
|
1389
|
+
x_estimated = state_estimator.update_with_data_points(processed_data, u_current)
|
|
1390
|
+
x_current = x_estimated
|
|
1391
|
+
logger.info(f"State updated: U={x_current.U:.1%}, Y=${x_current.Y/1e9:.2f}B")
|
|
1392
|
+
|
|
1393
|
+
# 2. Monitoring
|
|
1394
|
+
if monitor.should_check():
|
|
1395
|
+
if previous_policy is None:
|
|
1396
|
+
u_current = ControlVector.sample_budget_simplex([
|
|
1397
|
+
"energy", "food", "infrastructure", "education",
|
|
1398
|
+
"healthcare", "R&D", "welfare"
|
|
1399
|
+
])
|
|
1400
|
+
else:
|
|
1401
|
+
u_current = previous_policy
|
|
1402
|
+
is_feasible, violations, metrics = monitor.check_state(x_current, u_current)
|
|
1403
|
+
|
|
1404
|
+
if violations:
|
|
1405
|
+
alerting.create_alert(
|
|
1406
|
+
AlertLevel.WARNING,
|
|
1407
|
+
f"Constraint violations detected: {len(violations)}",
|
|
1408
|
+
"monitor",
|
|
1409
|
+
{"violations": violations}
|
|
1410
|
+
)
|
|
1411
|
+
|
|
1412
|
+
# 3. MPC optimization (use CRCA if available)
|
|
1413
|
+
crca_agent = system.get("crca_agent")
|
|
1414
|
+
scenario_gen = ScenarioGenerator(crca_agent=crca_agent)
|
|
1415
|
+
if crca_agent is not None:
|
|
1416
|
+
try:
|
|
1417
|
+
scenarios = scenario_gen.generate_causal_scenarios(
|
|
1418
|
+
n_scenarios=5,
|
|
1419
|
+
horizon=12,
|
|
1420
|
+
current_state=x_current
|
|
1421
|
+
)
|
|
1422
|
+
except Exception:
|
|
1423
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=5, horizon=12)
|
|
1424
|
+
else:
|
|
1425
|
+
scenarios = scenario_gen.generate_gaussian(n_scenarios=5, horizon=12)
|
|
1426
|
+
|
|
1427
|
+
policy, solver_info = solver.solve(x_current, scenarios, u_prev=previous_policy)
|
|
1428
|
+
logger.info(f"MPC solved: best_score={solver_info.get('best_score', 'N/A'):.4f}")
|
|
1429
|
+
|
|
1430
|
+
# 4. Safety check
|
|
1431
|
+
state_confidence = state_estimator.get_confidence()
|
|
1432
|
+
is_safe, reason, requires_approval = safety.check_policy_safety(
|
|
1433
|
+
policy,
|
|
1434
|
+
previous_policy,
|
|
1435
|
+
state_confidence
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
if not is_safe:
|
|
1439
|
+
logger.warning(f"Policy unsafe: {reason}")
|
|
1440
|
+
alerting.create_alert(
|
|
1441
|
+
AlertLevel.CRITICAL,
|
|
1442
|
+
f"Unsafe policy detected: {reason}",
|
|
1443
|
+
"safety_interlocks"
|
|
1444
|
+
)
|
|
1445
|
+
continue # Skip execution
|
|
1446
|
+
|
|
1447
|
+
# 5. Check if approval needed (major change > 10%)
|
|
1448
|
+
if requires_approval:
|
|
1449
|
+
logger.info(f"Major change detected, requesting approval: {reason}")
|
|
1450
|
+
|
|
1451
|
+
# Request approval via governance
|
|
1452
|
+
approval_id = governance.request_approval(
|
|
1453
|
+
policy,
|
|
1454
|
+
reason,
|
|
1455
|
+
"system",
|
|
1456
|
+
objectives=None # Would compute from solver
|
|
1457
|
+
)
|
|
1458
|
+
|
|
1459
|
+
approval_history.append({
|
|
1460
|
+
"day": day + 1,
|
|
1461
|
+
"approval_id": approval_id,
|
|
1462
|
+
"policy": policy,
|
|
1463
|
+
"reason": reason,
|
|
1464
|
+
})
|
|
1465
|
+
|
|
1466
|
+
logger.info(f"Approval requested: {approval_id}")
|
|
1467
|
+
logger.info("Waiting for human approval...")
|
|
1468
|
+
|
|
1469
|
+
# In real system, would wait for approval
|
|
1470
|
+
# For demo, simulate approval after delay
|
|
1471
|
+
# governance.approve_policy(approval_id, "human_operator", "Approved for demo")
|
|
1472
|
+
|
|
1473
|
+
continue # Skip execution until approved
|
|
1474
|
+
|
|
1475
|
+
# 6. Execute policy (automated for minor changes)
|
|
1476
|
+
logger.info("Executing policy (automated - minor change)")
|
|
1477
|
+
|
|
1478
|
+
execution_id, exec_message, exec_info = policy_executor.execute_policy(
|
|
1479
|
+
policy,
|
|
1480
|
+
require_approval=False
|
|
1481
|
+
)
|
|
1482
|
+
|
|
1483
|
+
if exec_info.get("success", False):
|
|
1484
|
+
# Record in rollback system
|
|
1485
|
+
rollback.record_policy_execution(policy, execution_id)
|
|
1486
|
+
|
|
1487
|
+
# Log for compliance
|
|
1488
|
+
compliance.log_decision(
|
|
1489
|
+
"policy_execution",
|
|
1490
|
+
policy.to_dict(),
|
|
1491
|
+
"system",
|
|
1492
|
+
"Automated execution (minor change)",
|
|
1493
|
+
approved_by=["system"]
|
|
1494
|
+
)
|
|
1495
|
+
|
|
1496
|
+
# Track accountability
|
|
1497
|
+
system["accountability"].attribute_decision(
|
|
1498
|
+
execution_id,
|
|
1499
|
+
policy,
|
|
1500
|
+
["system"],
|
|
1501
|
+
)
|
|
1502
|
+
|
|
1503
|
+
execution_history.append({
|
|
1504
|
+
"day": day + 1,
|
|
1505
|
+
"execution_id": execution_id,
|
|
1506
|
+
"policy": policy,
|
|
1507
|
+
"status": "executed",
|
|
1508
|
+
})
|
|
1509
|
+
|
|
1510
|
+
previous_policy = policy
|
|
1511
|
+
logger.info(f"Policy executed: {execution_id}")
|
|
1512
|
+
|
|
1513
|
+
# 7. Create state snapshot for rollback
|
|
1514
|
+
rollback.create_snapshot(x_current)
|
|
1515
|
+
|
|
1516
|
+
# 8. Update state (simulate forward)
|
|
1517
|
+
x_next = system["dynamics"].step(x_current, policy)
|
|
1518
|
+
x_current = x_next
|
|
1519
|
+
state_history.append(x_current.copy())
|
|
1520
|
+
policy_history.append(policy)
|
|
1521
|
+
|
|
1522
|
+
logger.info(f"Day {day + 1} complete: U={x_current.U:.1%}, Y=${x_current.Y/1e9:.2f}B")
|
|
1523
|
+
|
|
1524
|
+
logger.info("=== Real-Time Control Loop Complete ===")
|
|
1525
|
+
|
|
1526
|
+
return {
|
|
1527
|
+
"state_history": state_history,
|
|
1528
|
+
"policy_history": policy_history,
|
|
1529
|
+
"execution_history": execution_history,
|
|
1530
|
+
"approval_history": approval_history,
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
|
|
1534
|
+
def demonstrate_approval_workflow(system: Dict[str, Any]) -> None:
|
|
1535
|
+
"""Demonstrate human approval workflow for major changes."""
|
|
1536
|
+
logger.info("=== Demonstrating Approval Workflow ===")
|
|
1537
|
+
|
|
1538
|
+
governance = system["governance"]
|
|
1539
|
+
policy_executor = system["policy_executor"]
|
|
1540
|
+
|
|
1541
|
+
# Create a policy with major change
|
|
1542
|
+
previous_policy = ControlVector(budget_shares={
|
|
1543
|
+
"energy": 0.15,
|
|
1544
|
+
"food": 0.15,
|
|
1545
|
+
"infrastructure": 0.20,
|
|
1546
|
+
"education": 0.15,
|
|
1547
|
+
"healthcare": 0.15,
|
|
1548
|
+
"R&D": 0.10,
|
|
1549
|
+
"welfare": 0.10,
|
|
1550
|
+
})
|
|
1551
|
+
|
|
1552
|
+
# Major change policy (> 10% in energy)
|
|
1553
|
+
major_change_policy = ControlVector(budget_shares={
|
|
1554
|
+
"energy": 0.30, # 15% -> 30% = 15% change (major!)
|
|
1555
|
+
"food": 0.15,
|
|
1556
|
+
"infrastructure": 0.15,
|
|
1557
|
+
"education": 0.15,
|
|
1558
|
+
"healthcare": 0.15,
|
|
1559
|
+
"R&D": 0.05,
|
|
1560
|
+
"welfare": 0.05,
|
|
1561
|
+
})
|
|
1562
|
+
|
|
1563
|
+
# Check if approval needed
|
|
1564
|
+
requires_approval, reason = governance.requires_approval(major_change_policy, previous_policy)
|
|
1565
|
+
logger.info(f"Requires approval: {requires_approval}, reason: {reason}")
|
|
1566
|
+
|
|
1567
|
+
if requires_approval:
|
|
1568
|
+
# Request approval
|
|
1569
|
+
approval_id = governance.request_approval(
|
|
1570
|
+
major_change_policy,
|
|
1571
|
+
reason,
|
|
1572
|
+
"system"
|
|
1573
|
+
)
|
|
1574
|
+
|
|
1575
|
+
logger.info(f"Approval requested: {approval_id}")
|
|
1576
|
+
logger.info(f"Pending approvals: {len(governance.get_pending_approvals())}")
|
|
1577
|
+
|
|
1578
|
+
# Simulate human approval
|
|
1579
|
+
success, message = governance.approve_policy(
|
|
1580
|
+
approval_id,
|
|
1581
|
+
"human_operator",
|
|
1582
|
+
"Approved: Energy security priority"
|
|
1583
|
+
)
|
|
1584
|
+
|
|
1585
|
+
logger.info(f"Approval result: {success}, {message}")
|
|
1586
|
+
|
|
1587
|
+
# Now execute
|
|
1588
|
+
success, exec_message, exec_info = policy_executor.execute_policy(
|
|
1589
|
+
major_change_policy,
|
|
1590
|
+
execution_id=approval_id,
|
|
1591
|
+
require_approval=False # Already approved
|
|
1592
|
+
)
|
|
1593
|
+
|
|
1594
|
+
logger.info(f"Executed approved policy: {success}, {exec_message}")
|
|
1595
|
+
|
|
1596
|
+
|
|
1597
|
+
def demonstrate_rollback(system: Dict[str, Any]) -> None:
|
|
1598
|
+
"""Demonstrate 7-day rollback capability."""
|
|
1599
|
+
logger.info("=== Demonstrating Rollback System ===")
|
|
1600
|
+
|
|
1601
|
+
rollback = system["rollback"]
|
|
1602
|
+
|
|
1603
|
+
# Create some state snapshots
|
|
1604
|
+
states = [
|
|
1605
|
+
StateVector(P=360000.0, U=0.07, Y=1300000000.0),
|
|
1606
|
+
StateVector(P=361000.0, U=0.08, Y=1320000000.0),
|
|
1607
|
+
StateVector(P=362000.0, U=0.09, Y=1340000000.0),
|
|
1608
|
+
]
|
|
1609
|
+
|
|
1610
|
+
snapshot_ids = []
|
|
1611
|
+
for i, state in enumerate(states):
|
|
1612
|
+
snap_id = rollback.create_snapshot(state, f"snapshot_{i}")
|
|
1613
|
+
snapshot_ids.append(snap_id)
|
|
1614
|
+
logger.info(f"Created snapshot {i}: {snap_id}")
|
|
1615
|
+
|
|
1616
|
+
# Record some policy executions
|
|
1617
|
+
policies = [
|
|
1618
|
+
ControlVector(budget_shares={"energy": 0.2, "food": 0.2, "infrastructure": 0.6}),
|
|
1619
|
+
ControlVector(budget_shares={"energy": 0.3, "food": 0.2, "infrastructure": 0.5}),
|
|
1620
|
+
]
|
|
1621
|
+
|
|
1622
|
+
for i, policy in enumerate(policies):
|
|
1623
|
+
rollback.record_policy_execution(policy, f"exec_{i}")
|
|
1624
|
+
|
|
1625
|
+
logger.info(f"Recorded {len(policies)} policy executions")
|
|
1626
|
+
|
|
1627
|
+
# Rollback last policy
|
|
1628
|
+
rolled_back = rollback.rollback_policies(1)
|
|
1629
|
+
logger.info(f"Rolled back policies: {rolled_back}")
|
|
1630
|
+
|
|
1631
|
+
# Restore state
|
|
1632
|
+
restored_state = rollback.restore_state(timestamp=None) # Most recent
|
|
1633
|
+
if restored_state:
|
|
1634
|
+
logger.info(f"Restored state: U={restored_state.U:.1%}, Y=${restored_state.Y/1e9:.2f}B")
|
|
1635
|
+
|
|
1636
|
+
logger.info(f"Rollback window: {rollback.get_rollback_window()/86400:.0f} days")
|
|
1637
|
+
|
|
1638
|
+
|
|
1639
|
+
def demonstrate_compliance(system: Dict[str, Any]) -> None:
|
|
1640
|
+
"""Demonstrate compliance and accountability."""
|
|
1641
|
+
logger.info("=== Demonstrating Compliance System ===")
|
|
1642
|
+
|
|
1643
|
+
compliance = system["compliance"]
|
|
1644
|
+
accountability = system["accountability"]
|
|
1645
|
+
|
|
1646
|
+
# Log a decision
|
|
1647
|
+
policy = ControlVector(budget_shares={"energy": 0.25, "food": 0.25, "infrastructure": 0.5})
|
|
1648
|
+
|
|
1649
|
+
log_id = compliance.log_decision(
|
|
1650
|
+
"policy_execution",
|
|
1651
|
+
policy.to_dict(),
|
|
1652
|
+
"system",
|
|
1653
|
+
"Automated execution (minor change)",
|
|
1654
|
+
approved_by=["system"]
|
|
1655
|
+
)
|
|
1656
|
+
|
|
1657
|
+
logger.info(f"Decision logged: {log_id}")
|
|
1658
|
+
|
|
1659
|
+
# Attribute decision
|
|
1660
|
+
accountability.attribute_decision(
|
|
1661
|
+
log_id,
|
|
1662
|
+
policy,
|
|
1663
|
+
["system"],
|
|
1664
|
+
board_votes={"growth_board": "APPROVE"}
|
|
1665
|
+
)
|
|
1666
|
+
|
|
1667
|
+
# Track performance
|
|
1668
|
+
accountability.track_performance(
|
|
1669
|
+
log_id,
|
|
1670
|
+
{"U": 0.07, "Y": 1300000000.0},
|
|
1671
|
+
{"U": 0.075, "Y": 1310000000.0},
|
|
1672
|
+
time.time()
|
|
1673
|
+
)
|
|
1674
|
+
|
|
1675
|
+
# Generate transparency report
|
|
1676
|
+
report = accountability.generate_transparency_report()
|
|
1677
|
+
logger.info(f"Transparency report: {report['n_decisions']} decisions, "
|
|
1678
|
+
f"avg performance: {report['avg_performance_score']:.2f}")
|
|
1679
|
+
|
|
1680
|
+
# Get audit trail
|
|
1681
|
+
audit_trail = compliance.get_audit_trail()
|
|
1682
|
+
logger.info(f"Audit trail entries: {len(audit_trail)}")
|
|
1683
|
+
|
|
1684
|
+
|
|
1685
|
+
def main() -> None:
|
|
1686
|
+
"""
|
|
1687
|
+
Main entry point for production real-time control system.
|
|
1688
|
+
|
|
1689
|
+
This is the production system that runs continuously.
|
|
1690
|
+
"""
|
|
1691
|
+
import signal
|
|
1692
|
+
import sys
|
|
1693
|
+
|
|
1694
|
+
logger.info("=" * 60)
|
|
1695
|
+
logger.info("PRIDNESTROVIA REAL-TIME ECONOMIC CONTROL SYSTEM")
|
|
1696
|
+
logger.info("Production Mode - Real-Time Operation")
|
|
1697
|
+
logger.info(f"Started: {datetime.now().isoformat()}")
|
|
1698
|
+
logger.info("=" * 60)
|
|
1699
|
+
|
|
1700
|
+
# Initialize and start controller
|
|
1701
|
+
controller = PridnestroviaRealtimeController()
|
|
1702
|
+
|
|
1703
|
+
# Setup signal handlers for graceful shutdown
|
|
1704
|
+
def signal_handler(sig, frame):
|
|
1705
|
+
logger.info("\nShutdown signal received...")
|
|
1706
|
+
controller.stop()
|
|
1707
|
+
sys.exit(0)
|
|
1708
|
+
|
|
1709
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
1710
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
|
1711
|
+
|
|
1712
|
+
# Start the system
|
|
1713
|
+
controller.start()
|
|
1714
|
+
|
|
1715
|
+
# Use TUI if available, otherwise fallback to text dashboard
|
|
1716
|
+
try:
|
|
1717
|
+
if TUI_AVAILABLE and CRCA_SD_TUI is not None:
|
|
1718
|
+
_run_with_tui(controller)
|
|
1719
|
+
else:
|
|
1720
|
+
_run_with_text_dashboard(controller)
|
|
1721
|
+
except KeyboardInterrupt:
|
|
1722
|
+
logger.info("Shutdown requested by user")
|
|
1723
|
+
finally:
|
|
1724
|
+
controller.stop()
|
|
1725
|
+
logger.info("System shutdown complete")
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
def _run_with_tui(controller: PridnestroviaRealtimeController) -> None:
|
|
1729
|
+
"""Run controller with TUI interface."""
|
|
1730
|
+
tui = CRCA_SD_TUI(title="Pridnestrovia Real-Time Economic Control System")
|
|
1731
|
+
|
|
1732
|
+
def update_tui(tui_instance: CRCA_SD_TUI) -> None:
|
|
1733
|
+
"""Update TUI state from controller."""
|
|
1734
|
+
# Get current status
|
|
1735
|
+
status = controller.get_status()
|
|
1736
|
+
progress = controller._compute_progress_towards_vision()
|
|
1737
|
+
vision = controller._get_successful_republic_vision()
|
|
1738
|
+
|
|
1739
|
+
# Get alerts
|
|
1740
|
+
alerts = controller.alerting.get_unacknowledged_alerts()
|
|
1741
|
+
alert_list = [
|
|
1742
|
+
{
|
|
1743
|
+
"level": a.get("level", "info"),
|
|
1744
|
+
"message": a.get("message", ""),
|
|
1745
|
+
"timestamp": a.get("timestamp", time.time())
|
|
1746
|
+
}
|
|
1747
|
+
for a in alerts[-10:] # Last 10 alerts
|
|
1748
|
+
]
|
|
1749
|
+
|
|
1750
|
+
# Update TUI
|
|
1751
|
+
tui_instance.update_state(
|
|
1752
|
+
current_state=controller.x_current,
|
|
1753
|
+
vision_progress=progress,
|
|
1754
|
+
vision_target=vision,
|
|
1755
|
+
system_status=status,
|
|
1756
|
+
execution_history=controller.execution_history,
|
|
1757
|
+
pending_approvals=controller.governance.get_pending_approvals(),
|
|
1758
|
+
alerts=alert_list,
|
|
1759
|
+
policy=controller.previous_policy
|
|
1760
|
+
)
|
|
1761
|
+
|
|
1762
|
+
# Initial update
|
|
1763
|
+
update_tui(tui)
|
|
1764
|
+
|
|
1765
|
+
# Run TUI with live updates
|
|
1766
|
+
try:
|
|
1767
|
+
tui.run_live(update_tui, refresh_rate=1.0)
|
|
1768
|
+
# TUI exited (either via Q key or other means)
|
|
1769
|
+
if tui._should_quit:
|
|
1770
|
+
logger.info("TUI closed by user (Q key)")
|
|
1771
|
+
else:
|
|
1772
|
+
logger.info("TUI closed")
|
|
1773
|
+
except KeyboardInterrupt:
|
|
1774
|
+
logger.info("TUI closed by user (Ctrl+C)")
|
|
1775
|
+
finally:
|
|
1776
|
+
controller.stop()
|
|
1777
|
+
logger.info("Controller stopped")
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
def _run_with_text_dashboard(controller: PridnestroviaRealtimeController) -> None:
|
|
1781
|
+
"""Run controller with text dashboard (fallback)."""
|
|
1782
|
+
# Display initial dashboard with vision
|
|
1783
|
+
progress = controller._compute_progress_towards_vision()
|
|
1784
|
+
vision = controller._get_successful_republic_vision()
|
|
1785
|
+
|
|
1786
|
+
dashboard = Visualization.realtime_dashboard(
|
|
1787
|
+
controller.x_current,
|
|
1788
|
+
system_health=controller.monitor.get_health_status()
|
|
1789
|
+
)
|
|
1790
|
+
|
|
1791
|
+
vision_section = f"""
|
|
1792
|
+
--- 🎯 Vision: Successful Republic Progress ---
|
|
1793
|
+
Overall Progress: {progress['overall']:.1%} towards successful republic
|
|
1794
|
+
Unemployment: {progress['unemployment']:.1%} (target: <5%)
|
|
1795
|
+
GDP Growth: {progress['gdp']:.1%} (target: 2x current)
|
|
1796
|
+
Stability: {progress['stability']:.1%} (target: 85%)
|
|
1797
|
+
Infrastructure: {progress['infrastructure']:.1%} (target: 85%)
|
|
1798
|
+
Literacy: {progress['literacy']:.1%} (target: 99%)
|
|
1799
|
+
|
|
1800
|
+
Current → Vision:
|
|
1801
|
+
GDP: ${controller.x_current.Y/1e9:.2f}B → ${vision.Y/1e9:.2f}B
|
|
1802
|
+
Unemployment: {controller.x_current.U:.1%} → {vision.U:.1%}
|
|
1803
|
+
Stability: {controller.x_current.S:.1%} → {vision.S:.1%}
|
|
1804
|
+
Infrastructure: {controller.x_current.I:.1%} → {vision.I:.1%}
|
|
1805
|
+
============================================================
|
|
1806
|
+
"""
|
|
1807
|
+
|
|
1808
|
+
print("\n" + dashboard + vision_section)
|
|
1809
|
+
|
|
1810
|
+
# Run continuously
|
|
1811
|
+
try:
|
|
1812
|
+
last_dashboard_update = time.time()
|
|
1813
|
+
dashboard_update_freq = 300.0 # Update dashboard every 5 minutes
|
|
1814
|
+
|
|
1815
|
+
while controller.is_running:
|
|
1816
|
+
current_time = time.time()
|
|
1817
|
+
|
|
1818
|
+
# Update dashboard periodically
|
|
1819
|
+
if current_time - last_dashboard_update >= dashboard_update_freq:
|
|
1820
|
+
status = controller.get_status()
|
|
1821
|
+
progress = controller._compute_progress_towards_vision()
|
|
1822
|
+
|
|
1823
|
+
logger.info(f"System Status: Running | Executions: {status['n_executions']} | "
|
|
1824
|
+
f"Pending Approvals: {status['n_pending_approvals']} | "
|
|
1825
|
+
f"Vision Progress: {progress['overall']:.1%}")
|
|
1826
|
+
|
|
1827
|
+
# Display dashboard with vision (use Formatter if available)
|
|
1828
|
+
if FORMATTER_AVAILABLE and formatter is not None:
|
|
1829
|
+
try:
|
|
1830
|
+
vision = controller._get_successful_republic_vision()
|
|
1831
|
+
dashboard_md = f"""# System Status Update
|
|
1832
|
+
|
|
1833
|
+
**Time:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
1834
|
+
|
|
1835
|
+
## Current State
|
|
1836
|
+
|
|
1837
|
+
- **GDP:** ${controller.x_current.Y/1e9:.2f}B
|
|
1838
|
+
- **Unemployment:** {controller.x_current.U:.1%}
|
|
1839
|
+
- **Stability:** {controller.x_current.S:.1%}
|
|
1840
|
+
|
|
1841
|
+
## Vision Progress
|
|
1842
|
+
|
|
1843
|
+
**Overall:** {progress['overall']:.1%} | **U:** {progress['unemployment']:.1%} | **GDP:** {progress['gdp']:.1%} | **S:** {progress['stability']:.1%}
|
|
1844
|
+
|
|
1845
|
+
**Current → Target:**
|
|
1846
|
+
- GDP: ${controller.x_current.Y/1e9:.2f}B → ${vision.Y/1e9:.2f}B
|
|
1847
|
+
- Unemployment: {controller.x_current.U:.1%} → {vision.U:.1%}
|
|
1848
|
+
"""
|
|
1849
|
+
formatter.print_markdown(dashboard_md, title="Status Update", border_style="cyan")
|
|
1850
|
+
except Exception:
|
|
1851
|
+
# Fallback
|
|
1852
|
+
dashboard = Visualization.realtime_dashboard(
|
|
1853
|
+
controller.x_current,
|
|
1854
|
+
execution_status=controller.execution_history[-1] if controller.execution_history else None,
|
|
1855
|
+
pending_approvals=controller.governance.get_pending_approvals(),
|
|
1856
|
+
system_health=controller.monitor.get_health_status()
|
|
1857
|
+
)
|
|
1858
|
+
vision = controller._get_successful_republic_vision()
|
|
1859
|
+
vision_section = f"""
|
|
1860
|
+
--- 🎯 Vision Progress: Successful Republic ---
|
|
1861
|
+
Overall: {progress['overall']:.1%} | U: {progress['unemployment']:.1%} | GDP: {progress['gdp']:.1%} | S: {progress['stability']:.1%}
|
|
1862
|
+
Current GDP: ${controller.x_current.Y/1e9:.2f}B → Target: ${vision.Y/1e9:.2f}B
|
|
1863
|
+
Current U: {controller.x_current.U:.1%} → Target: {vision.U:.1%}
|
|
1864
|
+
============================================================
|
|
1865
|
+
"""
|
|
1866
|
+
print("\n" + dashboard + vision_section)
|
|
1867
|
+
else:
|
|
1868
|
+
# Plain text fallback
|
|
1869
|
+
dashboard = Visualization.realtime_dashboard(
|
|
1870
|
+
controller.x_current,
|
|
1871
|
+
execution_status=controller.execution_history[-1] if controller.execution_history else None,
|
|
1872
|
+
pending_approvals=controller.governance.get_pending_approvals(),
|
|
1873
|
+
system_health=controller.monitor.get_health_status()
|
|
1874
|
+
)
|
|
1875
|
+
vision = controller._get_successful_republic_vision()
|
|
1876
|
+
vision_section = f"""
|
|
1877
|
+
--- 🎯 Vision Progress: Successful Republic ---
|
|
1878
|
+
Overall: {progress['overall']:.1%} | U: {progress['unemployment']:.1%} | GDP: {progress['gdp']:.1%} | S: {progress['stability']:.1%}
|
|
1879
|
+
Current GDP: ${controller.x_current.Y/1e9:.2f}B → Target: ${vision.Y/1e9:.2f}B
|
|
1880
|
+
Current U: {controller.x_current.U:.1%} → Target: {vision.U:.1%}
|
|
1881
|
+
============================================================
|
|
1882
|
+
"""
|
|
1883
|
+
print("\n" + dashboard + vision_section)
|
|
1884
|
+
last_dashboard_update = current_time
|
|
1885
|
+
|
|
1886
|
+
# Sleep briefly
|
|
1887
|
+
time.sleep(10.0) # Check every 10 seconds
|
|
1888
|
+
|
|
1889
|
+
except KeyboardInterrupt:
|
|
1890
|
+
logger.info("Shutdown requested by user")
|
|
1891
|
+
|
|
1892
|
+
except KeyboardInterrupt:
|
|
1893
|
+
logger.info("Shutdown requested by user")
|
|
1894
|
+
finally:
|
|
1895
|
+
controller.stop()
|
|
1896
|
+
logger.info("System shutdown complete")
|
|
1897
|
+
|
|
1898
|
+
|
|
1899
|
+
if __name__ == "__main__":
|
|
1900
|
+
"""Run production real-time control system."""
|
|
1901
|
+
main()
|
|
1902
|
+
|