engineering-platform 2.3.90__tar.gz → 2.3.92__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.90 → engineering_platform-2.3.92}/PKG-INFO +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/pyproject.toml +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/dashboard.css +3 -3
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_host.py +124 -5
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_repository.py +76 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_timing.py +23 -0
- engineering_platform-2.3.92/src/engineering_platform/managed_workspace_readiness.py +85 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/parity_context.py +5 -2
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/parity_lifecycle_dispatcher.py +8 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/platform_version.py +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/revision_binding.py +10 -4
- engineering_platform-2.3.92/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +103 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/server.py +64 -3
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/submission_service.py +42 -3
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/templates/workspace-config.json +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/workspace_preflight.py +10 -2
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform.egg-info/PKG-INFO +1 -1
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform.egg-info/SOURCES.txt +2 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/README.md +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/setup.cfg +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/__init__.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/__main__.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/agent_state.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/agent_trust.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/dashboard.js +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/dashboard_locales.mjs +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/assurance_scope.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/capability_preflight.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/capability_review.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/central_data_transfer.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/central_database.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/central_operational_reset.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/central_store_migration.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/codex_capacity.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/codex_chat.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/codex_observability.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/component_lock.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/component_logging.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/console_presentation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/console_route_ownership.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/contracts/__init__.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/contracts/ep_consumer.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/contracts/models.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/contracts/projection.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/dashboard_browser_validation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/dashboard_state.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/dashboard_supervisor.swift +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/dashboard_translation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/dependabot_producer.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/development_profile.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/drift_diagnostics.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/emergency_recovery.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/engineering_memory.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/ep_consumer_credentials.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/evidence_projection.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_activity.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_context.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_errors.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_evidence.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_executor.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_finalization.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_host_evidence.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_lease.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_lifecycle.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_models.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_readiness.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_reporting.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_timeout_policy.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/execution_transaction.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/external_producer_binding.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/file_inbox.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/forensic_attribution.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/forensic_attribution_v2.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/forensic_delta.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/golden_scenario.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/host_admin.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/host_preflight.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_relocation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_activation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_admission.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_backup.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_composition.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_executor.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_migration.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_operation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_plan.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/installation_update_preparation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/investigation_ledger.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/legacy_inbox_migration.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/legacy_installation_adoption.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/lifecycle_worker.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/live_status.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/local_api.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/local_api_keychain.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/local_repository_binding.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/managed_autonomy.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/managed_codex_runtime.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/merge_delegation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/operational_installation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/operational_installation_lock.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/operational_installation_record.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/owner_credential_recovery.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/platform_admin.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/platform_api.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/platform_bootstrap.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/platform_components.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/pr_check_repair.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/pr_evidence_backfill.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/producer.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/product_installation_readback.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/project_agent.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/project_agent_service.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/project_topology.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/prompt_history.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_context.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_context_benchmark.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_context_scope.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_interruption.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_process_identity.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_readiness.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_recovery.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/provider_usage.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/providers.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/qualification.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/qualification_runtime.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/recommendation_handoff.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/reconciliation_adoption.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/release_operation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/report_analysis.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/repository_attachment.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/repository_handoff.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/resources.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/reviewer_evidence.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/server_console_services.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/server_relay.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/server_service.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/status_model.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/status_reconciliation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/storage.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/submission_cli.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/submission_intake.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/system_installation_topology.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/system_server_service.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/telemetry.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/telemetry_contract.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/telemetry_export.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/telemetry_metrics.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/validation_identity.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/validation_profile.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/version_preparation_delivery.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/worktree_provenance.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform/worktree_tooling.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform.egg-info/entry_points.txt +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/src/engineering_platform.egg-info/top_level.txt +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/tests/test_adaptive_action_sizing_design.py +0 -0
- {engineering_platform-2.3.90 → engineering_platform-2.3.92}/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.92",
|
|
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.92",
|
|
10
10
|
"report_format": 2,
|
|
11
|
-
"runner_version": "2.3.
|
|
11
|
+
"runner_version": "2.3.92",
|
|
12
12
|
"status_model": 1,
|
|
13
13
|
"storage_schema": 45,
|
|
14
|
-
"watcher_version": "2.3.
|
|
14
|
+
"watcher_version": "2.3.92"
|
|
15
15
|
}
|
|
@@ -1144,9 +1144,9 @@ html[data-theme="light"] .dashboard-status-banner--provider-auth_required .provi
|
|
|
1144
1144
|
the other operational banners rather than as a scrolling dashboard card. */
|
|
1145
1145
|
.dashboard-sticky-header:has(#noProjectSelected:not([hidden])){padding-bottom:7px}.dashboard-status-banner--no-project{align-items:center;background:#163b59;border-bottom:1px solid #62bdf0;color:#e7f5ff;font:600 13px/1.45 system-ui}.dashboard-status-banner--no-project strong{color:#9bd7ff}.no-project-selected__dismiss{align-items:center;background:transparent!important;border:1px solid currentColor!important;border-radius:50%;color:inherit!important;cursor:pointer;display:inline-flex;flex:none;font:22px/1 system-ui;height:30px;justify-content:center;margin-left:auto;min-height:30px;min-width:30px;padding:0;width:30px}.no-project-selected__dismiss:hover,.no-project-selected__dismiss:focus-visible{background:#9bd7ff!important;border-color:#9bd7ff!important;color:#123a58!important}.no-project-selected__dismiss:focus-visible{box-shadow:0 0 0 4px #9bd7ff55!important;outline:2px solid #9bd7ff!important;outline-offset:2px!important}html[data-theme="light"] .dashboard-status-banner--no-project{background:#e2f3ff;color:#12466b}html[data-theme="light"] .dashboard-status-banner--no-project strong{color:#075985}html[data-theme="light"] .no-project-selected__dismiss:hover,html[data-theme="light"] .no-project-selected__dismiss:focus-visible{background:#075985!important;border-color:#075985!important;color:#fff!important}
|
|
1146
1146
|
|
|
1147
|
-
/*
|
|
1148
|
-
|
|
1149
|
-
.prompt-detail-card--pull-requests
|
|
1147
|
+
/* Active PR evidence starts in the left column directly below the lifecycle.
|
|
1148
|
+
Historical Mission details keep PR evidence in their right context column. */
|
|
1149
|
+
.prompt-detail-card--pull-requests{grid-column:2}.active-run-pull-requests{grid-column:1}.prompt-detail-pr-link{border-bottom:1px solid currentColor;color:var(--category-color);font-weight:400;text-decoration:none}.prompt-detail-pr-link:hover{background:transparent;color:var(--category-color);outline:0}.prompt-detail-pr-link:focus-visible{background:transparent;color:var(--category-color);outline:2px solid var(--category-color);outline-offset:2px}.prompt-detail-pr-metrics{color:var(--dashboard-modal-muted);display:flex;flex-wrap:wrap;font-size:12px;gap:5px 12px;margin-top:7px}.prompt-detail-pr-metric{white-space:nowrap}@media (max-width:620px){.prompt-detail-card--pull-requests,.active-run-pull-requests{grid-column:1;grid-row:auto}}
|
|
1150
1150
|
|
|
1151
1151
|
/* Authentication is a recoverable warning, not a destructive provider failure. */
|
|
1152
1152
|
.dashboard-status-banner--provider-auth_required .provider-readiness-banner__action{background:transparent!important;border-color:#ffd768!important;color:#fff4d6!important}.dashboard-status-banner--provider-auth_required .provider-readiness-banner__action:hover:not(:disabled),.dashboard-status-banner--provider-auth_required .provider-readiness-banner__action:focus-visible{background:#f4c34f!important;border-color:#ffd768!important;color:#2a2415!important}.dashboard-status-banner--provider-auth_required .provider-readiness-banner__action:focus-visible{box-shadow:0 0 0 4px #f4c34f88;outline-color:#ffd768}
|
|
@@ -119,6 +119,7 @@ from .execution_timing import complete_active_phase as _complete_active_phase
|
|
|
119
119
|
from .execution_timing import complete_phase as _complete_phase
|
|
120
120
|
from .execution_timing import start_or_resume_phase as _start_or_resume_phase
|
|
121
121
|
from .execution_timing import start_phase as _start_phase
|
|
122
|
+
from .execution_timing import update_active_phase_metadata as _update_active_phase_metadata
|
|
122
123
|
from .managed_autonomy import (
|
|
123
124
|
append_action as record_managed_action,
|
|
124
125
|
append_pr_check_observation as record_managed_pr_check,
|
|
@@ -194,6 +195,20 @@ def complete_phase(root: Path, active: ActivePhase | None, **kwargs: object) ->
|
|
|
194
195
|
)
|
|
195
196
|
|
|
196
197
|
|
|
198
|
+
def update_phase_metadata(
|
|
199
|
+
root: Path, active: ActivePhase | None, metadata: dict[str, object],
|
|
200
|
+
) -> None:
|
|
201
|
+
"""Publish optional bounded live phase data without affecting the run."""
|
|
202
|
+
if active is None:
|
|
203
|
+
return
|
|
204
|
+
try:
|
|
205
|
+
_update_active_phase_metadata(root, active, metadata)
|
|
206
|
+
except EngineeringStorageError as error:
|
|
207
|
+
_timing_unavailable(
|
|
208
|
+
root, active.run_id, error, central_database=active.central_database,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
197
212
|
def complete_active_phase(root: Path, run_id: str, phase_name: str, **kwargs: object) -> bool:
|
|
198
213
|
try:
|
|
199
214
|
return _complete_active_phase(root, run_id, phase_name, **kwargs)
|
|
@@ -700,6 +715,7 @@ class EngineeringRunner:
|
|
|
700
715
|
selection: ReviewerSelection,
|
|
701
716
|
event: str,
|
|
702
717
|
result: ReviewerResult | None = None,
|
|
718
|
+
phase: ActivePhase | None = None,
|
|
703
719
|
) -> None:
|
|
704
720
|
"""Publish bounded reviewer lifecycle status without granting reviewer authority."""
|
|
705
721
|
self._heartbeat()
|
|
@@ -725,6 +741,18 @@ class EngineeringRunner:
|
|
|
725
741
|
else 0
|
|
726
742
|
)
|
|
727
743
|
break
|
|
744
|
+
update_phase_metadata(
|
|
745
|
+
self.root,
|
|
746
|
+
phase,
|
|
747
|
+
{"reviewer_agents": [
|
|
748
|
+
{
|
|
749
|
+
"reviewer": str(item.get("reviewer", ""))[:80],
|
|
750
|
+
"capability": str(item.get("capability", "engineering"))[:80],
|
|
751
|
+
"status": str(item.get("status", "selected"))[:16],
|
|
752
|
+
}
|
|
753
|
+
for item in self.reviewer_runtime[:12]
|
|
754
|
+
]},
|
|
755
|
+
)
|
|
728
756
|
write_live_status(self.root, state, "Capability review: " + selection.reviewer, self.reviewer_runtime)
|
|
729
757
|
|
|
730
758
|
def _persist_agent_usage(self, run_id: str) -> None:
|
|
@@ -3086,6 +3114,15 @@ First implementation pull-request publication gate:
|
|
|
3086
3114
|
"Accepted repository revision binding is invalid.",
|
|
3087
3115
|
)
|
|
3088
3116
|
if revision_binding is not None:
|
|
3117
|
+
if (revision_binding.repository_identity is not None
|
|
3118
|
+
and (evidence.repository != revision_binding.repository_identity
|
|
3119
|
+
or not callable(getattr(self.repository, "trusted_origin_identity", None))
|
|
3120
|
+
or self.repository.trusted_origin_identity(self.root)
|
|
3121
|
+
!= revision_binding.repository_identity)):
|
|
3122
|
+
return self._save_terminal(
|
|
3123
|
+
state, "BLOCKED", "repository_identity_binding",
|
|
3124
|
+
"Managed workspace origin differs from the authorized repository identity.",
|
|
3125
|
+
)
|
|
3089
3126
|
if state.requested_repository_revision not in {None, revision_binding.requested_revision}:
|
|
3090
3127
|
return self._save_terminal(
|
|
3091
3128
|
state, "BLOCKED", "repository_revision_binding",
|
|
@@ -3212,10 +3249,47 @@ First implementation pull-request publication gate:
|
|
|
3212
3249
|
self.transaction = self.transaction.with_lease(self.active_lease)
|
|
3213
3250
|
self.lease_heartbeat.start()
|
|
3214
3251
|
if recovered_resume:
|
|
3252
|
+
self._heartbeat()
|
|
3253
|
+
if revision_binding is not None and context.execution_mode == "MANAGED":
|
|
3254
|
+
recovered_head = self.repository.inspect(self.root)
|
|
3255
|
+
expected_baseline = (
|
|
3256
|
+
revision_binding.allowed_baseline_revision
|
|
3257
|
+
or revision_binding.requested_revision
|
|
3258
|
+
)
|
|
3259
|
+
if (state.execution_baseline_sha != expected_baseline
|
|
3260
|
+
or recovered_head.repository != state.repository
|
|
3261
|
+
or not recovered_head.clean
|
|
3262
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3263
|
+
or (state.branch is not None and recovered_head.branch not in {state.branch, "main"})
|
|
3264
|
+
or not callable(getattr(self.repository, "trusted_origin_identity", None))
|
|
3265
|
+
or self.repository.trusted_origin_identity(self.root) != state.repository
|
|
3266
|
+
or not callable(getattr(self.repository, "revision_is_ancestor", None))
|
|
3267
|
+
or not self.repository.revision_is_ancestor(
|
|
3268
|
+
self.root, expected_baseline, recovered_head.head_sha,
|
|
3269
|
+
)):
|
|
3270
|
+
return self._save_terminal(
|
|
3271
|
+
state, "BLOCKED", "recovered_workspace_baseline",
|
|
3272
|
+
"Recovered provider result lacks the authorized workspace baseline.",
|
|
3273
|
+
)
|
|
3215
3274
|
# Consume immutable attempt-two evidence before any fresh provider
|
|
3216
3275
|
# preparation or repository synchronization. This preserves the
|
|
3217
3276
|
# original branch/worktree and cannot allocate a new invocation.
|
|
3218
3277
|
result = self._invoke_agent_with_timing(state, "")
|
|
3278
|
+
if (revision_binding is not None and context.execution_mode == "MANAGED"
|
|
3279
|
+
and recovery_snapshot["lifecycle_phase"] == "EXECUTE_AGENT"
|
|
3280
|
+
and result.terminal_state == "COMPLETE"):
|
|
3281
|
+
result_head = self.repository.inspect(self.root)
|
|
3282
|
+
if (not result.commit_sha or not result.branch
|
|
3283
|
+
or result_head.head_sha != result.commit_sha
|
|
3284
|
+
or result_head.branch != result.branch or not result_head.clean
|
|
3285
|
+
or self.repository.trusted_origin_identity(self.root) != state.repository
|
|
3286
|
+
or not self.repository.revision_is_ancestor(
|
|
3287
|
+
self.root, state.execution_baseline_sha, result.commit_sha,
|
|
3288
|
+
)):
|
|
3289
|
+
return self._save_terminal(
|
|
3290
|
+
state, "BLOCKED", "recovered_workspace_result_drift",
|
|
3291
|
+
"Recovered provider result no longer matches the bound workspace commit.",
|
|
3292
|
+
)
|
|
3219
3293
|
state = self._record_agent_execution_time(state)
|
|
3220
3294
|
state = self._record_validation_evidence(state, result)
|
|
3221
3295
|
state = self._record_verified_result_commit(
|
|
@@ -3229,10 +3303,18 @@ First implementation pull-request publication gate:
|
|
|
3229
3303
|
# and so the bounded retry policy in the repository client is used.
|
|
3230
3304
|
if context.execution_mode == "MANAGED":
|
|
3231
3305
|
try:
|
|
3232
|
-
#
|
|
3233
|
-
#
|
|
3234
|
-
#
|
|
3235
|
-
if revision_binding is None
|
|
3306
|
+
# An exact pin is prepared by the owning repository client
|
|
3307
|
+
# under this lease. It may fast forward only to that SHA,
|
|
3308
|
+
# never to an ambient newer origin/main.
|
|
3309
|
+
if revision_binding is not None and revision_binding.allowed_baseline_revision is None:
|
|
3310
|
+
prepare = getattr(self.repository, "prepare_main_revision", None)
|
|
3311
|
+
if not callable(prepare):
|
|
3312
|
+
raise RunnerError("MANAGED_PREPARATION_UNAVAILABLE")
|
|
3313
|
+
evidence = prepare(
|
|
3314
|
+
self.root, revision_binding.requested_revision,
|
|
3315
|
+
revision_binding.repository_identity or state.repository,
|
|
3316
|
+
)
|
|
3317
|
+
else:
|
|
3236
3318
|
self.repository.synchronize_main(self.root)
|
|
3237
3319
|
# The initial observation predates lease acquisition. Always
|
|
3238
3320
|
# refresh it here: an exact pin skips synchronization, never
|
|
@@ -3312,6 +3394,18 @@ First implementation pull-request publication gate:
|
|
|
3312
3394
|
}
|
|
3313
3395
|
for item in selections
|
|
3314
3396
|
]
|
|
3397
|
+
update_phase_metadata(
|
|
3398
|
+
self.root,
|
|
3399
|
+
capability_review,
|
|
3400
|
+
{"reviewer_agents": [
|
|
3401
|
+
{
|
|
3402
|
+
"reviewer": str(item["reviewer"])[:80],
|
|
3403
|
+
"capability": str(item["capability"])[:80],
|
|
3404
|
+
"status": "selected",
|
|
3405
|
+
}
|
|
3406
|
+
for item in self.reviewer_runtime[:12]
|
|
3407
|
+
]},
|
|
3408
|
+
)
|
|
3315
3409
|
write_live_status(
|
|
3316
3410
|
self.root,
|
|
3317
3411
|
state
|
|
@@ -3326,13 +3420,26 @@ First implementation pull-request publication gate:
|
|
|
3326
3420
|
self.reviewer_runtime,
|
|
3327
3421
|
)
|
|
3328
3422
|
self._require_provider_dispatch_admission(state)
|
|
3423
|
+
self._heartbeat()
|
|
3424
|
+
if state.execution_mode == "MANAGED" and state.execution_baseline_sha is not None:
|
|
3425
|
+
reviewer_head = self.repository.inspect(self.root)
|
|
3426
|
+
if (reviewer_head.repository != state.repository or reviewer_head.branch != "main"
|
|
3427
|
+
or not reviewer_head.clean or reviewer_head.head_sha != state.execution_baseline_sha
|
|
3428
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3429
|
+
or (state.requested_repository_revision is not None
|
|
3430
|
+
and self.repository.trusted_origin_identity(self.root) != state.repository)):
|
|
3431
|
+
complete_phase(self.root, capability_review, outcome="FAILED")
|
|
3432
|
+
return self._save_terminal(
|
|
3433
|
+
state, "BLOCKED", "managed_workspace_drift",
|
|
3434
|
+
"Managed workspace changed after baseline admission and before capability review.",
|
|
3435
|
+
)
|
|
3329
3436
|
results = run_reviews(
|
|
3330
3437
|
self.root,
|
|
3331
3438
|
selections,
|
|
3332
3439
|
objective,
|
|
3333
3440
|
self.agent if hasattr(self.agent, "review") else None,
|
|
3334
3441
|
progress=lambda selection, event, result: self._publish_reviewer_progress(
|
|
3335
|
-
state, selection, event, result
|
|
3442
|
+
state, selection, event, result, capability_review
|
|
3336
3443
|
),
|
|
3337
3444
|
evidence=reviewer_evidence,
|
|
3338
3445
|
)
|
|
@@ -3426,6 +3533,18 @@ First implementation pull-request publication gate:
|
|
|
3426
3533
|
),
|
|
3427
3534
|
)[1]
|
|
3428
3535
|
)
|
|
3536
|
+
if state.execution_mode == "MANAGED" and state.execution_baseline_sha is not None:
|
|
3537
|
+
self._heartbeat()
|
|
3538
|
+
execution_head = self.repository.inspect(self.root)
|
|
3539
|
+
if (execution_head.repository != state.repository or execution_head.branch != "main"
|
|
3540
|
+
or not execution_head.clean or execution_head.head_sha != state.execution_baseline_sha
|
|
3541
|
+
or self.repository.workspace_operation_active(self.root)
|
|
3542
|
+
or (state.requested_repository_revision is not None
|
|
3543
|
+
and self.repository.trusted_origin_identity(self.root) != state.repository)):
|
|
3544
|
+
return self._save_terminal(
|
|
3545
|
+
state, "BLOCKED", "managed_workspace_drift",
|
|
3546
|
+
"Managed workspace changed after baseline admission and before provider implementation.",
|
|
3547
|
+
)
|
|
3429
3548
|
result = self._invoke_agent_with_timing(
|
|
3430
3549
|
state,
|
|
3431
3550
|
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.")
|
|
@@ -132,6 +132,29 @@ def complete_phase(root: Path, active: ActivePhase, *, outcome: str = "COMPLETE"
|
|
|
132
132
|
connection.close()
|
|
133
133
|
|
|
134
134
|
|
|
135
|
+
def update_active_phase_metadata(
|
|
136
|
+
root: Path, active: ActivePhase, metadata: Mapping[str, object],
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Replace bounded metadata for one exact active phase.
|
|
139
|
+
|
|
140
|
+
Live projections can change while the measured phase is active. The phase
|
|
141
|
+
identity and timing remain immutable; only its bounded presentation data is
|
|
142
|
+
replaced, and a terminal phase cannot be rewritten.
|
|
143
|
+
"""
|
|
144
|
+
encoded = _metadata(metadata)
|
|
145
|
+
connection = _connection(root, active.central_database)
|
|
146
|
+
try:
|
|
147
|
+
changed = connection.execute(
|
|
148
|
+
"""UPDATE execution_phase_spans SET metadata=?
|
|
149
|
+
WHERE phase_id=? AND run_id=? AND outcome='ACTIVE'""",
|
|
150
|
+
(encoded, active.phase_id, active.run_id),
|
|
151
|
+
).rowcount
|
|
152
|
+
if changed != 1:
|
|
153
|
+
raise EngineeringStorageError("Execution phase is not active.")
|
|
154
|
+
finally:
|
|
155
|
+
connection.close()
|
|
156
|
+
|
|
157
|
+
|
|
135
158
|
def start_or_resume_phase(root: Path, run_id: str, phase_name: str, **kwargs: object) -> ActivePhase:
|
|
136
159
|
"""Start one envelope or resume its observed active database boundary.
|
|
137
160
|
|
|
@@ -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.92"
|
|
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)
|