@atmem/architect 0.0.0-stage → 0.2.0

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 (512) hide show
  1. package/CONSTITUTION.md +144 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +6 -0
  4. package/README.md +31 -2
  5. package/agent-skills/discovery/SKILL.md +48 -0
  6. package/agent-skills/discovery/topics.json +139 -0
  7. package/agent-skills/generation-capabilities.json +760 -0
  8. package/agent-skills/service-lifecycle.json +21 -0
  9. package/agent-skills/specialists/architecture/SKILL.md +15 -0
  10. package/agent-skills/specialists/aws/SKILL.md +17 -0
  11. package/agent-skills/specialists/azure/SKILL.md +7 -0
  12. package/agent-skills/specialists/composition/SKILL.md +17 -0
  13. package/agent-skills/specialists/devops/SKILL.md +10 -0
  14. package/agent-skills/specialists/finops/SKILL.md +7 -0
  15. package/agent-skills/specialists/gcp/SKILL.md +7 -0
  16. package/agent-skills/specialists/ibm/SKILL.md +7 -0
  17. package/agent-skills/specialists/manifest.json +13 -0
  18. package/agent-skills/specialists/pulumi/SKILL.md +7 -0
  19. package/agent-skills/specialists/security/SKILL.md +7 -0
  20. package/agent-skills/specialists/terraform/SKILL.md +14 -0
  21. package/agent-skills/upstream/aws/LICENSE +175 -0
  22. package/agent-skills/upstream/aws/SKILL.md +125 -0
  23. package/agent-skills/upstream/azure/LICENSE +21 -0
  24. package/agent-skills/upstream/azure/SKILL.md +387 -0
  25. package/agent-skills/upstream/gcp/LICENSE +202 -0
  26. package/agent-skills/upstream/gcp/SKILL.md +159 -0
  27. package/agent-skills/upstream/manifest.json +57 -0
  28. package/agent-skills/upstream/pulumi/LICENSE +201 -0
  29. package/agent-skills/upstream/pulumi/SKILL.md +501 -0
  30. package/agent-skills/upstream/terraform/LICENSE +373 -0
  31. package/agent-skills/upstream/terraform/SKILL.md +316 -0
  32. package/agent-skills/workflows/workflows.json +601 -0
  33. package/cli/architect.mjs +3 -0
  34. package/cli/runtime.mjs +115 -0
  35. package/dist/assets/html2canvas.esm-QH1iLAAe.js +22 -0
  36. package/dist/assets/index-BTLHaa3J.css +1 -0
  37. package/dist/assets/index-CQ2C1gKF.js +21338 -0
  38. package/dist/assets/index.es-DTyqIdaO.js +18 -0
  39. package/dist/assets/purify.es-CAi2OJFm.js +3 -0
  40. package/dist/assets/visual-export-Ox0j5xj5.js +173 -0
  41. package/dist/favicon.svg +2 -0
  42. package/dist/fonts/DM-Sans-OFL.txt +93 -0
  43. package/dist/fonts/Manrope-OFL.txt +93 -0
  44. package/dist/fonts/NotoSans-Regular.ttf +0 -0
  45. package/dist/fonts/OFL.txt +94 -0
  46. package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
  47. package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
  48. package/dist/index.html +4 -0
  49. package/dist/licenses/atmem-APACHE-2.0.txt +202 -0
  50. package/dist/licenses/aws-architect-LICENSE.txt +17 -0
  51. package/dist/licenses/aws-mcp-LICENSE.txt +175 -0
  52. package/dist/licenses/aws-mcp-NOTICE.txt +1 -0
  53. package/dist/licenses/cloud-emulation-notices.txt +36619 -0
  54. package/dist/licenses/dependency-notices.txt +6379 -0
  55. package/dist/licenses/emulation-notices.txt +717 -0
  56. package/dist/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  57. package/dist/licenses/memory-dependency-notices.txt +3319 -0
  58. package/dist/licenses/openarchflow-LICENSE.txt +21 -0
  59. package/dist/licenses/python-dependency-notices.txt +11951 -0
  60. package/docs/upstream-lock.json +26 -0
  61. package/knowledge/engineering-practices.json +536 -0
  62. package/package.json +30 -4
  63. package/packaging/uv-release-lock.json +54 -0
  64. package/public/licenses/atmem-APACHE-2.0.txt +202 -0
  65. package/public/licenses/aws-architect-LICENSE.txt +17 -0
  66. package/public/licenses/aws-mcp-LICENSE.txt +175 -0
  67. package/public/licenses/aws-mcp-NOTICE.txt +1 -0
  68. package/public/licenses/cloud-emulation-notices.txt +36619 -0
  69. package/public/licenses/dependency-notices.txt +6379 -0
  70. package/public/licenses/emulation-notices.txt +717 -0
  71. package/public/licenses/github-copilot-sdk-LICENSE.txt +21 -0
  72. package/public/licenses/memory-dependency-notices.txt +3319 -0
  73. package/public/licenses/openarchflow-LICENSE.txt +21 -0
  74. package/public/licenses/python-dependency-notices.txt +11951 -0
  75. package/scripts/terraform-render.mjs +8 -0
  76. package/server/__init__.py +0 -0
  77. package/server/abstraction.py +28 -0
  78. package/server/agent_runtime.py +153 -0
  79. package/server/app.py +257 -0
  80. package/server/architect.py +112 -0
  81. package/server/architecture_activity.py +67 -0
  82. package/server/attachments.py +101 -0
  83. package/server/cloud-emulation-requirements.txt +29 -0
  84. package/server/codex_app_server.py +219 -0
  85. package/server/codex_engineering_backend.py +266 -0
  86. package/server/codex_worker_policy.py +193 -0
  87. package/server/contracts.py +315 -0
  88. package/server/copilot_worker.py +16 -0
  89. package/server/dependency_mirror.py +54 -0
  90. package/server/design_patch.py +43 -0
  91. package/server/emulation-requirements.txt +8 -0
  92. package/server/emulation_adapters.py +20 -0
  93. package/server/emulation_routes.py +98 -0
  94. package/server/emulation_worker.py +351 -0
  95. package/server/engineering_artifacts.py +221 -0
  96. package/server/engineering_assets/application-runtime.json +4372 -0
  97. package/server/engineering_assets/architecture_work.schema.json +79 -0
  98. package/server/engineering_assets/materialize_runtime.py +62 -0
  99. package/server/engineering_assets/prepare_tools.py +96 -0
  100. package/server/engineering_assets/sql_validation.py +59 -0
  101. package/server/engineering_contexts.py +120 -0
  102. package/server/engineering_delivery.py +210 -0
  103. package/server/engineering_finalization.py +210 -0
  104. package/server/engineering_handoff.py +172 -0
  105. package/server/engineering_jobs.py +206 -0
  106. package/server/engineering_knowledge.py +75 -0
  107. package/server/engineering_reconciliation.py +159 -0
  108. package/server/engineering_routes.py +483 -0
  109. package/server/engineering_sessions.py +273 -0
  110. package/server/engineering_tools.py +166 -0
  111. package/server/generation_lint.py +18 -0
  112. package/server/local_providers.py +185 -0
  113. package/server/local_validation.py +236 -0
  114. package/server/memory-requirements.lock +181 -0
  115. package/server/memory-requirements.txt +6 -0
  116. package/server/memory_context.py +58 -0
  117. package/server/memory_routes.py +141 -0
  118. package/server/memory_service.py +306 -0
  119. package/server/memory_worker.py +129 -0
  120. package/server/openai_voice.py +80 -0
  121. package/server/orca_handoff.py +90 -0
  122. package/server/packaged_app.py +9 -0
  123. package/server/pricing.py +190 -0
  124. package/server/process_control_observation.py +31 -0
  125. package/server/prompts.py +136 -0
  126. package/server/public_faq_emulation_worker.py +44 -0
  127. package/server/requirements.lock +1618 -0
  128. package/server/requirements.txt +68 -0
  129. package/server/runtime_dependency_locks.py +27 -0
  130. package/server/runtime_evidence.py +93 -0
  131. package/server/settings.py +14 -0
  132. package/server/skills.py +103 -0
  133. package/server/storage_emulation_worker.py +160 -0
  134. package/server/structured_emulation_worker.py +48 -0
  135. package/server/terraform_routes.py +118 -0
  136. package/server/upstream/__init__.py +0 -0
  137. package/server/upstream/agent/__init__.py +1 -0
  138. package/server/upstream/agent/aws_architect.py +600 -0
  139. package/server/upstream/agent/config/__init__.py +1 -0
  140. package/server/upstream/agent/config/agent_config.py +82 -0
  141. package/server/upstream/agent/config/prompts.py +138 -0
  142. package/server/upstream/agent/rate_limiter.py +62 -0
  143. package/server/upstream/utils/__init__.py +1 -0
  144. package/server/upstream/utils/file_writer.py +43 -0
  145. package/server/validation_applicability.py +85 -0
  146. package/server/validation_jobs.py +252 -0
  147. package/server/validation_workers.py +48 -0
  148. package/server/voice_routes.py +91 -0
  149. package/server/voice_worker.py +26 -0
  150. package/server/windows_snapshot.py +119 -0
  151. package/specs/028-convergence-evaluation/evidence/20261110-ibm-invoice-native/registry-structured/qualification.json +72 -0
  152. package/specs/028-convergence-evaluation/evidence/20261110-invoice-runtime/durable-current/receipt.json +61 -0
  153. package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json +22 -0
  154. package/src/ArchitectureActivity.jsx +54 -0
  155. package/src/ArchitectureWorkPanel.jsx +39 -0
  156. package/src/ArtifactChecks.jsx +49 -0
  157. package/src/BlockRequirements.jsx +13 -0
  158. package/src/BrainActivity.jsx +11 -0
  159. package/src/ChatMessage.jsx +29 -0
  160. package/src/ChatResizeHandle.jsx +6 -0
  161. package/src/CodePreview.jsx +8 -0
  162. package/src/ComponentReview.jsx +31 -0
  163. package/src/DeliveryViews.jsx +59 -0
  164. package/src/EmulationPanel.jsx +44 -0
  165. package/src/EngagementViews.jsx +387 -0
  166. package/src/EngineeringPanel.jsx +151 -0
  167. package/src/FileTree.jsx +7 -0
  168. package/src/FinalChecklist.jsx +15 -0
  169. package/src/HelpNote.jsx +3 -0
  170. package/src/ImplementationDelivery.jsx +91 -0
  171. package/src/JourneyViews.jsx +403 -0
  172. package/src/LocationChoices.jsx +12 -0
  173. package/src/MemoryPanel.jsx +58 -0
  174. package/src/OpenAIVoicePanel.jsx +66 -0
  175. package/src/OutputsView.jsx +71 -0
  176. package/src/ProjectChecks.jsx +44 -0
  177. package/src/TerraformView.jsx +57 -0
  178. package/src/WorkbenchDialogs.jsx +532 -0
  179. package/src/activity-presentation.mjs +28 -0
  180. package/src/ai-qualification-scenarios.mjs +31 -0
  181. package/src/approval-application-files.mjs +32 -0
  182. package/src/approval-applications.mjs +82 -0
  183. package/src/approval-spec-kit.mjs +30 -0
  184. package/src/architecture-activity.css +28 -0
  185. package/src/architecture-activity.mjs +63 -0
  186. package/src/architecture-work.mjs +176 -0
  187. package/src/artifact-work.mjs +103 -0
  188. package/src/async-documents.mjs +191 -0
  189. package/src/atflow.css +1140 -0
  190. package/src/atforma.css +748 -0
  191. package/src/atmem-tokens.css +79 -0
  192. package/src/aws-preflight.mjs +60 -0
  193. package/src/aws-public-faq.mjs +102 -0
  194. package/src/aws-validation-scenarios.mjs +10 -0
  195. package/src/aws-validation.mjs +48 -0
  196. package/src/azure-plan-mocks.mjs +25 -0
  197. package/src/azure-structured.mjs +133 -0
  198. package/src/bedrock-summary.mjs +152 -0
  199. package/src/bounded-rag.mjs +60 -0
  200. package/src/brand.css +9 -0
  201. package/src/canvas-view.mjs +28 -0
  202. package/src/capability-composition.mjs +44 -0
  203. package/src/chat-attachments.mjs +13 -0
  204. package/src/cloud-provider-locks.mjs +9 -0
  205. package/src/cloud-storage-scenarios.mjs +2 -0
  206. package/src/component-review.mjs +55 -0
  207. package/src/composition-spec-kit.mjs +30 -0
  208. package/src/consultation-context.mjs +15 -0
  209. package/src/consultation.mjs +52 -0
  210. package/src/container-contracts.mjs +5 -0
  211. package/src/container-inspection.mjs +75 -0
  212. package/src/container-runtime.mjs +30 -0
  213. package/src/container-security-inspection.mjs +49 -0
  214. package/src/container-terraform.mjs +109 -0
  215. package/src/conversation.mjs +18 -0
  216. package/src/core.mjs +863 -0
  217. package/src/cross-cloud-storage.mjs +100 -0
  218. package/src/delivery-capabilities.mjs +25 -0
  219. package/src/delivery.mjs +58 -0
  220. package/src/deployment-ownership.mjs +10 -0
  221. package/src/deployment-region.mjs +11 -0
  222. package/src/derive.mjs +31 -0
  223. package/src/design-build-flow.mjs +10 -0
  224. package/src/diagram-attention.mjs +24 -0
  225. package/src/discovery.mjs +359 -0
  226. package/src/document.mjs +170 -0
  227. package/src/emulation-feedback.mjs +61 -0
  228. package/src/emulation-guidance.mjs +37 -0
  229. package/src/engagement.mjs +274 -0
  230. package/src/engineering-client.mjs +73 -0
  231. package/src/engineering-defaults.mjs +17 -0
  232. package/src/engineering.css +31 -0
  233. package/src/enterprise-application.mjs +76 -0
  234. package/src/enterprise-aws-host-infrastructure.mjs +62 -0
  235. package/src/enterprise-aws-host-tests.mjs +15 -0
  236. package/src/enterprise-aws-infrastructure-tests.mjs +38 -0
  237. package/src/enterprise-aws-infrastructure.mjs +138 -0
  238. package/src/enterprise-google-infrastructure.mjs +84 -0
  239. package/src/enterprise-google-tests.mjs +25 -0
  240. package/src/estimate.mjs +190 -0
  241. package/src/existing-references.mjs +18 -0
  242. package/src/external-identities.mjs +17 -0
  243. package/src/faq-lambda-build.mjs +28 -0
  244. package/src/final-package.mjs +34 -0
  245. package/src/gcp-structured.mjs +104 -0
  246. package/src/generation-provider.mjs +7 -0
  247. package/src/generation-quality.mjs +69 -0
  248. package/src/handoff.mjs +141 -0
  249. package/src/ibm-registry.mjs +12 -0
  250. package/src/ibm-structured.mjs +103 -0
  251. package/src/identifiers.mjs +15 -0
  252. package/src/implementation-map.mjs +14 -0
  253. package/src/implementation-outcome.mjs +8 -0
  254. package/src/incomplete-terraform.mjs +9 -0
  255. package/src/integrations.ts +137 -0
  256. package/src/interface-contracts.mjs +30 -0
  257. package/src/invoice-application.mjs +66 -0
  258. package/src/invoice-aws-operations.mjs +136 -0
  259. package/src/invoice-aws.mjs +143 -0
  260. package/src/invoice-azure-operations.mjs +147 -0
  261. package/src/invoice-azure.mjs +134 -0
  262. package/src/invoice-builder.mjs +35 -0
  263. package/src/invoice-dependencies.mjs +43 -0
  264. package/src/invoice-gcp-operations.mjs +178 -0
  265. package/src/invoice-gcp.mjs +104 -0
  266. package/src/invoice-ibm-operations.mjs +278 -0
  267. package/src/invoice-ibm.mjs +142 -0
  268. package/src/invoice-operations.mjs +143 -0
  269. package/src/invoice-plan.mjs +45 -0
  270. package/src/invoice-region.mjs +6 -0
  271. package/src/invoice-spec-kit.mjs +61 -0
  272. package/src/invoice-state.mjs +7 -0
  273. package/src/invoice-terraform.mjs +29 -0
  274. package/src/invoice-tests.mjs +122 -0
  275. package/src/journey-workspace.css +106 -0
  276. package/src/journey.mjs +97 -0
  277. package/src/levels.mjs +145 -0
  278. package/src/local-agent.mjs +184 -0
  279. package/src/main.jsx +2481 -0
  280. package/src/model-policy-preflight.mjs +34 -0
  281. package/src/openai-voice.mjs +102 -0
  282. package/src/output-bundle.mjs +13 -0
  283. package/src/ownership-inspection.mjs +28 -0
  284. package/src/pack.mjs +201 -0
  285. package/src/pricing.mjs +85 -0
  286. package/src/production-state.mjs +8 -0
  287. package/src/project-copy.mjs +10 -0
  288. package/src/project-file.mjs +160 -0
  289. package/src/project-links.mjs +3 -0
  290. package/src/protected-state.mjs +43 -0
  291. package/src/public-faq-builder.mjs +19 -0
  292. package/src/public-faq-clouds.mjs +251 -0
  293. package/src/public-faq.mjs +122 -0
  294. package/src/pulumi.mjs +123 -0
  295. package/src/python-container.mjs +25 -0
  296. package/src/python-runtime.mjs +50 -0
  297. package/src/rag-handler.mjs +43 -0
  298. package/src/rag-web-assets.mjs +52 -0
  299. package/src/rag-web.mjs +68 -0
  300. package/src/records.mjs +177 -0
  301. package/src/resources.mjs +163 -0
  302. package/src/review.mjs +252 -0
  303. package/src/runtime/EnterpriseDocument.java +89 -0
  304. package/src/runtime/approved_http_destination.py +72 -0
  305. package/src/runtime/aws-lambda-qualification-lock.json +7 -0
  306. package/src/runtime/aws-python-lock.json +82 -0
  307. package/src/runtime/aws-web-python-lock.json +887 -0
  308. package/src/runtime/aws_json_model.py +42 -0
  309. package/src/runtime/azure-python-lock.json +863 -0
  310. package/src/runtime/azure-sources.json +8 -0
  311. package/src/runtime/azure-test-lock.json +23 -0
  312. package/src/runtime/azure_acceptance.py +192 -0
  313. package/src/runtime/azure_structured.py +153 -0
  314. package/src/runtime/bounded_rag.py +126 -0
  315. package/src/runtime/catalog_admin.py +70 -0
  316. package/src/runtime/cloud-sql-proxy-lock.json +8 -0
  317. package/src/runtime/cloud-sql-proxy-security-review.json +30 -0
  318. package/src/runtime/connector_cli.py +50 -0
  319. package/src/runtime/connector_sync.py +70 -0
  320. package/src/runtime/durable-python-lock.json +247 -0
  321. package/src/runtime/durable_workflow.py +325 -0
  322. package/src/runtime/enterprise-application-manifest.json +110 -0
  323. package/src/runtime/enterprise-application-sources.json +266 -0
  324. package/src/runtime/enterprise-auth-python-lock.json +592 -0
  325. package/src/runtime/enterprise-aws-host-bootstrap-source.json +1 -0
  326. package/src/runtime/enterprise-aws-host-probe-source.json +1 -0
  327. package/src/runtime/enterprise-aws-task-template.json +235 -0
  328. package/src/runtime/enterprise-document-lock.json +18 -0
  329. package/src/runtime/enterprise-document.Dockerfile +15 -0
  330. package/src/runtime/enterprise-runtime-aws-python-lock.json +1115 -0
  331. package/src/runtime/enterprise-runtime-azure-python-lock.json +1106 -0
  332. package/src/runtime/enterprise-runtime-gcp-python-lock.json +1060 -0
  333. package/src/runtime/enterprise-runtime-ibm-python-lock.json +1096 -0
  334. package/src/runtime/enterprise-runtime-python-lock.json +1058 -0
  335. package/src/runtime/enterprise-runtime.Dockerfile +15 -0
  336. package/src/runtime/enterprise-web-app.js +1 -0
  337. package/src/runtime/enterprise-web-entry.js +105 -0
  338. package/src/runtime/enterprise-web-lock.json +29 -0
  339. package/src/runtime/enterprise-web-notices.txt +229 -0
  340. package/src/runtime/enterprise-web.css +4 -0
  341. package/src/runtime/enterprise-web.html +8 -0
  342. package/src/runtime/enterprise_audit.py +91 -0
  343. package/src/runtime/enterprise_audit_schema.sql +25 -0
  344. package/src/runtime/enterprise_auth_schema.sql +67 -0
  345. package/src/runtime/enterprise_auth_store.py +241 -0
  346. package/src/runtime/enterprise_aws_host_bootstrap.py +120 -0
  347. package/src/runtime/enterprise_aws_host_probe.py +105 -0
  348. package/src/runtime/enterprise_aws_hosts.py +136 -0
  349. package/src/runtime/enterprise_aws_jobs.py +300 -0
  350. package/src/runtime/enterprise_aws_objects.py +93 -0
  351. package/src/runtime/enterprise_aws_transfer.py +83 -0
  352. package/src/runtime/enterprise_azure_batch_api.py +128 -0
  353. package/src/runtime/enterprise_azure_host.py +599 -0
  354. package/src/runtime/enterprise_azure_jobs.py +294 -0
  355. package/src/runtime/enterprise_azure_objects.py +234 -0
  356. package/src/runtime/enterprise_azure_pool.py +161 -0
  357. package/src/runtime/enterprise_azure_transfer.py +122 -0
  358. package/src/runtime/enterprise_configuration.py +136 -0
  359. package/src/runtime/enterprise_document.py +116 -0
  360. package/src/runtime/enterprise_document_cli.py +32 -0
  361. package/src/runtime/enterprise_document_contract.py +54 -0
  362. package/src/runtime/enterprise_document_job.py +109 -0
  363. package/src/runtime/enterprise_document_jobs.py +122 -0
  364. package/src/runtime/enterprise_document_jobs_schema.sql +23 -0
  365. package/src/runtime/enterprise_extraction_cache.py +186 -0
  366. package/src/runtime/enterprise_extraction_schema.sql +17 -0
  367. package/src/runtime/enterprise_google_jobs.py +275 -0
  368. package/src/runtime/enterprise_google_transfer.py +85 -0
  369. package/src/runtime/enterprise_http.py +212 -0
  370. package/src/runtime/enterprise_identity.py +52 -0
  371. package/src/runtime/enterprise_knowledge.py +152 -0
  372. package/src/runtime/enterprise_models.py +94 -0
  373. package/src/runtime/enterprise_native.py +181 -0
  374. package/src/runtime/enterprise_oauth.py +132 -0
  375. package/src/runtime/enterprise_operator.py +160 -0
  376. package/src/runtime/enterprise_parser_service.py +136 -0
  377. package/src/runtime/enterprise_parser_transport.py +68 -0
  378. package/src/runtime/enterprise_queries.py +255 -0
  379. package/src/runtime/enterprise_queries_schema.sql +27 -0
  380. package/src/runtime/enterprise_query_service.py +111 -0
  381. package/src/runtime/enterprise_secrets.py +110 -0
  382. package/src/runtime/enterprise_sessions.py +95 -0
  383. package/src/runtime/enterprise_sources.py +260 -0
  384. package/src/runtime/enterprise_web.py +39 -0
  385. package/src/runtime/enterprise_worker.py +68 -0
  386. package/src/runtime/export_contract_acceptance.py +18 -0
  387. package/src/runtime/faq-output-contract.json +40 -0
  388. package/src/runtime/faq-web-app.js +41 -0
  389. package/src/runtime/faq-web.css +1 -0
  390. package/src/runtime/faq-web.html +6 -0
  391. package/src/runtime/gcp-sources.json +9 -0
  392. package/src/runtime/gcp_acceptance.py +110 -0
  393. package/src/runtime/gcp_structured.py +150 -0
  394. package/src/runtime/http_acceptance.py +39 -0
  395. package/src/runtime/iap-web-app.js +36 -0
  396. package/src/runtime/iap-web-source.json +1 -0
  397. package/src/runtime/ibm-python-lock.json +856 -0
  398. package/src/runtime/ibm-sources.json +9 -0
  399. package/src/runtime/ibm_acceptance.py +133 -0
  400. package/src/runtime/ibm_structured.py +113 -0
  401. package/src/runtime/invoice-azapi-provider-lock.json +7 -0
  402. package/src/runtime/invoice-ibm-provider-lock.json +7 -0
  403. package/src/runtime/invoice-parser-lock.json +1199 -0
  404. package/src/runtime/invoice-parser-python-lock.json +56 -0
  405. package/src/runtime/invoice-parser.Dockerfile +190 -0
  406. package/src/runtime/invoice-sources.json +58 -0
  407. package/src/runtime/invoice-test-sources.json +24 -0
  408. package/src/runtime/invoice-web.css +2 -0
  409. package/src/runtime/invoice-web.html +12 -0
  410. package/src/runtime/invoice-web.js +112 -0
  411. package/src/runtime/invoice_configuration.py +17 -0
  412. package/src/runtime/invoice_document.py +95 -0
  413. package/src/runtime/invoice_extraction.py +96 -0
  414. package/src/runtime/invoice_http.py +129 -0
  415. package/src/runtime/invoice_identity.py +5 -0
  416. package/src/runtime/invoice_maintenance.py +40 -0
  417. package/src/runtime/invoice_native.py +77 -0
  418. package/src/runtime/invoice_object_store.py +153 -0
  419. package/src/runtime/invoice_operations.py +108 -0
  420. package/src/runtime/invoice_operator.py +79 -0
  421. package/src/runtime/invoice_operator_core.py +39 -0
  422. package/src/runtime/invoice_operator_job.py +147 -0
  423. package/src/runtime/invoice_parser_cli.py +17 -0
  424. package/src/runtime/invoice_parser_identity.py +39 -0
  425. package/src/runtime/invoice_parser_service.py +89 -0
  426. package/src/runtime/invoice_parser_transport.py +89 -0
  427. package/src/runtime/invoice_processing.py +24 -0
  428. package/src/runtime/invoice_retention.py +16 -0
  429. package/src/runtime/invoice_runtime_secrets.py +43 -0
  430. package/src/runtime/invoice_stage.py +80 -0
  431. package/src/runtime/invoice_web.py +39 -0
  432. package/src/runtime/invoice_worker.py +50 -0
  433. package/src/runtime/lambda_faq.py +5 -0
  434. package/src/runtime/parser-requirements.lock +4 -0
  435. package/src/runtime/policy_review.py +18 -0
  436. package/src/runtime/postgres-qualification-lock.json +21 -0
  437. package/src/runtime/public-faq-sources.json +22 -0
  438. package/src/runtime/public_catalog_admin.py +122 -0
  439. package/src/runtime/public_catalog_store.py +125 -0
  440. package/src/runtime/public_faq.py +144 -0
  441. package/src/runtime/public_faq_app.py +49 -0
  442. package/src/runtime/python-container-lock.json +18 -0
  443. package/src/runtime/rag-sources.json +10 -0
  444. package/src/runtime/rag_acceptance.py +60 -0
  445. package/src/runtime/rag_aws_adapter.py +95 -0
  446. package/src/runtime/rds-ca-source.json +9 -0
  447. package/src/runtime/rds-global-ca.pem +2888 -0
  448. package/src/runtime/state-contract-check-source.json +4 -0
  449. package/src/runtime/state_contract_check.py +338 -0
  450. package/src/runtime/structured-source.json +1 -0
  451. package/src/runtime/structured-web-app.js +71 -0
  452. package/src/runtime/structured-web-source.json +1 -0
  453. package/src/runtime/structured_http.py +105 -0
  454. package/src/runtime/structured_output.py +48 -0
  455. package/src/runtime/web-python-lock.json +802 -0
  456. package/src/runtime/web_user_admin.py +44 -0
  457. package/src/runtime/workflow_application.py +62 -0
  458. package/src/runtime/workflow_bindings.py +128 -0
  459. package/src/runtime/workflow_configuration.py +40 -0
  460. package/src/runtime/workflow_connection.py +105 -0
  461. package/src/runtime/workflow_contract.py +54 -0
  462. package/src/runtime/workflow_database.py +94 -0
  463. package/src/runtime/workflow_errors.py +6 -0
  464. package/src/runtime/workflow_http.py +178 -0
  465. package/src/runtime/workflow_identity.py +69 -0
  466. package/src/runtime/workflow_payload.py +118 -0
  467. package/src/runtime/workflow_process_stage.py +88 -0
  468. package/src/runtime/workflow_profile.py +91 -0
  469. package/src/runtime/workflow_review.py +106 -0
  470. package/src/runtime/workflow_role_bootstrap.py +104 -0
  471. package/src/runtime/workflow_schema.sql +72 -0
  472. package/src/runtime/workflow_worker.py +142 -0
  473. package/src/runtime-settings.mjs +15 -0
  474. package/src/s3-access.mjs +14 -0
  475. package/src/source-contracts.mjs +17 -0
  476. package/src/spec-kit.mjs +186 -0
  477. package/src/state-custody.mjs +32 -0
  478. package/src/state-inspection.mjs +45 -0
  479. package/src/state-spec-kit.mjs +13 -0
  480. package/src/storage-tests.mjs +25 -0
  481. package/src/structured-api.mjs +133 -0
  482. package/src/structured-contract.mjs +19 -0
  483. package/src/structured-operation-policy.mjs +2 -0
  484. package/src/structured-web.mjs +17 -0
  485. package/src/style.css +1 -0
  486. package/src/system-description.mjs +26 -0
  487. package/src/terraform-admission.mjs +66 -0
  488. package/src/terraform-composition.mjs +83 -0
  489. package/src/terraform-expressions.mjs +46 -0
  490. package/src/terraform-validation-coverage.mjs +11 -0
  491. package/src/terraform.mjs +128 -0
  492. package/src/text-statistics.mjs +51 -0
  493. package/src/upstream/openarchflow/format-payload.ts +26 -0
  494. package/src/upstream/openarchflow/import/mermaid.ts +205 -0
  495. package/src/upstream/openarchflow/import/sql-ddl.ts +109 -0
  496. package/src/upstream/openarchflow/layout.ts +54 -0
  497. package/src/upstream/openarchflow/providers/aws.ts +196 -0
  498. package/src/upstream/openarchflow/providers/azure.ts +126 -0
  499. package/src/upstream/openarchflow/providers/cloudnative.ts +71 -0
  500. package/src/upstream/openarchflow/providers/generic.ts +227 -0
  501. package/src/upstream/openarchflow/providers/integration.ts +22 -0
  502. package/src/upstream/openarchflow/providers/types.ts +2 -0
  503. package/src/upstream/openarchflow/templates.ts +937 -0
  504. package/src/upstream-catalog.mjs +10 -0
  505. package/src/useChatScroll.jsx +37 -0
  506. package/src/useEmulation.jsx +36 -0
  507. package/src/useEngineeringStatus.mjs +17 -0
  508. package/src/validation-receipt.mjs +10 -0
  509. package/src/visual-export.mjs +92 -0
  510. package/src/voice-conversation.mjs +117 -0
  511. package/src/work-intake.mjs +24 -0
  512. package/src/workflow-runtime-inventory.mjs +3 -0
