engineering-platform 2.3.100__tar.gz → 2.3.101__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 (173) hide show
  1. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/PKG-INFO +1 -1
  2. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/pyproject.toml +1 -1
  3. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
  4. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
  5. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/agent_state.py +45 -5
  6. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard.css +3 -0
  7. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard.js +223 -8
  8. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_locales.mjs +20 -0
  9. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_host.py +67 -8
  10. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_lifecycle.py +3 -0
  11. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/platform_version.py +1 -1
  12. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/report_analysis.py +12 -1
  13. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/reviewer_evidence.py +9 -1
  14. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/server_console_services.py +8 -0
  15. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/templates/workspace-config.json +1 -1
  16. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/PKG-INFO +1 -1
  17. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/README.md +0 -0
  18. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/setup.cfg +0 -0
  19. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/__init__.py +0 -0
  20. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/__main__.py +0 -0
  21. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/agent_trust.py +0 -0
  22. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  23. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
  24. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  25. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  26. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  27. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  28. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  29. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  30. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/assurance_scope.py +0 -0
  31. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/capability_preflight.py +0 -0
  32. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/capability_review.py +0 -0
  33. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/central_data_transfer.py +0 -0
  34. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/central_database.py +0 -0
  35. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/central_operational_reset.py +0 -0
  36. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/central_store_migration.py +0 -0
  37. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/codex_capacity.py +0 -0
  38. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/codex_chat.py +0 -0
  39. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/codex_observability.py +0 -0
  40. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/component_lock.py +0 -0
  41. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/component_logging.py +0 -0
  42. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/console_presentation.py +0 -0
  43. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/console_route_ownership.py +0 -0
  44. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/contracts/__init__.py +0 -0
  45. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  46. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/contracts/models.py +0 -0
  47. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/contracts/projection.py +0 -0
  48. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_browser_validation.py +0 -0
  49. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_state.py +0 -0
  50. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  51. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_translation.py +0 -0
  52. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/dependabot_producer.py +0 -0
  53. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/development_profile.py +0 -0
  54. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/drift_diagnostics.py +0 -0
  55. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/emergency_recovery.py +0 -0
  56. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/engineering_memory.py +0 -0
  57. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  58. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/evidence_projection.py +0 -0
  59. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_activity.py +0 -0
  60. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_context.py +0 -0
  61. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_errors.py +0 -0
  62. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_evidence.py +0 -0
  63. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_executor.py +0 -0
  64. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_finalization.py +0 -0
  65. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_host_evidence.py +0 -0
  66. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_lease.py +0 -0
  67. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_models.py +0 -0
  68. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_readiness.py +0 -0
  69. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_reporting.py +0 -0
  70. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_repository.py +0 -0
  71. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_timeout_policy.py +0 -0
  72. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_timing.py +0 -0
  73. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/execution_transaction.py +0 -0
  74. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/external_producer_binding.py +0 -0
  75. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/file_inbox.py +0 -0
  76. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/forensic_attribution.py +0 -0
  77. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  78. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/forensic_delta.py +0 -0
  79. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/golden_scenario.py +0 -0
  80. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  81. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/host_admin.py +0 -0
  82. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/host_preflight.py +0 -0
  83. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_relocation.py +0 -0
  84. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_activation.py +0 -0
  85. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_admission.py +0 -0
  86. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_backup.py +0 -0
  87. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_composition.py +0 -0
  88. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_executor.py +0 -0
  89. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_migration.py +0 -0
  90. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_operation.py +0 -0
  91. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_plan.py +0 -0
  92. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_preparation.py +0 -0
  93. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/investigation_ledger.py +0 -0
  94. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  95. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/legacy_installation_adoption.py +0 -0
  96. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/lifecycle_worker.py +0 -0
  97. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/live_status.py +0 -0
  98. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/local_api.py +0 -0
  99. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/local_api_keychain.py +0 -0
  100. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/local_repository_binding.py +0 -0
  101. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/managed_autonomy.py +0 -0
  102. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/managed_codex_runtime.py +0 -0
  103. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/managed_workspace_readiness.py +0 -0
  104. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/managed_workspace_recovery.py +0 -0
  105. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/merge_delegation.py +0 -0
  106. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation.py +0 -0
  107. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation_lock.py +0 -0
  108. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation_record.py +0 -0
  109. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/owner_credential_recovery.py +0 -0
  110. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/parity_context.py +0 -0
  111. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
  112. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/platform_admin.py +0 -0
  113. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/platform_api.py +0 -0
  114. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/platform_bootstrap.py +0 -0
  115. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/platform_components.py +0 -0
  116. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/pr_check_repair.py +0 -0
  117. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  118. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/producer.py +0 -0
  119. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/product_installation_readback.py +0 -0
  120. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/project_agent.py +0 -0
  121. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/project_agent_service.py +0 -0
  122. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/project_topology.py +0 -0
  123. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/prompt_history.py +0 -0
  124. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_context.py +0 -0
  125. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_context_benchmark.py +0 -0
  126. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_context_scope.py +0 -0
  127. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_interruption.py +0 -0
  128. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_process_identity.py +0 -0
  129. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_readiness.py +0 -0
  130. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_recovery.py +0 -0
  131. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/provider_usage.py +0 -0
  132. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/providers.py +0 -0
  133. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/qualification.py +0 -0
  134. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/qualification_runtime.py +0 -0
  135. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/recommendation_handoff.py +0 -0
  136. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/reconciliation_adoption.py +0 -0
  137. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/release_operation.py +0 -0
  138. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/repository_attachment.py +0 -0
  139. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/repository_handoff.py +0 -0
  140. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/resources.py +0 -0
  141. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/revision_binding.py +0 -0
  142. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
  143. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +0 -0
  144. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  145. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  146. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/server.py +0 -0
  147. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/server_relay.py +0 -0
  148. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/server_service.py +0 -0
  149. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/status_model.py +0 -0
  150. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/status_reconciliation.py +0 -0
  151. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/storage.py +0 -0
  152. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/submission_cli.py +0 -0
  153. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/submission_intake.py +0 -0
  154. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/submission_service.py +0 -0
  155. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/system_installation_topology.py +0 -0
  156. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/system_server_service.py +0 -0
  157. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/telemetry.py +0 -0
  158. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_contract.py +0 -0
  159. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_export.py +0 -0
  160. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_metrics.py +0 -0
  161. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
  162. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/validation_identity.py +0 -0
  163. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/validation_profile.py +0 -0
  164. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/version_preparation_delivery.py +0 -0
  165. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/workspace_preflight.py +0 -0
  166. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/worktree_provenance.py +0 -0
  167. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform/worktree_tooling.py +0 -0
  168. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
  169. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  170. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  171. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/top_level.txt +0 -0
  172. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/tests/test_adaptive_action_sizing_design.py +0 -0
  173. {engineering_platform-2.3.100 → engineering_platform-2.3.101}/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.100
