engineering-platform 2.3.93__tar.gz → 2.3.94__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.93 → engineering_platform-2.3.94}/PKG-INFO +1 -1
  2. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/pyproject.toml +1 -1
  3. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
  4. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
  5. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/agent_state.py +33 -1
  6. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/dashboard.css +4 -0
  7. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/dashboard.js +116 -36
  8. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/dashboard_locales.mjs +10 -5
  9. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/capability_review.py +104 -3
  10. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/dashboard_state.py +8 -7
  11. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_executor.py +64 -20
  12. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_host.py +82 -33
  13. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_reporting.py +18 -0
  14. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/live_status.py +11 -11
  15. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/platform_version.py +1 -1
  16. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/qualification_runtime.py +15 -2
  17. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/templates/workspace-config.json +1 -1
  18. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform.egg-info/PKG-INFO +1 -1
  19. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/README.md +0 -0
  20. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/setup.cfg +0 -0
  21. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/__init__.py +0 -0
  22. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/__main__.py +0 -0
  23. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/agent_trust.py +0 -0
  24. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  25. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
  26. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  27. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  28. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  29. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  30. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  31. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  32. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/assurance_scope.py +0 -0
  33. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/capability_preflight.py +0 -0
  34. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/central_data_transfer.py +0 -0
  35. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/central_database.py +0 -0
  36. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/central_operational_reset.py +0 -0
  37. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/central_store_migration.py +0 -0
  38. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/codex_capacity.py +0 -0
  39. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/codex_chat.py +0 -0
  40. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/codex_observability.py +0 -0
  41. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/component_lock.py +0 -0
  42. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/component_logging.py +0 -0
  43. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/console_presentation.py +0 -0
  44. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/console_route_ownership.py +0 -0
  45. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/contracts/__init__.py +0 -0
  46. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  47. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/contracts/models.py +0 -0
  48. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/contracts/projection.py +0 -0
  49. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/dashboard_browser_validation.py +0 -0
  50. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  51. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/dashboard_translation.py +0 -0
  52. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/dependabot_producer.py +0 -0
  53. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/development_profile.py +0 -0
  54. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/drift_diagnostics.py +0 -0
  55. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/emergency_recovery.py +0 -0
  56. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/engineering_memory.py +0 -0
  57. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  58. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/evidence_projection.py +0 -0
  59. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_activity.py +0 -0
  60. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_context.py +0 -0
  61. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_errors.py +0 -0
  62. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_evidence.py +0 -0
  63. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_finalization.py +0 -0
  64. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_host_evidence.py +0 -0
  65. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_lease.py +0 -0
  66. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_lifecycle.py +0 -0
  67. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_models.py +0 -0
  68. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_readiness.py +0 -0
  69. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_repository.py +0 -0
  70. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_timeout_policy.py +0 -0
  71. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_timing.py +0 -0
  72. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/execution_transaction.py +0 -0
  73. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/external_producer_binding.py +0 -0
  74. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/file_inbox.py +0 -0
  75. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/forensic_attribution.py +0 -0
  76. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  77. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/forensic_delta.py +0 -0
  78. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/golden_scenario.py +0 -0
  79. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  80. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/host_admin.py +0 -0
  81. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/host_preflight.py +0 -0
  82. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_relocation.py +0 -0
  83. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_activation.py +0 -0
  84. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_admission.py +0 -0
  85. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_backup.py +0 -0
  86. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_composition.py +0 -0
  87. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_executor.py +0 -0
  88. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_migration.py +0 -0
  89. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_operation.py +0 -0
  90. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_plan.py +0 -0
  91. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/installation_update_preparation.py +0 -0
  92. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/investigation_ledger.py +0 -0
  93. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  94. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/legacy_installation_adoption.py +0 -0
  95. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/lifecycle_worker.py +0 -0
  96. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/local_api.py +0 -0
  97. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/local_api_keychain.py +0 -0
  98. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/local_repository_binding.py +0 -0
  99. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/managed_autonomy.py +0 -0
  100. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/managed_codex_runtime.py +0 -0
  101. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/managed_workspace_readiness.py +0 -0
  102. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/merge_delegation.py +0 -0
  103. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/operational_installation.py +0 -0
  104. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/operational_installation_lock.py +0 -0
  105. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/operational_installation_record.py +0 -0
  106. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/owner_credential_recovery.py +0 -0
  107. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/parity_context.py +0 -0
  108. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
  109. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/platform_admin.py +0 -0
  110. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/platform_api.py +0 -0
  111. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/platform_bootstrap.py +0 -0
  112. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/platform_components.py +0 -0
  113. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/pr_check_repair.py +0 -0
  114. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  115. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/producer.py +0 -0
  116. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/product_installation_readback.py +0 -0
  117. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/project_agent.py +0 -0
  118. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/project_agent_service.py +0 -0
  119. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/project_topology.py +0 -0
  120. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/prompt_history.py +0 -0
  121. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_context.py +0 -0
  122. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_context_benchmark.py +0 -0
  123. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_context_scope.py +0 -0
  124. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_interruption.py +0 -0
  125. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_process_identity.py +0 -0
  126. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_readiness.py +0 -0
  127. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_recovery.py +0 -0
  128. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/provider_usage.py +0 -0
  129. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/providers.py +0 -0
  130. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/qualification.py +0 -0
  131. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/recommendation_handoff.py +0 -0
  132. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/reconciliation_adoption.py +0 -0
  133. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/release_operation.py +0 -0
  134. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/report_analysis.py +0 -0
  135. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/repository_attachment.py +0 -0
  136. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/repository_handoff.py +0 -0
  137. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/resources.py +0 -0
  138. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/reviewer_evidence.py +0 -0
  139. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/revision_binding.py +0 -0
  140. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
  141. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +0 -0
  142. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  143. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  144. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/server.py +0 -0
  145. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/server_console_services.py +0 -0
  146. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/server_relay.py +0 -0
  147. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/server_service.py +0 -0
  148. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/status_model.py +0 -0
  149. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/status_reconciliation.py +0 -0
  150. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/storage.py +0 -0
  151. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/submission_cli.py +0 -0
  152. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/submission_intake.py +0 -0
  153. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/submission_service.py +0 -0
  154. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/system_installation_topology.py +0 -0
  155. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/system_server_service.py +0 -0
  156. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/telemetry.py +0 -0
  157. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/telemetry_contract.py +0 -0
  158. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/telemetry_export.py +0 -0
  159. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/telemetry_metrics.py +0 -0
  160. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
  161. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/validation_identity.py +0 -0
  162. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/validation_profile.py +0 -0
  163. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/version_preparation_delivery.py +0 -0
  164. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/workspace_preflight.py +0 -0
  165. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/worktree_provenance.py +0 -0
  166. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform/worktree_tooling.py +0 -0
  167. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
  168. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  169. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  170. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/src/engineering_platform.egg-info/top_level.txt +0 -0
  171. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/tests/test_adaptive_action_sizing_design.py +0 -0
  172. {engineering_platform-2.3.93 → engineering_platform-2.3.94}/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.93
