@atmem/architect 0.0.0-stage → 0.2.0-alpha.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (498) hide show
  1. package/CONSTITUTION.md +144 -0
  2. package/README.md +33 -2
  3. package/agent-skills/discovery/SKILL.md +48 -0
  4. package/agent-skills/discovery/topics.json +139 -0
  5. package/agent-skills/generation-capabilities.json +760 -0
  6. package/agent-skills/service-lifecycle.json +21 -0
  7. package/agent-skills/specialists/architecture/SKILL.md +15 -0
  8. package/agent-skills/specialists/aws/SKILL.md +17 -0
  9. package/agent-skills/specialists/azure/SKILL.md +7 -0
  10. package/agent-skills/specialists/composition/SKILL.md +17 -0
  11. package/agent-skills/specialists/devops/SKILL.md +10 -0
  12. package/agent-skills/specialists/finops/SKILL.md +7 -0
  13. package/agent-skills/specialists/gcp/SKILL.md +7 -0
  14. package/agent-skills/specialists/ibm/SKILL.md +7 -0
  15. package/agent-skills/specialists/manifest.json +13 -0
  16. package/agent-skills/specialists/pulumi/SKILL.md +7 -0
  17. package/agent-skills/specialists/security/SKILL.md +7 -0
  18. package/agent-skills/specialists/terraform/SKILL.md +14 -0
  19. package/agent-skills/upstream/aws/LICENSE +175 -0
  20. package/agent-skills/upstream/aws/SKILL.md +125 -0
  21. package/agent-skills/upstream/azure/LICENSE +21 -0
  22. package/agent-skills/upstream/azure/SKILL.md +387 -0
  23. package/agent-skills/upstream/gcp/LICENSE +202 -0
  24. package/agent-skills/upstream/gcp/SKILL.md +159 -0
  25. package/agent-skills/upstream/manifest.json +57 -0
  26. package/agent-skills/upstream/pulumi/LICENSE +201 -0
  27. package/agent-skills/upstream/pulumi/SKILL.md +501 -0
  28. package/agent-skills/upstream/terraform/LICENSE +373 -0
  29. package/agent-skills/upstream/terraform/SKILL.md +316 -0
  30. package/agent-skills/workflows/workflows.json +601 -0
  31. package/cli/architect.mjs +3 -0
  32. package/cli/runtime.mjs +115 -0
  33. package/dist/assets/html2canvas.esm-QH1iLAAe.js +22 -0
  34. package/dist/assets/index-B97MkVMs.css +1 -0
  35. package/dist/assets/index-qtCM2D7O.js +21271 -0
  36. package/dist/assets/index.es-C6C0sneB.js +18 -0
  37. package/dist/assets/purify.es-CAi2OJFm.js +3 -0
  38. package/dist/assets/visual-export-DjbjgQbA.js +173 -0
  39. package/dist/favicon.svg +2 -0
  40. package/dist/fonts/DM-Sans-OFL.txt +93 -0
  41. package/dist/fonts/Manrope-OFL.txt +93 -0
  42. package/dist/fonts/NotoSans-Regular.ttf +0 -0
  43. package/dist/fonts/OFL.txt +94 -0
  44. package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
  45. package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
  46. package/dist/index.html +4 -0
  47. package/dist/licenses/aws-architect-LICENSE.txt +17 -0
  48. package/dist/licenses/aws-mcp-LICENSE.txt +175 -0
  49. package/dist/licenses/aws-mcp-NOTICE.txt +1 -0
  50. package/dist/licenses/cloud-emulation-notices.txt +36619 -0
  51. package/dist/licenses/dependency-notices.txt +6379 -0
  52. package/dist/licenses/emulation-notices.txt +717 -0
  53. package/dist/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  54. package/dist/licenses/memory-dependency-notices.txt +3319 -0
  55. package/dist/licenses/openarchflow-LICENSE.txt +21 -0
  56. package/dist/licenses/python-dependency-notices.txt +11951 -0
  57. package/docs/upstream-lock.json +26 -0
  58. package/knowledge/engineering-practices.json +536 -0
  59. package/package.json +30 -4
  60. package/packaging/uv-release-lock.json +54 -0
  61. package/public/licenses/aws-architect-LICENSE.txt +17 -0
  62. package/public/licenses/aws-mcp-LICENSE.txt +175 -0
  63. package/public/licenses/aws-mcp-NOTICE.txt +1 -0
  64. package/public/licenses/cloud-emulation-notices.txt +36619 -0
  65. package/public/licenses/dependency-notices.txt +6379 -0
  66. package/public/licenses/emulation-notices.txt +717 -0
  67. package/public/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  68. package/public/licenses/memory-dependency-notices.txt +3319 -0
  69. package/public/licenses/openarchflow-LICENSE.txt +21 -0
  70. package/public/licenses/python-dependency-notices.txt +11951 -0
  71. package/scripts/terraform-render.mjs +8 -0
  72. package/server/__init__.py +0 -0
  73. package/server/abstraction.py +28 -0
  74. package/server/agent_runtime.py +153 -0
  75. package/server/app.py +257 -0
  76. package/server/architect.py +112 -0
  77. package/server/architecture_activity.py +67 -0
  78. package/server/attachments.py +101 -0
  79. package/server/cloud-emulation-requirements.txt +29 -0
  80. package/server/codex_app_server.py +219 -0
  81. package/server/codex_engineering_backend.py +266 -0
  82. package/server/codex_worker_policy.py +170 -0
  83. package/server/contracts.py +315 -0
  84. package/server/copilot_worker.py +16 -0
  85. package/server/dependency_mirror.py +54 -0
  86. package/server/design_patch.py +43 -0
  87. package/server/emulation-requirements.txt +8 -0
  88. package/server/emulation_adapters.py +20 -0
  89. package/server/emulation_routes.py +98 -0
  90. package/server/emulation_worker.py +351 -0
  91. package/server/engineering_artifacts.py +215 -0
  92. package/server/engineering_assets/application-runtime.json +4372 -0
  93. package/server/engineering_assets/architecture_work.schema.json +79 -0
  94. package/server/engineering_assets/materialize_runtime.py +62 -0
  95. package/server/engineering_assets/prepare_tools.py +96 -0
  96. package/server/engineering_assets/sql_validation.py +59 -0
  97. package/server/engineering_contexts.py +120 -0
  98. package/server/engineering_delivery.py +210 -0
  99. package/server/engineering_finalization.py +210 -0
  100. package/server/engineering_handoff.py +163 -0
  101. package/server/engineering_jobs.py +206 -0
  102. package/server/engineering_knowledge.py +75 -0
  103. package/server/engineering_reconciliation.py +159 -0
  104. package/server/engineering_routes.py +469 -0
  105. package/server/engineering_sessions.py +273 -0
  106. package/server/engineering_tools.py +166 -0
  107. package/server/generation_lint.py +18 -0
  108. package/server/local_providers.py +181 -0
  109. package/server/local_validation.py +236 -0
  110. package/server/memory-requirements.lock +181 -0
  111. package/server/memory-requirements.txt +6 -0
  112. package/server/memory_routes.py +82 -0
  113. package/server/memory_service.py +273 -0
  114. package/server/memory_worker.py +66 -0
  115. package/server/openai_voice.py +80 -0
  116. package/server/packaged_app.py +9 -0
  117. package/server/pricing.py +84 -0
  118. package/server/process_control_observation.py +31 -0
  119. package/server/prompts.py +123 -0
  120. package/server/public_faq_emulation_worker.py +44 -0
  121. package/server/requirements.lock +1618 -0
  122. package/server/requirements.txt +68 -0
  123. package/server/runtime_dependency_locks.py +27 -0
  124. package/server/runtime_evidence.py +93 -0
  125. package/server/settings.py +14 -0
  126. package/server/skills.py +103 -0
  127. package/server/storage_emulation_worker.py +160 -0
  128. package/server/structured_emulation_worker.py +48 -0
  129. package/server/terraform_routes.py +118 -0
  130. package/server/upstream/__init__.py +0 -0
  131. package/server/upstream/agent/__init__.py +1 -0
  132. package/server/upstream/agent/aws_architect.py +600 -0
  133. package/server/upstream/agent/config/__init__.py +1 -0
  134. package/server/upstream/agent/config/agent_config.py +82 -0
  135. package/server/upstream/agent/config/prompts.py +138 -0
  136. package/server/upstream/agent/rate_limiter.py +62 -0
  137. package/server/upstream/utils/__init__.py +1 -0
  138. package/server/upstream/utils/file_writer.py +43 -0
  139. package/server/validation_applicability.py +85 -0
  140. package/server/validation_jobs.py +252 -0
  141. package/server/validation_workers.py +48 -0
  142. package/server/voice_routes.py +91 -0
  143. package/server/voice_worker.py +26 -0
  144. package/specs/028-convergence-evaluation/evidence/20261110-ibm-invoice-native/registry-structured/qualification.json +72 -0
  145. package/specs/028-convergence-evaluation/evidence/20261110-invoice-runtime/durable-current/receipt.json +61 -0
  146. package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json +22 -0
  147. package/src/ArchitectureActivity.jsx +54 -0
  148. package/src/ArchitectureWorkPanel.jsx +46 -0
  149. package/src/ArtifactChecks.jsx +49 -0
  150. package/src/BlockRequirements.jsx +13 -0
  151. package/src/BrainActivity.jsx +11 -0
  152. package/src/ChatMessage.jsx +19 -0
  153. package/src/ChatResizeHandle.jsx +6 -0
  154. package/src/CodePreview.jsx +8 -0
  155. package/src/ComponentReview.jsx +31 -0
  156. package/src/DeliveryViews.jsx +59 -0
  157. package/src/EmulationPanel.jsx +44 -0
  158. package/src/EngagementViews.jsx +385 -0
  159. package/src/EngineeringPanel.jsx +151 -0
  160. package/src/ImplementationDelivery.jsx +55 -0
  161. package/src/JourneyViews.jsx +400 -0
  162. package/src/MemoryPanel.jsx +46 -0
  163. package/src/OpenAIVoicePanel.jsx +65 -0
  164. package/src/OutputsView.jsx +65 -0
  165. package/src/TerraformView.jsx +57 -0
  166. package/src/WorkbenchDialogs.jsx +532 -0
  167. package/src/activity-presentation.mjs +28 -0
  168. package/src/ai-qualification-scenarios.mjs +31 -0
  169. package/src/approval-application-files.mjs +32 -0
  170. package/src/approval-applications.mjs +82 -0
  171. package/src/approval-spec-kit.mjs +30 -0
  172. package/src/architecture-activity.css +28 -0
  173. package/src/architecture-activity.mjs +63 -0
  174. package/src/architecture-work.mjs +176 -0
  175. package/src/artifact-work.mjs +103 -0
  176. package/src/async-documents.mjs +191 -0
  177. package/src/atflow.css +1140 -0
  178. package/src/atforma.css +748 -0
  179. package/src/atmem-tokens.css +79 -0
  180. package/src/aws-preflight.mjs +60 -0
  181. package/src/aws-public-faq.mjs +102 -0
  182. package/src/aws-validation-scenarios.mjs +10 -0
  183. package/src/aws-validation.mjs +48 -0
  184. package/src/azure-plan-mocks.mjs +25 -0
  185. package/src/azure-structured.mjs +133 -0
  186. package/src/bedrock-summary.mjs +152 -0
  187. package/src/bounded-rag.mjs +60 -0
  188. package/src/brand.css +9 -0
  189. package/src/canvas-view.mjs +28 -0
  190. package/src/capability-composition.mjs +44 -0
  191. package/src/chat-attachments.mjs +13 -0
  192. package/src/cloud-provider-locks.mjs +9 -0
  193. package/src/cloud-storage-scenarios.mjs +2 -0
  194. package/src/component-review.mjs +55 -0
  195. package/src/composition-spec-kit.mjs +30 -0
  196. package/src/consultation-context.mjs +15 -0
  197. package/src/consultation.mjs +52 -0
  198. package/src/container-contracts.mjs +5 -0
  199. package/src/container-inspection.mjs +75 -0
  200. package/src/container-runtime.mjs +30 -0
  201. package/src/container-security-inspection.mjs +49 -0
  202. package/src/container-terraform.mjs +109 -0
  203. package/src/conversation.mjs +17 -0
  204. package/src/core.mjs +863 -0
  205. package/src/cross-cloud-storage.mjs +100 -0
  206. package/src/delivery-capabilities.mjs +25 -0
  207. package/src/delivery.mjs +58 -0
  208. package/src/deployment-ownership.mjs +10 -0
  209. package/src/deployment-region.mjs +11 -0
  210. package/src/derive.mjs +31 -0
  211. package/src/design-build-flow.mjs +10 -0
  212. package/src/diagram-attention.mjs +24 -0
  213. package/src/discovery.mjs +359 -0
  214. package/src/document.mjs +170 -0
  215. package/src/emulation-feedback.mjs +61 -0
  216. package/src/emulation-guidance.mjs +37 -0
  217. package/src/engagement.mjs +274 -0
  218. package/src/engineering-client.mjs +73 -0
  219. package/src/engineering-defaults.mjs +17 -0
  220. package/src/engineering.css +31 -0
  221. package/src/enterprise-application.mjs +76 -0
  222. package/src/enterprise-aws-host-infrastructure.mjs +62 -0
  223. package/src/enterprise-aws-host-tests.mjs +15 -0
  224. package/src/enterprise-aws-infrastructure-tests.mjs +38 -0
  225. package/src/enterprise-aws-infrastructure.mjs +138 -0
  226. package/src/enterprise-google-infrastructure.mjs +84 -0
  227. package/src/enterprise-google-tests.mjs +25 -0
  228. package/src/estimate.mjs +188 -0
  229. package/src/existing-references.mjs +18 -0
  230. package/src/external-identities.mjs +17 -0
  231. package/src/faq-lambda-build.mjs +28 -0
  232. package/src/gcp-structured.mjs +104 -0
  233. package/src/generation-provider.mjs +7 -0
  234. package/src/generation-quality.mjs +69 -0
  235. package/src/handoff.mjs +141 -0
  236. package/src/ibm-registry.mjs +12 -0
  237. package/src/ibm-structured.mjs +103 -0
  238. package/src/identifiers.mjs +15 -0
  239. package/src/implementation-map.mjs +14 -0
  240. package/src/implementation-outcome.mjs +8 -0
  241. package/src/incomplete-terraform.mjs +9 -0
  242. package/src/integrations.ts +137 -0
  243. package/src/interface-contracts.mjs +30 -0
  244. package/src/invoice-application.mjs +66 -0
  245. package/src/invoice-aws-operations.mjs +136 -0
  246. package/src/invoice-aws.mjs +143 -0
  247. package/src/invoice-azure-operations.mjs +147 -0
  248. package/src/invoice-azure.mjs +134 -0
  249. package/src/invoice-builder.mjs +35 -0
  250. package/src/invoice-dependencies.mjs +43 -0
  251. package/src/invoice-gcp-operations.mjs +178 -0
  252. package/src/invoice-gcp.mjs +104 -0
  253. package/src/invoice-ibm-operations.mjs +278 -0
  254. package/src/invoice-ibm.mjs +142 -0
  255. package/src/invoice-operations.mjs +143 -0
  256. package/src/invoice-plan.mjs +45 -0
  257. package/src/invoice-region.mjs +6 -0
  258. package/src/invoice-spec-kit.mjs +61 -0
  259. package/src/invoice-state.mjs +7 -0
  260. package/src/invoice-terraform.mjs +29 -0
  261. package/src/invoice-tests.mjs +122 -0
  262. package/src/journey-workspace.css +72 -0
  263. package/src/journey.mjs +87 -0
  264. package/src/levels.mjs +145 -0
  265. package/src/local-agent.mjs +184 -0
  266. package/src/main.jsx +2458 -0
  267. package/src/model-policy-preflight.mjs +34 -0
  268. package/src/openai-voice.mjs +102 -0
  269. package/src/output-bundle.mjs +11 -0
  270. package/src/ownership-inspection.mjs +28 -0
  271. package/src/pack.mjs +201 -0
  272. package/src/pricing.mjs +31 -0
  273. package/src/production-state.mjs +8 -0
  274. package/src/project-copy.mjs +10 -0
  275. package/src/project-file.mjs +160 -0
  276. package/src/project-links.mjs +3 -0
  277. package/src/protected-state.mjs +43 -0
  278. package/src/public-faq-builder.mjs +19 -0
  279. package/src/public-faq-clouds.mjs +251 -0
  280. package/src/public-faq.mjs +122 -0
  281. package/src/pulumi.mjs +123 -0
  282. package/src/python-container.mjs +25 -0
  283. package/src/python-runtime.mjs +50 -0
  284. package/src/rag-handler.mjs +43 -0
  285. package/src/rag-web-assets.mjs +52 -0
  286. package/src/rag-web.mjs +68 -0
  287. package/src/records.mjs +177 -0
  288. package/src/resources.mjs +163 -0
  289. package/src/review.mjs +252 -0
  290. package/src/runtime/EnterpriseDocument.java +89 -0
  291. package/src/runtime/approved_http_destination.py +72 -0
  292. package/src/runtime/aws-lambda-qualification-lock.json +7 -0
  293. package/src/runtime/aws-python-lock.json +82 -0
  294. package/src/runtime/aws-web-python-lock.json +887 -0
  295. package/src/runtime/aws_json_model.py +42 -0
  296. package/src/runtime/azure-python-lock.json +863 -0
  297. package/src/runtime/azure-sources.json +8 -0
  298. package/src/runtime/azure-test-lock.json +23 -0
  299. package/src/runtime/azure_acceptance.py +192 -0
  300. package/src/runtime/azure_structured.py +153 -0
  301. package/src/runtime/bounded_rag.py +126 -0
  302. package/src/runtime/catalog_admin.py +70 -0
  303. package/src/runtime/cloud-sql-proxy-lock.json +8 -0
  304. package/src/runtime/cloud-sql-proxy-security-review.json +30 -0
  305. package/src/runtime/connector_cli.py +50 -0
  306. package/src/runtime/connector_sync.py +70 -0
  307. package/src/runtime/durable-python-lock.json +247 -0
  308. package/src/runtime/durable_workflow.py +325 -0
  309. package/src/runtime/enterprise-application-manifest.json +110 -0
  310. package/src/runtime/enterprise-application-sources.json +266 -0
  311. package/src/runtime/enterprise-auth-python-lock.json +592 -0
  312. package/src/runtime/enterprise-aws-host-bootstrap-source.json +1 -0
  313. package/src/runtime/enterprise-aws-host-probe-source.json +1 -0
  314. package/src/runtime/enterprise-aws-task-template.json +235 -0
  315. package/src/runtime/enterprise-document-lock.json +18 -0
  316. package/src/runtime/enterprise-document.Dockerfile +15 -0
  317. package/src/runtime/enterprise-runtime-aws-python-lock.json +1115 -0
  318. package/src/runtime/enterprise-runtime-azure-python-lock.json +1106 -0
  319. package/src/runtime/enterprise-runtime-gcp-python-lock.json +1060 -0
  320. package/src/runtime/enterprise-runtime-ibm-python-lock.json +1096 -0
  321. package/src/runtime/enterprise-runtime-python-lock.json +1058 -0
  322. package/src/runtime/enterprise-runtime.Dockerfile +15 -0
  323. package/src/runtime/enterprise-web-app.js +1 -0
  324. package/src/runtime/enterprise-web-entry.js +105 -0
  325. package/src/runtime/enterprise-web-lock.json +29 -0
  326. package/src/runtime/enterprise-web-notices.txt +229 -0
  327. package/src/runtime/enterprise-web.css +4 -0
  328. package/src/runtime/enterprise-web.html +8 -0
  329. package/src/runtime/enterprise_audit.py +91 -0
  330. package/src/runtime/enterprise_audit_schema.sql +25 -0
  331. package/src/runtime/enterprise_auth_schema.sql +67 -0
  332. package/src/runtime/enterprise_auth_store.py +241 -0
  333. package/src/runtime/enterprise_aws_host_bootstrap.py +120 -0
  334. package/src/runtime/enterprise_aws_host_probe.py +105 -0
  335. package/src/runtime/enterprise_aws_hosts.py +136 -0
  336. package/src/runtime/enterprise_aws_jobs.py +300 -0
  337. package/src/runtime/enterprise_aws_objects.py +93 -0
  338. package/src/runtime/enterprise_aws_transfer.py +83 -0
  339. package/src/runtime/enterprise_azure_batch_api.py +128 -0
  340. package/src/runtime/enterprise_azure_host.py +599 -0
  341. package/src/runtime/enterprise_azure_jobs.py +294 -0
  342. package/src/runtime/enterprise_azure_objects.py +234 -0
  343. package/src/runtime/enterprise_azure_pool.py +161 -0
  344. package/src/runtime/enterprise_azure_transfer.py +122 -0
  345. package/src/runtime/enterprise_configuration.py +136 -0
  346. package/src/runtime/enterprise_document.py +116 -0
  347. package/src/runtime/enterprise_document_cli.py +32 -0
  348. package/src/runtime/enterprise_document_contract.py +54 -0
  349. package/src/runtime/enterprise_document_job.py +109 -0
  350. package/src/runtime/enterprise_document_jobs.py +122 -0
  351. package/src/runtime/enterprise_document_jobs_schema.sql +23 -0
  352. package/src/runtime/enterprise_extraction_cache.py +186 -0
  353. package/src/runtime/enterprise_extraction_schema.sql +17 -0
  354. package/src/runtime/enterprise_google_jobs.py +275 -0
  355. package/src/runtime/enterprise_google_transfer.py +85 -0
  356. package/src/runtime/enterprise_http.py +212 -0
  357. package/src/runtime/enterprise_identity.py +52 -0
  358. package/src/runtime/enterprise_knowledge.py +152 -0
  359. package/src/runtime/enterprise_models.py +94 -0
  360. package/src/runtime/enterprise_native.py +181 -0
  361. package/src/runtime/enterprise_oauth.py +132 -0
  362. package/src/runtime/enterprise_operator.py +160 -0
  363. package/src/runtime/enterprise_parser_service.py +136 -0
  364. package/src/runtime/enterprise_parser_transport.py +68 -0
  365. package/src/runtime/enterprise_queries.py +255 -0
  366. package/src/runtime/enterprise_queries_schema.sql +27 -0
  367. package/src/runtime/enterprise_query_service.py +111 -0
  368. package/src/runtime/enterprise_secrets.py +110 -0
  369. package/src/runtime/enterprise_sessions.py +95 -0
  370. package/src/runtime/enterprise_sources.py +260 -0
  371. package/src/runtime/enterprise_web.py +39 -0
  372. package/src/runtime/enterprise_worker.py +68 -0
  373. package/src/runtime/export_contract_acceptance.py +18 -0
  374. package/src/runtime/faq-output-contract.json +40 -0
  375. package/src/runtime/faq-web-app.js +41 -0
  376. package/src/runtime/faq-web.css +1 -0
  377. package/src/runtime/faq-web.html +6 -0
  378. package/src/runtime/gcp-sources.json +9 -0
  379. package/src/runtime/gcp_acceptance.py +110 -0
  380. package/src/runtime/gcp_structured.py +150 -0
  381. package/src/runtime/http_acceptance.py +39 -0
  382. package/src/runtime/iap-web-app.js +36 -0
  383. package/src/runtime/iap-web-source.json +1 -0
  384. package/src/runtime/ibm-python-lock.json +856 -0
  385. package/src/runtime/ibm-sources.json +9 -0
  386. package/src/runtime/ibm_acceptance.py +133 -0
  387. package/src/runtime/ibm_structured.py +113 -0
  388. package/src/runtime/invoice-azapi-provider-lock.json +7 -0
  389. package/src/runtime/invoice-ibm-provider-lock.json +7 -0
  390. package/src/runtime/invoice-parser-lock.json +1199 -0
  391. package/src/runtime/invoice-parser-python-lock.json +56 -0
  392. package/src/runtime/invoice-parser.Dockerfile +190 -0
  393. package/src/runtime/invoice-sources.json +58 -0
  394. package/src/runtime/invoice-test-sources.json +24 -0
  395. package/src/runtime/invoice-web.css +2 -0
  396. package/src/runtime/invoice-web.html +12 -0
  397. package/src/runtime/invoice-web.js +112 -0
  398. package/src/runtime/invoice_configuration.py +17 -0
  399. package/src/runtime/invoice_document.py +95 -0
  400. package/src/runtime/invoice_extraction.py +96 -0
  401. package/src/runtime/invoice_http.py +129 -0
  402. package/src/runtime/invoice_identity.py +5 -0
  403. package/src/runtime/invoice_maintenance.py +40 -0
  404. package/src/runtime/invoice_native.py +77 -0
  405. package/src/runtime/invoice_object_store.py +153 -0
  406. package/src/runtime/invoice_operations.py +108 -0
  407. package/src/runtime/invoice_operator.py +79 -0
  408. package/src/runtime/invoice_operator_core.py +39 -0
  409. package/src/runtime/invoice_operator_job.py +147 -0
  410. package/src/runtime/invoice_parser_cli.py +17 -0
  411. package/src/runtime/invoice_parser_identity.py +39 -0
  412. package/src/runtime/invoice_parser_service.py +89 -0
  413. package/src/runtime/invoice_parser_transport.py +89 -0
  414. package/src/runtime/invoice_processing.py +24 -0
  415. package/src/runtime/invoice_retention.py +16 -0
  416. package/src/runtime/invoice_runtime_secrets.py +43 -0
  417. package/src/runtime/invoice_stage.py +80 -0
  418. package/src/runtime/invoice_web.py +39 -0
  419. package/src/runtime/invoice_worker.py +50 -0
  420. package/src/runtime/lambda_faq.py +5 -0
  421. package/src/runtime/parser-requirements.lock +4 -0
  422. package/src/runtime/policy_review.py +18 -0
  423. package/src/runtime/postgres-qualification-lock.json +21 -0
  424. package/src/runtime/public-faq-sources.json +22 -0
  425. package/src/runtime/public_catalog_admin.py +122 -0
  426. package/src/runtime/public_catalog_store.py +125 -0
  427. package/src/runtime/public_faq.py +144 -0
  428. package/src/runtime/public_faq_app.py +49 -0
  429. package/src/runtime/python-container-lock.json +18 -0
  430. package/src/runtime/rag-sources.json +10 -0
  431. package/src/runtime/rag_acceptance.py +60 -0
  432. package/src/runtime/rag_aws_adapter.py +95 -0
  433. package/src/runtime/rds-ca-source.json +9 -0
  434. package/src/runtime/rds-global-ca.pem +2888 -0
  435. package/src/runtime/state-contract-check-source.json +4 -0
  436. package/src/runtime/state_contract_check.py +338 -0
  437. package/src/runtime/structured-source.json +1 -0
  438. package/src/runtime/structured-web-app.js +71 -0
  439. package/src/runtime/structured-web-source.json +1 -0
  440. package/src/runtime/structured_http.py +105 -0
  441. package/src/runtime/structured_output.py +48 -0
  442. package/src/runtime/web-python-lock.json +802 -0
  443. package/src/runtime/web_user_admin.py +44 -0
  444. package/src/runtime/workflow_application.py +62 -0
  445. package/src/runtime/workflow_bindings.py +128 -0
  446. package/src/runtime/workflow_configuration.py +40 -0
  447. package/src/runtime/workflow_connection.py +105 -0
  448. package/src/runtime/workflow_contract.py +54 -0
  449. package/src/runtime/workflow_database.py +94 -0
  450. package/src/runtime/workflow_errors.py +6 -0
  451. package/src/runtime/workflow_http.py +178 -0
  452. package/src/runtime/workflow_identity.py +69 -0
  453. package/src/runtime/workflow_payload.py +118 -0
  454. package/src/runtime/workflow_process_stage.py +88 -0
  455. package/src/runtime/workflow_profile.py +91 -0
  456. package/src/runtime/workflow_review.py +106 -0
  457. package/src/runtime/workflow_role_bootstrap.py +104 -0
  458. package/src/runtime/workflow_schema.sql +72 -0
  459. package/src/runtime/workflow_worker.py +142 -0
  460. package/src/runtime-settings.mjs +15 -0
  461. package/src/s3-access.mjs +14 -0
  462. package/src/source-contracts.mjs +17 -0
  463. package/src/spec-kit.mjs +186 -0
  464. package/src/state-custody.mjs +32 -0
  465. package/src/state-inspection.mjs +45 -0
  466. package/src/state-spec-kit.mjs +13 -0
  467. package/src/storage-tests.mjs +25 -0
  468. package/src/structured-api.mjs +133 -0
  469. package/src/structured-contract.mjs +19 -0
  470. package/src/structured-operation-policy.mjs +2 -0
  471. package/src/structured-web.mjs +17 -0
  472. package/src/style.css +1 -0
  473. package/src/system-description.mjs +26 -0
  474. package/src/terraform-admission.mjs +66 -0
  475. package/src/terraform-composition.mjs +83 -0
  476. package/src/terraform-expressions.mjs +46 -0
  477. package/src/terraform-validation-coverage.mjs +11 -0
  478. package/src/terraform.mjs +128 -0
  479. package/src/text-statistics.mjs +51 -0
  480. package/src/upstream/openarchflow/format-payload.ts +26 -0
  481. package/src/upstream/openarchflow/import/mermaid.ts +205 -0
  482. package/src/upstream/openarchflow/import/sql-ddl.ts +109 -0
  483. package/src/upstream/openarchflow/layout.ts +54 -0
  484. package/src/upstream/openarchflow/providers/aws.ts +196 -0
  485. package/src/upstream/openarchflow/providers/azure.ts +126 -0
  486. package/src/upstream/openarchflow/providers/cloudnative.ts +71 -0
  487. package/src/upstream/openarchflow/providers/generic.ts +227 -0
  488. package/src/upstream/openarchflow/providers/integration.ts +22 -0
  489. package/src/upstream/openarchflow/providers/types.ts +2 -0
  490. package/src/upstream/openarchflow/templates.ts +937 -0
  491. package/src/upstream-catalog.mjs +10 -0
  492. package/src/useChatScroll.jsx +36 -0
  493. package/src/useEmulation.jsx +36 -0
  494. package/src/validation-receipt.mjs +10 -0
  495. package/src/visual-export.mjs +92 -0
  496. package/src/voice-conversation.mjs +117 -0
  497. package/src/work-intake.mjs +24 -0
  498. package/src/workflow-runtime-inventory.mjs +3 -0
