engineering-platform 2.3.89__tar.gz → 2.3.91__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.
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/PKG-INFO +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/pyproject.toml +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/central_operational_reset.py +32 -7
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_host.py +83 -4
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_repository.py +76 -0
- engineering_platform-2.3.91/src/engineering_platform/managed_workspace_readiness.py +85 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/parity_context.py +5 -2
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/parity_lifecycle_dispatcher.py +8 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/platform_version.py +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/revision_binding.py +10 -4
- engineering_platform-2.3.91/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +103 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/server.py +31 -3
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/submission_service.py +42 -3
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/templates/workspace-config.json +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/workspace_preflight.py +10 -2
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform.egg-info/PKG-INFO +1 -1
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform.egg-info/SOURCES.txt +2 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/README.md +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/setup.cfg +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/__init__.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/__main__.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/agent_state.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/agent_trust.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/dashboard.css +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/dashboard.js +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/dashboard_locales.mjs +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/assurance_scope.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/capability_preflight.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/capability_review.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/central_data_transfer.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/central_database.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/central_store_migration.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/codex_capacity.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/codex_chat.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/codex_observability.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/component_lock.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/component_logging.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/console_presentation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/console_route_ownership.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/contracts/__init__.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/contracts/ep_consumer.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/contracts/models.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/contracts/projection.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/dashboard_browser_validation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/dashboard_state.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/dashboard_supervisor.swift +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/dashboard_translation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/dependabot_producer.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/development_profile.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/drift_diagnostics.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/emergency_recovery.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/engineering_memory.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/ep_consumer_credentials.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/evidence_projection.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_activity.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_context.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_errors.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_evidence.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_executor.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_finalization.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_host_evidence.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_lease.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_lifecycle.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_models.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_readiness.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_reporting.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_timeout_policy.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_timing.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/execution_transaction.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/external_producer_binding.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/file_inbox.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/forensic_attribution.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/forensic_attribution_v2.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/forensic_delta.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/golden_scenario.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/host_admin.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/host_preflight.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_relocation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_activation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_admission.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_backup.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_composition.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_executor.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_migration.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_operation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_plan.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/installation_update_preparation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/investigation_ledger.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/legacy_inbox_migration.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/legacy_installation_adoption.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/lifecycle_worker.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/live_status.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/local_api.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/local_api_keychain.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/local_repository_binding.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/managed_autonomy.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/managed_codex_runtime.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/merge_delegation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/operational_installation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/operational_installation_lock.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/operational_installation_record.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/owner_credential_recovery.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/platform_admin.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/platform_api.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/platform_bootstrap.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/platform_components.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/pr_check_repair.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/pr_evidence_backfill.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/producer.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/product_installation_readback.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/project_agent.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/project_agent_service.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/project_topology.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/prompt_history.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_context.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_context_benchmark.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_context_scope.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_interruption.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_process_identity.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_readiness.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_recovery.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/provider_usage.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/providers.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/qualification.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/qualification_runtime.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/recommendation_handoff.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/reconciliation_adoption.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/release_operation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/report_analysis.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/repository_attachment.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/repository_handoff.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/resources.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/reviewer_evidence.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/server_console_services.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/server_relay.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/server_service.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/status_model.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/status_reconciliation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/storage.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/submission_cli.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/submission_intake.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/system_installation_topology.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/system_server_service.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/telemetry.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/telemetry_contract.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/telemetry_export.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/telemetry_metrics.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/validation_identity.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/validation_profile.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/version_preparation_delivery.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/worktree_provenance.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform/worktree_tooling.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform.egg-info/entry_points.txt +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/src/engineering_platform.egg-info/top_level.txt +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/tests/test_adaptive_action_sizing_design.py +0 -0
- {engineering_platform-2.3.89 → engineering_platform-2.3.91}/tests/test_role_task_model_policy_design.py +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bootstrap_contract": "2026.12",
|
|
3
3
|
"checkpoint_format": 1,
|
|
4
|
-
"dashboard_version": "2.3.
|
|
4
|
+
"dashboard_version": "2.3.91",
|
|
5
5
|
"handoff_protocol": 1,
|
|
6
6
|
"memory_format": 2,
|
|
7
7
|
"minimum_codex_cli": "0.146.0",
|
|
8
8
|
"inbox_protocol": 1,
|
|
9
|
-
"platform_version": "2.3.
|
|
9
|
+
"platform_version": "2.3.91",
|
|
10
10
|
"report_format": 2,
|
|
11
|
-
"runner_version": "2.3.
|
|
11
|
+
"runner_version": "2.3.91",
|
|
12
12
|
"status_model": 1,
|
|
13
13
|
"storage_schema": 45,
|
|
14
|
-
"watcher_version": "2.3.
|
|
14
|
+
"watcher_version": "2.3.91"
|
|
15
15
|
}
|
|
@@ -223,6 +223,31 @@ def _implementation_digest() -> str:
|
|
|
223
223
|
})
|
|
224
224
|
|
|
225
225
|
|
|
226
|
+
# The published 2.3.89 reset implementation can leave an operation at
|
|
227
|
+
# ARTIFACTS_ARCHIVED when operational engineering_metadata rows are present.
|
|
228
|
+
# Permit only that exact installed implementation to cross the fixed apply
|
|
229
|
+
# boundary; the plan, backup, identity, schema, generation and fences are still
|
|
230
|
+
# verified by apply before any database effect.
|
|
231
|
+
_ARCHIVED_RESET_COMPATIBILITY = frozenset({
|
|
232
|
+
("2.3.89", "UNAVAILABLE_IN_INSTALLED_PACKAGE",
|
|
233
|
+
"sha256:17ec03725e15672ef9511382e0b3d2c72e3f502823a35b89bea170882f4a14b8"),
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _implementation_binding_valid(plan: dict[str, object], state: str) -> bool:
|
|
238
|
+
binding = (
|
|
239
|
+
plan.get("product_version"), plan.get("implementation_source_revision"),
|
|
240
|
+
plan.get("implementation_digest"),
|
|
241
|
+
)
|
|
242
|
+
current = (
|
|
243
|
+
CURRENT_PLATFORM_VERSION, _implementation_source_revision(),
|
|
244
|
+
_implementation_digest(),
|
|
245
|
+
)
|
|
246
|
+
return binding == current or (
|
|
247
|
+
state == "ARTIFACTS_ARCHIVED" and binding in _ARCHIVED_RESET_COMPATIBILITY
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
226
251
|
def _implementation_source_revision() -> str:
|
|
227
252
|
try:
|
|
228
253
|
module = Path(__file__).resolve()
|
|
@@ -2302,11 +2327,7 @@ def apply(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str,
|
|
|
2302
2327
|
raise OperationalResetError("PRESERVED_BINDINGS_CHANGED")
|
|
2303
2328
|
if _schema_objects(connection) != plan["schema_objects"]:
|
|
2304
2329
|
raise OperationalResetError("SCHEMA_OBJECTS_CHANGED")
|
|
2305
|
-
if (
|
|
2306
|
-
plan.get("product_version") != CURRENT_PLATFORM_VERSION
|
|
2307
|
-
or plan.get("implementation_source_revision") != _implementation_source_revision()
|
|
2308
|
-
or plan.get("implementation_digest") != _implementation_digest()
|
|
2309
|
-
):
|
|
2330
|
+
if not _implementation_binding_valid(plan, "ARTIFACTS_ARCHIVED"):
|
|
2310
2331
|
raise OperationalResetError("IMPLEMENTATION_PROVENANCE_CHANGED")
|
|
2311
2332
|
generation_before = int(connection.execute(
|
|
2312
2333
|
"SELECT generation FROM ep_operational_dataset_state WHERE singleton=1"
|
|
@@ -2316,11 +2337,15 @@ def apply(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str,
|
|
|
2316
2337
|
# Immutable-evidence and maintenance-block triggers are removed and
|
|
2317
2338
|
# recreated inside this one uncommitted transaction. Other writers
|
|
2318
2339
|
# cannot observe an unfenced schema window.
|
|
2340
|
+
reset_trigger_tables = (
|
|
2341
|
+
OPERATIONAL_HISTORY | DERIVED_CACHE_OR_PROJECTION
|
|
2342
|
+
| {"engineering_metadata"}
|
|
2343
|
+
)
|
|
2319
2344
|
triggers = [
|
|
2320
2345
|
(str(name), str(sql)) for name, sql in connection.execute(
|
|
2321
2346
|
"SELECT name,sql FROM sqlite_master WHERE type='trigger' AND tbl_name IN ("
|
|
2322
|
-
+ ",".join("?" for _ in
|
|
2323
|
-
tuple(sorted(
|
|
2347
|
+
+ ",".join("?" for _ in reset_trigger_tables) + ")",
|
|
2348
|
+
tuple(sorted(reset_trigger_tables)),
|
|
2324
2349
|
).fetchall() if sql is not None
|
|
2325
2350
|
]
|
|
2326
2351
|
for name, _sql in triggers:
|
|
@@ -3086,6 +3086,15 @@ First implementation pull-request publication gate:
|
|
|
3086
3086
|
"Accepted repository revision binding is invalid.",
|
|
3087
3087
|
)
|
|
3088
3088
|
if revision_binding is not None:
|
|
3089
|
+
if (revision_binding.repository_identity is not None
|
|
3090
|
+
and (evidence.repository != revision_binding.repository_identity
|
|
3091
|
+
or not callable(getattr(self.repository, "trusted_origin_identity", None))
|
|
3092
|
+
or self.repository.trusted_origin_identity(self.root)
|
|
3093
|
+
!= revision_binding.repository_identity)):
|
|
3094
|
+
return self._save_terminal(
|
|
3095
|
+
state, "BLOCKED", "repository_identity_binding",
|
|
3096
|
+
"Managed workspace origin differs from the authorized repository identity.",
|
|
3097
|
+
)
|
|
3089
3098
|
if state.requested_repository_revision not in {None, revision_binding.requested_revision}:
|
|
3090
3099
|
return self._save_terminal(
|
|
3091
3100
|
state, "BLOCKED", "repository_revision_binding",
|
|
@@ -3212,10 +3221,47 @@ First implementation pull-request publication gate:
|
|
|
3212
3221
|
self.transaction = self.transaction.with_lease(self.active_lease)
|
|
3213
3222
|
self.lease_heartbeat.start()
|
|
3214
3223
|
if recovered_resume:
|
|
3224
|
+
self._heartbeat()
|
|
3225
|
+
if revision_binding is not None and context.execution_mode == "MANAGED":
|
|
3226
|
+
recovered_head = self.repository.inspect(self.root)
|
|
3227
|
+
expected_baseline = (
|
|
3228
|
+
revision_binding.allowed_baseline_revision
|
|
3229
|
+
or revision_binding.requested_revision
|
|
3230
|
+
)
|
|
3231
|
+
if (state.execution_baseline_sha != expected_baseline
|
|
3232
|
+
or recovered_head.repository != state.repository
|
|
3233
|
+
or not recovered_head.clean
|
|
3234
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3235
|
+
or (state.branch is not None and recovered_head.branch not in {state.branch, "main"})
|
|
3236
|
+
or not callable(getattr(self.repository, "trusted_origin_identity", None))
|
|
3237
|
+
or self.repository.trusted_origin_identity(self.root) != state.repository
|
|
3238
|
+
or not callable(getattr(self.repository, "revision_is_ancestor", None))
|
|
3239
|
+
or not self.repository.revision_is_ancestor(
|
|
3240
|
+
self.root, expected_baseline, recovered_head.head_sha,
|
|
3241
|
+
)):
|
|
3242
|
+
return self._save_terminal(
|
|
3243
|
+
state, "BLOCKED", "recovered_workspace_baseline",
|
|
3244
|
+
"Recovered provider result lacks the authorized workspace baseline.",
|
|
3245
|
+
)
|
|
3215
3246
|
# Consume immutable attempt-two evidence before any fresh provider
|
|
3216
3247
|
# preparation or repository synchronization. This preserves the
|
|
3217
3248
|
# original branch/worktree and cannot allocate a new invocation.
|
|
3218
3249
|
result = self._invoke_agent_with_timing(state, "")
|
|
3250
|
+
if (revision_binding is not None and context.execution_mode == "MANAGED"
|
|
3251
|
+
and recovery_snapshot["lifecycle_phase"] == "EXECUTE_AGENT"
|
|
3252
|
+
and result.terminal_state == "COMPLETE"):
|
|
3253
|
+
result_head = self.repository.inspect(self.root)
|
|
3254
|
+
if (not result.commit_sha or not result.branch
|
|
3255
|
+
or result_head.head_sha != result.commit_sha
|
|
3256
|
+
or result_head.branch != result.branch or not result_head.clean
|
|
3257
|
+
or self.repository.trusted_origin_identity(self.root) != state.repository
|
|
3258
|
+
or not self.repository.revision_is_ancestor(
|
|
3259
|
+
self.root, state.execution_baseline_sha, result.commit_sha,
|
|
3260
|
+
)):
|
|
3261
|
+
return self._save_terminal(
|
|
3262
|
+
state, "BLOCKED", "recovered_workspace_result_drift",
|
|
3263
|
+
"Recovered provider result no longer matches the bound workspace commit.",
|
|
3264
|
+
)
|
|
3219
3265
|
state = self._record_agent_execution_time(state)
|
|
3220
3266
|
state = self._record_validation_evidence(state, result)
|
|
3221
3267
|
state = self._record_verified_result_commit(
|
|
@@ -3229,10 +3275,18 @@ First implementation pull-request publication gate:
|
|
|
3229
3275
|
# and so the bounded retry policy in the repository client is used.
|
|
3230
3276
|
if context.execution_mode == "MANAGED":
|
|
3231
3277
|
try:
|
|
3232
|
-
#
|
|
3233
|
-
#
|
|
3234
|
-
#
|
|
3235
|
-
if revision_binding is None
|
|
3278
|
+
# An exact pin is prepared by the owning repository client
|
|
3279
|
+
# under this lease. It may fast forward only to that SHA,
|
|
3280
|
+
# never to an ambient newer origin/main.
|
|
3281
|
+
if revision_binding is not None and revision_binding.allowed_baseline_revision is None:
|
|
3282
|
+
prepare = getattr(self.repository, "prepare_main_revision", None)
|
|
3283
|
+
if not callable(prepare):
|
|
3284
|
+
raise RunnerError("MANAGED_PREPARATION_UNAVAILABLE")
|
|
3285
|
+
evidence = prepare(
|
|
3286
|
+
self.root, revision_binding.requested_revision,
|
|
3287
|
+
revision_binding.repository_identity or state.repository,
|
|
3288
|
+
)
|
|
3289
|
+
else:
|
|
3236
3290
|
self.repository.synchronize_main(self.root)
|
|
3237
3291
|
# The initial observation predates lease acquisition. Always
|
|
3238
3292
|
# refresh it here: an exact pin skips synchronization, never
|
|
@@ -3326,6 +3380,19 @@ First implementation pull-request publication gate:
|
|
|
3326
3380
|
self.reviewer_runtime,
|
|
3327
3381
|
)
|
|
3328
3382
|
self._require_provider_dispatch_admission(state)
|
|
3383
|
+
self._heartbeat()
|
|
3384
|
+
if state.execution_mode == "MANAGED" and state.execution_baseline_sha is not None:
|
|
3385
|
+
reviewer_head = self.repository.inspect(self.root)
|
|
3386
|
+
if (reviewer_head.repository != state.repository or reviewer_head.branch != "main"
|
|
3387
|
+
or not reviewer_head.clean or reviewer_head.head_sha != state.execution_baseline_sha
|
|
3388
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3389
|
+
or (state.requested_repository_revision is not None
|
|
3390
|
+
and self.repository.trusted_origin_identity(self.root) != state.repository)):
|
|
3391
|
+
complete_phase(self.root, capability_review, outcome="FAILED")
|
|
3392
|
+
return self._save_terminal(
|
|
3393
|
+
state, "BLOCKED", "managed_workspace_drift",
|
|
3394
|
+
"Managed workspace changed after baseline admission and before capability review.",
|
|
3395
|
+
)
|
|
3329
3396
|
results = run_reviews(
|
|
3330
3397
|
self.root,
|
|
3331
3398
|
selections,
|
|
@@ -3426,6 +3493,18 @@ First implementation pull-request publication gate:
|
|
|
3426
3493
|
),
|
|
3427
3494
|
)[1]
|
|
3428
3495
|
)
|
|
3496
|
+
if state.execution_mode == "MANAGED" and state.execution_baseline_sha is not None:
|
|
3497
|
+
self._heartbeat()
|
|
3498
|
+
execution_head = self.repository.inspect(self.root)
|
|
3499
|
+
if (execution_head.repository != state.repository or execution_head.branch != "main"
|
|
3500
|
+
or not execution_head.clean or execution_head.head_sha != state.execution_baseline_sha
|
|
3501
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3502
|
+
or (state.requested_repository_revision is not None
|
|
3503
|
+
and self.repository.trusted_origin_identity(self.root) != state.repository)):
|
|
3504
|
+
return self._save_terminal(
|
|
3505
|
+
state, "BLOCKED", "managed_workspace_drift",
|
|
3506
|
+
"Managed workspace changed after baseline admission and before provider implementation.",
|
|
3507
|
+
)
|
|
3429
3508
|
result = self._invoke_agent_with_timing(
|
|
3430
3509
|
state,
|
|
3431
3510
|
assemble_prompt(
|
|
@@ -31,6 +31,18 @@ def github_repository_slug(remote: str) -> str:
|
|
|
31
31
|
return value
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
def trusted_github_repository_slug(remote: str) -> str | None:
|
|
35
|
+
"""Resolve only an authorized GitHub transport, never a path or alias."""
|
|
36
|
+
value = remote.strip()
|
|
37
|
+
if value.startswith("git@github.com:"):
|
|
38
|
+
slug = value.removeprefix("git@github.com:").removesuffix(".git")
|
|
39
|
+
elif value.startswith("https://github.com/"):
|
|
40
|
+
slug = value.removeprefix("https://github.com/").removesuffix(".git")
|
|
41
|
+
else:
|
|
42
|
+
return None
|
|
43
|
+
return slug if re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", slug) else None
|
|
44
|
+
|
|
45
|
+
|
|
34
46
|
class RepositoryClient(Protocol):
|
|
35
47
|
def inspect(self, root: Path) -> RepositoryEvidence: ...
|
|
36
48
|
def main_contains(self, root: Path, sha: str) -> bool: ...
|
|
@@ -38,6 +50,10 @@ class RepositoryClient(Protocol):
|
|
|
38
50
|
def refresh_main_reference(self, root: Path) -> None: ...
|
|
39
51
|
def remote_main_contains(self, root: Path, sha: str) -> bool: ...
|
|
40
52
|
def synchronize_main(self, root: Path) -> None: ...
|
|
53
|
+
def prepare_main_revision(self, root: Path, revision: str, repository_id: str) -> RepositoryEvidence: ...
|
|
54
|
+
def revision_is_ancestor(self, root: Path, ancestor: str, descendant: str) -> bool: ...
|
|
55
|
+
def trusted_origin_identity(self, root: Path) -> str | None: ...
|
|
56
|
+
def workspace_operation_active(self, root: Path) -> bool: ...
|
|
41
57
|
|
|
42
58
|
|
|
43
59
|
class GitHubClient(Protocol):
|
|
@@ -73,6 +89,19 @@ class SubprocessRepositoryClient:
|
|
|
73
89
|
contained = self.provider.execute(root, "git", "merge-base", "--is-ancestor", head_sha, "main").returncode == 0
|
|
74
90
|
return RepositoryEvidence(repository, branch, head_sha, clean, contained)
|
|
75
91
|
|
|
92
|
+
def trusted_origin_identity(self, root: Path) -> str | None:
|
|
93
|
+
return trusted_github_repository_slug(self._run(root, "git", "remote", "get-url", "origin"))
|
|
94
|
+
|
|
95
|
+
def workspace_operation_active(self, root: Path) -> bool:
|
|
96
|
+
for name in ("index.lock", "MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD",
|
|
97
|
+
"REVERT_HEAD", "BISECT_LOG", "rebase-merge", "rebase-apply"):
|
|
98
|
+
path = Path(self._run(root, "git", "rev-parse", "--git-path", name))
|
|
99
|
+
if not path.is_absolute():
|
|
100
|
+
path = root / path
|
|
101
|
+
if path.exists():
|
|
102
|
+
return True
|
|
103
|
+
return False
|
|
104
|
+
|
|
76
105
|
def main_contains(self, root: Path, sha: str) -> bool:
|
|
77
106
|
return self.provider.execute(root, "git", "merge-base", "--is-ancestor", sha, "main").returncode == 0
|
|
78
107
|
|
|
@@ -91,6 +120,13 @@ class SubprocessRepositoryClient:
|
|
|
91
120
|
def remote_main_contains(self, root: Path, sha: str) -> bool:
|
|
92
121
|
return self.provider.execute(root, "git", "merge-base", "--is-ancestor", sha, "origin/main").returncode == 0
|
|
93
122
|
|
|
123
|
+
def revision_is_ancestor(self, root: Path, ancestor: str, descendant: str) -> bool:
|
|
124
|
+
if not all(re.fullmatch(r"[0-9a-f]{40}", value) for value in (ancestor, descendant)):
|
|
125
|
+
return False
|
|
126
|
+
return self.provider.execute(
|
|
127
|
+
root, "git", "merge-base", "--is-ancestor", ancestor, descendant,
|
|
128
|
+
).returncode == 0
|
|
129
|
+
|
|
94
130
|
@staticmethod
|
|
95
131
|
def _is_transient_index_lock_conflict(error: RuntimeError) -> bool:
|
|
96
132
|
"""Recognize only Git's contention signal, never a permission failure."""
|
|
@@ -180,6 +216,46 @@ class SubprocessRepositoryClient:
|
|
|
180
216
|
f"{self._managed_sync_diagnostics(root)}; {self._managed_sync_error_detail(error)}"
|
|
181
217
|
) from error
|
|
182
218
|
|
|
219
|
+
def prepare_main_revision(self, root: Path, revision: str, repository_id: str) -> RepositoryEvidence:
|
|
220
|
+
"""Fast forward a clean Managed main to one authorized protected revision.
|
|
221
|
+
|
|
222
|
+
The caller owns the execution lease. This method never resets local
|
|
223
|
+
work, switches branches, or treats a branch name as commit evidence.
|
|
224
|
+
"""
|
|
225
|
+
if re.fullmatch(r"[0-9a-f]{40}", revision) is None:
|
|
226
|
+
raise RunnerError("MANAGED_PREPARATION_INVALID_REVISION")
|
|
227
|
+
before = self.inspect(root)
|
|
228
|
+
if self.trusted_origin_identity(root) != repository_id:
|
|
229
|
+
raise RunnerError("MANAGED_PREPARATION_ORIGIN_UNTRUSTED")
|
|
230
|
+
if before.repository != repository_id:
|
|
231
|
+
raise RunnerError("MANAGED_PREPARATION_REPOSITORY_MISMATCH")
|
|
232
|
+
if before.branch != "main" or not before.clean or not before.main_contains_head:
|
|
233
|
+
raise RunnerError("MANAGED_PREPARATION_UNSAFE_WORKTREE")
|
|
234
|
+
if self.workspace_operation_active(root):
|
|
235
|
+
raise RunnerError("MANAGED_PREPARATION_GIT_OPERATION_ACTIVE")
|
|
236
|
+
self._synchronize_command(root, "git", "fetch", "--prune", "origin", "main")
|
|
237
|
+
if not self.remote_main_contains(root, revision):
|
|
238
|
+
raise RunnerError("MANAGED_PREPARATION_REVISION_NOT_ON_PROTECTED_MAIN")
|
|
239
|
+
if before.head_sha == revision:
|
|
240
|
+
if (self.inspect(root) != before or self.trusted_origin_identity(root) != repository_id
|
|
241
|
+
or self.workspace_operation_active(root)):
|
|
242
|
+
raise RunnerError("MANAGED_PREPARATION_WORKSPACE_DRIFT")
|
|
243
|
+
return before
|
|
244
|
+
if self.provider.execute(root, "git", "merge-base", "--is-ancestor", before.head_sha, revision).returncode:
|
|
245
|
+
raise RunnerError("MANAGED_PREPARATION_NON_FAST_FORWARD")
|
|
246
|
+
after_fetch = self.inspect(root)
|
|
247
|
+
if (after_fetch != before or self.trusted_origin_identity(root) != repository_id
|
|
248
|
+
or self.workspace_operation_active(root)):
|
|
249
|
+
raise RunnerError("MANAGED_PREPARATION_WORKSPACE_DRIFT")
|
|
250
|
+
self._synchronize_command(root, "git", "merge", "--ff-only", revision)
|
|
251
|
+
prepared = self.inspect(root)
|
|
252
|
+
if (prepared.repository != repository_id or prepared.branch != "main" or not prepared.clean
|
|
253
|
+
or not prepared.main_contains_head or prepared.head_sha != revision
|
|
254
|
+
or self.trusted_origin_identity(root) != repository_id
|
|
255
|
+
or self.workspace_operation_active(root)):
|
|
256
|
+
raise RunnerError("MANAGED_PREPARATION_RESULT_UNCERTAIN")
|
|
257
|
+
return prepared
|
|
258
|
+
|
|
183
259
|
def cleanup_transaction(self, root: Path, branches: tuple[str | None, ...]) -> str:
|
|
184
260
|
self._run(root, "git", "fetch", "--prune"); self.synchronize_main(root)
|
|
185
261
|
if not self.inspect(root).clean: raise RunnerError("Cleanup blocked: workspace is not clean.")
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Read-only, project-scoped Managed workspace capability inspection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import re
|
|
8
|
+
import sqlite3
|
|
9
|
+
|
|
10
|
+
from .execution_repository import trusted_github_repository_slug
|
|
11
|
+
from .providers import GitProvider
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def project_readiness(connection: sqlite3.Connection, *, project_id: str,
|
|
15
|
+
repository_id: str) -> dict[str, object]:
|
|
16
|
+
"""Report known blockers without planning or changing the checkout."""
|
|
17
|
+
observed_at = datetime.now(timezone.utc).isoformat()
|
|
18
|
+
binding = connection.execute(
|
|
19
|
+
"SELECT b.local_root FROM ep_local_repository_bindings b "
|
|
20
|
+
"JOIN ep_repository_registrations r ON r.repository_id=b.repository_id "
|
|
21
|
+
"AND r.project_id=b.project_id AND r.role='authority' "
|
|
22
|
+
"WHERE b.project_id=? AND b.repository_id=? AND b.state='BOUND'",
|
|
23
|
+
(project_id, repository_id),
|
|
24
|
+
).fetchone()
|
|
25
|
+
response: dict[str, object] = {
|
|
26
|
+
"contract_version": "1.0", "project_id": project_id,
|
|
27
|
+
"repository_id": repository_id,
|
|
28
|
+
"managed_workspace_id": f"{project_id}:{repository_id}",
|
|
29
|
+
"execution_mode": "MANAGED", "repository_identity": None,
|
|
30
|
+
"origin": None, "head_sha": None, "branch": None, "clean": None,
|
|
31
|
+
"busy": None, "active_lease": None,
|
|
32
|
+
"preparation_capability": "EXACT_MAIN_FAST_FORWARD_V1",
|
|
33
|
+
"status": "BLOCKED", "known_blocker": "MANAGED_WORKSPACE_UNBOUND",
|
|
34
|
+
"observed_at": observed_at,
|
|
35
|
+
}
|
|
36
|
+
if binding is None:
|
|
37
|
+
return response
|
|
38
|
+
root = Path(str(binding[0]))
|
|
39
|
+
git = GitProvider()
|
|
40
|
+
|
|
41
|
+
def read(*args: str) -> str | None:
|
|
42
|
+
try:
|
|
43
|
+
result = git.execute(root, "git", *args)
|
|
44
|
+
except (OSError, RuntimeError):
|
|
45
|
+
return None
|
|
46
|
+
return result.stdout.strip() if result.returncode == 0 else None
|
|
47
|
+
|
|
48
|
+
head = read("rev-parse", "--verify", "HEAD")
|
|
49
|
+
branch = read("branch", "--show-current")
|
|
50
|
+
remote = read("remote", "get-url", "origin")
|
|
51
|
+
status = read("status", "--porcelain", "--untracked-files=all")
|
|
52
|
+
identity = trusted_github_repository_slug(remote) if remote else None
|
|
53
|
+
active_lease = connection.execute(
|
|
54
|
+
"SELECT 1 FROM execution_run_leases l JOIN ep_execution_runs r ON r.run_id=l.run_id "
|
|
55
|
+
"WHERE r.project_id=? AND l.lease_state='ACTIVE' LIMIT 1",
|
|
56
|
+
(project_id,),
|
|
57
|
+
).fetchone() is not None
|
|
58
|
+
operation = False
|
|
59
|
+
for name in ("index.lock", "MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD",
|
|
60
|
+
"REVERT_HEAD", "BISECT_LOG", "rebase-merge", "rebase-apply"):
|
|
61
|
+
marker = read("rev-parse", "--git-path", name)
|
|
62
|
+
if marker is None:
|
|
63
|
+
operation = True
|
|
64
|
+
break
|
|
65
|
+
path = Path(marker)
|
|
66
|
+
if (path if path.is_absolute() else root / path).exists():
|
|
67
|
+
operation = True
|
|
68
|
+
break
|
|
69
|
+
blocker = (
|
|
70
|
+
"MANAGED_WORKSPACE_UNAVAILABLE" if head is None or status is None or branch is None
|
|
71
|
+
or re.fullmatch(r"[0-9a-f]{40}", head) is None else
|
|
72
|
+
"MANAGED_ORIGIN_UNTRUSTED" if identity is None else
|
|
73
|
+
"MANAGED_BRANCH_UNEXPECTED" if branch != "main" else
|
|
74
|
+
"MANAGED_WORKSPACE_DIRTY" if status else
|
|
75
|
+
"MANAGED_GIT_OPERATION_ACTIVE" if operation else
|
|
76
|
+
"MANAGED_LEASE_ACTIVE" if active_lease else None
|
|
77
|
+
)
|
|
78
|
+
response.update({
|
|
79
|
+
"repository_identity": identity, "origin": identity,
|
|
80
|
+
"head_sha": head if head and re.fullmatch(r"[0-9a-f]{40}", head) else None,
|
|
81
|
+
"branch": branch, "clean": status == "" if status is not None else None,
|
|
82
|
+
"busy": operation or active_lease, "active_lease": active_lease,
|
|
83
|
+
"status": "READY" if blocker is None else "BLOCKED", "known_blocker": blocker,
|
|
84
|
+
})
|
|
85
|
+
return response
|
|
@@ -78,8 +78,11 @@ class ParityProjectStore:
|
|
|
78
78
|
|
|
79
79
|
def queued_submissions(self) -> list[dict[str, object]]:
|
|
80
80
|
rows = self.connection.execute(
|
|
81
|
-
"SELECT submission_id,repository_id,state,admission,created_at,prompt_digest "
|
|
82
|
-
"FROM ep_submissions
|
|
81
|
+
"SELECT s.submission_id,s.repository_id,s.state,s.admission,s.created_at,s.prompt_digest "
|
|
82
|
+
"FROM ep_submissions AS s LEFT JOIN ep_parity_lifecycle_dispatches AS d "
|
|
83
|
+
"ON d.submission_id=s.submission_id WHERE s.project_id=? AND d.submission_id IS NULL "
|
|
84
|
+
"AND s.state='QUEUED' AND s.admission='ADMITTED' "
|
|
85
|
+
"ORDER BY s.created_at,s.submission_id",
|
|
83
86
|
(self.context.project_id,),
|
|
84
87
|
).fetchall()
|
|
85
88
|
return [{"submission_id": str(row[0]), "repository_id": str(row[1]), "state": str(row[2]),
|
|
@@ -117,6 +117,8 @@ def _retry_constraints_for_current_main(
|
|
|
117
117
|
"requested_revision": binding.requested_revision,
|
|
118
118
|
"allowed_baseline_revision": current_main,
|
|
119
119
|
}
|
|
120
|
+
if binding.repository_identity is not None:
|
|
121
|
+
rebound[CONSTRAINT_KEY]["repository_identity"] = binding.repository_identity
|
|
120
122
|
return rebound
|
|
121
123
|
|
|
122
124
|
|
|
@@ -477,7 +479,12 @@ class ParityLifecycleDispatcher:
|
|
|
477
479
|
retry_parent_run_id=candidate.retry_parent_run_id, resume_parent_run_id=None, recorded_at=now,
|
|
478
480
|
)
|
|
479
481
|
host = execute_host_preflight(repository_root, run_id=run_id)
|
|
480
|
-
|
|
482
|
+
revision_binding = parse_repository_revision_binding(candidate.constraints)
|
|
483
|
+
workspace = execute_workspace_preflight(
|
|
484
|
+
repository_root, candidate.prompt, run_id=run_id,
|
|
485
|
+
**({"exact_revision_preparation": True}
|
|
486
|
+
if revision_binding is not None and revision_binding.allowed_baseline_revision is None else {}),
|
|
487
|
+
)
|
|
481
488
|
capability = execute_capability_preflight(repository_root, candidate.prompt, run_id=run_id)
|
|
482
489
|
decision, _ = _record_provider_free_admission(
|
|
483
490
|
repository_root, run_id=run_id, submission_id=canonical_submission_id,
|
|
@@ -12,7 +12,7 @@ from .storage import ENGINEERING_STORAGE_SCHEMA_VERSION
|
|
|
12
12
|
|
|
13
13
|
SEMVER = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$")
|
|
14
14
|
CONTRACT = re.compile(r"^(\d{4})\.(0[1-9]|1[0-2])$")
|
|
15
|
-
CURRENT_PLATFORM_VERSION = "2.3.
|
|
15
|
+
CURRENT_PLATFORM_VERSION = "2.3.91"
|
|
16
16
|
MANIFEST_FIELDS = frozenset(
|
|
17
17
|
{
|
|
18
18
|
"platform_version",
|
|
@@ -17,6 +17,7 @@ class RepositoryRevisionBinding:
|
|
|
17
17
|
|
|
18
18
|
requested_revision: str
|
|
19
19
|
allowed_baseline_revision: str | None = None
|
|
20
|
+
repository_identity: str | None = None
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def parse_repository_revision_binding(
|
|
@@ -26,9 +27,10 @@ def parse_repository_revision_binding(
|
|
|
26
27
|
if constraints is None or CONSTRAINT_KEY not in constraints:
|
|
27
28
|
return None
|
|
28
29
|
raw = constraints[CONSTRAINT_KEY]
|
|
29
|
-
if not isinstance(raw, Mapping) or set(raw)
|
|
30
|
-
"requested_revision", "allowed_baseline_revision",
|
|
31
|
-
|
|
30
|
+
if not isinstance(raw, Mapping) or set(raw) not in (
|
|
31
|
+
{"requested_revision", "allowed_baseline_revision"},
|
|
32
|
+
{"requested_revision", "allowed_baseline_revision", "repository_identity"},
|
|
33
|
+
):
|
|
32
34
|
raise ValueError("repository revision binding shape is invalid")
|
|
33
35
|
requested = raw.get("requested_revision")
|
|
34
36
|
allowed = raw.get("allowed_baseline_revision")
|
|
@@ -36,4 +38,8 @@ def parse_repository_revision_binding(
|
|
|
36
38
|
raise ValueError("requested repository revision is invalid")
|
|
37
39
|
if allowed is not None and (not isinstance(allowed, str) or _SHA.fullmatch(allowed) is None):
|
|
38
40
|
raise ValueError("allowed baseline repository revision is invalid")
|
|
39
|
-
|
|
41
|
+
identity = raw.get("repository_identity")
|
|
42
|
+
if identity is not None and (not isinstance(identity, str)
|
|
43
|
+
or re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", identity) is None):
|
|
44
|
+
raise ValueError("repository identity is invalid")
|
|
45
|
+
return RepositoryRevisionBinding(requested, allowed, identity)
|
engineering_platform-2.3.91/src/engineering_platform/schemas/producer-readback-v1.3.schema.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://engineering-platform.local/schemas/producer-readback-v1.3.schema.json",
|
|
4
|
+
"title": "Engineering Platform producer readback v1.3 current execution disposition",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["contract_version", "submission", "producer", "correlation", "provenance", "disposition", "run", "result", "evidence"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"contract_version": {"const": "1.3"},
|
|
10
|
+
"submission": {
|
|
11
|
+
"type": "object", "additionalProperties": false,
|
|
12
|
+
"required": ["id", "project_id", "repository_id", "state", "admission", "transport", "created_at", "accepted_request_digest"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"id": {"type": "string"}, "project_id": {"type": "string"},
|
|
15
|
+
"repository_id": {"type": "string"}, "state": {"type": "string"},
|
|
16
|
+
"admission": {"type": "string"}, "transport": {"type": "string"},
|
|
17
|
+
"created_at": {"type": "string"},
|
|
18
|
+
"accepted_request_digest": {"type": "string", "pattern": "^sha256:[0-9a-f]{64}$"}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"producer": {
|
|
22
|
+
"type": "object", "additionalProperties": false,
|
|
23
|
+
"required": ["id", "type", "version"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"id": {"type": "string"}, "type": {"type": "string"},
|
|
26
|
+
"version": {"type": ["string", "null"]}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"correlation": {
|
|
30
|
+
"type": "object", "additionalProperties": false,
|
|
31
|
+
"required": ["correlation_id", "mission_id", "engineering_action_id"],
|
|
32
|
+
"properties": {
|
|
33
|
+
"correlation_id": {"type": ["string", "null"]},
|
|
34
|
+
"mission_id": {"type": ["string", "null"]},
|
|
35
|
+
"engineering_action_id": {"type": ["string", "null"]}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"provenance": {
|
|
39
|
+
"type": "object", "additionalProperties": false,
|
|
40
|
+
"required": ["status", "forge_execution"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"status": {"type": "string"},
|
|
43
|
+
"forge_execution": {"type": ["object", "null"]}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"disposition": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"required": ["state", "terminal", "execution_eligible", "revision", "operation_id", "event_reference", "reason", "actor_reference", "recorded_at", "resolution_submission_id", "retry_parent_run_id"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"state": {"enum": ["QUEUED", "DEFERRED", "QUARANTINED", "DECLINED", "CLAIMED", "RUNNING", "COMPLETE", "BLOCKED", "FAILED", "DISMISSED"]},
|
|
52
|
+
"terminal": {"type": "boolean"},
|
|
53
|
+
"execution_eligible": {"type": "boolean"},
|
|
54
|
+
"revision": {"type": "integer", "minimum": 0},
|
|
55
|
+
"operation_id": {"type": ["string", "null"]},
|
|
56
|
+
"event_reference": {"type": ["string", "null"]},
|
|
57
|
+
"reason": {"type": "string"},
|
|
58
|
+
"actor_reference": {"type": "string"},
|
|
59
|
+
"recorded_at": {"type": ["string", "null"]},
|
|
60
|
+
"resolution_submission_id": {"type": ["string", "null"]},
|
|
61
|
+
"retry_parent_run_id": {"type": ["string", "null"]}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"run": {
|
|
65
|
+
"type": ["object", "null"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"id": {"type": "string", "minLength": 1},
|
|
68
|
+
"state": {"type": "string", "minLength": 1},
|
|
69
|
+
"terminal": {"type": "boolean"},
|
|
70
|
+
"operator_resolution": {"type": "string"},
|
|
71
|
+
"updated_at": {"type": "string"},
|
|
72
|
+
"execution_started_at": {"type": "string", "format": "date-time"},
|
|
73
|
+
"execution_completed_at": {"type": "string", "format": "date-time"},
|
|
74
|
+
"execution_duration_ms": {"type": "integer", "minimum": 1}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"result": {
|
|
78
|
+
"type": "object", "additionalProperties": false,
|
|
79
|
+
"required": ["outcome", "terminal", "delivery_qualified"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"outcome": {"type": "string"},
|
|
82
|
+
"terminal": {"type": "boolean"},
|
|
83
|
+
"delivery_qualified": {"type": "boolean"}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"evidence": {
|
|
87
|
+
"type": "object", "additionalProperties": false,
|
|
88
|
+
"required": ["status", "terminal_artifact", "repository"],
|
|
89
|
+
"properties": {
|
|
90
|
+
"status": {"type": "string"},
|
|
91
|
+
"terminal_artifact": {"type": ["object", "null"]},
|
|
92
|
+
"repository": {
|
|
93
|
+
"type": "object", "additionalProperties": false,
|
|
94
|
+
"required": ["id", "revision"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"id": {"type": ["string", "null"]},
|
|
97
|
+
"revision": {"type": ["string", "null"]}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|