engineering-platform 2.3.91__tar.gz → 2.3.93__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/PKG-INFO +1 -1
  2. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/pyproject.toml +1 -1
  3. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
  4. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
  5. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/dashboard.css +4 -4
  6. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/dashboard.js +139 -12
  7. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/dashboard_locales.mjs +10 -0
  8. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_host.py +71 -1
  9. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_timing.py +23 -0
  10. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/platform_version.py +1 -1
  11. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/server.py +51 -0
  12. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/server_console_services.py +24 -1
  13. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/templates/workspace-config.json +1 -1
  14. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform.egg-info/PKG-INFO +1 -1
  15. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/README.md +0 -0
  16. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/setup.cfg +0 -0
  17. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/__init__.py +0 -0
  18. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/__main__.py +0 -0
  19. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/agent_state.py +0 -0
  20. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/agent_trust.py +0 -0
  21. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  22. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
  23. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  24. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  25. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  26. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  27. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  28. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  29. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/assurance_scope.py +0 -0
  30. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/capability_preflight.py +0 -0
  31. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/capability_review.py +0 -0
  32. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/central_data_transfer.py +0 -0
  33. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/central_database.py +0 -0
  34. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/central_operational_reset.py +0 -0
  35. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/central_store_migration.py +0 -0
  36. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/codex_capacity.py +0 -0
  37. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/codex_chat.py +0 -0
  38. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/codex_observability.py +0 -0
  39. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/component_lock.py +0 -0
  40. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/component_logging.py +0 -0
  41. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/console_presentation.py +0 -0
  42. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/console_route_ownership.py +0 -0
  43. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/contracts/__init__.py +0 -0
  44. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  45. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/contracts/models.py +0 -0
  46. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/contracts/projection.py +0 -0
  47. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/dashboard_browser_validation.py +0 -0
  48. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/dashboard_state.py +0 -0
  49. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  50. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/dashboard_translation.py +0 -0
  51. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/dependabot_producer.py +0 -0
  52. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/development_profile.py +0 -0
  53. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/drift_diagnostics.py +0 -0
  54. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/emergency_recovery.py +0 -0
  55. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/engineering_memory.py +0 -0
  56. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  57. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/evidence_projection.py +0 -0
  58. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_activity.py +0 -0
  59. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_context.py +0 -0
  60. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_errors.py +0 -0
  61. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_evidence.py +0 -0
  62. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_executor.py +0 -0
  63. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_finalization.py +0 -0
  64. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_host_evidence.py +0 -0
  65. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_lease.py +0 -0
  66. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_lifecycle.py +0 -0
  67. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_models.py +0 -0
  68. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_readiness.py +0 -0
  69. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_reporting.py +0 -0
  70. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_repository.py +0 -0
  71. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_timeout_policy.py +0 -0
  72. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/execution_transaction.py +0 -0
  73. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/external_producer_binding.py +0 -0
  74. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/file_inbox.py +0 -0
  75. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/forensic_attribution.py +0 -0
  76. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  77. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/forensic_delta.py +0 -0
  78. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/golden_scenario.py +0 -0
  79. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  80. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/host_admin.py +0 -0
  81. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/host_preflight.py +0 -0
  82. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_relocation.py +0 -0
  83. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_activation.py +0 -0
  84. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_admission.py +0 -0
  85. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_backup.py +0 -0
  86. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_composition.py +0 -0
  87. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_executor.py +0 -0
  88. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_migration.py +0 -0
  89. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_operation.py +0 -0
  90. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_plan.py +0 -0
  91. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/installation_update_preparation.py +0 -0
  92. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/investigation_ledger.py +0 -0
  93. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  94. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/legacy_installation_adoption.py +0 -0
  95. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/lifecycle_worker.py +0 -0
  96. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/live_status.py +0 -0
  97. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/local_api.py +0 -0
  98. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/local_api_keychain.py +0 -0
  99. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/local_repository_binding.py +0 -0
  100. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/managed_autonomy.py +0 -0
  101. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/managed_codex_runtime.py +0 -0
  102. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/managed_workspace_readiness.py +0 -0
  103. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/merge_delegation.py +0 -0
  104. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/operational_installation.py +0 -0
  105. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/operational_installation_lock.py +0 -0
  106. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/operational_installation_record.py +0 -0
  107. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/owner_credential_recovery.py +0 -0
  108. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/parity_context.py +0 -0
  109. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
  110. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/platform_admin.py +0 -0
  111. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/platform_api.py +0 -0
  112. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/platform_bootstrap.py +0 -0
  113. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/platform_components.py +0 -0
  114. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/pr_check_repair.py +0 -0
  115. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  116. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/producer.py +0 -0
  117. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/product_installation_readback.py +0 -0
  118. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/project_agent.py +0 -0
  119. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/project_agent_service.py +0 -0
  120. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/project_topology.py +0 -0
  121. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/prompt_history.py +0 -0
  122. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_context.py +0 -0
  123. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_context_benchmark.py +0 -0
  124. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_context_scope.py +0 -0
  125. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_interruption.py +0 -0
  126. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_process_identity.py +0 -0
  127. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_readiness.py +0 -0
  128. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_recovery.py +0 -0
  129. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/provider_usage.py +0 -0
  130. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/providers.py +0 -0
  131. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/qualification.py +0 -0
  132. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/qualification_runtime.py +0 -0
  133. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/recommendation_handoff.py +0 -0
  134. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/reconciliation_adoption.py +0 -0
  135. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/release_operation.py +0 -0
  136. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/report_analysis.py +0 -0
  137. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/repository_attachment.py +0 -0
  138. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/repository_handoff.py +0 -0
  139. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/resources.py +0 -0
  140. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/reviewer_evidence.py +0 -0
  141. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/revision_binding.py +0 -0
  142. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
  143. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +0 -0
  144. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  145. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  146. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/server_relay.py +0 -0
  147. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/server_service.py +0 -0
  148. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/status_model.py +0 -0
  149. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/status_reconciliation.py +0 -0
  150. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/storage.py +0 -0
  151. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/submission_cli.py +0 -0
  152. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/submission_intake.py +0 -0
  153. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/submission_service.py +0 -0
  154. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/system_installation_topology.py +0 -0
  155. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/system_server_service.py +0 -0
  156. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/telemetry.py +0 -0
  157. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/telemetry_contract.py +0 -0
  158. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/telemetry_export.py +0 -0
  159. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/telemetry_metrics.py +0 -0
  160. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
  161. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/validation_identity.py +0 -0
  162. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/validation_profile.py +0 -0
  163. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/version_preparation_delivery.py +0 -0
  164. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/workspace_preflight.py +0 -0
  165. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/worktree_provenance.py +0 -0
  166. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform/worktree_tooling.py +0 -0
  167. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
  168. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  169. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  170. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/src/engineering_platform.egg-info/top_level.txt +0 -0
  171. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/tests/test_adaptive_action_sizing_design.py +0 -0
  172. {engineering_platform-2.3.91 → engineering_platform-2.3.93}/tests/test_role_task_model_policy_design.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-platform