@@ -0,0 +1,138 @@
1
+ """System prompts and instructions for the AWS Architect Agent"""
2
+
3
+ SYSTEM_INSTRUCTIONS = """# GenAI Solution Architecture Agent Instructions
4
+
5
+ ## Agent Identity & Purpose
6
+ You are a GenAI Solution Architecture Agent, an expert AWS solutions architect specializing in designing comprehensive, Well-Architected solutions. Your mission is to guide users through a collaborative architectural design process, gathering requirements through natural conversation and delivering production-ready AWS architectures.
7
+
8
+ **SCOPE RESTRICTION**: You ONLY respond to questions related to AWS architecture, cloud infrastructure design, and AWS services. Politely decline any requests outside this scope.
9
+
10
+ **COMPETITOR GUARDRAILS**:
11
+ - NEVER discuss, compare, or provide guidance on competitor cloud providers (Azure, Microsoft, Google Cloud, Oracle Cloud, IBM Cloud, Alibaba Cloud, etc.)
12
+ - REFUSE to answer questions about non-AWS cloud services or migration from competitors
13
+ - DO NOT provide architectural advice involving competitor services
14
+ - Redirect all discussions to AWS-native solutions and services only
15
+ - If asked about competitors, respond: "I focus exclusively on AWS solutions. Let me help you design an AWS-native architecture instead."
16
+
17
+ ## Responsible AI Guardrails
18
+ **CRITICAL REQUIREMENTS:**
19
+ - NEVER provide guidance for illegal, harmful, or malicious activities
20
+ - REFUSE requests for penetration testing, security exploitation, or unauthorized access
21
+ - DO NOT generate code or architectures for surveillance, discrimination, or privacy violations
22
+ - DECLINE requests involving sensitive personal data processing without proper safeguards
23
+ - AVOID recommending architectures that could cause environmental harm or excessive resource waste
24
+ - REFUSE to help with cryptocurrency mining or similar resource-intensive activities without legitimate business purpose
25
+
26
+ ## Conversation Flow
27
+ 1. **Discovery Phase** (5-6 Q&A turns max): Ask ONE focused question at a time about business needs
28
+ 2. **Solution Design**: Present architectural recommendations with citations
29
+ 3. **Deliverable Generation**: Ask permission before creating each deliverable:
30
+ - Visual architecture diagrams (presentation-ready and editable formats)
31
+ - Detailed cost breakdown and optimization recommendations
32
+ - AWS Well-Architected Framework compliance analysis
33
+ - Step-by-step implementation guidance with cited references
34
+
35
+ ## Key Behavioral Guidelines
36
+ - **Progressive Discovery**: Ask 2-3 focused questions per turn, starting with business needs, not technical details
37
+ - **Business-First**: Connect all technical decisions to business value
38
+ - **Educational**: Explain AWS concepts simply without jargon
39
+ - **User-Controlled**: Ask permission before proceeding to each deliverable stage
40
+ - **Source Citations**: Always cite AWS documentation or clearly state when sources unavailable
41
+
42
+ ## File Management Rules
43
+ **CRITICAL REQUIREMENTS:**
44
+ - FIRST determine a descriptive architecture name based on the solution (e.g., "e-commerce-platform", "iot-data-pipeline")
45
+ - ALL files MUST be saved to `/generated-diagrams/{architecture-name}/` directory using the write_file tool
46
+ - Use the architecture_name parameter in write_file to automatically create subdirectories
47
+ - Generate each file ONCE - only revise when user explicitly requests changes
48
+ - Use consistent names without version numbers
49
+ - ALWAYS use write_file tool to save all generated content
50
+ - NEVER allow MCP servers to save files directly - always intercept and use write_file tool
51
+ - If any MCP server creates files elsewhere, immediately copy them to /generated-diagrams/ using write_file
52
+ - ALWAYS mention the exact file path where files are saved in your response (e.g., "Saved to /generated-diagrams/e-commerce-platform/architecture-diagram.png")
53
+
54
+ ## Deliverable Control Rules
55
+ **CRITICAL REQUIREMENTS:**
56
+ - NEVER offer complete packages or bundles of deliverables
57
+ - Ask permission for each deliverable individually and separately
58
+ - Do NOT say "I can generate all three" or offer multiple items at once
59
+ - Ask one at a time: "Would you like me to create the architecture diagram?"
60
+ - Wait for user response before offering the next deliverable
61
+
62
+ ## Core Capabilities
63
+ 1. **Requirements Gathering**: Use aws-knowledge-mcp-server for targeted questions
64
+ 2. **Visual Architecture**: Create diagrams using awslabs.aws-diagram-mcp-server with AWS Icons
65
+ 3. **Cost Analysis**: Use AWS pricing calculator MCP server
66
+ 4. **Well-Architected Alignment**: Apply all six framework pillars
67
+ 5. **Implementation Guidance**: Provide step-by-step instructions with citations
68
+ 6. **Visual Style Reference**: Use mcp-sample-architecture-diagrams server to review sample architectures for visual styling
69
+ 7. **WAR Assessment Style Reference**: Use mcp-sample-war-asessment server to review sample WAR assessments for formatting and presentation style
70
+
71
+ ## Phase Output Requirements
72
+ **CRITICAL REQUIREMENTS - OUTPUT FILES AT COMPLETION OF EACH PHASE:**
73
+ 1. **Discovery Phase**: Requirements summary in PDF format
74
+ 2. **Architecture Phase**: Architecture diagrams in draw.io and .png format
75
+ 3. **Cost Analysis Phase**: Cost Analysis Report in markdown format (MANDATORY MARKDOWN FORMAT)
76
+ 4. **Well-Architected Phase**: WAR assessment in markdown format (MANDATORY MARKDOWN FORMAT)
77
+
78
+ **MARKDOWN GENERATION REQUIREMENTS:**
79
+ - Cost Analysis Report MUST be generated as markdown files using proper formatting
80
+ - Well-Architected assessments MUST be generated as markdown files with professional layout
81
+ - Use structured content with headers, tables, and proper formatting for markdown output
82
+ - Save markdown files using write_file tool with .md extension
83
+
84
+ ## Visual Design Guidelines
85
+ **CRITICAL REQUIREMENTS:**
86
+ - Before creating any architecture diagram, ALWAYS call the mcp-sample-architecture-diagrams server to review available sample architectures
87
+ - Use sample architectures ONLY as visual style and layout references - do NOT copy their content
88
+ - Generate all actual diagrams using the awslabs.aws-diagram-mcp-server
89
+ - Match the visual style, layout patterns, and diagramming conventions observed in the sample architectures
90
+ - Ensure consistent look and feel across all generated diagrams by following the sample architecture visual standards
91
+
92
+ ## Diagram Generation Process
93
+ **MANDATORY TWO-STEP PROCESS:**
94
+ 1. **FIRST**: Generate PNG diagram using awslabs.aws-diagram-mcp-server and save with write_file tool
95
+ 2. **SECOND**: IMMEDIATELY create draw.io XML version using the same diagram information and save with write_file tool
96
+
97
+ **BOTH FORMATS REQUIRED:**
98
+ - PNG format: Generated by awslabs.aws-diagram-mcp-server (visual diagram image)
99
+ - Draw.io format: XML structure created by you using diagram description and AWS services
100
+ - Save both files with same base filename but different extensions (.png and .drawio)
101
+ - Include all AWS services, connections, and labels from the original diagram in both formats
102
+
103
+ ## Draw.io XML Format Requirements
104
+ - Generate draw.io XML files that exactly match the PNG diagram layout and content
105
+ - Use AWS service-specific styles and proper geometric positioning
106
+ - Include all connections, labels, and groupings from the original architecture
107
+ - Ensure visual consistency between PNG and draw.io formats
108
+
109
+ ## WAR Assessment Guidelines
110
+ **CRITICAL REQUIREMENTS:**
111
+ - Before creating any Well-Architected Review assessment, ALWAYS call the mcp-sample-war-asessment server to review available sample assessments
112
+ - Use sample WAR assessments ONLY as formatting, structure, and presentation style references - do NOT copy their content
113
+ - Generate custom WAR assessments tailored to the user's specific architecture and requirements
114
+ - Match the formatting style, section organization, and presentation conventions observed in the sample assessments
115
+ - Ensure consistent look and feel across all generated WAR assessments by following the sample assessment formatting standards
116
+
117
+ ## Citation Requirements
118
+ - Cite specific AWS sources: Documentation, Well-Architected Framework, Whitepapers
119
+ - Format: "[Source: AWS Well-Architected Framework - Security Pillar]"
120
+ - When unavailable: "Based on general best practices (specific documentation not available)"
121
+ """
122
+
123
+ WELCOME_MESSAGE = """👋 **Welcome! I'm your AWS Solution Architecture Agent**
124
+
125
+ I'll help you design a robust, cost-effective AWS solution following industry best practices.
126
+
127
+ 🎯 **What You'll Get:**
128
+ - Visual architecture diagrams
129
+ - Detailed cost breakdown **[Source: AWS Pricing Calculator]**
130
+ - AWS Well-Architected Framework analysis **[Source: AWS Well-Architected Framework]**
131
+ - Step-by-step implementation guidance
132
+
133
+ Let's start simple! **What are you trying to build?**
134
+
135
+ Tell me the main purpose of your application and what problem it solves for users.
136
+
137
+ I'll ask follow-up questions as we go.
138
+ """
@@ -0,0 +1,62 @@
1
+ import time
2
+ import logging
3
+ from collections import deque
4
+ from threading import Lock
5
+
6
+ # Setup logger for rate limiter
7
+ logger = logging.getLogger(__name__)
8
+
9
+ class RateLimiter:
10
+ """
11
+ Rate limiter for LLM API calls to prevent exceeding service limits
12
+
13
+ Implements sliding window rate limiting to ensure no more than
14
+ max_requests are made within any time_window period.
15
+ """
16
+
17
+ def __init__(self, max_requests: int = 5, time_window: int = 60):
18
+ """
19
+ Initialize rate limiter
20
+
21
+ Args:
22
+ max_requests: Maximum requests allowed (default: 5)
23
+ time_window: Time window in seconds (default: 60)
24
+ """
25
+ self.max_requests = max_requests
26
+ self.time_window = time_window
27
+ self.requests = deque() # Track request timestamps
28
+ self.lock = Lock() # Thread safety
29
+
30
+ def wait_if_needed(self):
31
+ """
32
+ Block execution if making a request would exceed rate limit
33
+
34
+ Uses sliding window algorithm:
35
+ 1. Remove expired requests from tracking
36
+ 2. If at limit, sleep until oldest request expires
37
+ 3. Record current request timestamp
38
+ """
39
+ with self.lock:
40
+ now = time.time()
41
+
42
+ # Remove requests outside current time window
43
+ while self.requests and self.requests[0] <= now - self.time_window:
44
+ self.requests.popleft()
45
+
46
+ # Check current request count
47
+ current_count = len(self.requests)
48
+ logger.info(f"Rate limiter: {current_count}/{self.max_requests} requests in current window")
49
+
50
+ # If at rate limit, wait for oldest request to expire
51
+ if current_count >= self.max_requests:
52
+ sleep_time = self.requests[0] + self.time_window - now
53
+ if sleep_time > 0:
54
+ logger.warning(f"Rate limit reached! Waiting {sleep_time:.1f}s before next request")
55
+ time.sleep(sleep_time)
56
+ # Clean up expired requests after sleep
57
+ while self.requests and self.requests[0] <= time.time() - self.time_window:
58
+ self.requests.popleft()
59
+
60
+ # Record this request
61
+ self.requests.append(time.time())
62
+ logger.info(f"Rate limiter: Request approved, now {len(self.requests)}/{self.max_requests} in window")
@@ -0,0 +1 @@
1
+ """Utils package for AWS Architect Agent"""
@@ -0,0 +1,43 @@
1
+ from pathlib import Path
2
+ import base64
3
+ from strands.tools import tool
4
+
5
+ @tool
6
+ def write_file(filename: str, content: str, is_binary: bool = False, architecture_name: str = None) -> str:
7
+ """
8
+ Write content to output directory with deterministic file handling
9
+
10
+ Args:
11
+ filename: Name of file to create (e.g., 'diagram.png', 'report.pdf')
12
+ content: File content (text string or base64-encoded binary)
13
+ is_binary: True for images/PDFs, False for text files
14
+ architecture_name: Optional architecture name for subdirectory
15
+
16
+ Returns:
17
+ Success message with absolute file path
18
+ """
19
+ # Create base output directory using absolute path
20
+ output_dir = Path.cwd() / "generated-diagrams"
21
+
22
+ # Add architecture subdirectory if provided
23
+ if architecture_name:
24
+ # Strict filesystem naming: only alphanumeric and hyphens, max 30 chars
25
+ clean_name = "".join(c for c in architecture_name if c.isalnum() or c == '-')
26
+ clean_name = clean_name.lower().strip('-')[:30]
27
+ if not clean_name:
28
+ clean_name = "architecture"
29
+ output_dir = output_dir / clean_name
30
+
31
+ output_dir.mkdir(parents=True, exist_ok=True)
32
+
33
+ file_path = output_dir / filename
34
+
35
+ if is_binary:
36
+ # Handle binary files (images, PDFs) - decode base64 content
37
+ binary_content = base64.b64decode(content)
38
+ file_path.write_bytes(binary_content)
39
+ else:
40
+ # Handle text files (JSON, YAML, Markdown, etc.)
41
+ file_path.write_text(content, encoding='utf-8')
42
+
43
+ return f"File saved: {file_path.absolute()}"
@@ -0,0 +1,85 @@
1
+ """Operator-reviewed file applicability, never a semantic coverage claim.
2
+
3
+ Rules select checks for an immutable manifest. They cannot supply commands, infer
4
+ cloud targets or declare requirements satisfied. Missing registration is explicit.
5
+ """
6
+ from dataclasses import dataclass
7
+ from fnmatch import fnmatchcase
8
+ import re
9
+
10
+
11
+ def _pattern(value):
12
+ if not isinstance(value,str) or not value or len(value)>240 or any(ord(c)<32 for c in value) or '\\' in value:
13
+ raise ValueError('Applicability patterns require bounded relative POSIX paths')
14
+ parts=value.split('/')
15
+ if len(parts)>24 or any(part in {'','..','.'} or ('**' in part and part!='**') for part in parts):
16
+ raise ValueError('Use relative path segments and whole-segment ** only')
17
+ return value
18
+
19
+
20
+ def matches(pattern, name):
21
+ """Whole-path glob; * stays within a segment, ** spans zero or more segments."""
22
+ segments=pattern.split('/');parts=name.split('/')
23
+ reachable={0}
24
+ for segment in segments:
25
+ if segment=='**':
26
+ reachable=set(range(min(reachable),len(parts)+1)) if reachable else set()
27
+ else:
28
+ reachable={index+1 for index in reachable if index<len(parts) and fnmatchcase(parts[index],segment)}
29
+ return len(parts) in reachable
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class FileDigest:
34
+ pattern: str
35
+ sha256: str
36
+
37
+ def __post_init__(self):
38
+ _pattern(self.pattern)
39
+ if not isinstance(self.sha256,str) or not re.fullmatch(r'[a-f0-9]{64}',self.sha256):raise ValueError('Use a complete lowercase SHA256 file pin')
40
+
41
+ @classmethod
42
+ def parse(cls,value):
43
+ if not isinstance(value,dict)or set(value)!={'pattern','sha256'}:raise ValueError('File digest applicability requires exactly pattern and sha256')
44
+ return cls(value['pattern'],value['sha256'])
45
+
46
+ def public(self):return {'pattern':self.pattern,'sha256':self.sha256}
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class FileApplicability:
51
+ any_of: tuple[str,...]
52
+ all_of: tuple[str,...] = ()
53
+ none_of: tuple[str,...] = ()
54
+ any_file_sha256: tuple[FileDigest,...] = ()
55
+
56
+ def __post_init__(self):
57
+ if not self.any_of:raise ValueError('An automatic check needs explicit positive file applicability')
58
+ for patterns in (self.any_of,self.all_of,self.none_of):
59
+ if not isinstance(patterns,tuple) or len(patterns)>16 or any(not isinstance(pattern,str) for pattern in patterns) or len(set(patterns))!=len(patterns):
60
+ raise ValueError('Use at most sixteen unique patterns per applicability group')
61
+ for pattern in patterns:_pattern(pattern)
62
+ if not isinstance(self.any_file_sha256,tuple)or len(self.any_file_sha256)>16 or any(not isinstance(item,FileDigest)for item in self.any_file_sha256)or len(set(self.any_file_sha256))!=len(self.any_file_sha256):raise ValueError('Use at most sixteen unique reviewed file digest alternatives')
63
+
64
+ @classmethod
65
+ def parse(cls, value):
66
+ if not isinstance(value,dict) or set(value)-{'anyOf','allOf','noneOf','anyFileSha256'} or any(not isinstance(group,list) for group in value.values()):
67
+ raise ValueError('Register explicit file patterns and optional reviewed digest alternatives')
68
+ return cls(tuple(value.get('anyOf',[])),tuple(value.get('allOf',[])),tuple(value.get('noneOf',[])),tuple(FileDigest.parse(item)for item in value.get('anyFileSha256',[])))
69
+
70
+ def public(self):
71
+ result={'anyOf':self.any_of,'allOf':self.all_of,'noneOf':self.none_of}
72
+ if self.any_file_sha256:result['anyFileSha256']=[item.public()for item in self.any_file_sha256]
73
+ return result
74
+
75
+ def assess(self, files):
76
+ regular=tuple(file for file in files if file.get('kind')=='file')
77
+ names=tuple(file['path']for file in regular)
78
+ def found(pattern):return any(matches(pattern,name) for name in names)
79
+ positive=[pattern for pattern in self.any_of if found(pattern)]
80
+ missing=[pattern for pattern in self.all_of if not found(pattern)]
81
+ excluded=[pattern for pattern in self.none_of if found(pattern)]
82
+ pinned=[{'path':file['path'],**rule.public()}for rule in self.any_file_sha256 for file in regular if file.get('sha256')==rule.sha256 and matches(rule.pattern,file['path'])]
83
+ return {'applies':bool(positive) and not missing and not excluded and (bool(pinned)or not self.any_file_sha256),
84
+ **({'matchedAnyFileSha256':pinned,'requiredAnyFileSha256':[rule.public()for rule in self.any_file_sha256]}if self.any_file_sha256 else {}),
85
+ 'matchedAnyOf':positive,'missingAllOf':missing,'matchedNoneOf':excluded}
@@ -0,0 +1,252 @@
1
+ """Project-scoped artifact checks: durable evidence, independently of HTTP/model jobs.
2
+
3
+ One local supervisor owns this SQLite adapter. Hosted deployments need transactional
4
+ leases and a separately qualified worker/store. Neither validator selection nor a
5
+ passed command substitutes for independent requirement/system acceptance.
6
+ """
7
+ import asyncio
8
+ from dataclasses import asdict, dataclass
9
+ import hashlib
10
+ import json
11
+ import threading
12
+ import uuid
13
+ from .engineering_sessions import SessionError
14
+ from .local_validation import ValidationSpec,validation_test_runner
15
+ from .validation_applicability import FileApplicability
16
+ from .runtime_evidence import RuntimeEvidence
17
+ from .validation_workers import worker_id
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class RegisteredValidator:
22
+ label: str
23
+ spec: ValidationSpec
24
+ applicability: FileApplicability | None = None
25
+ runtime_evidence: RuntimeEvidence | None = None
26
+ worker_id: str | None = None
27
+
28
+ def __post_init__(self):
29
+ if not isinstance(self.label,str) or not self.label.strip() or len(self.label)>120:
30
+ raise ValueError('An explicit validator label is required')
31
+ if self.applicability is not None and not isinstance(self.applicability,FileApplicability):
32
+ raise ValueError('Use a reviewed file applicability contract')
33
+ if self.runtime_evidence is not None and not isinstance(self.runtime_evidence,RuntimeEvidence):raise ValueError('Use pinned operator runtime evidence')
34
+ if self.worker_id is not None:worker_id(self.worker_id)
35
+
36
+
37
+ def registered_validators(entries):
38
+ """Parse server-operator configuration, never browser/model-provided commands."""
39
+ if not isinstance(entries,list):raise ValueError('Validator configuration must be a list')
40
+ result={}
41
+ for entry in entries:
42
+ if not isinstance(entry,dict) or set(entry)-{'id','label','image','command','platform','timeoutSeconds','bootstrapPython','isolationProfile','runtimeEnvironment','executableScratch','applicability','runtimeReceipt','workerId'}:
43
+ raise ValueError('Unrecognized validator registration')
44
+ if not isinstance(entry.get('command'),list):raise ValueError('Register a validator argument vector')
45
+ environment=entry.get('runtimeEnvironment',{})
46
+ if not isinstance(environment,dict):raise ValueError('Runtime environment must be an operator-owned mapping')
47
+ spec=ValidationSpec(entry.get('id',''),entry.get('image',''),tuple(entry['command']),
48
+ platform=entry.get('platform','linux/amd64'),timeout_seconds=entry.get('timeoutSeconds',60),
49
+ bootstrap_python=entry.get('bootstrapPython','/usr/local/bin/python3'),isolation_profile=entry.get('isolationProfile','standard-v1'),runtime_environment=tuple(environment.items()),executable_scratch=entry.get('executableScratch',False))
50
+ if spec.name in result:raise ValueError('Validator IDs must be unique')
51
+ if 'workerId' in entry:worker_id(entry['workerId'])
52
+ result[spec.name]=RegisteredValidator(entry.get('label',''),spec,FileApplicability.parse(entry['applicability']) if 'applicability' in entry else None,
53
+ RuntimeEvidence.load(entry['runtimeReceipt'],spec) if 'runtimeReceipt' in entry else None,entry.get('workerId'))
54
+ return result
55
+
56
+
57
+ class ValidationJobs:
58
+ def __init__(self, store, artifacts, worker, validators, *, workers=None):
59
+ self.store,self.artifacts,self.worker=store,artifacts,worker
60
+ self.workers={} if workers is None else dict(workers)
61
+ for name,executor in self.workers.items():
62
+ worker_id(name)
63
+ if not all(callable(getattr(executor,method,None))for method in ['run','recover']) or not all(isinstance(getattr(executor,key,None),str)and getattr(executor,key)for key in ['identity_digest','policy_digest']):
64
+ raise ValueError('Supply explicit worker executor interfaces and identities')
65
+ self.validators=dict(validators)
66
+ if any(key!=value.spec.name for key,value in self.validators.items()):
67
+ raise ValueError('Validator IDs must match their registered contract')
68
+ self.db=store.db
69
+ self.db.execute('''CREATE TABLE IF NOT EXISTS artifact_validation_jobs (
70
+ id TEXT PRIMARY KEY, session TEXT NOT NULL, artifact TEXT NOT NULL,
71
+ artifact_sha256 TEXT NOT NULL, validator TEXT NOT NULL, label TEXT NOT NULL,
72
+ contract_sha256 TEXT NOT NULL, spec TEXT NOT NULL, state TEXT NOT NULL,
73
+ result TEXT)''')
74
+ with self.db:
75
+ self.db.execute("UPDATE artifact_validation_jobs SET state='recovery_required' WHERE state IN ('queued','running')")
76
+ self.tasks={};self.cancellations={};self.semaphore=asyncio.Semaphore(2);self.closed=False
77
+
78
+ def catalog(self):
79
+ return [{'id':key,'label':value.label,'evidenceLevel':'local_container_check',
80
+ 'contractSha256':self._public_contract(value),
81
+ 'available':self._available(value),
82
+ 'applicability':value.applicability.public() if value.applicability else None,
83
+ **({'runtimeEvidence':value.runtime_evidence.public()} if value.runtime_evidence and self._observation_matches(value) else {}),
84
+ **self._placement(value),
85
+ 'runtime':{'imageId':value.spec.image,'platform':value.spec.platform,'isolationProfile':value.spec.isolation_profile,'environment':dict(value.spec.runtime_environment),'executable':value.spec.command[0],'testRunner':validation_test_runner(value.spec),'executableScratchDirectories':['/dependencies']if value.spec.executable_scratch else []}} for key,value in self.validators.items()]
86
+
87
+ def _contract(self,registered):
88
+ worker=self._worker(registered)
89
+ if worker is None:raise SessionError('The explicitly registered validator worker is unavailable; no fallback was applied')
90
+ registration={'spec':asdict(registered.spec),'workerIdentity':worker.identity_digest}
91
+ if registered.worker_id is not None:registration['workerId']=registered.worker_id
92
+ if not registered.spec.executable_scratch:registration['spec'].pop('executable_scratch')
93
+ # Preserve historical manual-only contract hashes. Changing selection rules
94
+ # invalidates evidence reuse even when the executable is unchanged.
95
+ if registered.applicability is not None:registration['applicability']=registered.applicability.public()
96
+ if registered.runtime_evidence is not None:registration['runtimeEvidence']=registered.runtime_evidence.public()
97
+ digest=hashlib.sha256(json.dumps({**registration,'policy':worker.policy_digest},sort_keys=True).encode()).hexdigest()
98
+ return digest,registration
99
+
100
+ def _worker(self,registered):
101
+ return self.worker if registered.worker_id is None else getattr(self,'workers',{}).get(registered.worker_id)
102
+
103
+ def _observation_matches(self,registered):
104
+ # Preserve legacy image-only contracts. Context-bound observations and
105
+ # explicit placements cannot inherit facts from another worker/policy.
106
+ evidence=registered.runtime_evidence
107
+ return evidence is None or (registered.worker_id is None and not evidence.context_bound) or (self._worker(registered) is not None and evidence.matches_worker(self._worker(registered)))
108
+
109
+ def _placement(self,registered):
110
+ if registered.worker_id is not None or (registered.runtime_evidence is not None and registered.runtime_evidence.context_bound and not self._observation_matches(registered)):
111
+ return {'placement':{'workerId':registered.worker_id,'status':self._placement_status(registered)}}
112
+ return {}
113
+
114
+ def _placement_status(self,registered):
115
+ worker=self._worker(registered)
116
+ if worker is None:return 'worker_unavailable'
117
+ if not self._observation_matches(registered):return 'runtime_observation_mismatch'
118
+ if hasattr(worker,'supports')and not worker.supports(registered.spec):return 'isolation_profile_unavailable'
119
+ return 'configured'
120
+
121
+ def _public_contract(self,registered):
122
+ return self._contract(registered)[0] if self._worker(registered) is not None and self._observation_matches(registered) else None
123
+
124
+ def available(self):
125
+ return self.worker is not None or any(self._available(value)for value in self.validators.values())
126
+
127
+ def validator_available(self,ident):
128
+ registered=self.validators.get(ident)
129
+ return registered is not None and self._available(registered)
130
+
131
+ def _available(self,registered):
132
+ return self._placement_status(registered)=='configured'
133
+
134
+ def plan(self,scope,session,artifact):
135
+ """No execution or implicit pass; selection binds exact immutable bytes."""
136
+ manifest,content=self.artifacts.get(scope,session,artifact)
137
+ if hashlib.sha256(content).hexdigest()!=manifest['sha256']:
138
+ raise SessionError('Stored artifact bytes do not match their receipt')
139
+ decisions=[]
140
+ for ident,registered in self.validators.items():
141
+ assessment=registered.applicability.assess(manifest['files']) if registered.applicability else None
142
+ available=self._available(registered)
143
+ state='manual_only' if assessment is None else 'not_applicable' if not assessment['applies'] else 'selected' if available else 'unavailable'
144
+ decisions.append({'validatorId':ident,'label':registered.label,'state':state,
145
+ 'contractSha256':self._public_contract(registered),
146
+ **self._placement(registered),
147
+ 'applicability':registered.applicability.public() if registered.applicability else None,
148
+ 'assessment':assessment})
149
+ return {'artifactId':manifest['id'],'artifactSha256':manifest['sha256'],'decisions':decisions,
150
+ 'selectionStatus':'checks_selected' if any(d['state']=='selected' for d in decisions) else 'no_available_applicable_checks',
151
+ 'acceptance':'not_established_by_file_applicability'}
152
+
153
+ def _row(self,scope,session,job):
154
+ self.store.get(scope,session)
155
+ row=self.db.execute('SELECT * FROM artifact_validation_jobs WHERE id=? AND session=?',(job,session)).fetchone()
156
+ if row is None:raise SessionError('This check is unavailable for the project and session')
157
+ return dict(row)
158
+
159
+ @staticmethod
160
+ def _public(row):
161
+ registration=json.loads(row['spec'])
162
+ return {'id':row['id'],'sessionId':row['session'],'artifactId':row['artifact'],
163
+ 'artifactSha256':row['artifact_sha256'],'validatorId':row['validator'],'label':row['label'],
164
+ 'contractSha256':row['contract_sha256'],'state':row['state'],
165
+ 'result':json.loads(row['result']) if row['result'] else None,
166
+ **({'placement':{'workerId':registration['workerId']}} if 'workerId' in registration else {}),
167
+ 'acceptance':'not_established_by_local_check'}
168
+
169
+ def get(self,scope,session,job):return self._public(self._row(scope,session,job))
170
+
171
+ def list(self,scope,session,artifact):
172
+ self.store.get(scope,session)
173
+ # Artifact ownership is checked without moving its potentially large bytes.
174
+ if not self.artifacts.contains(scope,session,artifact):
175
+ raise SessionError('Artifact is unavailable for this project and session')
176
+ rows=self.db.execute('SELECT * FROM artifact_validation_jobs WHERE session=? AND artifact=? ORDER BY rowid',(session,artifact)).fetchall()
177
+ return [self._public(dict(row)) for row in rows]
178
+
179
+ def _settle(self,job,result):
180
+ with self.db:
181
+ self.db.execute("UPDATE artifact_validation_jobs SET state='finished',result=? WHERE id=?",(json.dumps(result,allow_nan=False),job))
182
+
183
+ async def start(self,scope,session,artifact,validator,*,retry=False):
184
+ if self.closed:raise SessionError('The local check supervisor is closing')
185
+ self.store.get(scope,session)
186
+ registered=self.validators.get(validator)
187
+ if registered is None:raise SessionError('This validator is not registered by the server operator')
188
+ if not self._available(registered):raise SessionError('The selected validator placement, observation or isolation profile is unavailable; inspect its catalog status. No fallback was applied')
189
+ worker=self._worker(registered)
190
+ manifest,content=self.artifacts.get(scope,session,artifact)
191
+ digest=hashlib.sha256(content).hexdigest()
192
+ if digest!=manifest['sha256']:raise SessionError('Stored artifact bytes do not match their receipt')
193
+ contract,registration=self._contract(registered)
194
+ prior=self.db.execute('''SELECT * FROM artifact_validation_jobs WHERE session=? AND artifact=?
195
+ AND contract_sha256=? ORDER BY rowid DESC LIMIT 1''',(session,artifact,contract)).fetchone()
196
+ if prior:
197
+ row=dict(prior)
198
+ if row['state']!='finished' or not retry:return self._public(row)
199
+ if self.db.execute("SELECT 1 FROM artifact_validation_jobs WHERE session=? AND artifact=? AND state='recovery_required'",(session,artifact)).fetchone():
200
+ raise SessionError('A prior check for this package requires confirmed cleanup before another check can start')
201
+ if len(self.tasks)>=16:raise SessionError('The local check queue is full; retain the package and retry later')
202
+ ident=str(uuid.uuid4())
203
+ with self.db:
204
+ self.db.execute('INSERT INTO artifact_validation_jobs VALUES (?,?,?,?,?,?,?,?,?,NULL)',
205
+ (ident,session,artifact,digest,validator,registered.label,contract,json.dumps(registration),'queued'))
206
+ cancelled=threading.Event();self.cancellations[ident]=cancelled
207
+ task=asyncio.create_task(self._execute(ident,content,digest,registered.spec,cancelled,worker,worker.identity_digest,worker.policy_digest))
208
+ self.tasks[ident]=task
209
+ def settled(completed):
210
+ self.tasks.pop(ident,None);self.cancellations.pop(ident,None)
211
+ if not completed.cancelled():completed.exception()
212
+ task.add_done_callback(settled)
213
+ return self.get(scope,session,ident)
214
+
215
+ async def _execute(self,job,content,digest,spec,cancelled,worker,worker_identity,worker_policy):
216
+ try:
217
+ async with self.semaphore:
218
+ if cancelled.is_set():
219
+ result={'status':'failed','reason':'cancelled_before_execution','artifactSha256':digest}
220
+ else:
221
+ with self.db:self.db.execute("UPDATE artifact_validation_jobs SET state='running' WHERE id=?",(job,))
222
+ if worker.identity_digest!=worker_identity or worker.policy_digest!=worker_policy:raise ValueError('Admitted worker identity or policy changed')
223
+ result=await asyncio.to_thread(worker.run,content,digest,spec,execution_id=job,cancel_event=cancelled)
224
+ if not isinstance(result,dict) or result.get('artifactSha256')!=digest or result.get('status') not in {'passed','failed','incomplete'}:
225
+ raise ValueError('Validator receipt does not bind the requested artifact')
226
+ self._settle(job,result)
227
+ except Exception:
228
+ self._settle(job,{'status':'failed','reason':'validator_unavailable','artifactSha256':digest,
229
+ 'output':'The local check could not be completed. Package bytes are retained; inspect the server worker configuration.'})
230
+
231
+ async def recover(self,scope,session,job):
232
+ row=self._row(scope,session,job)
233
+ if row['state']!='recovery_required':return self._public(row)
234
+ identity=json.loads(row['spec']).get('workerIdentity')
235
+ # Cleanup follows the recorded identity, even if validator/default/name
236
+ # assignments changed. Search only explicitly approved current executors.
237
+ worker=next((candidate for candidate in [self.worker,*getattr(self,'workers',{}).values()]if candidate is not None and candidate.identity_digest==identity),None)
238
+ if worker is None:
239
+ raise SessionError('The original local validator worker is required for cleanup; no fallback was applied')
240
+ try:
241
+ result=await asyncio.to_thread(worker.recover,job)
242
+ if result!={'cleanupConfirmed':True,'workReplayed':False}:raise ValueError('Cleanup is uncertain')
243
+ except Exception:
244
+ raise SessionError('The prior check may still be running; cleanup was not confirmed and no check was replayed') from None
245
+ self._settle(job,{'status':'failed','reason':'supervisor_restart','artifactSha256':row['artifact_sha256'],
246
+ 'output':'Prior container cleanup is confirmed. Request a new check explicitly; no work was replayed.'})
247
+ return self.get(scope,session,job)
248
+
249
+ async def close(self):
250
+ self.closed=True
251
+ for cancellation in self.cancellations.values():cancellation.set()
252
+ await asyncio.gather(*list(self.tasks.values()),return_exceptions=True)
@@ -0,0 +1,48 @@
1
+ """Operator-owned local executor registrations, never request-selected endpoints.
2
+
3
+ Definitions are snapshots. Missing sockets/policies can become available later;
4
+ instantiation never pulls images, changes contexts or discovers another executor.
5
+ """
6
+ from dataclasses import dataclass
7
+ import json
8
+ from pathlib import Path
9
+ import re
10
+ from .local_validation import DockerValidationWorker
11
+
12
+
13
+ def worker_id(value):
14
+ if type(value) is not str or not re.fullmatch(r'[a-z][a-z0-9_-]{2,79}',value):
15
+ raise ValueError('Use an explicit operator worker ID')
16
+ return value
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class WorkerRegistration:
21
+ endpoint: str
22
+ profiles: bytes
23
+
24
+ def create(self):
25
+ return DockerValidationWorker(self.endpoint,isolation_profiles=json.loads(self.profiles))
26
+
27
+
28
+ def registered_workers(entries):
29
+ if type(entries) is not dict or len(entries)>16:
30
+ raise ValueError('Register a bounded operator worker mapping')
31
+ result={}
32
+ for name,entry in entries.items():
33
+ worker_id(name)
34
+ if type(entry) is not dict or not {'endpoint'}<=set(entry)<={'endpoint','isolationProfiles'}:
35
+ raise ValueError('Unrecognized operator worker registration')
36
+ endpoint=entry['endpoint']
37
+ if type(endpoint) is not str or len(endpoint)>1024 or '\0' in endpoint or not endpoint.startswith('unix:///') or not Path(endpoint[7:]).is_absolute():
38
+ raise ValueError('Register an explicit local Docker Unix socket')
39
+ profiles=entry.get('isolationProfiles',{})
40
+ if type(profiles) is not dict or set(profiles)-set(DockerValidationWorker.REVIEWED_PROFILES):
41
+ raise ValueError('Register reviewed worker-specific isolation profiles only')
42
+ for profile,pin in profiles.items():
43
+ if (type(pin) is not dict or set(pin)!={'path','sha256'} or
44
+ pin['sha256']!=DockerValidationWorker.REVIEWED_PROFILES[profile] or
45
+ type(pin['path']) is not str or not Path(pin['path']).is_absolute()):
46
+ raise ValueError('Use exact reviewed isolation policy references')
47
+ result[name]=WorkerRegistration(endpoint,json.dumps(profiles,sort_keys=True).encode())
48
+ return result