engineering-platform 2.3.82__tar.gz → 2.3.83__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 (168) hide show
  1. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/PKG-INFO +1 -1
  2. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/pyproject.toml +1 -1
  3. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
  4. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
  5. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/central_operational_reset.py +177 -9
  6. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/platform_version.py +1 -1
  7. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/templates/workspace-config.json +1 -1
  8. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform.egg-info/PKG-INFO +1 -1
  9. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/README.md +0 -0
  10. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/setup.cfg +0 -0
  11. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/__init__.py +0 -0
  12. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/__main__.py +0 -0
  13. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/agent_state.py +0 -0
  14. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/agent_trust.py +0 -0
  15. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/dashboard.css +0 -0
  16. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/dashboard.js +0 -0
  17. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/dashboard_locales.mjs +0 -0
  18. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
  19. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
  20. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  21. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  22. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
  23. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
  24. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  25. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
  26. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/capability_preflight.py +0 -0
  27. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/capability_review.py +0 -0
  28. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/central_data_transfer.py +0 -0
  29. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/central_database.py +0 -0
  30. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/central_store_migration.py +0 -0
  31. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/codex_capacity.py +0 -0
  32. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/codex_chat.py +0 -0
  33. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/codex_observability.py +0 -0
  34. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/component_lock.py +0 -0
  35. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/component_logging.py +0 -0
  36. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/console_presentation.py +0 -0
  37. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/console_route_ownership.py +0 -0
  38. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/contracts/__init__.py +0 -0
  39. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/contracts/ep_consumer.py +0 -0
  40. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/contracts/models.py +0 -0
  41. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/contracts/projection.py +0 -0
  42. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/dashboard_browser_validation.py +0 -0
  43. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/dashboard_state.py +0 -0
  44. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/dashboard_supervisor.swift +0 -0
  45. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/dashboard_translation.py +0 -0
  46. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/dependabot_producer.py +0 -0
  47. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/development_profile.py +0 -0
  48. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/drift_diagnostics.py +0 -0
  49. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/emergency_recovery.py +0 -0
  50. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/engineering_memory.py +0 -0
  51. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/ep_consumer_credentials.py +0 -0
  52. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/evidence_projection.py +0 -0
  53. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_activity.py +0 -0
  54. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_context.py +0 -0
  55. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_errors.py +0 -0
  56. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_evidence.py +0 -0
  57. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_executor.py +0 -0
  58. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_finalization.py +0 -0
  59. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_host.py +0 -0
  60. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_host_evidence.py +0 -0
  61. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_lease.py +0 -0
  62. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_lifecycle.py +0 -0
  63. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_models.py +0 -0
  64. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_readiness.py +0 -0
  65. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_reporting.py +0 -0
  66. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_repository.py +0 -0
  67. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_timeout_policy.py +0 -0
  68. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_timing.py +0 -0
  69. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/execution_transaction.py +0 -0
  70. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/external_producer_binding.py +0 -0
  71. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/file_inbox.py +0 -0
  72. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/forensic_attribution.py +0 -0
  73. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/forensic_attribution_v2.py +0 -0
  74. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/forensic_delta.py +0 -0
  75. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/golden_scenario.py +0 -0
  76. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
  77. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/host_admin.py +0 -0
  78. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/host_preflight.py +0 -0
  79. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_relocation.py +0 -0
  80. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_activation.py +0 -0
  81. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_admission.py +0 -0
  82. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_backup.py +0 -0
  83. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_composition.py +0 -0
  84. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_executor.py +0 -0
  85. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_migration.py +0 -0
  86. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_operation.py +0 -0
  87. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_plan.py +0 -0
  88. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/installation_update_preparation.py +0 -0
  89. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/investigation_ledger.py +0 -0
  90. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/legacy_inbox_migration.py +0 -0
  91. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/legacy_installation_adoption.py +0 -0
  92. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/lifecycle_worker.py +0 -0
  93. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/live_status.py +0 -0
  94. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/local_api.py +0 -0
  95. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/local_api_keychain.py +0 -0
  96. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/local_repository_binding.py +0 -0
  97. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/managed_autonomy.py +0 -0
  98. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/managed_codex_runtime.py +0 -0
  99. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/operational_installation.py +0 -0
  100. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/operational_installation_lock.py +0 -0
  101. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/operational_installation_record.py +0 -0
  102. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/owner_credential_recovery.py +0 -0
  103. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/parity_context.py +0 -0
  104. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
  105. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/platform_admin.py +0 -0
  106. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/platform_api.py +0 -0
  107. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/platform_bootstrap.py +0 -0
  108. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/platform_components.py +0 -0
  109. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/pr_check_repair.py +0 -0
  110. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/pr_evidence_backfill.py +0 -0
  111. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/producer.py +0 -0
  112. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/product_installation_readback.py +0 -0
  113. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/project_agent.py +0 -0
  114. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/project_agent_service.py +0 -0
  115. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/project_topology.py +0 -0
  116. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/prompt_history.py +0 -0
  117. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_context.py +0 -0
  118. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_context_benchmark.py +0 -0
  119. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_context_scope.py +0 -0
  120. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_interruption.py +0 -0
  121. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_process_identity.py +0 -0
  122. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_readiness.py +0 -0
  123. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_recovery.py +0 -0
  124. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/provider_usage.py +0 -0
  125. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/providers.py +0 -0
  126. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/qualification.py +0 -0
  127. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/qualification_runtime.py +0 -0
  128. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/recommendation_handoff.py +0 -0
  129. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/reconciliation_adoption.py +0 -0
  130. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/release_operation.py +0 -0
  131. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/report_analysis.py +0 -0
  132. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/repository_attachment.py +0 -0
  133. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/repository_handoff.py +0 -0
  134. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/resources.py +0 -0
  135. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/reviewer_evidence.py +0 -0
  136. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/revision_binding.py +0 -0
  137. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
  138. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
  139. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
  140. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/server.py +0 -0
  141. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/server_console_services.py +0 -0
  142. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/server_relay.py +0 -0
  143. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/server_service.py +0 -0
  144. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/status_model.py +0 -0
  145. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/status_reconciliation.py +0 -0
  146. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/storage.py +0 -0
  147. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/submission_cli.py +0 -0
  148. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/submission_intake.py +0 -0
  149. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/submission_service.py +0 -0
  150. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/system_installation_topology.py +0 -0
  151. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/system_server_service.py +0 -0
  152. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/telemetry.py +0 -0
  153. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/telemetry_contract.py +0 -0
  154. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/telemetry_export.py +0 -0
  155. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/telemetry_metrics.py +0 -0
  156. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
  157. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/validation_identity.py +0 -0
  158. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/validation_profile.py +0 -0
  159. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/version_preparation_delivery.py +0 -0
  160. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/workspace_preflight.py +0 -0
  161. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/worktree_provenance.py +0 -0
  162. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform/worktree_tooling.py +0 -0
  163. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
  164. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
  165. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform.egg-info/entry_points.txt +0 -0
  166. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/src/engineering_platform.egg-info/top_level.txt +0 -0
  167. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/tests/test_adaptive_action_sizing_design.py +0 -0
  168. {engineering_platform-2.3.82 → engineering_platform-2.3.83}/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.82
