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.
- {forge_autonomy-2.3.1/forge_autonomy.egg-info → forge_autonomy-2.3.2}/PKG-INFO +1 -1
- forge_autonomy-2.3.2/forge/__main__.py +63 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/__init__.py +2 -1
- forge_autonomy-2.3.2/forge/runtime/bootstrap.py +263 -0
- forge_autonomy-2.3.2/forge/runtime/data_root.py +49 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/database.py +18 -14
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2/forge_autonomy.egg-info}/PKG-INFO +1 -1
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/SOURCES.txt +2 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/product-version.json +1 -1
- forge_autonomy-2.3.2/tests/test_canonical_data_root.py +75 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_bootstrap.py +5 -12
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_instance_persistence.py +12 -12
- forge_autonomy-2.3.1/forge/__main__.py +0 -20
- forge_autonomy-2.3.1/forge/runtime/bootstrap.py +0 -360
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/MANIFEST.in +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/README.md +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/_version.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_qualification.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/action_derivation_reattempt.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/ai_architect/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/ai_architect/provider_registry.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/advisor.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/presentation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/architecture/workspace.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/advisor.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/ingress.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/presentation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/business/workspace.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/canary.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/capabilities/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/capabilities/delegation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/completion/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/completion/assessor.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/constitutional/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/constitutional/assessor.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/core/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/core/json_store.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/decision_evidence/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/decision_evidence/repository.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/dispatcher/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/dispatcher/dispatcher.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/loop.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/execution/presentation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/foundation/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/foundation/loader.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/generation_two.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/generation_two_execution.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/execution_policy.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance/profiles.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/governance_authority.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/intake.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/coordinator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/integration/repository.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/consumer.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/knowledge/registry.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/lifecycle/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/lifecycle/store.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/mission_amendment.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/mission_scheduler.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/action.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/action_derivation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/agent_policy.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_architect_provider.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_architect_session.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/ai_provider_registry.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_mission.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_reasoning.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/architecture_review.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/codex_runtime_prompt.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/constitutional_validation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/decision_evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/execution_host.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/foundation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/historical_intent.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/integration.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/intent.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/intent_authoring.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_candidate.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_planner.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/mission_recommendation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/phase_completion.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/planning.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/producer.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/prompt_artifact.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/proposal.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/runtime_prompt.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/models/solution_template.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/operator_identity.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/action_derivation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/engine.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/openai_responses.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planner/provider_adapter.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/loader.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/planning/registry.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/portfolio_intelligence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/programme_authorization.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/codex_cli.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/prompts/generator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/proposals/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/proposals/generator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/provider_security.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/bootstrap_sequence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/generation_one.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/qualification/installed_smoke.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/recommendations/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/recommendations/engine.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/repository_truth.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/review/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/review/engine.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/execution_context.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/runner.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/runtime/service.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/adapter.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/ep_http_adapter.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/ep_v12.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/scheduler/scheduler.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/common.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/catalogue.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/solutions/generator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/state/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/state/mission_state.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge/workspace/__init__.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/dependency_links.txt +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/entry_points.txt +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/forge_autonomy.egg-info/top_level.txt +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/pyproject.toml +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/common.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/setup.cfg +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_action_derivation_qualification.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_agent_policy.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_architect_provider.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_architect_session.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_development_projection.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ai_provider_registry.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_reasoning.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_review_engine.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_architecture_workspace.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_adapter.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_canary.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_runner.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_mission_scheduler.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_bootstrap_sequence_qualification.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_business_governance_ingress.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_business_workspace.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_capability_delegation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_codex_cli_runtime_prompt.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_constitutional_validation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_decision_evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_default_project_quality_policy.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_distribution_identity.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_action_architecture.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_intent_authoring.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_intent_lifecycle.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_mission.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_planning.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_prompt_artifacts.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_engineering_proposals.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_ep_http_adapter.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_context.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_host_contract.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_execution_loop.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_forge_v1_bootstrap_scheduler_contract.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_forge_v1_implementation_dag.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_foundation_loader.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_foundation_models.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_one_bootstrap_qualification.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_two_execution.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_generation_two_mission_intake.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_governance_authority.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_governed_coverage.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_historical_engineering_intent.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_integration_coordination.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_knowledge_consumption.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_dispatcher.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_planner.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_recommendation_engine.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_recommendation_lifecycle.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_runtime_projection.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_runtime_scheduler.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_mission_state_store.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_openai_action_derivation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_operator_identity.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_phase_completion.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_platform_contract_documents.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_portfolio_intelligence_operation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_producer_contract.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_product_version_operations.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_productization_reconciliation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_programme_authorization.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_provider_security.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_repository_truth.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_database.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_evidence.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_prompt_generation.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_runtime_service.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_scheduler_dependency_boundary.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_schemas.py +0 -0
- {forge_autonomy-2.3.1 → forge_autonomy-2.3.2}/tests/test_solution_templates.py +0 -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
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
142
|
-
#
|
|
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
|
|
1260
|
-
|
|
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
|
|
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:
|
|
@@ -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
|
|
@@ -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
|
|
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
|
-
|
|
79
|
-
RuntimeResolver(self.root).resolve()
|
|
77
|
+
self.assertEqual(RuntimeResolver(self.root).resolve().path, database.path.resolve())
|
|
80
78
|
|
|
81
|
-
def
|
|
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
|
-
|
|
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.
|
|
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__":
|