engineering-platform 2.3.0__tar.gz → 2.3.58__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 (162) hide show
  1. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/PKG-INFO +2 -2
  2. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/pyproject.toml +2 -2
  3. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +10 -3
  4. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +5 -5
  5. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/agent_state.py +95 -8
  6. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/dashboard.css +9 -4
  7. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/dashboard.js +639 -220
  8. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/dashboard_locales.mjs +83 -14
  9. engineering_platform-2.3.58/src/engineering_platform/assets/dashboard_translation.mjs +192 -0
  10. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/central_data_transfer.py +2 -1
  11. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/central_database.py +19 -15
  12. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/central_store_migration.py +16 -9
  13. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/codex_chat.py +56 -38
  14. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/component_logging.py +281 -13
  15. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/console_route_ownership.py +11 -2
  16. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/contracts/projection.py +38 -51
  17. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/dashboard_browser_validation.py +4 -1
  18. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/dashboard_translation.py +36 -18
  19. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/dependabot_producer.py +11 -3
  20. engineering_platform-2.3.58/src/engineering_platform/development_profile.py +344 -0
  21. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/evidence_projection.py +20 -2
  22. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_executor.py +45 -2
  23. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_host.py +465 -46
  24. engineering_platform-2.3.58/src/engineering_platform/execution_host_evidence.py +167 -0
  25. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_lease.py +57 -11
  26. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_lifecycle.py +45 -5
  27. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_timing.py +3 -1
  28. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/host_admin.py +8 -3
  29. engineering_platform-2.3.58/src/engineering_platform/installation_update_activation.py +125 -0
  30. engineering_platform-2.3.58/src/engineering_platform/installation_update_admission.py +479 -0
  31. engineering_platform-2.3.58/src/engineering_platform/installation_update_backup.py +56 -0
  32. engineering_platform-2.3.58/src/engineering_platform/installation_update_composition.py +326 -0
  33. engineering_platform-2.3.58/src/engineering_platform/installation_update_executor.py +192 -0
  34. engineering_platform-2.3.58/src/engineering_platform/installation_update_migration.py +62 -0
  35. engineering_platform-2.3.58/src/engineering_platform/installation_update_operation.py +683 -0
  36. engineering_platform-2.3.58/src/engineering_platform/installation_update_plan.py +136 -0
  37. engineering_platform-2.3.58/src/engineering_platform/installation_update_preparation.py +532 -0
  38. engineering_platform-2.3.58/src/engineering_platform/legacy_installation_adoption.py +384 -0
  39. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/lifecycle_worker.py +53 -5
  40. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/managed_autonomy.py +17 -1
  41. engineering_platform-2.3.58/src/engineering_platform/operational_installation.py +409 -0
  42. engineering_platform-2.3.58/src/engineering_platform/operational_installation_lock.py +51 -0
  43. engineering_platform-2.3.58/src/engineering_platform/operational_installation_record.py +181 -0
  44. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/parity_context.py +46 -1
  45. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/parity_lifecycle_dispatcher.py +395 -43
  46. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/platform_bootstrap.py +3 -2
  47. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/platform_version.py +1 -1
  48. engineering_platform-2.3.58/src/engineering_platform/product_installation_readback.py +567 -0
  49. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/prompt_history.py +2 -2
  50. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_interruption.py +15 -7
  51. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_readiness.py +7 -6
  52. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/providers.py +274 -5
  53. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/qualification_runtime.py +48 -13
  54. engineering_platform-2.3.58/src/engineering_platform/release_operation.py +313 -0
  55. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/report_analysis.py +43 -10
  56. engineering_platform-2.3.58/src/engineering_platform/revision_binding.py +39 -0
  57. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +13 -1
  58. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/server.py +3224 -300
  59. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/server_console_services.py +4 -4
  60. engineering_platform-2.3.58/src/engineering_platform/server_service.py +398 -0
  61. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/storage.py +470 -72
  62. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/submission_service.py +487 -27
  63. engineering_platform-2.3.58/src/engineering_platform/system_installation_topology.py +596 -0
  64. engineering_platform-2.3.58/src/engineering_platform/system_server_service.py +607 -0
  65. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/templates/workspace-config.json +18 -4
  66. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/validation_profile.py +196 -7
  67. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform.egg-info/PKG-INFO +2 -2
  68. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform.egg-info/SOURCES.txt +24 -1
  69. engineering_platform-2.3.58/tests/test_adaptive_action_sizing_design.py +119 -0
  70. engineering_platform-2.3.58/tests/test_role_task_model_policy_design.py +141 -0
  71. engineering_platform-2.3.0/src/engineering_platform/server_service.py +0 -161
  72. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/README.md +0 -0
  73. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/setup.cfg +0 -0
  74. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/__init__.py +0 -0
  75. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/__main__.py +0 -0
  76. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/agent_trust.py +0 -0
  77. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  78. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  79. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  80. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  81. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  82. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  83. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  84. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/capability_preflight.py +0 -0
  85. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/capability_review.py +0 -0
  86. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/codex_capacity.py +0 -0
  87. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/codex_observability.py +0 -0
  88. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/component_lock.py +0 -0
  89. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/console_presentation.py +0 -0
  90. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/contracts/__init__.py +0 -0
  91. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  92. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/contracts/models.py +0 -0
  93. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/dashboard_state.py +0 -0
  94. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  95. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/drift_diagnostics.py +0 -0
  96. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/emergency_recovery.py +0 -0
  97. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/engineering_memory.py +0 -0
  98. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  99. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_activity.py +0 -0
  100. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_context.py +0 -0
  101. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_errors.py +0 -0
  102. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_evidence.py +0 -0
  103. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_finalization.py +0 -0
  104. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_models.py +0 -0
  105. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_readiness.py +0 -0
  106. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_reporting.py +0 -0
  107. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_repository.py +0 -0
  108. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_timeout_policy.py +0 -0
  109. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/execution_transaction.py +0 -0
  110. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/external_producer_binding.py +0 -0
  111. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/file_inbox.py +0 -0
  112. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/forensic_attribution.py +0 -0
  113. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  114. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/forensic_delta.py +0 -0
  115. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/golden_scenario.py +0 -0
  116. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  117. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/host_preflight.py +0 -0
  118. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/installation_relocation.py +0 -0
  119. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/investigation_ledger.py +0 -0
  120. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  121. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/live_status.py +0 -0
  122. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/local_api.py +0 -0
  123. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/local_api_keychain.py +0 -0
  124. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/local_repository_binding.py +0 -0
  125. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/managed_codex_runtime.py +0 -0
  126. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/platform_admin.py +0 -0
  127. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/platform_api.py +0 -0
  128. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/platform_components.py +0 -0
  129. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/pr_check_repair.py +0 -0
  130. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  131. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/producer.py +0 -0
  132. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/project_agent.py +0 -0
  133. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/project_agent_service.py +0 -0
  134. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/project_topology.py +0 -0
  135. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_context.py +0 -0
  136. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_context_benchmark.py +0 -0
  137. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_context_scope.py +0 -0
  138. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_process_identity.py +0 -0
  139. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_recovery.py +0 -0
  140. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/provider_usage.py +0 -0
  141. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/qualification.py +0 -0
  142. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/recommendation_handoff.py +0 -0
  143. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/repository_attachment.py +0 -0
  144. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/repository_handoff.py +0 -0
  145. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/resources.py +0 -0
  146. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/reviewer_evidence.py +0 -0
  147. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  148. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  149. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/server_relay.py +0 -0
  150. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/status_model.py +0 -0
  151. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/status_reconciliation.py +0 -0
  152. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/submission_cli.py +0 -0
  153. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/submission_intake.py +0 -0
  154. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/telemetry.py +0 -0
  155. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/validation_identity.py +0 -0
  156. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/version_preparation_delivery.py +0 -0
  157. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/workspace_preflight.py +0 -0
  158. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/worktree_provenance.py +0 -0
  159. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform/worktree_tooling.py +0 -0
  160. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  161. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  162. {engineering_platform-2.3.0 → engineering_platform-2.3.58}/src/engineering_platform.egg-info/top_level.txt +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-platform
