engineering-platform 2.3.98__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.98 → engineering_platform-2.3.101}/PKG-INFO +1 -1
  2. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/pyproject.toml +1 -1
  3. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
  4. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
  5. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/agent_state.py +46 -6
  6. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard.css +4 -0
  7. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard.js +263 -22
  8. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_locales.mjs +20 -0
  9. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/capability_review.py +8 -1
  10. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_executor.py +47 -26
  11. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_host.py +79 -9
  12. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_lifecycle.py +3 -0
  13. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/platform_version.py +1 -1
  14. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/report_analysis.py +12 -1
  15. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/reviewer_evidence.py +9 -1
  16. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/server_console_services.py +8 -0
  17. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/templates/workspace-config.json +1 -1
  18. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/PKG-INFO +1 -1
  19. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/README.md +0 -0
  20. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/setup.cfg +0 -0
  21. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/__init__.py +0 -0
  22. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/__main__.py +0 -0
  23. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/agent_trust.py +0 -0
  24. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  25. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
  26. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  27. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  28. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  29. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  30. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  31. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  32. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/assurance_scope.py +0 -0
  33. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/capability_preflight.py +0 -0
  34. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/central_data_transfer.py +0 -0
  35. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/central_database.py +0 -0
  36. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/central_operational_reset.py +0 -0
  37. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/central_store_migration.py +0 -0
  38. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/codex_capacity.py +0 -0
  39. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/codex_chat.py +0 -0
  40. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/codex_observability.py +0 -0
  41. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/component_lock.py +0 -0
  42. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/component_logging.py +0 -0
  43. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/console_presentation.py +0 -0
  44. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/console_route_ownership.py +0 -0
  45. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/contracts/__init__.py +0 -0
  46. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  47. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/contracts/models.py +0 -0
  48. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/contracts/projection.py +0 -0
  49. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_browser_validation.py +0 -0
  50. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_state.py +0 -0
  51. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  52. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/dashboard_translation.py +0 -0
  53. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/dependabot_producer.py +0 -0
  54. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/development_profile.py +0 -0
  55. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/drift_diagnostics.py +0 -0
  56. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/emergency_recovery.py +0 -0
  57. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/engineering_memory.py +0 -0
  58. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  59. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/evidence_projection.py +0 -0
  60. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_activity.py +0 -0
  61. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_context.py +0 -0
  62. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_errors.py +0 -0
  63. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_evidence.py +0 -0
  64. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_finalization.py +0 -0
  65. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_host_evidence.py +0 -0
  66. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_lease.py +0 -0
  67. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_models.py +0 -0
  68. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_readiness.py +0 -0
  69. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_reporting.py +0 -0
  70. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_repository.py +0 -0
  71. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_timeout_policy.py +0 -0
  72. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_timing.py +0 -0
  73. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/execution_transaction.py +0 -0
  74. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/external_producer_binding.py +0 -0
  75. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/file_inbox.py +0 -0
  76. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/forensic_attribution.py +0 -0
  77. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  78. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/forensic_delta.py +0 -0
  79. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/golden_scenario.py +0 -0
  80. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  81. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/host_admin.py +0 -0
  82. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/host_preflight.py +0 -0
  83. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_relocation.py +0 -0
  84. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_activation.py +0 -0
  85. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_admission.py +0 -0
  86. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_backup.py +0 -0
  87. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_composition.py +0 -0
  88. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_executor.py +0 -0
  89. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_migration.py +0 -0
  90. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_operation.py +0 -0
  91. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_plan.py +0 -0
  92. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/installation_update_preparation.py +0 -0
  93. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/investigation_ledger.py +0 -0
  94. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  95. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/legacy_installation_adoption.py +0 -0
  96. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/lifecycle_worker.py +0 -0
  97. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/live_status.py +0 -0
  98. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/local_api.py +0 -0
  99. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/local_api_keychain.py +0 -0
  100. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/local_repository_binding.py +0 -0
  101. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/managed_autonomy.py +0 -0
  102. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/managed_codex_runtime.py +0 -0
  103. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/managed_workspace_readiness.py +0 -0
  104. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/managed_workspace_recovery.py +0 -0
  105. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/merge_delegation.py +0 -0
  106. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation.py +0 -0
  107. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation_lock.py +0 -0
  108. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/operational_installation_record.py +0 -0
  109. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/owner_credential_recovery.py +0 -0
  110. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/parity_context.py +0 -0
  111. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
  112. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/platform_admin.py +0 -0
  113. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/platform_api.py +0 -0
  114. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/platform_bootstrap.py +0 -0
  115. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/platform_components.py +0 -0
  116. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/pr_check_repair.py +0 -0
  117. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  118. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/producer.py +0 -0
  119. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/product_installation_readback.py +0 -0
  120. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/project_agent.py +0 -0
  121. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/project_agent_service.py +0 -0
  122. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/project_topology.py +0 -0
  123. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/prompt_history.py +0 -0
  124. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_context.py +0 -0
  125. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_context_benchmark.py +0 -0
  126. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_context_scope.py +0 -0
  127. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_interruption.py +0 -0
  128. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_process_identity.py +0 -0
  129. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_readiness.py +0 -0
  130. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_recovery.py +0 -0
  131. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/provider_usage.py +0 -0
  132. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/providers.py +0 -0
  133. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/qualification.py +0 -0
  134. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/qualification_runtime.py +0 -0
  135. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/recommendation_handoff.py +0 -0
  136. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/reconciliation_adoption.py +0 -0
  137. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/release_operation.py +0 -0
  138. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/repository_attachment.py +0 -0
  139. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/repository_handoff.py +0 -0
  140. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/resources.py +0 -0
  141. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/revision_binding.py +0 -0
  142. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
  143. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +0 -0
  144. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  145. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  146. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/server.py +0 -0
  147. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/server_relay.py +0 -0
  148. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/server_service.py +0 -0
  149. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/status_model.py +0 -0
  150. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/status_reconciliation.py +0 -0
  151. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/storage.py +0 -0
  152. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/submission_cli.py +0 -0
  153. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/submission_intake.py +0 -0
  154. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/submission_service.py +0 -0
  155. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/system_installation_topology.py +0 -0
  156. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/system_server_service.py +0 -0
  157. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/telemetry.py +0 -0
  158. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_contract.py +0 -0
  159. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_export.py +0 -0
  160. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/telemetry_metrics.py +0 -0
  161. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
  162. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/validation_identity.py +0 -0
  163. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/validation_profile.py +0 -0
  164. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/version_preparation_delivery.py +0 -0
  165. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/workspace_preflight.py +0 -0
  166. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/worktree_provenance.py +0 -0
  167. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform/worktree_tooling.py +0 -0
  168. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
  169. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  170. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  171. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/src/engineering_platform.egg-info/top_level.txt +0 -0
  172. {engineering_platform-2.3.98 → engineering_platform-2.3.101}/tests/test_adaptive_action_sizing_design.py +0 -0
  173. {engineering_platform-2.3.98 → 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.98
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.98"
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.98",
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.98",
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.98",
9
+ "platform_version": "2.3.101",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.98",
11
+ "runner_version": "2.3.101",
12
12
  "status_model": 1,
13
13
  "storage_schema": 45,
14
- "watcher_version": "2.3.98"
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"}
@@ -490,7 +530,7 @@ class TransactionState:
490
530
  or not isinstance(review.get("completed_at"), str)
491
531
  ))