3
+ Version: 2.3.94
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.93"
7
+ version = "2.3.94"
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.93",
6
+ "version": "2.3.94",
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.93",
4
+ "dashboard_version": "2.3.94",
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.93",
9
+ "platform_version": "2.3.94",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.93",
11
+ "runner_version": "2.3.94",
12
12
  "status_model": 1,
13
13
  "storage_schema": 45,
14
- "watcher_version": "2.3.93"
14
+ "watcher_version": "2.3.94"
15
15
  }
@@ -458,13 +458,16 @@ class TransactionState:
458
458
  raise StateError("checkpoint assurance profile is invalid")
459
459
  review_fields = {"reviewer", "status", "candidate_sha", "profile_digest", "invocation_id", "findings"}
460
460
  current_review_fields = review_fields | {"contract_version", "started_at", "completed_at"}
461
+ integral_review_fields = current_review_fields | {"coverage", "finding_dispositions"}
461
462
  finding_fields = {"id", "fingerprint", "category", "criterion", "observation", "severity", "confidence", "blocking", "disposition"}
462
463
  current_finding_fields = finding_fields | {"evidence_ref"}
464
+ coverage_fields = {"surface", "status", "evidence_ref"}
465
+ finding_disposition_fields = {"finding_id", "disposition", "evidence_ref"}
463
466
  if (
464
467
  not isinstance(state.assurance_reviews, tuple)
465
468
  or len(state.assurance_reviews) > 16
466
469
  or any(
467
- not isinstance(review, dict) or set(review) not in (review_fields, current_review_fields)
470
+ not isinstance(review, dict) or set(review) not in (review_fields, current_review_fields, integral_review_fields)
468
471
  or review.get("reviewer") not in {"quality", "security"}
469
472
  or review.get("status") not in {"PASS", "FAIL", "UNRESOLVED"}
470
473
  or not isinstance(review.get("candidate_sha"), str) or not re.fullmatch(r"[0-9a-f]{40}", review["candidate_sha"])
@@ -486,6 +489,35 @@ class TransactionState:
486
489
  or not isinstance(review.get("started_at"), str)
487
490
  or not isinstance(review.get("completed_at"), str)
488
491
  ))
492
+ or (set(review) == integral_review_fields and (
493
+ review.get("contract_version") != "2.0"
494
+ or not isinstance(review.get("started_at"), str)
495
+ or not isinstance(review.get("completed_at"), str)
496
+ or not isinstance(review.get("coverage"), list)
497
+ or not 1 <= len(review["coverage"]) <= 16
498
+ or any(
499
+ not isinstance(item, dict) or set(item) != coverage_fields
500
+ or item.get("status") not in {"REVIEWED", "NOT_APPLICABLE"}
501
+ or any(
502
+ not isinstance(value, str) or not value or len(value) > 240
503
+ or value != redact_diagnostic(value, limit=240)
504
+ for value in item.values()
505
+ )
506
+ for item in review["coverage"]
507
+ )
508
+ or not isinstance(review.get("finding_dispositions"), list)
509
+ or len(review["finding_dispositions"]) > 64
510
+ or any(
511
+ not isinstance(item, dict) or set(item) != finding_disposition_fields
512
+ or item.get("disposition") not in {"RESOLVED", "OPEN"}
513
+ or any(
514
+ not isinstance(value, str) or not value or len(value) > 240
515
+ or value != redact_diagnostic(value, limit=240)
516
+ for value in item.values()
517
+ )
518
+ for item in review["finding_dispositions"]
519
+ )
520
+ ))
489
521
  for review in state.assurance_reviews
490
522
  )
491
523
  ):
