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,41 @@
|
|
|
1
|
+
export function normalizeDashboardStatus(status, fallback) {
|
|
2
|
+
return status && typeof status === "object" && !Array.isArray(status)
|
|
3
|
+
? status
|
|
4
|
+
: fallback;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function normalizeDashboardSnapshot(snapshot) {
|
|
8
|
+
return snapshot && typeof snapshot === "object" && !Array.isArray(snapshot)
|
|
9
|
+
? snapshot
|
|
10
|
+
: {};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createDashboardStatusStore({ fallback, render }) {
|
|
14
|
+
if (typeof render !== "function")
|
|
15
|
+
throw new TypeError("A dashboard status renderer is required.");
|
|
16
|
+
|
|
17
|
+
let latestSnapshotSource = null, latestSnapshotRevision = -1;
|
|
18
|
+
const store = {
|
|
19
|
+
status: fallback,
|
|
20
|
+
snapshot: {},
|
|
21
|
+
update(status, snapshot = {}) {
|
|
22
|
+
const nextStatus = normalizeDashboardStatus(status, fallback);
|
|
23
|
+
const nextSnapshot = normalizeDashboardSnapshot(snapshot);
|
|
24
|
+
const source = typeof nextSnapshot.snapshot_source === "string" ? nextSnapshot.snapshot_source : null;
|
|
25
|
+
const revision = Number.isSafeInteger(nextSnapshot.snapshot_revision) && nextSnapshot.snapshot_revision >= 0
|
|
26
|
+
? nextSnapshot.snapshot_revision
|
|
27
|
+
: null;
|
|
28
|
+
if (source && revision !== null) {
|
|
29
|
+
if (source === latestSnapshotSource && revision < latestSnapshotRevision)
|
|
30
|
+
return { status: store.status, snapshot: store.snapshot };
|
|
31
|
+
if (source !== latestSnapshotSource) latestSnapshotSource = source;
|
|
32
|
+
latestSnapshotRevision = revision;
|
|
33
|
+
}
|
|
34
|
+
store.status = nextStatus;
|
|
35
|
+
store.snapshot = nextSnapshot;
|
|
36
|
+
render(store.status, store.snapshot);
|
|
37
|
+
return { status: store.status, snapshot: store.snapshot };
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
return store;
|
|
41
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "EP Operations",
|
|
3
|
+
"short_name": "EP Operations",
|
|
4
|
+
"display": "standalone",
|
|
5
|
+
"background_color": "#0a6b9d",
|
|
6
|
+
"theme_color": "#0a6b9d",
|
|
7
|
+
"icons": [
|
|
8
|
+
{"src": "/assets/operations-console/icon-dark.png", "sizes": "1254x1254", "type": "image/png", "purpose": "any"},
|
|
9
|
+
{"src": "/assets/operations-console/icon-light.png", "sizes": "1254x1254", "type": "image/png", "purpose": "any"}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"""Fail-closed Level 3 capability admission for Engineering Inbox work.
|
|
2
|
+
|
|
3
|
+
This module evaluates only declared transaction requirements against the local
|
|
4
|
+
Execution Host contract. It never claims an Inbox item, allocates a run or
|
|
5
|
+
touches a target repository.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import asdict, dataclass
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
import re
|
|
16
|
+
import tempfile
|
|
17
|
+
from time import monotonic
|
|
18
|
+
|
|
19
|
+
from .platform_version import (
|
|
20
|
+
EngineeringPlatformCompatibilityError,
|
|
21
|
+
EngineeringPlatformManifest,
|
|
22
|
+
RunnerCompatibility,
|
|
23
|
+
_semver,
|
|
24
|
+
)
|
|
25
|
+
from .drift_diagnostics import evidence_for_checks, guidance, persist as persist_drift_evidence
|
|
26
|
+
from .provider_readiness import failures as provider_readiness_failures
|
|
27
|
+
from .central_database import capacity_reserve_from_environment
|
|
28
|
+
from .codex_capacity import read_remaining_percent
|
|
29
|
+
from .resources import package_path
|
|
30
|
+
|
|
31
|
+
RECOVERABILITY = frozenset(
|
|
32
|
+
{
|
|
33
|
+
"RETRYABLE",
|
|
34
|
+
"RETRYABLE_AFTER_HOST_REPAIR",
|
|
35
|
+
"REQUIRES_NEW_PROMPT",
|
|
36
|
+
"REQUIRES_OPERATOR_DECISION",
|
|
37
|
+
"NON_RETRYABLE",
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
FAILURE_ORIGINS = frozenset(
|
|
41
|
+
{"HOST", "WORKSPACE", "CAPABILITY", "VALIDATION", "ENGINEERING", "GOVERNANCE"}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class CapabilityCheck:
|
|
47
|
+
identifier: str
|
|
48
|
+
outcome: str
|
|
49
|
+
reason: str
|
|
50
|
+
recovery: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class CapabilityPreflightResult:
|
|
55
|
+
outcome: str
|
|
56
|
+
timestamp: str
|
|
57
|
+
duration_ms: int
|
|
58
|
+
checks: tuple[CapabilityCheck, ...]
|
|
59
|
+
recoverability: str
|
|
60
|
+
failure_origin: str | None
|
|
61
|
+
recommendation: str
|
|
62
|
+
drift_evidence: tuple[dict[str, str], ...] = ()
|
|
63
|
+
resume_guidance: dict[str, object] | None = None
|
|
64
|
+
|
|
65
|
+
def payload(self, run_id: str | None = None) -> dict[str, object]:
|
|
66
|
+
value = asdict(self)
|
|
67
|
+
value["checks"] = [asdict(check) for check in self.checks]
|
|
68
|
+
value["run_id"] = run_id
|
|
69
|
+
return value
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _check(identifier: str, passed: bool, reason: str, recovery: str) -> CapabilityCheck:
|
|
73
|
+
return CapabilityCheck(identifier, "PASS" if passed else "FAIL", reason, recovery)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _value(prompt: str, field: str) -> str | None:
|
|
77
|
+
match = re.search(rf"(?mi)^\s*{re.escape(field)}\s*:\s*([^\n]+)$", prompt)
|
|
78
|
+
return match.group(1).strip() if match else None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _requirements(prompt: str) -> dict[str, str]:
|
|
82
|
+
"""Read a bounded, provider-neutral declaration from the transaction."""
|
|
83
|
+
aliases = {
|
|
84
|
+
"Execution Host Version": "platform_version",
|
|
85
|
+
"Runner Version": "runner_version",
|
|
86
|
+
"Configuration Schema": "configuration_schema",
|
|
87
|
+
"Engineering Database Schema": "storage_schema",
|
|
88
|
+
"Checkpoint Format": "checkpoint_format",
|
|
89
|
+
"Memory Format": "memory_format",
|
|
90
|
+
"Report Format": "report_format",
|
|
91
|
+
"Execution Mode": "execution_mode",
|
|
92
|
+
"Required Runtime Components": "runtime_components",
|
|
93
|
+
"Required Provider Support": "provider_support",
|
|
94
|
+
"Required Capabilities": "capabilities",
|
|
95
|
+
}
|
|
96
|
+
return {key: value for field, key in aliases.items() if (value := _value(prompt, field))}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _persist(root: Path, result: CapabilityPreflightResult, run_id: str | None) -> None:
|
|
100
|
+
directory = root / ".engineering" / "status"
|
|
101
|
+
if not directory.is_dir():
|
|
102
|
+
return
|
|
103
|
+
temporary: str | None = None
|
|
104
|
+
try:
|
|
105
|
+
descriptor, temporary = tempfile.mkstemp(prefix=".capability-preflight-", dir=directory)
|
|
106
|
+
with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
|
|
107
|
+
handle.write(
|
|
108
|
+
json.dumps(result.payload(run_id), separators=(",", ":"), sort_keys=True) + "\n"
|
|
109
|
+
)
|
|
110
|
+
os.replace(temporary, directory / "capability_preflight.json")
|
|
111
|
+
except OSError:
|
|
112
|
+
if temporary:
|
|
113
|
+
Path(temporary).unlink(missing_ok=True)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def execute(root: Path, prompt: str, *, run_id: str | None = None) -> CapabilityPreflightResult:
|
|
117
|
+
"""Evaluate declared requirements before claim; absent declarations are compatible."""
|
|
118
|
+
started, checks = monotonic(), []
|
|
119
|
+
requirements = _requirements(prompt)
|
|
120
|
+
mode = requirements.get("execution_mode", "MANAGED").strip().upper()
|
|
121
|
+
required_providers = provider_readiness_failures(root, require_github=mode != "GENESIS")
|
|
122
|
+
checks.append(
|
|
123
|
+
_check(
|
|
124
|
+
"provider_readiness",
|
|
125
|
+
not required_providers,
|
|
126
|
+
"Required provider sessions are ready." if not required_providers else "Required provider sessions need attention: " + ", ".join(required_providers) + ".",
|
|
127
|
+
"Use the Engineering dashboard provider notification to install or sign in, then retry admission.",
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
reserve_percent = capacity_reserve_from_environment()
|
|
131
|
+
if reserve_percent:
|
|
132
|
+
remaining = read_remaining_percent()
|
|
133
|
+
capacity_ready = remaining is not None and remaining >= reserve_percent
|
|
134
|
+
checks.append(
|
|
135
|
+
_check(
|
|
136
|
+
"codex_capacity_reserve",
|
|
137
|
+
capacity_ready,
|
|
138
|
+
(
|
|
139
|
+
f"Codex has {remaining:.0f}% remaining; the configured reserve is {reserve_percent}%."
|
|
140
|
+
if remaining is not None
|
|
141
|
+
else "Codex capacity could not be verified for the configured admission reserve."
|
|
142
|
+
),
|
|
143
|
+
"Wait for Codex capacity to recover or lower the reserve in Available AI capacity before retrying admission.",
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
try:
|
|
147
|
+
manifest = EngineeringPlatformManifest.load(
|
|
148
|
+
package_path("ENGINEERING_PLATFORM_VERSION.json")
|
|
149
|
+
)
|
|
150
|
+
runner = RunnerCompatibility()
|
|
151
|
+
except EngineeringPlatformCompatibilityError as error:
|
|
152
|
+
checks.append(
|
|
153
|
+
_check("host_contract", False, str(error), "Repair the Execution Host contract.")
|
|
154
|
+
)
|
|
155
|
+
manifest = None
|
|
156
|
+
runner = None
|
|
157
|
+
if manifest and runner:
|
|
158
|
+
versions = (
|
|
159
|
+
(
|
|
160
|
+
"platform_version",
|
|
161
|
+
"execution_host_version",
|
|
162
|
+
manifest.platform_version,
|
|
163
|
+
runner.platform_version,
|
|
164
|
+
),
|
|
165
|
+
("runner_version", "runner_version", manifest.runner_version, runner.runner_version),
|
|
166
|
+
)
|
|
167
|
+
for requirement, identifier, available, actual in versions:
|
|
168
|
+
required = requirements.get(requirement)
|
|
169
|
+
passed = not required or _semver(actual, identifier) >= _semver(required, requirement)
|
|
170
|
+
checks.append(
|
|
171
|
+
_check(
|
|
172
|
+
identifier,
|
|
173
|
+
passed,
|
|
174
|
+
f"Required {required or 'none'}; available {available}.",
|
|
175
|
+
"Upgrade the Execution Host or submit a compatible prompt.",
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
formats = (
|
|
179
|
+
("checkpoint_format", manifest.checkpoint_format, runner.checkpoint_formats),
|
|
180
|
+
("memory_format", manifest.memory_format, runner.memory_formats),
|
|
181
|
+
("report_format", manifest.report_format, runner.report_formats),
|
|
182
|
+
("storage_schema", manifest.storage_schema, runner.storage_schemas),
|
|
183
|
+
)
|
|
184
|
+
for requirement, available, supported in formats:
|
|
185
|
+
required = (
|
|
186
|
+
int(requirements[requirement])
|
|
187
|
+
if requirements.get(requirement, "").isdigit()
|
|
188
|
+
else available
|
|
189
|
+
)
|
|
190
|
+
checks.append(
|
|
191
|
+
_check(
|
|
192
|
+
requirement,
|
|
193
|
+
required in supported,
|
|
194
|
+
f"Required {required}; supported {sorted(supported)}.",
|
|
195
|
+
"Upgrade the Execution Host or use a supported format.",
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
configuration_schema = (
|
|
199
|
+
int(requirements["configuration_schema"])
|
|
200
|
+
if requirements.get("configuration_schema", "").isdigit()
|
|
201
|
+
else 1
|
|
202
|
+
)
|
|
203
|
+
checks.append(
|
|
204
|
+
_check(
|
|
205
|
+
"configuration_schema",
|
|
206
|
+
configuration_schema == 1,
|
|
207
|
+
f"Required {configuration_schema}; supported [1].",
|
|
208
|
+
"Upgrade the Execution Host or use configuration schema 1.",
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
mode = requirements.get("execution_mode", "MANAGED").upper()
|
|
212
|
+
checks.append(
|
|
213
|
+
_check(
|
|
214
|
+
"execution_mode",
|
|
215
|
+
mode in {"MANAGED", "GENESIS"},
|
|
216
|
+
f"Execution mode {mode} is supported."
|
|
217
|
+
if mode in {"MANAGED", "GENESIS"}
|
|
218
|
+
else f"Execution mode {mode} is unsupported.",
|
|
219
|
+
"Use Managed or Genesis execution mode.",
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
for requirement, identifier, available in (
|
|
223
|
+
("runtime_components", "runtime_components", {"codex", "python", "git"}),
|
|
224
|
+
("provider_support", "provider_support", {"launchd"}),
|
|
225
|
+
(
|
|
226
|
+
"capabilities",
|
|
227
|
+
"required_capabilities",
|
|
228
|
+
{
|
|
229
|
+
"workspace_authorization",
|
|
230
|
+
"host_preflight",
|
|
231
|
+
"workspace_preflight",
|
|
232
|
+
"capability_preflight",
|
|
233
|
+
},
|
|
234
|
+
),
|
|
235
|
+
):
|
|
236
|
+
requested = {
|
|
237
|
+
item.strip().casefold()
|
|
238
|
+
for item in requirements.get(requirement, "").split(",")
|
|
239
|
+
if item.strip()
|
|
240
|
+
}
|
|
241
|
+
missing = requested - available
|
|
242
|
+
checks.append(
|
|
243
|
+
_check(
|
|
244
|
+
identifier,
|
|
245
|
+
not missing,
|
|
246
|
+
"All declared requirements are available."
|
|
247
|
+
if not missing
|
|
248
|
+
else f"Unsupported requirements: {', '.join(sorted(missing))}.",
|
|
249
|
+
"Install or configure the required host capability before retrying.",
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
failed = any(check.outcome == "FAIL" for check in checks)
|
|
253
|
+
drift_evidence = persist_drift_evidence(root, evidence_for_checks(
|
|
254
|
+
checks, stage="Capability Preflight", repository=str(root.resolve())
|
|
255
|
+
))
|
|
256
|
+
result = CapabilityPreflightResult(
|
|
257
|
+
"FAIL" if failed else "PASS",
|
|
258
|
+
datetime.now(timezone.utc).isoformat(),
|
|
259
|
+
round((monotonic() - started) * 1000),
|
|
260
|
+
tuple(checks),
|
|
261
|
+
"RETRYABLE_AFTER_HOST_REPAIR" if failed else "RETRYABLE",
|
|
262
|
+
"CAPABILITY" if failed else None,
|
|
263
|
+
"Repair or upgrade the Execution Host before resubmitting."
|
|
264
|
+
if failed
|
|
265
|
+
else "Capability admission passed.",
|
|
266
|
+
drift_evidence,
|
|
267
|
+
guidance(drift_evidence),
|
|
268
|
+
)
|
|
269
|
+
_persist(root, result, run_id)
|
|
270
|
+
return result
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def latest(root: Path) -> dict[str, object]:
|
|
274
|
+
try:
|
|
275
|
+
payload = json.loads(
|
|
276
|
+
(root / ".engineering/status/capability_preflight.json").read_text(encoding="utf-8")
|
|
277
|
+
)
|
|
278
|
+
except (OSError, json.JSONDecodeError):
|
|
279
|
+
return {}
|
|
280
|
+
if not isinstance(payload, dict):
|
|
281
|
+
return {}
|
|
282
|
+
return {key: payload[key] for key in (
|
|
283
|
+
"outcome", "timestamp", "duration_ms", "checks", "recoverability",
|
|
284
|
+
"failure_origin", "recommendation", "drift_evidence", "resume_guidance", "run_id",
|
|
285
|
+
) if key in payload}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Deterministic, read-only capability reviewer selection for the Execution Host."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Callable, Protocol
|
|
10
|
+
|
|
11
|
+
from .agent_state import redact_diagnostic
|
|
12
|
+
from .provider_context import ProviderRole, project_context
|
|
13
|
+
from .provider_context_scope import ContextScope, POLICY_ID, provider_instruction
|
|
14
|
+
from .reviewer_evidence import ReviewerEvidence
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
REVIEWER_ORDER = (
|
|
18
|
+
"apple_platform",
|
|
19
|
+
"windows_platform",
|
|
20
|
+
"home_assistant_integration",
|
|
21
|
+
"esphome_firmware",
|
|
22
|
+
"pi_renderer",
|
|
23
|
+
"universal_receiver",
|
|
24
|
+
"website",
|
|
25
|
+
"api",
|
|
26
|
+
"repository_governance",
|
|
27
|
+
"validation",
|
|
28
|
+
"documentation",
|
|
29
|
+
"finalization",
|
|
30
|
+
)
|
|
31
|
+
REVIEWER_LABELS = {
|
|
32
|
+
"apple_platform": "Apple Platform Reviewer",
|
|
33
|
+
"windows_platform": "Windows Platform Reviewer",
|
|
34
|
+
"home_assistant_integration": "Home Assistant Integration Reviewer",
|
|
35
|
+
"esphome_firmware": "ESPHome Firmware Reviewer",
|
|
36
|
+
"pi_renderer": "Pi Renderer Reviewer",
|
|
37
|
+
"universal_receiver": "Universal Receiver Reviewer",
|
|
38
|
+
"website": "Website Reviewer",
|
|
39
|
+
"api": "API Reviewer",
|
|
40
|
+
"repository_governance": "Repository Governance Reviewer",
|
|
41
|
+
"validation": "Validation Reviewer",
|
|
42
|
+
"documentation": "Documentation Reviewer",
|
|
43
|
+
"finalization": "Finalization Reviewer",
|
|
44
|
+
}
|
|
45
|
+
PRODUCT_MATCHERS = {
|
|
46
|
+
"apple_platform": (("apps/apple/", "engineering-platform-app", "swiftui", "watchos", "macos", "ios"), "Apple platform capability"),
|
|
47
|
+
"windows_platform": (("apps/windows/", "engineering-platform-windows", "maui", "windows packaging"), "Windows platform capability"),
|
|
48
|
+
"home_assistant_integration": (("custom_components/engineering_platform", "home assistant", "config flow", "options flow", "coordinator", "entity model"), "Home Assistant integration capability"),
|
|
49
|
+
"esphome_firmware": (("esphome", "engineering-platform-esp32", "firmware yaml", ".yaml"), "ESPHome firmware capability"),
|
|
50
|
+
"pi_renderer": (("engineering-platform-pi", "pi renderer", "raspberry pi", "display lifecycle"), "Pi renderer capability"),
|
|
51
|
+
"universal_receiver": (("universal receiver", "vibecast", "browser receiver", "receiver transport"), "Universal Receiver capability"),
|
|
52
|
+
"website": (("engineering-platform-website", "website", "static site", "product messaging"), "Website capability"),
|
|
53
|
+
"api": (("engineering-platform-api", "rest api", "api contract", "api documentation"), "API capability"),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class ReviewerSelection:
|
|
59
|
+
reviewer: str
|
|
60
|
+
selected_because: str
|
|
61
|
+
confidence: float
|
|
62
|
+
capability: str = "engineering"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class ReviewerResult:
|
|
67
|
+
reviewer: str
|
|
68
|
+
contribution: str
|
|
69
|
+
recommendations: tuple[str, ...] = ()
|
|
70
|
+
failed: bool = False
|
|
71
|
+
usage: dict[str, object] = field(default_factory=dict)
|
|
72
|
+
runtime_metadata: dict[str, object] = field(default_factory=dict)
|
|
73
|
+
churn: dict[str, object] = field(default_factory=dict)
|
|
74
|
+
duration_seconds: float | None = None
|
|
75
|
+
usage_snapshots: tuple[dict[str, int], ...] = ()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ReviewerClient(Protocol):
|
|
79
|
+
def review(
|
|
80
|
+
self,
|
|
81
|
+
root: Path,
|
|
82
|
+
selection: ReviewerSelection,
|
|
83
|
+
objective: str,
|
|
84
|
+
evidence: ReviewerEvidence | None = None,
|
|
85
|
+
) -> ReviewerResult: ...
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def select_reviewers(objective: str, prompt_path: Path, transaction_kind: str, memory: object) -> tuple[ReviewerSelection, ...]:
|
|
89
|
+
"""Select only registered reviewers from objective, lifecycle and safe memory evidence."""
|
|
90
|
+
text = f"{prompt_path.name} {objective}".lower()
|
|
91
|
+
selected: dict[str, str] = {}
|
|
92
|
+
for reviewer, (markers, reason) in PRODUCT_MATCHERS.items():
|
|
93
|
+
if any(marker in text for marker in markers):
|
|
94
|
+
selected[reviewer] = reason
|
|
95
|
+
if any(token in text for token in ("governance", "repository", "roadmap", "policy", "bootstrap")):
|
|
96
|
+
selected["repository_governance"] = "repository-governance objective"
|
|
97
|
+
if any(token in text for token in ("test", "ruff", "bandit", "assurance", "validation", "failure")):
|
|
98
|
+
selected["validation"] = "validation-related objective"
|
|
99
|
+
if prompt_path.suffix.lower() == ".md" or any(token in text for token in ("document", "wording", "readme", "backlog")):
|
|
100
|
+
selected["documentation"] = "documentation-oriented objective"
|
|
101
|
+
if transaction_kind == "FINALIZATION" or "finalization" in text:
|
|
102
|
+
selected["finalization"] = "Finalization lifecycle evidence"
|
|
103
|
+
history = _reviewer_memory(memory)
|
|
104
|
+
result: list[ReviewerSelection] = []
|
|
105
|
+
for reviewer in REVIEWER_ORDER:
|
|
106
|
+
reason = selected.get(reviewer)
|
|
107
|
+
if reason is None:
|
|
108
|
+
continue
|
|
109
|
+
confidence = min(1.0, 0.5 + history.get(reviewer, 0.0))
|
|
110
|
+
capability = reviewer if reviewer in PRODUCT_MATCHERS else "engineering"
|
|
111
|
+
result.append(ReviewerSelection(reviewer, reason, confidence, capability))
|
|
112
|
+
return tuple(result)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
ReviewerProgressCallback = Callable[[ReviewerSelection, str, ReviewerResult | None], None]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def run_reviews(
|
|
119
|
+
root: Path,
|
|
120
|
+
selections: tuple[ReviewerSelection, ...],
|
|
121
|
+
objective: str,
|
|
122
|
+
client: ReviewerClient | None,
|
|
123
|
+
progress: ReviewerProgressCallback | None = None,
|
|
124
|
+
evidence: ReviewerEvidence | None = None,
|
|
125
|
+
) -> tuple[ReviewerResult, ...]:
|
|
126
|
+
"""Run independent read-only reviews in parallel; any failure remains advisory."""
|
|
127
|
+
if not selections:
|
|
128
|
+
return ()
|
|
129
|
+
if client is None:
|
|
130
|
+
results = tuple(ReviewerResult(item.reviewer, "Reviewer client unavailable; primary review continues.", failed=True) for item in selections)
|
|
131
|
+
if progress:
|
|
132
|
+
for selection, result in zip(selections, results, strict=True):
|
|
133
|
+
progress(selection, "failed", result)
|
|
134
|
+
return results
|
|
135
|
+
|
|
136
|
+
def invoke(selection: ReviewerSelection) -> ReviewerResult:
|
|
137
|
+
if progress:
|
|
138
|
+
progress(selection, "started", None)
|
|
139
|
+
try:
|
|
140
|
+
result = client.review(root, selection, objective, evidence)
|
|
141
|
+
if result.reviewer != selection.reviewer:
|
|
142
|
+
result = ReviewerResult(selection.reviewer, "Reviewer identity mismatch; primary review continues.", failed=True)
|
|
143
|
+
else:
|
|
144
|
+
result = ReviewerResult(
|
|
145
|
+
selection.reviewer,
|
|
146
|
+
redact_diagnostic(result.contribution, limit=240),
|
|
147
|
+
tuple(redact_diagnostic(value, limit=240) for value in result.recommendations[:3]),
|
|
148
|
+
result.failed,
|
|
149
|
+
result.usage,
|
|
150
|
+
result.runtime_metadata,
|
|
151
|
+
result.churn,
|
|
152
|
+
result.duration_seconds,
|
|
153
|
+
)
|
|
154
|
+
except Exception: # Reviewer failure is advisory and cannot block the transaction.
|
|
155
|
+
result = ReviewerResult(selection.reviewer, "Reviewer failed; primary review continues.", failed=True)
|
|
156
|
+
if progress:
|
|
157
|
+
progress(selection, "failed" if result.failed else "completed", result)
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
with ThreadPoolExecutor(max_workers=len(selections)) as executor:
|
|
161
|
+
completed = {item.reviewer: executor.submit(invoke, item) for item in selections}
|
|
162
|
+
return tuple(completed[item.reviewer].result() for item in selections)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def reconciled_recommendations(results: tuple[ReviewerResult, ...]) -> tuple[str, ...]:
|
|
166
|
+
"""Deduplicate safe advisory recommendations for the primary agent prompt."""
|
|
167
|
+
accepted: list[str] = []
|
|
168
|
+
for result in results:
|
|
169
|
+
if result.failed:
|
|
170
|
+
continue
|
|
171
|
+
for recommendation in result.recommendations:
|
|
172
|
+
if recommendation and recommendation not in accepted:
|
|
173
|
+
accepted.append(recommendation)
|
|
174
|
+
return tuple(accepted[:8])
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def records_for_storage(selections: tuple[ReviewerSelection, ...], results: tuple[ReviewerResult, ...]) -> tuple[dict[str, object], ...]:
|
|
178
|
+
by_reviewer = {result.reviewer: result for result in results}
|
|
179
|
+
records: list[dict[str, object]] = []
|
|
180
|
+
for selection in selections:
|
|
181
|
+
result = by_reviewer.get(selection.reviewer, ReviewerResult(selection.reviewer, "No result.", failed=True))
|
|
182
|
+
records.append({
|
|
183
|
+
"reviewer": selection.reviewer,
|
|
184
|
+
"capability": selection.capability,
|
|
185
|
+
"selected_because": selection.selected_because,
|
|
186
|
+
"confidence": selection.confidence,
|
|
187
|
+
"contribution": result.contribution,
|
|
188
|
+
"accepted_recommendations": len(result.recommendations) if not result.failed else 0,
|
|
189
|
+
"rejected_recommendations": 0,
|
|
190
|
+
"failed": result.failed,
|
|
191
|
+
"codex_commands_executed": _command_count(result.churn),
|
|
192
|
+
})
|
|
193
|
+
return tuple(records)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _command_count(churn: object) -> int:
|
|
197
|
+
"""Return the safe, per-review command total without sharing agent state."""
|
|
198
|
+
if not isinstance(churn, dict):
|
|
199
|
+
return 0
|
|
200
|
+
value = churn.get("tool_loop_operations", 0)
|
|
201
|
+
return value if isinstance(value, int) and not isinstance(value, bool) and value >= 0 else 0
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _reviewer_memory(memory: object) -> dict[str, float]:
|
|
205
|
+
if not isinstance(memory, dict):
|
|
206
|
+
return {}
|
|
207
|
+
result: dict[str, float] = {}
|
|
208
|
+
for entry in memory.get("reviewers", []):
|
|
209
|
+
if isinstance(entry, dict) and entry.get("reviewer") in REVIEWER_ORDER:
|
|
210
|
+
confidence = entry.get("future_confidence")
|
|
211
|
+
if isinstance(confidence, (int, float)) and 0.0 <= confidence <= 1.0:
|
|
212
|
+
result[str(entry["reviewer"])] = float(confidence)
|
|
213
|
+
return result
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def reviewer_prompt(
|
|
217
|
+
selection: ReviewerSelection,
|
|
218
|
+
objective: str,
|
|
219
|
+
evidence: ReviewerEvidence | None = None,
|
|
220
|
+
) -> str:
|
|
221
|
+
"""Build the bounded read-only reviewer instruction without lifecycle authority."""
|
|
222
|
+
projection = project_context(ProviderRole.SPECIALIST_REVIEW, objective)
|
|
223
|
+
prompt: dict[str, object] = {
|
|
224
|
+
"reviewer": REVIEWER_LABELS[selection.reviewer],
|
|
225
|
+
"capability": selection.capability,
|
|
226
|
+
"selected_because": selection.selected_because,
|
|
227
|
+
"objective": projection.text,
|
|
228
|
+
"context_projection": {
|
|
229
|
+
"role": projection.role.value,
|
|
230
|
+
"budget_version": projection.budget_version,
|
|
231
|
+
"source_item_count": projection.source_item_count,
|
|
232
|
+
"omitted_low_priority_count": projection.omitted_low_priority_count,
|
|
233
|
+
},
|
|
234
|
+
"provider_context_scope": {
|
|
235
|
+
"policy": POLICY_ID,
|
|
236
|
+
"initial_scope": ContextScope.NORMAL.value,
|
|
237
|
+
"instruction": provider_instruction(ContextScope.NORMAL),
|
|
238
|
+
},
|
|
239
|
+
"authority": "Read-only inspection and recommendations only. Do not edit, commit, push, merge, create pull requests, finalize, or change lifecycle state.",
|
|
240
|
+
"scope": "Analyse only the declared capability. Cross-capability analysis requires objective repository evidence.",
|
|
241
|
+
}
|
|
242
|
+
if evidence is not None:
|
|
243
|
+
prompt["run_scoped_repository_evidence"] = evidence.to_dict()
|
|
244
|
+
prompt["evidence_instructions"] = (
|
|
245
|
+
"These are host-observed facts for this exact Run ID, collected after "
|
|
246
|
+
"synchronization and before this reviewer wave. Reuse them for ordinary "
|
|
247
|
+
"repository-state questions; do not rediscover branch, HEAD, worktree, "
|
|
248
|
+
"repository identity, or main ancestry with Git/GitHub. They are facts, "
|
|
249
|
+
"not conclusions. Retrieve only narrower additional evidence that your "
|
|
250
|
+
"capability review genuinely requires. This snapshot expires at any "
|
|
251
|
+
"repository mutation, validation, PR/merge, finalization, or cleanup boundary."
|
|
252
|
+
)
|
|
253
|
+
prompt["invocation_read_reuse"] = (
|
|
254
|
+
"Within this one reviewer invocation, reuse already inspected immutable file "
|
|
255
|
+
"content for factual inspection rather than accidentally rereading it. "
|
|
256
|
+
"Do not share content, conclusions, or reasoning with another reviewer or "
|
|
257
|
+
"Run ID. Reread after an edit, generated-artifact refresh, repository "
|
|
258
|
+
"change, validation, PR/merge, finalization, cleanup, or whenever freshness "
|
|
259
|
+
"is uncertain. Deliberate verification reads remain required."
|
|
260
|
+
)
|
|
261
|
+
return json.dumps(prompt, sort_keys=True)
|