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,591 @@
|
|
|
1
|
+
"""Canonical SQLite index for completed Engineering Platform prompt runs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import sqlite3
|
|
11
|
+
|
|
12
|
+
from .storage import open_storage
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
RUN_ID_PATTERN = re.compile(r"[a-z0-9][a-z0-9-]{0,63}")
|
|
16
|
+
REPORT_RUN_ID = re.compile(r"^- Run ID: `([a-z0-9][a-z0-9-]{0,63})`$", re.MULTILINE)
|
|
17
|
+
REPORT_STATE = re.compile(r"^- Terminal state: `(COMPLETE|BLOCKED|FAILED)`$", re.MULTILINE)
|
|
18
|
+
REPORT_TIMESTAMP = re.compile(r"^- Timestamp: ([^\n]{1,80})$", re.MULTILINE)
|
|
19
|
+
REPORT_OBJECTIVE = re.compile(r"^- Objective: (.+)$", re.MULTILINE)
|
|
20
|
+
REPORT_TITLE = re.compile(r"^# (.+)$", re.MULTILINE)
|
|
21
|
+
REPORT_INCREMENT_TITLE = re.compile(r"^# Engineering Platform Increment\s+—\s+(.+)$", re.MULTILINE)
|
|
22
|
+
REPORT_COMMIT = re.compile(
|
|
23
|
+
r"^- (?:Target Commit|Genesis-commit|Implementation Merge Commit|Finalization Merge Commit): `?([0-9a-f]{7,64})`?$",
|
|
24
|
+
re.MULTILINE | re.IGNORECASE,
|
|
25
|
+
)
|
|
26
|
+
REPORT_TARGET_BRANCH = re.compile(r"^- Target Branch: `([^`\n]{1,255})`$", re.MULTILINE)
|
|
27
|
+
REPORT_EXECUTION_METADATA = {
|
|
28
|
+
"modified": re.compile(r"^- Files Modified: `(\d{1,9})`$", re.MULTILINE),
|
|
29
|
+
"created": re.compile(r"^- Files Created: `(\d{1,9})`$", re.MULTILINE),
|
|
30
|
+
"deleted": re.compile(r"^- Files Deleted: `(\d{1,9})`$", re.MULTILINE),
|
|
31
|
+
"codex_commands_executed": re.compile(r"^- Codex Commands Executed: `(\d{1,9})`$", re.MULTILINE),
|
|
32
|
+
}
|
|
33
|
+
RETRY_OF = re.compile(r"^- Retry Of: `([a-z0-9][a-z0-9-]{0,63})`$", re.MULTILINE)
|
|
34
|
+
ORIGINAL_RUN = re.compile(r"^- Original Run: `([a-z0-9][a-z0-9-]{0,63})`$", re.MULTILINE)
|
|
35
|
+
RETRY_GENERATION = re.compile(r"^- Retry Generation: `(\d+)`$", re.MULTILINE)
|
|
36
|
+
RETRY_TIMESTAMP = re.compile(r"^- Retry Timestamp: ([^\n]{1,80})$", re.MULTILINE)
|
|
37
|
+
TERMINAL_STATES = frozenset({"COMPLETE", "BLOCKED", "FAILED"})
|
|
38
|
+
RETRY_CHILD_STATES = frozenset({"QUEUED", "ACTIVE", *TERMINAL_STATES})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _safe_run_id(value: object) -> str | None:
|
|
42
|
+
return value if isinstance(value, str) and RUN_ID_PATTERN.fullmatch(value) else None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _safe_timestamp(value: object) -> str:
|
|
46
|
+
if isinstance(value, datetime):
|
|
47
|
+
return value.astimezone(timezone.utc).isoformat()
|
|
48
|
+
if isinstance(value, str) and value.strip():
|
|
49
|
+
timestamp = value.strip()[:80]
|
|
50
|
+
return re.sub(r"T(\d{2})-(\d{2})-(\d{2})Z$", r"T\1:\2:\3Z", timestamp)
|
|
51
|
+
return datetime.now(timezone.utc).isoformat()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _relative_report(root: Path, report: Path | None, *, central_database: Path | None = None) -> str | None:
|
|
55
|
+
if report is None:
|
|
56
|
+
return None
|
|
57
|
+
central = str(central_database) if central_database is not None else os.environ.get("EP_CENTRAL_OPERATIONAL_DATABASE")
|
|
58
|
+
if central:
|
|
59
|
+
try:
|
|
60
|
+
return "CENTRAL:" + str(report.resolve().relative_to(Path(central).resolve().parent / "artifacts"))
|
|
61
|
+
except (OSError, ValueError):
|
|
62
|
+
return None
|
|
63
|
+
try:
|
|
64
|
+
relative = report.resolve().relative_to((root / ".engineering" / "reports").resolve())
|
|
65
|
+
except (OSError, ValueError):
|
|
66
|
+
return None
|
|
67
|
+
return str(relative)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _safe_checkout_path(value: object) -> str | None:
|
|
71
|
+
"""Keep only an absolute, bounded terminal checkout snapshot."""
|
|
72
|
+
if not isinstance(value, (str, Path)):
|
|
73
|
+
return None
|
|
74
|
+
path = Path(value).expanduser()
|
|
75
|
+
if not path.is_absolute():
|
|
76
|
+
return None
|
|
77
|
+
resolved = str(path.resolve())
|
|
78
|
+
return resolved if len(resolved) <= 1_000 else None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _safe_tracked_file_count(value: object) -> int | None:
|
|
82
|
+
return value if isinstance(value, int) and not isinstance(value, bool) and 0 <= value <= 10_000_000 else None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _safe_target_branch(value: object) -> str | None:
|
|
86
|
+
"""Keep a bounded, single-line branch snapshot safe for presentation."""
|
|
87
|
+
if not isinstance(value, str):
|
|
88
|
+
return None
|
|
89
|
+
branch = value.strip()
|
|
90
|
+
if not branch or len(branch) > 255 or any(character in branch for character in "\0\r\n"):
|
|
91
|
+
return None
|
|
92
|
+
return branch
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def safe_execution_metadata(value: object) -> dict[str, int]:
|
|
96
|
+
"""Keep only bounded, aggregate execution counters for presentation."""
|
|
97
|
+
if not isinstance(value, dict):
|
|
98
|
+
return {}
|
|
99
|
+
return {
|
|
100
|
+
key: item
|
|
101
|
+
for key in ("modified", "created", "deleted", "codex_commands_executed")
|
|
102
|
+
for item in (value.get(key),)
|
|
103
|
+
if isinstance(item, int) and not isinstance(item, bool) and 0 <= item <= 1_000_000
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def execution_metadata_from_terminal_report(report: Path | None) -> dict[str, int]:
|
|
108
|
+
"""Read only aggregate execution counters from an authoritative report."""
|
|
109
|
+
if report is None:
|
|
110
|
+
return {}
|
|
111
|
+
try:
|
|
112
|
+
content = report.read_text(encoding="utf-8")
|
|
113
|
+
except OSError:
|
|
114
|
+
return {}
|
|
115
|
+
return safe_execution_metadata({
|
|
116
|
+
key: int(match.group(1))
|
|
117
|
+
for key, pattern in REPORT_EXECUTION_METADATA.items()
|
|
118
|
+
if (match := pattern.search(content)) is not None
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def record_prompt_execution(
|
|
123
|
+
root: Path,
|
|
124
|
+
*,
|
|
125
|
+
run_id: object,
|
|
126
|
+
terminal_state: object,
|
|
127
|
+
prompt_title: object,
|
|
128
|
+
executed_at: object,
|
|
129
|
+
report: Path | None = None,
|
|
130
|
+
git_commit: object = None,
|
|
131
|
+
retry_of: object = None,
|
|
132
|
+
original_run_id: object = None,
|
|
133
|
+
retry_generation: object = None,
|
|
134
|
+
retry_timestamp: object = None,
|
|
135
|
+
target_checkout_path: object = None,
|
|
136
|
+
tracked_file_count: object = None,
|
|
137
|
+
target_branch: object = None,
|
|
138
|
+
execution_metadata: object = None,
|
|
139
|
+
central_database: Path | None = None,
|
|
140
|
+
) -> None:
|
|
141
|
+
"""Upsert a terminal prompt projection without changing execution authority."""
|
|
142
|
+
safe_run_id = _safe_run_id(run_id)
|
|
143
|
+
if safe_run_id is None or terminal_state not in TERMINAL_STATES:
|
|
144
|
+
raise ValueError("prompt history requires a terminal Engineering Platform run")
|
|
145
|
+
title = str(prompt_title or safe_run_id).strip()[:500] or safe_run_id
|
|
146
|
+
commit = git_commit if isinstance(git_commit, str) and re.fullmatch(r"[0-9a-f]{7,64}", git_commit) else None
|
|
147
|
+
parent = _safe_run_id(retry_of)
|
|
148
|
+
original = _safe_run_id(original_run_id)
|
|
149
|
+
generation = retry_generation if isinstance(retry_generation, int) and retry_generation >= 1 else None
|
|
150
|
+
timestamp = _safe_timestamp(retry_timestamp) if parent and retry_timestamp else None
|
|
151
|
+
checkout_path = _safe_checkout_path(target_checkout_path)
|
|
152
|
+
tracked_files = _safe_tracked_file_count(tracked_file_count)
|
|
153
|
+
branch = _safe_target_branch(target_branch)
|
|
154
|
+
metadata = safe_execution_metadata(execution_metadata) or execution_metadata_from_terminal_report(report)
|
|
155
|
+
if parent is None:
|
|
156
|
+
original = generation = timestamp = None
|
|
157
|
+
elif original is None:
|
|
158
|
+
original = parent
|
|
159
|
+
elif generation is None:
|
|
160
|
+
generation = 1
|
|
161
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
162
|
+
if central_database is None:
|
|
163
|
+
connection = open_storage(root)
|
|
164
|
+
else:
|
|
165
|
+
connection = sqlite3.connect(central_database.resolve(), isolation_level=None)
|
|
166
|
+
connection.execute("PRAGMA foreign_keys=ON")
|
|
167
|
+
try:
|
|
168
|
+
connection.execute(
|
|
169
|
+
"""
|
|
170
|
+
INSERT INTO prompt_execution_history(
|
|
171
|
+
run_id, terminal_state, prompt_title, executed_at, git_commit, report_path, retry_of,
|
|
172
|
+
original_run_id, retry_generation, retry_timestamp, target_checkout_path,
|
|
173
|
+
tracked_file_count, target_branch, execution_metadata, updated_at
|
|
174
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
175
|
+
ON CONFLICT(run_id) DO UPDATE SET
|
|
176
|
+
terminal_state=excluded.terminal_state,
|
|
177
|
+
prompt_title=excluded.prompt_title,
|
|
178
|
+
executed_at=excluded.executed_at,
|
|
179
|
+
git_commit=COALESCE(excluded.git_commit, prompt_execution_history.git_commit),
|
|
180
|
+
report_path=COALESCE(excluded.report_path, prompt_execution_history.report_path),
|
|
181
|
+
retry_of=COALESCE(excluded.retry_of, prompt_execution_history.retry_of),
|
|
182
|
+
original_run_id=COALESCE(excluded.original_run_id, prompt_execution_history.original_run_id),
|
|
183
|
+
retry_generation=COALESCE(excluded.retry_generation, prompt_execution_history.retry_generation),
|
|
184
|
+
retry_timestamp=COALESCE(excluded.retry_timestamp, prompt_execution_history.retry_timestamp),
|
|
185
|
+
target_checkout_path=COALESCE(excluded.target_checkout_path, prompt_execution_history.target_checkout_path),
|
|
186
|
+
tracked_file_count=COALESCE(excluded.tracked_file_count, prompt_execution_history.tracked_file_count),
|
|
187
|
+
target_branch=COALESCE(excluded.target_branch, prompt_execution_history.target_branch),
|
|
188
|
+
execution_metadata=CASE WHEN excluded.execution_metadata != '{}' THEN excluded.execution_metadata ELSE prompt_execution_history.execution_metadata END,
|
|
189
|
+
updated_at=excluded.updated_at
|
|
190
|
+
""",
|
|
191
|
+
(
|
|
192
|
+
safe_run_id,
|
|
193
|
+
terminal_state,
|
|
194
|
+
title,
|
|
195
|
+
_safe_timestamp(executed_at),
|
|
196
|
+
commit,
|
|
197
|
+
_relative_report(root, report, central_database=central_database),
|
|
198
|
+
parent,
|
|
199
|
+
original,
|
|
200
|
+
generation,
|
|
201
|
+
timestamp,
|
|
202
|
+
checkout_path,
|
|
203
|
+
tracked_files,
|
|
204
|
+
branch,
|
|
205
|
+
json.dumps(metadata, separators=(",", ":"), sort_keys=True),
|
|
206
|
+
now,
|
|
207
|
+
),
|
|
208
|
+
)
|
|
209
|
+
finally:
|
|
210
|
+
connection.close()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _report_record(root: Path, report: Path) -> dict[str, object] | None:
|
|
214
|
+
try:
|
|
215
|
+
content = report.read_text(encoding="utf-8")
|
|
216
|
+
except OSError:
|
|
217
|
+
return None
|
|
218
|
+
run = REPORT_RUN_ID.search(content)
|
|
219
|
+
state = REPORT_STATE.search(content)
|
|
220
|
+
if run is None or state is None:
|
|
221
|
+
return None
|
|
222
|
+
title = REPORT_TITLE.search(content)
|
|
223
|
+
increment_title = REPORT_INCREMENT_TITLE.search(content)
|
|
224
|
+
objective = REPORT_OBJECTIVE.search(content)
|
|
225
|
+
timestamp = REPORT_TIMESTAMP.search(content)
|
|
226
|
+
commit = REPORT_COMMIT.search(content)
|
|
227
|
+
retry_of = RETRY_OF.search(content)
|
|
228
|
+
original_run = ORIGINAL_RUN.search(content)
|
|
229
|
+
retry_generation = RETRY_GENERATION.search(content)
|
|
230
|
+
retry_timestamp = RETRY_TIMESTAMP.search(content)
|
|
231
|
+
target_branch = REPORT_TARGET_BRANCH.search(content)
|
|
232
|
+
return {
|
|
233
|
+
"run_id": run.group(1),
|
|
234
|
+
"terminal_state": state.group(1),
|
|
235
|
+
"prompt_title": (
|
|
236
|
+
increment_title.group(1).strip()
|
|
237
|
+
if increment_title and increment_title.group(1).strip()
|
|
238
|
+
else objective.group(1).strip()
|
|
239
|
+
if objective and objective.group(1).strip()
|
|
240
|
+
else title.group(1).strip()
|
|
241
|
+
if title
|
|
242
|
+
else run.group(1)
|
|
243
|
+
),
|
|
244
|
+
"executed_at": timestamp.group(1)
|
|
245
|
+
if timestamp
|
|
246
|
+
else datetime.fromtimestamp(report.stat().st_mtime, timezone.utc).isoformat(),
|
|
247
|
+
"report": report,
|
|
248
|
+
"git_commit": commit.group(1) if commit else None,
|
|
249
|
+
"retry_of": retry_of.group(1) if retry_of else None,
|
|
250
|
+
"original_run_id": original_run.group(1) if original_run else None,
|
|
251
|
+
"retry_generation": int(retry_generation.group(1)) if retry_generation else None,
|
|
252
|
+
"retry_timestamp": retry_timestamp.group(1) if retry_timestamp else None,
|
|
253
|
+
"target_branch": target_branch.group(1) if target_branch else None,
|
|
254
|
+
"execution_metadata": execution_metadata_from_terminal_report(report),
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def submission_prompt_title(root: Path, run_id: str) -> str | None:
|
|
259
|
+
"""Read the submitted title without deriving it from prompt content."""
|
|
260
|
+
connection = open_storage(root)
|
|
261
|
+
try:
|
|
262
|
+
row = connection.execute(
|
|
263
|
+
"SELECT submission.prompt_metadata FROM execution_submissions AS submission "
|
|
264
|
+
"JOIN execution_submission_links AS link ON link.submission_id=submission.submission_id "
|
|
265
|
+
"WHERE link.run_id=?",
|
|
266
|
+
(run_id,),
|
|
267
|
+
).fetchone()
|
|
268
|
+
finally:
|
|
269
|
+
connection.close()
|
|
270
|
+
if row is None or not isinstance(row[0], str):
|
|
271
|
+
return None
|
|
272
|
+
try:
|
|
273
|
+
metadata = json.loads(row[0])
|
|
274
|
+
except json.JSONDecodeError:
|
|
275
|
+
return None
|
|
276
|
+
title = metadata.get("title") if isinstance(metadata, dict) else None
|
|
277
|
+
return str(title).strip()[:500] or None if isinstance(title, str) else None
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def record_terminal_report(root: Path, report: Path, *, central_database: Path | None = None) -> None:
|
|
281
|
+
"""Project one authoritative terminal report into prompt history.
|
|
282
|
+
|
|
283
|
+
Direct execution-host invocations do not pass through the inbox watcher.
|
|
284
|
+
Keeping this projection here makes the terminal report the shared source
|
|
285
|
+
for both paths and lets a later reconciled report correct an older,
|
|
286
|
+
incomplete history row for the same run.
|
|
287
|
+
"""
|
|
288
|
+
record = _report_record(root, report)
|
|
289
|
+
if record is None:
|
|
290
|
+
raise ValueError("terminal report cannot be projected into prompt history")
|
|
291
|
+
submitted_title = submission_prompt_title(root, str(record["run_id"])) if central_database is None else None
|
|
292
|
+
# A managed Inbox submission owns its title. The terminal report's
|
|
293
|
+
# Objective is deliberately non-authoritative input context and must never
|
|
294
|
+
# replace the title already recorded at submission, including when the
|
|
295
|
+
# report supplies a non-generic placeholder for that Objective.
|
|
296
|
+
if submitted_title:
|
|
297
|
+
record["prompt_title"] = submitted_title
|
|
298
|
+
record_prompt_execution(root, central_database=central_database, **record)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def backfill_prompt_history(root: Path) -> None:
|
|
302
|
+
"""Cache legacy reports and telemetry rows into the canonical history index."""
|
|
303
|
+
reports = root / ".engineering" / "reports"
|
|
304
|
+
connection = open_storage(root)
|
|
305
|
+
try:
|
|
306
|
+
indexed_run_ids = {
|
|
307
|
+
row[0]
|
|
308
|
+
for row in connection.execute("SELECT run_id FROM prompt_execution_history").fetchall()
|
|
309
|
+
if isinstance(row[0], str)
|
|
310
|
+
}
|
|
311
|
+
finally:
|
|
312
|
+
connection.close()
|
|
313
|
+
if reports.is_dir():
|
|
314
|
+
for report in reports.glob("*.md"):
|
|
315
|
+
record = _report_record(root, report)
|
|
316
|
+
# The stored report path is the canonical terminal projection. A
|
|
317
|
+
# legacy fallback can share a Run ID with a later, real report;
|
|
318
|
+
# never let a filesystem scan replace that explicit reference.
|
|
319
|
+
if record is not None and record["run_id"] not in indexed_run_ids:
|
|
320
|
+
record_terminal_report(root, report)
|
|
321
|
+
indexed_run_ids.add(record["run_id"])
|
|
322
|
+
connection = open_storage(root)
|
|
323
|
+
try:
|
|
324
|
+
rows = connection.execute(
|
|
325
|
+
"""
|
|
326
|
+
SELECT run_id, terminal_state, execution_finished_at
|
|
327
|
+
FROM execution_runs
|
|
328
|
+
WHERE run_id NOT IN (SELECT run_id FROM prompt_execution_history)
|
|
329
|
+
"""
|
|
330
|
+
).fetchall()
|
|
331
|
+
finally:
|
|
332
|
+
connection.close()
|
|
333
|
+
for run_id, terminal_state, finished_at in rows:
|
|
334
|
+
record_prompt_execution(
|
|
335
|
+
root,
|
|
336
|
+
run_id=run_id,
|
|
337
|
+
terminal_state=terminal_state,
|
|
338
|
+
prompt_title=run_id,
|
|
339
|
+
executed_at=finished_at,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _active_retry_children(root: Path) -> list[dict[str, object]]:
|
|
344
|
+
"""Read active child lineage from watcher-persisted job records."""
|
|
345
|
+
try:
|
|
346
|
+
status = json.loads((root / ".engineering" / "status" / "status.json").read_text(encoding="utf-8"))
|
|
347
|
+
except (OSError, json.JSONDecodeError):
|
|
348
|
+
return []
|
|
349
|
+
active_run_id = _safe_run_id(status.get("run_id")) if isinstance(status, dict) else None
|
|
350
|
+
if active_run_id is None:
|
|
351
|
+
return []
|
|
352
|
+
children: list[dict[str, object]] = []
|
|
353
|
+
for job in (root / ".engineering" / "inbox-processing").glob("*/job.json"):
|
|
354
|
+
try:
|
|
355
|
+
payload = json.loads(job.read_text(encoding="utf-8"))
|
|
356
|
+
except (OSError, json.JSONDecodeError):
|
|
357
|
+
continue
|
|
358
|
+
if not isinstance(payload, dict) or payload.get("run_id") != active_run_id:
|
|
359
|
+
continue
|
|
360
|
+
retry = payload.get("retry")
|
|
361
|
+
parent = _safe_run_id(retry.get("retry_of")) if isinstance(retry, dict) else None
|
|
362
|
+
if parent is not None:
|
|
363
|
+
children.append(
|
|
364
|
+
{
|
|
365
|
+
"retry_of": parent,
|
|
366
|
+
"run_id": active_run_id,
|
|
367
|
+
"status": "ACTIVE",
|
|
368
|
+
"retry_timestamp": retry.get("retry_timestamp"),
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
return children
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _valid_retry_children(children: object) -> list[dict[str, object]]:
|
|
375
|
+
"""Accept bounded persisted child projections without inventing run IDs."""
|
|
376
|
+
if not isinstance(children, list):
|
|
377
|
+
return []
|
|
378
|
+
valid: list[dict[str, object]] = []
|
|
379
|
+
for child in children:
|
|
380
|
+
if not isinstance(child, dict):
|
|
381
|
+
continue
|
|
382
|
+
parent, run_id = _safe_run_id(child.get("retry_of")), _safe_run_id(child.get("run_id"))
|
|
383
|
+
state = child.get("status")
|
|
384
|
+
if parent is None or state not in RETRY_CHILD_STATES:
|
|
385
|
+
continue
|
|
386
|
+
if state != "QUEUED" and run_id is None:
|
|
387
|
+
continue
|
|
388
|
+
projection = {
|
|
389
|
+
"retry_of": parent,
|
|
390
|
+
"status": state,
|
|
391
|
+
"retry_timestamp": _safe_timestamp(child["retry_timestamp"])
|
|
392
|
+
if child.get("retry_timestamp")
|
|
393
|
+
else None,
|
|
394
|
+
}
|
|
395
|
+
if run_id is not None:
|
|
396
|
+
projection["run_id"] = run_id
|
|
397
|
+
valid.append(projection)
|
|
398
|
+
return valid
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def prompt_history(
|
|
402
|
+
root: Path, *, limit: int = 1_000, queued_retry_children: list[dict[str, object]] | None = None,
|
|
403
|
+
central_database: Path | None = None,
|
|
404
|
+
) -> list[dict[str, object]]:
|
|
405
|
+
"""Return bounded, newest-first projections safe for the private dashboard."""
|
|
406
|
+
bounded_limit = min(max(limit, 1), 1_000)
|
|
407
|
+
chat_cutoff = (datetime.now(timezone.utc) - timedelta(days=90)).isoformat()
|
|
408
|
+
if central_database is None:
|
|
409
|
+
connection = open_storage(root)
|
|
410
|
+
else:
|
|
411
|
+
connection = sqlite3.connect(central_database.resolve(), isolation_level=None)
|
|
412
|
+
connection.execute("PRAGMA foreign_keys=ON")
|
|
413
|
+
try:
|
|
414
|
+
rows = connection.execute(
|
|
415
|
+
"""
|
|
416
|
+
SELECT history.run_id,
|
|
417
|
+
CASE WHEN emergency.run_id IS NOT NULL THEN 'CANCELLED' ELSE history.terminal_state END,
|
|
418
|
+
history.prompt_title, history.executed_at,
|
|
419
|
+
history.git_commit, history.report_path, history.retry_of, history.original_run_id,
|
|
420
|
+
history.retry_generation, history.retry_timestamp, history.target_checkout_path,
|
|
421
|
+
history.tracked_file_count, history.target_branch,
|
|
422
|
+
COALESCE(NULLIF(history.execution_metadata, '{}'), runs.execution_metadata, '{}'),
|
|
423
|
+
COALESCE(runs.execution_mode, admission.execution_mode), runs.repository,
|
|
424
|
+
COALESCE(
|
|
425
|
+
runs.total_execution_seconds,
|
|
426
|
+
ROUND((
|
|
427
|
+
SELECT MAX(span.duration_ms) / 1000.0
|
|
428
|
+
FROM execution_phase_spans AS span
|
|
429
|
+
WHERE span.run_id = history.run_id
|
|
430
|
+
AND span.phase_name = 'TOTAL_EXECUTION'
|
|
431
|
+
AND span.outcome IN ('COMPLETE', 'FAILED')
|
|
432
|
+
), 3),
|
|
433
|
+
ROUND((
|
|
434
|
+
SELECT MAX(
|
|
435
|
+
0.0,
|
|
436
|
+
(julianday(MAX(CASE
|
|
437
|
+
WHEN json_extract(log.payload, '$.event') IN ('job_completed', 'job_failed')
|
|
438
|
+
THEN log.created_at END)) - julianday(MIN(CASE
|
|
439
|
+
WHEN json_extract(log.payload, '$.event') = 'runner_started'
|
|
440
|
+
THEN log.created_at END))) * 86400.0
|
|
441
|
+
)
|
|
442
|
+
FROM engineering_component_logs AS log
|
|
443
|
+
WHERE log.component = 'inbox'
|
|
444
|
+
AND json_extract(log.payload, '$.run_id') = history.run_id
|
|
445
|
+
), 3)
|
|
446
|
+
) AS total_execution_seconds,
|
|
447
|
+
COALESCE(submission.producer_id, runs.producer_id),
|
|
448
|
+
COALESCE(submission.producer_type, runs.producer_type),
|
|
449
|
+
COALESCE(submission.producer_version, runs.producer_version),
|
|
450
|
+
COALESCE(submission.correlation_id, runs.correlation_id),
|
|
451
|
+
COALESCE(submission.mission_id, runs.mission_id),
|
|
452
|
+
COALESCE(submission.engineering_action_id, runs.engineering_action_id),
|
|
453
|
+
runs.execution_constraint_version, submission.submission_id,
|
|
454
|
+
submission.contract_version, submission.execution_context_version,
|
|
455
|
+
submission.execution_context_snapshot, submission.forge_governance_handoff_version,
|
|
456
|
+
submission.forge_governance_handoff_snapshot, dismissal.terminal_state,
|
|
457
|
+
dismissal.handling_state, dismissal.dismissed_at, dismissal.dismissed_by,
|
|
458
|
+
emergency.cancelled_at,
|
|
459
|
+
(SELECT COUNT(*) FROM execution_chat_messages AS chat
|
|
460
|
+
WHERE chat.run_id = history.run_id AND chat.created_at >= ?)
|
|
461
|
+
FROM prompt_execution_history AS history
|
|
462
|
+
LEFT JOIN execution_runs AS runs ON runs.run_id = history.run_id
|
|
463
|
+
LEFT JOIN execution_submission_links AS submission_link ON submission_link.run_id = history.run_id
|
|
464
|
+
LEFT JOIN execution_submissions AS submission ON submission.submission_id = submission_link.submission_id
|
|
465
|
+
LEFT JOIN execution_admission_decisions AS admission ON admission.run_id = history.run_id
|
|
466
|
+
LEFT JOIN execution_dismissals AS dismissal ON dismissal.run_id = history.run_id
|
|
467
|
+
LEFT JOIN execution_emergency_recoveries AS emergency ON emergency.run_id = history.run_id
|
|
468
|
+
ORDER BY history.executed_at DESC, history.run_id DESC
|
|
469
|
+
LIMIT ?
|
|
470
|
+
""",
|
|
471
|
+
(chat_cutoff, bounded_limit),
|
|
472
|
+
).fetchall()
|
|
473
|
+
finally:
|
|
474
|
+
connection.close()
|
|
475
|
+
records = [
|
|
476
|
+
{
|
|
477
|
+
"run_id": row[0],
|
|
478
|
+
"status": row[1],
|
|
479
|
+
"title": row[2],
|
|
480
|
+
"executed_at": row[3],
|
|
481
|
+
"git_commit": row[4],
|
|
482
|
+
"report_available": bool(row[5]),
|
|
483
|
+
"retry_of": row[6],
|
|
484
|
+
"original_run_id": row[7],
|
|
485
|
+
"retry_generation": row[8],
|
|
486
|
+
"retry_timestamp": row[9],
|
|
487
|
+
"target_checkout_path": row[10],
|
|
488
|
+
"tracked_file_count": row[11],
|
|
489
|
+
"target_branch": row[12],
|
|
490
|
+
"execution_metadata": safe_execution_metadata(json.loads(row[13])) if isinstance(row[13], str) else {},
|
|
491
|
+
"execution_mode": row[14],
|
|
492
|
+
"repository": row[15],
|
|
493
|
+
"total_execution_seconds": row[16],
|
|
494
|
+
"producer_id": row[17] or "legacy",
|
|
495
|
+
"producer_type": row[18] or "HUMAN",
|
|
496
|
+
"producer_version": row[19],
|
|
497
|
+
"correlation_id": row[20],
|
|
498
|
+
"mission_id": row[21],
|
|
499
|
+
"engineering_action_id": row[22],
|
|
500
|
+
"execution_constraint_version": row[23],
|
|
501
|
+
"submission_id": row[24],
|
|
502
|
+
"producer_submission_contract_version": row[25],
|
|
503
|
+
"execution_context_version": row[26],
|
|
504
|
+
"execution_context": json.loads(row[27]) if isinstance(row[27], str) else None,
|
|
505
|
+
"forge_governance_handoff_version": row[28],
|
|
506
|
+
"forge_governance_handoff": json.loads(row[29]) if isinstance(row[29], str) else None,
|
|
507
|
+
"dismissed": row[30] is not None,
|
|
508
|
+
"handling_state": row[31] or "OPEN",
|
|
509
|
+
"dismissed_at": row[32],
|
|
510
|
+
"dismissed_by": row[33],
|
|
511
|
+
"emergency_cancelled_at": row[34],
|
|
512
|
+
"chat_message_count": row[35],
|
|
513
|
+
}
|
|
514
|
+
for row in rows
|
|
515
|
+
]
|
|
516
|
+
for record in records:
|
|
517
|
+
if record["forge_governance_handoff"] is None:
|
|
518
|
+
record.pop("forge_governance_handoff_version")
|
|
519
|
+
record.pop("forge_governance_handoff")
|
|
520
|
+
if record["emergency_cancelled_at"] is None:
|
|
521
|
+
record.pop("emergency_cancelled_at")
|
|
522
|
+
# Lineage is a read-only projection of persisted child evidence. It never
|
|
523
|
+
# changes a terminal parent or treats retry as resume. A terminal child
|
|
524
|
+
# wins over active, which wins over an unclaimed Inbox child.
|
|
525
|
+
children: dict[str, dict[str, object]] = {}
|
|
526
|
+
for child in [
|
|
527
|
+
*_valid_retry_children(queued_retry_children),
|
|
528
|
+
# CENTRAL history may not inspect a checkout-local watcher projection.
|
|
529
|
+
*(_active_retry_children(root) if central_database is None else ()),
|
|
530
|
+
*[record for record in records if record.get("retry_of")],
|
|
531
|
+
]:
|
|
532
|
+
parent = child.get("retry_of")
|
|
533
|
+
if isinstance(parent, str):
|
|
534
|
+
children[parent] = child
|
|
535
|
+
for record in records:
|
|
536
|
+
child = children.get(record["run_id"])
|
|
537
|
+
record["retry_child_run_id"] = child.get("run_id") if child else None
|
|
538
|
+
record["retry_status"] = child.get("status") if child else None
|
|
539
|
+
record["retry_timestamp"] = child.get("retry_timestamp") if child else record["retry_timestamp"]
|
|
540
|
+
record["queued_retry_child"] = bool(child and child.get("status") == "QUEUED")
|
|
541
|
+
record["active_retry_child"] = bool(child and child.get("status") == "ACTIVE")
|
|
542
|
+
record["can_retry"] = record.get("status") in {"BLOCKED", "FAILED"} and child is None and not record["dismissed"]
|
|
543
|
+
chain = [record["run_id"]]
|
|
544
|
+
cursor = record
|
|
545
|
+
while cursor.get("retry_of") and cursor["retry_of"] not in chain:
|
|
546
|
+
chain.insert(0, cursor["retry_of"])
|
|
547
|
+
cursor = next((item for item in records if item["run_id"] == cursor["retry_of"]), {})
|
|
548
|
+
record["retry_chain"] = chain
|
|
549
|
+
record["current_active_run"] = (
|
|
550
|
+
child.get("run_id") if child and child.get("status") != "QUEUED" else record["run_id"]
|
|
551
|
+
)
|
|
552
|
+
return records
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def report_path_for_prompt_history(root: Path, run_id: object) -> Path | None:
|
|
556
|
+
"""Resolve only the report explicitly indexed for the requested terminal run."""
|
|
557
|
+
safe_run_id = _safe_run_id(run_id)
|
|
558
|
+
if safe_run_id is None:
|
|
559
|
+
return None
|
|
560
|
+
connection = open_storage(root)
|
|
561
|
+
try:
|
|
562
|
+
row = connection.execute(
|
|
563
|
+
"SELECT report_path FROM prompt_execution_history WHERE run_id=?", (safe_run_id,)
|
|
564
|
+
).fetchone()
|
|
565
|
+
finally:
|
|
566
|
+
connection.close()
|
|
567
|
+
if not row or not isinstance(row[0], str):
|
|
568
|
+
return None
|
|
569
|
+
central = os.environ.get("EP_CENTRAL_OPERATIONAL_DATABASE")
|
|
570
|
+
if central and row[0].startswith("CENTRAL:"):
|
|
571
|
+
path = (Path(central).resolve().parent / "artifacts" / row[0].removeprefix("CENTRAL:")).resolve()
|
|
572
|
+
try:
|
|
573
|
+
path.relative_to(Path(central).resolve().parent / "artifacts")
|
|
574
|
+
return path if path.is_file() else None
|
|
575
|
+
except (OSError, ValueError):
|
|
576
|
+
return None
|
|
577
|
+
path = (root / ".engineering" / "reports" / row[0]).resolve()
|
|
578
|
+
try:
|
|
579
|
+
path.relative_to((root / ".engineering" / "reports").resolve())
|
|
580
|
+
return path if path.is_file() else None
|
|
581
|
+
except (OSError, ValueError):
|
|
582
|
+
return None
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def report_for_prompt_history(root: Path, run_id: object) -> bytes | None:
|
|
586
|
+
"""Return only a report explicitly indexed for the requested terminal run."""
|
|
587
|
+
path = report_path_for_prompt_history(root, run_id)
|
|
588
|
+
try:
|
|
589
|
+
return path.read_bytes() if path is not None else None
|
|
590
|
+
except OSError:
|
|
591
|
+
return None
|