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,630 @@
|
|
|
1
|
+
"""Read-only state projections used by the Engineering Status dashboard.
|
|
2
|
+
|
|
3
|
+
This module deliberately has no HTTP concerns. The dashboard façade supplies
|
|
4
|
+
the small repository-specific readers, which keeps state composition testable
|
|
5
|
+
without giving it lifecycle or transaction authority.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
from .host_preflight import latest as latest_host_preflight
|
|
16
|
+
from .workspace_preflight import latest as latest_workspace_preflight
|
|
17
|
+
from .capability_preflight import latest as latest_capability_preflight
|
|
18
|
+
from .drift_diagnostics import guidance as drift_guidance
|
|
19
|
+
from .platform_api import PlatformConfigurationError, execution_host_configuration
|
|
20
|
+
from .telemetry import comparable_duration_estimate
|
|
21
|
+
from .storage import EngineeringStorageError, import_legacy_projection_once, is_active_blocking_predecessor, load_execution_context_snapshot, load_forge_governance_handoff_snapshot, load_projection, load_readiness_evaluation, open_storage
|
|
22
|
+
from .execution_lease import liveness as lease_liveness
|
|
23
|
+
from .execution_lifecycle import projection as lifecycle_projection
|
|
24
|
+
from .agent_state import redact_diagnostic
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
JsonReader = Callable[[Path], bytes]
|
|
28
|
+
RunJsonReader = Callable[[Path, str | None], bytes]
|
|
29
|
+
TERMINAL_PHASES = frozenset({"COMPLETE", "BLOCKED", "FAILED"})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _successful_reviewer_agents(value: object) -> list[dict[str, object]]:
|
|
33
|
+
"""Expose only a wholly successful review beyond its live phase."""
|
|
34
|
+
if not isinstance(value, list):
|
|
35
|
+
return []
|
|
36
|
+
reviewers = [item for item in value if isinstance(item, dict)]
|
|
37
|
+
if not reviewers or len(reviewers) != len(value):
|
|
38
|
+
return []
|
|
39
|
+
return reviewers if all(item.get("status") == "completed" for item in reviewers) else []
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _active_runner_checkpoint(root: Path) -> tuple[dict[str, object], dict[str, object]] | None:
|
|
43
|
+
"""Return a current checkpoint only while its recorded runner group exists.
|
|
44
|
+
|
|
45
|
+
The watcher intentionally detaches while a managed execution is running.
|
|
46
|
+
Its last status publication can therefore lag the runner. The runner's
|
|
47
|
+
atomic checkpoint is safe to present only when the exact recorded process
|
|
48
|
+
group is still alive; a status file by itself never establishes liveness.
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
current = json.loads((root / ".engineering" / "status" / "current.json").read_text(encoding="utf-8"))
|
|
52
|
+
runner = json.loads((root / ".engineering" / "status" / "runner_process.json").read_text(encoding="utf-8"))
|
|
53
|
+
except (OSError, json.JSONDecodeError):
|
|
54
|
+
return None
|
|
55
|
+
run_id, phase = current.get("run_id"), current.get("phase")
|
|
56
|
+
pid, process_group = runner.get("pid"), runner.get("process_group")
|
|
57
|
+
if (
|
|
58
|
+
not isinstance(run_id, str)
|
|
59
|
+
or not run_id
|
|
60
|
+
or not isinstance(phase, str)
|
|
61
|
+
or phase in TERMINAL_PHASES
|
|
62
|
+
or runner.get("run_id") != run_id
|
|
63
|
+
or not isinstance(pid, int)
|
|
64
|
+
or pid <= 0
|
|
65
|
+
or not isinstance(process_group, int)
|
|
66
|
+
or process_group <= 0
|
|
67
|
+
):
|
|
68
|
+
return None
|
|
69
|
+
try:
|
|
70
|
+
if os.getpgid(pid) != process_group:
|
|
71
|
+
return None
|
|
72
|
+
os.killpg(process_group, 0)
|
|
73
|
+
except OSError:
|
|
74
|
+
return None
|
|
75
|
+
return current, {
|
|
76
|
+
"state": "LIVE",
|
|
77
|
+
"source": "RUNNER_PROCESS",
|
|
78
|
+
"runner_pid": pid,
|
|
79
|
+
"process_group": process_group,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _active_prompt_metadata(root: Path, run_id: object) -> tuple[str | None, str | None]:
|
|
84
|
+
"""Return bounded title-only prompt context for the active run.
|
|
85
|
+
|
|
86
|
+
The watcher normally owns these fields. A restart can leave an older run
|
|
87
|
+
with only its durable transaction checkpoint, so recover just the first
|
|
88
|
+
Markdown H1 and filename for the operator hand-off. Never expose prompt
|
|
89
|
+
body text through the status projection.
|
|
90
|
+
"""
|
|
91
|
+
if not isinstance(run_id, str) or not run_id:
|
|
92
|
+
return None, None
|
|
93
|
+
try:
|
|
94
|
+
connection = open_storage(root, create=False)
|
|
95
|
+
try:
|
|
96
|
+
row = connection.execute(
|
|
97
|
+
"SELECT payload FROM engineering_transactions WHERE run_id=?", (run_id,)
|
|
98
|
+
).fetchone()
|
|
99
|
+
finally:
|
|
100
|
+
connection.close()
|
|
101
|
+
checkpoint = json.loads(row[0]) if row and isinstance(row[0], str) else {}
|
|
102
|
+
prompt_path = checkpoint.get("prompt_path") if isinstance(checkpoint, dict) else None
|
|
103
|
+
if not isinstance(prompt_path, str) or not prompt_path:
|
|
104
|
+
return None, None
|
|
105
|
+
path = Path(prompt_path)
|
|
106
|
+
filename = redact_diagnostic(path.name, limit=240) or None
|
|
107
|
+
with path.open(encoding="utf-8") as prompt:
|
|
108
|
+
for _ in range(512):
|
|
109
|
+
line = prompt.readline()
|
|
110
|
+
if not line:
|
|
111
|
+
break
|
|
112
|
+
if line.startswith("# ") and line[2:].strip():
|
|
113
|
+
return filename, redact_diagnostic(line[2:].strip(), limit=240) or filename
|
|
114
|
+
return filename, filename
|
|
115
|
+
except (EngineeringStorageError, OSError, UnicodeDecodeError, json.JSONDecodeError):
|
|
116
|
+
return None, None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _transient_live_action(root: Path, run_id: object) -> str | None:
|
|
120
|
+
"""Read the non-persistent current action title for its owning live run."""
|
|
121
|
+
if not isinstance(run_id, str):
|
|
122
|
+
return None
|
|
123
|
+
try:
|
|
124
|
+
current = json.loads((root / ".engineering" / "status" / "current.json").read_text(encoding="utf-8"))
|
|
125
|
+
except (OSError, json.JSONDecodeError):
|
|
126
|
+
return None
|
|
127
|
+
action = current.get("transient_action") if current.get("run_id") == run_id else None
|
|
128
|
+
return action if isinstance(action, str) and 4 <= len(action) <= 160 else None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _terminal_checkpoint(root: Path, run_id: object) -> bool:
|
|
132
|
+
"""Return whether a live-status run has already reached a terminal checkpoint.
|
|
133
|
+
|
|
134
|
+
``current.json`` is written by the runner and can briefly outlive its terminal
|
|
135
|
+
checkpoint. It must therefore never keep a completed execution visible as
|
|
136
|
+
an active dashboard prompt.
|
|
137
|
+
"""
|
|
138
|
+
if not isinstance(run_id, str):
|
|
139
|
+
return False
|
|
140
|
+
try:
|
|
141
|
+
connection = open_storage(root)
|
|
142
|
+
try:
|
|
143
|
+
row = connection.execute(
|
|
144
|
+
"SELECT phase FROM engineering_transactions WHERE run_id=?", (run_id,)
|
|
145
|
+
).fetchone()
|
|
146
|
+
finally:
|
|
147
|
+
connection.close()
|
|
148
|
+
except EngineeringStorageError:
|
|
149
|
+
return False
|
|
150
|
+
if row:
|
|
151
|
+
return row[0] in TERMINAL_PHASES
|
|
152
|
+
# Narrow compatibility window for a terminal pre-v12 runner that did not
|
|
153
|
+
# contain enough fields to be promoted during the one-time migration.
|
|
154
|
+
try:
|
|
155
|
+
checkpoint = json.loads(
|
|
156
|
+
(root / ".engineering" / "engineering-runs" / f"{run_id}.json").read_text(encoding="utf-8")
|
|
157
|
+
)
|
|
158
|
+
except (OSError, json.JSONDecodeError):
|
|
159
|
+
return False
|
|
160
|
+
return isinstance(checkpoint, dict) and checkpoint.get("phase") in TERMINAL_PHASES
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _watcher_has_terminal_run(watcher: object, run_id: object) -> bool:
|
|
164
|
+
"""Return whether the watcher has already closed the live run."""
|
|
165
|
+
return (
|
|
166
|
+
isinstance(watcher, dict)
|
|
167
|
+
and isinstance(run_id, str)
|
|
168
|
+
and watcher.get("last_executed_run") == run_id
|
|
169
|
+
and watcher.get("last_executed_phase") in TERMINAL_PHASES
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _watcher_lags_live_phase(
|
|
174
|
+
watcher: object, live: object, lifecycle: object,
|
|
175
|
+
) -> bool:
|
|
176
|
+
"""Return whether an old implementation-merge wait masks later progress.
|
|
177
|
+
|
|
178
|
+
The watcher can retain its last operator-merge publication while the
|
|
179
|
+
resumed Execution Host has already persisted a later phase for the same
|
|
180
|
+
run: finalization, bounded validation repair, or cleanup. That is not
|
|
181
|
+
another merge wait. Keep the later lifecycle visible even when the host
|
|
182
|
+
lease has subsequently gone stale, so the operator sees the durable state
|
|
183
|
+
and its ownership warning instead of an obsolete PR hand-off.
|
|
184
|
+
"""
|
|
185
|
+
return (
|
|
186
|
+
isinstance(watcher, dict)
|
|
187
|
+
and isinstance(live, dict)
|
|
188
|
+
and watcher.get("run_id") == live.get("run_id")
|
|
189
|
+
and watcher.get("watcher_state") == "WAITING_FOR_OPERATOR_MERGE"
|
|
190
|
+
and watcher.get("current_phase") == "WAIT_FOR_OPERATOR_MERGE"
|
|
191
|
+
and isinstance(lifecycle, dict)
|
|
192
|
+
and lifecycle.get("current_step") in {
|
|
193
|
+
"INITIALIZE", "CAPABILITY_REVIEW", "EXECUTE_AGENT", "REPAIR_AGENT", "FINALIZATION_REPAIR_AGENT", "FINALIZE_AGENT", "RECONCILE_AGENT", "REPOSITORY_CLEANUP",
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _is_operator_merge_wait(live: object, lifecycle: object) -> bool:
|
|
199
|
+
"""Keep the durable PR hand-off visible during internal check polling.
|
|
200
|
+
|
|
201
|
+
``WAIT_FOR_TERMINAL_EVIDENCE`` is an implementation detail used while an
|
|
202
|
+
open implementation PR is polled. Its lifecycle projection deliberately
|
|
203
|
+
presents that interval as ``WAIT_FOR_OPERATOR_MERGE``. The dashboard
|
|
204
|
+
status must use the same presentation phase even when a short-lived live
|
|
205
|
+
lease wins over the watcher projection; otherwise the operator's PR
|
|
206
|
+
controls flicker away between polling updates.
|
|
207
|
+
"""
|
|
208
|
+
if not isinstance(live, dict) or not isinstance(lifecycle, dict):
|
|
209
|
+
return False
|
|
210
|
+
phase = live.get("phase")
|
|
211
|
+
if phase == "WAIT_FOR_OPERATOR_MERGE":
|
|
212
|
+
return lifecycle.get("current_step") in {
|
|
213
|
+
"WAIT_FOR_OPERATOR_MERGE", "WAIT_FOR_FINALIZATION_MERGE", "WAIT_FOR_RECONCILIATION_MERGE",
|
|
214
|
+
}
|
|
215
|
+
return (
|
|
216
|
+
phase == "WAIT_FOR_TERMINAL_EVIDENCE"
|
|
217
|
+
and lifecycle.get("current_step") in {"WAIT_FOR_OPERATOR_MERGE", "WAIT_FOR_FINALIZATION_MERGE", "WAIT_FOR_RECONCILIATION_MERGE"}
|
|
218
|
+
and isinstance(live.get("pull_request"), int)
|
|
219
|
+
and not isinstance(live.get("pull_request"), bool)
|
|
220
|
+
and live["pull_request"] > 0
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _has_verified_merge_continuation(watcher: object, live: object, lifecycle: object) -> bool:
|
|
225
|
+
"""Return whether a proven merge has already scheduled its visible next step."""
|
|
226
|
+
return (
|
|
227
|
+
isinstance(watcher, dict)
|
|
228
|
+
and isinstance(live, dict)
|
|
229
|
+
and isinstance(lifecycle, dict)
|
|
230
|
+
and watcher.get("watcher_state") == "ENGINEERING_RUN_ACTIVE"
|
|
231
|
+
and watcher.get("run_id") == live.get("run_id")
|
|
232
|
+
and watcher.get("current_phase") == lifecycle.get("current_step")
|
|
233
|
+
and watcher.get("current_phase") in {"FINALIZE_AGENT", "RECONCILE_AGENT"}
|
|
234
|
+
and watcher.get("current_action") in {
|
|
235
|
+
"create_finalization", "reconcile_rolling_records_on_main",
|
|
236
|
+
}
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def unavailable_status() -> bytes:
|
|
241
|
+
"""Return the complete, safe status shape when no projection exists yet."""
|
|
242
|
+
return json.dumps(
|
|
243
|
+
{
|
|
244
|
+
"watcher_state": "REMOTE_ENGINEERING_DEGRADED",
|
|
245
|
+
"current_phase": "status niet beschikbaar",
|
|
246
|
+
"current_action": "Voer het Engineering Platform uit om een statusupdate te publiceren.",
|
|
247
|
+
"run_id": None,
|
|
248
|
+
"queue_depth": 0,
|
|
249
|
+
"queue_items": [],
|
|
250
|
+
"implementation_pr": None,
|
|
251
|
+
"finalization_pr": None,
|
|
252
|
+
"reconciliation_pr": None,
|
|
253
|
+
"repository_state": "UNKNOWN",
|
|
254
|
+
"workspace_state": "UNKNOWN",
|
|
255
|
+
"diagnostic": "Er is nog geen lokale engineeringstatus gepubliceerd.",
|
|
256
|
+
"submitted_filename": None,
|
|
257
|
+
"prompt_title": None,
|
|
258
|
+
"last_executed_filename": None,
|
|
259
|
+
"last_executed_title": None,
|
|
260
|
+
"last_executed_run": None,
|
|
261
|
+
"last_executed_phase": None,
|
|
262
|
+
"blocking_predecessor_run": None,
|
|
263
|
+
"blocking_predecessor_phase": None,
|
|
264
|
+
"blocking_predecessor_filename": None,
|
|
265
|
+
"blocking_predecessor_title": None,
|
|
266
|
+
"predecessor_recovery_action": None,
|
|
267
|
+
},
|
|
268
|
+
separators=(",", ":"),
|
|
269
|
+
).encode()
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def status(root: Path) -> bytes:
|
|
273
|
+
"""Project watcher and live-run state into the stable dashboard contract."""
|
|
274
|
+
try:
|
|
275
|
+
watcher = load_projection(root, "watcher_status")
|
|
276
|
+
live = load_projection(root, "live_status")
|
|
277
|
+
# One explicit compatibility migration supports upgraded hosts where
|
|
278
|
+
# status files predate the canonical store. It is not a normal read
|
|
279
|
+
# path once the row has been imported.
|
|
280
|
+
if watcher is None:
|
|
281
|
+
watcher = import_legacy_projection_once(
|
|
282
|
+
root, "watcher_status", root / ".engineering" / "status" / "status.json"
|
|
283
|
+
)
|
|
284
|
+
if live is None:
|
|
285
|
+
live = import_legacy_projection_once(
|
|
286
|
+
root, "live_status", root / ".engineering" / "status" / "current.json"
|
|
287
|
+
)
|
|
288
|
+
runner_checkpoint = _active_runner_checkpoint(root)
|
|
289
|
+
if runner_checkpoint is not None:
|
|
290
|
+
# A detached watcher can retain RUNNER_STARTING while the exact
|
|
291
|
+
# Execution Host process group continues the run. The fresh runner
|
|
292
|
+
# checkpoint is then the authoritative dashboard run projection.
|
|
293
|
+
live, runner_liveness = runner_checkpoint
|
|
294
|
+
else:
|
|
295
|
+
runner_liveness = None
|
|
296
|
+
watcher = watcher or {}
|
|
297
|
+
# The dashboard is a read model, but it must not repeat a stale
|
|
298
|
+
# compatibility projection after SQLite has recorded dismissal. The
|
|
299
|
+
# watcher persists the same reconciliation on its next publication.
|
|
300
|
+
predecessor_run = watcher.get("blocking_predecessor_run")
|
|
301
|
+
if (
|
|
302
|
+
watcher.get("watcher_state") == "WAITING_FOR_PREDECESSOR"
|
|
303
|
+
and isinstance(predecessor_run, str)
|
|
304
|
+
and predecessor_run
|
|
305
|
+
and not is_active_blocking_predecessor(
|
|
306
|
+
root, predecessor_run, watcher.get("blocking_predecessor_phase"),
|
|
307
|
+
)
|
|
308
|
+
):
|
|
309
|
+
watcher = {
|
|
310
|
+
**watcher,
|
|
311
|
+
"watcher_state": "WATCHER_IDLE",
|
|
312
|
+
"current_phase": None,
|
|
313
|
+
"current_action": "Execution Host Idle",
|
|
314
|
+
"blocking_predecessor_run": None,
|
|
315
|
+
"blocking_predecessor_phase": None,
|
|
316
|
+
"blocking_predecessor_filename": None,
|
|
317
|
+
"blocking_predecessor_title": None,
|
|
318
|
+
"predecessor_recovery_action": None,
|
|
319
|
+
}
|
|
320
|
+
# A watcher publication from before predecessor projection was
|
|
321
|
+
# introduced can still say WATCHER_IDLE while its undismissed terminal
|
|
322
|
+
# execution would hold every later Inbox submission. The dashboard is
|
|
323
|
+
# read-only, so normalize that misleading legacy projection here until
|
|
324
|
+
# the watcher publishes the same state on its next cycle.
|
|
325
|
+
if (
|
|
326
|
+
watcher.get("watcher_state") == "WATCHER_IDLE"
|
|
327
|
+
and is_active_blocking_predecessor(
|
|
328
|
+
root, watcher.get("last_executed_run"), watcher.get("last_executed_phase"),
|
|
329
|
+
)
|
|
330
|
+
):
|
|
331
|
+
predecessor_run = watcher["last_executed_run"]
|
|
332
|
+
watcher = {
|
|
333
|
+
**watcher,
|
|
334
|
+
"watcher_state": "WAITING_FOR_PREDECESSOR",
|
|
335
|
+
"current_phase": "WAITING_FOR_PREDECESSOR",
|
|
336
|
+
"current_action": "Wachtrij gepauzeerd tot de voorafgaande prompt is hersteld.",
|
|
337
|
+
"blocking_predecessor_run": predecessor_run,
|
|
338
|
+
"blocking_predecessor_phase": watcher.get("last_executed_phase"),
|
|
339
|
+
"blocking_predecessor_filename": watcher.get("last_executed_filename"),
|
|
340
|
+
"blocking_predecessor_title": watcher.get("last_executed_title"),
|
|
341
|
+
"predecessor_recovery_action": (
|
|
342
|
+
"Herstel de geblokkeerde prompt of dien die bewust opnieuw in met een eigen regel "
|
|
343
|
+
f"`Retry-Of: {predecessor_run}`. De wachtrij blijft gepauzeerd totdat deze herindiening voltooid is."
|
|
344
|
+
),
|
|
345
|
+
}
|
|
346
|
+
except EngineeringStorageError:
|
|
347
|
+
watcher = {}
|
|
348
|
+
live = None
|
|
349
|
+
try:
|
|
350
|
+
if live is None:
|
|
351
|
+
raise ValueError("No canonical live status")
|
|
352
|
+
live_liveness = lease_liveness(root, live.get("run_id"))
|
|
353
|
+
if runner_liveness is not None and runner_liveness.get("state") == "LIVE":
|
|
354
|
+
live_liveness = {**live_liveness, **runner_liveness}
|
|
355
|
+
transient_action = _transient_live_action(root, live.get("run_id"))
|
|
356
|
+
lifecycle = lifecycle_projection(root, live.get("run_id"))
|
|
357
|
+
if isinstance(lifecycle, dict) and transient_action:
|
|
358
|
+
# Ephemeral, redacted CLI progress is presentation-only. It is
|
|
359
|
+
# deliberately not persisted in lifecycle, reports or telemetry.
|
|
360
|
+
lifecycle["live_activity"] = transient_action
|
|
361
|
+
fallback_filename, fallback_prompt_title = _active_prompt_metadata(root, live.get("run_id"))
|
|
362
|
+
projection = json.dumps(
|
|
363
|
+
{
|
|
364
|
+
"watcher_state": "ENGINEERING_RUN_ACTIVE",
|
|
365
|
+
"platform_version": watcher.get("platform_version"),
|
|
366
|
+
"current_phase": live.get("phase") or "INITIALIZE",
|
|
367
|
+
"current_action": transient_action or live.get("current_action") or "Engineeringuitvoering is actief.",
|
|
368
|
+
"run_id": live.get("run_id"),
|
|
369
|
+
# The watcher owns the queue. A live runner only adds current
|
|
370
|
+
# execution details, so it must not replace the queued count.
|
|
371
|
+
"queue_depth": watcher.get("queue_depth", len(watcher.get("queue_items", []))),
|
|
372
|
+
"queue_items": watcher.get("queue_items", []),
|
|
373
|
+
"implementation_pr": live.get("implementation_pr"),
|
|
374
|
+
"finalization_pr": live.get("finalization_pr"),
|
|
375
|
+
"reconciliation_pr": live.get("reconciliation_pr"),
|
|
376
|
+
"pull_request": live.get("pull_request"),
|
|
377
|
+
"waiting_for_merge_since": live.get("waiting_for_merge_since"),
|
|
378
|
+
"repository_state": live.get("repository_state") or "ACTIVE",
|
|
379
|
+
"workspace_state": live.get("workspace_state") or "ACTIVE",
|
|
380
|
+
"prompt_characters": live.get("prompt_characters"),
|
|
381
|
+
"diagnostic": live.get("diagnostic"),
|
|
382
|
+
"submitted_filename": watcher.get("submitted_filename") or fallback_filename,
|
|
383
|
+
"prompt_title": watcher.get("prompt_title") or fallback_prompt_title,
|
|
384
|
+
"last_executed_filename": watcher.get("last_executed_filename"),
|
|
385
|
+
"last_executed_title": watcher.get("last_executed_title"),
|
|
386
|
+
"last_executed_run": watcher.get("last_executed_run"),
|
|
387
|
+
"last_executed_phase": watcher.get("last_executed_phase"),
|
|
388
|
+
"blocking_predecessor_run": watcher.get("blocking_predecessor_run"),
|
|
389
|
+
"blocking_predecessor_phase": watcher.get("blocking_predecessor_phase"),
|
|
390
|
+
"blocking_predecessor_filename": watcher.get("blocking_predecessor_filename"),
|
|
391
|
+
"blocking_predecessor_title": watcher.get("blocking_predecessor_title"),
|
|
392
|
+
"predecessor_recovery_action": watcher.get("predecessor_recovery_action"),
|
|
393
|
+
"execution_mode": live.get("execution_mode"),
|
|
394
|
+
"target_repository": live.get("target_repository"),
|
|
395
|
+
"checkout_path": live.get("checkout_path"),
|
|
396
|
+
"active_branch": live.get("active_branch"),
|
|
397
|
+
# Only a wholly successful specialist review survives its
|
|
398
|
+
# live phase as historical evidence for this active run. A
|
|
399
|
+
# partial, failed or stale reviewer projection remains hidden.
|
|
400
|
+
"reviewer_agents": (
|
|
401
|
+
live.get("reviewer_agents", [])
|
|
402
|
+
if live.get("phase") == "CAPABILITY_REVIEW"
|
|
403
|
+
else _successful_reviewer_agents(live.get("reviewer_agents"))
|
|
404
|
+
),
|
|
405
|
+
"runtime_metadata": live.get("runtime_metadata", {}),
|
|
406
|
+
"workspace_progress": live.get("workspace_progress"),
|
|
407
|
+
"execution_liveness": live_liveness,
|
|
408
|
+
"readiness": load_readiness_evaluation(root, live.get("run_id")),
|
|
409
|
+
# The dashboard consumes only the immutable context snapshot
|
|
410
|
+
# linked to this run; legacy/current prompt projections never
|
|
411
|
+
# become an Execution Context source.
|
|
412
|
+
"execution_context": load_execution_context_snapshot(root, str(live.get("run_id"))),
|
|
413
|
+
"forge_governance_handoff": load_forge_governance_handoff_snapshot(root, str(live.get("run_id"))),
|
|
414
|
+
"lifecycle": lifecycle,
|
|
415
|
+
},
|
|
416
|
+
separators=(",", ":"),
|
|
417
|
+
).encode()
|
|
418
|
+
except (ValueError, TypeError):
|
|
419
|
+
live, projection, lifecycle = None, None, None
|
|
420
|
+
if live and _has_verified_merge_continuation(watcher, live, lifecycle):
|
|
421
|
+
continuation_projection = json.loads(projection or b"{}")
|
|
422
|
+
continuation_projection.update(
|
|
423
|
+
{
|
|
424
|
+
"watcher_state": watcher["watcher_state"],
|
|
425
|
+
"current_phase": watcher["current_phase"],
|
|
426
|
+
"current_action": watcher["current_action"],
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
return json.dumps(continuation_projection, separators=(",", ":")).encode()
|
|
430
|
+
if (
|
|
431
|
+
live
|
|
432
|
+
and _is_operator_merge_wait(live, lifecycle)
|
|
433
|
+
and not _terminal_checkpoint(root, live.get("run_id"))
|
|
434
|
+
):
|
|
435
|
+
waiting_projection = json.loads(projection or b"{}")
|
|
436
|
+
waiting_projection.update(
|
|
437
|
+
{
|
|
438
|
+
"watcher_state": "WAITING_FOR_OPERATOR_MERGE",
|
|
439
|
+
"current_phase": "WAIT_FOR_OPERATOR_MERGE",
|
|
440
|
+
"current_action": "Waiting for the operator to merge the pull request.",
|
|
441
|
+
"pull_request": live.get("pull_request"),
|
|
442
|
+
"waiting_for_merge_since": live.get("waiting_for_merge_since"),
|
|
443
|
+
}
|
|
444
|
+
)
|
|
445
|
+
return json.dumps(waiting_projection, separators=(",", ":")).encode()
|
|
446
|
+
if (
|
|
447
|
+
live
|
|
448
|
+
and live.get("phase") not in TERMINAL_PHASES
|
|
449
|
+
and live_liveness.get("state") != "LIVE"
|
|
450
|
+
and not _terminal_checkpoint(root, live.get("run_id"))
|
|
451
|
+
and (
|
|
452
|
+
not watcher
|
|
453
|
+
or watcher.get("watcher_state") == "WATCHER_IDLE"
|
|
454
|
+
or watcher.get("run_id") == live.get("run_id")
|
|
455
|
+
or _watcher_lags_live_phase(watcher, live, lifecycle)
|
|
456
|
+
)
|
|
457
|
+
):
|
|
458
|
+
# Lifecycle is intentionally retained for auditability, but a stale
|
|
459
|
+
# lease must never be presented as an actively running execution.
|
|
460
|
+
stale_projection = json.loads(projection or b"{}")
|
|
461
|
+
reconciliation = live_liveness.get("reconciliation_outcome")
|
|
462
|
+
recovery = (
|
|
463
|
+
"RESUME_AVAILABLE"
|
|
464
|
+
if reconciliation == "RECOVERABLE"
|
|
465
|
+
else "TERMINAL_EVIDENCE_RECONCILIATION"
|
|
466
|
+
if reconciliation == "TERMINAL_EVIDENCE_PRESENT"
|
|
467
|
+
else "OPERATOR_INTERVENTION_REQUIRED"
|
|
468
|
+
)
|
|
469
|
+
stale_projection.update(
|
|
470
|
+
{
|
|
471
|
+
"watcher_state": "ENGINEERING_RUN_STALE",
|
|
472
|
+
# The lifecycle is the canonical presentation mapping for
|
|
473
|
+
# internal polling. In particular, a finalization PR's check
|
|
474
|
+
# polling must never be labelled as the older implementation
|
|
475
|
+
# merge hand-off.
|
|
476
|
+
"current_phase": lifecycle.get("current_step") or live.get("phase"),
|
|
477
|
+
"current_action": "Execution Host ownership is stale; no execution is currently running.",
|
|
478
|
+
"recovery_action": recovery,
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
return json.dumps(stale_projection, separators=(",", ":")).encode()
|
|
482
|
+
if (
|
|
483
|
+
live
|
|
484
|
+
and live.get("phase") not in TERMINAL_PHASES
|
|
485
|
+
and live_liveness.get("state") == "LIVE"
|
|
486
|
+
and not _terminal_checkpoint(root, live.get("run_id"))
|
|
487
|
+
and not _watcher_has_terminal_run(watcher, live.get("run_id"))
|
|
488
|
+
):
|
|
489
|
+
# A watcher can already be idle after it has detached a runner. A
|
|
490
|
+
# confirmed live lease is authoritative for the active execution and
|
|
491
|
+
# must not be hidden by that older watcher projection.
|
|
492
|
+
return projection
|
|
493
|
+
if watcher:
|
|
494
|
+
# A queued prompt can be held before it receives its own run ID when
|
|
495
|
+
# its predecessor is terminally blocked. Keep that predecessor's
|
|
496
|
+
# persisted lifecycle visible in the operational card so the operator
|
|
497
|
+
# can see the exact blocking flow, without misrepresenting it as a
|
|
498
|
+
# live execution of the queued prompt.
|
|
499
|
+
predecessor_run = watcher.get("blocking_predecessor_run")
|
|
500
|
+
if (
|
|
501
|
+
watcher.get("watcher_state") == "WAITING_FOR_PREDECESSOR"
|
|
502
|
+
and isinstance(predecessor_run, str)
|
|
503
|
+
and predecessor_run
|
|
504
|
+
):
|
|
505
|
+
watcher = dict(watcher)
|
|
506
|
+
lifecycle = dict(lifecycle_projection(root, predecessor_run))
|
|
507
|
+
# Recovery belongs to the predecessor detail view. The queue wait
|
|
508
|
+
# card only presents its immutable lifecycle evidence.
|
|
509
|
+
lifecycle["recovery"] = None
|
|
510
|
+
watcher["lifecycle"] = lifecycle
|
|
511
|
+
return json.dumps(watcher, separators=(",", ":")).encode()
|
|
512
|
+
return projection or unavailable_status()
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def sse_status(root: Path) -> bytes:
|
|
516
|
+
"""Encode the status as a single SSE data line."""
|
|
517
|
+
try:
|
|
518
|
+
payload = json.loads(status(root))
|
|
519
|
+
except json.JSONDecodeError:
|
|
520
|
+
payload = json.loads(unavailable_status())
|
|
521
|
+
return json.dumps(payload, separators=(",", ":")).encode()
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def snapshot(
|
|
525
|
+
root: Path,
|
|
526
|
+
*,
|
|
527
|
+
status_reader: JsonReader,
|
|
528
|
+
unavailable_reader: Callable[[], bytes],
|
|
529
|
+
prompt_started_reader: JsonReader,
|
|
530
|
+
usage_reader: JsonReader,
|
|
531
|
+
rate_limits_reader: Callable[[], bytes],
|
|
532
|
+
usage_for_run_reader: RunJsonReader,
|
|
533
|
+
completion_commits_reader: JsonReader,
|
|
534
|
+
last_executed_commits_reader: JsonReader,
|
|
535
|
+
reviewer_agents_reader: RunJsonReader,
|
|
536
|
+
execution_reader: RunJsonReader,
|
|
537
|
+
runtime_metadata_reader: RunJsonReader,
|
|
538
|
+
report_analysis_available_reader: Callable[[Path, str | None], bool],
|
|
539
|
+
telemetry_reader: Callable[[Path], list[dict[str, Any]]],
|
|
540
|
+
process_metrics_reader: Callable[[], bytes],
|
|
541
|
+
build_commit_reader: Callable[[Path], str],
|
|
542
|
+
component_log_versions_reader: Callable[[Path], dict[str, str]],
|
|
543
|
+
dashboard_version: str,
|
|
544
|
+
worker_version: str,
|
|
545
|
+
) -> bytes:
|
|
546
|
+
"""Compose one complete read-only dashboard snapshot from small readers."""
|
|
547
|
+
def read_json(reader: Callable[..., bytes], *args: object, fallback: Any) -> Any:
|
|
548
|
+
try:
|
|
549
|
+
return json.loads(reader(*args))
|
|
550
|
+
except json.JSONDecodeError:
|
|
551
|
+
return fallback
|
|
552
|
+
|
|
553
|
+
status_payload = read_json(status_reader, root, fallback=None)
|
|
554
|
+
if not isinstance(status_payload, dict):
|
|
555
|
+
status_payload = read_json(unavailable_reader, fallback={})
|
|
556
|
+
run_id = status_payload.get("last_executed_run")
|
|
557
|
+
active_run_id = status_payload.get("run_id")
|
|
558
|
+
active_liveness = lease_liveness(root, active_run_id)
|
|
559
|
+
active = (
|
|
560
|
+
status_payload.get("watcher_state") == "ENGINEERING_RUN_ACTIVE"
|
|
561
|
+
and isinstance(active_run_id, str)
|
|
562
|
+
and active_liveness.get("state") == "LIVE"
|
|
563
|
+
)
|
|
564
|
+
try:
|
|
565
|
+
telemetry = telemetry_reader(root)
|
|
566
|
+
except Exception:
|
|
567
|
+
telemetry = []
|
|
568
|
+
try:
|
|
569
|
+
duration_estimate = (
|
|
570
|
+
comparable_duration_estimate(
|
|
571
|
+
root,
|
|
572
|
+
prompt_characters=status_payload.get("prompt_characters"),
|
|
573
|
+
runtime_metadata=status_payload.get("runtime_metadata"),
|
|
574
|
+
run_id=active_run_id,
|
|
575
|
+
current_phase=status_payload.get("current_phase"),
|
|
576
|
+
execution_mode=status_payload.get("execution_mode"),
|
|
577
|
+
)
|
|
578
|
+
if active
|
|
579
|
+
else {}
|
|
580
|
+
)
|
|
581
|
+
except Exception:
|
|
582
|
+
duration_estimate = {}
|
|
583
|
+
try:
|
|
584
|
+
identity = execution_host_configuration(root).resolve_execution_host_identity()
|
|
585
|
+
execution_host = {
|
|
586
|
+
"name": identity.name,
|
|
587
|
+
"version": identity.version,
|
|
588
|
+
"runtime": identity.runtime,
|
|
589
|
+
"runtime_prompt_transport": identity.runtime_prompt_transport,
|
|
590
|
+
}
|
|
591
|
+
except PlatformConfigurationError:
|
|
592
|
+
execution_host = {}
|
|
593
|
+
host_preflight = latest_host_preflight(root)
|
|
594
|
+
workspace_preflight = latest_workspace_preflight(root)
|
|
595
|
+
capability_preflight = latest_capability_preflight(root)
|
|
596
|
+
# A successful preflight supersedes any evidence it may have replaced on
|
|
597
|
+
# disk. Only unresolved checks belong in the current-drift projection.
|
|
598
|
+
current_drift = next((
|
|
599
|
+
item for preflight in (host_preflight, workspace_preflight, capability_preflight)
|
|
600
|
+
if str(preflight.get("outcome", "")).upper() != "PASS"
|
|
601
|
+
for item in preflight.get("drift_evidence", []) if isinstance(item, dict)
|
|
602
|
+
), None)
|
|
603
|
+
return json.dumps(
|
|
604
|
+
{
|
|
605
|
+
"status": status_payload,
|
|
606
|
+
"build_commit": build_commit_reader(root),
|
|
607
|
+
"prompt_started": read_json(prompt_started_reader, root, fallback={}),
|
|
608
|
+
"usage": read_json(usage_reader, root, fallback={}),
|
|
609
|
+
"rate_limits": read_json(rate_limits_reader, fallback={}),
|
|
610
|
+
"last_executed_usage": read_json(usage_for_run_reader, root, run_id, fallback={}),
|
|
611
|
+
"completion_commits": read_json(completion_commits_reader, root, fallback={}),
|
|
612
|
+
"last_executed_commits": read_json(last_executed_commits_reader, root, fallback={}),
|
|
613
|
+
"last_executed_reviewer_agents": read_json(reviewer_agents_reader, root, run_id, fallback=[]),
|
|
614
|
+
"last_executed_execution": read_json(execution_reader, root, run_id, fallback={}),
|
|
615
|
+
"last_executed_runtime_metadata": read_json(runtime_metadata_reader, root, run_id, fallback={}),
|
|
616
|
+
"last_executed_report_analysis_available": report_analysis_available_reader(root, run_id),
|
|
617
|
+
"telemetry": telemetry,
|
|
618
|
+
"duration_estimate": duration_estimate,
|
|
619
|
+
"process_metrics": read_json(process_metrics_reader, root, fallback={}) if active else {},
|
|
620
|
+
"component_log_versions": component_log_versions_reader(root),
|
|
621
|
+
"component_versions": {"dashboard": dashboard_version, "worker": worker_version},
|
|
622
|
+
"host_preflight": host_preflight,
|
|
623
|
+
"workspace_preflight": workspace_preflight,
|
|
624
|
+
"capability_preflight": capability_preflight,
|
|
625
|
+
"current_drift": current_drift or {},
|
|
626
|
+
"resume_guidance": drift_guidance([current_drift] if current_drift else []),
|
|
627
|
+
"execution_host": execution_host,
|
|
628
|
+
},
|
|
629
|
+
separators=(",", ":"),
|
|
630
|
+
).encode()
|