3
+ Version: 2.3.101
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.100"
7
+ version = "2.3.101"
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.100",
6
+ "version": "2.3.101",
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.100",
4
+ "dashboard_version": "2.3.101",
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.100",
9
+ "platform_version": "2.3.101",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.100",
11
+ "runner_version": "2.3.101",
12
12
  "status_model": 1,
13
13
  "storage_schema": 45,
14
- "watcher_version": "2.3.100"
14
+ "watcher_version": "2.3.101"
15
15
  }
@@ -134,13 +134,16 @@ class TransactionState:
134
134
  implementation_branch: str | None = None
135
135
  implementation_pull_request: int | None = None
136
136
  implementation_head_sha: str | None = None
137
+ implementation_changed_paths: tuple[str, ...] = ()
137
138
  implementation_merge_commit: str | None = None
138
139
  finalization_branch: str | None = None
139
140
  finalization_pull_request: int | None = None
140
141
  finalization_head_sha: str | None = None
142
+ finalization_changed_paths: tuple[str, ...] = ()
141
143
  finalization_merge_commit: str | None = None
142
144
  reconciliation_pull_request: int | None = None
143
145
  reconciliation_head_sha: str | None = None
146
+ reconciliation_changed_paths: tuple[str, ...] = ()
144
147
  reconciliation_merge_commit: str | None = None
145
148
  delivery_control_validation_required: bool = False
146
149
  merge_delegation_id: str | None = None
@@ -155,6 +158,9 @@ class TransactionState:
155
158
  # observations; a later review appends a new record instead of changing an
156
159
  # earlier finding into a pass.
157
160
  assurance_profile: dict[str, str] | None = None
161
+ # Live, bounded progress for the current two-reviewer assurance wave. The
162
+ # immutable review records remain in ``assurance_reviews``.
163
+ assurance_review_progress: tuple[dict[str, str], ...] = ()
158
164
  assurance_reviews: tuple[dict[str, object], ...] = ()
159
165
  assurance_resolutions: tuple[dict[str, str], ...] = ()
160
166
  repair_iterations: int = 0
@@ -188,11 +194,11 @@ class TransactionState:
188
194
  "allowed_baseline_revision": None,
189
195
  "action_intent": "MUTATING_DELIVERY",
190
196
  "implementation_branch": None, "implementation_pull_request": None,
191
- "implementation_head_sha": None, "implementation_merge_commit": None,
197
+ "implementation_head_sha": None, "implementation_changed_paths": (), "implementation_merge_commit": None,
192
198
  "finalization_branch": None, "finalization_pull_request": None,
193
- "finalization_head_sha": None, "finalization_merge_commit": None,
199
+ "finalization_head_sha": None, "finalization_changed_paths": (), "finalization_merge_commit": None,
194
200
  "reconciliation_pull_request": None,
195
- "reconciliation_head_sha": None,
201
+ "reconciliation_head_sha": None, "reconciliation_changed_paths": (),
196
202
  "reconciliation_merge_commit": None,
197
203
  "delivery_control_validation_required": False,
198
204
  "merge_delegation_id": None,
@@ -203,6 +209,7 @@ class TransactionState:
203
209
  "validation_evidence": (),
204
210
  "quality_evidence": (),
205
211
  "assurance_profile": None,
212
+ "assurance_review_progress": (),
206
213
  "assurance_reviews": (),
207
214
  "assurance_resolutions": (),
208
215
  "repair_iterations": 0,
@@ -227,8 +234,13 @@ class TransactionState:
227
234
  raw = {**raw, "validation_evidence": tuple(raw["validation_evidence"])}
228
235
  if isinstance(raw.get("quality_evidence"), list):
229
236
  raw = {**raw, "quality_evidence": tuple(raw["quality_evidence"])}
237
+ for field in ("implementation_changed_paths", "finalization_changed_paths", "reconciliation_changed_paths"):
238
+ if isinstance(raw.get(field), list):
239
+ raw = {**raw, field: tuple(raw[field])}
230
240
  if isinstance(raw.get("assurance_reviews"), list):
231
241
  raw = {**raw, "assurance_reviews": tuple(raw["assurance_reviews"])}
242
+ if isinstance(raw.get("assurance_review_progress"), list):
243
+ raw = {**raw, "assurance_review_progress": tuple(raw["assurance_review_progress"])}
232
244
  if isinstance(raw.get("assurance_resolutions"), list):
233
245
  raw = {**raw, "assurance_resolutions": tuple(raw["assurance_resolutions"])}
234
246
  if isinstance(raw.get("repair_audit"), list):
@@ -311,14 +323,26 @@ class TransactionState:
311
323
  optional_pr_fields = (state.implementation_pull_request, state.finalization_pull_request, state.reconciliation_pull_request)
312
324
  if any(value is not None and (not isinstance(value, int) or value < 1) for value in optional_pr_fields):
313
325
  raise StateError("checkpoint lifecycle pull request is invalid")
326
+ for paths in (state.implementation_changed_paths, state.finalization_changed_paths, state.reconciliation_changed_paths):
327
+ if (
328
+ not isinstance(paths, tuple)
329
+ or len(paths) > 4096
330
+ or any(
331
+ not isinstance(path, str) or not path or len(path) > 4096
332
+ or path.startswith("/") or ".." in Path(path).parts or "\x00" in path
333
+ for path in paths
334
+ )
335
+ ):
336
+ raise StateError("checkpoint changed paths are invalid")
314
337
  if not isinstance(state.repair_iterations, int) or state.repair_iterations < 0:
315
338
  raise StateError("checkpoint repair iteration count is invalid")
316
339
  audit_fields = {"iteration", "observed_at", "failed_checks", "proposed_action", "agent_summary", "commit_sha", "outcome"}
317
- if not isinstance(state.local_validation_iterations, int) or not 0 <= state.local_validation_iterations <= 3:
340
+ # Initial validation plus at most three run-wide repair candidates.
341
+ if not isinstance(state.local_validation_iterations, int) or not 0 <= state.local_validation_iterations <= 4:
318
342
  raise StateError("checkpoint local validation iteration count is invalid")
319
343
  if (
320
344
  not isinstance(state.local_validation_audit, tuple)
321
- or len(state.local_validation_audit) > 3
345
+ or len(state.local_validation_audit) > 4
322
346
  or any(
323
347
  not isinstance(item, dict) or set(item) != audit_fields
324
348
  or not all(isinstance(value, str) and value and len(value) <= MAX_DIAGNOSTIC_LENGTH and value == redact_diagnostic(value) for value in item.values())
@@ -456,6 +480,22 @@ class TransactionState:
456
480
  )
457
481
  ):
458
482
  raise StateError("checkpoint assurance profile is invalid")
483
+ progress_fields = {"reviewer", "status"}
484
+ if (
485
+ not isinstance(state.assurance_review_progress, tuple)
486
+ or len(state.assurance_review_progress) > 2
487
+ or any(
488
+ not isinstance(item, dict)
489
+ or set(item) != progress_fields
490
+ or item.get("reviewer") not in {"quality", "security"}
491
+ or item.get("status") not in {"PENDING", "ACTIVE", "COMPLETED"}
492
+ for item in state.assurance_review_progress
493
+ )
494
+ or len({item["reviewer"] for item in state.assurance_review_progress})
495
+ != len(state.assurance_review_progress)
496
+ or sum(item["status"] == "ACTIVE" for item in state.assurance_review_progress) > 1
497
+ ):
498
+ raise StateError("checkpoint assurance review progress is invalid")
459
499
  review_fields = {"reviewer", "status", "candidate_sha", "profile_digest", "invocation_id", "findings"}
460
500
  current_review_fields = review_fields | {"contract_version", "started_at", "completed_at"}
461
501
  integral_review_fields = current_review_fields | {"coverage", "finding_dispositions"}
@@ -281,6 +281,7 @@ html[data-theme="light"] :is(#rateLimitReset,#codexCliUpdate){background:#e8fff5
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
283
  .prompt-detail-assurance-review__content{display:grid;gap:5px;margin:0;white-space:normal}.prompt-detail-assurance-review__line{display:block;overflow-wrap:anywhere;white-space:pre-wrap}.assurance-review-status{align-items:center;display:inline-flex;gap:8px;width:max-content}.assurance-review-status__text{line-height:18px}
284
+ .prompt-detail-assurance-wave-heading{border-top:1px solid color-mix(in srgb,var(--category-color) 45%,transparent);color:var(--category-color);font-size:15px;margin:18px 0 12px;padding-top:16px}.prompt-detail-assurance-wave-heading:first-of-type{border-top:0;margin-top:0;padding-top:0}
284
285
  .reviewer-agent__status--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313;font:800 14px/1 system-ui;height:16px;width:16px}
285
286
  .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}
286
287
  .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}
@@ -1343,3 +1344,5 @@ html[data-theme="light"] :is(.dashboard-status-banner--provider-auth_required .p
1343
1344
  .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}}
1344
1345
  /* Status markers inside lifecycle assurance evidence mirror the main status language. */
1345
1346
  .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}
1347
+ .lifecycle-detail-modal__assurance-progress{align-items:center;color:var(--modal-secondary-accent);display:flex;gap:9px;margin:10px 0 14px}.lifecycle-detail-modal__assurance-progress .reviewer-agent__status{flex:0 0 auto}
1348
+ .lifecycle-detail-modal__assurance-wave-heading{border-top:1px solid color-mix(in srgb,var(--modal-secondary-accent) 45%,transparent);color:var(--modal-secondary-accent);font-weight:800;margin-top:18px;padding-top:16px}.lifecycle-detail-modal__assurance-wave-heading:first-child{border-top:0;margin-top:0;padding-top:0}
@@ -2178,7 +2178,8 @@ function lifecycleQualityEvidence(step) {
2178
2178
  }