@@ -0,0 +1,45 @@
1
+ import {resourceAddress} from './identifiers.mjs';
2
+ import{existingDeployment}from'./deployment-ownership.mjs';
3
+ import{existingReference}from'./existing-references.mjs';
4
+ import{validInvoiceRegion,invoicePartitionGap}from'./invoice-region.mjs';
5
+
6
+ export const INVOICE_SERVICES={aws:'Amazon ECS',azure:'Azure Container Apps',gcp:'Google Cloud Run',ibm:'IBM Code Engine'};
7
+ export const hasInvoice=project=>project.nodes.some(node=>node.data.kind!=='note'&&node.data.implementation==='invoice-workflow');
8
+ const address=resourceAddress;
9
+ const resourceTypes={aws:['aws_vpc','aws_db_instance','aws_s3_bucket','aws_ecs_cluster'],azure:['azurerm_resource_group','azurerm_postgresql_flexible_server','azurerm_storage_account','azurerm_container_app_environment'],gcp:['google_compute_network','google_sql_database_instance','google_storage_bucket','google_artifact_registry_repository'],ibm:['ibm_code_engine_project','ibm_database','ibm_cos_bucket','ibm_appid_application']};
10
+
11
+ // One composed delivery unit owns its API, worker, isolated parser, private SQL,
12
+ // original-document store, identities and operating tasks. Extra drawn systems
13
+ // remain in the plan with explicit gaps; they are never silently absorbed/deleted.
14
+ export function invoiceResourcePlan(project){
15
+ const nodes=project.nodes.filter(node=>node.data.kind!=='note'),gapDetails=[];
16
+ const add=(id,message,links={})=>gapDetails.push({id,message,...links});
17
+ const candidates=nodes.filter(node=>node.data.implementation==='invoice-workflow'&&INVOICE_SERVICES[node.data.provider]===node.data.service&&!existingDeployment(node)&&node.data.origin!=='existing');
18
+ const selected=candidates.length===1?candidates[0]:null;
19
+ if(!selected)add('invoice-composition-scope','Select one proposed invoice-workflow delivery unit on its exact supported provider/service. Multiple independent workflows require separate compositions.');
20
+ const browsers=nodes.filter(node=>existingDeployment(node)&&node.data.provider==='tools'&&node.data.binding==='web-browser');
21
+ const references=nodes.map(node=>existingReference(node)).filter(Boolean);
22
+ const browserEdges=selected?project.edges.filter(edge=>edge.target===selected.id&&edge.integration==='browser-https'&&browsers.some(node=>node.id===edge.source)):[];
23
+ const accountingEdges=selected?project.edges.filter(edge=>edge.source===selected.id&&edge.integration==='approved-accounting-api'&&references.some(ref=>ref.id===edge.target)):[];
24
+ if(selected){
25
+ if(!browserEdges.length)add('invoice-browser-contract','Connect the existing staff browser to the workflow with browser-https.',{componentIds:[selected.id]});
26
+ if(accountingEdges.length!==1)add('invoice-accounting-contract','Connect the workflow to exactly one explicitly existing accounting service with approved-accounting-api. Its endpoint, credential and normalized action/idempotency acceptance are destination inputs, not a replacement accounting system.',{componentIds:[selected.id]});
27
+ const config=selected.data.config||{};
28
+ if(config.region&&config.region!=='To be selected'&&!validInvoiceRegion(selected.data.provider,config.region))add('invoice-config-region',invoicePartitionGap(selected.data.provider,config.region)||'Preserve the selected placement and propose a canonical provider region within that accepted residency. Country names or expressions are not deployment-region identifiers; this is engineering work, not a request for the user to configure infrastructure.',{componentIds:[selected.id]});
29
+ for(const[key,expected]of Object.entries({maxPdfBytes:10000000,maxPdfPages:100,retentionDays:90}))if(config[key]!==undefined&&config[key]!==expected)add('invoice-config-'+key,'The invoice implementation supplies '+key+'='+expected+'; preserve the explicit '+config[key]+' requirement and implement that change before claiming coverage.',{componentIds:[selected.id]});
30
+ for(const key of ['outputContract','modelId','maxInputBytes','maxOutputTokens','memoryMb','containerMemoryBytes','functionTimeoutSeconds','concurrency','logRetentionDays'])if(config[key]!==undefined)add('invoice-config-'+key,'Explicit '+key+' is not mapped by this composed invoice contract; retain and implement that selection instead of substituting the recipe setting.',{componentIds:[selected.id]});
31
+ }
32
+ const generatedEdges=new Set([...browserEdges,...(accountingEdges.length===1?accountingEdges:[])].map(edge=>edge.id));
33
+ const rows=nodes.map(node=>{
34
+ const d=node.data,existing=existingDeployment(node),reference=references.find(ref=>ref.id===node.id),invoice=selected?.id===node.id;
35
+ const externalBrowser=existing&&d.provider==='tools'&&d.binding==='web-browser';
36
+ const row={id:node.id,address:address(node.id),label:d.label,provider:d.provider,service:d.service||d.label,sourceExisting:d.origin==='existing',existing,foundation:false,compute:false,reference:false,externalReference:externalBrowser,existingServiceReference:reference||null,invoice,implemented:invoice||externalBrowser||!!reference,resources:invoice?resourceTypes[d.provider]:[],region:d.config?.region||'To be selected',settings:{},dependencies:project.edges.filter(edge=>edge.target===node.id).map(edge=>edge.source),selection:'Explicit invoice composition or preserved existing reference',costDrivers:invoice?'API/worker/parser/operator compute, private database/backup/storage, NAT/private endpoints, identity, registry, model tokens, retained object versions, logging and notification delivery. Verify current regional rates and quotas; capacity limits are not spending caps.':'Existing system or actor; review its externally owned costs and access contract.',terraform:invoice?'Composed invoice API/worker/parser, durable SQL queue, private originals, review authorization, guarded accounting delivery and operating tasks generated; destination behavior remains unverified':reference?'Existing service reference — preserve without provisioning/import; actual connection acceptance required':externalBrowser?'External staff browser — authenticated workflow channel generated; no browser infrastructure to provision':'Additional required component is not implemented by this invoice composition'};
37
+ if(!row.implemented)add('resource-'+row.address,d.label+': '+row.terraform+'.',{componentIds:[node.id]});
38
+ return row;
39
+ });
40
+ const connections=project.edges.map(edge=>({id:edge.id,source:edge.source,target:edge.target,data:edge.label||'data',generated:generatedEdges.has(edge.id),status:generatedEdges.has(edge.id)?'Typed invoice contract/source generated; account, authorization and runtime acceptance required':'Additional required integration remains unimplemented'}));
41
+ for(const edge of connections)if(!edge.generated)add('connection-'+address(edge.id),'Implement the preserved integration '+edge.source+' → '+edge.target+'.',{edgeIds:[edge.id]});
42
+ const row=selected?rows.find(row=>row.id===selected.id):null;
43
+ const invoicePlan={entries:row?[{row,provider:row.provider,browserIds:browserEdges.map(edge=>edge.source),accountingId:accountingEdges.length===1?accountingEdges[0].target:null}]:[],componentIds:row?[row.id]:[],edgeIds:[...generatedEdges]};
44
+ return {revision:project.revision,rows,connections,invoicePlan,gaps:gapDetails.map(gap=>gap.message),gapDetails,accessPlan:{bindings:[],connections:[]},asyncPlan:{entries:[],pipelines:[],componentIds:[],edgeIds:[]},summaryPlan:{entries:[],modelIds:[]},ragPlan:{entries:[],componentIds:[]},sourceContractPlan:{sources:[],connections:[]},webPlan:{entries:[],componentIds:[]},structuredApiPlan:{entries:[]},publicFaqPlan:{entries:[],componentIds:[],editorIds:[],edgeIds:[]},azureStructuredPlan:{entries:[],componentIds:[]},gcpStructuredPlan:{entries:[],componentIds:[]},ibmStructuredPlan:{entries:[],componentIds:[]},scope:'Typed composed invoice implementation; extra required systems and flows remain visible. Source generation and local qualifications do not prove the destination deployment.',sources:[]};
45
+ }
@@ -0,0 +1,6 @@
1
+ import {PROVIDER_REGION_PATTERNS,validProviderRegion} from './deployment-region.mjs';
2
+ export const INVOICE_REGION_PATTERNS={...PROVIDER_REGION_PATTERNS,aws:'^[a-z]{2}-[a-z]+-[0-9]{1,2}$'};
3
+ // This domain adapter still has commercial ARN/registry/model contracts. Do not
4
+ // inherit supplied-image partition support without implementing the whole policy.
5
+ export const invoicePartitionGap=(provider,region)=>provider==='aws'&&/^(cn-|us-gov-)/.test(region||'')?'Preserve the requested AWS partition and region. This invoice adapter still has commercial-partition ARN, registry and model contracts; implement partition support without substituting another destination.':null;
6
+ export const validInvoiceRegion=(provider,region)=>validProviderRegion(provider,region)&&!invoicePartitionGap(provider,region);
@@ -0,0 +1,61 @@
1
+ const key=value=>Array.from(new TextEncoder().encode(value),v=>v.toString(16).padStart(2,'0')).join('');
2
+
3
+ export function applyInvoiceTasks(project,plan,emitted,tasks){
4
+ for(const entry of plan.invoicePlan?.entries||[])applyInvoiceUnitTasks(project,{...plan,invoicePlan:{...plan.invoicePlan,entries:[entry]}},emitted,tasks);
5
+ }
6
+ function applyInvoiceUnitTasks(project,plan,emitted,tasks){
7
+ if(!plan.invoicePlan?.entries.length)return;
8
+ const{row}=plan.invoicePlan.entries[0],directory='terraform/'+(row.modulePath?row.modulePath+'/':''),base=directory+'applications/'+row.address+'/',componentIds=[row.id],requirementIds=(project.needs||[]).filter(need=>need.links?.includes(row.id)).map(need=>need.id);
9
+ const task=id=>tasks.find(task=>task.id===id);
10
+ const setup=task('TASK-SETUP');const setupStep='Use the supplied Python 3.13 Linux/amd64 API/worker and isolated parser images. Read '+base+'BUILD.md and TESTING.md. Install the exact provider test-requirements.lock in a Linux Python environment or build Dockerfile.tests. Run tests/start-local-fixture.py only against an existing local Unix Docker socket, then tests/run.py with the owned loopback fixture. Keep SDK environments isolated. Do not ask the user to choose a port, command, queue or runtime already implemented here.';
11
+ if(row.modulePath)setup.steps.push(setupStep);else setup.steps[1]=setupStep;
12
+ const resource=task('TASK-RESOURCE-'+key(row.id));
13
+ resource.steps=[`Preserve this responsibility and linked requirements: ${project.nodes.find(node=>node.id===row.id)?.data.description||row.label}.`,
14
+ 'Inspect terraform/main.tf.json, invoice-contract.json and resource-schedule.json. This composition generates the API, worker, isolated PDF parser, private originals/SQL queue, native staff identities and separate operating tasks. Additional drawn scope remains visible and blocks incomplete exports.',
15
+ 'Read '+base+'invoice_http.py, invoice_identity.py, workflow_identity.py, workflow_configuration.py, invoice_processing.py, invoice_worker.py, approved_http_destination.py and workflow_schema.sql. Current SQL user/reviewer/supervisor admission is separate from valid native login.',
16
+ 'Run the portable tests and independent image/parser checks; retain exact source, dependency, image and tool hashes. Local fixture/model/identity protocols do not prove native cloud behavior or extraction quality.',
17
+ 'Keep API, worker, parser and operator credentials/permissions separate. Populate destination secret references outside Terraform/source; never give model/parser/public tools operator launch or SQL administrator authority.',
18
+ 'Follow the explicit foundation → immutable image publication → manual SQL/bootstrap/membership → operating schedule/alert acceptance → application release sequence. Cloud access, publication, apply and migrations each require existing authorization.',
19
+ 'Record the actual requirement-to-test outcomes, remaining destination/compatibility/security findings and approved owner decisions. No task is complete on generation alone.'];
20
+ resource.outputs=[base+'runtime/parser sources and locks','terraform/main.tf.json and native tests/invoice.tftest.hcl','Protected local acceptance receipts and exact image/security evidence'];
21
+ for(const edge of plan.connections.filter(edge=>edge.generated&&(edge.source===row.id||edge.target===row.id))){
22
+ for(const prefix of ['TASK-CONTRACT-','TASK-INTEGRATION-']){
23
+ const current=task(prefix+key(edge.id));if(!current)continue;
24
+ current.steps=[`Read the implemented ${project.edges.find(item=>item.id===edge.id)?.integration} contract in spec-kit/interfaces.json, retaining original component/edge IDs and requirements.`,
25
+ edge.target===row.id?'Inspect invoice_http.py, invoice_identity.py and workflow_identity.py: raw PDF upload, immutable server-owned storage references, live SQL membership, revision-bound review/approval and denied uploader approvals. Run the shipped HTTP/identity/browser tests.':'Inspect approved_http_destination.py and workflow_worker.py: existing accounting endpoint/scope/credential inputs, exact normalized-action-v1 request/receipt, approval digest, stable key, bounded TLS call and uncertain-outcome fencing. Run local TLS/worker/recovery tests; do not infer actual vendor API compatibility.',
26
+ 'Keep synthetic protocol fixtures separate from independently authorized destination acceptance. Preserve unsupported edge/contract requirements as generator work; never rename/remove them to obtain a pass.'];
27
+ }
28
+ }
29
+ const add=(id,title,dependsOn,steps,outputs,acceptance)=>tasks.push({id,phase:'Invoice delivery',title,status:'todo',dependsOn,steps,outputs,acceptance,componentIds,requirementIds});
30
+ const source='TASK-INVOICE-SOURCE-'+key(row.id),state='TASK-INVOICE-STATE-'+key(row.id),foundation='TASK-INVOICE-FOUNDATION-'+key(row.id),images='TASK-INVOICE-IMAGES-'+key(row.id),bootstrap='TASK-INVOICE-BOOTSTRAP-'+key(row.id),operations='TASK-INVOICE-OPERATIONS-'+key(row.id),release='TASK-INVOICE-APPLICATION-'+key(row.id);
31
+ add(source,'Qualify the emitted invoice package locally',['TASK-SETUP','TASK-SECURITY-DESIGN'],['Read '+base+'TESTING.md. Use the exact isolated provider test lock; run shipped tests on an owned loopback PostgreSQL fixture with nonce validation. Never use a client/cloud database.', 'From terraform/, run terraform init -backend=false, terraform validate and terraform test. Retain full native positive/negative-plan evidence; mocks do not inspect an account.', 'Build/test exact runtime, test and parser images from pinned bases/wheels/native packages. Test actual text/scanned PDF extraction, malformed/encrypted/oversize/page-limit behavior, extraction evidence validation, duplicate delivery/restart, review denial, approval edits, uncertain action recovery and expired-only cleanup.', 'Record dependency/security findings and source/image digests. Fix generator causes and regenerate, never hand-edit a single exported bundle.'],['Portable local suite receipt','Native schema/mock, image/parser, security and failure-path evidence'],['Checks target this complete emitted source/dependency set.','Failed, unavailable, stale or fixture-only results remain explicit.']);
32
+ add(state,'Verify protected state and environment custody',['TASK-SCOPE'],['Read terraform/STATE.md and backend.hcl.example. Production references its reviewed provider-specific protected state/lock backend, with no account/state deployment implicit.', 'Review actual state residency/custody, per-project/environment access, sensitive computed provider values, encryption and version recovery. Supply authentication only through the approved environment chain.', 'With explicit platform-access authorization, verify lock conflict/owner-safe unlock/recovery on an isolated test state. Do not migrate/adopt existing state or disable locking to bypass failure.'],['State owner/access/residency/recovery record','Protected reviewed backend configuration; never in source'],['Actual state protocol and ownership/locking/recovery are evidenced before account planning.']);
33
+ task('TASK-CLOUD-PLAN').dependsOn.push(source,state);
34
+ add(foundation,'Apply only the reviewed invoice foundation',['TASK-CLOUD-PLAN','TASK-COST'],['Obtain explicit foundation apply authorization for the exact current plan. Set applications_enabled=false, operations_enabled=false and maintenance_enabled=false.', 'Verify new owned regional database/private routing, original store/lifecycle, registry, native identity and secret-reference configuration. Preserve external accounting, existing organization routes/groups and state.', 'Retain actual resources/identities and rollback/deletion protections; native resource existence does not prove application/SQL/model behavior.'],['Authorized foundation receipt and exact resource inventory'],['Reviewed foundation is observed; no application or scheduled privileged work is prematurely enabled.']);
35
+ add(images,'Publish qualified immutable API/worker and parser images',[source,foundation],['Use the exact tested runtime/parser digests, registry namespace and supply-chain evidence. Obtain publication authorization; publish without mutable tags in runtime inputs.', 'Review open high-severity findings, native model availability/processing policy, host architecture and native parser redistribution notices. Do not represent cached scans or local protocol mocks as production approval.'],['Authorized immutable image publication and security decision records'],['The actual owned repository contains the qualified digests and unresolved findings have accountable decisions.']);
36
+ add(bootstrap,'Initialize owned SQL and admit verified staff',[images],['Keep application/maintenance flags false; enable only operations_enabled with the qualified runtime image. Review terraform/OPERATING_JOBS.md and exact operator_deployment output.', 'With separate operator launch/SQL authority, run the fixed initialize task and observe completion plus initialized:true. Never give the application/model an administrator credential.', 'Admit exact native staff subjects and separate SQL user/reviewer/supervisor memberships. Native login alone is not reviewer authority. Populate separate existing accounting/model/parser secret/policy references as documented, outside Terraform/source.', 'Verify native private SQL TLS, role marker/grants, duplicate bootstrap, denied runtime schema/audit mutations and wrong-account/identity behavior.'],['Observed owned bootstrap and membership/secret-reference acceptance'],['Fresh owned schema and correct restricted roles are evidenced; no unrelated deployment or role was adopted.']);
37
+ add(operations,'Verify scheduled cleanup and actionable monitoring',[bootstrap],['Run fixed maintain/monitor tasks and inspect real successful count/status-only receipts. Verify actual native logging destination and existing on-call recipients/delivery.', 'Enable maintenance only after bootstrap. For IBM, explicitly run install-schedules and check-schedules through the isolated CLI context; these are owned Knative sources outside Terraform, and the boolean alone does not pause/delete installed timers.', 'Observe actual hourly monitor/daily cleanup and inject an approved synthetic failure/missing-run condition. Verify alert evaluation/first-sample or zero-sample behavior and real notification delivery.', 'Review 90-day access/retention eligibility, object versions, SQL backups and lifecycle lag; exercise the separate isolated restore/reconciliation procedure without replaying uncertain accounting effects.'],['Native schedule/task/monitor/alert and restore evidence'],['Ready timer configuration is distinguished from job completion and on-call delivery.','Retention/restore/recovery limits remain explicit; no universal exact erasure claim.']);
38
+ add(release,'Release and test the complete staff invoice journey',[operations],['Obtain explicit application-release authorization for the exact current plan and digests. Enable applications_enabled only after native bootstrap/operations acceptance.', 'Exercise actual staff sign-in, upload/review/revision/approval, ordinary-uploader denial, extraction quality on representative invoices, duplicate bursts, restart recovery and preserved originals/history.', 'Independently verify existing accounting normalized-action-v1 compatibility and same-key idempotency before enabling uncertain replay. Check provider/residency/model-policy/identity/network paths and customer-data logging boundaries.', 'Retain original requirements and all meaningful limitations, failed checks and owner decisions; produce a deployment/rollback record without treating generated source as live acceptance.'],['Authorized application release and end-to-end evidence'],['Confirmed behavior and boundaries have actual results for this project; no unsupported requirement was removed.']);
39
+ if(row.modulePath){
40
+ const child=JSON.parse(emitted[row.modulePath+'/main.tf.json']);
41
+ const names=[...Object.keys(child.variable||{}),...Object.keys(child.output||{})].filter(name=>name!=='review_approved'&&name.includes('_')).sort((a,b)=>b.length-a.length);
42
+ const relocate=text=>{let value=text.replaceAll('terraform/main.tf.json',directory+'main.tf.json').replaceAll('terraform/OPERATING_JOBS.md',directory+'OPERATING_JOBS.md');for(const name of names)value=value.replace(new RegExp('\\b'+name+'\\b','g'),row.module+'__'+name);return value;};
43
+ resource.steps=resource.steps.map((step,index)=>index?relocate(step):step);resource.outputs=resource.outputs.map(relocate);
44
+ for(const current of tasks.filter(t=>t.id.startsWith('TASK-INVOICE-')&&t.componentIds?.includes(row.id))){current.steps=current.steps.map(relocate);if(current.id===source)current.steps.push('Validate the complete composition from terraform/, then run terraform init -backend=false, terraform validate and terraform test from '+directory+'. Retain both root and unit receipts.');}
45
+ task(state).steps=['Read terraform/README.md, composition.json and '+directory+'STATE.md. State custody belongs to the whole composition; this unit never chooses a backend for other units. Production remains blocked until root state/locking/access/residency/recovery and operating responsibilities are implemented and independently reviewed.','Keep all root state inputs outside source and obtain explicit authorization before cloud access, migration or deployment.'];
46
+ }
47
+ // Generic staging/live/acceptance work must wait for the phased module release.
48
+ task('TASK-STAGING').dependsOn.push(release);
49
+ }
50
+
51
+ export function invoiceSpecDocuments(plan){
52
+ if(!plan.composition)return invoiceUnitDocuments(plan);
53
+ const files={};for(const entry of plan.invoicePlan?.entries||[]){const single=invoiceUnitDocuments({...plan,invoicePlan:{...plan.invoicePlan,entries:[entry]}}),directory='terraform/'+entry.row.modulePath+'/';files['spec-kit/invoice-delivery-'+key(entry.row.id)+'.md']=Object.values(single)[0].replace('terraform/STATE.md, OPERATING_JOBS.md, OPERATIONS.md, invoice-contract.json and',directory+'STATE.md, '+directory+'OPERATING_JOBS.md, '+directory+'OPERATIONS.md, '+directory+'invoice-contract.json and').replace('applications/'+entry.row.address+'/',directory+'applications/'+entry.row.address+'/')+'\nTerraform inputs and outputs at the composition root use the '+entry.row.module+'__ prefix; unit-local tests retain their local names. Root state acceptance remains a prerequisite.\n';}
54
+ files['spec-kit/invoice-delivery.md']='# Invoice delivery units\n\n'+Object.keys(files).map(path=>'- '+path).join('\n')+'\n\nRead each unit document and its scoped TASK-INVOICE-* phases. Shared composition state and all unit/interface checks remain prerequisites.\n';
55
+ return files;
56
+ }
57
+ function invoiceUnitDocuments(plan){
58
+ if(!plan.invoicePlan?.entries.length)return{};
59
+ const{row}=plan.invoicePlan.entries[0];
60
+ return {'spec-kit/invoice-delivery.md':`# Invoice delivery implementation\n\nProvider: ${row.provider}; component: ${row.id}.\n\nThe API, worker, parser, durable SQL queue/outbox, private versioned originals,\nidentity boundaries and operator jobs are supplied source, not tasks for the user\nto invent. Run the dependency-ordered TASK-INVOICE-* phases in tasks.json.\n\nLocal source/native-schema/mock/image tests precede authorized platform/state and\naccount planning. Foundation precedes immutable image publication, SQL/bootstrap\nand staff membership, then real schedules/alerts, then application release. The\nexisting accounting system remains external and its actual normalized action/\nidempotency contract must be accepted independently. No account apply, publication,\nstate migration or customer deployment is authorized by this bundle.\n\nRead terraform/STATE.md, OPERATING_JOBS.md, OPERATIONS.md, invoice-contract.json and\napplications/${row.address}/BUILD.md and TESTING.md. Keep exact original requirements\nand additional unimplemented components visible. All tasks start todo; generated\nsource and prior local qualifications are not this project's deployment evidence.\n`};
61
+ }
@@ -0,0 +1,7 @@
1
+ import {protectedState} from './protected-state.mjs';
2
+ // Compatibility adapter: the established invoice default is an explicit policy.
3
+ export function invoiceState(provider){
4
+ const backend={aws:'s3',azure:'azurerm',gcp:'gcs',ibm:'http'}[provider];
5
+ if(!backend)throw Error('Invoice state must preserve the selected provider');
6
+ return protectedState(backend,{title:'Invoice state and environment ownership'});
7
+ }
@@ -0,0 +1,29 @@
1
+ import{awsInvoiceTerraform}from'./invoice-aws.mjs';
2
+ import{azureInvoiceTerraform}from'./invoice-azure.mjs';
3
+ import{gcpInvoiceTerraform}from'./invoice-gcp.mjs';
4
+ import{ibmInvoiceTerraform}from'./invoice-ibm.mjs';
5
+ import{invoiceState}from'./invoice-state.mjs';
6
+ import{validInvoiceRegion}from'./invoice-region.mjs';
7
+ import{incompleteTerraform}from'./incomplete-terraform.mjs';
8
+
9
+ // Public dispatch is deliberately separate from isolated native-adapter fixtures.
10
+ // It retains all graph gaps and blocks a partial module from passing as the whole.
11
+ export function invoiceTerraform(project,plan,environment='staging',options={}){
12
+ const entries=plan.invoicePlan?.entries||[];
13
+ if(entries.length!==1)return incompleteTerraform(project,plan,environment);
14
+ const{row}=entries[0],adapter={aws:awsInvoiceTerraform,azure:azureInvoiceTerraform,gcp:gcpInvoiceTerraform,ibm:ibmInvoiceTerraform}[row.provider];
15
+ if(!adapter)return incompleteTerraform(project,plan,environment);
16
+ const files=adapter(project,{...row,region:validInvoiceRegion(row.provider,row.region)?row.region:''},environment),config=JSON.parse(files['main.tf.json']);
17
+ config.locals.unfinished_work=plan.gapDetails.map(gap=>gap.id);
18
+ config.resource.terraform_data.review_gate.lifecycle.precondition.push({condition:'${length(local.unfinished_work) == 0}',error_message:'Preserved requirements/components/connections are not all implemented. Inspect resource-schedule.json and repair the generator composition; do not clear unfinished_work.'});
19
+ const state=invoiceState(row.provider);
20
+ if(environment==='production'&&options.stateScope!=='parent')config.terraform.backend=state.backend;
21
+ files['main.tf.json']=JSON.stringify(config,null,2)+'\n';
22
+ files['resource-schedule.json']=JSON.stringify(plan,null,2)+'\n';
23
+ files['invoice-contract.json']=JSON.stringify({format:'invoice-workflow-v1',provider:row.provider,componentId:row.id,accountingComponentId:entries[0].accountingId,limits:{maxPdfBytes:10000000,maxPdfPages:100,retentionDays:90},review:'Separate live SQL user/reviewer roles; only approved payload hashes admit accounting delivery.',accounting:'Existing normalized-action-v1 adapter, destination contract digest and stable operation identity. Actual accounting compatibility/idempotency is independently accepted; uncertain outcomes are fenced and reconciled, not blindly retried.',evidence:'Generated source and contracts; not account-plan, cloud runtime or production evidence.'},null,2)+'\n';
24
+ if(options.stateScope==='parent')files['STATE.md']='# Composition-owned state\n\nUse the composition root and its reviewed state custody. This unit does not select a backend for other units. Production stays blocked until whole-composition state ownership, residency, access, locking and recovery have evidence.\n';
25
+ else Object.assign(files,state.files);
26
+ files['.gitignore']+='backend.hcl\n*.tfbackend\nreviewed-plan.json\n';
27
+ files['README.md']+=options.stateScope==='parent'?'\n## Composition unit\n\nRun Terraform from the composition root. This unit retains its application, contracts and protections; it does not select a backend. Read the root composition.json and README.md. Production stays blocked until whole-composition state and operations acceptance.\n':'\n## Whole-project scope and state\n\nRead invoice-contract.json, resource-schedule.json, OPERATING_JOBS.md and STATE.md.\nAdditional requested components/flows/configuration remain visible and block the\nreview gate until implemented. No diagram requirement is removed by this module.\nProduction uses its reviewed provider-specific protected state/locking backend; no\nstate store is deployed or silently borrowed from another cloud. Destination\nstate residency, access, locking and recovery acceptance precede account planning.\n';
28
+ return files;
29
+ }
@@ -0,0 +1,122 @@
1
+ import sources from'./runtime/invoice-test-sources.json'with{type:'json'};
2
+ import runtime from'./runtime/invoice-sources.json'with{type:'json'};
3
+ import base from'./runtime/python-container-lock.json'with{type:'json'};
4
+
5
+ export function invoiceTestFiles(provider,address){
6
+ const root='applications/'+address+'/',files={};
7
+ for(const[name,original]of Object.entries(sources)){
8
+ if(!name.endsWith('.py'))continue;
9
+ let code=original;
10
+ if(name==='start-durable-fixture.py'){
11
+ code=code.replace("import argparse\n","import argparse\nimport hashlib\n").replace("name='atmem-durable-qualification'+('-pg18'if args.major=='18'else'')","name='atmem-invoice-'+hashlib.sha256(str(ROOT).encode()).hexdigest()[:12]+('-pg18'if args.major=='18'else'')");
12
+ }else{
13
+ if(!code.includes('ROOT=Path(__file__).resolve().parents[2]')&&!['workflow_tls_destination_fixture.py','durable_fixture_tasks.py'].includes(name))throw Error('Review portable invoice test root: '+name);
14
+ code=code.replaceAll('ROOT=Path(__file__).resolve().parents[2]',"ROOT=Path(__file__).resolve().parents[1]\nsys.path.insert(0,str(ROOT/'parser'))");
15
+ }
16
+ code=code.replaceAll("ROOT/'src/runtime/rds-global-ca.pem'","ROOT/'test-fixtures/rds-global-ca.pem'").replaceAll("ROOT/'src/runtime/postgres-qualification-lock.json'","ROOT/'test-fixtures/postgres-qualification-lock.json'").replaceAll("ROOT/'src/runtime'","ROOT").replaceAll("ROOT/'tests/runtime'","ROOT/'tests'").replaceAll(",str(ROOT/'.local/azure-runtime-sdk')",'');
17
+ if(name==='durable_postgres_acceptance.py')code=code.replace("c.get('name')not in {'atmem-durable-qualification','atmem-durable-qualification-pg18'}","(c.get('name')not in {'atmem-durable-qualification','atmem-durable-qualification-pg18'}and not re.fullmatch(r'atmem-invoice-[0-9a-f]{12}(?:-pg18)?',str(c.get('name',''))))");
18
+ if(name==='invoice_http_acceptance.py'){
19
+ const fixture="(ROOT/'benchmarks/convergence/fixtures/invoices/invoice-text.pdf').read_bytes()";
20
+ if(!code.includes(fixture))throw Error('Review portable PDF transport fixture');
21
+ code='import base64\n'+code.replace(fixture,"base64.b64decode((ROOT/'test-fixtures/invoice-text.pdf.base64').read_text())");
22
+ }
23
+ if(name==='invoice_storage_acceptance.py'&&provider!=='aws'){
24
+ const start=code.indexOf('class NativeS3InvoiceObjectsTests('),end=code.indexOf("if __name__=='__main__':");
25
+ if(start<0||end<=start)throw Error('Review isolated provider test boundary');
26
+ code=code.slice(0,start)+code.slice(end);code=code.replace(/^import boto3\n/m,'').replace(/^from botocore\.[^\n]+\n/gm,'');
27
+ }
28
+ if(name==='invoice_parser_rpc_acceptance.py'&&provider!=='azure'){
29
+ const start=code.indexOf('class AzureParserIdentityTests('),end=code.indexOf('class IbmParserIdentityTests(');
30
+ if(start<0||end<=start)throw Error('Review Azure-only native SDK test boundary');
31
+ code=code.slice(0,start)+code.slice(end);
32
+ }
33
+ files[root+(name==='start-durable-fixture.py'?'tests/start-local-fixture.py':'tests/'+name)]=code;
34
+ }
35
+ files[root+'test-fixtures/postgres-qualification-lock.json']=sources['postgres-qualification-lock.json'];
36
+ files[root+'test-fixtures/invoice-text.pdf.base64']=sources['invoice-text.pdf.base64']+'\n';
37
+ files[root+'test-fixtures/rds-global-ca.pem']=runtime['rds-global-ca.pem'];
38
+ files[root+'test-scope.json']=JSON.stringify({provider,scope:'Owned local SQL and synthetic protocol checks; provider SDK requirements follow the selected delivery lock.',sdkCases:{awsS3:provider==='aws',azureManagedIdentity:provider==='azure'},excludedForeignSdkCases:provider==='aws'?['azure ManagedIdentityCredential']:provider==='azure'?['AWS S3 boto3']:['AWS S3 boto3','azure ManagedIdentityCredential'],boundary:'Exclusion of a foreign SDK case is explicit contract selection, not a skipped test or evidence for that foreign provider.'},null,2)+'\n';
39
+ files[root+'tests/run.py']=INVOICE_TEST_RUNNER;
40
+ files[root+'TESTING.md']=INVOICE_TESTING;
41
+ const patch=base.securityPackages[0];
42
+ files[root+'Dockerfile.tests']=`FROM ${base.image}\nENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1\nADD --checksum=sha256:${patch.sha256} ${patch.url} /tmp/runtime-security.deb\nRUN dpkg -i /tmp/runtime-security.deb && rm /tmp/runtime-security.deb\nWORKDIR /app\nCOPY test-requirements.lock ./\nRUN python -I -m pip --isolated install --no-cache-dir --only-binary=:all: --require-hashes -r test-requirements.lock\nCOPY *.py *.sql invoice-deployment.json invoice-web.* ./\nCOPY parser/*.py ./parser/\nCOPY tests/ ./tests/\nCOPY test-fixtures/ ./test-fixtures/\nENTRYPOINT ["python", "-I", "tests/run.py"]\n`;
43
+ files[root+'Dockerfile.tests.dockerignore']='*\n!test-requirements.lock\n!*.py\n!*.sql\n!invoice-deployment.json\n!invoice-web.*\n!parser/\n!parser/*.py\n!tests/\n!tests/*.py\n!test-fixtures/\n!test-fixtures/*\n';
44
+ return files;
45
+ }
46
+
47
+ const INVOICE_TEST_RUNNER=`"""Run emitted local acceptance sources; never connect to a cloud database."""
48
+ import argparse
49
+ import fcntl
50
+ import hashlib
51
+ import json
52
+ import os
53
+ from pathlib import Path
54
+ import re
55
+ import subprocess
56
+ import sys
57
+ ROOT=Path(__file__).resolve().parents[1]
58
+ TESTS=['invoice_extraction_acceptance.py','invoice_storage_acceptance.py','invoice_http_acceptance.py','invoice_web_acceptance.py','invoice_identity_acceptance.py','invoice_parser_rpc_acceptance.py','invoice_parser_identity_acceptance.py','invoice_worker_acceptance.py','invoice_operations_acceptance.py','invoice_operator_acceptance.py','invoice_operator_job_acceptance.py','workflow_payload_acceptance.py','workflow_http_acceptance.py','workflow_application_acceptance.py','workflow_bindings_acceptance.py']
59
+
60
+ if __name__=='__main__':
61
+ parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--fixture',required=True);parser.add_argument('--out',required=True);args=parser.parse_args()
62
+ fixture=Path(args.fixture).resolve();out=Path(args.out).resolve()
63
+ if out.exists()or not out.is_relative_to(ROOT/'.local'):raise ValueError('Use a fresh private .local output directory')
64
+ out.mkdir(parents=True,mode=0o700);out.chmod(0o700)
65
+ # Guarded fixture validation happens before any acceptance test writes SQL.
66
+ os.environ['ATMEM_WORKFLOW_TEST_CONFIG']=str(fixture);sys.path[:0]=[str(ROOT),str(ROOT/'tests')]
67
+ from durable_postgres_acceptance import fixture_dsn
68
+ fixture_dsn()
69
+ files=[*ROOT.glob('*.py'),*ROOT.glob('*.sql'),*ROOT.glob('*.lock'),*ROOT.glob('invoice-web.*'),*(ROOT/'tests').glob('*.py'),*(ROOT/'test-fixtures').glob('*')]
70
+ def hashes():return {str(path.relative_to(ROOT)):hashlib.sha256(path.read_bytes()).hexdigest()for path in sorted(files)}
71
+ before=hashes();checks=[]
72
+ with (fixture.parent/'invoice-export-tests.lock').open('a')as lock:
73
+ os.chmod(lock.name,0o600);fcntl.flock(lock,fcntl.LOCK_EX|fcntl.LOCK_NB)
74
+ for name in TESTS:
75
+ log=out/(name+'.log')
76
+ with log.open('wb')as stream:result=subprocess.run([sys.executable,'-I',str(ROOT/'tests'/name)],cwd=ROOT,env={**os.environ,'ATMEM_WORKFLOW_TEST_CONFIG':str(fixture),'PYTHONDONTWRITEBYTECODE':'1'},stdout=stream,stderr=subprocess.STDOUT,timeout=60)
77
+ counts=re.findall(r'Ran (\\d+) tests in',log.read_text());checks.append({'name':name,'passed':result.returncode==0,'tests':int(counts[0])if len(counts)==1 else None,'log':log.name})
78
+ passed=all(check['passed']and check['tests']for check in checks)and before==hashes()
79
+ receipt={'format':'invoice-package-local-tests-v1','passed':passed,'checks':checks,'sourceHashes':before,'sourcesUnchanged':before==hashes(),'cloudOperations':False,'boundary':'Actual emitted source and owned loopback SQL with synthetic identities/storage/model/accounting protocols. Not native cloud authentication, model quality, real parser image, managed restore, account plan or deployment.'}
80
+ (out/'receipt.json').write_text(json.dumps(receipt,indent=2)+'\\n');print(json.dumps({'passed':passed,'tests':sum(check['tests']or 0 for check in checks),'receipt':str(out/'receipt.json')}));sys.exit(0 if passed else 1)
81
+ `;
82
+
83
+ const INVOICE_TESTING=`# Portable local invoice acceptance
84
+
85
+ On Linux/amd64, create a separate Python 3.13 virtual environment from this application
86
+ directory for this provider. Install test-requirements.lock using pip --require-hashes
87
+ --only-binary=:all:. Do not mix IBM/AWS SDK environments or substitute another
88
+ provider's dependency resolution. Install OpenSSL with req -addext support for the
89
+ synthetic loopback TLS tests. No cloud credential is needed.
90
+
91
+ The wheel hashes target Linux/amd64. On another host, use the emitted Linux test
92
+ image: docker build --platform linux/amd64 -f Dockerfile.tests -t invoice-local-tests .
93
+ It is a separate developer test image, not the delivered API/worker image. Pass a
94
+ private owned loopback fixture configuration and a writable private output directory
95
+ to tests/run.py; do not copy credentials into its build context. Host networking
96
+ must be explicitly enabled/supported by the local Docker engine for loopback SQL.
97
+ No cloud/database/identity credential from the host is implicitly forwarded.
98
+
99
+ With an existing local Unix Docker socket, explicitly create the synthetic fixture:
100
+
101
+ python tests/start-local-fixture.py --docker-host unix:///ABSOLUTE_LOCAL_DOCKER_SOCKET --major 18
102
+ python tests/run.py --fixture .local/durable-postgres/fixture-pg18.json --out .local/test-run-1
103
+
104
+ Use the pinned native PostgreSQL image and retain its digest. The fixture binds only
105
+ 127.0.0.1, gets a directory-derived owned name, uses private generated credentials
106
+ and validates its schema marker. Never point these tests at a client/cloud database.
107
+ The tests create synthetic accounts/roles/records; keep the fixture disposable and
108
+ run suites serially. No container/database adoption, dump, migration or cloud access
109
+ is implicit. Missing Docker/socket/image/prerequisite is a failed prerequisite,
110
+ not a skipped pass. Review any authorized image download and local resource costs.
111
+
112
+ The suite covers extraction validation, version-bound storage protocols, signed
113
+ staff/API admission and SQL memberships, upload/review/approval/history, local TLS
114
+ parser/action protocols, worker behavior, guarded operator initialization,
115
+ retention/monitoring and browser safety. AWS includes native SDK shape tests; other
116
+ providers include scripted HTTP contracts without pulling in AWS's SDK. Protocol
117
+ fixtures are not cloud IAM or actual model quality. Real PDF/OCR image acceptance,
118
+ native model examples, destination accounting compatibility, restore and actual
119
+ private-network/scheduled-alert behavior require their separate acceptance tasks.
120
+ Receipts distinguish these boundaries. Keep private .local credentials/logs/state
121
+ out of source control; do not send diagnostic logs containing secrets to a model.
122
+ `;
@@ -0,0 +1,106 @@
1
+ /* Only the owner-requested stage navigation, board sidebar and consolidated review. */
2
+ .stage-tabs{display:flex;gap:8px;overflow:auto;padding:8px 12px;width:100%;box-sizing:border-box}
3
+ .stage-tabs>button{display:flex;align-items:center;gap:7px;white-space:nowrap;background:var(--paper,#fff);color:var(--ink,#263043);border:1px solid var(--line,#dce2e8);border-radius:8px;padding:10px 14px;cursor:pointer}
4
+ .stage-tabs>button[aria-selected=true]{outline:2px solid var(--accent,#be5679);outline-offset:-2px;font-weight:600}
5
+ .stage-tabs>button.stage-complete{background:#e7f4eb;color:#215d3b;border-color:#a9cdb4}
6
+ .stage-tabs>button>span{font-size:.85em;border:1px solid currentColor;border-radius:50%;width:22px;height:22px;display:grid;place-items:center}
7
+ .unified-journey{display:flex;flex-direction:column;align-items:stretch}
8
+ .unified-journey .journey-current{padding:4px 14px;display:flex;gap:12px;align-items:center}
9
+ .unified-journey .journey-current p{margin:4px 0;flex:1}
10
+ .project-rename{display:flex;align-items:center;min-width:0}.project-rename>svg{opacity:0}.project-rename:hover>svg,.project-rename:focus-within>svg{opacity:1}
11
+ .bar .projects-btn{display:inline-flex;align-items:center;gap:7px;width:auto;min-width:100px;padding:7px 10px}
12
+ .board-surface{position:absolute;inset:0}.board-surface[hidden],.review-workspace[hidden]{display:none!important}
13
+ .board-components{position:absolute;left:12px;top:12px;z-index:15;max-width:270px;max-height:calc(100% - 90px);overflow:auto;background:var(--paper,#fff);border:1px solid var(--line,#dce2e8);border-radius:10px;padding:8px}
14
+ .board-component-tree{padding:10px 0;max-width:245px}.board-component-tree details{padding:8px 0}.board-component-tree button{display:flex;align-items:center;gap:7px;text-align:left;max-width:100%;margin:5px 0}.board-component-tree small{display:block;overflow-wrap:anywhere}
15
+ .board-start{position:absolute;left:50%;top:42%;transform:translate(-50%,-50%);z-index:10;width:min(540px,calc(100% - 40px));background:var(--paper,#fff);border:1px solid var(--line,#dce2e8);border-radius:14px;padding:20px;box-sizing:border-box}.board-start .row{display:flex;flex-wrap:wrap;gap:8px}.board-start small{display:block;margin-top:12px;color:var(--ink-2,#627080)}
16
+ .review-workspace{position:absolute;inset:0;overflow:auto;background:var(--paper,#fff);padding:20px;box-sizing:border-box}
17
+ .review-workspace .doc{position:static;inset:auto;width:auto;max-width:none;overflow:visible;height:auto;box-shadow:none;margin:0 0 24px;padding:12px}
18
+ .review-generation,.review-infrastructure{margin:20px 12px;padding:16px;border:1px solid var(--line,#dce2e8);border-radius:10px}.review-generation .engineering-panel{max-width:none;margin:0;padding:0}.review-infrastructure>summary{cursor:pointer;font-weight:600}.review-workspace .engineering-panel pre{white-space:pre-wrap;overflow-wrap:anywhere}
19
+ .code-preview{white-space:pre;overflow:auto}.code-preview .code-string{color:#a33c31}.code-preview .code-number{color:#236c44}.code-preview .code-keyword{color:#7153ad}.code-preview .code-comment{color:#697780}
20
+ @media(max-width:650px){.stage-tabs{gap:5px;padding:8px}.stage-tabs>button{padding:8px;font-size:12px}.stage-tabs>button>span{width:18px;height:18px}.unified-journey .journey-current{flex-wrap:wrap}.review-workspace{padding:6px}.board-components{max-width:220px}.project-rename .project-name{max-width:150px}}
21
+
22
+ .choices-workspace{position:absolute;inset:0;overflow:auto;background:var(--paper,#fff);padding:16px}.choices-workspace[hidden]{display:none!important}.choices-workspace .doc{position:static;inset:auto;width:auto;max-width:none;height:auto;overflow:visible;box-shadow:none;margin-bottom:18px}
23
+
24
+ .bar .projects-btn{color:var(--ink,#243047);border:1px solid var(--line,#cbd4df);border-radius:8px;background:var(--paper,#fff);font-weight:600}.board-surface>.board-components{position:absolute}.review-group{margin:12px;padding:14px;border:1px solid var(--line,#dce2e8);border-radius:10px}.review-group>summary{font-weight:600;cursor:pointer}.review-intro{margin:12px}.review-intro p{color:var(--ink-2,#627080)}
25
+
26
+ .review-workspace fieldset{min-width:0;box-sizing:border-box}.review-workspace .row{flex-wrap:wrap}.board-component-tree button>svg{flex-shrink:0}.board-component-tree button>span{min-width:0}
27
+
28
+ .board-surface{--component-sidebar-width:min(245px,45%)}
29
+ .board-surface.has-component-sidebar>.react-flow{width:calc(100% - var(--component-sidebar-width));margin-left:var(--component-sidebar-width)}
30
+ .board-surface>.board-components[data-expanded=true]{left:0;top:0;bottom:0;max-height:none;width:var(--component-sidebar-width);max-width:none;box-sizing:border-box;border-radius:0}
31
+ .board-components .btn{max-width:100%;white-space:normal}
32
+ .board-surface.has-component-sidebar>.toolbar{left:calc(var(--component-sidebar-width) + 12px)}
33
+ .board-surface.has-component-sidebar>.board-start{left:calc(var(--component-sidebar-width) + (100% - var(--component-sidebar-width))/2);width:min(540px,calc(100% - var(--component-sidebar-width) - 24px))}
34
+
35
+ .code-preview .code-key{color:light-dark(#175b91,#92cfff)}
36
+ .code-preview .code-string{color:light-dark(#a33c31,#ffc0a6)}
37
+ .code-preview .code-number{color:light-dark(#236c44,#9ce5b2)}
38
+ .code-preview .code-keyword{color:light-dark(#7153ad,#d4b8ff)}
39
+ .code-preview .code-comment{color:light-dark(#526171,#b3c0cb)}
40
+ .memory-panel select,.memory-panel textarea{color:var(--ink);background:var(--paper);border:1px solid var(--line);opacity:1}
41
+ .memory-panel textarea::placeholder{color:var(--ink-2);opacity:1}
42
+ .memory-panel option{color:var(--ink);background:var(--paper)}
43
+ .memory-panel button:disabled{background:light-dark(#e5e9ed,#273033);color:light-dark(#556171,#b9c9cc);opacity:1}
44
+ /* A document remains a light paper surface even when the surrounding app is dark. */
45
+ .requirements-paper{color-scheme:light;--ink:#172033;--ink-2:#52616c;--paper:#fffefa;--board:#fafbf9;--line:#7a8696;--accent:#873b50;color:#172033}
46
+ .requirements-paper .btn,.requirements-paper input,.requirements-paper select,.requirements-paper textarea{color:#172033;background:#fffefa;border-color:#7a8696}
47
+ .requirements-paper .btn.primary{background:#f4a4b8;color:#172033}
48
+ .requirements-paper .muted{color:#52616c}
49
+ .app button:disabled{opacity:1;background:light-dark(#e5e9ed,#273033);color:light-dark(#556171,#b9c9cc);cursor:not-allowed}
50
+ .app :is(input,textarea,select):disabled{opacity:1;color:var(--ink-2);background:var(--board)}
51
+ .app input::placeholder,.app textarea::placeholder{color:var(--ink-2);opacity:1}
52
+ .app .resource-schedule article span,.app .resource-schedule article small{color:var(--ink-2)}
53
+ @media(min-width:900px){
54
+ .bar .project-rename{flex:0 1 480px;max-width:60vw}
55
+ .bar .project-rename .project-name{width:100%;min-width:0;max-width:none!important;box-sizing:border-box}
56
+ }
57
+
58
+ /* Onboarding must never obscure the active component picker. */
59
+ .board-surface>.palette{z-index:30;top:12px;left:12px;transform:none;width:min(320px,calc(100% - 24px));max-height:calc(100% - 24px)}
60
+ .board-start-close{position:absolute;top:8px;right:8px}
61
+ .board-start>h2{padding-right:24px}
62
+ .palette-search>.icon{flex-shrink:0}
63
+
64
+ .turn-state-icon.has-brain{width:24px;display:inline-flex;align-items:center;animation:none}
65
+ .chat{position:relative}.chat-resize-handle{display:none}
66
+ @media(min-width:901px){
67
+ .app:not(.chat-closed){grid-template-columns:minmax(0,1fr) clamp(320px,var(--chat-panel-width,360px),calc(100vw - 360px))}
68
+ .chat-resize-handle{display:block;position:absolute;top:0;bottom:0;left:-6px;width:12px;z-index:35;cursor:col-resize;touch-action:none}
69
+ .chat-resize-handle:hover,.chat-resize-handle:focus-visible{background:var(--accent-soft);outline:2px solid var(--accent);outline-offset:-3px}
70
+ }
71
+
72
+ .chat-width-toggle{display:none}@media(min-width:901px){.chat-width-toggle{display:inline-flex;margin-left:auto;padding:5px 8px}}
73
+
74
+ .review-costs,.review-generation{padding:20px;border:1px solid var(--line);border-radius:16px;background:var(--paper);margin:16px 0}
75
+ .review-costs>.doc{padding:0}.review-costs h2,.review-generation h2{font-size:1.25rem;margin-top:0}
76
+ .review-finish{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:20px 0;border-top:1px solid var(--line)}
77
+ .review-finish p{margin:5px 0;color:var(--muted);font-size:.9rem}.review-finish>.btn{flex-shrink:0}
78
+ .chat-working-status{display:flex;align-items:center;gap:10px;padding:12px 16px;border-top:1px solid var(--line);background:var(--paper);font-size:.9rem}
79
+ .chat-working-status .brain-activity{flex-shrink:0}.generation-status{display:flex;gap:8px;align-items:center}
80
+ .engineering-panel .generation-conversation{max-height:none;overflow:visible}.engineering-panel .generation-conversation[open]>.engineering-conversation{max-height:300px;overflow:auto}
81
+ .review-generation .engineering-panel textarea{min-height:72px}.review-generation .engineering-actions{display:block}
82
+ @media(max-width:650px){.review-finish{align-items:stretch;flex-direction:column}.review-finish>.btn{width:100%}}
83
+ .chat-jump-latest{position:absolute;right:24px;bottom:230px;z-index:40;border:1px solid var(--line);border-radius:50%;background:var(--paper);color:var(--ink);box-shadow:0 3px 12px #0002;width:40px;height:40px;font-size:24px;cursor:pointer}
84
+ .project-checks{padding:20px;border:1px solid var(--line);border-radius:16px;background:var(--paper);margin:16px 0}.section-action{display:flex;align-items:center;gap:8px}.section-action h3{margin:0}.section-action>.btn{margin-left:auto}
85
+ .check-rows,.final-checklist ul{padding:0;list-style:none}.check-rows li,.final-checklist li{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);font-size:.9rem}.check-rows strong,.final-checklist strong{margin-left:auto;font-size:.85rem}.check-complete{color:#217143}.check-pending{color:#946000}.final-checklist{margin:20px 0}.final-checklist li>span:first-child{width:24px;height:24px;display:grid;place-items:center;border:1px solid currentColor;border-radius:50%;flex-shrink:0}
86
+ [data-theme=dark] .check-complete{color:#80d6a2}[data-theme=dark] .check-pending{color:#f0c575}
87
+ .project-checks pre{max-height:300px;overflow:auto;white-space:pre-wrap}.delivery-state{font-weight:600}
88
+ .message-list>.msg{border-top:1px solid var(--line);padding-top:14px;margin-top:14px}.message-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:.75rem;color:var(--muted);margin-bottom:6px}.message-meta time{font-variant-numeric:tabular-nums}
89
+ .memory-modal{width:min(1280px,96vw)!important;max-width:1280px!important;height:min(88vh,1000px);overflow:auto}.memory-panel{width:100%}
90
+ .file-tree{min-width:0;overflow:auto;border-right:1px solid var(--line);padding:8px 0;max-height:650px;background:var(--paper)}.file-tree ul{list-style:none;padding:0;margin:0}.file-tree button{display:flex;align-items:center;gap:5px;width:100%;min-height:30px;text-align:left;background:transparent;color:var(--ink);border:0;border-radius:0;font:inherit;font-size:.8rem;cursor:pointer;white-space:nowrap}.file-tree button:hover{background:var(--accent-soft)}.file-tree button.selected{background:var(--accent-soft);box-shadow:inset 2px 0 var(--accent)}.file-tree button>svg{flex-shrink:0}.tree-indent{width:13px;flex-shrink:0}.file-tree button>span:last-child{overflow:hidden;text-overflow:ellipsis}
91
+ .concise-answer{min-width:0}.message-details{display:inline-flex;align-items:center;min-height:32px;padding:2px 0;text-decoration:underline;text-underline-offset:3px;cursor:pointer;font-size:.85rem}
92
+
93
+
94
+ .final-checklist li{padding:0}.final-checklist li>button{display:flex;align-items:center;gap:12px;width:100%;padding:12px 4px;border:0;border-radius:6px;background:transparent;color:var(--ink);font:inherit;text-align:left;cursor:pointer}.final-checklist li>button:hover,.final-checklist li>button:focus-visible{background:var(--accent-soft);outline:2px solid var(--ink);outline-offset:-2px}.final-checklist button>span:first-child{width:24px;height:24px;display:grid;place-items:center;border:1px solid currentColor;border-radius:50%;flex-shrink:0}.checklist-arrow{font-size:1.15em}
95
+
96
+ .inline-note{display:block;max-width:100%;margin:6px 0 10px;line-height:1.5;color:var(--muted);overflow-wrap:anywhere}
97
+
98
+ .cost-size-selector .btn{display:inline-flex;align-items:center;gap:6px}.cost-size-selector .btn[aria-pressed="true"]{font-weight:600}.cost-selection-status{font-size:.9rem;color:var(--muted)}
99
+
100
+ .cost-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.cost-heading h2{margin:0}.cost-heading>.btn{flex-shrink:0}
101
+
102
+ .memory-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.memory-heading h2,.memory-heading h3{margin:0}.memory-profile-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:12px 0;border-bottom:1px solid var(--line);margin-bottom:12px}.memory-profile-bar label{display:flex;align-items:center;gap:8px}.memory-profile-bar input{max-width:190px}.memory-profile-bar code{font-size:.72rem;overflow-wrap:anywhere}.memory-state{margin-left:auto}.memory-toolbar{display:flex;gap:10px;align-items:center;margin:16px 0 10px}.memory-toolbar input{flex:1;min-width:100px}.memory-toolbar strong{white-space:nowrap;font-size:.85rem}.memory-table-wrap{max-height:50vh;overflow:auto;border:1px solid var(--line);border-radius:10px}.memory-table{width:100%;border-collapse:collapse;font-size:.8rem;table-layout:fixed}.memory-table th{position:sticky;top:0;background:var(--paper);z-index:1;font-weight:600;text-align:left}.memory-table td,.memory-table th{padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:top;overflow-wrap:anywhere}.memory-table th:first-child{width:20%}.memory-table th:nth-child(2){width:35%}.memory-table th:last-child{width:60px}.memory-table td:nth-child(5){font-variant-numeric:tabular-nums;font-size:.73rem}.memory-content{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;border:0;padding:0;background:none;color:var(--ink);font:inherit;text-align:left;cursor:pointer}.memory-table .link{padding:0;font:inherit;text-align:left;overflow-wrap:anywhere}.memory-badge{font-size:.72rem;border-radius:20px;padding:3px 6px;background:var(--board)}.memory-badge.active{color:#21633a;background:#e8f4eb}.memory-pagination{display:flex;align-items:center;justify-content:flex-end;gap:10px;padding:12px 0}.memory-pagination>span{margin-right:auto;font-size:.8rem}.memory-preference-form{display:flex;gap:10px;flex-wrap:wrap;padding:12px 0}.memory-preference-form input{flex:1;min-width:140px}.memory-record-detail{padding:16px;border:1px solid var(--line);border-radius:10px;margin:12px 0}.memory-record-detail dl{display:grid;grid-template-columns:140px 1fr;gap:8px;font-size:.8rem}.memory-record-detail dd{margin:0;overflow-wrap:anywhere}.memory-record-detail p{white-space:pre-wrap}.memory-feedback{display:flex;align-items:center;gap:6px;font-size:.8rem;margin:8px 0}.memory-empty{padding:32px;text-align:center;color:var(--muted)}.memory-table-wrap[aria-busy=true]{opacity:.65}.memory-preview{padding:16px;border:1px solid var(--line);border-radius:10px}.memory-preview .btn{margin-right:8px}@media(max-width:700px){.memory-table{min-width:800px}.memory-profile-bar code{font-size:.65rem}.memory-record-detail dl{grid-template-columns:1fr}.memory-toolbar{flex-wrap:wrap}}
103
+
104
+ .memory-modal{height:auto!important;max-height:88vh!important}.memory-profile-bar input,.memory-toolbar input,.memory-toolbar select,.memory-preference-form input,.memory-preference-form select{font:inherit;font-size:.85rem;min-height:36px;box-sizing:border-box;padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--paper);color:var(--ink)}.memory-table th:last-child{width:84px;white-space:nowrap}.memory-table td:last-child{white-space:nowrap}.memory-table th:nth-child(4){width:90px}.memory-table th:nth-child(5){width:130px}.memory-table th:nth-child(3){width:84px}.memory-toolbar>strong{color:var(--muted);font-weight:500}.memory-pagination .btn{min-height:32px}.memory-record-detail .memory-table{table-layout:auto}.memory-table .memory-content:hover{text-decoration:underline;text-underline-offset:3px}
105
+
106
+ .location-region-form{display:flex;align-items:flex-end;gap:12px}.location-region-form label{display:flex;flex-direction:column;gap:6px}.location-region-form input{font:inherit;padding:9px 12px;border:1px solid var(--line);border-radius:8px;background:var(--paper);color:var(--ink)}
@@ -0,0 +1,97 @@
1
+ // Progress records acknowledge a working draft, never cloud validation or deployment permission.
2
+ // Navigation is independent of completion: opening a section must not accept a
3
+ // decision, advance a checkpoint or send a model request.
4
+ export const DESIGN_SECTIONS=Object.freeze([
5
+ {id:'board',label:'Board',mode:'design',view:'board'},
6
+ {id:'scope',label:'Requirements',mode:'design',view:'requirements'},
7
+ {id:'cloud',label:'Choices',mode:'design',view:'options'},
8
+ {id:'review',label:'Review',mode:'review',view:'board'},
9
+ {id:'delivery',label:'Delivery',mode:'design',view:'outputs'},
10
+ ].map(Object.freeze));
11
+ export function journeySectionId(id){return ({location:'cloud',architecture:'cloud',estimate:'review'})[id]||id;}
12
+ export function designSection(mode,view){
13
+ if(mode==='deploy')return DESIGN_SECTIONS[4];
14
+ if(mode==='estimate'||mode==='review'||view==='terraform')return DESIGN_SECTIONS[3];
15
+ if(view==='location'||view==='decisions')view='options';
16
+ return DESIGN_SECTIONS.find(s=>s.mode===mode&&s.view===view)||DESIGN_SECTIONS[0];
17
+ }
18
+ export function completedStages(p){
19
+ const keys=journeyKeys(p),saved=p.extensions?.journey||{};
20
+ return {board:p.nodes.some(n=>n.data.kind!=='note'),scope:saved.scope===keys.scope,
21
+ cloud:cloudMapping(p).ready&&saved.architecture===keys.architecture,
22
+ review:saved.review===keys.architecture&&saved.estimate===keys.estimate,
23
+ delivery:saved.delivery===keys.delivery}; // Delivery means the exact package was downloaded, not deployed.
24
+ }
25
+ export function journeyAction(guidance,section='board'){
26
+ if(section===journeySectionId(guidance.id)&&guidance.checkpoint&&section!=='board')return {kind:'continue',label:guidance.continueLabel};
27
+ if(section!=='board')return null;
28
+ const destination={scope:['scope','Review requirements'],location:['cloud','Choose country & region'],review:['review','Review design'],estimate:['review','Review costs'],delivery:['delivery','Review delivery']}[guidance.id];
29
+ if(destination)return {kind:'navigate',section:destination[0],label:destination[1]};
30
+ return {kind:guidance.checkpoint?'continue':'assist',label:guidance.checkpoint?guidance.continueLabel:guidance.action};
31
+ }
32
+ const clouds={aws:'AWS',azure:'Azure',gcp:'Google Cloud',ibm:'IBM Cloud'};
33
+ export const CLOUD_SERVICES={
34
+ aws:['Amazon S3','Amazon Bedrock','Bedrock Guardrails','AWS Lambda','Amazon API Gateway','Amazon Cognito','Amazon OpenSearch Serverless','Amazon OpenSearch Service','Amazon DynamoDB','Amazon RDS','Amazon ECS','AWS Fargate','Amazon CloudWatch','AWS IAM','IAM policy','Amazon VPC','AWS KMS','Amazon SageMaker AI','SageMaker AI','Amazon EventBridge','Amazon SQS'],
35
+ azure:['Azure Blob Storage','Azure AI Search','Azure OpenAI','Azure OpenAI Service','Microsoft Foundry','Azure AI Foundry','Azure Functions','Azure Container Apps','Azure API Management','Microsoft Entra ID','Azure Key Vault','Azure Monitor','Azure Cosmos DB','Azure SQL','Azure SQL Database','Azure Virtual Network','Azure App Service','Azure Service Bus'],
36
+ gcp:['Cloud Storage','Google Cloud Storage','Vertex AI','Vertex AI Search','Cloud Run','Cloud Functions','API Gateway','Identity Platform','Cloud IAM','Cloud Logging','Cloud Monitoring','Secret Manager','Cloud SQL','Firestore','BigQuery','Pub/Sub','Google Kubernetes Engine','VPC'],
37
+ ibm:['IBM Cloud Object Storage','watsonx.ai','watsonx.ai Runtime','watsonx model deployment','watsonx Orchestrate','IBM Cloud Code Engine','IBM Cloud IAM','IBM Cloud Databases for PostgreSQL','IBM Db2','IBM Cloud Kubernetes Service','IBM Cloud Secrets Manager','IBM Cloud Logs','IBM Cloud Monitoring','IBM Cloud VPC','IBM Event Streams']
38
+ };
39
+ const choice=(p,subject)=>[...(p.decisions||[])].reverse().find(d=>d.subject===subject&&d.status==='Accepted')?.decision;
40
+ // Compact change fingerprints, not security/authentication tokens or copies of project text.
41
+ const snapshot=value=>{const text=JSON.stringify(value);let a=2166136261,b=5381;for(let i=0;i<text.length;i++){a=Math.imul(a^text.charCodeAt(i),16777619);b=Math.imul(b,33)^text.charCodeAt(i);}return `${text.length}-${(a>>>0).toString(16)}-${(b>>>0).toString(16)}`;};
42
+ export function journeyKeys(p){
43
+ const scope=snapshot([p.brief?.application||p.requirements||'',(p.needs||[]).filter(r=>r.source==='user').map(r=>[r.id,r.statement,r.measure]).sort()]);
44
+ const architecture=snapshot([scope,p.nodes.filter(n=>n.data.kind!=='note').map(n=>[n.id,n.data.label,n.data.service,n.data.provider,n.data.config,n.data.description]).sort(),p.edges.map(e=>[e.source,e.target,e.label]).sort(),choice(p,'platform.cloud'),choice(p,'cloud.region'),choice(p,'data.country')]);
45
+ const estimate=snapshot([architecture,p.estimate||{}]);return {scope,architecture,estimate,delivery:snapshot([architecture,estimate,p.revision])};
46
+ }
47
+ export function cloudMapping(p){
48
+ const provider=choice(p,'platform.cloud');
49
+ const nodes=p.nodes.filter(n=>n.data.kind!=='note'&&n.data.origin!=='existing');
50
+ const services=CLOUD_SERVICES[provider]||[];
51
+ const gaps=nodes.flatMap(n=>{
52
+ const errors=[];
53
+ // This acknowledges a named working draft, never service availability or
54
+ // implementation support. Examples are a legacy label fallback, not a registry.
55
+ const explicit=typeof n.data.service==='string'&&n.data.service.trim()&&!/^(?:storage|compute|database|service|api|ai|unknown|tbd|to be .*|select.*)$/i.test(n.data.service.trim());
56
+ if(n.data.provider!==provider || !(explicit||services.some(s=>s.toLowerCase()===String(n.data.label||'').toLowerCase())))errors.push(`${n.data.label}: choose a named ${clouds[provider]||'cloud'} service`);
57
+ if(!n.data.config?.region||/select|unknown|tbd/i.test(n.data.config.region))errors.push(`${n.data.label}: clarify regional or global placement`);
58
+ return errors;
59
+ });
60
+ if(nodes.length>1&&!p.edges.length)gaps.push('Connect the cloud services and describe the interactions');
61
+ for(const edge of p.edges)if(!edge.label || /^(data|flow|connection)$/i.test(edge.label))gaps.push('Describe what each service connection carries');
62
+ if(!nodes.length)gaps.push('No proposed cloud services are drawn yet');
63
+ if(provider&&!Object.hasOwn(CLOUD_SERVICES,provider))gaps.push('The selected cloud has no reviewed journey mapping; preserve the target and clarify its support.');
64
+ return {provider,ready:Object.hasOwn(CLOUD_SERVICES,provider)&&nodes.length>0&&!gaps.length,gaps,boundary:'named_working_draft_only'};
65
+ }
66
+ export function journey(p){
67
+ const keys=journeyKeys(p),saved=p.extensions?.journey||{},mapping=cloudMapping(p);
68
+ const base={keys,mapping,availableModes:['design']};
69
+ const step=(id,title,reason,action,mode,view,prompt,extra={})=>({...base,id,title,reason,action,mode,view,prompt,...extra});
70
+ if(!p.nodes.some(n=>n.data.kind!=='note'))return step('idea','Sketch your idea','Tell me the outcome you want. We’ll draw it and clarify the requirements together.','Help me shape the idea','design','board','Help me shape my idea. Ask one useful question about the desired outcome; draw only from what I tell you.');
71
+ if(saved.scope!==keys.scope)return step('scope','Sketch and document','We have a first design. Let’s check that the document captures what you want before choosing cloud services.','Work through this design','design','requirements','Review the board and requirements together. Briefly summarise the intended outcome and ask the most important unresolved scope question. Update the document from the discussion. Do not jump to costs or deployment.',{checkpoint:'scope',continueLabel:'Continue to cloud options'});
72
+ if(!mapping.provider)return step('cloud','Explore cloud solutions','We’ll compare how AWS, Azure, Google Cloud and IBM would implement this scope, then choose together.','Explore cloud options','design','options','Compare AWS, Azure, Google Cloud and IBM for our agreed working scope. Populate optionAssessment with actual service combinations for each option, integration tradeoffs and unknowns. Ask one question about existing systems or cloud preference. Do not assume a choice.');
73
+ if(!choice(p,'data.country')&&!choice(p,'cloud.region'))return step('location','Choose where it will run',`We’re exploring ${clouds[mapping.provider]}. Country and data residency determine which services and regions fit.`,'Discuss country and residency','design','board',`We have chosen ${clouds[mapping.provider]}. Ask which country the users and data should be in, and whether data must stay there. Offer regional choices after the answer; do not silently select a country.`);
74
+ if(!mapping.ready || saved.architecture!==keys.architecture)return step('architecture',`Build the ${clouds[mapping.provider]} architecture`,mapping.ready?'The board now names cloud services. Let’s check how they connect and what still needs validating.':'Translate the concept into named cloud services, their responsibilities, connections and regional placement.','Develop the cloud architecture','design','board',`Create or refine a concrete ${clouds[mapping.provider]} architecture for our scope and chosen country/region. Return a complete graph proposal using real named services in data.service and data.label, explicit responsibilities in descriptions, meaningful connection labels and region placement. Preserve existing systems and comments. Explain the mapping and ask one useful refinement question. Identify unverified regional availability and integration assumptions. Service candidates: ${CLOUD_SERVICES[mapping.provider].join(', ')}. Current mapping gaps: ${mapping.gaps.join('; ')||'none; discuss the integrations and remaining assumptions'}.`,{checkpoint:mapping.ready?'architecture':null,continueLabel:'Review this cloud design'});
75
+ base.availableModes=['design','review'];
76
+ if(saved.review!==keys.architecture)return step('review','Check the design together','We have a concrete service design. Let’s examine security, resilience, integration gaps and the assumptions that need validation.','Walk through the design risks','review','board','Review the concrete cloud architecture against our requirements. Explain the highest-impact risk or integration assumption, identify verification needed, and ask one question. A diagram is not evidence that services work together.',{checkpoint:'review',continueLabel:'Estimate with the remaining risks recorded'});
77
+ base.availableModes=['design','review','estimate'];
78
+ if(saved.estimate!==keys.estimate)return step('estimate','Build the cost estimate','We’ll use the actual services and ask about usage, then model sourced running costs and implementation effort.','Work through the costs','estimate','board','Estimate the concrete cloud architecture progressively. Use sourced prices where supported. Ask the single missing usage/model/scale question with the biggest effect. Separate cloud running cost and delivery effort, and keep missing rates explicit.',{checkpoint:'estimate',continueLabel:'Prepare a delivery draft with cost gaps noted'});
79
+ base.availableModes=['design','review','estimate','deploy'];
80
+ return step('delivery','Review the handoff','Inspect the captured implementation, requirements and exact check evidence. Missing implementation or validation remains visible.','Review delivery','design','outputs','Review the actual delivery package and its requirements, implementation, infrastructure and recorded checks. Explain the next engineering task from that evidence. Treat design-only output, missing or stale implementation and unexecuted checks explicitly. Do not claim cloud availability, deployment or full project acceptance from a diagram or local check.');
81
+ }
82
+ export function advanceJourney(p,checkpoint){
83
+ const state=journey(p);
84
+ if(state.checkpoint!==checkpoint)return p;
85
+ const key=checkpoint==='review'?'architecture':checkpoint;
86
+ return {...p,extensions:{...p.extensions,journey:{...p.extensions?.journey,[checkpoint]:state.keys[key]}}};
87
+ }
88
+
89
+ // Explicit completion actions acknowledge a working draft; navigation never does.
90
+ export function acknowledgeStage(p,stage){
91
+ const keys=journeyKeys(p),previous=p.extensions?.journey||{},saved={...previous};
92
+ if(stage==='scope'&&(p.needs?.length||p.brief?.application?.trim()))saved.scope=keys.scope;
93
+ if(stage==='cloud'&&cloudMapping(p).ready)saved.architecture=keys.architecture;
94
+ if(stage==='review')saved.review=keys.architecture;
95
+ if(stage==='delivery')saved.delivery=keys.delivery;
96
+ return {...p,extensions:{...p.extensions,journey:saved}};
97
+ }