engineering-platform 2.2.0__py3-none-any.whl
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.
- engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +32 -0
- engineering_platform/ENGINEERING_PLATFORM_VERSION.json +15 -0
- engineering_platform/__init__.py +1 -0
- engineering_platform/__main__.py +7 -0
- engineering_platform/agent_state.py +530 -0
- engineering_platform/agent_trust.py +174 -0
- engineering_platform/assets/dashboard.css +1317 -0
- engineering_platform/assets/dashboard.js +8534 -0
- engineering_platform/assets/dashboard_locales.mjs +4049 -0
- engineering_platform/assets/dashboard_status_store.mjs +41 -0
- engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- engineering_platform/assets/operations-console/icon-dark.png +0 -0
- engineering_platform/assets/operations-console/icon-light.png +0 -0
- engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- engineering_platform/assets/operations-console/manifest.webmanifest +11 -0
- engineering_platform/capability_preflight.py +285 -0
- engineering_platform/capability_review.py +261 -0
- engineering_platform/central_data_transfer.py +195 -0
- engineering_platform/central_database.py +245 -0
- engineering_platform/central_store_migration.py +1672 -0
- engineering_platform/codex_capacity.py +81 -0
- engineering_platform/codex_chat.py +226 -0
- engineering_platform/codex_observability.py +153 -0
- engineering_platform/component_lock.py +40 -0
- engineering_platform/component_logging.py +420 -0
- engineering_platform/console_presentation.py +14 -0
- engineering_platform/console_route_ownership.py +83 -0
- engineering_platform/contracts/__init__.py +38 -0
- engineering_platform/contracts/ep_consumer.py +391 -0
- engineering_platform/contracts/models.py +105 -0
- engineering_platform/contracts/projection.py +401 -0
- engineering_platform/dashboard_browser_validation.py +206 -0
- engineering_platform/dashboard_state.py +630 -0
- engineering_platform/dashboard_supervisor.swift +105 -0
- engineering_platform/dashboard_translation.py +129 -0
- engineering_platform/dependabot_producer.py +349 -0
- engineering_platform/drift_diagnostics.py +144 -0
- engineering_platform/emergency_recovery.py +268 -0
- engineering_platform/engineering_memory.py +139 -0
- engineering_platform/ep_consumer_credentials.py +473 -0
- engineering_platform/evidence_projection.py +213 -0
- engineering_platform/execution_activity.py +218 -0
- engineering_platform/execution_context.py +132 -0
- engineering_platform/execution_errors.py +42 -0
- engineering_platform/execution_evidence.py +24 -0
- engineering_platform/execution_executor.py +730 -0
- engineering_platform/execution_finalization.py +44 -0
- engineering_platform/execution_host.py +3306 -0
- engineering_platform/execution_lease.py +365 -0
- engineering_platform/execution_lifecycle.py +447 -0
- engineering_platform/execution_models.py +43 -0
- engineering_platform/execution_readiness.py +166 -0
- engineering_platform/execution_reporting.py +1607 -0
- engineering_platform/execution_repository.py +253 -0
- engineering_platform/execution_timeout_policy.py +56 -0
- engineering_platform/execution_timing.py +440 -0
- engineering_platform/execution_transaction.py +28 -0
- engineering_platform/external_producer_binding.py +235 -0
- engineering_platform/file_inbox.py +249 -0
- engineering_platform/forensic_attribution.py +338 -0
- engineering_platform/forensic_attribution_v2.py +134 -0
- engineering_platform/forensic_delta.py +299 -0
- engineering_platform/golden_scenario.py +63 -0
- engineering_platform/historical_dashboard_configuration.py +171 -0
- engineering_platform/host_admin.py +199 -0
- engineering_platform/host_preflight.py +231 -0
- engineering_platform/installation_relocation.py +122 -0
- engineering_platform/investigation_ledger.py +89 -0
- engineering_platform/legacy_inbox_migration.py +79 -0
- engineering_platform/lifecycle_worker.py +223 -0
- engineering_platform/live_status.py +267 -0
- engineering_platform/local_api.py +209 -0
- engineering_platform/local_api_keychain.py +51 -0
- engineering_platform/local_repository_binding.py +138 -0
- engineering_platform/managed_autonomy.py +509 -0
- engineering_platform/managed_codex_runtime.py +105 -0
- engineering_platform/parity_context.py +203 -0
- engineering_platform/parity_lifecycle_dispatcher.py +488 -0
- engineering_platform/platform_admin.py +13 -0
- engineering_platform/platform_api.py +428 -0
- engineering_platform/platform_bootstrap.py +385 -0
- engineering_platform/platform_components.py +65 -0
- engineering_platform/platform_version.py +171 -0
- engineering_platform/pr_check_repair.py +276 -0
- engineering_platform/pr_evidence_backfill.py +278 -0
- engineering_platform/producer.py +209 -0
- engineering_platform/project_agent.py +366 -0
- engineering_platform/project_agent_service.py +244 -0
- engineering_platform/project_topology.py +126 -0
- engineering_platform/prompt_history.py +591 -0
- engineering_platform/provider_context.py +136 -0
- engineering_platform/provider_context_benchmark.py +41 -0
- engineering_platform/provider_context_scope.py +90 -0
- engineering_platform/provider_interruption.py +168 -0
- engineering_platform/provider_process_identity.py +80 -0
- engineering_platform/provider_readiness.py +138 -0
- engineering_platform/provider_recovery.py +647 -0
- engineering_platform/provider_usage.py +497 -0
- engineering_platform/providers.py +471 -0
- engineering_platform/qualification.py +220 -0
- engineering_platform/recommendation_handoff.py +238 -0
- engineering_platform/report_analysis.py +193 -0
- engineering_platform/repository_attachment.py +171 -0
- engineering_platform/repository_handoff.py +95 -0
- engineering_platform/resources.py +38 -0
- engineering_platform/reviewer_evidence.py +70 -0
- engineering_platform/schemas/repository-attachment.schema.json +61 -0
- engineering_platform/server.py +3679 -0
- engineering_platform/server_console_services.py +2024 -0
- engineering_platform/server_relay.py +172 -0
- engineering_platform/server_service.py +122 -0
- engineering_platform/status_model.py +135 -0
- engineering_platform/status_reconciliation.py +34 -0
- engineering_platform/storage.py +2440 -0
- engineering_platform/submission_cli.py +77 -0
- engineering_platform/submission_intake.py +45 -0
- engineering_platform/submission_service.py +317 -0
- engineering_platform/telemetry.py +951 -0
- engineering_platform/templates/workspace-config.json +25 -0
- engineering_platform/validation_identity.py +50 -0
- engineering_platform/validation_profile.py +211 -0
- engineering_platform/workspace_preflight.py +263 -0
- engineering_platform/worktree_provenance.py +147 -0
- engineering_platform/worktree_tooling.py +18 -0
- engineering_platform-2.2.0.dist-info/METADATA +18 -0
- engineering_platform-2.2.0.dist-info/RECORD +130 -0
- engineering_platform-2.2.0.dist-info/WHEEL +5 -0
- engineering_platform-2.2.0.dist-info/entry_points.txt +6 -0
- engineering_platform-2.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 2,
|
|
3
|
+
"platform": {
|
|
4
|
+
"id": "engineering-platform",
|
|
5
|
+
"name": "Engineering Platform",
|
|
6
|
+
"version": "2.2.0",
|
|
7
|
+
"generation": 2,
|
|
8
|
+
"documentation_namespace": "engineering-platform",
|
|
9
|
+
"capability_registry_version": 1
|
|
10
|
+
},
|
|
11
|
+
"workspace": {
|
|
12
|
+
"id": "engineering-platform",
|
|
13
|
+
"name": "Engineering Platform",
|
|
14
|
+
"repository": {"provider": "github", "owner": "pcvantol", "name": "engineering-platform", "default_branch": "main"},
|
|
15
|
+
"branding": {"dashboard_title": "EP Operations"},
|
|
16
|
+
"workspace_authorization": {
|
|
17
|
+
"allowed_roots": [],
|
|
18
|
+
"allowed_repositories": [],
|
|
19
|
+
"denied_repositories": [],
|
|
20
|
+
"symlink_policy": "reject",
|
|
21
|
+
"case_sensitivity": "host"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"providers": {
|
|
25
|
+
"runtime": "codex_cli",
|
|
26
|
+
"repository": "github",
|
|
27
|
+
"service_manager": "launchd",
|
|
28
|
+
"remote_submission": "icloud_inbox",
|
|
29
|
+
"private_remote_access": "tailscale",
|
|
30
|
+
"dashboard": "private_http"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bootstrap_contract": "2026.12",
|
|
3
|
+
"checkpoint_format": 1,
|
|
4
|
+
"dashboard_version": "2.2.0",
|
|
5
|
+
"handoff_protocol": 1,
|
|
6
|
+
"memory_format": 2,
|
|
7
|
+
"minimum_codex_cli": "0.146.0",
|
|
8
|
+
"inbox_protocol": 1,
|
|
9
|
+
"platform_version": "2.2.0",
|
|
10
|
+
"report_format": 2,
|
|
11
|
+
"runner_version": "2.2.0",
|
|
12
|
+
"status_model": 1,
|
|
13
|
+
"storage_schema": 41,
|
|
14
|
+
"watcher_version": "2.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Local-only, repository-grounded engineering transaction runner."""
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
"""Validated, atomic local checkpoints for bounded engineering transactions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import re
|
|
10
|
+
import sqlite3
|
|
11
|
+
import tempfile
|
|
12
|
+
|
|
13
|
+
from .storage import (
|
|
14
|
+
CENTRAL_OPERATIONAL_DATABASE_ENVIRONMENT,
|
|
15
|
+
EngineeringStorageError,
|
|
16
|
+
open_storage,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
SCHEMA_VERSION = 1
|
|
21
|
+
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
|
+
RUN_ID_PATTERN = re.compile(r"^[a-z0-9][a-z0-9-]{0,63}$")
|
|
23
|
+
MAX_DIAGNOSTIC_LENGTH = 500
|
|
24
|
+
MAX_COMMIT_EVIDENCE_RECORDS = 48
|
|
25
|
+
COMMIT_EVIDENCE_FIELDS = frozenset({"phase", "observed_at", "commit_sha", "description"})
|
|
26
|
+
COMMIT_EVIDENCE_TIMESTAMP_PATTERN = re.compile(
|
|
27
|
+
r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?\+00:00"
|
|
28
|
+
)
|
|
29
|
+
MUTATING_COMMIT_PHASES = frozenset({
|
|
30
|
+
"EXECUTE_AGENT",
|
|
31
|
+
"LOCAL_REPOSITORY_VALIDATION",
|
|
32
|
+
"QUALITY_CONTROL_AGENT",
|
|
33
|
+
"REPAIR_AGENT",
|
|
34
|
+
"FINALIZE_AGENT",
|
|
35
|
+
"RECONCILE_AGENT",
|
|
36
|
+
"WAIT_FOR_OPERATOR_MERGE",
|
|
37
|
+
})
|
|
38
|
+
COMMIT_EVIDENCE_DESCRIPTIONS = frozenset({
|
|
39
|
+
"implementation_agent_commit_verified",
|
|
40
|
+
"genesis_implementation_commit_verified",
|
|
41
|
+
"local_repository_validation_commit_verified",
|
|
42
|
+
"quality_control_commit_verified",
|
|
43
|
+
"pull_request_repair_commit_verified",
|
|
44
|
+
"finalization_commit_verified",
|
|
45
|
+
"end_reconciliation_commit_verified",
|
|
46
|
+
"implementation_merge_verified",
|
|
47
|
+
"finalization_merge_verified",
|
|
48
|
+
"reconciliation_merge_verified",
|
|
49
|
+
})
|
|
50
|
+
SENSITIVE_DIAGNOSTIC_PATTERN = re.compile(
|
|
51
|
+
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+"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class StateError(ValueError):
|
|
56
|
+
"""Raised when local advisory state is missing, malformed, or unsafe."""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def redact_diagnostic(value: str, *, limit: int = MAX_DIAGNOSTIC_LENGTH) -> str:
|
|
60
|
+
"""Return bounded human-readable text that is safe to display or persist."""
|
|
61
|
+
if not isinstance(value, str):
|
|
62
|
+
return "Diagnostic omitted because it was not valid text."
|
|
63
|
+
compact = " ".join(value.replace("\x00", " ").split())
|
|
64
|
+
compact = SENSITIVE_DIAGNOSTIC_PATTERN.sub("[REDACTED]", compact)
|
|
65
|
+
return compact[:limit]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def is_valid_commit_evidence_record(value: object) -> bool:
|
|
69
|
+
"""Return whether one persisted commit-timeline record is strict and safe.
|
|
70
|
+
|
|
71
|
+
This is deliberately the sole schema predicate for the append-only commit
|
|
72
|
+
timeline. Runtime writers and read-only dashboard projections share it, so
|
|
73
|
+
merge, repair and other mutating phases cannot drift into incompatible
|
|
74
|
+
evidence shapes.
|
|
75
|
+
"""
|
|
76
|
+
return (
|
|
77
|
+
isinstance(value, dict)
|
|
78
|
+
and set(value) == COMMIT_EVIDENCE_FIELDS
|
|
79
|
+
and value.get("phase") in MUTATING_COMMIT_PHASES
|
|
80
|
+
and isinstance(value.get("observed_at"), str)
|
|
81
|
+
and bool(COMMIT_EVIDENCE_TIMESTAMP_PATTERN.fullmatch(value["observed_at"]))
|
|
82
|
+
and isinstance(value.get("commit_sha"), str)
|
|
83
|
+
and bool(re.fullmatch(r"[0-9a-f]{40}", value["commit_sha"]))
|
|
84
|
+
and isinstance(value.get("description"), str)
|
|
85
|
+
and value["description"] in COMMIT_EVIDENCE_DESCRIPTIONS
|
|
86
|
+
and len(value["description"]) <= MAX_DIAGNOSTIC_LENGTH
|
|
87
|
+
and value["description"] == redact_diagnostic(value["description"])
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def verified_commit_evidence_record(
|
|
92
|
+
*, phase: str, observed_at: str, commit_sha: str, description: str
|
|
93
|
+
) -> dict[str, str]:
|
|
94
|
+
"""Build one canonical verified-commit record or reject unsafe evidence."""
|
|
95
|
+
record = {
|
|
96
|
+
"phase": phase,
|
|
97
|
+
"observed_at": observed_at,
|
|
98
|
+
"commit_sha": commit_sha,
|
|
99
|
+
"description": description,
|
|
100
|
+
}
|
|
101
|
+
if not is_valid_commit_evidence_record(record):
|
|
102
|
+
raise StateError("commit evidence record is invalid or unsafe")
|
|
103
|
+
return record
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass(frozen=True)
|
|
107
|
+
class TransactionState:
|
|
108
|
+
run_id: str
|
|
109
|
+
repository: str
|
|
110
|
+
prompt_path: str
|
|
111
|
+
phase: str
|
|
112
|
+
branch: str | None = None
|
|
113
|
+
pull_request: int | None = None
|
|
114
|
+
last_verified_sha: str | None = None
|
|
115
|
+
next_action: str = "invoke_agent"
|
|
116
|
+
terminal_condition: str = "repository_reconciled"
|
|
117
|
+
diagnostic: str | None = None
|
|
118
|
+
owner_authorized: bool = False
|
|
119
|
+
transaction_kind: str = "IMPLEMENTATION"
|
|
120
|
+
execution_mode: str = "MANAGED"
|
|
121
|
+
action_intent: str = "MUTATING_DELIVERY"
|
|
122
|
+
genesis_repository_path: str | None = None
|
|
123
|
+
genesis_commit_sha: str | None = None
|
|
124
|
+
implementation_branch: str | None = None
|
|
125
|
+
implementation_pull_request: int | None = None
|
|
126
|
+
implementation_head_sha: str | None = None
|
|
127
|
+
implementation_merge_commit: str | None = None
|
|
128
|
+
finalization_branch: str | None = None
|
|
129
|
+
finalization_pull_request: int | None = None
|
|
130
|
+
finalization_head_sha: str | None = None
|
|
131
|
+
finalization_merge_commit: str | None = None
|
|
132
|
+
reconciliation_pull_request: int | None = None
|
|
133
|
+
latest_repository_evidence: str | None = None
|
|
134
|
+
latest_github_evidence: str | None = None
|
|
135
|
+
agent_execution_seconds: float | None = None
|
|
136
|
+
validation_evidence: tuple[dict[str, str], ...] = ()
|
|
137
|
+
quality_evidence: tuple[dict[str, str], ...] = ()
|
|
138
|
+
repair_iterations: int = 0
|
|
139
|
+
repair_audit: tuple[dict[str, str], ...] = ()
|
|
140
|
+
local_validation_iterations: int = 0
|
|
141
|
+
local_validation_audit: tuple[dict[str, str], ...] = ()
|
|
142
|
+
commit_evidence: tuple[dict[str, str], ...] = ()
|
|
143
|
+
waiting_for_merge_since: str | None = None
|
|
144
|
+
auth_recovery_phase: str | None = None
|
|
145
|
+
auth_recovery_next_action: str | None = None
|
|
146
|
+
auth_recovery_providers: tuple[str, ...] = ()
|
|
147
|
+
admission_decision: str = "NOT_STARTED"
|
|
148
|
+
admission_completed_at: str | None = None
|
|
149
|
+
admission_evidence_source: str | None = None
|
|
150
|
+
# A run-bound, append-only record of the one automatic provider restart.
|
|
151
|
+
# This is checkpoint data, not a database migration: old rows simply read
|
|
152
|
+
# with an empty ledger.
|
|
153
|
+
provider_recovery_attempts: tuple[dict[str, str], ...] = ()
|
|
154
|
+
terminal: bool = False
|
|
155
|
+
schema_version: int = SCHEMA_VERSION
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def from_dict(cls, raw: object) -> "TransactionState":
|
|
159
|
+
if not isinstance(raw, dict):
|
|
160
|
+
raise StateError("checkpoint must be a JSON object")
|
|
161
|
+
expected = {field.name for field in cls.__dataclass_fields__.values()}
|
|
162
|
+
defaults = {
|
|
163
|
+
"diagnostic": None, "owner_authorized": False, "transaction_kind": "IMPLEMENTATION",
|
|
164
|
+
"execution_mode": "MANAGED", "genesis_repository_path": None, "genesis_commit_sha": None,
|
|
165
|
+
"action_intent": "MUTATING_DELIVERY",
|
|
166
|
+
"implementation_branch": None, "implementation_pull_request": None,
|
|
167
|
+
"implementation_head_sha": None, "implementation_merge_commit": None,
|
|
168
|
+
"finalization_branch": None, "finalization_pull_request": None,
|
|
169
|
+
"finalization_head_sha": None, "finalization_merge_commit": None,
|
|
170
|
+
"reconciliation_pull_request": None,
|
|
171
|
+
"latest_repository_evidence": None, "latest_github_evidence": None,
|
|
172
|
+
"agent_execution_seconds": None,
|
|
173
|
+
"validation_evidence": (),
|
|
174
|
+
"quality_evidence": (),
|
|
175
|
+
"repair_iterations": 0,
|
|
176
|
+
"repair_audit": (),
|
|
177
|
+
"local_validation_iterations": 0,
|
|
178
|
+
"local_validation_audit": (),
|
|
179
|
+
"commit_evidence": (),
|
|
180
|
+
"waiting_for_merge_since": None,
|
|
181
|
+
"auth_recovery_phase": None,
|
|
182
|
+
"auth_recovery_next_action": None,
|
|
183
|
+
"auth_recovery_providers": (),
|
|
184
|
+
"admission_decision": "NOT_STARTED",
|
|
185
|
+
"admission_completed_at": None,
|
|
186
|
+
"admission_evidence_source": None,
|
|
187
|
+
"provider_recovery_attempts": (),
|
|
188
|
+
}
|
|
189
|
+
if set(raw).issubset(expected) and set(raw) | set(defaults) == expected:
|
|
190
|
+
raw = {**defaults, **raw}
|
|
191
|
+
elif set(raw) != expected:
|
|
192
|
+
raise StateError("checkpoint fields are incompatible")
|
|
193
|
+
if isinstance(raw.get("validation_evidence"), list):
|
|
194
|
+
raw = {**raw, "validation_evidence": tuple(raw["validation_evidence"])}
|
|
195
|
+
if isinstance(raw.get("quality_evidence"), list):
|
|
196
|
+
raw = {**raw, "quality_evidence": tuple(raw["quality_evidence"])}
|
|
197
|
+
if isinstance(raw.get("repair_audit"), list):
|
|
198
|
+
raw = {**raw, "repair_audit": tuple(raw["repair_audit"])}
|
|
199
|
+
if isinstance(raw.get("local_validation_audit"), list):
|
|
200
|
+
raw = {**raw, "local_validation_audit": tuple(raw["local_validation_audit"])}
|
|
201
|
+
if isinstance(raw.get("commit_evidence"), list):
|
|
202
|
+
raw = {**raw, "commit_evidence": tuple(raw["commit_evidence"])}
|
|
203
|
+
if isinstance(raw.get("auth_recovery_providers"), list):
|
|
204
|
+
raw = {**raw, "auth_recovery_providers": tuple(raw["auth_recovery_providers"])}
|
|
205
|
+
if isinstance(raw.get("provider_recovery_attempts"), list):
|
|
206
|
+
raw = {**raw, "provider_recovery_attempts": tuple(raw["provider_recovery_attempts"])}
|
|
207
|
+
try:
|
|
208
|
+
state = cls(**raw)
|
|
209
|
+
except TypeError as error:
|
|
210
|
+
raise StateError("checkpoint fields are invalid") from error
|
|
211
|
+
if state.schema_version != SCHEMA_VERSION:
|
|
212
|
+
raise StateError("unsupported checkpoint schema version")
|
|
213
|
+
if not RUN_ID_PATTERN.fullmatch(state.run_id):
|
|
214
|
+
raise StateError("checkpoint run_id is invalid")
|
|
215
|
+
if not all(isinstance(value, str) and value for value in (state.repository, state.prompt_path, state.phase, state.next_action, state.terminal_condition)):
|
|
216
|
+
raise StateError("checkpoint identity or phase is invalid")
|
|
217
|
+
if state.phase not in PHASES or (state.branch is not None and not isinstance(state.branch, str)):
|
|
218
|
+
raise StateError("checkpoint phase or branch is invalid")
|
|
219
|
+
if state.pull_request is not None and (not isinstance(state.pull_request, int) or state.pull_request < 1):
|
|
220
|
+
raise StateError("checkpoint pull_request is invalid")
|
|
221
|
+
if state.last_verified_sha is not None and not re.fullmatch(r"[0-9a-f]{40}", state.last_verified_sha):
|
|
222
|
+
raise StateError("checkpoint last_verified_sha is invalid")
|
|
223
|
+
if state.diagnostic is not None and (not isinstance(state.diagnostic, str) or not state.diagnostic or state.diagnostic != redact_diagnostic(state.diagnostic)):
|
|
224
|
+
raise StateError("checkpoint diagnostic is invalid or unsafe")
|
|
225
|
+
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"}:
|
|
226
|
+
raise StateError("checkpoint authorization or transaction kind is invalid")
|
|
227
|
+
if state.admission_decision not in {"NOT_STARTED", "PASS", "FAIL", "BLOCKED", "UNAVAILABLE"}:
|
|
228
|
+
raise StateError("checkpoint admission decision is invalid")
|
|
229
|
+
if state.admission_decision == "PASS" and not isinstance(state.admission_completed_at, str):
|
|
230
|
+
raise StateError("passed admission requires a completion timestamp")
|
|
231
|
+
if state.admission_completed_at is not None and not isinstance(state.admission_completed_at, str):
|
|
232
|
+
raise StateError("checkpoint admission completion timestamp is invalid")
|
|
233
|
+
if state.admission_evidence_source is not None and state.admission_evidence_source not in {"WATCHER", "RUNNER"}:
|
|
234
|
+
raise StateError("checkpoint admission evidence source is invalid")
|
|
235
|
+
recovery_fields = {"original_invocation_id", "replacement_invocation_id", "phase", "classification", "eligibility", "result", "requested_at", "started_at", "completed_at"}
|
|
236
|
+
if (
|
|
237
|
+
not isinstance(state.provider_recovery_attempts, tuple)
|
|
238
|
+
or len(state.provider_recovery_attempts) > 1
|
|
239
|
+
or any(
|
|
240
|
+
not isinstance(item, dict) or set(item) != recovery_fields
|
|
241
|
+
or any(not isinstance(value, str) or not value or len(value) > 160 or value != redact_diagnostic(value, limit=160) for value in item.values())
|
|
242
|
+
or item["classification"] != "provider_turn_interrupted"
|
|
243
|
+
or item["eligibility"] not in {"ELIGIBLE", "INELIGIBLE", "PRECHECK_FAILED", "CANCELLED"}
|
|
244
|
+
or item["result"] not in {"RECOVERY_AVAILABLE", "ACTIVE", "RECOVERED", "INTERRUPTED_AGAIN", "INELIGIBLE", "PRECHECK_FAILED", "CANCELLED", "PROVIDER_FAILED"}
|
|
245
|
+
for item in state.provider_recovery_attempts
|
|
246
|
+
)
|
|
247
|
+
):
|
|
248
|
+
raise StateError("checkpoint provider recovery ledger is invalid or unsafe")
|
|
249
|
+
if state.genesis_repository_path is not None and (not isinstance(state.genesis_repository_path, str) or not Path(state.genesis_repository_path).is_absolute()):
|
|
250
|
+
raise StateError("genesis repository path is invalid")
|
|
251
|
+
if state.genesis_commit_sha is not None and (not isinstance(state.genesis_commit_sha, str) or not re.fullmatch(r"[0-9a-f]{40}", state.genesis_commit_sha)):
|
|
252
|
+
raise StateError("genesis commit SHA is invalid")
|
|
253
|
+
optional_sha_fields = (state.implementation_head_sha, state.implementation_merge_commit, state.finalization_head_sha, state.finalization_merge_commit)
|
|
254
|
+
if any(value is not None and (not isinstance(value, str) or not re.fullmatch(r"[0-9a-f]{40}", value)) for value in optional_sha_fields):
|
|
255
|
+
raise StateError("checkpoint lifecycle SHA is invalid")
|
|
256
|
+
optional_pr_fields = (state.implementation_pull_request, state.finalization_pull_request, state.reconciliation_pull_request)
|
|
257
|
+
if any(value is not None and (not isinstance(value, int) or value < 1) for value in optional_pr_fields):
|
|
258
|
+
raise StateError("checkpoint lifecycle pull request is invalid")
|
|
259
|
+
if not isinstance(state.repair_iterations, int) or state.repair_iterations < 0:
|
|
260
|
+
raise StateError("checkpoint repair iteration count is invalid")
|
|
261
|
+
audit_fields = {"iteration", "observed_at", "failed_checks", "proposed_action", "agent_summary", "commit_sha", "outcome"}
|
|
262
|
+
if not isinstance(state.local_validation_iterations, int) or not 0 <= state.local_validation_iterations <= 3:
|
|
263
|
+
raise StateError("checkpoint local validation iteration count is invalid")
|
|
264
|
+
if (
|
|
265
|
+
not isinstance(state.local_validation_audit, tuple)
|
|
266
|
+
or len(state.local_validation_audit) > 3
|
|
267
|
+
or any(
|
|
268
|
+
not isinstance(item, dict) or set(item) != audit_fields
|
|
269
|
+
or not all(isinstance(value, str) and value and len(value) <= MAX_DIAGNOSTIC_LENGTH and value == redact_diagnostic(value) for value in item.values())
|
|
270
|
+
or not item["iteration"].isdigit() or int(item["iteration"]) < 1
|
|
271
|
+
or item["outcome"] not in {"validated", "validation_failed", "agent_failed"}
|
|
272
|
+
or (item["commit_sha"] != "not_recorded" and not re.fullmatch(r"[0-9a-f]{40}", item["commit_sha"]))
|
|
273
|
+
for item in state.local_validation_audit
|
|
274
|
+
)
|
|
275
|
+
):
|
|
276
|
+
raise StateError("checkpoint local validation audit is invalid or unsafe")
|
|
277
|
+
if (
|
|
278
|
+
not isinstance(state.repair_audit, tuple)
|
|
279
|
+
or len(state.repair_audit) > 3
|
|
280
|
+
or any(
|
|
281
|
+
not isinstance(item, dict) or set(item) != audit_fields
|
|
282
|
+
or not all(isinstance(value, str) and value and len(value) <= MAX_DIAGNOSTIC_LENGTH and value == redact_diagnostic(value) for value in item.values())
|
|
283
|
+
or not item["iteration"].isdigit() or int(item["iteration"]) < 1
|
|
284
|
+
or item["outcome"] not in {"planned", "submitted_for_recheck", "agent_failed", "agent_timed_out"}
|
|
285
|
+
or (item["commit_sha"] != "not_recorded" and not re.fullmatch(r"[0-9a-f]{40}", item["commit_sha"]))
|
|
286
|
+
for item in state.repair_audit
|
|
287
|
+
)
|
|
288
|
+
):
|
|
289
|
+
raise StateError("checkpoint repair audit is invalid or unsafe")
|
|
290
|
+
if (
|
|
291
|
+
not isinstance(state.commit_evidence, tuple)
|
|
292
|
+
or len(state.commit_evidence) > MAX_COMMIT_EVIDENCE_RECORDS
|
|
293
|
+
or any(
|
|
294
|
+
not is_valid_commit_evidence_record(item)
|
|
295
|
+
for item in state.commit_evidence
|
|
296
|
+
)
|
|
297
|
+
or len({(item["phase"], item["commit_sha"]) for item in state.commit_evidence}) != len(state.commit_evidence)
|
|
298
|
+
):
|
|
299
|
+
raise StateError("checkpoint commit evidence is invalid or unsafe")
|
|
300
|
+
if state.waiting_for_merge_since is not None and (
|
|
301
|
+
not isinstance(state.waiting_for_merge_since, str)
|
|
302
|
+
or len(state.waiting_for_merge_since) > 80
|
|
303
|
+
):
|
|
304
|
+
raise StateError("checkpoint merge wait timestamp is invalid")
|
|
305
|
+
if state.auth_recovery_phase is not None and state.auth_recovery_phase not in PHASES:
|
|
306
|
+
raise StateError("checkpoint auth recovery phase is invalid")
|
|
307
|
+
if state.auth_recovery_next_action is not None and (
|
|
308
|
+
not isinstance(state.auth_recovery_next_action, str) or not state.auth_recovery_next_action
|
|
309
|
+
):
|
|
310
|
+
raise StateError("checkpoint auth recovery action is invalid")
|
|
311
|
+
if (
|
|
312
|
+
not isinstance(state.auth_recovery_providers, tuple)
|
|
313
|
+
or any(provider not in {"CODEX", "GITHUB"} for provider in state.auth_recovery_providers)
|
|
314
|
+
or len(set(state.auth_recovery_providers)) != len(state.auth_recovery_providers)
|
|
315
|
+
or (state.auth_recovery_phase is None) != (not state.auth_recovery_providers)
|
|
316
|
+
):
|
|
317
|
+
raise StateError("checkpoint auth recovery providers are invalid")
|
|
318
|
+
for value in (state.latest_repository_evidence, state.latest_github_evidence):
|
|
319
|
+
if value is not None and (not isinstance(value, str) or len(value) > MAX_DIAGNOSTIC_LENGTH or value != redact_diagnostic(value)):
|
|
320
|
+
raise StateError("checkpoint evidence is invalid or unsafe")
|
|
321
|
+
if state.agent_execution_seconds is not None and (
|
|
322
|
+
isinstance(state.agent_execution_seconds, bool)
|
|
323
|
+
or not isinstance(state.agent_execution_seconds, (int, float))
|
|
324
|
+
or not 0 <= state.agent_execution_seconds <= 86_400
|
|
325
|
+
):
|
|
326
|
+
raise StateError("checkpoint agent execution duration is invalid")
|
|
327
|
+
if (
|
|
328
|
+
not isinstance(state.validation_evidence, tuple)
|
|
329
|
+
or len(state.validation_evidence) > 12
|
|
330
|
+
or any(
|
|
331
|
+
not isinstance(item, dict)
|
|
332
|
+
or set(item) != {"command", "result"}
|
|
333
|
+
or any(
|
|
334
|
+
not isinstance(value, str)
|
|
335
|
+
or not value
|
|
336
|
+
or len(value) > 240
|
|
337
|
+
or value != redact_diagnostic(value, limit=240)
|
|
338
|
+
for value in item.values()
|
|
339
|
+
)
|
|
340
|
+
for item in state.validation_evidence
|
|
341
|
+
)
|
|
342
|
+
):
|
|
343
|
+
raise StateError("checkpoint validation evidence is invalid or unsafe")
|
|
344
|
+
quality_activities = {"REFACTOR", "TEST_COVERAGE", "DOCUMENTATION", "VALIDATION", "NO_CHANGE_REQUIRED"}
|
|
345
|
+
if (
|
|
346
|
+
not isinstance(state.quality_evidence, tuple)
|
|
347
|
+
or len(state.quality_evidence) > 8
|
|
348
|
+
or any(
|
|
349
|
+
not isinstance(item, dict)
|
|
350
|
+
or set(item) != {"activity", "result"}
|
|
351
|
+
or item["activity"] not in quality_activities
|
|
352
|
+
or not isinstance(item["result"], str)
|
|
353
|
+
or not item["result"]
|
|
354
|
+
or len(item["result"]) > 240
|
|
355
|
+
or item["result"] != redact_diagnostic(item["result"], limit=240)
|
|
356
|
+
for item in state.quality_evidence
|
|
357
|
+
)
|
|
358
|
+
):
|
|
359
|
+
raise StateError("checkpoint quality evidence is invalid or unsafe")
|
|
360
|
+
if not isinstance(state.terminal, bool) or state.terminal != (state.phase in {"COMPLETE", "BLOCKED", "FAILED"}):
|
|
361
|
+
raise StateError("checkpoint terminal flag conflicts with phase")
|
|
362
|
+
return state
|
|
363
|
+
|
|
364
|
+
def to_dict(self) -> dict[str, object]:
|
|
365
|
+
return asdict(self)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class StateStore:
|
|
369
|
+
"""Stores canonical transaction state in SQLite and emits JSON projections.
|
|
370
|
+
|
|
371
|
+
The run JSON files are intentionally retained for recovery tooling and
|
|
372
|
+
operator inspection, but are never consulted for normal lifecycle reads.
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
def __init__(
|
|
376
|
+
self,
|
|
377
|
+
directory: Path,
|
|
378
|
+
*,
|
|
379
|
+
central_database: Path | None = None,
|
|
380
|
+
emit_local_projection: bool = True,
|
|
381
|
+
) -> None:
|
|
382
|
+
self.directory = directory
|
|
383
|
+
# A CENTRAL lifecycle is deliberately bound to a database by its
|
|
384
|
+
# composition root. It must never rediscover that authority from the
|
|
385
|
+
# execution checkout. The directory remains only a compatibility
|
|
386
|
+
# location for legacy JSON projections.
|
|
387
|
+
self.central_database = central_database.resolve() if central_database else None
|
|
388
|
+
self.emit_local_projection = emit_local_projection
|
|
389
|
+
|
|
390
|
+
def path_for(self, run_id: str) -> Path:
|
|
391
|
+
if not RUN_ID_PATTERN.fullmatch(run_id):
|
|
392
|
+
raise StateError("run_id must use lowercase letters, digits, and hyphens")
|
|
393
|
+
return self.directory / f"{run_id}.json"
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def root(self) -> Path:
|
|
397
|
+
# StateStore is constructed with ``<root>/.engineering/engineering-runs``.
|
|
398
|
+
return self.directory.parent.parent
|
|
399
|
+
|
|
400
|
+
def _open(self, *, create: bool) -> sqlite3.Connection:
|
|
401
|
+
if self.central_database is None:
|
|
402
|
+
return open_storage(self.root, create=create)
|
|
403
|
+
if not self.central_database.is_file():
|
|
404
|
+
raise StateError("CENTRAL lifecycle database is unavailable")
|
|
405
|
+
try:
|
|
406
|
+
connection = sqlite3.connect(
|
|
407
|
+
self.central_database if create else f"file:{self.central_database}?mode=rw",
|
|
408
|
+
uri=not create,
|
|
409
|
+
isolation_level=None,
|
|
410
|
+
)
|
|
411
|
+
connection.execute("PRAGMA foreign_keys=ON")
|
|
412
|
+
connection.execute("PRAGMA busy_timeout=10000")
|
|
413
|
+
return connection
|
|
414
|
+
except sqlite3.DatabaseError as error:
|
|
415
|
+
raise StateError("CENTRAL lifecycle database is unavailable") from error
|
|
416
|
+
|
|
417
|
+
def run_ids(self) -> tuple[str, ...]:
|
|
418
|
+
"""Return canonical run identities without consulting JSON shadows."""
|
|
419
|
+
try:
|
|
420
|
+
connection = self._open(create=False)
|
|
421
|
+
try:
|
|
422
|
+
return tuple(str(row[0]) for row in connection.execute(
|
|
423
|
+
"SELECT run_id FROM engineering_transactions ORDER BY updated_at,run_id"
|
|
424
|
+
))
|
|
425
|
+
finally:
|
|
426
|
+
connection.close()
|
|
427
|
+
except (EngineeringStorageError, StateError, sqlite3.DatabaseError) as error:
|
|
428
|
+
raise StateError("canonical engineering storage is unavailable") from error
|
|
429
|
+
|
|
430
|
+
def load(self, run_id: str) -> TransactionState:
|
|
431
|
+
try:
|
|
432
|
+
connection = self._open(create=False)
|
|
433
|
+
try:
|
|
434
|
+
row = connection.execute(
|
|
435
|
+
"SELECT payload FROM engineering_transactions WHERE run_id=?", (run_id,)
|
|
436
|
+
).fetchone()
|
|
437
|
+
finally:
|
|
438
|
+
connection.close()
|
|
439
|
+
except EngineeringStorageError as error:
|
|
440
|
+
raise StateError("canonical engineering storage is unavailable") from error
|
|
441
|
+
if not row:
|
|
442
|
+
raise StateError(f"no checkpoint exists for run_id {run_id}")
|
|
443
|
+
try:
|
|
444
|
+
return TransactionState.from_dict(json.loads(row[0]))
|
|
445
|
+
except (TypeError, json.JSONDecodeError) as error:
|
|
446
|
+
raise StateError("canonical checkpoint is corrupt") from error
|
|
447
|
+
|
|
448
|
+
def save(self, state: TransactionState) -> Path:
|
|
449
|
+
path = self.path_for(state.run_id)
|
|
450
|
+
canonical = json.dumps(state.to_dict(), separators=(",", ":"), sort_keys=True)
|
|
451
|
+
try:
|
|
452
|
+
connection = self._open(create=True)
|
|
453
|
+
try:
|
|
454
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
455
|
+
connection.execute(
|
|
456
|
+
"INSERT INTO engineering_transactions(run_id,payload,phase,updated_at) VALUES(?,?,?,CURRENT_TIMESTAMP) "
|
|
457
|
+
"ON CONFLICT(run_id) DO UPDATE SET payload=excluded.payload,phase=excluded.phase,updated_at=excluded.updated_at",
|
|
458
|
+
(state.run_id, canonical, state.phase),
|
|
459
|
+
)
|
|
460
|
+
connection.execute(
|
|
461
|
+
"INSERT OR IGNORE INTO execution_lifecycle_events(run_id,phase,checkpoint,recorded_at) VALUES(?,?,?,CURRENT_TIMESTAMP)",
|
|
462
|
+
(state.run_id, state.phase, canonical),
|
|
463
|
+
)
|
|
464
|
+
connection.execute("COMMIT")
|
|
465
|
+
except Exception:
|
|
466
|
+
connection.execute("ROLLBACK")
|
|
467
|
+
raise
|
|
468
|
+
finally:
|
|
469
|
+
connection.close()
|
|
470
|
+
except (EngineeringStorageError, OSError) as error:
|
|
471
|
+
raise StateError("canonical engineering storage could not save checkpoint") from error
|
|
472
|
+
# CENTRAL runs must not create a repository-local checkpoint shadow.
|
|
473
|
+
# The database row above is the sole durable state and is sufficient
|
|
474
|
+
# for restart, recovery and Console/history projections.
|
|
475
|
+
if (
|
|
476
|
+
self.central_database is not None
|
|
477
|
+
or not self.emit_local_projection
|
|
478
|
+
# Compatibility only for a preserved legacy runner injected by a
|
|
479
|
+
# caller that has not yet accepted an explicit store binding.
|
|
480
|
+
or os.environ.get(CENTRAL_OPERATIONAL_DATABASE_ENVIRONMENT)
|
|
481
|
+
):
|
|
482
|
+
return path
|
|
483
|
+
self.directory.mkdir(mode=0o700, parents=True, exist_ok=True)
|
|
484
|
+
encoded = (json.dumps(state.to_dict(), indent=2, sort_keys=True) + "\n").encode("utf-8")
|
|
485
|
+
descriptor, temporary = tempfile.mkstemp(prefix=f".{state.run_id}.", suffix=".tmp", dir=self.directory)
|
|
486
|
+
try:
|
|
487
|
+
os.fchmod(descriptor, 0o600)
|
|
488
|
+
with os.fdopen(descriptor, "wb") as handle:
|
|
489
|
+
handle.write(encoded)
|
|
490
|
+
handle.flush()
|
|
491
|
+
os.fsync(handle.fileno())
|
|
492
|
+
os.replace(temporary, path)
|
|
493
|
+
os.chmod(path, 0o600)
|
|
494
|
+
except OSError:
|
|
495
|
+
try:
|
|
496
|
+
os.unlink(temporary)
|
|
497
|
+
except FileNotFoundError:
|
|
498
|
+
pass
|
|
499
|
+
raise
|
|
500
|
+
if state.phase == "COMPLETE":
|
|
501
|
+
self._prune_completed_history()
|
|
502
|
+
return path
|
|
503
|
+
|
|
504
|
+
def remove(self, run_id: str) -> None:
|
|
505
|
+
path = self.path_for(run_id)
|
|
506
|
+
try:
|
|
507
|
+
connection = self._open(create=False)
|
|
508
|
+
try:
|
|
509
|
+
connection.execute("DELETE FROM engineering_transactions WHERE run_id=?", (run_id,))
|
|
510
|
+
finally:
|
|
511
|
+
connection.close()
|
|
512
|
+
except EngineeringStorageError as error:
|
|
513
|
+
raise StateError("canonical engineering storage is unavailable") from error
|
|
514
|
+
if self.emit_local_projection and self.central_database is None and path.exists():
|
|
515
|
+
path.unlink()
|
|
516
|
+
|
|
517
|
+
def _prune_completed_history(self) -> None:
|
|
518
|
+
try:
|
|
519
|
+
connection = self._open(create=False)
|
|
520
|
+
try:
|
|
521
|
+
rows = connection.execute(
|
|
522
|
+
"SELECT run_id FROM engineering_transactions WHERE phase='COMPLETE' ORDER BY updated_at DESC, run_id DESC LIMIT -1 OFFSET 10"
|
|
523
|
+
).fetchall()
|
|
524
|
+
finally:
|
|
525
|
+
connection.close()
|
|
526
|
+
except EngineeringStorageError:
|
|
527
|
+
return
|
|
528
|
+
# Removing a compatibility projection must never erase canonical state.
|
|
529
|
+
for (run_id,) in rows:
|
|
530
|
+
self.path_for(str(run_id)).unlink(missing_ok=True)
|