2179
2179
  function lifecycleAssuranceEvidence(step) {
2180
2180
  const reviews = Array.isArray(step?.assurance_reviews) ? step.assurance_reviews : [];
2181
- if (!reviews.length) return null;
2181
+ const progress = Array.isArray(step?.assurance_review_progress) ? step.assurance_review_progress : [];
2182
+ if (!reviews.length && !progress.length) return null;
2182
2183
  const section = document.createElement("section");
2183
2184
  section.className = "lifecycle-detail-modal__quality-evidence lifecycle-detail-modal__assurance-evidence";
2184
2185
  const rounds = step?.repair_rounds || {};
@@ -2186,10 +2187,40 @@ function lifecycleAssuranceEvidence(step) {
2186
2187
  if (Number.isFinite(Number(rounds.used))) section.append(Object.assign(document.createElement("p"), {
2187
2188
  className: "estimate-meta", textContent: t("lifecycle.repair_rounds", { used: rounds.used, maximum: rounds.maximum || 3 }),
2188
2189
  }));
2190
+ const completedReviewers = progress.filter((item) => String(item?.status || "").toUpperCase() === "COMPLETED").length;
2191
+ const activeReviewer = progress.find((item) => String(item?.status || "").toUpperCase() === "ACTIVE");
2192
+ if (progress.length && completedReviewers < progress.length) {
2193
+ const row = document.createElement("p"), indicator = document.createElement("span"), text = document.createElement("span");
2194
+ row.className = "lifecycle-detail-modal__assurance-progress";
2195
+ indicator.className = "reviewer-agent__status reviewer-agent__status--running";
2196
+ indicator.setAttribute("aria-label", t("ui.reviewer_status_running"));
2197
+ text.textContent = activeReviewer
2198
+ ? t("lifecycle.assurance_progress_active", {
2199
+ completed: completedReviewers,
2200
+ total: progress.length,
2201
+ reviewer: reviewerLabel(activeReviewer.reviewer),
2202
+ })
2203
+ : t("lifecycle.assurance_progress_waiting", { completed: completedReviewers, total: progress.length });
2204
+ row.append(indicator, text);
2205
+ section.append(row);
2206
+ }
2189
2207
  const list = document.createElement("ol"); list.className = "lifecycle-detail-modal__phase-list";
2190
2208
  const dynamicRows = [];
2209
+ let currentCandidate = null, waveIndex = -1;
2191
2210
  for (const review of reviews) {
2192
2211
  if (!review || typeof review !== "object") continue;
2212
+ const candidate = /^[0-9a-f]{40}$/.test(String(review.candidate_sha || ""))
2213
+ ? String(review.candidate_sha) : "unbound";
2214
+ if (candidate !== currentCandidate) {
2215
+ currentCandidate = candidate;
2216
+ waveIndex += 1;
2217
+ list.append(Object.assign(document.createElement("li"), {
2218
+ className: "lifecycle-detail-modal__assurance-wave-heading",
2219
+ textContent: waveIndex === 0
2220
+ ? t("lifecycle.assurance_initial_wave")
2221
+ : t("lifecycle.assurance_repair_wave", { iteration: waveIndex }),
2222
+ }));
2223
+ }
2193
2224
  const findings = Array.isArray(review.findings) ? review.findings : [];
2194
2225
  const item = document.createElement("li"), heading = document.createElement("strong"),
2195
2226
  status = String(review.status || "UNRESOLVED"), statusPresentation = assuranceStatusPresentation(status);
@@ -2292,6 +2323,16 @@ function lifecycleDeliveryEvidence(step) {
2292
2323
  const label = t(pullRequestLabels[role] || pullRequestLabels.implementation);
2293
2324
  fields.push(lifecyclePullRequestField(label, evidence.pull_request, evidence.repository));
2294
2325
  }
2326
+ if (Array.isArray(evidence.changed_paths) && evidence.changed_paths.length) {
2327
+ const field = lifecycleDetailField(t("detail.changed_files"), "");
2328
+ const list = document.createElement("ul");
2329
+ list.className = "lifecycle-detail-modal__changed-paths";
2330
+ for (const path of evidence.changed_paths) {
2331
+ list.append(Object.assign(document.createElement("li"), { textContent: String(path) }));
2332
+ }
2333
+ field.lastElementChild.replaceWith(list);
2334
+ fields.push(field);
2335
+ }
2295
2336
  if (!fields.length) return null;
2296
2337
  const section = document.createElement("section");
2297
2338
  section.className = "lifecycle-detail-modal__implementation-evidence";
@@ -2448,9 +2489,9 @@ function lifecycleStepWithEvidence(step, context = {}) {
2448
2489
  if (reviewers.length) enriched.reviewer_evidence = reviewers;
2449
2490
  }
2450
2491
  const deliverySteps = {
2451
- EXECUTE_AGENT: { role: "implementation", candidate: "implementation_candidate_sha", branch: "implementation_branch", pullRequest: "implementation_pr" },
2452
- FINALIZE_AGENT: { role: "finalization", candidate: "finalization_candidate_sha", branch: "finalization_branch", pullRequest: "finalization_pr" },
2453
- RECONCILE_AGENT: { role: "reconciliation", candidate: "reconciliation_candidate_sha", branch: "reconciliation_branch", pullRequest: "reconciliation_pr" },
2492
+ EXECUTE_AGENT: { role: "implementation", candidate: "implementation_candidate_sha", branch: "implementation_branch", pullRequest: "implementation_pr", changedPaths: "implementation_changed_paths" },
2493
+ FINALIZE_AGENT: { role: "finalization", candidate: "finalization_candidate_sha", branch: "finalization_branch", pullRequest: "finalization_pr", changedPaths: "finalization_changed_paths" },
2494
+ RECONCILE_AGENT: { role: "reconciliation", candidate: "reconciliation_candidate_sha", branch: "reconciliation_branch", pullRequest: "reconciliation_pr", changedPaths: "reconciliation_changed_paths" },
2454
2495
  };
2455
2496
  const delivery = deliverySteps[id];
2456
2497
  if (delivery) {
@@ -2462,6 +2503,11 @@ function lifecycleStepWithEvidence(step, context = {}) {
2462
2503
  evidence.role = delivery.role;
2463
2504
  if (/^[0-9a-f]{40}$/.test(candidate)) evidence.candidate_sha = candidate;
2464
2505
  if (branch) evidence.branch = branch;
2506
+ if (Array.isArray(context[delivery.changedPaths])) {
2507
+ evidence.changed_paths = context[delivery.changedPaths]
2508
+ .map((path) => String(path || "").trim())
2509
+ .filter((path) => path && !path.startsWith("/") && !path.split("/").includes(".."));
2510
+ }
2465
2511
  if (Number.isInteger(pullRequest) && pullRequest > 0) evidence.pull_request = pullRequest;
2466
2512
  if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) evidence.repository = repository;
2467
2513
  if (Object.keys(evidence).length > 1) enriched.delivery_evidence = evidence;
@@ -5970,6 +6016,144 @@ function promptHistoryMarkdownCommitTimeline(entries) {
5970
6016
  });
5971
6017
  return items.length ? `## ${promptHistoryMarkdownText(t("detail.commit_timeline"))}\n\n${items.join("\n")}\n` : "";
5972
6018
  }
6019
+ function promptHistoryMarkdownReviewers(reviewers) {
6020
+ if (!Array.isArray(reviewers) || !reviewers.length) return "";
6021
+ const sections = reviewers.filter((reviewer) => reviewer && typeof reviewer === "object").map((reviewer) => {
6022
+ const status = `${reviewerCapabilityLabel(reviewer.capability || "ENGINEERING")} · ${reviewerStatusLabel(reviewer.status || "completed")}`;
6023
+ return `### ${promptHistoryMarkdownText(reviewerLabel(reviewer.reviewer, t("detail.specialist_review")))}\n\n${promptHistoryMarkdownTable([
6024
+ [t("detail.prompt_status"), status],
6025
+ [t("detail.selected_because"), reviewer.selected_because || t("detail.not_recorded")],
6026
+ [t("detail.initial_observation"), reviewer.contribution],
6027
+ [t("detail.accepted_recommendations"), Number(reviewer.accepted_recommendations) || 0],
6028
+ [t("detail.rejected_recommendations"), Number.isInteger(reviewer.rejected_recommendations) ? reviewer.rejected_recommendations : null],
6029
+ ])}`;
6030
+ });
6031
+ return sections.length ? `## ${promptHistoryMarkdownText(t("detail.specialist_reviews"))}\n\n${sections.join("\n")}` : "";
6032
+ }
6033
+ function promptHistoryMarkdownAssuranceReviews(payload) {
6034
+ const lifecycleReviews = Array.isArray(payload?.lifecycle?.steps)
6035
+ ? payload.lifecycle.steps.find((step) => step?.id === "QUALITY_CONTROL_AGENT")?.assurance_reviews
6036
+ : null;
6037
+ const reviews = Array.isArray(payload?.assurance_reviews) ? payload.assurance_reviews
6038
+ : (Array.isArray(lifecycleReviews) ? lifecycleReviews : []);
6039
+ if (!reviews.length) return "";
6040
+ const qualityStep = Array.isArray(payload?.lifecycle?.steps)
6041
+ ? payload.lifecycle.steps.find((step) => step?.id === "QUALITY_CONTROL_AGENT") : null;
6042
+ const rounds = qualityStep?.repair_rounds || {};
6043
+ const sections = Number.isFinite(Number(rounds.used))
6044
+ ? [t("lifecycle.repair_rounds", { used: rounds.used, maximum: rounds.maximum || 3 }) + "\n"] : [];
6045
+ let currentCandidate = null, waveIndex = -1;
6046
+ for (const review of reviews) {
6047
+ if (!review || typeof review !== "object") continue;
6048
+ const candidate = String(review.candidate_sha || "").trim();
6049
+ const candidateKey = /^[0-9a-f]{40}$/.test(candidate) ? candidate : "unbound";
6050
+ if (candidateKey !== currentCandidate) {
6051
+ currentCandidate = candidateKey; waveIndex += 1;
6052
+ sections.push(`### ${promptHistoryMarkdownText(waveIndex === 0
6053
+ ? t("lifecycle.assurance_initial_wave")
6054
+ : t("lifecycle.assurance_repair_wave", { iteration: waveIndex }))}`);
6055
+ }
6056
+ const findings = Array.isArray(review.findings)
6057
+ ? review.findings.map((finding) => String(finding?.observation || "").trim()).filter(Boolean)
6058
+ : [];
6059
+ const coverage = Array.isArray(review.coverage) ? review.coverage : [];
6060
+ const dispositions = Array.isArray(review.finding_dispositions) ? review.finding_dispositions : [];
6061
+ sections.push(`#### ${promptHistoryMarkdownText(reviewerLabel(review.reviewer, t("detail.specialist_review")))}\n\n${promptHistoryMarkdownTable([
6062
+ [t("detail.prompt_status"), assuranceStatusLabel(review.status || "UNRESOLVED")],
6063
+ [t("detail.candidate_sha"), candidate],
6064
+ [t("detail.recorded_evidence"), findings.length ? findings.join("\n") : t("lifecycle.assurance_no_findings")],
6065
+ [t("detail.audit_evidence"), coverage.length || dispositions.length ? t("lifecycle.assurance_integral_evidence", { coverage: coverage.length, dispositions: dispositions.length }) : null],
6066
+ ])}`);
6067
+ }
6068
+ return sections.length ? `## ${promptHistoryMarkdownText(t("lifecycle.detail_assurance"))}\n\n${sections.join("\n")}` : "";
6069
+ }
6070
+ function promptHistoryMarkdownLifecycle(lifecycle) {
6071
+ if (!lifecycle || lifecycle.available !== true || !Array.isArray(lifecycle.steps)) return "";
6072
+ const steps = lifecycle.steps.filter((step) => step && typeof step === "object").map((step) => {
6073
+ const timing = step.timing && typeof step.timing === "object" ? step.timing : {};
6074
+ const spans = Array.isArray(timing.spans) ? timing.spans : [];
6075
+ const phaseTiming = lifecyclePhaseTiming(spans).map((span) => [
6076
+ t("lifecycle.phase." + String(span.phase || "").toLowerCase(), {}, span.phase),
6077
+ `${Number.isFinite(Number(span.duration_ms)) ? durationText(Number(span.duration_ms) / 1000) : t("format.unavailable")} · ${lifecycleStateLabel(span.outcome)}`,
6078
+ ]);
6079
+ const delivery = step.delivery_evidence || step.implementation_evidence || {};
6080
+ const qualityEvidence = Array.isArray(step.quality_evidence) ? step.quality_evidence : [];
6081
+ const fields = [
6082
+ [t("lifecycle.detail_state"), lifecycleStateLabel(step.state)],
6083
+ [t("lifecycle.detail_started_at"), timing.started_at || step.started_at],
6084
+ [t("lifecycle.detail_finished_at"), timing.finished_at],
6085
+ [t("lifecycle.detail_iterations"), step.iteration_count],
6086
+ [t("workspace.current_branch"), delivery.branch],
6087
+ [t("detail.candidate_sha"), delivery.candidate_sha],
6088
+ [t("detail.changed_files"), Array.isArray(delivery.changed_paths) ? delivery.changed_paths.join("\n") : null],
6089
+ ...qualityEvidence.map((item) => [
6090
+ t("lifecycle.detail_quality_evidence") + " — " + t("lifecycle.quality_evidence." + String(item?.activity || "").toLowerCase(), {}, item?.activity),
6091
+ item?.result,
6092
+ ]),
6093
+ ...phaseTiming,
6094
+ ];
6095
+ return `### ${promptHistoryMarkdownText(lifecycleLabel(step))}\n\n${promptHistoryMarkdownTable(fields)}`;
6096
+ });
6097
+ return steps.length ? `## ${promptHistoryMarkdownText(t("lifecycle.title"))}\n\n${steps.join("\n")}` : "";
6098
+ }
6099
+ function promptHistoryMarkdownRecovery(recovery) {
6100
+ if (recovery?.kind !== "status_reconciliation" || !recovery.run_id) return "";
6101
+ return promptHistoryMarkdownSection(t("status_reconciliation.title"), [
6102
+ [t("detail.run_id"), recovery.run_id],
6103
+ [t("detail.recorded_evidence"), t("status_reconciliation.description")],
6104
+ ]);
6105
+ }
6106
+ function promptHistoryMarkdownRecommendationHandoff(handoff) {
6107
+ if (!handoff || typeof handoff !== "object") return "";
6108
+ const recommendation = handoff.recommendation || {};
6109
+ const alternatives = Array.isArray(handoff.alternatives)
6110
+ ? handoff.alternatives.map((item) => [item.rank, item.title, item.ordering_reason].filter(Boolean).join(" · "))
6111
+ : [];
6112
+ return promptHistoryMarkdownSection(t("detail.recommendation_handoff"), [
6113
+ [t("detail.projection_incomplete"), handoff.projection_status === "INCOMPLETE" ? (handoff.missing_fields || []).join("\n") : null],
6114
+ [t("detail.recommendation_status"), recommendation.status],
6115
+ [t("detail.recommended_next_mission"), recommendation.title],
6116
+ [t("detail.mission_origin"), recommendation.mission_origin],
6117
+ [t("detail.business_value"), recommendation.business_value],
6118
+ [t("detail.confidence"), recommendation.confidence],
6119
+ [t("detail.dependencies"), Array.isArray(recommendation.dependencies) ? recommendation.dependencies.join("\n") : null],
6120
+ [t("detail.evidence"), recommendation.summary],
6121
+ [t("detail.decision_evidence"), recommendation.decision_evidence],
6122
+ [t("detail.artefact_path"), handoff.artifact_path],
6123
+ [t("detail.alternatives"), alternatives.join("\n")],
6124
+ ]);
6125
+ }
6126
+ function promptHistoryMarkdownRepairHistory(payload) {
6127
+ const lifecycle = payload?.lifecycle && typeof payload.lifecycle === "object" ? payload.lifecycle : {};
6128
+ const steps = Array.isArray(lifecycle.steps) ? lifecycle.steps : [];
6129
+ const records = [], seen = new Set();
6130
+ const audits = [
6131
+ ...(Array.isArray(payload?.repair_audit) ? [payload.repair_audit] : []),
6132
+ ...steps.map((step) => Array.isArray(step?.repair_audit) ? step.repair_audit : []),
6133
+ ];
6134
+ for (const audit of audits) {
6135
+ for (const item of audit) {
6136
+ if (!item || typeof item !== "object") continue;
6137
+ const key = String(item.repair_id || [item.iteration, item.commit_sha, item.observed_at].join(":"));
6138
+ if (seen.has(key)) continue;
6139
+ seen.add(key); records.push(item);
6140
+ }
6141
+ }
6142
+ if (!records.length) return "";
6143
+ const rounds = records.map((item, index) => {
6144
+ const iteration = String(item.iteration || index + 1);
6145
+ const outcome = String(item.outcome || "").trim();
6146
+ const table = promptHistoryMarkdownTable([
6147
+ [t("detail.failed_checks"), item.failed_checks],
6148
+ [t("detail.proposed_action"), item.proposed_action],
6149
+ [t("detail.ai_repair_summary"), item.agent_summary],
6150
+ [t("detail.commit"), item.commit_sha === "not_recorded" ? t("detail.not_recorded") : `\`${item.commit_sha}\``],
6151
+ [t("detail.outcome"), t("lifecycle.repair_outcome." + outcome, {}, outcome || t("detail.not_recorded"))],
6152
+ ]);
6153
+ return `### ${promptHistoryMarkdownText(t("lifecycle.assurance_repair_wave", { iteration }))}\n\n${table}`;
6154
+ });
6155
+ return `## ${promptHistoryMarkdownText(t("detail.repair_history"))}\n\n${rounds.join("\n")}`;
6156
+ }
5973
6157
  function promptHistoryDetailMarkdown(payload, title) {
5974
6158
  const history = payload?.history && typeof payload.history === "object" ? payload.history : {};
5975
6159
  const execution = payload?.execution && typeof payload.execution === "object" ? payload.execution : {};
@@ -5980,12 +6164,16 @@ function promptHistoryDetailMarkdown(payload, title) {
5980
6164
  const activity = history.execution_activity_summary && typeof history.execution_activity_summary === "object"
5981
6165
  ? history.execution_activity_summary : null;
5982
6166
  const timestamp = Date.parse(String(history.executed_at || ""));
6167
+ const contextKeysProjectedExplicitly = new Set([
6168
+ "mission_id", "engineering_action_id", "correlation_id", "context_version",
6169
+ ]);
5983
6170
  const sections = [
5984
6171
  promptHistoryMarkdownSection(t("detail.execution"), [
5985
6172
  [t("detail.prompt_title"), history.title || title],
5986
6173
  [t("detail.run_id"), history.run_id || promptHistoryDetailRunId],
5987
6174
  [t("detail.prompt_status"), promptHistoryStatus(history.status)],
5988
6175
  [t("detail.executed_at"), Number.isFinite(timestamp) ? locale.dateTime(new Date(timestamp)) : history.executed_at],
6176
+ [t("detail.dismissed_at"), history.dismissed_at],
5989
6177
  [t("detail.execution_mode"), history.execution_mode],
5990
6178
  [t("detail.operator_handling"), operatorHandlingLabel(history)],
5991
6179
  ...(promptHistoryIsBlocked(history.status)
@@ -6000,6 +6188,12 @@ function promptHistoryDetailMarkdown(payload, title) {
6000
6188
  [t("detail.producer"), history.producer_id],
6001
6189
  [t("detail.producer_type"), history.producer_type ? producerTypeLabel(history.producer_type) : null],
6002
6190
  [t("detail.producer_version"), history.producer_version],
6191
+ [t("detail.producer_submission_contract"), history.producer_submission_contract_version],
6192
+ [t("detail.submission_id"), history.submission_id],
6193
+ [t("execution_context.version"), history.execution_context_version || context.context_version],
6194
+ [t("detail.mission_id"), context.mission_id || history.mission_id],
6195
+ [t("detail.engineering_action_id"), history.engineering_action_id || context.engineering_action_id],
6196
+ [t("detail.correlation_id"), history.correlation_id || context.correlation_id],
6003
6197
  [t("detail.target_repository"), history.target_repository],
6004
6198
  [t("detail.target_branch"), history.target_branch],
6005
6199
  [t("detail.target_checkout"), history.target_checkout_path],
@@ -6008,7 +6202,7 @@ function promptHistoryDetailMarkdown(payload, title) {
6008
6202
  [t("detail.files_created"), metadata.created],
6009
6203
  [t("detail.files_deleted"), metadata.deleted],
6010
6204
  ...Object.entries(context)
6011
- .filter(([key]) => !["execution_phase", "dispatcher_state"].includes(key))
6205
+ .filter(([key]) => !["execution_phase", "dispatcher_state"].includes(key) && !contextKeysProjectedExplicitly.has(key))
6012
6206
  .map(([key, value]) => [promptHistoryMarkdownLabel(key), value]),
6013
6207
  ]),
6014
6208
  promptHistoryMarkdownSection(t("detail.runtime"), [
@@ -6032,10 +6226,17 @@ function promptHistoryDetailMarkdown(payload, title) {
6032
6226
  [t("detail.delivery_target"), activity.terminal_delivery_diff?.terminal_target_sha],
6033
6227
  [t("detail.delivery_paths"), activity.terminal_delivery_diff?.total_unique_changed_paths],
6034
6228
  [t("detail.delivery_renamed"), activity.terminal_delivery_diff?.renamed?.length],
6229
+ [t("detail.delivery_pr_scope"), executionActivityDisplayValue(activity.terminal_delivery_diff?.per_pr_changed_file_counts)],
6035
6230
  ] : [[t("detail.activity_unavailable"), t("detail.activity_unavailable")]]),
6036
6231
  promptHistoryMarkdownSection(t("detail.git_commit"), Object.entries(payload?.commits || {})),
6037
6232
  promptHistoryMarkdownPullRequests(payload?.pull_requests),
6038
6233
  promptHistoryMarkdownCommitTimeline(payload?.commit_timeline),
6234
+ promptHistoryMarkdownLifecycle(payload?.lifecycle),
6235
+ promptHistoryMarkdownRepairHistory(payload),
6236
+ promptHistoryMarkdownReviewers(payload?.reviewers),
6237
+ promptHistoryMarkdownAssuranceReviews(payload),
6238
+ promptHistoryMarkdownRecovery(payload?.lifecycle?.recovery),
6239
+ promptHistoryMarkdownRecommendationHandoff(payload?.recommendation_handoff),
6039
6240
  promptHistoryMarkdownList(t("detail.execution_evidence"), payload?.evidence),
6040
6241
  ].filter(Boolean);
6041
6242
  return [`# ${promptHistoryMarkdownText(history.title || title || promptHistoryDetailRunId)}`, "", t("history.details_description"), "", ...sections].join("\n").trimEnd() + "\n";
@@ -8662,7 +8863,21 @@ function promptDetailReviewersSection(reviewers, { wide = true } = {}) {
8662
8863
  }
8663
8864
  function promptDetailAssuranceReviewsSection(reviews) {
8664
8865
  if (!reviews.length) return null;
8665
- const fields = reviews.map((review) => {
8866
+ const fields = [];
8867
+ let currentCandidate = null, waveIndex = -1;
8868
+ for (const review of reviews) {
8869
+ const candidateKey = /^[0-9a-f]{40}$/.test(String(review?.candidate_sha || ""))
8870
+ ? String(review.candidate_sha) : "unbound";
8871
+ if (candidateKey !== currentCandidate) {
8872
+ currentCandidate = candidateKey;
8873
+ waveIndex += 1;
8874
+ fields.push(Object.assign(document.createElement("h4"), {
8875
+ className: "prompt-detail-assurance-wave-heading",
8876
+ textContent: waveIndex === 0
8877
+ ? t("lifecycle.assurance_initial_wave")
8878
+ : t("lifecycle.assurance_repair_wave", { iteration: waveIndex }),
8879
+ }));
8880
+ }
8666
8881
  const findings = Array.isArray(review.findings) ? review.findings : [];
8667
8882
  const candidate = String(review.candidate_sha || "").trim();
8668
8883
  const field = detailField(
@@ -8682,8 +8897,8 @@ function promptDetailAssuranceReviewsSection(reviews) {
8682
8897
  for (const line of lines) content.append(Object.assign(document.createElement("span"), {
8683
8898
  className: "prompt-detail-assurance-review__line", textContent: line,
8684
8899
  }));
8685
- return field;
8686
- });
8900
+ fields.push(field);
8901
+ }
8687
8902
  return promptDetailCard(
8688
8903
  t("lifecycle.detail_assurance"), fields, true,
8689
8904
  "prompt-detail-card--assurance-reviews",
@@ -3421,6 +3421,16 @@ Object.assign(DASHBOARD_MESSAGES.nl, {"state.QUALITY_CONTROL_AGENT":"Autonome kw
3421
3421
  Object.assign(DASHBOARD_MESSAGES.de, {"state.QUALITY_CONTROL_AGENT":"Autonome Qualitätskontrolle","lifecycle.step.quality_control_agent":"Autonome Qualitätskontrolle"});
3422
3422
  Object.assign(DASHBOARD_MESSAGES.fr, {"state.QUALITY_CONTROL_AGENT":"Contrôle qualité autonome","lifecycle.step.quality_control_agent":"Contrôle qualité autonome"});
3423
3423
  Object.assign(DASHBOARD_MESSAGES.es, {"state.QUALITY_CONTROL_AGENT":"Control de calidad autónomo","lifecycle.step.quality_control_agent":"Control de calidad autónomo"});
3424
+ Object.assign(DASHBOARD_MESSAGES.en, {"state.CAPABILITY_REVIEW":"Specialist review"});
3425
+ Object.assign(DASHBOARD_MESSAGES.nl, {"state.CAPABILITY_REVIEW":"Specialistenreview"});
3426
+ Object.assign(DASHBOARD_MESSAGES.de, {"state.CAPABILITY_REVIEW":"Fachprüfung"});
3427
+ Object.assign(DASHBOARD_MESSAGES.fr, {"state.CAPABILITY_REVIEW":"Revue spécialisée"});
3428
+ Object.assign(DASHBOARD_MESSAGES.es, {"state.CAPABILITY_REVIEW":"Revisión especializada"});
3429
+ Object.assign(DASHBOARD_MESSAGES.en, {"detail.changed_files":"Changed files"});
3430
+ Object.assign(DASHBOARD_MESSAGES.nl, {"detail.changed_files":"Gewijzigde bestanden"});
3431
+ Object.assign(DASHBOARD_MESSAGES.de, {"detail.changed_files":"Geänderte Dateien"});
3432
+ Object.assign(DASHBOARD_MESSAGES.fr, {"detail.changed_files":"Fichiers modifiés"});
3433
+ Object.assign(DASHBOARD_MESSAGES.es, {"detail.changed_files":"Archivos modificados"});
3424
3434
 
3425
3435
  Object.assign(DASHBOARD_MESSAGES.en, {"provider_usage.speed.fast":"Fast","provider_usage.speed.normal_default":"Normal (default)","provider_usage.speed.other":"Other","provider_usage.speed.unknown":"Unknown","provider_usage.authority.authoritative":"Provider-observed","provider_usage.authority.derived":"Derived","provider_usage.authority.unavailable":"Not available"});
3426
3436
  Object.assign(DASHBOARD_MESSAGES.nl, {"provider_usage.speed.fast":"Snel","provider_usage.speed.normal_default":"Normaal (standaard)","provider_usage.speed.other":"Anders","provider_usage.speed.unknown":"Onbekend","provider_usage.authority.authoritative":"Door provider waargenomen","provider_usage.authority.derived":"Afgeleid","provider_usage.authority.unavailable":"Niet beschikbaar"});
@@ -4291,3 +4301,13 @@ Object.assign(DASHBOARD_MESSAGES.nl, {"configuration.timeout_policy_description"
4291
4301
  Object.assign(DASHBOARD_MESSAGES.de, {"configuration.timeout_policy_description":"Fortschrittsabhängige Hostgrenzen pro Provider-Aktion. Konkreter Ausführungsfortschritt setzt die Inaktivitätsgrenze zurück; das absolute Maximum gilt immer.","configuration.timeout_5_max":"maximal 5 Min.","configuration.timeout_10_idle_30_max":"10 Min. ohne Fortschritt · maximal 30 Min.","configuration.timeout_15_idle_45_max":"15 Min. ohne Fortschritt · maximal 45 Min."});
4292
4302
  Object.assign(DASHBOARD_MESSAGES.fr, {"configuration.timeout_policy_description":"Limites hôte sensibles à la progression pour chaque action fournisseur. Une progression concrète réinitialise la limite d’inactivité ; le maximum absolu reste applicable.","configuration.timeout_5_max":"5 min maximum","configuration.timeout_10_idle_30_max":"10 min sans progression · 30 min maximum","configuration.timeout_15_idle_45_max":"15 min sans progression · 45 min maximum"});
4293
4303
  Object.assign(DASHBOARD_MESSAGES.es, {"configuration.timeout_policy_description":"Límites del host sensibles al progreso para cada acción del proveedor. El progreso concreto restablece el límite de inactividad; el máximo absoluto siempre se aplica.","configuration.timeout_5_max":"máximo 5 min","configuration.timeout_10_idle_30_max":"10 min sin progreso · máximo 30 min","configuration.timeout_15_idle_45_max":"15 min sin progreso · máximo 45 min"});
4304
+ Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.assurance_progress_active":"Reviews in progress: {completed} of {total} completed · {reviewer} active","lifecycle.assurance_progress_waiting":"Reviews in progress: {completed} of {total} completed"});
4305
+ Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.assurance_progress_active":"Reviews bezig: {completed} van {total} afgerond · {reviewer} actief","lifecycle.assurance_progress_waiting":"Reviews bezig: {completed} van {total} afgerond"});
4306
+ Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.assurance_progress_active":"Prüfungen laufen: {completed} von {total} abgeschlossen · {reviewer} aktiv","lifecycle.assurance_progress_waiting":"Prüfungen laufen: {completed} von {total} abgeschlossen"});
4307
+ Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.assurance_progress_active":"Revues en cours : {completed} sur {total} terminées · {reviewer} active","lifecycle.assurance_progress_waiting":"Revues en cours : {completed} sur {total} terminées"});
4308
+ Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.assurance_progress_active":"Revisiones en curso: {completed} de {total} completadas · {reviewer} activa","lifecycle.assurance_progress_waiting":"Revisiones en curso: {completed} de {total} completadas"});
4309
+ Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.assurance_initial_wave":"Initial assessment","lifecycle.assurance_repair_wave":"Repair round {iteration}"});
4310
+ Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.assurance_initial_wave":"Initiële beoordeling","lifecycle.assurance_repair_wave":"Herstelronde {iteration}"});
4311
+ Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.assurance_initial_wave":"Erstbewertung","lifecycle.assurance_repair_wave":"Reparaturrunde {iteration}"});
4312
+ Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.assurance_initial_wave":"Évaluation initiale","lifecycle.assurance_repair_wave":"Cycle de correction {iteration}"});
4313
+ Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.assurance_initial_wave":"Evaluación inicial","lifecycle.assurance_repair_wave":"Ronda de reparación {iteration}"});