492
532
  or (set(review) == integral_review_fields and (
493
- review.get("contract_version") != "2.0"
533
+ review.get("contract_version") not in {"2.0", "3.0"}
494
534
  or not isinstance(review.get("started_at"), str)
495
535
  or not isinstance(review.get("completed_at"), str)
496
536
  or not isinstance(review.get("coverage"), list)
@@ -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
+ .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}
283
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}
284
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}
285
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}
@@ -1342,3 +1344,5 @@ html[data-theme="light"] :is(.dashboard-status-banner--provider-auth_required .p
1342
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}}
1343
1345
  /* Status markers inside lifecycle assurance evidence mirror the main status language. */
1344
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}
@@ -144,6 +144,32 @@ function assuranceStatusLabel(value, fallback = t("format.not_available")) {
144
144
  if (!raw) return fallback;
145
145
  return t(`lifecycle.assurance_status.${reviewerKey(raw)}`, {}, raw);
146
146
  }
147
+ function assuranceStatusPresentation(value) {
148
+ const status = String(value || "UNRESOLVED").toUpperCase();
149
+ const passed = status === "PASS", failed = ["FAIL", "FAILED", "UNRESOLVED"].includes(status);
150
+ return {
151
+ glyph: passed ? "✓" : failed ? "×" : "•",
152
+ label: assuranceStatusLabel(status, status),
153
+ tone: passed ? "passed" : failed ? "failed" : "neutral",
154
+ };
155
+ }
156
+ function assuranceStatusIcon(presentation) {
157
+ const icon = document.createElement("span");
158
+ icon.className = "assurance-review-status__icon assurance-review-status__icon--" + presentation.tone
159
+ + " lifecycle-detail-modal__assurance-status lifecycle-detail-modal__assurance-status--" + presentation.tone;
160
+ icon.setAttribute("aria-hidden", "true");
161
+ icon.textContent = presentation.glyph;
162
+ return icon;
163
+ }
164
+ function assuranceStatusRow(value) {
165
+ const presentation = assuranceStatusPresentation(value), row = document.createElement("span"),
166
+ text = document.createElement("span");
167
+ row.className = "assurance-review-status";
168
+ text.className = "assurance-review-status__text";
169
+ text.textContent = presentation.label;
170
+ row.append(assuranceStatusIcon(presentation), text);
171
+ return row;
172
+ }
147
173
  function reviewerCapabilityLabel(value, fallback = t("format.not_available")) {
148
174
  const raw = String(value || "").trim();
149
175
  return raw ? enumLabel(raw.toUpperCase(), raw) : fallback;
@@ -2152,7 +2178,8 @@ function lifecycleQualityEvidence(step) {
2152
2178
  }
2153
2179
  function lifecycleAssuranceEvidence(step) {
2154
2180
  const reviews = Array.isArray(step?.assurance_reviews) ? step.assurance_reviews : [];
2155
- 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;
2156
2183
  const section = document.createElement("section");
2157
2184
  section.className = "lifecycle-detail-modal__quality-evidence lifecycle-detail-modal__assurance-evidence";
2158
2185
  const rounds = step?.repair_rounds || {};
@@ -2160,23 +2187,47 @@ function lifecycleAssuranceEvidence(step) {
2160
2187
  if (Number.isFinite(Number(rounds.used))) section.append(Object.assign(document.createElement("p"), {
2161
2188
  className: "estimate-meta", textContent: t("lifecycle.repair_rounds", { used: rounds.used, maximum: rounds.maximum || 3 }),
2162
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
+ }
2163
2207
  const list = document.createElement("ol"); list.className = "lifecycle-detail-modal__phase-list";
2164
2208
  const dynamicRows = [];
2209
+ let currentCandidate = null, waveIndex = -1;
2165
2210
  for (const review of reviews) {
2166
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
+ }
2167
2224
  const findings = Array.isArray(review.findings) ? review.findings : [];
2168
2225
  const item = document.createElement("li"), heading = document.createElement("strong"),
2169
- statusIcon = document.createElement("span"), status = String(review.status || "UNRESOLVED"),
2170
- normalizedStatus = status.toUpperCase();
2226
+ status = String(review.status || "UNRESOLVED"), statusPresentation = assuranceStatusPresentation(status);
2171
2227
  const role = String(review.reviewer || "");
2172
- const passed = normalizedStatus === "PASS", failed = ["FAIL", "FAILED", "UNRESOLVED"].includes(normalizedStatus);
2173
2228
  heading.className = "lifecycle-detail-modal__assurance-heading";
2174
- statusIcon.className = "lifecycle-detail-modal__assurance-status lifecycle-detail-modal__assurance-status--"
2175
- + (passed ? "passed" : failed ? "failed" : "neutral");
2176
- statusIcon.setAttribute("aria-hidden", "true");
2177
- statusIcon.textContent = passed ? "✓" : failed ? "×" : "•";
2178
- heading.append(statusIcon, Object.assign(document.createElement("span"), {
2179
- textContent: `${reviewerLabel(role, role)} · ${assuranceStatusLabel(status, status)}`,
2229
+ heading.append(assuranceStatusIcon(statusPresentation), Object.assign(document.createElement("span"), {
2230
+ textContent: `${reviewerLabel(role, role)} · ${statusPresentation.label}`,
2180
2231
  }));
2181
2232
  item.append(heading);
2182
2233
  const summary = findings.map((finding) => String(finding?.observation || "").trim()).filter(Boolean).join("; ");
@@ -2272,6 +2323,16 @@ function lifecycleDeliveryEvidence(step) {
2272
2323
  const label = t(pullRequestLabels[role] || pullRequestLabels.implementation);
2273
2324
  fields.push(lifecyclePullRequestField(label, evidence.pull_request, evidence.repository));
2274
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
+ }
2275
2336
  if (!fields.length) return null;
2276
2337
  const section = document.createElement("section");
2277
2338
  section.className = "lifecycle-detail-modal__implementation-evidence";
@@ -2428,9 +2489,9 @@ function lifecycleStepWithEvidence(step, context = {}) {
2428
2489
  if (reviewers.length) enriched.reviewer_evidence = reviewers;
2429
2490
  }
2430
2491
  const deliverySteps = {
2431
- EXECUTE_AGENT: { role: "implementation", candidate: "implementation_candidate_sha", branch: "implementation_branch", pullRequest: "implementation_pr" },
2432
- FINALIZE_AGENT: { role: "finalization", candidate: "finalization_candidate_sha", branch: "finalization_branch", pullRequest: "finalization_pr" },
2433
- 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" },
2434
2495
  };
2435
2496
  const delivery = deliverySteps[id];
2436
2497
  if (delivery) {
@@ -2442,6 +2503,11 @@ function lifecycleStepWithEvidence(step, context = {}) {
2442
2503
  evidence.role = delivery.role;
2443
2504
  if (/^[0-9a-f]{40}$/.test(candidate)) evidence.candidate_sha = candidate;
2444
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
+ }
2445
2511
  if (Number.isInteger(pullRequest) && pullRequest > 0) evidence.pull_request = pullRequest;
2446
2512
  if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) evidence.repository = repository;
2447
2513
  if (Object.keys(evidence).length > 1) enriched.delivery_evidence = evidence;
@@ -5950,6 +6016,144 @@ function promptHistoryMarkdownCommitTimeline(entries) {
5950
6016
  });
5951
6017
  return items.length ? `## ${promptHistoryMarkdownText(t("detail.commit_timeline"))}\n\n${items.join("\n")}\n` : "";
5952
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
+ }
5953
6157
  function promptHistoryDetailMarkdown(payload, title) {
5954
6158
  const history = payload?.history && typeof payload.history === "object" ? payload.history : {};
5955
6159
  const execution = payload?.execution && typeof payload.execution === "object" ? payload.execution : {};
@@ -5960,12 +6164,16 @@ function promptHistoryDetailMarkdown(payload, title) {
5960
6164
  const activity = history.execution_activity_summary && typeof history.execution_activity_summary === "object"
5961
6165
  ? history.execution_activity_summary : null;
5962
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
+ ]);
5963
6170
  const sections = [
5964
6171
  promptHistoryMarkdownSection(t("detail.execution"), [
5965
6172
  [t("detail.prompt_title"), history.title || title],
5966
6173
  [t("detail.run_id"), history.run_id || promptHistoryDetailRunId],
5967
6174
  [t("detail.prompt_status"), promptHistoryStatus(history.status)],
5968
6175
  [t("detail.executed_at"), Number.isFinite(timestamp) ? locale.dateTime(new Date(timestamp)) : history.executed_at],
6176
+ [t("detail.dismissed_at"), history.dismissed_at],
5969
6177
  [t("detail.execution_mode"), history.execution_mode],
5970
6178
  [t("detail.operator_handling"), operatorHandlingLabel(history)],
5971
6179
  ...(promptHistoryIsBlocked(history.status)
@@ -5980,6 +6188,12 @@ function promptHistoryDetailMarkdown(payload, title) {
5980
6188
  [t("detail.producer"), history.producer_id],
5981
6189
  [t("detail.producer_type"), history.producer_type ? producerTypeLabel(history.producer_type) : null],
5982
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],
5983
6197
  [t("detail.target_repository"), history.target_repository],
5984
6198
  [t("detail.target_branch"), history.target_branch],
5985
6199
  [t("detail.target_checkout"), history.target_checkout_path],
@@ -5988,7 +6202,7 @@ function promptHistoryDetailMarkdown(payload, title) {
5988
6202
  [t("detail.files_created"), metadata.created],
5989
6203
  [t("detail.files_deleted"), metadata.deleted],
5990
6204
  ...Object.entries(context)
5991
- .filter(([key]) => !["execution_phase", "dispatcher_state"].includes(key))
6205
+ .filter(([key]) => !["execution_phase", "dispatcher_state"].includes(key) && !contextKeysProjectedExplicitly.has(key))
5992
6206
  .map(([key, value]) => [promptHistoryMarkdownLabel(key), value]),
5993
6207
  ]),
5994
6208
  promptHistoryMarkdownSection(t("detail.runtime"), [
@@ -6012,10 +6226,17 @@ function promptHistoryDetailMarkdown(payload, title) {
6012
6226
  [t("detail.delivery_target"), activity.terminal_delivery_diff?.terminal_target_sha],
6013
6227
  [t("detail.delivery_paths"), activity.terminal_delivery_diff?.total_unique_changed_paths],
6014
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)],
6015
6230
  ] : [[t("detail.activity_unavailable"), t("detail.activity_unavailable")]]),
6016
6231
  promptHistoryMarkdownSection(t("detail.git_commit"), Object.entries(payload?.commits || {})),
6017
6232
  promptHistoryMarkdownPullRequests(payload?.pull_requests),
6018
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),
6019
6240
  promptHistoryMarkdownList(t("detail.execution_evidence"), payload?.evidence),
6020
6241
  ].filter(Boolean);
6021
6242
  return [`# ${promptHistoryMarkdownText(history.title || title || promptHistoryDetailRunId)}`, "", t("history.details_description"), "", ...sections].join("\n").trimEnd() + "\n";
@@ -8642,22 +8863,42 @@ function promptDetailReviewersSection(reviewers, { wide = true } = {}) {
8642
8863
  }
8643
8864
  function promptDetailAssuranceReviewsSection(reviews) {
8644
8865
  if (!reviews.length) return null;
8645
- 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
+ }
8646
8881
  const findings = Array.isArray(review.findings) ? review.findings : [];
8647
8882
  const candidate = String(review.candidate_sha || "").trim();
8883
+ const field = detailField(
8884
+ reviewerLabel(review.reviewer, t("detail.specialist_review")),
8885
+ "",
8886
+ true,
8887
+ );
8888
+ const content = field.lastElementChild;
8889
+ content.className = "prompt-detail-assurance-review__content";
8890
+ content.replaceChildren(assuranceStatusRow(review.status || "UNRESOLVED"));
8648
8891
  const lines = [
8649
- assuranceStatusLabel(review.status || "UNRESOLVED"),
8650
8892
  candidate ? t("detail.candidate_sha") + ": " + candidate : null,
8651
8893
  ...(findings.length
8652
8894
  ? findings.map((finding) => String(finding?.observation || "").trim()).filter(Boolean)
8653
8895
  : [t("lifecycle.assurance_no_findings")]),
8654
8896
  ].filter(Boolean);
8655
- return detailField(
8656
- reviewerLabel(review.reviewer, t("detail.specialist_review")),
8657
- lines.join("\n"),
8658
- true,
8659
- );
8660
- });
8897
+ for (const line of lines) content.append(Object.assign(document.createElement("span"), {
8898
+ className: "prompt-detail-assurance-review__line", textContent: line,
8899
+ }));
8900
+ fields.push(field);
8901
+ }
8661
8902
  return promptDetailCard(
8662
8903
  t("lifecycle.detail_assurance"), fields, true,
8663
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}"});