@@ -280,6 +280,8 @@ html[data-theme="light"] :is(#rateLimitReset,#codexCliUpdate){background:#e8fff5
280
280
  .prompt-detail-provider-review{display:grid;gap:18px;grid-column:1/-1;grid-template-columns:minmax(0,1fr) minmax(320px,.78fr)}@media (max-width:760px){.prompt-detail-provider-review{grid-template-columns:1fr}}
281
281
  .prompt-detail-provider-review-stack{display:grid;gap:18px;grid-column:1/-1}.prompt-detail-provider-review>.prompt-detail-card{align-self:stretch;box-sizing:border-box}.prompt-detail-card--commit-timeline{display:flex;flex-direction:column;min-height:0}.prompt-detail-commit-timeline__list{align-content:start;display:grid;flex:1;gap:10px;list-style:none;margin:0;max-height:none;min-height:0;overflow:auto;padding:0 8px 0 0;scrollbar-gutter:stable}.prompt-detail-commit-timeline__item{border-top:1px solid color-mix(in srgb,var(--category-color) 38%,transparent);display:grid;gap:3px;padding-top:10px}.prompt-detail-commit-timeline__item:first-child{border-top:0;padding-top:0}.prompt-detail-commit-timeline__meta{color:var(--dashboard-modal-muted);font-size:12px;line-height:1.35}.prompt-detail-commit-timeline__item code{font-size:12px;overflow-wrap:normal;white-space:nowrap}.prompt-detail-commit-timeline__item>span{font-size:13px;line-height:1.4;overflow-wrap:anywhere}
282
282
  .prompt-detail-card--evidence pre,.prompt-detail-card--reviewers pre,.prompt-detail-card--assurance-reviews pre{font-family:inherit}
283
+ .reviewer-agent__status--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313;font:800 14px/1 system-ui;height:16px;width:16px}
284
+ .prompt-detail-reviewer{border-top:1px solid color-mix(in srgb,var(--category-color) 45%,transparent);display:grid;gap:7px;padding-top:14px}.prompt-detail-reviewer:first-of-type{border-top:0;padding-top:0}.prompt-detail-reviewer h4{color:var(--category-color);font-size:16px;margin:0 0 4px}.prompt-detail-reviewer>.field{margin:2px 0 0}.prompt-detail-reviewer__status{align-items:center;display:inline-flex;gap:8px}.prompt-detail-reviewer__status-icon{align-items:center;border-radius:50%;display:inline-flex;flex:0 0 18px;font:800 12px/1 system-ui;height:18px;justify-content:center}.prompt-detail-reviewer__status-icon--completed{background:#51d88a;box-shadow:0 0 8px #51d88a66;color:#11261d}.prompt-detail-reviewer__status-icon--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313}.prompt-detail-reviewer__status-icon--neutral{background:#9a9aa3;color:#202027}
283
285
  .prompt-detail-commit-timeline__phase{border-top:1px solid color-mix(in srgb,var(--category-color) 52%,transparent);list-style:none;padding:13px 0 0}.prompt-detail-commit-timeline__phase:first-child{border-top:0;padding-top:0}.prompt-detail-commit-timeline__phase h4{color:var(--category-color);font-size:12px;letter-spacing:.04em;margin:0 0 9px;text-transform:uppercase}.prompt-detail-commit-timeline__phase-entries{display:grid;gap:10px;list-style:none;margin:0;padding:0 0 2px}.prompt-detail-commit-timeline__phase-entries .prompt-detail-commit-timeline__item{border-top:0;padding-top:0}
284
286
  .prompt-detail-commit-timeline__phase{--commit-kind-color:#8dc7ff;border-left:3px solid var(--commit-kind-color);padding-left:10px}.prompt-detail-commit-timeline__phase--implementation{--commit-kind-color:#65c5d9}.prompt-detail-commit-timeline__phase--validation{--commit-kind-color:#65d9a3}.prompt-detail-commit-timeline__phase--quality{--commit-kind-color:#c29aff}.prompt-detail-commit-timeline__phase--repair{--commit-kind-color:#f4c34f}.prompt-detail-commit-timeline__phase--finalization{--commit-kind-color:#ff99a7}.prompt-detail-commit-timeline__phase--implementation_merge,.prompt-detail-commit-timeline__phase--finalization_merge,.prompt-detail-commit-timeline__phase--reconciliation_merge{--commit-kind-color:#f3d36a}.prompt-detail-commit-timeline__phase--reconciliation{--commit-kind-color:#73d6b0}.prompt-detail-commit-timeline__phase h4{align-items:center;color:var(--commit-kind-color);display:flex;gap:7px}.prompt-detail-commit-timeline__kind{border:1px solid currentColor;border-radius:999px;font-size:10px;line-height:1;padding:4px 6px}.prompt-detail-commit-timeline__phase-name{color:var(--dashboard-modal-muted);font-size:11px;font-weight:500;letter-spacing:0;text-transform:none;white-space:nowrap}
285
287
 
@@ -1335,3 +1337,5 @@ html[data-theme="light"] :is(.dashboard-status-banner--provider-auth_required .p
1335
1337
  }
1336
1338
  .telemetry-note{color:var(--dashboard-muted,#b9b6c0);font-size:12px;line-height:1.45;margin:0 0 10px}.telemetry-run-detail{border-top:1px solid color-mix(in srgb,var(--category-color,#fb7185) 45%,transparent);display:grid;gap:16px;margin-top:16px;padding-top:16px}.telemetry-run-detail h4{color:var(--category-color,#fb7185);font-size:14px;margin:14px 0 8px}.telemetry-scope-switcher{display:flex;flex-wrap:wrap;gap:8px}.telemetry-scope-switcher button{background:var(--dashboard-expanded-content-surface,#24242d);border:1px solid color-mix(in srgb,var(--category-color,#fb7185) 72%,transparent);border-radius:7px;color:inherit;cursor:pointer;font:400 12px/1.2 system-ui;min-height:32px;padding:5px 9px}.telemetry-scope-switcher button:hover{background:color-mix(in srgb,var(--category-color,#fb7185) 14%,var(--dashboard-expanded-content-surface,#24242d));border-color:var(--category-color,#fb7185)}.telemetry-scope-switcher button[aria-selected="true"]{background:color-mix(in srgb,var(--category-color,#fb7185) 24%,var(--dashboard-expanded-content-surface,#24242d));border-color:var(--category-color,#fb7185);box-shadow:inset 3px 0 0 var(--category-color,#fb7185)}.telemetry-scope-switcher button:focus:not(:focus-visible){box-shadow:none!important;outline:0!important}.telemetry-scope-switcher button[aria-selected="true"]:focus:not(:focus-visible){box-shadow:inset 3px 0 0 var(--category-color,#fb7185)!important}.telemetry-timeline{display:grid;gap:5px;list-style:none;margin:0;padding:0}.telemetry-timeline li{border-left:2px solid color-mix(in srgb,var(--category-color,#fb7185) 60%,transparent);margin-left:calc(var(--timeline-depth,0) * 14px);padding:6px 8px;word-break:break-word}@media(max-width:620px){.telemetry-detail-modal__content .technical-grid{grid-template-columns:minmax(0,1fr)}.telemetry-scope-switcher{position:sticky;top:0;background:var(--dashboard-expanded-content-surface,#24242d);padding-block:6px;z-index:2}.telemetry-timeline li{margin-left:min(calc(var(--timeline-depth,0) * 9px),45px)}}
1337
1339
  .telemetry-timeline-axis{color:var(--dashboard-muted,#b9b6c0);display:flex;font:11px ui-monospace,monospace;justify-content:space-between;margin:4px 8px}.telemetry-timeline__label{font-size:12px;line-height:1.35}.telemetry-timeline__track{background:color-mix(in srgb,var(--category-color,#fb7185) 10%,transparent);border:1px solid color-mix(in srgb,var(--category-color,#fb7185) 24%,transparent);border-radius:4px;height:14px;margin:5px 0;overflow:hidden;position:relative}.telemetry-timeline__bar{background:var(--category-color,#fb7185);border-radius:3px;display:block;height:100%;min-width:2px;position:absolute}.telemetry-timeline__bar:focus-visible{outline:3px solid var(--house-style);outline-offset:2px}.telemetry-timeline__bar--unpositioned{background:repeating-linear-gradient(135deg,var(--category-color,#fb7185) 0 4px,transparent 4px 8px);inset:0;width:100%}.telemetry-timeline__identity{color:var(--dashboard-muted,#b9b6c0);display:block;font-size:10px;overflow-wrap:anywhere}.telemetry-export{min-width:38px}@media(max-width:620px){.telemetry-timeline-axis{margin-inline:0}.telemetry-timeline__identity{font-size:9px}.telemetry-actions{flex-wrap:wrap}}
1340
+ /* Status markers inside lifecycle assurance evidence mirror the main status language. */
1341
+ .lifecycle-detail-modal__assurance-heading{align-items:center;display:inline-flex;gap:8px}.lifecycle-detail-modal__assurance-status{align-items:center;border-radius:50%;display:inline-flex;flex:0 0 18px;font:800 12px/1 system-ui;height:18px;justify-content:center;width:18px!important}.lifecycle-detail-modal__assurance-status--passed{background:#51d88a;box-shadow:0 0 8px #51d88a66;color:#11261d!important}.lifecycle-detail-modal__assurance-status--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313!important}.lifecycle-detail-modal__assurance-status--neutral{background:#9a9aa3;color:#202027!important}
@@ -831,12 +831,12 @@ function reviewerPresentationState(status = {}) {
831
831
  }
832
832
  function activeReviewerAgents(items, executionStatus = {}) {
833
833
  const reviewActive = String(executionStatus?.current_phase || "").toUpperCase() === "CAPABILITY_REVIEW";
834
- // A later phase may retain only a fully successful review as compact
835
- // historical evidence. Running, failed or incomplete projections stay
836
- // phase-scoped so they can never look like live reviewer work.
837
- const completedReview = Array.isArray(items) && items.length > 0
838
- && items.every((agent) => String(agent?.status || "").toLowerCase() === "completed");
839
- const agents = (reviewActive || completedReview) && Array.isArray(items) ? items : [];
834
+ // A later phase may retain a wholly terminal review as compact historical
835
+ // evidence. Running or incomplete projections stay phase-scoped so they can
836
+ // never look like live reviewer work.
837
+ const terminalReview = Array.isArray(items) && items.length > 0
838
+ && items.every((agent) => ["completed", "failed"].includes(String(agent?.status || "").toLowerCase()));
839
+ const agents = (reviewActive || terminalReview) && Array.isArray(items) ? items : [];
840
840
  let card = $("activeReviewerAgents");
841
841
  if (!card) {
842
842
  card = document.createElement("section");
@@ -871,19 +871,23 @@ function activeReviewerAgents(items, executionStatus = {}) {
871
871
  indicator = document.createElement("span"), rawStatus = String(agent?.status || "").toLowerCase(),
872
872
  status = rawStatus === "running" && presentation !== "active" ? presentation : rawStatus;
873
873
  const isRunning = status === "running";
874
- const isCompleted = ["completed", "uitgevoerd"].includes(status);
874
+ const isCompleted = ["completed", "uitgevoerd"].includes(status), isFailed = status === "failed";
875
875
  row.className = "reviewer-agent";
876
876
  header.className = "reviewer-agent__header";
877
877
  name.className = "reviewer-agent__name";
878
878
  meta.className = "reviewer-agent__meta";
879
879
  name.textContent = reviewerLabel(agent.reviewer);
880
880
  meta.textContent = `${reviewerCapabilityLabel(agent.capability || "ENGINEERING")} · ${reviewerStatusLabel(status || "selected")}`;
881
- if (isRunning || isCompleted) {
882
- indicator.className = `reviewer-agent__status reviewer-agent__status--${isRunning ? "running" : "completed"}`;
881
+ if (isRunning || isCompleted || isFailed) {
882
+ const tone = isRunning ? "running" : isFailed ? "failed" : "completed";
883
+ indicator.className = `reviewer-agent__status reviewer-agent__status--${tone}`;
883
884
  indicator.setAttribute("role", "status");
884
- indicator.setAttribute("aria-label", isRunning ? t("ui.reviewer_status_running") : t("ui.reviewer_status_completed"));
885
+ indicator.setAttribute("aria-label", isRunning
886
+ ? t("ui.reviewer_status_running")
887
+ : isFailed ? reviewerStatusLabel("failed") : t("ui.reviewer_status_completed"));
885
888
  indicator.setAttribute("title", indicator.getAttribute("aria-label"));
886
889
  if (isCompleted) indicator.textContent = "✓";
890
+ if (isFailed) indicator.textContent = "×";
887
891
  }
888
892
  header.append(name, indicator);
889
893
  row.append(header, meta);
@@ -2143,12 +2147,31 @@ function lifecycleAssuranceEvidence(step) {
2143
2147
  for (const review of reviews) {
2144
2148
  if (!review || typeof review !== "object") continue;
2145
2149
  const findings = Array.isArray(review.findings) ? review.findings : [];
2146
- const item = document.createElement("li");
2147
- const role = String(review.reviewer || ""); const status = String(review.status || "UNRESOLVED");
2148
- item.append(Object.assign(document.createElement("strong"), { textContent: `${reviewerLabel(role, role)} · ${assuranceStatusLabel(status, status)}` }));
2150
+ const item = document.createElement("li"), heading = document.createElement("strong"),
2151
+ statusIcon = document.createElement("span"), status = String(review.status || "UNRESOLVED"),
2152
+ normalizedStatus = status.toUpperCase();
2153
+ const role = String(review.reviewer || "");
2154
+ const passed = normalizedStatus === "PASS", failed = ["FAIL", "FAILED", "UNRESOLVED"].includes(normalizedStatus);
2155
+ heading.className = "lifecycle-detail-modal__assurance-heading";
2156
+ statusIcon.className = "lifecycle-detail-modal__assurance-status lifecycle-detail-modal__assurance-status--"
2157
+ + (passed ? "passed" : failed ? "failed" : "neutral");
2158
+ statusIcon.setAttribute("aria-hidden", "true");
2159
+ statusIcon.textContent = passed ? "✓" : failed ? "×" : "•";
2160
+ heading.append(statusIcon, Object.assign(document.createElement("span"), {
2161
+ textContent: `${reviewerLabel(role, role)} · ${assuranceStatusLabel(status, status)}`,
2162
+ }));
2163
+ item.append(heading);
2149
2164
  const summary = findings.map((finding) => String(finding?.observation || "").trim()).filter(Boolean).join("; ");
2150
2165
  const summaryElement = Object.assign(document.createElement("span"), { textContent: summary || t("lifecycle.assurance_no_findings") });
2151
2166
  item.append(summaryElement);
2167
+ const coverage = Array.isArray(review.coverage) ? review.coverage : [];
2168
+ const dispositions = Array.isArray(review.finding_dispositions) ? review.finding_dispositions : [];
2169
+ if (coverage.length || dispositions.length) item.append(Object.assign(document.createElement("span"), {
2170
+ className: "estimate-meta",
2171
+ textContent: t("lifecycle.assurance_integral_evidence", {
2172
+ coverage: coverage.length, dispositions: dispositions.length,
2173
+ }),
2174
+ }));
2152
2175
  if (summary) dynamicRows.push({ source: summary, element: summaryElement });
2153
2176
  list.append(item);
2154
2177
  }
@@ -2200,20 +2223,46 @@ function lifecycleCapabilityEvidence(step) {
2200
2223
  section.append(list);
2201
2224
  return section;
2202
2225
  }
2203
- function lifecycleImplementationEvidence(step) {
2204
- const evidence = step?.implementation_evidence;
2226
+ function lifecyclePullRequestField(label, pullRequest, repository) {
2227
+ const field = lifecycleDetailField(label, `#${pullRequest}`);
2228
+ const repositoryIdentity = String(repository || "").trim();
2229
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repositoryIdentity)) return field;
2230
+ const link = document.createElement("a");
2231
+ link.className = "prompt-detail-pr-link";
2232
+ link.href = `https://github.com/${repositoryIdentity.split("/").map(encodeURIComponent).join("/")}/pull/${pullRequest}`;
2233
+ link.target = "_blank";
2234
+ link.rel = "noopener noreferrer";
2235
+ link.textContent = `#${pullRequest} ↗`;
2236
+ link.setAttribute("aria-label", `${label} #${pullRequest}`);
2237
+ field.lastElementChild.replaceWith(link);
2238
+ return field;
2239
+ }
2240
+ function lifecycleDeliveryEvidence(step) {
2241
+ const evidence = step?.delivery_evidence || step?.implementation_evidence;
2205
2242
  if (!evidence || typeof evidence !== "object") return null;
2243
+ const role = String(evidence.role || "implementation").toLowerCase();
2244
+ const titles = {
2245
+ implementation: "lifecycle.detail_implementation_evidence",
2246
+ finalization: "lifecycle.detail_finalization_evidence",
2247
+ reconciliation: "lifecycle.detail_reconciliation_evidence",
2248
+ };
2249
+ const pullRequestLabels = {
2250
+ implementation: "detail.implementation_pull_request",
2251
+ finalization: "detail.finalization_pull_request",
2252
+ reconciliation: "detail.reconciliation_pull_request",
2253
+ };
2206
2254
  const fields = [];
2207
2255
  if (evidence.branch) fields.push(lifecycleDetailField(t("workspace.current_branch"), String(evidence.branch)));
2208
2256
  if (evidence.candidate_sha) fields.push(lifecycleDetailField(t("detail.candidate_sha"), String(evidence.candidate_sha)));
2209
2257
  if (Number.isInteger(evidence.pull_request) && evidence.pull_request > 0) {
2210
- fields.push(lifecycleDetailField(t("detail.implementation_pull_request"), `#${evidence.pull_request}`));
2258
+ const label = t(pullRequestLabels[role] || pullRequestLabels.implementation);
2259
+ fields.push(lifecyclePullRequestField(label, evidence.pull_request, evidence.repository));
2211
2260
  }
2212
2261
  if (!fields.length) return null;
2213
2262
  const section = document.createElement("section");
2214
2263
  section.className = "lifecycle-detail-modal__implementation-evidence";
2215
2264
  section.append(
2216
- Object.assign(document.createElement("h3"), { textContent: t("lifecycle.detail_implementation_evidence") }),
2265
+ Object.assign(document.createElement("h3"), { textContent: t(titles[role] || titles.implementation) }),
2217
2266
  Object.assign(document.createElement("div"), { className: "technical-grid" }),
2218
2267
  );
2219
2268
  section.lastElementChild.append(...fields);
@@ -2346,8 +2395,8 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
2346
2395
  if (capabilityEvidence) content.append(capabilityEvidence);
2347
2396
  const assuranceEvidence = lifecycleAssuranceEvidence(step);
2348
2397
  if (assuranceEvidence) content.append(assuranceEvidence);
2349
- const implementationEvidence = lifecycleImplementationEvidence(step);
2350
- if (implementationEvidence) content.append(implementationEvidence);
2398
+ const deliveryEvidence = lifecycleDeliveryEvidence(step);
2399
+ if (deliveryEvidence) content.append(deliveryEvidence);
2351
2400
  const repairEvidence = lifecycleRepairEvidence(step);
2352
2401
  if (repairEvidence) content.append(repairEvidence);
2353
2402
  if (!modal.open) modal.showModal();
@@ -2364,15 +2413,24 @@ function lifecycleStepWithEvidence(step, context = {}) {
2364
2413
  : Array.isArray(context.reviewers) ? context.reviewers : [];
2365
2414
  if (reviewers.length) enriched.reviewer_evidence = reviewers;
2366
2415
  }
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);
2416
+ const deliverySteps = {
2417
+ EXECUTE_AGENT: { role: "implementation", candidate: "implementation_candidate_sha", branch: "implementation_branch", pullRequest: "implementation_pr" },
2418
+ FINALIZE_AGENT: { role: "finalization", candidate: "finalization_candidate_sha", branch: "finalization_branch", pullRequest: "finalization_pr" },
2419
+ RECONCILE_AGENT: { role: "reconciliation", candidate: "reconciliation_candidate_sha", branch: "reconciliation_branch", pullRequest: "reconciliation_pr" },
2420
+ };
2421
+ const delivery = deliverySteps[id];
2422
+ if (delivery) {
2423
+ const candidate = String(context[delivery.candidate] || "").trim();
2424
+ const branch = String(context[delivery.branch] || "").trim();
2425
+ const pullRequest = Number(context[delivery.pullRequest]);
2426
+ const repository = String(context.github_repository || context.target_repository || "").trim();
2371
2427
  const evidence = {};
2428
+ evidence.role = delivery.role;
2372
2429
  if (/^[0-9a-f]{40}$/.test(candidate)) evidence.candidate_sha = candidate;
2373
2430
  if (branch) evidence.branch = branch;
2374
2431
  if (Number.isInteger(pullRequest) && pullRequest > 0) evidence.pull_request = pullRequest;
2375
- if (Object.keys(evidence).length) enriched.implementation_evidence = evidence;
2432
+ if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) evidence.repository = repository;
2433
+ if (Object.keys(evidence).length > 1) enriched.delivery_evidence = evidence;
2376
2434
  }
2377
2435
  return enriched;
2378
2436
  }
@@ -8543,19 +8601,41 @@ function promptDetailRecommendationHandoff(handoff) {
8543
8601
  }
8544
8602
  function promptDetailReviewersSection(reviewers, { wide = true } = {}) {
8545
8603
  if (!reviewers.length) return null;
8546
- const fields = reviewers.map((reviewer) =>
8547
- detailField(
8548
- reviewerLabel(reviewer.reviewer, t("detail.specialist_review")),
8549
- t("detail.capability") + ": " +
8550
- reviewerCapabilityLabel(reviewer.capability || "ENGINEERING") + " · " +
8551
- reviewerStatusLabel(reviewer.status || "completed") + " · " +
8552
- t("detail.accepted_recommendations") + ": " +
8553
- (Number(reviewer.accepted_recommendations) || 0) + "\n" +
8554
- t("detail.selected_because") + ": " +
8604
+ const fields = reviewers.map((reviewer) => {
8605
+ const rawStatus = String(reviewer.status || "completed").toLowerCase();
8606
+ const failed = rawStatus === "failed", completed = ["completed", "uitgevoerd"].includes(rawStatus);
8607
+ const field = document.createElement("article"), heading = document.createElement("h4"),
8608
+ statusLabel = document.createElement("span"), statusRow = document.createElement("span"),
8609
+ indicator = document.createElement("span"), statusText = document.createElement("span");
8610
+ field.className = "field prompt-detail-reviewer";
8611
+ heading.textContent = reviewerLabel(reviewer.reviewer, t("detail.specialist_review"));
8612
+ statusLabel.className = "label";
8613
+ statusLabel.textContent = t("detail.prompt_status");
8614
+ statusRow.className = "prompt-detail-reviewer__status";
8615
+ indicator.className = "prompt-detail-reviewer__status-icon prompt-detail-reviewer__status-icon--"
8616
+ + (failed ? "failed" : completed ? "completed" : "neutral");
8617
+ indicator.setAttribute("aria-hidden", "true");
8618
+ indicator.textContent = failed ? "×" : completed ? "✓" : "•";
8619
+ statusText.className = "prompt-detail-reviewer__status-text";
8620
+ statusText.textContent = reviewerCapabilityLabel(reviewer.capability || "ENGINEERING")
8621
+ + " · " + reviewerStatusLabel(rawStatus);
8622
+ statusRow.append(indicator, statusText);
8623
+ field.append(
8624
+ heading,
8625
+ statusLabel,
8626
+ statusRow,
8627
+ detailField(
8628
+ t("detail.selected_because"),
8555
8629
  String(reviewer.selected_because || t("detail.not_recorded")),
8556
- true,
8557
- ),
8558
- );
8630
+ true,
8631
+ ),
8632
+ detailField(
8633
+ t("detail.accepted_recommendations"),
8634
+ String(Number(reviewer.accepted_recommendations) || 0),
8635
+ ),
8636
+ );
8637
+ return field;
8638
+ });
8559
8639
  return promptDetailCard(t("detail.specialist_reviews"), fields, wide, "prompt-detail-card--reviewers");
8560
8640
  }
8561
8641
  function promptDetailAssuranceReviewsSection(reviews) {
@@ -4273,8 +4273,13 @@ Object.assign(DASHBOARD_MESSAGES.es, {
4273
4273
  // A repair step can be entered before a pull request exists and shares its
4274
4274
  // bounded budget across local validation, assurance, hosted checks and
4275
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"});
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_finalization_evidence":"Finalization result","lifecycle.detail_reconciliation_evidence":"Reconciliation 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_finalization_evidence":"Finalisatieresultaat","lifecycle.detail_reconciliation_evidence":"Reconciliatieresultaat","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_finalization_evidence":"Finalisierungsergebnis","lifecycle.detail_reconciliation_evidence":"Abstimmungsergebnis","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_finalization_evidence":"Résultat de la finalisation","lifecycle.detail_reconciliation_evidence":"Résultat de la réconciliation","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_finalization_evidence":"Resultado de la finalización","lifecycle.detail_reconciliation_evidence":"Resultado de la conciliación","lifecycle.detail_validation_pass":"Pasada de validación {iteration}","detail.initial_observation":"Observación inicial","detail.rejected_recommendations":"Recomendaciones rechazadas"});
4281
+ Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.assurance_integral_evidence":"Impact surfaces reviewed: {coverage} · Prior findings reassessed: {dispositions}"});
4282
+ Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.assurance_integral_evidence":"Impactvlakken beoordeeld: {coverage} · Eerdere bevindingen herbeoordeeld: {dispositions}"});
4283
+ Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.assurance_integral_evidence":"Geprüfte Auswirkungsbereiche: {coverage} · Frühere Befunde erneut bewertet: {dispositions}"});
4284
+ Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.assurance_integral_evidence":"Surfaces d’impact examinées : {coverage} · Constats antérieurs réévalués : {dispositions}"});
4285
+ Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.assurance_integral_evidence":"Superficies de impacto revisadas: {coverage} · Hallazgos anteriores reevaluados: {dispositions}"});
@@ -44,10 +44,47 @@ REVIEWER_LABELS = {
44
44
  "documentation": "Documentation Reviewer",
45
45
  "finalization": "Finalization Reviewer",
46
46
  }
47
- MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION = "1.0"
47
+ ADVISORY_REVIEW_OUTPUT_CONTRACT_VERSION = "1.0"
48
+ MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION = "2.0"
48
49
  MANDATORY_FINDING_FIELDS = frozenset({
49
50
  "id", "observation", "category", "criterion", "severity", "confidence", "evidence_ref",
50
51
  })
52
+ MANDATORY_COVERAGE_FIELDS = frozenset({"surface", "status", "evidence_ref"})
53
+ MANDATORY_DISPOSITION_FIELDS = frozenset({"finding_id", "disposition", "evidence_ref"})
54
+ MANDATORY_COVERAGE_SURFACES = {
55
+ "IMPLEMENTATION": {
56
+ "quality": (
57
+ "approved_criteria", "full_candidate_diff", "callers_and_consumers",
58
+ "service_lifecycle", "maintenance_recovery_cleanup", "persistence_concurrency",
59
+ "transport_schema_compatibility", "regression_validation",
60
+ ),
61
+ "security": (
62
+ "approved_criteria", "full_candidate_diff", "trust_authentication",
63
+ "data_integrity_concurrency", "maintenance_recovery_cleanup",
64
+ "failure_redaction", "availability_resource_bounds", "security_validation",
65
+ ),
66
+ },
67
+ "FINALIZATION": {
68
+ "quality": (
69
+ "delivery_role_scope", "full_candidate_diff", "record_consistency",
70
+ "lifecycle_state_claims", "regression_validation",
71
+ ),
72
+ "security": (
73
+ "delivery_role_scope", "full_candidate_diff", "authority_scope",
74
+ "sensitive_data", "lifecycle_state_claims", "security_validation",
75
+ ),
76
+ },
77
+ "RECONCILIATION": {
78
+ "quality": (
79
+ "delivery_role_scope", "full_candidate_diff", "record_consistency",
80
+ "lifecycle_state_claims", "regression_validation",
81
+ ),
82
+ "security": (
83
+ "delivery_role_scope", "full_candidate_diff", "authority_scope",
84
+ "sensitive_data", "lifecycle_state_claims", "security_validation",
85
+ ),
86
+ },
87
+ }
51
88
  PRODUCT_MATCHERS = {
52
89
  "apple_platform": (("apps/apple/", "engineering-platform-app", "swiftui", "watchos", "macos", "ios"), "Apple platform capability"),
53
90
  "windows_platform": (("apps/windows/", "engineering-platform-windows", "maui", "windows packaging"), "Windows platform capability"),
@@ -77,13 +114,15 @@ class ReviewerResult:
77
114
  # In-process deterministic/test adapters construct this typed result only
78
115
  # after choosing the mandatory contract. Raw provider JSON is still
79
116
  # required to carry this field by ``CodexCliClient.review``.
80
- contract_version: str | None = MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION
117
+ contract_version: str | None = ADVISORY_REVIEW_OUTPUT_CONTRACT_VERSION
81
118
  failed: bool = False
82
119
  usage: dict[str, object] = field(default_factory=dict)
83
120
  runtime_metadata: dict[str, object] = field(default_factory=dict)
84
121
  churn: dict[str, object] = field(default_factory=dict)
85
122
  duration_seconds: float | None = None
86
123
  usage_snapshots: tuple[dict[str, int], ...] = ()
124
+ coverage: tuple[dict[str, str], ...] = ()
125
+ finding_dispositions: tuple[dict[str, str], ...] = ()
87
126
 
88
127
 
89
128
  class ReviewerClient(Protocol):
@@ -164,6 +203,8 @@ def run_reviews(
164
203
  result.churn,
165
204
  result.duration_seconds,
166
205
  result.usage_snapshots,
206
+ tuple(dict(item) for item in result.coverage if isinstance(item, dict)),
207
+ tuple(dict(item) for item in result.finding_dispositions if isinstance(item, dict)),
167
208
  )
168
209
  except Exception: # Reviewer failure is advisory and cannot block the transaction.
169
210
  result = ReviewerResult(selection.reviewer, "Reviewer failed; primary review continues.", failed=True)
@@ -192,7 +233,8 @@ def mandatory_findings(result: ReviewerResult) -> tuple[dict[str, str], ...] | N
192
233
  """Return validated mandatory output, never advice-shaped pseudo-evidence."""
193
234
  if result.failed or result.contract_version != MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION:
194
235
  return None
195
- if not isinstance(result.findings, tuple) or len(result.findings) > 64:
236
+ finding_limit = 12 if result.reviewer in {"quality", "security"} else 64
237
+ if not isinstance(result.findings, tuple) or len(result.findings) > finding_limit:
196
238
  return None
197
239
  normalized: list[dict[str, str]] = []
198
240
  seen: set[str] = set()
@@ -210,6 +252,65 @@ def mandatory_findings(result: ReviewerResult) -> tuple[dict[str, str], ...] | N
210
252
  return tuple(normalized)
211
253
 
212
254
 
255
+ def mandatory_coverage_surfaces(reviewer: str, delivery_role: str) -> tuple[str, ...]:
256
+ """Return the host-owned complete impact checklist for one assurance role."""
257
+ return MANDATORY_COVERAGE_SURFACES.get(delivery_role, {}).get(reviewer, ())
258
+
259
+
260
+ def mandatory_assessment(
261
+ result: ReviewerResult,
262
+ *,
263
+ delivery_role: str,
264
+ prior_finding_ids: tuple[str, ...],
265
+ ) -> tuple[tuple[dict[str, str], ...], tuple[dict[str, str], ...], tuple[dict[str, str], ...]] | None:
266
+ """Validate complete impact coverage and explicit prior-finding closure.
267
+
268
+ A syntactically valid list of findings is insufficient for mandatory
269
+ assurance. Each reviewer must cover every host-owned impact surface and
270
+ explicitly reassess every still-open finding previously raised by that
271
+ same independent role.
272
+ """
273
+ findings = mandatory_findings(result)
274
+ required_surfaces = mandatory_coverage_surfaces(result.reviewer, delivery_role)
275
+ if findings is None or not required_surfaces:
276
+ return None
277
+ coverage = result.coverage
278
+ dispositions = result.finding_dispositions
279
+ if (
280
+ not isinstance(coverage, tuple)
281
+ or len(coverage) != len(required_surfaces)
282
+ or any(not isinstance(item, dict) or set(item) != MANDATORY_COVERAGE_FIELDS for item in coverage)
283
+ or any(
284
+ item["surface"] not in required_surfaces
285
+ or item["status"] not in {"REVIEWED", "NOT_APPLICABLE"}
286
+ or not isinstance(item["evidence_ref"], str) or not item["evidence_ref"].strip()
287
+ or len(item["evidence_ref"]) > 240
288
+ for item in coverage
289
+ )
290
+ or {item["surface"] for item in coverage} != set(required_surfaces)
291
+ ):
292
+ return None
293
+ if (
294
+ not isinstance(dispositions, tuple)
295
+ or len(dispositions) != len(prior_finding_ids)
296
+ or any(not isinstance(item, dict) or set(item) != MANDATORY_DISPOSITION_FIELDS for item in dispositions)
297
+ or any(
298
+ item["finding_id"] not in prior_finding_ids
299
+ or item["disposition"] not in {"RESOLVED", "OPEN"}
300
+ or not isinstance(item["evidence_ref"], str) or not item["evidence_ref"].strip()
301
+ or len(item["evidence_ref"]) > 240
302
+ for item in dispositions
303
+ )
304
+ or {item["finding_id"] for item in dispositions} != set(prior_finding_ids)
305
+ ):
306
+ return None
307
+ return (
308
+ findings,
309
+ tuple({key: redact_diagnostic(value, limit=240) for key, value in item.items()} for item in coverage),
310
+ tuple({key: redact_diagnostic(value, limit=240) for key, value in item.items()} for item in dispositions),
311
+ )
312
+
313
+
213
314
  def records_for_storage(selections: tuple[ReviewerSelection, ...], results: tuple[ReviewerResult, ...]) -> tuple[dict[str, object], ...]:
214
315
  by_reviewer = {result.reviewer: result for result in results}
215
316
  records: list[dict[str, object]] = []
@@ -29,14 +29,15 @@ RunJsonReader = Callable[[Path, str | None], bytes]
29
29
  TERMINAL_PHASES = frozenset({"COMPLETE", "BLOCKED", "FAILED"})
30
30
 
31
31
 
32
- def _successful_reviewer_agents(value: object) -> list[dict[str, object]]:
33
- """Expose only a wholly successful review beyond its live phase."""
32
+ def _terminal_reviewer_agents(value: object) -> list[dict[str, object]]:
33
+ """Expose a wholly terminal review beyond its live phase."""
34
34
  if not isinstance(value, list):
35
35
  return []
36
36
  reviewers = [item for item in value if isinstance(item, dict)]
37
37
  if not reviewers or len(reviewers) != len(value):
38
38
  return []
39
- return reviewers if all(item.get("status") == "completed" for item in reviewers) else []
39
+ terminal = {"completed", "failed"}
40
+ return reviewers if all(item.get("status") in terminal for item in reviewers) else []
40
41
 
41
42
 
42
43
  def _run_workspace_preflight(root: Path, run_id: object) -> dict[str, object]:
@@ -417,13 +418,13 @@ def status(root: Path) -> bytes:
417
418
  "candidate_sha": live.get("candidate_sha"),
418
419
  "repair_iteration": live.get("repair_iteration"),
419
420
  "workspace_preflight": run_workspace_preflight,
420
- # Only a wholly successful specialist review survives its
421
- # live phase as historical evidence for this active run. A
422
- # partial, failed or stale reviewer projection remains hidden.
421
+ # Only a wholly terminal specialist review survives its live
422
+ # phase as historical evidence for this active run. A running
423
+ # or malformed reviewer projection remains hidden.
423
424
  "reviewer_agents": (
424
425
  live.get("reviewer_agents", [])
425
426
  if live.get("phase") == "CAPABILITY_REVIEW"
426
- else _successful_reviewer_agents(live.get("reviewer_agents"))
427
+ else _terminal_reviewer_agents(live.get("reviewer_agents"))
427
428
  ),
428
429
  "runtime_metadata": live.get("runtime_metadata", {}),
429
430
  "workspace_progress": live.get("workspace_progress"),