3
+ Version: 2.3.83
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.82"
7
+ version = "2.3.83"
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.82",
6
+ "version": "2.3.83",
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.82",
4
+ "dashboard_version": "2.3.83",
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.82",
9
+ "platform_version": "2.3.83",
10
10
  "report_format": 2,
11
- "runner_version": "2.3.82",
11
+ "runner_version": "2.3.83",
12
12
  "status_model": 1,
13
13
  "storage_schema": 45,
14
- "watcher_version": "2.3.82"
14
+ "watcher_version": "2.3.83"
15
15
  }
@@ -21,11 +21,13 @@ import re
21
21
  import shutil
22
22
  import sqlite3
23
23
  import stat
24
+ import subprocess
24
25
  import tempfile
25
- from typing import Iterator
26
+ from typing import Iterator, Mapping
26
27
 
27
28
  from . import central_database
28
29
  from .platform_admin import require_installation_owner
30
+ from .platform_version import CURRENT_PLATFORM_VERSION
29
31
  from .operational_installation_lock import (
30
32
  OperationalInstallationLock, OperationalInstallationLockError,
31
33
  )
@@ -33,7 +35,7 @@ from .storage import sqlite_connection
33
35
 
34
36
 
35
37
  PROFILE = "EP_CENTRAL_OPERATIONAL_HISTORY_V1"