3
- Version: 2.3.0
3
+ Version: 2.3.58
4
4
  Summary: Local-first Engineering Platform execution operations runtime
5
5
  Author: Peter van Tol
6
6
  License: MIT
7
- Requires-Python: >=3.11
7
+ Requires-Python: <3.15,>=3.14
8
8
  Description-Content-Type: text/markdown
9
9
 
10
10
  # Engineering Platform
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "engineering-platform"
7
- version = "2.3.0"
7
+ version = "2.3.58"
8
8
  description = "Local-first Engineering Platform execution operations runtime"
9
9
  readme = "README.md"
10
- requires-python = ">=3.11"
10
+ requires-python = ">=3.14,<3.15"
11
11
  license = {text = "MIT"}
12
12
  authors = [{name = "Peter van Tol"}]
13
13
  dependencies = []
@@ -3,7 +3,7 @@
3
3
  "platform": {
4
4
  "id": "engineering-platform",
5
5
  "name": "Engineering Platform",
6
- "version": "2.3.0",
6
+ "version": "2.3.58",
7
7
  "generation": 2,
8
8
  "documentation_namespace": "engineering-platform",
9
9
  "capability_registry_version": 1
@@ -11,8 +11,15 @@
11
11
  "workspace": {
12
12
  "id": "engineering-platform",
13
13
  "name": "Engineering Platform",
14
- "repository": {"provider": "github", "owner": "pcvantol", "name": "engineering-platform", "default_branch": "main"},
15
- "branding": {"dashboard_title": "EP Operations"},
14
+ "repository": {
15
+ "provider": "github",
16
+ "owner": "pcvantol",
17
+ "name": "engineering-platform",
18
+ "default_branch": "main"
19
+ },
20
+ "branding": {
21
+ "dashboard_title": "EP Operations"
22
+ },
16
23
  "workspace_authorization": {
17
24
  "allowed_roots": [],
18
25
  "allowed_repositories": [],
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "bootstrap_contract": "2026.12",
3
3
  "checkpoint_format": 1,
4
- "dashboard_version": "2.3.0",
4
+ "dashboard_version": "2.3.58",
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.0",
9
+ "platform_version": "2.3.58",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.0",
11
+ "runner_version": "2.3.58",
12
12
  "status_model": 1,
13
- "storage_schema": 41,
14
- "watcher_version": "2.3.0"
13
+ "storage_schema": 44,
14
+ "watcher_version": "2.3.58"
15
15
  }
@@ -4,11 +4,13 @@ from __future__ import annotations
4
4
 
5
5
  from dataclasses import asdict, dataclass
6
6
  import json
7
+ import logging
7
8
  import os
8
9
  from pathlib import Path
9
10
  import re
10
11
  import sqlite3
11
12
  import tempfile
13
+ from time import sleep
12
14
 
13
15
  from .storage import (
14
16
  CENTRAL_OPERATIONAL_DATABASE_ENVIRONMENT,
@@ -21,6 +23,7 @@ SCHEMA_VERSION = 1
21
23
  PHASES = frozenset({"INITIALIZE", "CAPABILITY_REVIEW", "EXECUTE_AGENT", "LOCAL_REPOSITORY_VALIDATION", "QUALITY_CONTROL_AGENT", "REPAIR_AGENT", "FINALIZE_AGENT", "RECONCILE_AGENT", "WAIT_FOR_TERMINAL_EVIDENCE", "WAIT_FOR_OPERATOR_MERGE", "REPOSITORY_CLEANUP", "COMPLETE", "BLOCKED", "FAILED"})
22
24
  RUN_ID_PATTERN = re.compile(r"^[a-z0-9][a-z0-9-]{0,63}$")
23
25
  MAX_DIAGNOSTIC_LENGTH = 500
26
+ _TRANSIENT_CHECKPOINT_DELAYS = (0.02,)
24
27
  MAX_COMMIT_EVIDENCE_RECORDS = 48
25
28
  COMMIT_EVIDENCE_FIELDS = frozenset({"phase", "observed_at", "commit_sha", "description"})
26
29
  COMMIT_EVIDENCE_TIMESTAMP_PATTERN = re.compile(
@@ -46,6 +49,7 @@ COMMIT_EVIDENCE_DESCRIPTIONS = frozenset({
46
49
  "implementation_merge_verified",
47
50
  "finalization_merge_verified",
48
51
  "reconciliation_merge_verified",
52
+ "managed_noop_repository_reconciled",
49
53
  })
50
54
  SENSITIVE_DIAGNOSTIC_PATTERN = re.compile(
51
55
  r"(?i)\b(api[_ -]?key|oauth|access[_ -]?token|refresh[_ -]?token|secret|cookie|authorization|password)\b\s*[:=]\s*\S+|\bbearer\s+\S+|\b[A-Z][A-Z0-9_]{2,}\s*=\s*\S+"
@@ -112,6 +116,12 @@ class TransactionState:
112
116
  branch: str | None = None
113
117
  pull_request: int | None = None
114
118
  last_verified_sha: str | None = None
119
+ # The original accepted request remains distinct from both the selected
120
+ # baseline and any implementation candidate. It is never inferred from a
121
+ # later checkout head.
122
+ requested_repository_revision: str | None = None
123
+ execution_baseline_sha: str | None = None
124
+ allowed_baseline_revision: str | None = None
115
125
  next_action: str = "invoke_agent"
116
126
  terminal_condition: str = "repository_reconciled"
117
127
  diagnostic: str | None = None
@@ -168,6 +178,8 @@ class TransactionState:
168
178
  defaults = {
169
179
  "diagnostic": None, "owner_authorized": False, "transaction_kind": "IMPLEMENTATION",
170
180
  "execution_mode": "MANAGED", "genesis_repository_path": None, "genesis_commit_sha": None,
181
+ "requested_repository_revision": None, "execution_baseline_sha": None,
182
+ "allowed_baseline_revision": None,
171
183
  "action_intent": "MUTATING_DELIVERY",
172
184
  "implementation_branch": None, "implementation_pull_request": None,
173
185
  "implementation_head_sha": None, "implementation_merge_commit": None,
@@ -233,6 +245,14 @@ class TransactionState:
233
245
  raise StateError("checkpoint pull_request is invalid")
234
246
  if state.last_verified_sha is not None and not re.fullmatch(r"[0-9a-f]{40}", state.last_verified_sha):
235
247
  raise StateError("checkpoint last_verified_sha is invalid")
248
+ revision_binding_fields = (
249
+ state.requested_repository_revision, state.execution_baseline_sha,
250
+ state.allowed_baseline_revision,
251
+ )
252
+ if any(value is not None and (not isinstance(value, str) or not re.fullmatch(r"[0-9a-f]{40}", value)) for value in revision_binding_fields):
253
+ raise StateError("checkpoint repository revision binding is invalid")
254
+ if state.allowed_baseline_revision is not None and state.requested_repository_revision is None:
255
+ raise StateError("checkpoint allowed baseline requires a requested revision")
236
256
  if state.diagnostic is not None and (not isinstance(state.diagnostic, str) or not state.diagnostic or state.diagnostic != redact_diagnostic(state.diagnostic)):
237
257
  raise StateError("checkpoint diagnostic is invalid or unsafe")
238
258
  if not isinstance(state.owner_authorized, bool) or state.transaction_kind not in {"IMPLEMENTATION", "FINALIZATION", "RECONCILIATION"} or state.execution_mode not in {"MANAGED", "GENESIS"} or state.action_intent not in {"MUTATING_DELIVERY", "VALIDATION_ONLY"}:
@@ -379,12 +399,21 @@ class TransactionState:
379
399
  raise StateError("checkpoint quality evidence is invalid or unsafe")
380
400
  profile_fields = {"version", "digest", "candidate_sha"}
381
401
  current_profile_fields = profile_fields | {"criteria_digest"}
402
+ validation_bound_profile_fields = current_profile_fields | {"validation_profile_digest"}
382
403
  if state.assurance_profile is not None and (
383
404
  not isinstance(state.assurance_profile, dict)
384
- or set(state.assurance_profile) not in (profile_fields, current_profile_fields)
405
+ or set(state.assurance_profile) not in (
406
+ profile_fields, current_profile_fields, validation_bound_profile_fields,
407
+ )
385
408
  or not all(isinstance(value, str) and value for value in state.assurance_profile.values())
386
409
  or not re.fullmatch(r"sha256:[0-9a-f]{64}", state.assurance_profile["digest"])
387
410
  or not re.fullmatch(r"[0-9a-f]{40}", state.assurance_profile["candidate_sha"])
411
+ or (
412
+ "validation_profile_digest" in state.assurance_profile
413
+ and not re.fullmatch(
414
+ r"sha256:[0-9a-f]{64}", state.assurance_profile["validation_profile_digest"],
415
+ )
416
+ )
388
417
  ):
389
418
  raise StateError("checkpoint assurance profile is invalid")
390
419
  review_fields = {"reviewer", "status", "candidate_sha", "profile_digest", "invocation_id", "findings"}
@@ -462,8 +491,25 @@ class StateStore:
462
491
  # composition root. It must never rediscover that authority from the
463
492
  # execution checkout. The directory remains only a compatibility
464
493
  # location for legacy JSON projections.
465
- self.central_database = central_database.resolve() if central_database else None
494
+ environment_database = os.environ.get(CENTRAL_OPERATIONAL_DATABASE_ENVIRONMENT)
495
+ self.central_database = (
496
+ central_database.resolve()
497
+ if central_database is not None
498
+ else Path(environment_database).expanduser().resolve()
499
+ if environment_database
500
+ else None
501
+ )
466
502
  self.emit_local_projection = emit_local_projection
503
+ self._lifecycle_logger = None
504
+ if self.central_database is not None:
505
+ # Delayed to keep the state validator independent of the logging
506
+ # formatter, which itself uses ``redact_diagnostic`` above.
507
+ from .component_logging import component_logger
508
+ self._lifecycle_logger = component_logger(
509
+ self.central_database.parent,
510
+ "lifecycle_worker",
511
+ central_database=self.central_database,
512
+ )
467
513
 
468
514
  def path_for(self, run_id: str) -> Path:
469
515
  if not RUN_ID_PATTERN.fullmatch(run_id):
@@ -526,10 +572,18 @@ class StateStore:
526
572
  def save(self, state: TransactionState) -> Path:
527
573
  path = self.path_for(state.run_id)
528
574
  canonical = json.dumps(state.to_dict(), separators=(",", ":"), sort_keys=True)
529
- try:
530
- connection = self._open(create=True)
575
+ previous_phase: str | None = None
576
+ for delay in (0.0, *_TRANSIENT_CHECKPOINT_DELAYS):
577
+ connection: sqlite3.Connection | None = None
531
578
  try:
579
+ if delay:
580
+ sleep(delay)
581
+ connection = self._open(create=True)
532
582
  connection.execute("BEGIN IMMEDIATE")
583
+ prior = connection.execute(
584
+ "SELECT phase FROM engineering_transactions WHERE run_id=?", (state.run_id,)
585
+ ).fetchone()
586
+ previous_phase = str(prior[0]) if prior is not None else None
533
587
  connection.execute(
534
588
  "INSERT INTO engineering_transactions(run_id,payload,phase,updated_at) VALUES(?,?,?,CURRENT_TIMESTAMP) "
535
589
  "ON CONFLICT(run_id) DO UPDATE SET payload=excluded.payload,phase=excluded.phase,updated_at=excluded.updated_at",
@@ -540,13 +594,46 @@ class StateStore:
540
594
  (state.run_id, state.phase, canonical),
541
595
  )
542
596
  connection.execute("COMMIT")
597
+ break
598
+ except sqlite3.OperationalError as error:
599
+ if connection is not None:
600
+ try:
601
+ connection.execute("ROLLBACK")
602
+ except sqlite3.DatabaseError:
603
+ pass
604
+ if delay == _TRANSIENT_CHECKPOINT_DELAYS[-1] or "disk i/o" not in str(error).casefold():
605
+ raise
606
+ continue
607
+ except (EngineeringStorageError, OSError) as error:
608
+ raise StateError("canonical engineering storage could not save checkpoint") from error
543
609
  except Exception:
544
- connection.execute("ROLLBACK")
610
+ if connection is not None:
611
+ try:
612
+ connection.execute("ROLLBACK")
613
+ except sqlite3.DatabaseError:
614
+ pass
545
615
  raise
546
616
  finally:
547
- connection.close()
548
- except (EngineeringStorageError, OSError) as error:
549
- raise StateError("canonical engineering storage could not save checkpoint") from error
617
+ if connection is not None:
618
+ connection.close()
619
+ else:
620
+ raise StateError("canonical engineering storage could not save checkpoint")
621
+ if self._lifecycle_logger is not None:
622
+ from .component_logging import log_event
623
+ log_event(
624
+ self._lifecycle_logger,
625
+ logging.INFO if not state.terminal or state.phase == "COMPLETE" else logging.WARNING,
626
+ "lifecycle_phase_checkpointed",
627
+ run_id=state.run_id,
628
+ diagnostic=state.diagnostic,
629
+ context={
630
+ "previous_phase": previous_phase or "INITIAL",
631
+ "phase": state.phase,
632
+ "next_action": state.next_action,
633
+ "terminal_state": state.phase if state.terminal else "RUNNING",
634
+ "execution_mode": state.execution_mode,
635
+ },
636
+ )
550
637
  # CENTRAL runs must not create a repository-local checkpoint shadow.
551
638
  # The database row above is the sole durable state and is sufficient
552
639
  # for restart, recovery and Console/history projections.
@@ -119,7 +119,7 @@ button:not(.theme-toggle):not(.section-state-toggle):hover:not(:disabled){backgr
119
119
  #copyToast{align-items:center;background:var(--house-style-surface);border:1px solid var(--house-style);border-radius:999px;box-shadow:0 8px 24px #0009;box-sizing:border-box;color:var(--house-style-contrast);display:flex;font:600 13px system-ui;gap:8px;inset:auto;inset-block-end:max(20px,env(safe-area-inset-bottom));inset-inline-start:50%;margin:0;max-width:calc(100vw - 32px);opacity:0;padding:10px 15px;pointer-events:none;position:fixed;transform:translate(-50%,16px);transition:opacity .16s ease,transform .16s ease;z-index:110}#copyToast::before{content:attr(data-toast-glyph);font:700 17px/1 system-ui}#copyToast.copy-toast--visible{opacity:1;transform:translate(-50%,0)}
120
120
  body{overflow-x:hidden}.dashboard-grid,.dashboard-grid>*{min-width:0}.telemetry,.platform-health{min-width:0}.telemetry-scroll{max-width:100%;-webkit-overflow-scrolling:touch}.platform-health__component{min-width:0}.platform-health__component-detail{overflow-wrap:anywhere}.dashboard-titlebar{align-items:center;background:#121217;box-shadow:0 10px 18px #121217;box-sizing:border-box;display:flex;gap:14px;justify-content:space-between;margin:0 0 18px;max-width:100%;padding:8px 16px 12px;position:sticky;top:0;width:100%;z-index:15}.dashboard-titlebar:has(+.dashboard-status-banner:not([hidden])){margin-bottom:0}.dashboard-status-banner{align-items:flex-start;box-sizing:border-box;display:flex;gap:8px;margin:0 0 18px;padding:10px 16px;position:sticky;top:0;width:100%;z-index:14}.dashboard-status-banner[hidden]{display:none}.dashboard-status-banner--usage-limit,.dashboard-status-banner--usage-warning,.dashboard-status-banner--usage-critical{box-shadow:0 10px 18px #121217;font:600 13px/1.45 system-ui}.dashboard-status-banner--usage-limit{background:color-mix(in srgb,var(--house-style) 24%,#241b16);border-bottom:1px solid var(--house-style);color:#fff0dc}.dashboard-status-banner--usage-limit strong{color:var(--house-style)}.dashboard-status-banner--usage-warning{background:#5b4316;border-bottom:1px solid #f4c34f;color:#fff4d6}.dashboard-status-banner--usage-warning strong{color:#ffd768}.dashboard-status-banner--usage-critical{background:#5b1d27;border-bottom:1px solid #ff6b7d;color:#ffe9ed}.dashboard-status-banner--usage-critical strong{color:#ff99a7}.dashboard-status-banner strong{flex:none}.dashboard-status-banner span{min-width:0}.dashboard-titlebar__brand{align-items:center;display:flex;flex:1 1 260px;gap:10px;min-width:0}.dashboard-titlebar h1{font-size:28px;line-height:1.1;margin:0;overflow-wrap:anywhere}.dashboard-titlebar__actions{align-items:center;display:flex;flex:none;gap:12px}.auto-refresh-toggle{align-items:center;color:#b9b6c0;cursor:pointer;display:flex;flex:none;font-size:12px;gap:7px;white-space:nowrap}.auto-refresh-toggle input{accent-color:#54d6a0;height:18px;margin:0;width:18px}.section-state-toggle{align-items:center;background:transparent;border:0;color:#b9b6c0;cursor:pointer;display:flex;font:12px system-ui;gap:7px;margin:0;min-height:44px;min-width:44px;padding:0;position:relative}.section-state-toggle::before{background:#4a4a55;border-radius:999px;content:"";height:24px;transition:background .18s ease;width:42px}.section-state-toggle::after{background:#f7f3ee;border-radius:50%;box-shadow:0 1px 3px #0008;content:"";height:18px;left:3px;position:absolute;top:13px;transform:translateX(0);transition:transform .18s ease;width:18px}.section-state-toggle[aria-checked="true"]::before{background:#8dc7ff}.section-state-toggle[aria-checked="true"]::after{transform:translateX(18px)}.section-state-toggle:focus-visible{box-shadow:none;outline:2px solid #8dc7ff;outline-offset:3px}@media (max-width:1400px){.dashboard-titlebar{align-items:flex-start;flex-wrap:wrap}.dashboard-titlebar__actions{flex:1 1 100%;flex-wrap:wrap;justify-content:flex-end}}@media (max-width:760px){.dashboard-titlebar__actions{justify-content:flex-start}}@media (max-width:620px){.dashboard-status-banner{align-items:stretch;flex-direction:column;margin-bottom:12px;padding:10px 14px}.dashboard-titlebar h1{font-size:25px}.auto-refresh-toggle span,.section-state-toggle__label{display:none}.dashboard-titlebar__actions{gap:8px}}html[data-theme="light"] .dashboard-status-banner--usage-limit{background:color-mix(in srgb,var(--house-style) 18%,#fff);color:#643a13}html[data-theme="light"] .dashboard-status-banner--usage-warning{background:#fff4d6;color:#654600}html[data-theme="light"] .dashboard-status-banner--usage-critical{background:#ffe8eb;color:#7d1726}
121
121
  .dashboard-titlebar__brand{align-items:center;display:flex;gap:10px;min-width:0}.dashboard-app-icon{border-radius:9px;display:block;flex:none;height:32px;width:32px}@media (max-width:620px){.dashboard-app-icon{height:28px;width:28px}}
122
- .inbox-queue{--category-color:#818cf8;background:#25243a;border:2px solid var(--category-color);border-radius:18px;box-shadow:0 5px 24px #0006;cursor:pointer;padding:14px}.inbox-queue>summary{border-bottom:1px solid var(--category-color);box-sizing:border-box;cursor:pointer;display:block;list-style:none;margin-bottom:8px;min-height:35px;padding:0 40px 10px 0;position:relative}.inbox-queue>summary::-webkit-details-marker{display:none}.inbox-queue>summary::before{color:var(--category-color);content:"▸ ";font-size:24px;line-height:1;margin:0;padding:0;position:absolute;right:0;top:0;vertical-align:-2px}.inbox-queue[open]>summary::before{content:"▾ "}.inbox-queue>summary>strong{color:var(--category-color);font-size:17px;font-weight:700;letter-spacing:.04em;line-height:1.25;text-transform:uppercase}.inbox-queue .category-description{color:#c9c7e2;font-size:14px;line-height:1.4;margin:12px 0}.inbox-queue .estimate-meta{color:#c9c7e2}.inbox-queue .queue-item{border-top-color:#48446f}
122
+ .inbox-queue{--category-color:#818cf8;background:#24242d;border:2px solid var(--category-color);border-radius:18px;box-shadow:0 5px 24px #0006;cursor:pointer;padding:14px}.inbox-queue>summary{border-bottom:1px solid var(--category-color);box-sizing:border-box;cursor:pointer;display:block;list-style:none;margin-bottom:8px;min-height:35px;padding:0 40px 10px 0;position:relative}.inbox-queue>summary::-webkit-details-marker{display:none}.inbox-queue>summary::before{color:var(--category-color);content:"▸ ";font-size:24px;line-height:1;margin:0;padding:0;position:absolute;right:0;top:0;vertical-align:-2px}.inbox-queue[open]>summary::before{content:"▾ "}.inbox-queue>summary>strong{color:var(--category-color);font-size:17px;font-weight:700;letter-spacing:.04em;line-height:1.25;text-transform:uppercase}.inbox-queue .category-description{color:#c9c7e2;font-size:14px;line-height:1.4;margin:12px 0}.inbox-queue .estimate-meta{color:#c9c7e2}.inbox-queue .queue-item{border-top-color:#48446f}
123
123
  .prompt-history{--category-color:#f29ab2;background:#36232d;border:2px solid var(--category-color);border-radius:18px;box-shadow:0 5px 24px #0006;cursor:pointer;padding:14px}.prompt-history>summary{border-bottom:1px solid var(--category-color);box-sizing:border-box;cursor:pointer;display:block;list-style:none;margin-bottom:8px;min-height:35px;padding:0 40px 10px 0;position:relative}.prompt-history>summary::-webkit-details-marker{display:none}.prompt-history>summary::before{color:var(--category-color);content:"▸ ";font-size:24px;line-height:1;margin:0;padding:0;position:absolute;right:0;top:0;vertical-align:-2px}.prompt-history[open]>summary::before{content:"▾ "}.prompt-history>summary>strong{color:var(--category-color);font-size:17px;font-weight:700;letter-spacing:.04em;line-height:1.25;text-transform:uppercase}.prompt-history .category-description{color:#dfc3ce;font-size:14px;line-height:1.4;margin:12px 0}.prompt-history .log-controls label,.prompt-history .log-table th{color:var(--category-color)}.prompt-history .log-table-wrap{border-color:color-mix(in srgb,var(--category-color) 55%,#3d3651)}.prompt-history .log-table th,.prompt-history .log-table td{border-bottom-color:color-mix(in srgb,var(--category-color) 30%,#3d3651)}.prompt-history .log-table th.log-sortable::after{color:var(--category-color)}.prompt-history .log-table th.log-sortable:focus-visible{outline:2px solid var(--category-color);outline-offset:-2px}.prompt-history .log-pagination button{background:#442b37;border-color:var(--category-color);color:#ffe9ef}.prompt-history-report,.prompt-history-analysis{align-items:center;background:transparent;border:1px solid var(--category-color);border-radius:50%;color:var(--category-color);display:inline-flex;font:16px/1 system-ui;justify-content:center;min-height:32px;min-width:32px;padding:0}.prompt-history-report:hover,.prompt-history-analysis:hover{background:var(--category-color);color:#271923}.prompt-history-analysis-actions{align-items:center;display:flex;gap:6px}.prompt-history-status{font-weight:700}.prompt-history-status--complete{color:#54d6a0}.prompt-history-status--blocked{color:#f0b66a}.prompt-history-status--failed{color:#ff718f}.report-view-modal{background:transparent;border:0;max-height:90vh;max-width:min(1000px,94vw);padding:0;width:min(1000px,94vw)}.report-view-modal::backdrop{background:#0d1018bb}.report-view-modal__panel{--category-color:#8dc7ff;background:#24242d;border:2px solid var(--category-color);border-radius:18px;box-shadow:0 16px 50px #000a;color:#f7f3ee;max-height:90vh;overflow:auto;padding:18px;position:relative}.report-view-modal__title{color:var(--category-color);font-size:20px;margin:0 80px 14px 0}.report-view-modal__actions{display:flex;gap:8px;position:absolute;right:16px;top:14px}.report-view-modal__actions .copy,.report-view-modal__actions .download{position:static}.report-view-modal__content{min-height:80px;padding:12px}.report-view-modal__close{background:#24242d;border:1px solid var(--category-color);border-radius:50%;color:var(--category-color);font:22px/1 system-ui;height:32px;min-height:32px;min-width:32px;padding:0}.report-view-modal__close:hover{background:var(--category-color);color:#17151a}
124
124
  .prompt-history-details{align-items:center;background:transparent;border:1px solid #8dc7ff;border-radius:50%;color:#8dc7ff;display:inline-flex;font:700 19px/1 system-ui;justify-content:center;min-height:32px;min-width:32px;padding:0}.prompt-history-details:hover{background:#8dc7ff!important;border-color:#8dc7ff!important;color:#172331!important}.prompt-history-run-id-field{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.prompt-history-run-id-field .label{flex-basis:100%}.prompt-history-run-id-field pre{margin:0}.prompt-history-run-id-copy{align-items:center;background:transparent;border:1px solid #8dc7ff;border-radius:50%;color:#8dc7ff;display:inline-flex;font:700 16px/1 system-ui;justify-content:center;min-height:28px;min-width:28px;padding:0}.prompt-history-run-id-copy:hover{background:#8dc7ff!important;border-color:#8dc7ff!important;color:#172331!important}
125
125
  #promptHistory .log-table{width:100%}#promptHistory .log-table th:nth-child(2),#promptHistory .log-table td:nth-child(2){width:100%}
@@ -406,7 +406,7 @@ html[data-theme="light"] :is(.dashboard-locale,.dashboard-project){color:#415168
406
406
 
407
407
  /* Main sections */
408
408
  .dashboard-grid{gap:var(--dashboard-section-gap)}
409
- .execution-context--primary{background:#1f3140!important;border-color:#65c5d9!important}.execution-context--primary strong{color:#8de1f2!important}.execution-context--primary .field{border-top:1px solid #65c5d955;padding-top:8px}.execution-context--primary .field:first-of-type{border-top:0;padding-top:0}.execution-context__phase{border:1px solid currentColor;border-radius:999px;display:inline-block;font-weight:700;padding:4px 8px}.execution-context__planning-empty{border-top:1px solid #65c5d955;color:var(--dashboard-modal-muted);font-size:14px;line-height:1.45;margin:0;padding-top:10px}
409
+ .execution-context--primary{background:#1f3140!important;border-color:#65c5d9!important}.execution-context--primary strong{color:#8de1f2!important}.execution-context--primary .field{border-top:1px solid #65c5d955;padding-top:8px}.execution-context--primary .field:first-of-type{border-top:0;padding-top:0}.execution-context__planning-empty{border-top:1px solid #65c5d955;color:var(--dashboard-modal-muted);font-size:14px;line-height:1.45;margin:0;padding-top:10px}
410
410
  .execution-mode-field__value{align-items:center;display:flex;gap:10px;justify-content:space-between;min-width:0}.execution-mode-field__value>span{min-width:0;overflow-wrap:anywhere}.execution-mode-info{color:#65c5d9;flex:none;grid-area:auto}.execution-mode-info:hover{background:#65c5d9!important;border-color:#65c5d9!important;color:#162832!important}
411
411
  .workspace-card{margin-bottom:0}
412
412
  .workspace-card,.inbox-queue,.prompt-history,#rateLimits,#componentLogs,#codexChat,#engineering-dashboard-content>.technical-details:not(#componentLogs),.telemetry,.platform-health,.current-run{box-shadow:none}
@@ -433,7 +433,7 @@ html[data-theme="light"] :is(.dashboard-locale,.dashboard-project){color:#415168
433
433
  @media (max-width:620px) and (orientation:portrait) and (hover:none) and (pointer:coarse){
434
434
  /* iOS handles a document scroll more reliably than a nested flex scroller.
435
435
  It also lets the title naturally leave the viewport with the content. */
436
- .dashboard-sticky-header{position:static}.dashboard-titlebar{position:static}
436
+ .dashboard-sticky-header{max-height:none;overflow:visible;overscroll-behavior:auto;position:static}.dashboard-titlebar{position:static}
437
437
  body{display:block;height:auto;min-height:100dvh;overflow-x:hidden;overflow-y:auto;padding-inline:max(12px,env(safe-area-inset-left)) max(12px,env(safe-area-inset-right))}
438
438
  .dashboard-scroll-region{min-height:auto;overflow:visible;padding-inline:6px;scrollbar-gutter:stable both-edges}
439
439
  .footer{box-sizing:border-box;display:flex;flex-wrap:wrap;gap:4px 10px;justify-content:center;overflow:visible;padding-inline:6px;text-align:center;white-space:normal}
@@ -1228,6 +1228,7 @@ html[data-theme="light"] .dashboard-status-banner--provider-unavailable .provide
1228
1228
  outline-offset:0!important;
1229
1229
  }
1230
1230
 
1231
+
1231
1232
  /* Native date editors otherwise inherit the muted category colour from their
1232
1233
  label. They are values, so use the same high-contrast ink as every field. */
1233
1234
  #componentLogControls :is(input[type="date"],input[type="datetime-local"]){
@@ -1298,7 +1299,11 @@ html[data-theme="light"] #componentLogControls :is(input[type="date"],input[type
1298
1299
  area. Do not add a later global bubble scroller: it would force short
1299
1300
  messages to reserve scrollbar chrome and defeat the 2/3 area limit. */
1300
1301
  @media (max-width:620px){.dashboard-status-banner{position:static}}
1301
- .platform-attention{background:#5b4316;border-bottom:1px solid #f4c34f;color:#fff4d6;margin:0 0 18px}.platform-attention[hidden]{display:none}.platform-attention>summary{align-items:center;cursor:pointer;display:flex;gap:9px;list-style:none;padding:10px 16px}.platform-attention>summary::-webkit-details-marker{display:none}.platform-attention>summary::after{content:"▸";margin-left:auto}.platform-attention[open]>summary::after{content:"▾"}.platform-attention>summary strong{color:#ffd768}.platform-attention>summary span{background:#f4c34f;border-radius:999px;color:#2a2415;font-size:12px;font-weight:800;min-width:1.4rem;padding:2px 5px;text-align:center}.platform-attention__items{display:grid;gap:8px;padding:0 12px 12px}.platform-attention__items .dashboard-status-banner{margin:0;position:static}.platform-attention__items .dashboard-status-banner--provider-readiness{align-items:flex-start}.platform-attention__items .provider-readiness-banner__action{align-self:center}
1302
+ .platform-attention{background:#5b4316;border-bottom:1px solid #f4c34f;color:#fff4d6;margin:0 0 18px}.platform-attention[hidden]{display:none}.platform-attention>summary{align-items:center;cursor:pointer;display:flex;gap:9px;list-style:none;padding:10px 16px}.platform-attention>summary::-webkit-details-marker{display:none}.platform-attention>summary::after{content:"▸";font-size:24px;font-weight:700;line-height:1;margin-left:auto}.platform-attention[open]>summary::after{content:"▾"}.platform-attention>summary strong{color:#ffd768}.platform-attention>summary span{background:#f4c34f;border-radius:999px;color:#2a2415;font-size:12px;font-weight:800;min-width:1.4rem;padding:2px 5px;text-align:center}.platform-attention__items{display:grid;gap:8px;padding:0 12px 12px}.platform-attention__items .dashboard-status-banner{margin:0;position:static}.platform-attention__items .dashboard-status-banner--provider-readiness{align-items:flex-start}.platform-attention__items .provider-readiness-banner__action{align-self:center}
1303
+
1304
+ /* An expanded provider failure is its own red banner, not content inside an
1305
+ amber frame. Keep the amber summary, but leave the failure card unframed. */
1306
+ .platform-attention[open]{background:transparent;border:0}.platform-attention[open]>summary{background:#5b4316;border-bottom:1px solid #f4c34f}.platform-attention[open] .platform-attention__items{padding:8px 0 0}
1302
1307
 
1303
1308
  /* Buttons are controls, not text links: every visible action gets a modest
1304
1309
  fill derived from its own ink/border colour. Semantic local-file links and