forge-autonomy 2.3.1__tar.gz → 2.3.2__tar.gz

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 (265) hide show
  1. {forge_autonomy-2.3.1/forge_autonomy.egg-info → forge_autonomy-2.3.2}/PKG-INFO +1 -1
  2. forge_autonomy-2.3.2/forge/__main__.py +63 -0
  3. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/__init__.py +2 -1
  4. forge_autonomy-2.3.2/forge/runtime/bootstrap.py +263 -0
  5. forge_autonomy-2.3.2/forge/runtime/data_root.py +49 -0
  6. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/database.py +18 -14
  7. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2/forge_autonomy.egg-info}/PKG-INFO +1 -1
  8. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/SOURCES.txt +2 -0
  9. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/product-version.json +1 -1
  10. forge_autonomy-2.3.2/tests/test_canonical_data_root.py +75 -0
  11. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_bootstrap.py +5 -12
  12. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_instance_persistence.py +12 -12
  13. forge_autonomy-2.3.1/forge/__main__.py +0 -20
  14. forge_autonomy-2.3.1/forge/runtime/bootstrap.py +0 -360
  15. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/MANIFEST.in +0 -0
  16. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/README.md +0 -0
  17. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/__init__.py +0 -0
  18. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/_version.py +0 -0
  19. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_canary_closure.py +0 -0
  20. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_evidence.py +0 -0
  21. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_qualification.py +0 -0
  22. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_reattempt.py +0 -0
  23. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/ai_architect/__init__.py +0 -0
  24. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/ai_architect/provider_registry.py +0 -0
  25. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/__init__.py +0 -0
  26. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/advisor.py +0 -0
  27. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/presentation.py +0 -0
  28. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/workspace.py +0 -0
  29. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/autonomous_orchestrator.py +0 -0
  30. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/__init__.py +0 -0
  31. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/advisor.py +0 -0
  32. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/ingress.py +0 -0
  33. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/presentation.py +0 -0
  34. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/workspace.py +0 -0
  35. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/canary.py +0 -0
  36. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/capabilities/__init__.py +0 -0
  37. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/capabilities/delegation.py +0 -0
  38. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/completion/__init__.py +0 -0
  39. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/completion/assessor.py +0 -0
  40. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/constitutional/__init__.py +0 -0
  41. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/constitutional/assessor.py +0 -0
  42. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/core/__init__.py +0 -0
  43. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/core/json_store.py +0 -0
  44. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/decision_evidence/__init__.py +0 -0
  45. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/decision_evidence/repository.py +0 -0
  46. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/dispatcher/__init__.py +0 -0
  47. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/dispatcher/dispatcher.py +0 -0
  48. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/__init__.py +0 -0
  49. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/loop.py +0 -0
  50. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/presentation.py +0 -0
  51. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/foundation/__init__.py +0 -0
  52. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/foundation/loader.py +0 -0
  53. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/generation_two.py +0 -0
  54. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/generation_two_execution.py +0 -0
  55. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/__init__.py +0 -0
  56. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/execution_policy.py +0 -0
  57. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/profiles.py +0 -0
  58. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance_authority.py +0 -0
  59. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/intake.py +0 -0
  60. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/__init__.py +0 -0
  61. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/coordinator.py +0 -0
  62. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/repository.py +0 -0
  63. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/__init__.py +0 -0
  64. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/consumer.py +0 -0
  65. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/registry.py +0 -0
  66. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/lifecycle/__init__.py +0 -0
  67. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/lifecycle/store.py +0 -0
  68. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/mission_amendment.py +0 -0
  69. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/mission_scheduler.py +0 -0
  70. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/__init__.py +0 -0
  71. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/action.py +0 -0
  72. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/action_derivation.py +0 -0
  73. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/agent_policy.py +0 -0
  74. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_architect_provider.py +0 -0
  75. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_architect_session.py +0 -0
  76. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_provider_registry.py +0 -0
  77. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_mission.py +0 -0
  78. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_reasoning.py +0 -0
  79. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_review.py +0 -0
  80. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/codex_runtime_prompt.py +0 -0
  81. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/constitutional_validation.py +0 -0
  82. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/decision_evidence.py +0 -0
  83. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/execution_host.py +0 -0
  84. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/foundation.py +0 -0
  85. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/historical_intent.py +0 -0
  86. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/integration.py +0 -0
  87. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/intent.py +0 -0
  88. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/intent_authoring.py +0 -0
  89. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission.py +0 -0
  90. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_candidate.py +0 -0
  91. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_planner.py +0 -0
  92. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_recommendation.py +0 -0
  93. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/phase_completion.py +0 -0
  94. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/planning.py +0 -0
  95. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/producer.py +0 -0
  96. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/prompt_artifact.py +0 -0
  97. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/proposal.py +0 -0
  98. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/runtime_prompt.py +0 -0
  99. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/solution_template.py +0 -0
  100. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/operator_identity.py +0 -0
  101. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/__init__.py +0 -0
  102. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/action_derivation.py +0 -0
  103. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/engine.py +0 -0
  104. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/openai_responses.py +0 -0
  105. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/provider_adapter.py +0 -0
  106. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/__init__.py +0 -0
  107. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/loader.py +0 -0
  108. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/registry.py +0 -0
  109. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/portfolio_intelligence.py +0 -0
  110. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/programme_authorization.py +0 -0
  111. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/__init__.py +0 -0
  112. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/codex_cli.py +0 -0
  113. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/generator.py +0 -0
  114. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/proposals/__init__.py +0 -0
  115. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/proposals/generator.py +0 -0
  116. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/provider_security.py +0 -0
  117. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/__init__.py +0 -0
  118. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/bootstrap_sequence.py +0 -0
  119. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/generation_one.py +0 -0
  120. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/installed_smoke.py +0 -0
  121. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/recommendations/__init__.py +0 -0
  122. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/recommendations/engine.py +0 -0
  123. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/repository_truth.py +0 -0
  124. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/review/__init__.py +0 -0
  125. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/review/engine.py +0 -0
  126. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/evidence.py +0 -0
  127. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/execution_context.py +0 -0
  128. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/runner.py +0 -0
  129. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/service.py +0 -0
  130. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/__init__.py +0 -0
  131. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/adapter.py +0 -0
  132. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/ep_http_adapter.py +0 -0
  133. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/ep_v12.py +0 -0
  134. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/scheduler.py +0 -0
  135. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/capability-registry-1.0.schema.json +0 -0
  136. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/capability.schema.json +0 -0
  137. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/common.schema.json +0 -0
  138. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/decision-evidence-1.0.schema.json +0 -0
  139. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-goal-0.5.schema.json +0 -0
  140. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
  141. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-mode.schema.json +0 -0
  142. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-plan-0.5.schema.json +0 -0
  143. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
  144. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-proposal-0.6.schema.json +0 -0
  145. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/evidence-reference-0.5.schema.json +0 -0
  146. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/foundation-document.schema.json +0 -0
  147. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/governance-profile.schema.json +0 -0
  148. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/knowledge-source-0.4.schema.json +0 -0
  149. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/knowledge-source.schema.json +0 -0
  150. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/mission-candidate-1.0.schema.json +0 -0
  151. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/mission-candidate-1.1.schema.json +0 -0
  152. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/phase-completion-1.0.schema.json +0 -0
  153. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/planning-document-0.5.schema.json +0 -0
  154. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/repository-catalog.schema.json +0 -0
  155. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/repository.schema.json +0 -0
  156. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/solution-template-1.0.schema.json +0 -0
  157. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/workspace.schema.json +0 -0
  158. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/__init__.py +0 -0
  159. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/catalogue.py +0 -0
  160. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/generator.py +0 -0
  161. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/state/__init__.py +0 -0
  162. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/state/mission_state.py +0 -0
  163. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/workspace/__init__.py +0 -0
  164. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/dependency_links.txt +0 -0
  165. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/entry_points.txt +0 -0
  166. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/top_level.txt +0 -0
  167. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/pyproject.toml +0 -0
  168. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/capability-registry-1.0.schema.json +0 -0
  169. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/capability.schema.json +0 -0
  170. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/common.schema.json +0 -0
  171. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/decision-evidence-1.0.schema.json +0 -0
  172. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-goal-0.5.schema.json +0 -0
  173. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
  174. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-mode.schema.json +0 -0
  175. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-plan-0.5.schema.json +0 -0
  176. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
  177. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-proposal-0.6.schema.json +0 -0
  178. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/evidence-reference-0.5.schema.json +0 -0
  179. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/foundation-document.schema.json +0 -0
  180. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/governance-profile.schema.json +0 -0
  181. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/knowledge-source-0.4.schema.json +0 -0
  182. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/knowledge-source.schema.json +0 -0
  183. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/mission-candidate-1.0.schema.json +0 -0
  184. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/mission-candidate-1.1.schema.json +0 -0
  185. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/phase-completion-1.0.schema.json +0 -0
  186. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/planning-document-0.5.schema.json +0 -0
  187. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/repository-catalog.schema.json +0 -0
  188. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/repository.schema.json +0 -0
  189. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/solution-template-1.0.schema.json +0 -0
  190. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/workspace.schema.json +0 -0
  191. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/setup.cfg +0 -0
  192. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation.py +0 -0
  193. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_canary_closure.py +0 -0
  194. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_evidence.py +0 -0
  195. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_qualification.py +0 -0
  196. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_agent_policy.py +0 -0
  197. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_architect_provider.py +0 -0
  198. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_architect_session.py +0 -0
  199. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_development_projection.py +0 -0
  200. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_provider_registry.py +0 -0
  201. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_reasoning.py +0 -0
  202. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_review_engine.py +0 -0
  203. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_workspace.py +0 -0
  204. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_autonomous_orchestrator.py +0 -0
  205. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_adapter.py +0 -0
  206. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_canary.py +0 -0
  207. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_runner.py +0 -0
  208. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_scheduler.py +0 -0
  209. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_sequence_qualification.py +0 -0
  210. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_business_governance_ingress.py +0 -0
  211. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_business_workspace.py +0 -0
  212. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_capability_delegation.py +0 -0
  213. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_codex_cli_runtime_prompt.py +0 -0
  214. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_constitutional_validation.py +0 -0
  215. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_decision_evidence.py +0 -0
  216. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_default_project_quality_policy.py +0 -0
  217. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_distribution_identity.py +0 -0
  218. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_action_architecture.py +0 -0
  219. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_intent_authoring.py +0 -0
  220. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_intent_lifecycle.py +0 -0
  221. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_mission.py +0 -0
  222. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_planning.py +0 -0
  223. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_prompt_artifacts.py +0 -0
  224. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_proposals.py +0 -0
  225. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ep_http_adapter.py +0 -0
  226. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_context.py +0 -0
  227. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_host_contract.py +0 -0
  228. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_loop.py +0 -0
  229. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_forge_v1_bootstrap_scheduler_contract.py +0 -0
  230. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_forge_v1_implementation_dag.py +0 -0
  231. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_foundation_loader.py +0 -0
  232. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_foundation_models.py +0 -0
  233. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_one_bootstrap_qualification.py +0 -0
  234. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_two_execution.py +0 -0
  235. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_two_mission_intake.py +0 -0
  236. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_governance_authority.py +0 -0
  237. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_governed_coverage.py +0 -0
  238. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_historical_engineering_intent.py +0 -0
  239. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_integration_coordination.py +0 -0
  240. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_knowledge_consumption.py +0 -0
  241. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_dispatcher.py +0 -0
  242. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_planner.py +0 -0
  243. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_recommendation_engine.py +0 -0
  244. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_recommendation_lifecycle.py +0 -0
  245. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_runtime_projection.py +0 -0
  246. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_runtime_scheduler.py +0 -0
  247. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_state_store.py +0 -0
  248. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_openai_action_derivation.py +0 -0
  249. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_operator_identity.py +0 -0
  250. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_phase_completion.py +0 -0
  251. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_platform_contract_documents.py +0 -0
  252. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_portfolio_intelligence_operation.py +0 -0
  253. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_producer_contract.py +0 -0
  254. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_product_version_operations.py +0 -0
  255. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_productization_reconciliation.py +0 -0
  256. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_programme_authorization.py +0 -0
  257. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_provider_security.py +0 -0
  258. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_repository_truth.py +0 -0
  259. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_database.py +0 -0
  260. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_evidence.py +0 -0
  261. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_prompt_generation.py +0 -0
  262. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_service.py +0 -0
  263. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_scheduler_dependency_boundary.py +0 -0
  264. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_schemas.py +0 -0
  265. {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_solution_templates.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forge-autonomy
3
- Version: 2.3.1
3
+ Version: 2.3.2
4
4
  Summary: Forge mission planning, producer contracts, and evidence interpretation runtime.
5
5
  Author: Forge maintainers
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,63 @@
1
+ """Read-only command entrypoint for the packaged Forge runtime."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import sqlite3
7
+
8
+ from ._version import canonical_version
9
+ from .runtime.data_root import DataRootResolver
10
+
11
+
12
+ def _status(data_root: str | None) -> dict[str, object]:
13
+ """Read only the operator-safe instance projection; never initialise it."""
14
+ root = DataRootResolver(cli_data_root=data_root).resolve()
15
+ database = root / "forge.db"
16
+ marker = root / "instance" / "runtime-instance.json"
17
+ result: dict[str, object] = {"product_version": canonical_version(), "data_root": str(root),
18
+ "initialized": marker.is_file() and database.is_file(),
19
+ "runtime_status": "uninitialized", "execution_host_peer": "not_configured"}
20
+ if not result["initialized"]:
21
+ return result
22
+ try:
23
+ connection = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
24
+ try:
25
+ metadata = dict(connection.execute("SELECT key, value FROM runtime_metadata"))
26
+ finally:
27
+ connection.close()
28
+ except sqlite3.Error:
29
+ result["runtime_status"] = "unavailable"
30
+ return result
31
+ result.update({"instance_id": metadata.get("runtime_id"), "storage_schema": metadata.get("schema_version"),
32
+ "runtime_status": metadata.get("status", "unavailable")})
33
+ return result
34
+
35
+
36
+ def main(argv: list[str] | None = None) -> int:
37
+ parser = argparse.ArgumentParser(
38
+ prog="forge",
39
+ description="Forge mission planning and evidence interpretation runtime.",
40
+ )
41
+ parser.add_argument("--version", action="version", version=canonical_version())
42
+ parser.add_argument("--data-root", help="Forge-owned runtime data root")
43
+ subparsers = parser.add_subparsers(dest="command")
44
+ server = subparsers.add_parser("server", help="manage local Forge storage")
45
+ server_commands = server.add_subparsers(dest="server_command", required=True)
46
+ server_commands.add_parser("init", help="create and validate the configured Forge data root")
47
+ server_commands.add_parser("status", help="print read-only runtime status as JSON")
48
+ subparsers.add_parser("status", help="print read-only runtime status as JSON")
49
+ args = parser.parse_args(argv)
50
+ if args.command == "server" and args.server_command == "init":
51
+ from .runtime import RuntimeBootstrap
52
+ database = RuntimeBootstrap(data_root=args.data_root, forge_version=canonical_version()).open()
53
+ try:
54
+ print(json.dumps(_status(args.data_root), sort_keys=True))
55
+ finally:
56
+ database.close()
57
+ elif args.command == "status" or (args.command == "server" and args.server_command == "status"):
58
+ print(json.dumps(_status(args.data_root), sort_keys=True))
59
+ return 0
60
+
61
+
62
+ if __name__ == "__main__":
63
+ raise SystemExit(main())
@@ -23,6 +23,7 @@ from .bootstrap import (
23
23
  repository_identity,
24
24
  repository_uuid,
25
25
  )
26
+ from .data_root import DataRootError, DataRootResolver, RUNTIME_DIRECTORIES
26
27
  from .evidence import RuntimeDecisionEvidenceReference, RuntimeEvidence
27
28
  from .runner import BootstrapMissionRunner, MissionRunnerError, RuntimePromptFactory
28
29
  from .service import ForgeRuntimeService, RuntimeServiceTick
@@ -30,5 +31,5 @@ from .service import ForgeRuntimeService, RuntimeServiceTick
30
31
  __all__ = [
31
32
  "BootstrapMissionRunner", "MissionRunnerError", "RuntimePromptFactory", "ForgeRuntimeService", "RuntimeServiceTick",
32
33
  "RUNTIME_SCHEMA_VERSION", "RuntimeDatabase", "RuntimeDatabaseError", "RuntimeIntegrityError", "RuntimeDecisionEvidenceReference", "RuntimeEvidence",
33
- "RUNTIME_INSTANCE_VERSION", "RUNTIME_INITIALIZATION_VERSION", "RuntimeBootstrap", "RuntimeIdentity", "RuntimeInstance", "RuntimeLocation", "RuntimeRecovery", "RuntimeResolutionError", "RuntimeResolver", "repository_identity", "repository_uuid",
34
+ "RUNTIME_INSTANCE_VERSION", "RUNTIME_INITIALIZATION_VERSION", "RuntimeBootstrap", "RuntimeIdentity", "RuntimeInstance", "RuntimeLocation", "RuntimeRecovery", "RuntimeResolutionError", "RuntimeResolver", "repository_identity", "repository_uuid", "DataRootError", "DataRootResolver", "RUNTIME_DIRECTORIES",
34
35
  ]
@@ -0,0 +1,263 @@
1
+ """Persistent Runtime Instance resolution, bootstrap, and recovery.
2
+
3
+ The Runtime Database is storage owned by a Runtime Instance; it is never the
4
+ identity of that instance. Resolution uses the product-owned data root and
5
+ validates every persisted boundary before SQLite is opened.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ import hashlib
12
+ import json
13
+ import os
14
+ from pathlib import Path
15
+ import subprocess
16
+ from typing import Any
17
+
18
+ from .data_root import DataRootResolver, RUNTIME_DIRECTORIES
19
+
20
+ try:
21
+ import fcntl
22
+ except ImportError: # pragma: no cover - supported Forge hosts are POSIX.
23
+ fcntl = None
24
+
25
+
26
+ RUNTIME_INSTANCE_VERSION = "1"
27
+ RUNTIME_INITIALIZATION_VERSION = "1"
28
+
29
+
30
+ class RuntimeResolutionError(RuntimeError):
31
+ """A canonical Runtime Instance cannot be determined safely."""
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class RuntimeIdentity:
36
+ """The immutable identity of a single Forge Runtime Instance.
37
+
38
+ Compatibility properties retain the Runtime Database vocabulary used by
39
+ earlier callers while the public architectural concept is Runtime Instance.
40
+ """
41
+
42
+ runtime_id: str
43
+ repository_identity: str
44
+ repository_root: str
45
+ instance_version: str
46
+ initialization_version: str
47
+ repository_uuid: str | None
48
+ created_at: str
49
+ database_location: str
50
+ last_access_at: str
51
+ status: str
52
+
53
+ @classmethod
54
+ def from_metadata(cls, metadata: dict[str, str]) -> "RuntimeIdentity":
55
+ required = ("runtime_id", "repository_identity", "repository_root", "created_at", "initialization_version")
56
+ if any(not metadata.get(key) for key in required):
57
+ raise RuntimeResolutionError("runtime identity metadata is incomplete")
58
+ return cls(metadata["runtime_id"], metadata["repository_identity"], metadata["repository_root"],
59
+ metadata.get("instance_version", RUNTIME_INSTANCE_VERSION), metadata["initialization_version"],
60
+ metadata.get("repository_uuid") or None, metadata["created_at"],
61
+ metadata.get("database_location", ""), metadata.get("last_access_at", ""), metadata.get("status", ""))
62
+
63
+ @property
64
+ def repository_id(self) -> str:
65
+ return self.repository_identity
66
+
67
+ @property
68
+ def database_version(self) -> str:
69
+ return self.instance_version
70
+
71
+ def to_dict(self) -> dict[str, str]:
72
+ result = {"runtime_id": self.runtime_id, "repository_identity": self.repository_identity,
73
+ "repository_id": self.repository_identity, "repository_root": self.repository_root,
74
+ "instance_version": self.instance_version, "database_version": self.instance_version,
75
+ "initialization_version": self.initialization_version,
76
+ "created_at": self.created_at, "database_location": self.database_location,
77
+ "last_access_at": self.last_access_at, "status": self.status}
78
+ if self.repository_uuid is not None:
79
+ result["repository_uuid"] = self.repository_uuid
80
+ return result
81
+
82
+
83
+ @dataclass(frozen=True)
84
+ class RuntimeInstance:
85
+ """Resolved Runtime Instance: immutable identity plus mutable placement."""
86
+
87
+ identity: RuntimeIdentity
88
+ location: Path
89
+ last_access_at: str
90
+ status: str
91
+
92
+ def to_dict(self) -> dict[str, str]:
93
+ result = self.identity.to_dict()
94
+ result.update({"instance_location": str(self.location), "database_location": str(self.location),
95
+ "last_access_at": self.last_access_at, "status": self.status})
96
+ return result
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class RuntimeLocation:
101
+ path: Path
102
+ source: str
103
+ bootstrap: bool
104
+
105
+
106
+ def canonical_repository_root(repository_root: Path | str) -> Path:
107
+ """Return the common Git checkout root for a main checkout or worktree."""
108
+ root = Path(repository_root)
109
+ try:
110
+ common_dir = subprocess.check_output(
111
+ ("git", "-C", str(root), "rev-parse", "--path-format=absolute", "--git-common-dir"),
112
+ text=True, stderr=subprocess.DEVNULL,
113
+ ).strip()
114
+ except (OSError, subprocess.CalledProcessError):
115
+ return root.resolve()
116
+ return Path(common_dir).resolve().parent
117
+
118
+
119
+ def repository_identity(repository_root: Path | str) -> str:
120
+ """Derive a location-independent identity from the Git root commit.
121
+
122
+ The root commit is shared by branches, worktrees, and filesystem moves.
123
+ A non-Git workspace has no durable Git identity and therefore remains
124
+ intentionally local to its canonical path.
125
+ """
126
+ root = canonical_repository_root(repository_root)
127
+ try:
128
+ initial_commit = subprocess.check_output(
129
+ ("git", "-C", str(root), "rev-list", "--max-parents=0", "HEAD"),
130
+ text=True, stderr=subprocess.DEVNULL,
131
+ ).strip().splitlines()
132
+ except (OSError, subprocess.CalledProcessError):
133
+ initial_commit = []
134
+ basis = initial_commit[0] if len(initial_commit) == 1 and initial_commit[0] else str(root.resolve())
135
+ return "forge-repository-" + hashlib.sha256(basis.encode("utf-8")).hexdigest()[:24]
136
+
137
+
138
+ def repository_uuid(repository_root: Path | str) -> str | None:
139
+ """Return an explicitly configured repository UUID when the host provides one."""
140
+ try:
141
+ value = subprocess.check_output(
142
+ ("git", "-C", str(canonical_repository_root(repository_root)), "config", "--get", "forge.repositoryUUID"),
143
+ text=True, stderr=subprocess.DEVNULL,
144
+ ).strip()
145
+ except (OSError, subprocess.CalledProcessError):
146
+ return None
147
+ return value or None
148
+
149
+
150
+ class RuntimeResolver:
151
+ """Resolve one installed Forge instance beneath the product-owned data root.
152
+
153
+ ``repository_root`` remains an API-compatibility argument only. It is not
154
+ consulted for location, identity, discovery, or writes.
155
+ """
156
+
157
+ def __init__(self, repository_root: Path | str = ".", *, configured_location: Path | str | None = None,
158
+ configured_runtime_root: Path | str | None = None, data_root: Path | str | None = None,
159
+ environment: dict[str, str] | None = None) -> None:
160
+ self.repository_root = Path(repository_root).resolve()
161
+ if configured_location is not None and (configured_runtime_root is not None or data_root is not None):
162
+ raise RuntimeResolutionError("choose a data root or an explicit database location, not both")
163
+ explicit_root = data_root if data_root is not None else configured_runtime_root
164
+ # Supplying a path to the long-standing library API is an explicit
165
+ # test/embedder root, never an inferred checkout location. Installed
166
+ # entrypoints use ``data_root`` (or the resolver default) instead.
167
+ self.compatibility_workspace = explicit_root is None and configured_location is None and repository_root != "."
168
+ self.data_root = (Path(repository_root).expanduser().resolve() if self.compatibility_workspace
169
+ else Path(configured_location).expanduser().resolve().parent if configured_location is not None
170
+ else DataRootResolver(cli_data_root=explicit_root, environment=environment).resolve())
171
+ self.configured_location = None if configured_location is None else Path(configured_location).expanduser().resolve()
172
+
173
+ @property
174
+ def default_location(self) -> Path:
175
+ return self.data_root / "forge.db"
176
+
177
+ @property
178
+ def instance_marker_path(self) -> Path:
179
+ return self.data_root / "instance" / "runtime-instance.json"
180
+
181
+ @property
182
+ def initialization_lock_path(self) -> Path:
183
+ return self.data_root / "locks" / "runtime.lock"
184
+
185
+ def resolve(self) -> RuntimeLocation:
186
+ path = self.configured_location or self.default_location
187
+ if path.is_file():
188
+ return RuntimeLocation(path.resolve(), "configured" if self.configured_location else "data_root", False)
189
+ if self.configured_location is None and self.instance_marker_path.exists():
190
+ raise RuntimeResolutionError("initialized Forge data root is missing forge.db")
191
+ return RuntimeLocation(path, "configured" if self.configured_location else "data_root", True)
192
+
193
+
194
+ class RuntimeBootstrap:
195
+ """Discover an existing Runtime Instance or create exactly one new instance."""
196
+
197
+ def __init__(self, repository_root: Path | str = ".", *, configured_location: Path | str | None = None,
198
+ configured_runtime_root: Path | str | None = None, data_root: Path | str | None = None,
199
+ environment: dict[str, str] | None = None, forge_version: str = "0.0") -> None:
200
+ self.resolver = RuntimeResolver(repository_root, configured_location=configured_location,
201
+ configured_runtime_root=configured_runtime_root, data_root=data_root, environment=environment)
202
+ self.forge_version = forge_version
203
+
204
+ def open(self):
205
+ from .database import RuntimeDatabase
206
+ if fcntl is None:
207
+ raise RuntimeResolutionError("Runtime Instance initialization lock is unavailable")
208
+ self._create_root_layout()
209
+ with self.resolver.initialization_lock_path.open("a+", encoding="utf-8") as lock:
210
+ try:
211
+ fcntl.flock(lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
212
+ except BlockingIOError as error:
213
+ raise RuntimeResolutionError("another mutating Forge runtime owns this data root") from error
214
+ try:
215
+ location = self.resolver.resolve()
216
+ database = RuntimeDatabase(self.resolver.repository_root, path=location.path, forge_version=self.forge_version,
217
+ installation_scoped=not self.resolver.compatibility_workspace)
218
+ try:
219
+ marker = self.resolver.instance_marker_path
220
+ temporary = marker.with_suffix(".tmp")
221
+ temporary.write_text(database.runtime_identity.runtime_id + "\n", encoding="utf-8")
222
+ os.chmod(temporary, 0o600)
223
+ os.replace(temporary, marker)
224
+ except Exception:
225
+ database.close()
226
+ raise
227
+ return database
228
+ finally:
229
+ fcntl.flock(lock.fileno(), fcntl.LOCK_UN)
230
+
231
+ def _create_root_layout(self) -> None:
232
+ root = self.resolver.data_root
233
+ root.mkdir(parents=True, exist_ok=True)
234
+ os.chmod(root, 0o700)
235
+ for name in RUNTIME_DIRECTORIES:
236
+ directory = root / name
237
+ directory.mkdir(exist_ok=True)
238
+ os.chmod(directory, 0o700)
239
+
240
+
241
+ class RuntimeRecovery:
242
+ """Runtime-only recovery projections; no source or legacy-state reconstruction."""
243
+
244
+ def __init__(self, database) -> None:
245
+ self._database = database
246
+
247
+ def recover(self) -> dict[str, Any]:
248
+ self._database.validate_integrity()
249
+ connection = self._database._connection
250
+ documents = lambda table: tuple(json.loads(row[0]) for row in connection.execute(f"SELECT document FROM {table} ORDER BY 1"))
251
+ receipts = tuple(dict(row) for row in connection.execute(
252
+ "SELECT receipt_id, mission_id, execution_host, execution_run_id, engineering_report_id, correlation_identity, executed_at, outcome FROM execution_receipts ORDER BY receipt_id"
253
+ ))
254
+ planning = None
255
+ row = connection.execute("SELECT document FROM planning_state WHERE singleton = 1").fetchone()
256
+ if row is not None:
257
+ planning = json.loads(row[0])
258
+ instance = RuntimeInstance(self._database.runtime_identity, self._database.path.resolve(),
259
+ self._database.metadata["last_access_at"], self._database.metadata["status"])
260
+ return {"runtime_instance": instance.to_dict(), "runtime_identity": instance.identity.to_dict(),
261
+ "mission_state": documents("mission_state"), "architecture_reviews": documents("architecture_reviews"),
262
+ "mission_recommendations": documents("mission_recommendations"), "decision_evidence": documents("decision_evidence"),
263
+ "execution_receipts": receipts, "planning_state": planning, "source": "runtime_instance"}
@@ -0,0 +1,49 @@
1
+ """Canonical, side-effect-free resolution of Forge-owned runtime storage.
2
+
3
+ This is deliberately the only place that chooses a writable location for an
4
+ installed Forge runtime. Resolving a root is a read-only operation; creation
5
+ belongs to :class:`forge.runtime.RuntimeBootstrap`.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from pathlib import Path
11
+ import sys
12
+ from typing import Mapping
13
+
14
+
15
+ class DataRootError(RuntimeError):
16
+ """The requested Forge data root is not a safe explicit location."""
17
+
18
+
19
+ class DataRootResolver:
20
+ """Resolve ``--data-root``, ``FORGE_DATA_ROOT``, then the native default."""
21
+
22
+ def __init__(self, *, cli_data_root: Path | str | None = None,
23
+ environment: Mapping[str, str] | None = None,
24
+ platform: str | None = None, home: Path | str | None = None) -> None:
25
+ self._cli_data_root = cli_data_root
26
+ self._environment = os.environ if environment is None else environment
27
+ self._platform = sys.platform if platform is None else platform
28
+ self._home = None if home is None else Path(home)
29
+
30
+ def resolve(self) -> Path:
31
+ candidate = self._cli_data_root
32
+ if candidate is None:
33
+ candidate = self._environment.get("FORGE_DATA_ROOT")
34
+ if candidate is not None and str(candidate).strip():
35
+ return Path(candidate).expanduser().resolve()
36
+ return self.native_default()
37
+
38
+ def native_default(self) -> Path:
39
+ home = (self._home or Path(self._environment.get("HOME", str(Path.home())))).expanduser()
40
+ if self._platform == "darwin":
41
+ return (home / "Library" / "Application Support" / "Forge Server").resolve()
42
+ if self._platform.startswith("win"):
43
+ base = self._environment.get("LOCALAPPDATA")
44
+ return (Path(base) if base else home / "AppData" / "Local") .joinpath("Forge Server").resolve()
45
+ base = self._environment.get("XDG_DATA_HOME")
46
+ return (Path(base) if base else home / ".local" / "share").joinpath("forge-server").resolve()
47
+
48
+
49
+ RUNTIME_DIRECTORIES = ("instance", "artifacts", "journals", "logs", "backups", "cache", "locks")
@@ -121,14 +121,14 @@ def _contains_secret_value(value: Any) -> bool:
121
121
  class RuntimeDatabase:
122
122
  """The sole Forge runtime database owner.
123
123
 
124
- ``path`` is injectable for tests, but production defaults to
125
- ``.forge/runtime.db`` beneath the supplied workspace root (or current
126
- directory). Opening is fail-closed: migrations and integrity validation
127
- complete before callers receive the database.
124
+ ``path`` is injectable for controlled bootstrap and tests. Installed
125
+ production opens only the resolved ``forge.db`` in Forge's data root.
126
+ Opening is fail-closed: migrations and integrity validation complete
127
+ before callers receive the database.
128
128
  """
129
129
 
130
130
  def __init__(self, workspace_root: Path | str = ".", *, path: Path | str | None = None,
131
- forge_version: str = "0.0") -> None:
131
+ forge_version: str = "0.0", installation_scoped: bool = False) -> None:
132
132
  if path is None:
133
133
  # Canonical creation and registration are a single inter-process
134
134
  # transaction owned by RuntimeBootstrap. Keep this compatibility
@@ -138,8 +138,9 @@ class RuntimeDatabase:
138
138
  self.__dict__.update(opened.__dict__)
139
139
  return
140
140
  self.repository_root = canonical_repository_root(workspace_root)
141
- # Explicit paths are reserved for bootstrap and relocation after their
142
- # resolver/claim step.
141
+ self._installation_scoped = installation_scoped
142
+ # Explicit paths are reserved for bootstrap and controlled tests after
143
+ # their resolver/claim step.
143
144
  self.path = Path(path)
144
145
  self.path.parent.mkdir(parents=True, exist_ok=True)
145
146
  self._connection = sqlite3.connect(self.path)
@@ -1256,16 +1257,18 @@ class RuntimeDatabase:
1256
1257
  created_at = now
1257
1258
  values = {
1258
1259
  "runtime_id": metadata.get("runtime_id") or f"forge-runtime-{uuid.uuid4()}",
1259
- "repository_identity": metadata.get("repository_identity") or repository_identity(self.repository_root),
1260
- "repository_root": metadata.get("repository_root") or str(self.repository_root),
1260
+ "repository_identity": metadata.get("repository_identity") or (
1261
+ "forge-installation" if self._installation_scoped else repository_identity(self.repository_root)),
1262
+ "repository_root": metadata.get("repository_root") or (
1263
+ "forge-data-root" if self._installation_scoped else str(self.repository_root)),
1261
1264
  "database_version": str(RUNTIME_SCHEMA_VERSION), "instance_version": "1",
1262
1265
  "initialization_version": metadata.get("initialization_version") or RUNTIME_INITIALIZATION_VERSION,
1263
- "database_location": str(self.path.resolve()),
1266
+ "database_location": "forge.db" if self._installation_scoped else str(self.path.resolve()),
1264
1267
  "created_at": created_at, "last_access_at": now, "status": "active",
1265
1268
  }
1266
- if values["repository_identity"] != repository_identity(self.repository_root):
1269
+ if not self._installation_scoped and values["repository_identity"] != repository_identity(self.repository_root):
1267
1270
  raise RuntimeIntegrityError("runtime database belongs to a different repository")
1268
- current_repository_uuid = repository_uuid(self.repository_root)
1271
+ current_repository_uuid = None if self._installation_scoped else repository_uuid(self.repository_root)
1269
1272
  stored_repository_uuid = metadata.get("repository_uuid")
1270
1273
  if stored_repository_uuid and current_repository_uuid and stored_repository_uuid != current_repository_uuid:
1271
1274
  raise RuntimeIntegrityError("runtime database repository UUID is inconsistent")
@@ -1322,9 +1325,10 @@ class RuntimeDatabase:
1322
1325
  raise RuntimeIntegrityError("runtime database schema version is inconsistent")
1323
1326
  self._require_canary_closure_structure()
1324
1327
  identity = self.runtime_identity
1325
- if identity.repository_identity != repository_identity(self.repository_root) or not identity.runtime_id or identity.status != "active":
1328
+ expected_identity = "forge-installation" if self._installation_scoped else repository_identity(self.repository_root)
1329
+ if identity.repository_identity != expected_identity or not identity.runtime_id or identity.status != "active":
1326
1330
  raise RuntimeIntegrityError("runtime identity is inconsistent")
1327
- current_repository_uuid = repository_uuid(self.repository_root)
1331
+ current_repository_uuid = None if self._installation_scoped else repository_uuid(self.repository_root)
1328
1332
  if identity.repository_uuid and current_repository_uuid and identity.repository_uuid != current_repository_uuid:
1329
1333
  raise RuntimeIntegrityError("runtime identity repository UUID is inconsistent")
1330
1334
  if self._connection.execute("PRAGMA foreign_key_check").fetchone() is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forge-autonomy
3
- Version: 2.3.1
3
+ Version: 2.3.2
4
4
  Summary: Forge mission planning, producer contracts, and evidence interpretation runtime.
5
5
  Author: Forge maintainers
6
6
  License-Expression: Apache-2.0
@@ -114,6 +114,7 @@ forge/review/__init__.py
114
114
  forge/review/engine.py
115
115
  forge/runtime/__init__.py
116
116
  forge/runtime/bootstrap.py
117
+ forge/runtime/data_root.py
117
118
  forge/runtime/database.py
118
119
  forge/runtime/evidence.py
119
120
  forge/runtime/execution_context.py
@@ -201,6 +202,7 @@ tests/test_bootstrap_mission_scheduler.py
201
202
  tests/test_bootstrap_sequence_qualification.py
202
203
  tests/test_business_governance_ingress.py
203
204
  tests/test_business_workspace.py
205
+ tests/test_canonical_data_root.py
204
206
  tests/test_capability_delegation.py
205
207
  tests/test_codex_cli_runtime_prompt.py
206
208
  tests/test_constitutional_validation.py
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "product": "forge",
3
3
  "schema_version": 1,
4
- "version": "2.3.1"
4
+ "version": "2.3.2"
5
5
  }
@@ -0,0 +1,75 @@
1
+ """Installed-runtime storage boundary regressions."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ from pathlib import Path
6
+ import subprocess
7
+ import sys
8
+ import tempfile
9
+ import unittest
10
+
11
+ from forge.runtime import DataRootResolver, RuntimeBootstrap, RuntimeResolutionError, RuntimeResolver
12
+
13
+
14
+ class CanonicalDataRootTests(unittest.TestCase):
15
+ def setUp(self) -> None:
16
+ self.temporary = tempfile.TemporaryDirectory()
17
+ self.root = Path(self.temporary.name)
18
+ self.addCleanup(self.temporary.cleanup)
19
+
20
+ def test_macos_default_and_precedence_are_deterministic(self) -> None:
21
+ home = self.root / "home"
22
+ env_root = self.root / "environment"
23
+ cli_root = self.root / "cli"
24
+ resolver = DataRootResolver(environment={"HOME": str(home), "FORGE_DATA_ROOT": str(env_root)}, platform="darwin")
25
+ self.assertEqual(resolver.resolve(), env_root.resolve())
26
+ self.assertEqual(DataRootResolver(cli_data_root=cli_root, environment={"HOME": str(home), "FORGE_DATA_ROOT": str(env_root)}, platform="darwin").resolve(), cli_root.resolve())
27
+ self.assertEqual(DataRootResolver(environment={"HOME": str(home)}, platform="darwin").resolve(), (home / "Library" / "Application Support" / "Forge Server").resolve())
28
+
29
+ def test_resolution_help_version_and_status_do_not_create_a_root(self) -> None:
30
+ root = self.root / "safe"
31
+ self.assertEqual(RuntimeResolver(data_root=root).resolve().path, (root / "forge.db").resolve())
32
+ self.assertFalse(root.exists())
33
+ for arguments in (("--help",), ("--version",), ("--data-root", str(root), "server", "status")):
34
+ completed = subprocess.run((sys.executable, "-m", "forge", *arguments), capture_output=True, text=True, check=True)
35
+ self.assertTrue(completed.stdout)
36
+ self.assertFalse(root.exists())
37
+
38
+ def test_init_creates_one_root_and_stable_identity(self) -> None:
39
+ root = self.root / "canonical"
40
+ first = RuntimeBootstrap(data_root=root, forge_version="test").open()
41
+ identity = first.runtime_identity.runtime_id
42
+ first.close()
43
+ self.assertEqual(RuntimeResolver(data_root=root).resolve().path, (root / "forge.db").resolve())
44
+ self.assertTrue((root / "instance" / "runtime-instance.json").is_file())
45
+ self.assertTrue(all((root / name).is_dir() for name in ("artifacts", "journals", "logs", "backups", "cache", "locks")))
46
+ second = RuntimeBootstrap(data_root=root, forge_version="test").open()
47
+ try:
48
+ self.assertEqual(second.runtime_identity.runtime_id, identity)
49
+ finally:
50
+ second.close()
51
+
52
+ def test_roots_are_independent_and_legacy_git_storage_is_ignored(self) -> None:
53
+ checkout = self.root / "checkout"
54
+ legacy = checkout / ".git" / "forge-runtime"
55
+ legacy.mkdir(parents=True)
56
+ (legacy / "runtime.db").write_text("not a Forge database", encoding="utf-8")
57
+ first = RuntimeBootstrap(checkout, data_root=self.root / "one", forge_version="test").open()
58
+ second = RuntimeBootstrap(checkout, data_root=self.root / "two", forge_version="test").open()
59
+ try:
60
+ self.assertNotEqual(first.runtime_identity.runtime_id, second.runtime_identity.runtime_id)
61
+ self.assertEqual((legacy / "runtime.db").read_text(encoding="utf-8"), "not a Forge database")
62
+ finally:
63
+ first.close(); second.close()
64
+
65
+ def test_initialized_root_missing_database_fails_closed(self) -> None:
66
+ root = self.root / "missing"
67
+ database = RuntimeBootstrap(data_root=root, forge_version="test").open()
68
+ database.close()
69
+ (root / "forge.db").unlink()
70
+ with self.assertRaisesRegex(RuntimeResolutionError, "missing forge.db"):
71
+ RuntimeResolver(data_root=root).resolve()
72
+
73
+
74
+ if __name__ == "__main__":
75
+ unittest.main()
@@ -46,7 +46,6 @@ class RuntimeBootstrapTests(unittest.TestCase):
46
46
  database = RuntimeBootstrap(self.root, configured_location=configured, forge_version="test").open()
47
47
  self.addCleanup(database.close)
48
48
  self.assertEqual(database.path, configured.resolve())
49
- self.assertEqual(RuntimeResolver(self.root).resolve().path, configured.resolve())
50
49
 
51
50
  def test_runtime_identity_is_immutable(self) -> None:
52
51
  database = self._database()
@@ -69,27 +68,21 @@ class RuntimeBootstrapTests(unittest.TestCase):
69
68
  self.assertEqual(recovered["planning_state"]["planner_version"], "test")
70
69
  self.assertEqual(recovered["source"], "runtime_instance")
71
70
 
72
- def test_multiple_runtime_candidates_fail_closed(self) -> None:
71
+ def test_checkout_candidates_are_not_discovered(self) -> None:
73
72
  database = self._database()
74
73
  database.close()
75
74
  duplicate = self.root / ".forge" / "duplicate" / "runtime-copy.db"
76
75
  duplicate.parent.mkdir(parents=True)
77
76
  duplicate.write_bytes(database.path.read_bytes())
78
- with self.assertRaises(RuntimeResolutionError):
79
- RuntimeResolver(self.root).resolve()
77
+ self.assertEqual(RuntimeResolver(self.root).resolve().path, database.path.resolve())
80
78
 
81
- def test_relocation_preserves_runtime_identity_and_recovers_records(self) -> None:
79
+ def test_distinct_explicit_roots_have_distinct_instances(self) -> None:
82
80
  database = self._database()
83
- self._persist_complete_runtime_slice(database)
84
81
  identity = database.runtime_identity.runtime_id
85
82
  database.close()
86
- destination = self.root / "runtime-store" / "canonical.db"
87
- location = RuntimeResolver(self.root).relocate(destination)
88
- self.assertEqual(location.path, destination.resolve())
89
- recovered = RuntimeBootstrap(self.root, forge_version="test").open()
83
+ recovered = RuntimeBootstrap(data_root=self.root / "runtime-store", forge_version="test").open()
90
84
  self.addCleanup(recovered.close)
91
- self.assertEqual(recovered.runtime_identity.runtime_id, identity)
92
- self.assertEqual(RuntimeRecovery(recovered).recover()["execution_receipts"][0]["receipt_id"], "receipt-1")
85
+ self.assertNotEqual(recovered.runtime_identity.runtime_id, identity)
93
86
 
94
87
 
95
88
  if __name__ == "__main__":