36
- PLAN_VERSION = 1
38
+ PLAN_VERSION = 2
37
39
  SCHEMA_VERSION = 68
38
40
  _OPERATION = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{7,127}")
39
41
  _INSTANCE_ID = re.compile(
@@ -212,6 +214,36 @@ def _file_digest(path: Path) -> str:
212
214
  return "sha256:" + digest.hexdigest()
213
215
 
214
216
 
217
+ def _implementation_digest() -> str:
218
+ return _digest({
219
+ "module_digest": _file_digest(Path(__file__)),
220
+ "product_version": CURRENT_PLATFORM_VERSION,
221
+ })
222
+
223
+
224
+ def _implementation_source_revision() -> str:
225
+ try:
226
+ module = Path(__file__).resolve()
227
+ root = Path(subprocess.check_output(
228
+ ("git", "-C", str(module.parent), "rev-parse", "--show-toplevel"),
229
+ text=True, stderr=subprocess.DEVNULL,
230
+ ).strip()).resolve()
231
+ relative = module.relative_to(root).as_posix()
232
+ subprocess.run(
233
+ ("git", "-C", str(root), "ls-files", "--error-unmatch", relative),
234
+ check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
235
+ )
236
+ revision = subprocess.check_output(
237
+ ("git", "-C", str(root), "rev-parse", "HEAD"),
238
+ text=True, stderr=subprocess.DEVNULL,
239
+ ).strip()
240
+ if re.fullmatch(r"[0-9a-f]{40}", revision):
241
+ return revision
242
+ except (OSError, ValueError, subprocess.CalledProcessError):
243
+ pass
244
+ return "UNAVAILABLE_IN_INSTALLED_PACKAGE"
245
+
246
+
215
247
  def _quote(identifier: str) -> str:
216
248
  return '"' + identifier.replace('"', '""') + '"'
217
249
 
@@ -1276,6 +1308,13 @@ def preview(data_root: Path) -> dict[str, object]:
1276
1308
  missing_writer_fences = sorted(
1277
1309
  _expected_writer_fences(tables) - installed_triggers
1278
1310
  )
1311
+ active_rows = [
1312
+ {"operation_id": str(row[0]), "state": str(row[1])}
1313
+ for row in connection.execute(
1314
+ "SELECT operation_id,state FROM ep_operational_reset_operations "
1315
+ "WHERE state NOT IN ('COMPLETED','ABORTED') ORDER BY operation_id"
1316
+ )
1317
+ ] if "ep_operational_reset_operations" in tables else []
1279
1318
  except (OSError, sqlite3.DatabaseError, TypeError, ValueError) as error:
1280
1319
  raise OperationalResetError("CENTRAL_INSPECTION_FAILED") from error
1281
1320
  external_error: str | None = None
@@ -1315,6 +1354,8 @@ def preview(data_root: Path) -> dict[str, object]:
1315
1354
  blockers.append("PRESERVATION_INTEGRITY_FAILED")
1316
1355
  if activity["active"]:
1317
1356
  blockers.append("TARGET_WRITER_ACTIVE")
1357
+ if active_rows:
1358
+ blockers.append("MAINTENANCE_ALREADY_ACTIVE")
1318
1359
  review = [str(item["id"]) for item in foreign_keys if item["classification"] == "OPERATIONAL_PURGE_SET"]
1319
1360
  target_digest = _digest(identity)
1320
1361
  effect_set = {
@@ -1326,8 +1367,12 @@ def preview(data_root: Path) -> dict[str, object]:
1326
1367
  "external_roots": list(_EFFECT_DIRECTORIES),
1327
1368
  }
1328
1369
  plan_basis = {
1329
- "plan_version": PLAN_VERSION, "profile": PROFILE, "target": identity,
1370
+ "plan_version": PLAN_VERSION, "operator_contract": "operational-reset-v1",
1371
+ "profile": PROFILE, "product_version": CURRENT_PLATFORM_VERSION,
1372
+ "implementation_source_revision": _implementation_source_revision(),
1373
+ "implementation_digest": _implementation_digest(), "target": identity,
1330
1374
  "target_digest": target_digest, "source_revision": source_revision,
1375
+ "meaningful_source_revision": source_revision,
1331
1376
  "preserved_bindings_digest": preserved_digest, "dataset_generation": generation,
1332
1377
  "classification_counts": counts, "foreign_key_findings": foreign_keys,
1333
1378
  "external_files": external,
@@ -1347,6 +1392,7 @@ def preview(data_root: Path) -> dict[str, object]:
1347
1392
  return {
1348
1393
  **plan_basis, "plan_digest": _digest(plan_basis), "quick_check": quick,
1349
1394
  "runtime_activity": activity, "blocking_codes": sorted(set(blockers)),
1395
+ "active_maintenance": active_rows,
1350
1396
  "review_required": review,
1351
1397
  "runtime_control_external": [
1352
1398
  item for item in preserved_external
@@ -1665,7 +1711,10 @@ def prepare(
1665
1711
  plan = preview(root)
1666
1712
  if plan["plan_digest"] != plan_digest:
1667
1713
  raise OperationalResetError("PLAN_DIGEST_MISMATCH")
1668
- if plan["blocking_codes"]:
1714
+ non_maintenance_blockers = [
1715
+ code for code in plan["blocking_codes"] if code != "MAINTENANCE_ALREADY_ACTIVE"
1716
+ ]
1717
+ if non_maintenance_blockers:
1669
1718
  raise OperationalResetError("PLAN_BLOCKED", ",".join(plan["blocking_codes"]))
1670
1719
  expected_findings = tuple(sorted(str(item) for item in plan["review_required"]))
1671
1720
  allowed = tuple(sorted(set(allowed_fk_findings)))
@@ -1685,6 +1734,8 @@ def prepare(
1685
1734
  if existing["request_digest"] != request_digest:
1686
1735
  raise OperationalResetError("OPERATION_REQUEST_CONFLICT")
1687
1736
  return _public_status(existing)
1737
+ if plan["blocking_codes"]:
1738
+ raise OperationalResetError("PLAN_BLOCKED", ",".join(plan["blocking_codes"]))
1688
1739
  generation = int(connection.execute(
1689
1740
  "SELECT generation FROM ep_operational_dataset_state WHERE singleton=1"
1690
1741
  ).fetchone()[0])
@@ -1768,6 +1819,68 @@ def maintenance_active(data_root: Path) -> bool:
1768
1819
  raise OperationalResetError("MAINTENANCE_STATE_UNAVAILABLE") from error
1769
1820
 
1770
1821
 
1822
+ def revalidate(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str, object]:
1823
+ """Read-only proof for one already prepared owning operation."""
1824
+ root = _trusted_directory(data_root, code="DATA_ROOT_UNSAFE")
1825
+ actor = _actor(root)
1826
+ database = root / central_database.DATABASE_FILENAME
1827
+ with _central_connection(f"file:{database}?mode=ro", uri=True) as connection:
1828
+ connection.execute("PRAGMA query_only=ON")
1829
+ row = _operation(connection, operation_id)
1830
+ if row is None or row["plan_digest"] != plan_digest:
1831
+ raise OperationalResetError("AUTHORIZED_OPERATION_NOT_FOUND")
1832
+ if row["state"] != "AUTHORIZED":
1833
+ raise OperationalResetError("OPERATION_STATE_INVALID_FOR_REVALIDATION")
1834
+ if row["actor"] != actor:
1835
+ raise OperationalResetError("OPERATOR_AUTHORITY_CHANGED")
1836
+ plan = json.loads(str(row["plan_json"]))
1837
+ if int(plan.get("plan_version", -1)) != PLAN_VERSION:
1838
+ raise OperationalResetError("PLAN_VERSION_UNSUPPORTED")
1839
+ observed = preview(root)
1840
+ if observed["active_maintenance"] != [{
1841
+ "operation_id": operation_id, "state": "AUTHORIZED",
1842
+ }]:
1843
+ raise OperationalResetError("WRITER_FENCE_OWNER_CHANGED")
1844
+ if observed["blocking_codes"] != ["MAINTENANCE_ALREADY_ACTIVE"]:
1845
+ raise OperationalResetError("REVALIDATION_BLOCKED")
1846
+ for key in (
1847
+ "plan_digest", "target_digest", "source_revision", "preserved_bindings_digest",
1848
+ "dataset_generation", "effect_set", "schema_objects", "foreign_key_findings",
1849
+ "external_files", "preserved_external",
1850
+ ):
1851
+ expected = row["plan_digest"] if key == "plan_digest" else plan[key]
1852
+ if observed[key] != expected:
1853
+ raise OperationalResetError("REVALIDATION_CHANGED", key)
1854
+ if int(observed["dataset_generation"]) != int(row["generation_before"]):
1855
+ raise OperationalResetError("DATASET_GENERATION_CONFLICT")
1856
+ backup_path = row.get("backup_path")
1857
+ backup_digest = row.get("backup_manifest_digest")
1858
+ if not isinstance(backup_path, str) or not isinstance(backup_digest, str):
1859
+ raise OperationalResetError("BACKUP_BINDING_INVALID")
1860
+ verify_backup(
1861
+ Path(backup_path), operation_id=operation_id, plan_digest=plan_digest,
1862
+ expected_manifest_digest=backup_digest,
1863
+ )
1864
+ evidence = {
1865
+ "operation_id": operation_id, "state": str(row["state"]),
1866
+ "writer_fence_owner": operation_id, "actor": actor,
1867
+ "target_digest": str(row["target_digest"]),
1868
+ "plan_digest": str(row["plan_digest"]),
1869
+ "request_digest": str(row["request_digest"]),
1870
+ "source_revision": str(row["source_revision"]),
1871
+ "implementation_source_revision": str(plan["implementation_source_revision"]),
1872
+ "implementation_digest": str(plan["implementation_digest"]),
1873
+ "product_version": str(plan["product_version"]),
1874
+ "preserved_bindings_digest": str(plan["preserved_bindings_digest"]),
1875
+ "backup_manifest_digest": backup_digest,
1876
+ "dataset_generation": int(row["generation_before"]),
1877
+ }
1878
+ evidence["revalidation_digest"] = _digest(evidence)
1879
+ result = _public_status(row)
1880
+ result["revalidation"] = evidence
1881
+ return result
1882
+
1883
+
1771
1884
  def _archive_effects(data_root: Path, operation_id: str, plan: dict[str, object]) -> None:
1772
1885
  archive = _secure_mkdirs(
1773
1886
  data_root, Path("operational-reset-archive") / operation_id,
@@ -2082,12 +2195,14 @@ def _delete_operational(connection: sqlite3.Connection) -> None:
2082
2195
  def apply(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str, object]:
2083
2196
  root = _trusted_directory(data_root, code="DATA_ROOT_UNSAFE")
2084
2197
  with _operation_lock(root, operation_id):
2085
- _actor(root)
2198
+ actor = _actor(root)
2086
2199
  database = root / central_database.DATABASE_FILENAME
2087
2200
  with _central_connection(database) as connection:
2088
2201
  row = _operation(connection, operation_id)
2089
2202
  if row is None or row["plan_digest"] != plan_digest:
2090
2203
  raise OperationalResetError("AUTHORIZED_OPERATION_NOT_FOUND")
2204
+ if row["actor"] != actor:
2205
+ raise OperationalResetError("OPERATOR_AUTHORITY_CHANGED")
2091
2206
  state = str(row["state"])
2092
2207
  if state == "PREPARING":
2093
2208
  raise OperationalResetError("BACKUP_NOT_AUTHORIZED")
@@ -2106,9 +2221,7 @@ def apply(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str,
2106
2221
  return _public_status(row)
2107
2222
  plan = json.loads(str(row["plan_json"]))
2108
2223
  if state == "AUTHORIZED":
2109
- current = preview(root)
2110
- if current["source_revision"] != row["source_revision"] or current["plan_digest"] != plan_digest:
2111
- raise OperationalResetError("SOURCE_REVISION_CHANGED")
2224
+ revalidate(root, operation_id=operation_id, plan_digest=plan_digest)
2112
2225
  with _central_connection(database) as connection:
2113
2226
  connection.execute("BEGIN IMMEDIATE")
2114
2227
  _transition(connection, operation_id, "AUTHORIZED", "ARTIFACTS_ARCHIVING")
@@ -2133,6 +2246,39 @@ def apply(data_root: Path, *, operation_id: str, plan_digest: str) -> dict[str,
2133
2246
  current = _operation(connection, operation_id)
2134
2247
  if current is None or current["state"] != "ARTIFACTS_ARCHIVED":
2135
2248
  raise OperationalResetError("OPERATION_STATE_TRANSITION_CONFLICT")
2249
+ if _actor(root) != row["actor"]:
2250
+ raise OperationalResetError("OPERATOR_AUTHORITY_CHANGED")
2251
+ tables = _tables(connection)
2252
+ if tables != MAPPED_TABLES:
2253
+ raise OperationalResetError("TABLE_CLASSIFICATION_INCOMPLETE")
2254
+ active = [
2255
+ (str(item[0]), str(item[1])) for item in connection.execute(
2256
+ "SELECT operation_id,state FROM ep_operational_reset_operations "
2257
+ "WHERE state NOT IN ('COMPLETED','ABORTED') ORDER BY operation_id"
2258
+ )
2259
+ ]
2260
+ if active != [(operation_id, "ARTIFACTS_ARCHIVED")]:
2261
+ raise OperationalResetError("WRITER_FENCE_OWNER_CHANGED")
2262
+ identity = _identity(root, connection)
2263
+ if identity != plan["target"]:
2264
+ raise OperationalResetError("TARGET_IDENTITY_CONFLICT")
2265
+ if _logical_digest(connection, tables) != row["source_revision"]:
2266
+ raise OperationalResetError("SOURCE_REVISION_CHANGED")
2267
+ if _logical_digest(connection, tables, preserved_only=True) != plan["preserved_bindings_digest"]:
2268
+ raise OperationalResetError("PRESERVED_BINDINGS_CHANGED")
2269
+ if _schema_objects(connection) != plan["schema_objects"]:
2270
+ raise OperationalResetError("SCHEMA_OBJECTS_CHANGED")
2271
+ if (
2272
+ plan.get("product_version") != CURRENT_PLATFORM_VERSION
2273
+ or plan.get("implementation_source_revision") != _implementation_source_revision()
2274
+ or plan.get("implementation_digest") != _implementation_digest()
2275
+ ):
2276
+ raise OperationalResetError("IMPLEMENTATION_PROVENANCE_CHANGED")
2277
+ generation_before = int(connection.execute(
2278
+ "SELECT generation FROM ep_operational_dataset_state WHERE singleton=1"
2279
+ ).fetchone()[0])
2280
+ if generation_before != int(row["generation_before"]):
2281
+ raise OperationalResetError("DATASET_GENERATION_CONFLICT")
2136
2282
  # Immutable-evidence and maintenance-block triggers are removed and
2137
2283
  # recreated inside this one uncommitted transaction. Other writers
2138
2284
  # cannot observe an unfenced schema window.
@@ -2467,6 +2613,7 @@ def resume(data_root: Path, *, operation_id: str, plan_digest: str,
2467
2613
 
2468
2614
  def contract_readback(
2469
2615
  data_root: Path, *, command: str, operation_id: str | None,
2616
+ revalidation_result: Mapping[str, object] | None = None,
2470
2617
  ) -> dict[str, object]:
2471
2618
  """Project the shared operator contract from persisted, public state only.
2472
2619
 
@@ -2505,6 +2652,21 @@ def contract_readback(
2505
2652
  }
2506
2653
  target = observed["target"]
2507
2654
  blockers = list(observed["blocking_codes"])
2655
+ revalidation_evidence: dict[str, object] | None = None
2656
+ if command == "revalidate":
2657
+ candidate = None if revalidation_result is None else revalidation_result.get("revalidation")
2658
+ if not isinstance(candidate, Mapping):
2659
+ raise OperationalResetError("REVALIDATION_EVIDENCE_INVALID")
2660
+ allowed_keys = {
2661
+ "operation_id", "state", "writer_fence_owner", "actor", "target_digest",
2662
+ "plan_digest", "request_digest", "source_revision", "preserved_bindings_digest",
2663
+ "backup_manifest_digest", "dataset_generation", "implementation_source_revision",
2664
+ "implementation_digest", "product_version", "revalidation_digest",
2665
+ }
2666
+ if set(candidate) != allowed_keys:
2667
+ raise OperationalResetError("REVALIDATION_EVIDENCE_INVALID")
2668
+ revalidation_evidence = dict(candidate)
2669
+ blockers = []
2508
2670
  if operation.get("state") == "FAILED":
2509
2671
  blockers.append("OPERATION_FAILED_RECONCILIATION_REQUIRED")
2510
2672
  return {
@@ -2529,6 +2691,7 @@ def contract_readback(
2529
2691
  "details": {
2530
2692
  "credentials_included_in_receipt": False,
2531
2693
  "projection": "PERSISTED_PUBLIC_MAINTENANCE_STATE",
2694
+ **({"revalidation": revalidation_evidence} if revalidation_evidence is not None else {}),
2532
2695
  },
2533
2696
  }
2534
2697
 
@@ -2559,7 +2722,7 @@ def main(argv: list[str] | None = None) -> int:
2559
2722
  parser = _ReceiptArgumentParser(prog="engineering-platform-maintenance")
2560
2723
  parser.add_argument(
2561
2724
  "command",
2562
- choices=("preview", "prepare", "apply", "status", "resume", "verify", "finish", "abort"),
2725
+ choices=("preview", "prepare", "revalidate", "apply", "status", "resume", "verify", "finish", "abort"),
2563
2726
  )
2564
2727
  parser.add_argument("--data-root", type=Path, required=True)
2565
2728
  parser.add_argument("--operation-id")
@@ -2588,6 +2751,10 @@ def main(argv: list[str] | None = None) -> int:
2588
2751
  allowed_fk_findings=tuple(args.allow_operational_fk))
2589
2752
  elif args.command == "apply":
2590
2753
  result = apply(args.data_root, operation_id=args.operation_id, plan_digest=args.plan_digest)
2754
+ elif args.command == "revalidate":
2755
+ result = revalidate(
2756
+ args.data_root, operation_id=args.operation_id, plan_digest=args.plan_digest,
2757
+ )
2591
2758
  elif args.command == "resume":
2592
2759
  result = resume(args.data_root, operation_id=args.operation_id,
2593
2760
  plan_digest=args.plan_digest, backup_root=args.backup_root)
@@ -2601,6 +2768,7 @@ def main(argv: list[str] | None = None) -> int:
2601
2768
  # from the schema-owned public projection after the command completes.
2602
2769
  print(json.dumps(contract_readback(
2603
2770
  args.data_root, command=args.command, operation_id=args.operation_id,
2771
+ revalidation_result=result if args.command == "revalidate" else None,
2604
2772
  ), sort_keys=True))
2605
2773
  return 0
2606
2774
  except OperationalResetError as error:
@@ -12,7 +12,7 @@ from .storage import ENGINEERING_STORAGE_SCHEMA_VERSION
12
12
 
13
13
  SEMVER = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$")
14
14
  CONTRACT = re.compile(r"^(\d{4})\.(0[1-9]|1[0-2])$")
15
- CURRENT_PLATFORM_VERSION = "2.3.82"
15
+ CURRENT_PLATFORM_VERSION = "2.3.83"
16
16
  MANIFEST_FIELDS = frozenset(
17
17
  {
18
18
  "platform_version",
@@ -3,7 +3,7 @@
3
3
  "platform": {
4
4
  "id": "engineering-platform",
5
5
  "name": "Engineering Platform",
6
- "version": "2.3.82",
6
+ "version": "2.3.83",
7
7
  "generation": 2,
8
8
  "documentation_namespace": "engineering-platform",
9
9
  "capability_registry_version": 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-platform
3
- Version: 2.3.82
3
+ Version: 2.3.83
4
4
  Summary: Local-first Engineering Platform execution operations runtime
5
5
  Author: Peter van Tol
6
6
  License: MIT