@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,82 @@
1
+ import {existingDeployment} from './deployment-ownership.mjs';
2
+ import {sha256} from '@noble/hashes/sha2.js';
3
+ const canonical=v=>Array.isArray(v)?v.map(canonical):plain(v)?Object.fromEntries(Object.keys(v).sort().map(k=>[k,canonical(v[k])])):v;
4
+ const bytes=v=>new TextEncoder().encode(v).length;
5
+ const plain=v=>v!==null&&typeof v==='object'&&!Array.isArray(v)&&[Object.prototype,null].includes(Object.getPrototypeOf(v));
6
+ const fail=()=>{throw Error('Invalid approval application declaration; no fields were discarded.');};
7
+ const exact=(v,keys)=>{if(!plain(v)||Object.keys(v).length!==keys.length||keys.some(k=>!Object.hasOwn(v,k)))fail();};
8
+ const integer=(v,min,max)=>Number.isSafeInteger(v)&&v>=min&&v<=max;
9
+ function json(value,depth=0){
10
+ if(depth>32)fail();
11
+ if(typeof value==='string'){try{encodeURIComponent(value);}catch{fail();}}
12
+ else if(Array.isArray(value))value.forEach(v=>json(v,depth+1));
13
+ else if(plain(value))Object.values(value).forEach(v=>json(v,depth+1));
14
+ else if(value!==null&&typeof value!=='boolean'&&!Number.isSafeInteger(value))fail();
15
+ }
16
+ function schema(v,depth,budget){
17
+ if(depth>8||--budget.count<0||!plain(v))fail();
18
+ const shapes={object:['type','properties','required'],array:['type','items','maxItems'],string:['type','minBytes','maxBytes'],integer:['type','minimum','maximum'],boolean:['type'],enum:['type','values']};
19
+ if(!Object.hasOwn(shapes,v.type))fail();exact(v,shapes[v.type]);
20
+ if(v.type==='object'){
21
+ if(!plain(v.properties)||Object.keys(v.properties).length<1||Object.keys(v.properties).length>32||Object.keys(v.properties).some(k=>!/^[A-Za-z][A-Za-z0-9_]{0,79}$/.test(k))||!Array.isArray(v.required)||new Set(v.required).size!==v.required.length||v.required.some(k=>typeof k!=='string'||!Object.hasOwn(v.properties,k)))fail();
22
+ Object.values(v.properties).forEach(s=>schema(s,depth+1,budget));
23
+ }else if(v.type==='array'){if(!integer(v.maxItems,1,64))fail();schema(v.items,depth+1,budget);}
24
+ else if(v.type==='string'){if(!integer(v.minBytes,0,64000)||!integer(v.maxBytes,v.minBytes,64000))fail();}
25
+ else if(v.type==='integer'){if(!Number.isSafeInteger(v.minimum)||!Number.isSafeInteger(v.maximum)||v.minimum>v.maximum)fail();}
26
+ else if(v.type==='enum'){if(!Array.isArray(v.values)||v.values.length<1||v.values.length>64||new Set(v.values).size!==v.values.length||v.values.some(s=>typeof s!=='string'||bytes(s)<1||bytes(s)>256))fail();}
27
+ }
28
+ const IDENTITY={aws:['REGION','POOL_ID','CLIENT_ID','AUTH_ORIGIN','AUTH_SCOPE'],azure:['TENANT_ID','API_CLIENT_ID','SPA_CLIENT_ID'],gcp:['PROJECT_NUMBER','REGION','SERVICE_NAME'],ibm:['APPID_TENANT_ID','APPID_CLIENT_ID','APPID_ISSUER','AUTH_SCOPE']};
29
+ export function validateApprovalProfile(v){
30
+ if(v?.format==='approval-application-template-v1')return validateApprovalTemplate(v);
31
+ json(v);if(bytes(JSON.stringify(v))>64000)fail();
32
+ exact(v,['format','provider','componentId','environment','accountId','publicOrigin','operationKind','identitySettings','payloadContract','destinationContract']);
33
+ if(v.format!=='approval-application-v1'||!Object.hasOwn(IDENTITY,v.provider)||typeof v.componentId!=='string'||bytes(v.componentId)<1||bytes(v.componentId)>512||/[\x00-\x1f]/.test(v.componentId)||!['staging','production','qualification'].includes(v.environment)||!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(v.accountId)||!['document','draft','account_change'].includes(v.operationKind))fail();
34
+ try{
35
+ const p=new URL(v.publicOrigin),tail=v.publicOrigin.slice(v.publicOrigin.indexOf('://')+3);
36
+ if(typeof v.publicOrigin!=='string'||/[^\x21-\x7e]/.test(v.publicOrigin)||/[/?#]/.test(tail)||p.username||p.password||!p.hostname||p.port&&(!integer(Number(p.port),1,65535))||p.protocol!=='https:'&&!(p.protocol==='http:'&&['localhost','127.0.0.1','[::1]'].includes(p.hostname)))fail();
37
+ }catch{fail();}
38
+ exact(v.identitySettings,IDENTITY[v.provider]);if(Object.values(v.identitySettings).some(s=>typeof s!=='string'||bytes(s)<1||bytes(s)>2000))fail();
39
+ const p=v.payloadContract;exact(p,['version','id','source','result']);if(p.version!==1||typeof p.id!=='string'||!/^[a-z][a-z0-9-]{0,79}$/.test(p.id)||bytes(JSON.stringify(p))>64000)fail();
40
+ const budget={count:256};for(const side of ['source','result']){schema(p[side],0,budget);if(p[side].type!=='object')fail();}
41
+ const d=v.destinationContract;const keys=['id','endpointSha256','scope','mappingVersion'];if(Object.hasOwn(d||{},'payloadContractSha256'))keys.push('payloadContractSha256');exact(d,keys);
42
+ if(typeof d.id!=='string'||!/^[a-z0-9-]{1,80}$/.test(d.id)||typeof d.endpointSha256!=='string'||!/^[0-9a-f]{64}$/.test(d.endpointSha256)||typeof d.scope!=='string'||d.scope.length<1||d.scope.length>200||/[^\x21-\x7e]/.test(d.scope)||!integer(d.mappingVersion,1,10000)||d.payloadContractSha256!==undefined&&!/^[0-9a-f]{64}$/.test(d.payloadContractSha256))fail();
43
+ if(d.payloadContractSha256!==undefined){const hash=Array.from(sha256(new TextEncoder().encode(JSON.stringify(canonical(p)))),b=>b.toString(16).padStart(2,'0')).join('');if(hash!==d.payloadContractSha256)fail();}
44
+ return structuredClone(v);
45
+ }
46
+ export function outputReference(v){
47
+ exact(v,['nativeOutput']);const r=v.nativeOutput;exact(r,['componentId','provider','environment','name']);
48
+ if(typeof r.componentId!=='string'||bytes(r.componentId)<1||bytes(r.componentId)>512||/[\x00-\x1f]/.test(r.componentId)||!['aws','azure','gcp','ibm','tools'].includes(r.provider)||!['staging','production','qualification'].includes(r.environment)||typeof r.name!=='string'||!/^[A-Za-z][A-Za-z0-9_]{0,79}$/.test(r.name)||/secret|password|credential|private_?key/i.test(r.name))fail();
49
+ return r;
50
+ }
51
+ export function approvalReferences(v){
52
+ const refs=[];
53
+ if(plain(v.publicOrigin))refs.push({path:'publicOrigin',...outputReference(v.publicOrigin)});
54
+ for(const section of ['identitySettings','destinationContract'])for(const[key,value]of Object.entries(v[section]||{}))if(plain(value))refs.push({path:section+'/'+key,...outputReference(value)});
55
+ return refs;
56
+ }
57
+ function validateApprovalTemplate(v){
58
+ json(v);if(bytes(JSON.stringify(v))>64000)fail();const trial=structuredClone(v);trial.format='approval-application-v1';
59
+ const refs=approvalReferences(v);if(!refs.length)fail();
60
+ for(const r of refs){
61
+ if(r.environment!==v.environment||r.path.startsWith('identitySettings/')&&r.provider!==v.provider)fail();
62
+ if(r.path==='publicOrigin')trial.publicOrigin='https://unresolved.invalid';
63
+ else if(r.path.startsWith('identitySettings/'))trial.identitySettings[r.path.split('/')[1]]='UNRESOLVED_NATIVE_OUTPUT';
64
+ else if(['destinationContract/endpointSha256','destinationContract/scope'].includes(r.path))trial.destinationContract[r.path.split('/')[1]]=r.path.endsWith('endpointSha256')?'0'.repeat(64):'unresolved';
65
+ else fail();
66
+ }
67
+ validateApprovalProfile(trial);return structuredClone(v);
68
+ }
69
+ export function approvalProfiles(project){
70
+ const selected=[];
71
+ for(const node of project.nodes||[]){
72
+ if(node.data?.approvalProfile===undefined||node.data.approvalProfile===null)continue;
73
+ const profile=validateApprovalProfile(node.data.approvalProfile);
74
+ if(node.data.kind==='note'||node.data.binding||node.data.implementation!=='approval-workflow'||node.data.provider!==profile.provider||node.id!==profile.componentId||existingDeployment(node)||node.data.origin!==undefined&&node.data.origin!=='proposed')throw Error('Approval application must bind its exact proposed component/provider; preserve existing ownership.');
75
+ for(const ref of approvalReferences(profile)){
76
+ const source=project.nodes.find(n=>n.id===ref.componentId);
77
+ if(!source||source.data.kind==='note'||source.data.provider!==ref.provider)throw Error('Native output reference must retain an existing graph component/provider; no source was substituted.');
78
+ }
79
+ selected.push({node,profile});
80
+ }
81
+ return selected;
82
+ }
@@ -0,0 +1,30 @@
1
+ import {approvalProfiles,approvalReferences} from './approval-applications.mjs';
2
+ import {resourceAddress} from './identifiers.mjs';
3
+ export function applyApprovalTasks(project,files,tasks){
4
+ for(const {node,profile}of approvalProfiles(project)){
5
+ const root='terraform/applications/'+resourceAddress(node.id)+'/',deferred=profile.format==='approval-application-template-v1',metadata=deferred?'application-template.json':'application-profile.json';
6
+ const parent=tasks.find(t=>t.id.startsWith('TASK-RESOURCE-')&&t.componentIds?.includes(node.id));
7
+ if(!parent)throw Error('Selected application lost its component implementation task.');
8
+ const paths=Object.keys(files).filter(p=>p.startsWith(root));parent.files=[...new Set([...(parent.files||[]),...paths])];
9
+ parent.steps.push('Read '+root+metadata+', api.py and assembly-status.json. This is shared API source only; implement provider resources and the complete domain/worker behavior without deleting requirements or clearing work gates.');
10
+ const id='TASK-APP-ASSEMBLY-'+resourceAddress(node.id);
11
+ parent.dependsOn=[...new Set([...(parent.dependsOn||[]),id])];
12
+ tasks.push({id,phase:'Implementation',title:'Implement the selected approval application source: '+node.data.label,dependsOn:['TASK-SETUP','TASK-SECURITY-DESIGN'],componentIds:[node.id],requirementIds:parent.requirementIds||[],files:paths,steps:[
13
+ 'Retain exact component/provider/environment/account and complete requirements; reconcile '+profile.environment+' against the intended deployment environment.',
14
+ 'Build the emitted API image using the exact lock and native profile. Review native identity/database/API-role and worker-role environment bindings; keep credentials outside source.',
15
+ 'Implement a real domain processor and concrete worker entrypoint using create_native_worker; use the profile-bound destination and membership_key for explicitly admitted native users. Do not substitute fixture behavior or metadata-selected imports.',
16
+ 'Run clean local HTTP/queue/SQL/TLS positive and negative source checks including changed policy, authorization, idempotency and unknown effects. Record fixture boundaries; the dependent component/integration tasks still own provider resources and real destination compatibility.'
17
+ ],outputs:['Explicit runtime/profile input contract','Concrete domain source and worker entrypoint','Artifact-bound local source/integration evidence'],acceptance:['All linked requirements retain their original text/ownership.','API/worker/domain source has independent executable checks.','Provider linkage, schema/mocks and whole-system acceptance remain separate dependent work.']});
18
+ if(deferred){
19
+ const refs=approvalReferences(profile),bindingId='TASK-APP-BINDING-'+resourceAddress(node.id);
20
+ const sourceTasks=[...new Set(refs.map(ref=>tasks.find(t=>t.id.startsWith('TASK-RESOURCE-')&&t.componentIds?.includes(ref.componentId))?.id))];
21
+ if(sourceTasks.includes(undefined))throw Error('Application output source lost its component task.');
22
+ tasks.push({id:bindingId,phase:'Implementation',title:'Resolve public runtime inputs: '+node.data.label,dependsOn:[...new Set([id,parent.id,...sourceTasks])],componentIds:[...new Set([node.id,...refs.map(r=>r.componentId)])],requirementIds:parent.requirementIds||[],files:[root+metadata,root+'resolve-profile.py',root+'workflow_bindings.py'],steps:[
23
+ 'Build source independently of unresolved outputs. When the owned resources or explicit local fixtures supply their outputs, review exact component/provider/environment and source digests; do not invent native IDs or put credentials in the public ledger.',
24
+ 'Run python -I '+root+'resolve-profile.py --outputs /ABSOLUTE/PUBLIC-OUTPUT-LEDGER.json --out /ABSOLUTE/FRESH-BINDING-DIRECTORY. Mount that bundle read-only as runtime-binding before starting the API; reject missing, stale or mismatched receipts.',
25
+ 'Record structural resolution separately from real source/cloud identity, authorization and operating acceptance. Local fixtures must remain labelled; no cloud operation is authorized by this task.'
26
+ ],outputs:['Fresh application-profile.json and matching binding-receipt.json outside source control','Exact input/artifact digests and disclosed fixture boundaries'],acceptance:['No fallback or fixed ownership/policy change.','Unresolved and mismatched bundles fail before native runtime setup.','Connected acceptance uses the exact resolved application declaration.']});
27
+ for(const task of tasks)if(task.id==='TASK-E2E'||task.id.startsWith('TASK-ACCEPTANCE-')&&task.componentIds?.includes(node.id))task.dependsOn=[...new Set([...task.dependsOn,bindingId])];
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,28 @@
1
+ .build-design-button { gap:6px; white-space:normal; }
2
+ .conversation-activity { min-width:0; }
3
+ .turn-activity { min-width:0; margin:5px 0 12px; color:var(--muted); font-size:12px; }
4
+ .turn-activity-row { display:flex; gap:8px; align-items:center; min-width:0; }
5
+ .turn-activity-toggle { display:flex; align-items:center; min-width:0; flex:1; gap:5px; border:0; border-radius:5px; padding:5px 2px; min-height:30px; background:transparent; color:inherit; font:inherit; text-align:left; cursor:pointer; }
6
+ .turn-activity-toggle:hover { color:var(--ink); }
7
+ .turn-activity-toggle:focus-visible,.turn-inline-action:focus-visible { outline:2px solid var(--action); outline-offset:3px; }
8
+ .turn-activity-label { flex-shrink:0; }
9
+ .turn-latest { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
10
+ .turn-chevron { margin-left:auto; padding-left:4px; }
11
+ .turn-state-icon { display:inline-block; width:14px; text-align:center; flex-shrink:0; }
12
+ .turn-state-icon.is-working { animation:turn-working 1.5s linear infinite; }
13
+ .turn-inline-action { flex-shrink:0; border:0; background:transparent; color:var(--muted); text-decoration:underline; font:inherit; min-height:30px; padding:4px; cursor:pointer; }
14
+ .turn-activity-details { margin:2px 0 0 7px; padding:2px 0 2px 14px; border-left:1px solid var(--line); overflow-wrap:anywhere; }
15
+ .turn-activity-details ol { list-style:none; margin:0; padding:0; }
16
+ .turn-activity-details li { padding:4px 0; margin:0; }
17
+ .turn-activity-details p { margin:3px 0; }
18
+ .turn-selection { font-size:11px; color:var(--muted); margin-bottom:8px; }
19
+ .turn-activity-details .chat-markdown { color:var(--ink); }
20
+ .turn-activity-details pre { white-space:pre-wrap; overflow-wrap:anywhere; }
21
+ .legacy-activity { border-block:1px solid var(--line); margin:10px 0; color:var(--muted); font-size:12px; }
22
+ .legacy-activity > summary { padding:9px 2px; cursor:pointer; }
23
+ .legacy-activity > p { margin:4px 0 8px; }
24
+ .turn-activity.has-error .turn-activity-label { color:var(--color-error,#a82837); }
25
+ @keyframes turn-working { to { transform:rotate(360deg); } }
26
+ @media (prefers-reduced-motion:reduce) { .turn-state-icon.is-working { animation:none; } }
27
+
28
+ @media (max-width:480px) { .turn-activity-toggle,.turn-inline-action { min-height:40px; } }
@@ -0,0 +1,63 @@
1
+ export const ACTIVITY_KINDS=['context_started','context_ready','pass_started','model_started','model_message','model_checked','response_repair','tool_started','tool_finished','tool_cached','response_ready','failed','cancelled'];
2
+ export function architectureTurns(project){
3
+ const value=project.extensions?.architectureActivity;
4
+ if(value===undefined)return [];
5
+ if(value.version!==1||!Array.isArray(value.turns)||value.turns.length>1000)throw Error('Unsupported or oversized architecture activity history. Keep the original project file.');
6
+ const seen=new Set();
7
+ for(const t of value.turns){if(t?.requestIds!==undefined&&(!Array.isArray(t.requestIds)||t.requestIds.length>1000||t.requestIds.some(id=>typeof id!=='string'||id.length>100)))throw Error('Invalid architecture request association.');if(!t||typeof t.id!=='string'||!/^[a-f0-9-]{36}$/.test(t.id)||seen.has(t.id)||typeof t.model!=='string'||typeof t.provider!=='string'||!['submitted','response_received','failed','cancelled'].includes(t.clientStatus))throw Error('Invalid architecture turn identity.');seen.add(t.id);}
8
+ return value.turns;
9
+ }
10
+ export function recordArchitectureTurn(project,owner,turn){
11
+ if(project.id!==owner)return project;
12
+ const turns=architectureTurns(project);
13
+ if(turns.some(t=>t.id===turn.id))throw Error('Architecture turn is already recorded; no request was replayed.');
14
+ const value={version:1,turns:[...turns,{...turn,clientStatus:'submitted'}]};architectureTurns({extensions:{architectureActivity:value}});
15
+ return {...project,extensions:{...project.extensions,architectureActivity:value}};
16
+ }
17
+ export function finishArchitectureTurn(project,owner,id,clientStatus,detailsAvailable){
18
+ if(project.id!==owner)return project;
19
+ const turns=architectureTurns(project);if(!turns.some(t=>t.id===id))return project;
20
+ const value={version:1,turns:turns.map(t=>t.id===id?{...t,clientStatus,...(detailsAvailable===undefined?{}:{detailsAvailable})}:t)};architectureTurns({extensions:{architectureActivity:value}});
21
+ return {...project,extensions:{...project.extensions,architectureActivity:value}};
22
+ }
23
+ // Exact request/reply associations keep activity inside the conversation. Older
24
+ // unbound records stay in turn order before the next associated turn; never guess
25
+ // that an unrelated reply belongs to them or discard historical activity.
26
+ export function architectureConversation(project,messages){
27
+ let turns;try{turns=architectureTurns(project);}catch(error){return [...messages.map((message,index)=>({kind:'message',message,index})),{kind:'activity-error',error:error.message}];}
28
+ const positions=turns.map(turn=>{
29
+ const requests=messages.flatMap((m,i)=>m.role==='user'&&turn.requestIds?.includes(m.requestId)?[i]:[]);
30
+ if(requests.length)return Math.max(...requests)+1;
31
+ const reply=messages.findIndex(m=>m.activityId===turn.id);return reply<0?null:reply;
32
+ });
33
+ const slots=new Map();turns.forEach((turn,i)=>{
34
+ const at=positions[i]??positions.slice(i+1).find(p=>p!==null)??messages.length;
35
+ const entries=slots.get(at)||[];entries.push({kind:'activity',turn,number:i+1,unassociated:positions[i]===null});slots.set(at,entries);
36
+ });
37
+ return Array.from({length:messages.length+1},(_,i)=>[...(slots.get(i)||[]),...(i<messages.length?[{kind:'message',message:messages[i],index:i}]:[])]).flat();
38
+ }
39
+ export function mergeArchitectureActivity(current,incoming){
40
+ const map=new Map(current.map(e=>[e.sequence,e]));
41
+ for(const e of incoming){
42
+ if(!Number.isSafeInteger(e.sequence)||e.sequence<1||!ACTIVITY_KINDS.includes(e.kind)||typeof e.text!=='string'||e.text.length>16000)throw Error('The service returned unsupported activity details.');
43
+ if(map.has(e.sequence)&&JSON.stringify(map.get(e.sequence))!==JSON.stringify(e))throw Error('A recorded activity event changed identity.');
44
+ map.set(e.sequence,e);
45
+ }
46
+ return [...map.values()].sort((a,b)=>a.sequence-b.sequence);
47
+ }
48
+ export async function readArchitectureActivity(session,projectId,id,after,signal,fetcher=fetch){
49
+ const r=await fetcher('/api/architect/activity',{method:'POST',headers:{'Content-Type':'application/json',Authorization:'Bearer '+session.token},body:JSON.stringify({projectId,activityId:id,after}),signal});
50
+ if(!r.ok){const error=Error(r.status===404?'Detailed activity is not recorded in this service for this turn.':'Architecture activity could not be loaded.');error.status=r.status;throw error;}
51
+ const value=await r.json();if(value.id!==id||value.projectId!==projectId||!Array.isArray(value.events))throw Error('Activity does not belong to this project and turn.');return value;
52
+ }
53
+
54
+ export function architectureChatEntries(project,messages){
55
+ const entries=[];
56
+ for(const entry of architectureConversation(project,messages)){
57
+ if(entry.kind==='activity'&&entry.unassociated){
58
+ const previous=entries.at(-1);if(previous?.kind==='legacy-activity')previous.entries.push(entry);
59
+ else entries.push({kind:'legacy-activity',id:'legacy:'+entry.turn.id,entries:[entry]});
60
+ }else entries.push(entry);
61
+ }
62
+ return entries;
63
+ }
@@ -0,0 +1,176 @@
1
+ import {approvalReferences} from './approval-applications.mjs';
2
+ // Shared context/dependency model. Currency means exact context agreement, never
3
+ // proof that a claimed implementation, test, account plan or deployment succeeded.
4
+ import {engineeringConversation} from './engineering-client.mjs';
5
+ import {externalIdentity} from './external-identities.mjs';
6
+ export const WORK_VERSION=2;
7
+ export const WORK_KINDS=['responsibility','delivery-unit','interface','implementation','assumption','decision','evidence','requirement'];
8
+ const clone=value=>JSON.parse(JSON.stringify(value));
9
+ const order=(a,b)=>a<b?-1:a>b?1:0;
10
+ const plain=value=>value!==null&&typeof value==='object'&&!Array.isArray(value);
11
+ export function canonicalWork(value){
12
+ return JSON.stringify(value,(_,v)=>plain(v)?Object.fromEntries(Object.keys(v).sort().map(k=>[k,v[k]])):v);
13
+ }
14
+ function text(value,max,name){if(typeof value!=='string'||!value.trim()||[...value].length>max)throw Error(`Invalid ${name}; no content was truncated.`);return value;}
15
+ function only(value,keys,name){if(!plain(value)||Object.keys(value).some(k=>!keys.includes(k)))throw Error(`Invalid ${name} shape; retain the original file.`);}
16
+ function ref(value){return text(value,240,'work reference');}
17
+ function array(value,max,name){if(!Array.isArray(value)||value.length>max)throw Error(`Invalid or oversized ${name}; no records were discarded.`);}
18
+ function assertWorkJSON(v,depth=0){if(depth>40)throw Error('Architecture work is nested too deeply.');if(v===null||typeof v==='string'||typeof v==='boolean')return;if(typeof v==='number'&&Number.isFinite(v))return;if(Array.isArray(v)){v.forEach(x=>assertWorkJSON(x,depth+1));return;}if(plain(v)&&[Object.prototype,null].includes(Object.getPrototypeOf(v))){Object.values(v).forEach(x=>assertWorkJSON(x,depth+1));return;}throw Error('Work data must be lossless finite JSON values.');}
19
+
20
+ export function emptyArchitectureWork(){return {version:WORK_VERSION,records:[],intents:[],snapshots:[],bindings:[],history:[],artifactMappings:[]};}
21
+ export function validateArchitectureWork(value){
22
+ if(value===undefined)return emptyArchitectureWork();
23
+ if(value.version===1){only(value,['version','records','intents','snapshots','bindings','history'],'legacy architecture work');value={...value,version:WORK_VERSION,artifactMappings:[]};}
24
+ only(value,['version','records','intents','snapshots','bindings','history','artifactMappings'],'architecture work');
25
+ if(value.version!==WORK_VERSION)throw Error('Unsupported architecture work version; retain the file and use a compatible reader.');
26
+ for(const key of ['records','intents','snapshots','bindings','history','artifactMappings'])array(value[key],key==='snapshots'?4000:1000,key);
27
+ const unique=(items,key,name)=>{const seen=new Set();for(const item of items){const id=ref(item[key]);if(seen.has(id))throw Error(`Duplicate ${name}: ${id}`);seen.add(id);}};
28
+ unique(value.records,'id','work record');unique(value.intents,'id','engineering intent');unique(value.snapshots,'id','context snapshot');unique(value.bindings,'ref','context binding');
29
+ for(const r of value.records){
30
+ only(r,['id','kind','title','description','source','agreement','dependsOn','data'],'work record');
31
+ if(!WORK_KINDS.includes(r.kind)||!['user','agent','import'].includes(r.source)||!['proposed','accepted'].includes(r.agreement))throw Error('Record explicit work kind, provenance and agreement.');
32
+ text(r.id,200,'work record ID');text(r.title,200,'work title');if(typeof r.description!=='string'||[...r.description].length>16000||!plain(r.data))throw Error('Invalid work description/data; no content was truncated.');
33
+ array(r.dependsOn,100,'work dependencies');r.dependsOn.forEach(ref);if(new Set(r.dependsOn).size!==r.dependsOn.length)throw Error('Duplicate work dependency.');
34
+ if(r.kind==='implementation'&&r.data.files!==undefined){array(r.data.files,200,'implementation files');for(const file of r.data.files){text(file,500,'implementation path');if(file.startsWith('/')||/^[A-Za-z]:/.test(file)||/[\x00-\x1f]/.test(file)||file.includes('\\')||file.split('/').some(p=>!p||p==='.'||p==='..'))throw Error('Implementation paths must be relative project files.');}}
35
+ }
36
+ for(const i of value.intents){
37
+ only(i,['id','sessionId','sequence','text','status'],'engineering intent');text(i.sessionId,100,'session ID');text(i.text,80000,'engineering intent');
38
+ if(!Number.isSafeInteger(i.sequence)||i.sequence<1||!['accepted','pending','uncertain'].includes(i.status))throw Error('Invalid engineering intent identity/status.');
39
+ if(i.id!==`${i.sessionId}:${i.sequence}`)throw Error('Engineering intent identity differs from its session/sequence.');
40
+ }
41
+ const snapshots=new Map(value.snapshots.map(s=>[s.id,s]));
42
+ for(const s of value.snapshots){only(s,['id','ref','value'],'context snapshot');ref(s.ref);if(!plain(s.value)||s.value.id!==s.ref)throw Error('Invalid context snapshot value.');}
43
+ for(const b of [...value.bindings,...value.history]){
44
+ only(b,['ref','snapshotIds','recordedAt','recordedBy','scope'],'context binding');array(b.snapshotIds,2000,'binding sources');b.snapshotIds.forEach(ref);
45
+ if(new Set(b.snapshotIds).size!==b.snapshotIds.length||!b.snapshotIds.length||b.snapshotIds.some(id=>!snapshots.has(id)))throw Error('A context binding needs unique retained source snapshots.');
46
+ const refs=b.snapshotIds.map(id=>snapshots.get(id).ref);if(new Set(refs).size!==refs.length||!refs.includes(b.ref))throw Error('A binding must retain its own source exactly once.');
47
+ if(b.scope!=='context_review_only'||!['user','agent','import'].includes(b.recordedBy)||!/^\d{4}-\d\d-\d\dT/.test(b.recordedAt)||!Number.isFinite(Date.parse(b.recordedAt)))throw Error('Context review is distinct from executed evidence.');
48
+ }
49
+ unique(value.artifactMappings,'id','artifact mapping receipt');
50
+ for(const m of value.artifactMappings){
51
+ only(m,['id','receiptSha256','sessionId','runId','artifactId','artifactSha256','proposalSha256','contextId','contextRevision','contextSha256','definitionSha256','records','files','sourceSnapshotIds','recordedAt','scope'],'artifact mapping');
52
+ for(const key of ['id','sessionId','runId','artifactId','contextId'])text(m[key],100,key);
53
+ for(const key of ['receiptSha256','artifactSha256','proposalSha256','contextSha256','definitionSha256'])if(!/^[a-f0-9]{64}$/.test(m[key]))throw Error('Artifact references require exact SHA-256 digests.');
54
+ if(m.scope!=='artifact_file_binding_only'||!Number.isSafeInteger(m.contextRevision)||m.contextRevision<1||!Number.isFinite(Date.parse(m.recordedAt)))throw Error('Artifact file binding is distinct from execution or acceptance.');
55
+ array(m.records,200,'artifact records');if(!m.records.length)throw Error('Empty artifact mapping receipt.');
56
+ validateArchitectureWork({...emptyArchitectureWork(),records:m.records});
57
+ if(m.records.some(r=>r.source!=='agent'||r.agreement!=='proposed'))throw Error('Artifact mappings remain proposed.');
58
+ array(m.files,2000,'artifact file bindings');const paths=new Set();
59
+ for(const file of m.files){only(file,['path','bytes','sha256'],'artifact file binding');if(paths.has(file.path)||!Number.isSafeInteger(file.bytes)||file.bytes<0||!/^[a-f0-9]{64}$/.test(file.sha256))throw Error('Invalid artifact file binding.');paths.add(file.path);}
60
+ for(let i=0;i<m.files.length;i+=200)validateArchitectureWork({...emptyArchitectureWork(),records:[{id:'file-paths',kind:'implementation',title:'File paths',description:'',source:'agent',agreement:'proposed',dependsOn:[],data:{files:m.files.slice(i,i+200).map(f=>f.path)}}]});
61
+ array(m.sourceSnapshotIds,4000,'artifact basis');const refs=new Set();
62
+ for(const id of m.sourceSnapshotIds){const source=snapshots.get(id);if(!source||refs.has(source.ref))throw Error('Artifact basis must retain unique exact source snapshots.');refs.add(source.ref);}
63
+ if(!refs.has('project:identity'))throw Error('Artifact basis must retain its project identity.');
64
+ }
65
+ assertWorkJSON(value);
66
+ const encoded=JSON.stringify(value);if(new TextEncoder().encode(encoded).length>1_500_000)throw Error('Architecture work history exceeds its storage bound; retain/archive it before adding more. Nothing was discarded.');
67
+ return clone(value);
68
+ }
69
+ const stateOf=project=>validateArchitectureWork(project.extensions?.architectureWork);
70
+ function store(project,state){validateArchitectureWork(state);return {...project,extensions:{...project.extensions,architectureWork:state}};}
71
+
72
+ export function architectureSources(project,state=stateOf(project)){
73
+ const entries=[];const add=(id,kind,title,value,dependsOn=[])=>entries.push({id,kind,title,value:clone(value),dependsOn:[...new Set([...(id==='project:identity'?[]:['project:identity']),...dependsOn])].sort()});
74
+ add('project:identity','identity','Project identity',{id:project.id||null});
75
+ const annotations=(project.nodes||[]).filter(n=>n.data.kind==='note').map(n=>{const {inputPosition,outputPosition,config,provider,origin,...data}=n.data;return {id:n.id,data:{description:'',...data}};}).sort((a,b)=>order(a.id,b.id));
76
+ add('intent:project','intent','Project intent',{text:project.requirements||'',...Object.fromEntries(['brief','useCases','facts','workflow','domain'].filter(k=>project[k]!==undefined).map(k=>[k,project[k]])),...(annotations.length?{annotations}:{}),...(project.extensions?.terraformState?{terraformState:project.extensions.terraformState}:{})});
77
+ add('selection:provider','selection','Selected target provider',{provider:project.provider||'tools'});
78
+ const global=['intent:project','selection:provider',...state.intents.map(i=>'intent:'+i.id)];
79
+ for(const i of state.intents)add('intent:'+i.id,'intent','Engineering request '+i.sequence,i);
80
+ for(const r of project.needs||[])add('requirement:'+r.id,'requirement',r.statement,r);
81
+ for(const a of project.assumptions||[])add('assumption:'+a.id,'assumption',a.statement,a);
82
+ for(const q of project.openQuestions||[])add('question:'+q.id,'question',q.question,q);
83
+ for(const d of project.decisions||[])add('decision:'+d.id,'decision',d.title||d.subject||d.id,d,(d.requirementIds?.length?d.requirementIds:(project.needs||[]).filter(r=>!d.links?.length||r.links?.some(id=>d.links.includes(id))).map(r=>r.id)).map(id=>'requirement:'+id));
84
+ for(const n of project.nodes||[]){
85
+ if(n.data.kind==='note')continue;
86
+ const {inputPosition,outputPosition,...meaning}=n.data;
87
+ const linked=(rows,type)=>rows.filter(r=>r.links?.includes(n.id)).map(r=>type+':'+r.id);
88
+ const decisions=(project.decisions||[]).filter(d=>d.status==='Accepted'&&(!d.links?.length||d.links.includes(n.id))).map(d=>'decision:'+d.id);
89
+ const identity=externalIdentity(project,n.id);
90
+ add('block:'+n.id,'responsibility',n.data.label,{...meaning,...(identity?{externalProvenance:identity}:{})},[...global,...(n.data.approvalProfile?approvalReferences(n.data.approvalProfile).map(ref=>'block:'+ref.componentId):[]),...linked(project.needs||[],'requirement'),...linked(project.assumptions||[],'assumption'),...linked(project.openQuestions||[],'question'),...decisions]);
91
+ }
92
+ for(const e of project.edges||[]){
93
+ const {id,source,target,label}=e;
94
+ const visual=new Set(['id','type','sourceHandle','targetHandle','style','markerStart','markerEnd','animated','selected','hidden','labelStyle','labelBgStyle','labelShowBg','labelBgPadding','labelBgBorderRadius']);
95
+ add('interface:'+id,'interface',label||id,Object.fromEntries(Object.entries(e).filter(([key])=>!visual.has(key))),['block:'+source,'block:'+target]);
96
+ }
97
+ for(const r of state.records)add('work:'+r.id,r.kind,r.title,r,[...global,...r.dependsOn]);
98
+ if(new Set(entries.map(e=>e.id)).size!==entries.length)throw Error('Duplicate architecture source identity.');
99
+ return entries.sort((a,b)=>order(a.id,b.id));
100
+ }
101
+ function context(entries,target){
102
+ const byId=new Map(entries.map(e=>[e.id,e])),values=new Map(),missing=new Set(),pending=[target];
103
+ while(pending.length){const id=pending.pop();if(values.has(id)||missing.has(id))continue;const entry=byId.get(id);if(!entry){missing.add(id);continue;}values.set(id,entry);pending.push(...entry.dependsOn);}
104
+ return {values,missing:[...missing].sort()};
105
+ }
106
+ export function architectureWork(project){
107
+ const state=stateOf(project),sources=architectureSources(project,state),snapshots=new Map(state.snapshots.map(s=>[s.id,s]));
108
+ const bindings=new Map(state.bindings.map(b=>[b.ref,b]));
109
+ const currentValues=new Map(sources.map(e=>[e.id,canonicalWork(e)])),previousValues=new Map(state.snapshots.map(s=>[s.id,canonicalWork(s.value)]));
110
+ const entities=sources.map(entry=>{
111
+ const current=context(sources,entry.id),binding=bindings.get(entry.id),previous=new Map((binding?.snapshotIds||[]).map(id=>{const s=snapshots.get(id);return [s.ref,previousValues.get(s.id)];}));
112
+ const changed=binding?[...new Set([...current.values.keys(),...previous.keys()])].filter(id=>currentValues.get(id)!==previous.get(id)).sort():[];
113
+ return {...entry,contextStatus:current.missing.length?'missing':!binding?'unreviewed':changed.length?'changed':'current',changedRefs:changed,missingRefs:current.missing,review:binding?{recordedAt:binding.recordedAt,recordedBy:binding.recordedBy,scope:binding.scope}:null};
114
+ });
115
+ // Preserve deleted targets as visible orphans, including the original snapshots.
116
+ for(const b of state.bindings)if(!entities.some(e=>e.id===b.ref))entities.push({id:b.ref,kind:'removed',title:b.ref,contextStatus:'missing',changedRefs:[],missingRefs:[b.ref],review:{recordedAt:b.recordedAt,recordedBy:b.recordedBy,scope:b.scope}});
117
+ return {format:'atmem.architecture-work',version:WORK_VERSION,projectId:project.id||null,entities,
118
+ boundary:'Context currency and recorded mappings only. Evidence entries are claims/references, not independently verified execution or acceptance. Free-form engineering intent conservatively affects every work mapping until explicitly reconciled.'};
119
+ }
120
+ export function workContextIdentity(project,target){
121
+ const current=context(architectureSources(project),target);
122
+ return canonicalWork({sources:Object.fromEntries(current.values),missing:current.missing});
123
+ }
124
+ export function captureWorkSources(state,entries){
125
+ const snapshots=[...state.snapshots],ids=[];let next=1;
126
+ for(const s of snapshots){const n=Number(/^basis-(\d+)$/.exec(s.id)?.[1]);if(Number.isSafeInteger(n))next=Math.max(next,n+1);}
127
+ for(const value of [...entries].sort((a,b)=>order(a.id,b.id))){
128
+ let snapshot=snapshots.find(s=>s.ref===value.id&&canonicalWork(s.value)===canonicalWork(value));
129
+ if(!snapshot){snapshot={id:'basis-'+next++,ref:value.id,value:clone(value)};snapshots.push(snapshot);}ids.push(snapshot.id);
130
+ }
131
+ return {snapshots,ids};
132
+ }
133
+ export function applyArchitectureChange(project,owner,change){
134
+ if(project.id!==owner)return project;
135
+ if(change.kind==='propose')return proposeWorkRecords(project,change.records);
136
+ if(change.kind==='review')return reviewWorkContext(project,change.ref,{expectedContext:change.expectedContext});
137
+ throw Error('Unknown architecture work change.');
138
+ }
139
+ export function reviewWorkContext(project,target,{recordedBy='user',now=new Date(),expectedContext}={}){
140
+ if(!project.id)throw Error('Save the project identity before recording context review.');
141
+ const state=stateOf(project),current=context(architectureSources(project,state),target);
142
+ if(expectedContext!==undefined&&expectedContext!==canonicalWork({sources:Object.fromEntries(current.values),missing:current.missing}))throw Error('Work context changed; inspect its current sources before reviewing.');
143
+ if(current.missing.length||!current.values.size)throw Error('Resolve missing work references before recording context review.');
144
+ const snapshots=[...state.snapshots],ids=[];
145
+ let next=1;for(const s of snapshots){const n=Number(/^basis-(\d+)$/.exec(s.id)?.[1]);if(Number.isSafeInteger(n))next=Math.max(next,n+1);}
146
+ for(const [id,value] of [...current.values].sort(([a],[b])=>order(a,b))){
147
+ let snapshot=snapshots.find(s=>s.ref===id&&canonicalWork(s.value)===canonicalWork(value));
148
+ if(!snapshot){snapshot={id:'basis-'+next++,ref:id,value};snapshots.push(snapshot);}ids.push(snapshot.id);
149
+ }
150
+ const binding={ref:target,snapshotIds:ids,recordedAt:now.toISOString(),recordedBy,scope:'context_review_only'};
151
+ const previous=state.bindings.find(b=>b.ref===target);
152
+ return store(project,{...state,snapshots,bindings:[...state.bindings.filter(b=>b.ref!==target),binding],history:[...state.history,...(previous?[previous]:[])]});
153
+ }
154
+ export function proposeWorkRecords(project,records){
155
+ const state=stateOf(project);array(records,200,'work proposal');const byId=new Map(state.records.map(r=>[r.id,r]));
156
+ for(const row of records){
157
+ assertWorkJSON(row);
158
+ if(byId.has(row.id))throw Error('A work proposal cannot overwrite an existing mapping; revise it explicitly.');
159
+ byId.set(row.id,{...clone(row),source:'agent',agreement:'proposed'});
160
+ }
161
+ return store(project,{...state,records:[...byId.values()]});
162
+ }
163
+ export function synchronizeEngineeringIntent(project,sessionId,events,owner=project.id){
164
+ if(project.id!==owner)return project;
165
+ text(sessionId,100,'session ID');const state=stateOf(project),byId=new Map(state.intents.map(i=>[i.id,i]));let changed=false;
166
+ const rank={pending:0,uncertain:1,accepted:2};
167
+ for(const entry of engineeringConversation(events).filter(e=>e.role==='user')){
168
+ const id=`${sessionId}:${entry.id}`,old=byId.get(id);
169
+ if(old&&old.text!==entry.text)throw Error('Saved engineering intent changed identity; retain both histories for reconciliation.');
170
+ const status=old&&rank[old.status]>rank[entry.status]?old.status:entry.status;
171
+ const value={id,sessionId,sequence:entry.id,text:entry.text,status};
172
+ if(canonicalWork(old)!==canonicalWork(value)){byId.set(id,value);changed=true;}
173
+ }
174
+ const sessions=new Map([...new Set([...state.intents.map(i=>i.sessionId),sessionId])].map((id,index)=>[id,index]));
175
+ return changed?store(project,{...state,intents:[...byId.values()].sort((a,b)=>sessions.get(a.sessionId)-sessions.get(b.sessionId)||a.sequence-b.sequence)}):project;
176
+ }
@@ -0,0 +1,103 @@
1
+ // Backend-issued file/context bindings remain proposed architecture metadata.
2
+ // This is not a signature, execution result or business acceptance mechanism.
3
+ import {architectureSources,canonicalWork,captureWorkSources,synchronizeEngineeringIntent,validateArchitectureWork} from './architecture-work.mjs';
4
+ import {findCredentials} from './project-file.mjs';
5
+
6
+ const hash=async text=>[...new Uint8Array(await crypto.subtle.digest('SHA-256',new TextEncoder().encode(text)))].map(b=>b.toString(16).padStart(2,'0')).join('');
7
+ const same=(a,b)=>canonicalWork(a)===canonicalWork(b);
8
+ const sourceMap=(project,ids)=>architectureSources(project).filter(e=>!ids.has(e.id));
9
+ function contextProject(file){
10
+ // Context comparison must use the exact saved semantics. The legacy diagram
11
+ // importer normalizes runtime settings and recognized adapter enums; applying
12
+ // those compiler transformations here could hide a newly supplied contract.
13
+ if(!['atmem.ai-architect.project','atforma.project'].includes(file.format)||!file.meta||!Array.isArray(file.design?.nodes)||!Array.isArray(file.design?.edges))throw Error('Invalid saved architecture context.');
14
+ const d=file.discovery||{};
15
+ return {id:file.meta.id,provider:file.design.provider||'tools',requirements:d.problem||'',nodes:file.design.nodes,edges:file.design.edges,
16
+ ...Object.fromEntries(['brief','useCases','facts','workflow'].filter(k=>d[k]!==undefined).map(k=>[k,d[k]])),...(file.meta.domain?{domain:file.meta.domain}:{}),
17
+ needs:file.requirements||[],assumptions:file.assumptions||[],openQuestions:file.openQuestions||[],decisions:file.decisions||[],extensions:file.extensions||{}};
18
+ }
19
+
20
+ export async function verifyArtifactWork(receipt){
21
+ if(receipt?.status!=='prepared'||typeof receipt.content!=='string'||new TextEncoder().encode(receipt.content).length>6_000_000||await hash(receipt.content)!==receipt.sha256)throw Error('The mapping receipt digest did not match. No mappings were changed.');
22
+ const payload=JSON.parse(receipt.content);
23
+ const keys=['format','version','projectId','sessionId','runId','artifactId','artifactSha256','proposalSha256','context','events','proposal','files','definitionSha256','boundary'];
24
+ if(Object.keys(payload).some(k=>!keys.includes(k))||keys.some(k=>!(k in payload))||payload.format!=='atmem.architecture-proposal'||payload.version!==1||payload.boundary!=='artifact_file_binding_only')throw Error('Unsupported artifact mapping receipt.');
25
+ if(payload.context?.projectId!==payload.projectId||typeof payload.context?.content!=='string'||await hash(payload.context.content)!==payload.context.sha256)throw Error('The saved context digest did not match this receipt.');
26
+ if(findCredentials(payload).length)throw Error('Mapping receipt contains data that looks like a credential.');
27
+ return {id:receipt.id,receiptSha256:receipt.sha256,payload};
28
+ }
29
+
30
+ export function applyArtifactWork(project,owner,verified,{now=new Date()}={}){
31
+ if(project.id!==owner)return project;
32
+ const {id,receiptSha256,payload:p}=verified;
33
+ if(p.projectId!==owner||p.context?.projectId!==owner||p.boundary!=='artifact_file_binding_only')throw Error('This mapping receipt belongs to a different project.');
34
+ if(p.proposal?.version!==1||!Array.isArray(p.proposal.records)||!p.proposal.records.length||p.proposal.records.length>200||Object.keys(p.proposal).some(k=>!['version','records'].includes(k)))throw Error('Invalid artifact work proposal.');
35
+ const records=p.proposal.records.map(r=>({...r,source:'agent',agreement:'proposed'})),ids=new Set(records.map(r=>'work:'+r.id));
36
+ if(ids.size!==records.length)throw Error('Repeated work mapping identity.');
37
+ let basis=contextProject(JSON.parse(p.context.content));
38
+ if(basis.id!==owner)throw Error('Saved mapping context belongs to another project.');
39
+ // Merge exact durable client events on both sides; a late reply never replaces
40
+ // newer local requirements, another session's intent or a switched project.
41
+ basis=synchronizeEngineeringIntent(basis,p.sessionId,p.events,owner);
42
+ const current=synchronizeEngineeringIntent(project,p.sessionId,p.events,owner);
43
+ if(!same(sourceMap(current,ids),sourceMap(basis,ids)))throw Error('The design changed since this package was built. Regenerate against the current requirements before linking mappings.');
44
+ const state=validateArchitectureWork(current.extensions?.architectureWork);
45
+ const existing=state.artifactMappings.find(m=>m.id===id);
46
+ if(existing){if(existing.receiptSha256!==receiptSha256||!same(existing.records,records)||existing.artifactSha256!==p.artifactSha256)throw Error('A mapping receipt cannot change identity.');return current;}
47
+ const byId=new Map(state.records.map(r=>[r.id,r]));
48
+ for(const record of records){
49
+ const old=byId.get(record.id);
50
+ if(old){
51
+ const prior=state.artifactMappings.findLast(m=>m.records.some(r=>r.id===record.id));
52
+ if(!prior||old.source!=='agent'||old.agreement!=='proposed'||!same(old,prior.records.find(r=>r.id===record.id))||prior.sessionId!==p.sessionId)throw Error('A generated mapping conflicts with an existing or accepted record. Keep both histories and resolve the identity explicitly.');
53
+ }
54
+ byId.set(record.id,record);
55
+ }
56
+ const sourceState={...state,records:[...byId.values()]};
57
+ const sources=architectureSources({...current,extensions:{...current.extensions,architectureWork:sourceState}});
58
+ const known=new Set(sources.map(s=>s.id));
59
+ for(const record of records){
60
+ if(record.dependsOn.some(ref=>!known.has(ref)))throw Error('The proposal names a missing requirement, block, interface or work reference.');
61
+ const paths=record.data?.files||[];
62
+ if(record.kind==='implementation'&&!paths.length)throw Error('Implementation mappings must name captured artifact files.');
63
+ if(!Array.isArray(paths)||new Set(paths).size!==paths.length||paths.some(path=>!p.files.some(f=>f.path===path)))throw Error('A proposed mapping lacks an actual artifact file binding.');
64
+ }
65
+ const captured=captureWorkSources(state,sourceMap(current,ids));
66
+ const mapping={id,receiptSha256,sessionId:p.sessionId,runId:p.runId,artifactId:p.artifactId,artifactSha256:p.artifactSha256,proposalSha256:p.proposalSha256,
67
+ contextId:p.context.id,contextRevision:p.context.revision,contextSha256:p.context.sha256,definitionSha256:p.definitionSha256,
68
+ records,files:p.files,sourceSnapshotIds:captured.ids,recordedAt:now.toISOString(),scope:'artifact_file_binding_only'};
69
+ const next={...sourceState,snapshots:captured.snapshots,artifactMappings:[...state.artifactMappings,mapping]};
70
+ const validated=validateArchitectureWork(next);
71
+ return {...current,extensions:{...current.extensions,architectureWork:validated}};
72
+ }
73
+
74
+ export function artifactWorkProjection(project){
75
+ const state=validateArchitectureWork(project.extensions?.architectureWork),sources=architectureSources(project),byId=new Map(sources.map(s=>[s.id,s]));
76
+ const mappings=state.artifactMappings.map(m=>{
77
+ const ids=new Set(m.records.map(r=>'work:'+r.id)),expected=m.sourceSnapshotIds.map(id=>state.snapshots.find(s=>s.id===id).value);
78
+ const before=new Map(expected.map(s=>[s.id,s])),after=new Map(sources.filter(s=>!ids.has(s.id)).map(s=>[s.id,s]));
79
+ const changedRefs=[...new Set([...before.keys(),...after.keys()])].filter(ref=>!same(before.get(ref),after.get(ref))).sort();
80
+ for(const record of m.records)if(!same(byId.get('work:'+record.id)?.value,record))changedRefs.push('work:'+record.id);
81
+ const newer=state.artifactMappings.findLast(x=>x.sessionId===m.sessionId).artifactId!==m.artifactId;
82
+ return {...m,contextStatus:newer?'superseded':changedRefs.length?'changed':'current',changedRefs:[...new Set(changedRefs)]};
83
+ });
84
+ const coverage=sources.filter(s=>['requirement','responsibility','interface'].includes(s.kind)&&!s.id.startsWith('work:')).map(source=>{
85
+ const references=[];
86
+ for(const mapping of mappings.filter(m=>m.contextStatus==='current'))for(const record of mapping.records.filter(r=>r.kind==='implementation')){
87
+ const pending=[...record.dependsOn],seen=new Set();let linked=false;
88
+ while(pending.length){
89
+ const ref=pending.pop();if(seen.has(ref))continue;seen.add(ref);if(ref===source.id)linked=true;
90
+ const entry=byId.get(ref);
91
+ // Broad change dependencies (for example an unscoped ADR) are not claims
92
+ // that one implementation covers every requirement in that context.
93
+ if(ref.startsWith('work:'))pending.push(...(entry?.value.dependsOn||[]));
94
+ else if(ref.startsWith('block:'))pending.push(...(project.needs||[]).filter(r=>r.links?.includes(ref.slice(6))).map(r=>'requirement:'+r.id));
95
+ else if(ref.startsWith('interface:')&&entry)pending.push('block:'+entry.value.source,'block:'+entry.value.target);
96
+ }
97
+ if(linked)references.push({recordId:record.id,artifactId:mapping.artifactId,files:record.data.files||[]});
98
+ }
99
+ return {ref:source.id,title:source.title,status:references.length?'file_reference_linked':'unmapped',references};
100
+ });
101
+ return {format:'atmem.architecture-artifact-mappings',version:1,projectId:project.id,mappings,coverage,
102
+ boundary:'References to server-bound artifact files and saved context, not execution, acceptance or compiler coverage. Reopened project metadata is not an authenticated receipt; use the owning session service to reverify it.'};
103
+ }