3
- Version: 2.3.91
3
+ Version: 2.3.93
4
4
  Summary: Local-first Engineering Platform execution operations runtime
5
5
  Author: Peter van Tol
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "engineering-platform"
7
- version = "2.3.91"
7
+ version = "2.3.93"
8
8
  description = "Local-first Engineering Platform execution operations runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.14,<3.15"
@@ -3,7 +3,7 @@
3
3
  "platform": {
4
4
  "id": "engineering-platform",
5
5
  "name": "Engineering Platform",
6
- "version": "2.3.91",
6
+ "version": "2.3.93",
7
7
  "generation": 2,
8
8
  "documentation_namespace": "engineering-platform",
9
9
  "capability_registry_version": 1
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "bootstrap_contract": "2026.12",
3
3
  "checkpoint_format": 1,
4
- "dashboard_version": "2.3.91",
4
+ "dashboard_version": "2.3.93",
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.91",
9
+ "platform_version": "2.3.93",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.91",
11
+ "runner_version": "2.3.93",
12
12
  "status_model": 1,
13
13
  "storage_schema": 45,
14
- "watcher_version": "2.3.91"
14
+ "watcher_version": "2.3.93"
15
15
  }
@@ -990,7 +990,7 @@ html[data-theme="light"] ::-webkit-scrollbar-thumb:hover{background:#0a6b9d}
990
990
  /* Telemetry can contain multiple long tables. Keep its outer dialog within
991
991
  the visual viewport and scroll only its evidence body on small screens. */
992
992
  .telemetry-detail-modal{--modal-accent:#fb7185;--category-color:var(--modal-accent);--modal-outer-gutter:24px;--modal-panel-max-width:1120px;--modal-shell-inset:24px;--modal-shell-padding:0}.telemetry-detail-modal__panel{--modal-header-inset:var(--dashboard-modal-panel-padding);display:grid;grid-template-rows:auto auto minmax(0,1fr);height:100%;max-height:100%;overflow:hidden;width:min(1120px,100%)}.telemetry-detail-modal__content{max-height:none;min-height:0;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;padding:0 4px 4px}@media(max-width:620px){.telemetry-detail-modal__panel{--modal-header-inset:18px;padding:18px}.telemetry-detail-modal__content{padding-inline:2px}}
993
- .lifecycle-detail-modal{--modal-default-accent:#65c5d9;--modal-panel-max-width:920px}.lifecycle-detail-modal__panel{background:var(--modal-surface);border:2px solid var(--modal-accent);border-radius:var(--dashboard-modal-radius);box-sizing:border-box;color:var(--dashboard-modal-ink);display:grid;grid-template-rows:auto minmax(0,1fr);max-width:min(920px,calc(100vw - 32px));overflow:hidden;padding:var(--dashboard-modal-panel-padding);width:100%}.lifecycle-detail-modal__content{color:var(--dashboard-modal-ink);display:grid;gap:18px;max-height:none;min-height:0;overflow:auto;overscroll-behavior:contain;padding:4px}.lifecycle-detail-modal__content .field>span:last-child{color:var(--dashboard-modal-ink)}.lifecycle-detail-modal__content h3{color:var(--modal-accent);font-size:16px;margin:0 0 8px}.lifecycle-detail-modal :is(.label,.lifecycle-detail-modal__phase-list strong){color:var(--modal-secondary-accent)}.lifecycle-detail-modal__phase-list{display:grid;gap:8px;list-style:none;margin:0;padding:0}.lifecycle-detail-modal__phase-list li{align-items:baseline;border-bottom:1px solid color-mix(in srgb,var(--modal-accent) 32%,transparent);display:flex;gap:12px;justify-content:space-between;padding:8px 0}.lifecycle-detail-modal__phase-list li:last-child{border-bottom:0}.lifecycle-detail-modal__assurance-evidence .lifecycle-detail-modal__phase-list strong{flex:0 0 auto;white-space:nowrap}.lifecycle-detail-modal__assurance-evidence .lifecycle-detail-modal__phase-list span{flex:1 1 0;min-width:0;overflow-wrap:anywhere}.lifecycle-detail-modal__phase-list span{color:var(--dashboard-modal-muted);text-align:start}html[data-theme="light"] .lifecycle-detail-modal :is(.label,.lifecycle-detail-modal__phase-list strong){color:color-mix(in srgb,var(--modal-secondary-accent) 76%,#182230)}@media(max-width:620px){.lifecycle-detail-modal__panel{max-width:calc(100vw - 32px);padding:18px}.lifecycle-detail-modal__phase-list li{align-items:flex-start;flex-direction:column;gap:4px}.lifecycle-detail-modal__phase-list span{text-align:start}.lifecycle-detail-modal__assurance-evidence .lifecycle-detail-modal__phase-list strong{white-space:normal}}
993
+ .lifecycle-detail-modal{--modal-default-accent:#65c5d9;--modal-panel-max-width:920px}.lifecycle-detail-modal__panel{background:var(--modal-surface);border:2px solid var(--modal-accent);border-radius:var(--dashboard-modal-radius);box-sizing:border-box;color:var(--dashboard-modal-ink);display:grid;grid-template-rows:auto minmax(0,1fr);max-width:min(920px,calc(100vw - 32px));overflow:hidden;padding:var(--dashboard-modal-panel-padding);width:100%}.lifecycle-detail-modal__content{color:var(--dashboard-modal-ink);display:grid;gap:18px;max-height:none;min-height:0;overflow:auto;overscroll-behavior:contain;padding:4px}.lifecycle-detail-modal__content .field>span:last-child{color:var(--dashboard-modal-ink)}.lifecycle-detail-modal__content h3{color:var(--modal-accent);font-size:16px;margin:0 0 8px}.lifecycle-detail-modal__content h4{color:var(--dashboard-modal-ink);font-size:15px;margin:0 0 14px}.lifecycle-detail-modal :is(.label,.lifecycle-detail-modal__phase-list strong){color:var(--modal-secondary-accent)}.lifecycle-detail-modal__phase-list{display:grid;gap:8px;list-style:none;margin:0;padding:0}.lifecycle-detail-modal__phase-list li{align-items:baseline;border-bottom:1px solid color-mix(in srgb,var(--modal-accent) 32%,transparent);display:flex;gap:12px;justify-content:space-between;padding:8px 0}.lifecycle-detail-modal__phase-list li:last-child{border-bottom:0}.lifecycle-detail-modal :is(.lifecycle-detail-modal__assurance-evidence,.lifecycle-detail-modal__reviewer-evidence) .lifecycle-detail-modal__phase-list li{align-items:flex-start;flex-direction:column;gap:7px}.lifecycle-detail-modal :is(.lifecycle-detail-modal__assurance-evidence,.lifecycle-detail-modal__reviewer-evidence) .lifecycle-detail-modal__phase-list strong{white-space:normal}.lifecycle-detail-modal :is(.lifecycle-detail-modal__assurance-evidence,.lifecycle-detail-modal__reviewer-evidence) .lifecycle-detail-modal__phase-list span{min-width:0;overflow-wrap:anywhere;width:100%}.lifecycle-detail-modal__repair-iteration{padding:4px 0 10px}.lifecycle-detail-modal__repair-iteration+.lifecycle-detail-modal__repair-iteration{border-top:1px solid color-mix(in srgb,var(--modal-accent) 48%,transparent);margin-top:18px;padding-top:22px}.lifecycle-detail-modal__phase-list span{color:var(--dashboard-modal-muted);text-align:start}html[data-theme="light"] .lifecycle-detail-modal :is(.label,.lifecycle-detail-modal__phase-list strong){color:color-mix(in srgb,var(--modal-secondary-accent) 76%,#182230)}@media(max-width:620px){.lifecycle-detail-modal__panel{max-width:calc(100vw - 32px);padding:18px}.lifecycle-detail-modal__phase-list li{align-items:flex-start;flex-direction:column;gap:4px}.lifecycle-detail-modal__phase-list span{text-align:start}}
994
994
  /* A telemetry Run-ID is a redundant activator inside an interactive row.
995
995
  The row owns its continuous rose selection surface, never the text itself. */
996
996
  .telemetry-run-link{-webkit-appearance:none;appearance:none;background:transparent;border:0;color:inherit;cursor:pointer;font:inherit;line-height:inherit;min-height:0;min-width:0;padding:0;text-align:left;text-decoration:none;white-space:nowrap}.telemetry-run-link:is(:hover,:active){background:transparent!important;color:inherit!important}.telemetry-run-link:is(:focus,:focus-visible){border-color:transparent!important;box-shadow:none!important;outline:0!important}
@@ -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
- /* Managed PR evidence remains a normal link, positioned under execution
1148
- context so both current and historical operational context stay scannable. */
1149
- .prompt-detail-card--pull-requests,.active-run-pull-requests{grid-column:2}.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}}
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}
@@ -2157,6 +2157,68 @@ function lifecycleAssuranceEvidence(step) {
2157
2157
  void localizeDynamicEvidence(dynamicRows);
2158
2158
  return section;
2159
2159
  }
2160
+ function lifecycleCapabilityEvidence(step) {
2161
+ const reviewers = Array.isArray(step?.reviewer_evidence) ? step.reviewer_evidence : [];
2162
+ if (!reviewers.length) return null;
2163
+ const section = document.createElement("section");
2164
+ section.className = "lifecycle-detail-modal__quality-evidence lifecycle-detail-modal__reviewer-evidence";
2165
+ section.append(Object.assign(document.createElement("h3"), {
2166
+ textContent: t("detail.specialist_reviews"),
2167
+ }));
2168
+ const list = document.createElement("ol");
2169
+ list.className = "lifecycle-detail-modal__phase-list";
2170
+ for (const reviewer of reviewers) {
2171
+ if (!reviewer || typeof reviewer !== "object") continue;
2172
+ const item = document.createElement("li");
2173
+ const details = [
2174
+ reviewerCapabilityLabel(reviewer.capability || "ENGINEERING"),
2175
+ reviewerStatusLabel(reviewer.status || "completed"),
2176
+ reviewer.selected_because
2177
+ ? t("detail.selected_because") + ": " + String(reviewer.selected_because)
2178
+ : null,
2179
+ reviewer.contribution
2180
+ ? t("detail.initial_observation") + ": " + String(reviewer.contribution)
2181
+ : null,
2182
+ Number.isInteger(reviewer.accepted_recommendations)
2183
+ ? t("detail.accepted_recommendations") + ": " + reviewer.accepted_recommendations
2184
+ : null,
2185
+ Number.isInteger(reviewer.rejected_recommendations)
2186
+ ? t("detail.rejected_recommendations") + ": " + reviewer.rejected_recommendations
2187
+ : null,
2188
+ ].filter(Boolean);
2189
+ item.append(
2190
+ Object.assign(document.createElement("strong"), {
2191
+ textContent: reviewerLabel(reviewer.reviewer, t("detail.specialist_review")),
2192
+ }),
2193
+ Object.assign(document.createElement("span"), {
2194
+ textContent: details.join("\n"),
2195
+ }),
2196
+ );
2197
+ list.append(item);
2198
+ }
2199
+ if (!list.childElementCount) return null;
2200
+ section.append(list);
2201
+ return section;
2202
+ }
2203
+ function lifecycleImplementationEvidence(step) {
2204
+ const evidence = step?.implementation_evidence;
2205
+ if (!evidence || typeof evidence !== "object") return null;
2206
+ const fields = [];
2207
+ if (evidence.branch) fields.push(lifecycleDetailField(t("workspace.current_branch"), String(evidence.branch)));
2208
+ if (evidence.candidate_sha) fields.push(lifecycleDetailField(t("detail.candidate_sha"), String(evidence.candidate_sha)));
2209
+ if (Number.isInteger(evidence.pull_request) && evidence.pull_request > 0) {
2210
+ fields.push(lifecycleDetailField(t("detail.implementation_pull_request"), `#${evidence.pull_request}`));
2211
+ }
2212
+ if (!fields.length) return null;
2213
+ const section = document.createElement("section");
2214
+ section.className = "lifecycle-detail-modal__implementation-evidence";
2215
+ section.append(
2216
+ Object.assign(document.createElement("h3"), { textContent: t("lifecycle.detail_implementation_evidence") }),
2217
+ Object.assign(document.createElement("div"), { className: "technical-grid" }),
2218
+ );
2219
+ section.lastElementChild.append(...fields);
2220
+ return section;
2221
+ }
2160
2222
  function lifecycleRepairEvidence(step) {
2161
2223
  const audit = Array.isArray(step?.repair_audit) ? step.repair_audit : [];
2162
2224
  if (!audit.length) return null;
@@ -2171,9 +2233,16 @@ function lifecycleRepairEvidence(step) {
2171
2233
  const iteration = String(item.iteration || "").trim();
2172
2234
  if (!iteration) continue;
2173
2235
  const heading = document.createElement("h4");
2174
- heading.textContent = t("lifecycle.detail_repair_iteration", { iteration });
2236
+ heading.textContent = t(
2237
+ step?.id === "LOCAL_REPOSITORY_VALIDATION"
2238
+ ? "lifecycle.detail_validation_pass"
2239
+ : "lifecycle.detail_repair_iteration",
2240
+ { iteration },
2241
+ );
2175
2242
  const grid = document.createElement("div");
2176
2243
  grid.className = "technical-grid";
2244
+ const iterationSection = document.createElement("section");
2245
+ iterationSection.className = "lifecycle-detail-modal__repair-iteration";
2177
2246
  const outcome = String(item.outcome || "").trim();
2178
2247
  const dynamicField = (label, source) => {
2179
2248
  const value = String(source || t("detail.not_recorded"));
@@ -2188,7 +2257,8 @@ function lifecycleRepairEvidence(step) {
2188
2257
  lifecycleDetailField(t("detail.commit"), item.commit_sha === "not_recorded" ? t("detail.not_recorded") : String(item.commit_sha || t("detail.not_recorded"))),
2189
2258
  lifecycleDetailField(t("detail.outcome"), t("lifecycle.repair_outcome." + outcome, {}, outcome || t("detail.not_recorded"))),
2190
2259
  );
2191
- section.append(heading, grid);
2260
+ iterationSection.append(heading, grid);
2261
+ section.append(iterationSection);
2192
2262
  }
2193
2263
  if (section.childElementCount <= 1) return null;
2194
2264
  void localizeDynamicEvidence(dynamicRows);
@@ -2219,16 +2289,29 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
2219
2289
  content.replaceChildren();
2220
2290
  const overview = document.createElement("section"), grid = document.createElement("div");
2221
2291
  grid.className = "technical-grid";
2292
+ const rawSpans = Array.isArray(timing.spans) ? timing.spans : [];
2293
+ const activeSpan = [...rawSpans].reverse().find((span) => String(span?.outcome || "").toUpperCase() === "ACTIVE");
2222
2294
  grid.append(
2223
2295
  lifecycleDetailStatusField(step?.state),
2224
- lifecycleDetailField(t("lifecycle.detail_started_at"), formatTimestamp(timing.started_at || step?.started_at)),
2225
- lifecycleDetailField(t("lifecycle.detail_finished_at"), formatTimestamp(timing.finished_at, t("format.unavailable"))),
2296
+ lifecycleDetailField(
2297
+ t("lifecycle.detail_started_at"),
2298
+ formatTimestamp(activeSpan?.started_at || timing.started_at || step?.started_at),
2299
+ ),
2226
2300
  );
2301
+ if (String(step?.state || "").toUpperCase() !== "ACTIVE") {
2302
+ grid.append(lifecycleDetailField(
2303
+ t("lifecycle.detail_finished_at"),
2304
+ formatTimestamp(timing.finished_at, t("format.unavailable")),
2305
+ ));
2306
+ }
2227
2307
  if (Number.isInteger(step?.iteration_count) && step.iteration_count > 0) {
2228
2308
  grid.append(lifecycleDetailField(t("lifecycle.detail_iterations"), String(step.iteration_count)));
2229
2309
  }
2230
2310
  overview.append(grid); content.append(overview);
2231
- const spans = lifecyclePhaseTiming(Array.isArray(timing.spans) ? timing.spans : []);
2311
+ const localValidation = String(step?.id || "").toUpperCase() === "LOCAL_REPOSITORY_VALIDATION";
2312
+ const spans = localValidation && rawSpans.length > 1
2313
+ ? rawSpans.filter((span) => span && typeof span === "object").map((span, index) => ({ ...span, occurrence: index + 1 }))
2314
+ : lifecyclePhaseTiming(rawSpans);
2232
2315
  const phaseTiming = document.createElement("section");
2233
2316
  phaseTiming.append(Object.assign(document.createElement("h3"), { textContent: t("lifecycle.detail_phase_timing") }));
2234
2317
  if (!spans.length) {
@@ -2237,7 +2320,9 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
2237
2320
  const list = document.createElement("ol"); list.className = "lifecycle-detail-modal__phase-list";
2238
2321
  for (const span of spans) {
2239
2322
  const item = document.createElement("li"), heading = document.createElement("strong"), meta = document.createElement("span");
2240
- heading.textContent = telemetryLabel(span.phase);
2323
+ heading.textContent = localValidation
2324
+ ? t("lifecycle.detail_validation_pass", { iteration: span.occurrence })
2325
+ : telemetryLabel(span.phase);
2241
2326
  meta.textContent = t("lifecycle.detail_phase_meta", {
2242
2327
  duration: telemetryMs(span.duration_ms), outcome: lifecycleStateLabel(span.outcome),
2243
2328
  });
@@ -2257,8 +2342,12 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
2257
2342
  content.append(phaseTiming);
2258
2343
  const qualityEvidence = lifecycleQualityEvidence(step);
2259
2344
  if (qualityEvidence) content.append(qualityEvidence);
2345
+ const capabilityEvidence = lifecycleCapabilityEvidence(step);
2346
+ if (capabilityEvidence) content.append(capabilityEvidence);
2260
2347
  const assuranceEvidence = lifecycleAssuranceEvidence(step);
2261
2348
  if (assuranceEvidence) content.append(assuranceEvidence);
2349
+ const implementationEvidence = lifecycleImplementationEvidence(step);
2350
+ if (implementationEvidence) content.append(implementationEvidence);
2262
2351
  const repairEvidence = lifecycleRepairEvidence(step);
2263
2352
  if (repairEvidence) content.append(repairEvidence);
2264
2353
  if (!modal.open) modal.showModal();
@@ -2266,7 +2355,28 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
2266
2355
  }
2267
2356
  $("lifecycleDetailClose")?.addEventListener("click", closeLifecycleDetail);
2268
2357
  $("lifecycleDetailModal")?.addEventListener("close", () => { lifecycleDetailTrigger?.focus?.(); lifecycleDetailTrigger = null; lifecycleDetailStep = null; });
2269
- function lifecycleFlow(projection, { historical = false } = {}) {
2358
+ function lifecycleStepWithEvidence(step, context = {}) {
2359
+ const enriched = { ...step };
2360
+ const id = String(step?.id || "").toUpperCase();
2361
+ if (id === "CAPABILITY_REVIEW") {
2362
+ const reviewers = Array.isArray(context.reviewer_agents)
2363
+ ? context.reviewer_agents
2364
+ : Array.isArray(context.reviewers) ? context.reviewers : [];
2365
+ if (reviewers.length) enriched.reviewer_evidence = reviewers;
2366
+ }
2367
+ if (id === "EXECUTE_AGENT") {
2368
+ const candidate = String(context.implementation_candidate_sha || "").trim();
2369
+ const branch = String(context.implementation_branch || "").trim();
2370
+ const pullRequest = Number(context.implementation_pr);
2371
+ const evidence = {};
2372
+ if (/^[0-9a-f]{40}$/.test(candidate)) evidence.candidate_sha = candidate;
2373
+ if (branch) evidence.branch = branch;
2374
+ if (Number.isInteger(pullRequest) && pullRequest > 0) evidence.pull_request = pullRequest;
2375
+ if (Object.keys(evidence).length) enriched.implementation_evidence = evidence;
2376
+ }
2377
+ return enriched;
2378
+ }
2379
+ function lifecycleFlow(projection, { historical = false, context = {} } = {}) {
2270
2380
  const section = document.createElement("section");
2271
2381
  section.className = "execution-lifecycle" + (historical ? " execution-lifecycle--historical" : "");
2272
2382
  if (projection?.run_id) section.dataset.runId = projection.run_id;
@@ -2278,7 +2388,9 @@ function lifecycleFlow(projection, { historical = false } = {}) {
2278
2388
  }
2279
2389
  const scroll = document.createElement("div"), list = document.createElement("ol");
2280
2390
  scroll.className = "execution-lifecycle__scroll"; list.className = "execution-lifecycle__path";
2281
- const steps = Array.isArray(projection.steps) ? projection.steps : [];
2391
+ const steps = Array.isArray(projection.steps)
2392
+ ? projection.steps.map((step) => lifecycleStepWithEvidence(step, context))
2393
+ : [];
2282
2394
  for (const [index, step] of steps.entries()) {
2283
2395
  const state = String(step?.state || "UNKNOWN").toLowerCase();
2284
2396
  const operatorWait = state === "active" && !historical && isOperatorMergeStep(step);
@@ -2315,8 +2427,8 @@ function lifecycleFlow(projection, { historical = false } = {}) {
2315
2427
  }
2316
2428
  scroll.append(list); section.append(scroll);
2317
2429
  const summary = document.createElement("p"); summary.className = "execution-lifecycle__summary";
2318
- const currentStep = (projection.steps || []).find((step) => step?.state === "ACTIVE")
2319
- || (projection.steps || []).find((step) => step?.state === projection?.terminal_state) || {};
2430
+ const currentStep = steps.find((step) => step?.state === "ACTIVE")
2431
+ || steps.find((step) => step?.state === projection?.terminal_state) || {};
2320
2432
  summary.textContent = t("lifecycle.summary", {
2321
2433
  step: lifecycleLabel(currentStep),
2322
2434
  status: isOperatorMergeStep(currentStep)
@@ -2395,7 +2507,7 @@ function renderActiveLifecycle(projection, execution = {}) {
2395
2507
  : 0;
2396
2508
  previous?.remove();
2397
2509
  if (projection?.run_id) {
2398
- const lifecycle = lifecycleFlow(projection);
2510
+ const lifecycle = lifecycleFlow(projection, { context: execution });
2399
2511
  const identity = $("executionIdentity"), estimate = $("executionEstimate")?.closest(".card");
2400
2512
  placeExecutionEstimate();
2401
2513
  // Keep run identity and its phase-aware estimate ahead of the read-only
@@ -2419,6 +2531,18 @@ function renderActiveLifecycle(projection, execution = {}) {
2419
2531
  revealActiveLifecycleStep(lifecycle.querySelector(".execution-lifecycle__scroll"));
2420
2532
  }
2421
2533
  renderActivePullRequests(execution, lifecycle);
2534
+ if ($("lifecycleDetailModal")?.open && lifecycleDetailStep) {
2535
+ const refreshed = (projection.steps || []).find((step) => step?.id === lifecycleDetailStep.id);
2536
+ if (refreshed) {
2537
+ const scrollTop = $("lifecycleDetailContent")?.scrollTop || 0;
2538
+ openLifecycleDetail(
2539
+ lifecycleStepWithEvidence(refreshed, execution),
2540
+ lifecycleDetailTrigger,
2541
+ { presentationOnly: true },
2542
+ );
2543
+ if ($("lifecycleDetailContent")) $("lifecycleDetailContent").scrollTop = scrollTop;
2544
+ }
2545
+ }
2422
2546
  } else {
2423
2547
  renderActivePullRequests(execution, null);
2424
2548
  }
@@ -8516,7 +8640,10 @@ function renderPromptHistoryDetail(payload) {
8516
8640
  ]),
8517
8641
  ]),
8518
8642
  promptDetailRightbar([executionContext, promptDetailPullRequestsSection(pullRequests)]),
8519
- lifecycleFlow(payload?.lifecycle, { historical: true }),
8643
+ lifecycleFlow(payload?.lifecycle, {
8644
+ historical: true,
8645
+ context: { ...history, reviewers, commit_timeline: commitTimeline, pull_requests: pullRequests },
8646
+ }),
8520
8647
  statusReconciliationCard(payload?.lifecycle?.recovery),
8521
8648
  promptDetailProviderReviewSections(usage, reviewers, commitTimeline),
8522
8649
  promptDetailAssuranceReviewsSection(assuranceReviews),
@@ -3185,6 +3185,7 @@ Object.assign(DASHBOARD_MESSAGES.es, {
3185
3185
  "log_event.terminal_report_corrected":"Informe final corregido", "log_event.active_run_lease_reconciled":"Arrendamiento de ejecución activa conciliado", "log_event.detached_runner_job_missing":"Falta la tarea de ejecución desconectada", "log_event.inbox_scan":"Bandeja de entrada analizada", "log_event.active_transaction_queue_refreshed":"Cola de ejecución activa actualizada",
3186
3186
  "log_event.inbox_log_unavailable":"Registro del monitor de bandeja de entrada no disponible", "log_event.dashboard_log_unavailable":"Registro del panel de estado no disponible"
3187
3187
  });
3188
+
3188
3189
  Object.assign(DASHBOARD_MESSAGES.en, {"telemetry.download_overview_markdown":"Download complete overview as Markdown","telemetry.download_overview_json":"Download complete overview as JSON","telemetry.export_failed":"The telemetry export could not be created. Try again.","telemetry.export_download_target":"Telemetry export download response","telemetry.timeline_truncated_full_export":"Showing {shown} of {total} spans. The complete detail export contains all spans.","telemetry.invocations_truncated_full_export":"Showing {shown} of {total} invocations. The complete detail export contains all invocations.","telemetry.timing_correlation":"Timing correlation"});
3189
3190
  Object.assign(DASHBOARD_MESSAGES.nl, {"telemetry.download_overview_markdown":"Volledig overzicht als Markdown downloaden","telemetry.download_overview_json":"Volledig overzicht als JSON downloaden","telemetry.export_failed":"De telemetrie-export kon niet worden gemaakt. Probeer opnieuw.","telemetry.export_download_target":"Downloadrespons voor telemetrie-export","telemetry.timeline_truncated_full_export":"{shown} van {total} spans worden getoond. De volledige detailexport bevat alle spans.","telemetry.invocations_truncated_full_export":"{shown} van {total} invocations worden getoond. De volledige detailexport bevat alle invocations.","telemetry.timing_correlation":"Timingkoppeling"});
3190
3191
  Object.assign(DASHBOARD_MESSAGES.de, {"telemetry.download_overview_markdown":"Vollständige Übersicht als Markdown herunterladen","telemetry.download_overview_json":"Vollständige Übersicht als JSON herunterladen","telemetry.export_failed":"Der Telemetrieexport konnte nicht erstellt werden. Versuchen Sie es erneut.","telemetry.export_download_target":"Downloadantwort des Telemetrieexports","telemetry.timeline_truncated_full_export":"{shown} von {total} Zeitspannen werden angezeigt. Der vollständige Detailexport enthält alle Zeitspannen.","telemetry.invocations_truncated_full_export":"{shown} von {total} Aufrufen werden angezeigt. Der vollständige Detailexport enthält alle Aufrufe.","telemetry.timing_correlation":"Zeitkorrelation"});
@@ -4268,3 +4269,12 @@ Object.assign(DASHBOARD_MESSAGES.fr, {
4268
4269
  Object.assign(DASHBOARD_MESSAGES.es, {
4269
4270
  "telemetry.less_than_one_second":"<1 s","telemetry.population":"Población medida","telemetry.elapsed":"Tiempo transcurrido","telemetry.provider_unique_coverage":"Cobertura del proveedor en el tiempo transcurrido","telemetry.provider_cumulative_process":"Duración acumulada del proceso proveedor","telemetry.unassigned":"Tiempo no asignado","telemetry.observed_input":"Entrada observada","telemetry.observed_output":"Salida observada","telemetry.cache_ratio":"Proporción de caché","telemetry.measurement_coverage":"Cobertura de medición","telemetry.contract_version":"Contrato de cálculo","telemetry.inclusive_title":"Carga de fase inclusiva","telemetry.inclusive_help":"Los tiempos inclusivos pueden solaparse; sus porcentajes no son aditivos.","telemetry.exclusive_title":"Distribución exclusiva del tiempo transcurrido","telemetry.exclusive_help":"Distribución sin solapamiento del tiempo medido; el trabajo independiente simultáneo aparece como paralelo/solapamiento.","telemetry.category":"Categoría","telemetry.duration":"Duración","telemetry.longest_individual_span":"Tramo individual más largo","telemetry.scope_attempt":"Este intento","telemetry.scope_chain":"Cadena de ejecución completa","telemetry.chain_coverage":"Cobertura de la cadena","telemetry.chain_attempts":"Intentos en la cadena","telemetry.original_attempts":"Intentos originales","telemetry.retries":"Reintentos","telemetry.resumes":"Reanudaciones","telemetry.chain_elapsed":"Tiempo transcurrido de la cadena","telemetry.chain_processing":"Tiempo de procesamiento medido","telemetry.inter_attempt_gaps":"Intervalos entre intentos","telemetry.outside_window":"Intentos relacionados fuera de la fecha","telemetry.mission_scope":"Ámbito de Mission","telemetry.timeline":"Cronología","telemetry.timeline_truncated":"Cronología limitada a {count} observaciones.","telemetry.invocations":"Invocaciones del proveedor","telemetry.role":"Rol","telemetry.cached_input":"Entrada en caché","telemetry.uncached_input":"Entrada sin caché","telemetry.usage_coverage":"Cobertura de uso","telemetry.invocation_id":"ID de invocación","telemetry.retry_identity":"Número de reintento","telemetry.relation":"Relación","telemetry.technical_completion":"Finalización técnica","telemetry.qualification_status":"Calificación","telemetry.autonomy_acceptance":"Aceptación de autonomía","telemetry.coverage.complete":"Completa","telemetry.coverage.partial":"Parcial","telemetry.coverage.unavailable":"No disponible","telemetry.coverage.conflict":"En conflicto","telemetry.phase.parallel_overlap":"Paralelo / solapamiento","telemetry.phase.unassigned":"No asignado"
4270
4271
  });
4272
+
4273
+ // A repair step can be entered before a pull request exists and shares its
4274
+ // bounded budget across local validation, assurance, hosted checks and
4275
+ // finalization. Keep the flow label generic; detail evidence names the cause.
4276
+ Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.step.repair_agent":"Repair round","lifecycle.detail_repair_evidence":"Completed repair rounds","lifecycle.detail_implementation_evidence":"Implementation result","lifecycle.detail_validation_pass":"Validation pass {iteration}","detail.initial_observation":"Initial observation","detail.rejected_recommendations":"Rejected recommendations"});
4277
+ Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.step.repair_agent":"Herstelronde","lifecycle.detail_repair_evidence":"Uitgevoerde herstelrondes","lifecycle.detail_implementation_evidence":"Implementatieresultaat","lifecycle.detail_validation_pass":"Validatiepass {iteration}","detail.initial_observation":"Initiële bevinding","detail.rejected_recommendations":"Afgewezen aanbevelingen"});
4278
+ Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.step.repair_agent":"Reparaturrunde","lifecycle.detail_repair_evidence":"Abgeschlossene Reparaturrunden","lifecycle.detail_implementation_evidence":"Implementierungsergebnis","lifecycle.detail_validation_pass":"Validierungsdurchlauf {iteration}","detail.initial_observation":"Erste Beobachtung","detail.rejected_recommendations":"Abgelehnte Empfehlungen"});
4279
+ Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.step.repair_agent":"Cycle de réparation","lifecycle.detail_repair_evidence":"Cycles de réparation terminés","lifecycle.detail_implementation_evidence":"Résultat de l’implémentation","lifecycle.detail_validation_pass":"Passe de validation {iteration}","detail.initial_observation":"Observation initiale","detail.rejected_recommendations":"Recommandations rejetées"});
4280
+ Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.step.repair_agent":"Ronda de reparación","lifecycle.detail_repair_evidence":"Rondas de reparación completadas","lifecycle.detail_implementation_evidence":"Resultado de la implementación","lifecycle.detail_validation_pass":"Pasada de validación {iteration}","detail.initial_observation":"Observación inicial","detail.rejected_recommendations":"Recomendaciones rechazadas"});
@@ -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:
@@ -3366,6 +3394,18 @@ First implementation pull-request publication gate:
3366
3394
  }
3367
3395
  for item in selections
3368
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
+ )
3369
3409
  write_live_status(
3370
3410
  self.root,
3371
3411
  state
@@ -3399,7 +3439,7 @@ First implementation pull-request publication gate:
3399
3439
  objective,
3400
3440
  self.agent if hasattr(self.agent, "review") else None,
3401
3441
  progress=lambda selection, event, result: self._publish_reviewer_progress(
3402
- state, selection, event, result
3442
+ state, selection, event, result, capability_review
3403
3443
  ),
3404
3444
  evidence=reviewer_evidence,
3405
3445
  )
@@ -3413,6 +3453,36 @@ First implementation pull-request publication gate:
3413
3453
  observed_snapshots=reviewer.usage_snapshots,
3414
3454
  )
3415
3455
  self.reviewer_records = records_for_storage(selections, results)
3456
+ # Publish the bounded advisory result before leaving CAPABILITY_REVIEW.
3457
+ # The Console can then explain what each specialist contributed while
3458
+ # the Mission continues; it must not wait for the terminal report.
3459
+ self.reviewer_runtime = [
3460
+ {
3461
+ "reviewer": str(record.get("reviewer", ""))[:80],
3462
+ "capability": str(record.get("capability", "engineering"))[:80],
3463
+ "selected_because": redact_diagnostic(
3464
+ str(record.get("selected_because", "")), limit=180,
3465
+ ),
3466
+ "contribution": redact_diagnostic(
3467
+ str(record.get("contribution", "")), limit=240,
3468
+ ),
3469
+ "accepted_recommendations": max(
3470
+ 0, int(record.get("accepted_recommendations", 0) or 0),
3471
+ ),
3472
+ "rejected_recommendations": max(
3473
+ 0, int(record.get("rejected_recommendations", 0) or 0),
3474
+ ),
3475
+ "status": "failed" if record.get("failed") else "completed",
3476
+ }
3477
+ for record in self.reviewer_records[:12]
3478
+ ]
3479
+ update_phase_metadata(
3480
+ self.root, capability_review,
3481
+ {"reviewer_agents": self.reviewer_runtime},
3482
+ )
3483
+ write_live_status(
3484
+ self.root, state, "Capability review completed", self.reviewer_runtime,
3485
+ )
3416
3486
  # Reviewer reasoning is intentionally not merged into the primary
3417
3487
  # provider context. Reviewers share the bounded factual snapshot, but
3418
3488
  # retain independent reasoning responsibility and advisory records.
@@ -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
 
@@ -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.91"
15
+ CURRENT_PLATFORM_VERSION = "2.3.93"
16
16
  MANIFEST_FIELDS = frozenset(
17
17
  {
18
18
  "platform_version",
@@ -3770,7 +3770,9 @@ def _central_console_report_reviewers(report: bytes | None) -> list[dict[str, ob
3770
3770
  # the viewer's locale-specific fallback instead of leaking a Dutch
3771
3771
  # server string into another locale.
3772
3772
  "selected_because": field("Selected because"),
3773
+ "contribution": field("Initial observation"),
3773
3774
  "accepted_recommendations": int(accepted) if accepted and accepted.isdigit() else 0,
3775
+ "rejected_recommendations": int(rejected) if (rejected := field("Rejected recommendations")) and rejected.isdigit() else 0,
3774
3776
  "status": "completed",
3775
3777
  })
3776
3778
  if len(records) == 12:
@@ -3788,6 +3790,12 @@ def _central_console_invocation_reviewers(data_root: Path, run_id: str) -> list[
3788
3790
  """
3789
3791
  try:
3790
3792
  with storage.sqlite_connection(data_root / SERVER_DATABASE_FILENAME) as connection:
3793
+ capability_phase = connection.execute(
3794
+ """SELECT metadata,outcome FROM execution_phase_spans
3795
+ WHERE run_id=? AND phase_name='CAPABILITY_REVIEW'
3796
+ ORDER BY ordinal DESC LIMIT 1""",
3797
+ (run_id,),
3798
+ ).fetchone()
3791
3799
  rows = connection.execute(
3792
3800
  """SELECT role,completed_at FROM provider_invocations
3793
3801
  WHERE run_id=? AND phase='CAPABILITY_REVIEW'
@@ -3797,6 +3805,49 @@ def _central_console_invocation_reviewers(data_root: Path, run_id: str) -> list[
3797
3805
  ).fetchall()
3798
3806
  except (sqlite3.DatabaseError, storage.EngineeringStorageError):
3799
3807
  return []
3808
+ if capability_phase is not None:
3809
+ try:
3810
+ metadata = json.loads(str(capability_phase[0]))
3811
+ except (TypeError, ValueError, json.JSONDecodeError):
3812
+ metadata = {}
3813
+ live = metadata.get("reviewer_agents") if isinstance(metadata, dict) else None
3814
+ if isinstance(live, list) and 0 < len(live) <= 12:
3815
+ projected: list[dict[str, object]] = []
3816
+ for item in live:
3817
+ if not isinstance(item, Mapping):
3818
+ projected = []
3819
+ break
3820
+ reviewer = str(item.get("reviewer") or "").strip()
3821
+ capability = str(item.get("capability") or "engineering").strip()
3822
+ status = str(item.get("status") or "").strip().lower()
3823
+ if (
3824
+ re.fullmatch(r"[a-z0-9][a-z0-9_-]{0,79}", reviewer) is None
3825
+ or re.fullmatch(r"[a-z0-9][a-z0-9_-]{0,79}", capability) is None
3826
+ or status not in {"selected", "running", "completed", "failed"}
3827
+ ):
3828
+ projected = []
3829
+ break
3830
+ projected.append({
3831
+ "reviewer": reviewer, "capability": capability, "status": status,
3832
+ **({"selected_because": str(item["selected_because"])[:180]}
3833
+ if isinstance(item.get("selected_because"), str) else {}),
3834
+ **({"contribution": str(item["contribution"])[:240]}
3835
+ if isinstance(item.get("contribution"), str) else {}),
3836
+ **({"accepted_recommendations": max(0, int(item["accepted_recommendations"]))}
3837
+ if isinstance(item.get("accepted_recommendations"), int)
3838
+ and not isinstance(item.get("accepted_recommendations"), bool) else {}),
3839
+ **({"rejected_recommendations": max(0, int(item["rejected_recommendations"]))}
3840
+ if isinstance(item.get("rejected_recommendations"), int)
3841
+ and not isinstance(item.get("rejected_recommendations"), bool) else {}),
3842
+ })
3843
+ phase_outcome = str(capability_phase[1] or "").upper()
3844
+ terminal_detail = all(
3845
+ item.get("status") in {"completed", "failed"} for item in projected
3846
+ )
3847
+ if len(projected) == len(live) and (
3848
+ phase_outcome == "ACTIVE" or terminal_detail
3849
+ ):
3850
+ return projected
3800
3851
  reviewers: list[dict[str, object]] = []
3801
3852
  for role, completed_at in rows:
3802
3853
  name = str(role).removeprefix("reviewer:").strip()