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.

Potentially problematic release.


This version of engineering-platform might be problematic. Click here for more details.

Files changed (130) hide show
  1. engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +32 -0
  2. engineering_platform/ENGINEERING_PLATFORM_VERSION.json +15 -0
  3. engineering_platform/__init__.py +1 -0
  4. engineering_platform/__main__.py +7 -0
  5. engineering_platform/agent_state.py +530 -0
  6. engineering_platform/agent_trust.py +174 -0
  7. engineering_platform/assets/dashboard.css +1317 -0
  8. engineering_platform/assets/dashboard.js +8534 -0
  9. engineering_platform/assets/dashboard_locales.mjs +4049 -0
  10. engineering_platform/assets/dashboard_status_store.mjs +41 -0
  11. engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
  12. engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
  13. engineering_platform/assets/operations-console/icon-dark.png +0 -0
  14. engineering_platform/assets/operations-console/icon-light.png +0 -0
  15. engineering_platform/assets/operations-console/icon-transparent.png +0 -0
  16. engineering_platform/assets/operations-console/manifest.webmanifest +11 -0
  17. engineering_platform/capability_preflight.py +285 -0
  18. engineering_platform/capability_review.py +261 -0
  19. engineering_platform/central_data_transfer.py +195 -0
  20. engineering_platform/central_database.py +245 -0
  21. engineering_platform/central_store_migration.py +1672 -0
  22. engineering_platform/codex_capacity.py +81 -0
  23. engineering_platform/codex_chat.py +226 -0
  24. engineering_platform/codex_observability.py +153 -0
  25. engineering_platform/component_lock.py +40 -0
  26. engineering_platform/component_logging.py +420 -0
  27. engineering_platform/console_presentation.py +14 -0
  28. engineering_platform/console_route_ownership.py +83 -0
  29. engineering_platform/contracts/__init__.py +38 -0
  30. engineering_platform/contracts/ep_consumer.py +391 -0
  31. engineering_platform/contracts/models.py +105 -0
  32. engineering_platform/contracts/projection.py +401 -0
  33. engineering_platform/dashboard_browser_validation.py +206 -0
  34. engineering_platform/dashboard_state.py +630 -0
  35. engineering_platform/dashboard_supervisor.swift +105 -0
  36. engineering_platform/dashboard_translation.py +129 -0
  37. engineering_platform/dependabot_producer.py +349 -0
  38. engineering_platform/drift_diagnostics.py +144 -0
  39. engineering_platform/emergency_recovery.py +268 -0
  40. engineering_platform/engineering_memory.py +139 -0
  41. engineering_platform/ep_consumer_credentials.py +473 -0
  42. engineering_platform/evidence_projection.py +213 -0
  43. engineering_platform/execution_activity.py +218 -0
  44. engineering_platform/execution_context.py +132 -0
  45. engineering_platform/execution_errors.py +42 -0
  46. engineering_platform/execution_evidence.py +24 -0
  47. engineering_platform/execution_executor.py +730 -0
  48. engineering_platform/execution_finalization.py +44 -0
  49. engineering_platform/execution_host.py +3306 -0
  50. engineering_platform/execution_lease.py +365 -0
  51. engineering_platform/execution_lifecycle.py +447 -0
  52. engineering_platform/execution_models.py +43 -0
  53. engineering_platform/execution_readiness.py +166 -0
  54. engineering_platform/execution_reporting.py +1607 -0
  55. engineering_platform/execution_repository.py +253 -0
  56. engineering_platform/execution_timeout_policy.py +56 -0
  57. engineering_platform/execution_timing.py +440 -0
  58. engineering_platform/execution_transaction.py +28 -0
  59. engineering_platform/external_producer_binding.py +235 -0
  60. engineering_platform/file_inbox.py +249 -0
  61. engineering_platform/forensic_attribution.py +338 -0
  62. engineering_platform/forensic_attribution_v2.py +134 -0
  63. engineering_platform/forensic_delta.py +299 -0
  64. engineering_platform/golden_scenario.py +63 -0
  65. engineering_platform/historical_dashboard_configuration.py +171 -0
  66. engineering_platform/host_admin.py +199 -0
  67. engineering_platform/host_preflight.py +231 -0
  68. engineering_platform/installation_relocation.py +122 -0
  69. engineering_platform/investigation_ledger.py +89 -0
  70. engineering_platform/legacy_inbox_migration.py +79 -0
  71. engineering_platform/lifecycle_worker.py +223 -0
  72. engineering_platform/live_status.py +267 -0
  73. engineering_platform/local_api.py +209 -0
  74. engineering_platform/local_api_keychain.py +51 -0
  75. engineering_platform/local_repository_binding.py +138 -0
  76. engineering_platform/managed_autonomy.py +509 -0
  77. engineering_platform/managed_codex_runtime.py +105 -0
  78. engineering_platform/parity_context.py +203 -0
  79. engineering_platform/parity_lifecycle_dispatcher.py +488 -0
  80. engineering_platform/platform_admin.py +13 -0
  81. engineering_platform/platform_api.py +428 -0
  82. engineering_platform/platform_bootstrap.py +385 -0
  83. engineering_platform/platform_components.py +65 -0
  84. engineering_platform/platform_version.py +171 -0
  85. engineering_platform/pr_check_repair.py +276 -0
  86. engineering_platform/pr_evidence_backfill.py +278 -0
  87. engineering_platform/producer.py +209 -0
  88. engineering_platform/project_agent.py +366 -0
  89. engineering_platform/project_agent_service.py +244 -0
  90. engineering_platform/project_topology.py +126 -0
  91. engineering_platform/prompt_history.py +591 -0
  92. engineering_platform/provider_context.py +136 -0
  93. engineering_platform/provider_context_benchmark.py +41 -0
  94. engineering_platform/provider_context_scope.py +90 -0
  95. engineering_platform/provider_interruption.py +168 -0
  96. engineering_platform/provider_process_identity.py +80 -0
  97. engineering_platform/provider_readiness.py +138 -0
  98. engineering_platform/provider_recovery.py +647 -0
  99. engineering_platform/provider_usage.py +497 -0
  100. engineering_platform/providers.py +471 -0
  101. engineering_platform/qualification.py +220 -0
  102. engineering_platform/recommendation_handoff.py +238 -0
  103. engineering_platform/report_analysis.py +193 -0
  104. engineering_platform/repository_attachment.py +171 -0
  105. engineering_platform/repository_handoff.py +95 -0
  106. engineering_platform/resources.py +38 -0
  107. engineering_platform/reviewer_evidence.py +70 -0
  108. engineering_platform/schemas/repository-attachment.schema.json +61 -0
  109. engineering_platform/server.py +3679 -0
  110. engineering_platform/server_console_services.py +2024 -0
  111. engineering_platform/server_relay.py +172 -0
  112. engineering_platform/server_service.py +122 -0
  113. engineering_platform/status_model.py +135 -0
  114. engineering_platform/status_reconciliation.py +34 -0
  115. engineering_platform/storage.py +2440 -0
  116. engineering_platform/submission_cli.py +77 -0
  117. engineering_platform/submission_intake.py +45 -0
  118. engineering_platform/submission_service.py +317 -0
  119. engineering_platform/telemetry.py +951 -0
  120. engineering_platform/templates/workspace-config.json +25 -0
  121. engineering_platform/validation_identity.py +50 -0
  122. engineering_platform/validation_profile.py +211 -0
  123. engineering_platform/workspace_preflight.py +263 -0
  124. engineering_platform/worktree_provenance.py +147 -0
  125. engineering_platform/worktree_tooling.py +18 -0
  126. engineering_platform-2.2.0.dist-info/METADATA +18 -0
  127. engineering_platform-2.2.0.dist-info/RECORD +130 -0
  128. engineering_platform-2.2.0.dist-info/WHEEL +5 -0
  129. engineering_platform-2.2.0.dist-info/entry_points.txt +6 -0
  130. engineering_platform-2.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,199 @@
1
+ """Server-owned, containment-safe Host Admin observations and mutation gate.
2
+
3
+ Host Admin never discovers a target from a request, project, checkout, CWD,
4
+ remote, browser, or Finder. Deployments provide an explicit registry; this
5
+ module resolves opaque identifiers from that registry only.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ from pathlib import Path
11
+ import re
12
+ import shutil
13
+ import subprocess
14
+ from typing import Iterable
15
+
16
+ from . import managed_codex_runtime
17
+ from .component_logging import component_logger, log_event
18
+
19
+ _TARGET_ID = re.compile(r"[a-z][a-z0-9-]{0,63}")
20
+
21
+
22
+ class HostAdminTargetError(ValueError):
23
+ """A requested Host Admin target is absent, stale, or unsafe."""
24
+
25
+
26
+ def _resolved(path: Path) -> Path:
27
+ try:
28
+ return path.resolve(strict=True)
29
+ except OSError as error:
30
+ raise HostAdminTargetError("HOST_ADMIN_TARGET_STALE") from error
31
+
32
+
33
+ def _contained(path: Path, root: Path) -> bool:
34
+ try:
35
+ path.relative_to(root)
36
+ except ValueError:
37
+ return False
38
+ return True
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class HostAdminTarget:
43
+ """A deployment-approved Git/worktree boundary, never request-derived."""
44
+
45
+ target_id: str
46
+ containment_root: Path
47
+ primary_worktree: Path
48
+ worktrees: tuple[tuple[str, Path], ...] = ()
49
+
50
+ def validated(self) -> "HostAdminTarget":
51
+ if not _TARGET_ID.fullmatch(self.target_id):
52
+ raise HostAdminTargetError("HOST_ADMIN_TARGET_INVALID")
53
+ root, primary = _resolved(self.containment_root), _resolved(self.primary_worktree)
54
+ if not root.is_dir() or not primary.is_dir() or not _contained(primary, root):
55
+ raise HostAdminTargetError("HOST_ADMIN_TARGET_OUTSIDE_CONTAINMENT")
56
+ seen: set[str] = set(); approved: list[tuple[str, Path]] = []
57
+ for worktree_id, worktree in self.worktrees:
58
+ if not _TARGET_ID.fullmatch(worktree_id) or worktree_id in seen:
59
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_TARGET_INVALID")
60
+ candidate = _resolved(worktree)
61
+ if not candidate.is_dir() or not _contained(candidate, root):
62
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_ESCAPE")
63
+ seen.add(worktree_id); approved.append((worktree_id, candidate))
64
+ return HostAdminTarget(self.target_id, root, primary, tuple(approved))
65
+
66
+
67
+ class HostAdminTargetRegistry:
68
+ """The only source of mutable Host Admin target identity."""
69
+
70
+ def __init__(self, targets: Iterable[HostAdminTarget] = ()) -> None:
71
+ values = [target.validated() for target in targets]
72
+ if len({target.target_id for target in values}) != len(values):
73
+ raise HostAdminTargetError("HOST_ADMIN_TARGET_DUPLICATE")
74
+ self._targets = {target.target_id: target for target in values}
75
+
76
+ def target(self, target_id: object) -> HostAdminTarget:
77
+ if not isinstance(target_id, str) or target_id not in self._targets:
78
+ raise HostAdminTargetError("HOST_ADMIN_TARGET_UNKNOWN")
79
+ return self._targets[target_id].validated()
80
+
81
+ def worktree(self, target_id: object, worktree_id: object) -> Path:
82
+ target = self.target(target_id)
83
+ if not isinstance(worktree_id, str):
84
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_TARGET_UNKNOWN")
85
+ for registered_id, path in target.worktrees:
86
+ if registered_id == worktree_id:
87
+ return path
88
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_TARGET_UNKNOWN")
89
+
90
+
91
+ def installation_root(data_root: Path) -> Path:
92
+ return data_root.resolve()
93
+
94
+
95
+ def registry(_data_root: Path) -> HostAdminTargetRegistry:
96
+ """Fail closed until deployment provisions explicit targets outside HTTP."""
97
+ return HostAdminTargetRegistry()
98
+
99
+
100
+ def _audit(data_root: Path, event: str, *, target_id: object, outcome: str) -> None:
101
+ log_event(component_logger(data_root, "ep_server"), 20, event,
102
+ diagnostic=f"target_id={target_id!r}; outcome={outcome}")
103
+
104
+
105
+ def worktree_inventory(targets: HostAdminTargetRegistry, target_id: object) -> dict[str, object]:
106
+ """Return registered worktrees that Git currently reports, in containment."""
107
+ target = targets.target(target_id)
108
+ try:
109
+ result = subprocess.run(("git", "-C", str(target.primary_worktree), "worktree", "list", "--porcelain"),
110
+ check=False, capture_output=True, text=True)
111
+ except OSError as error:
112
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_INVENTORY_UNAVAILABLE") from error
113
+ if result.returncode != 0:
114
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_INVENTORY_UNAVAILABLE")
115
+ observed = {line.split(" ", 1)[1] for line in result.stdout.splitlines() if line.startswith("worktree ")}
116
+ rows = []
117
+ for worktree_id, path in target.worktrees:
118
+ current = _resolved(path)
119
+ rows.append({"worktree_id": worktree_id, "registered": True,
120
+ "present": str(current) in observed,
121
+ "primary": current == target.primary_worktree, "path": str(current)})
122
+ return {"target_id": target.target_id, "worktrees": rows}
123
+
124
+
125
+ def diagnose_git_lock(targets: HostAdminTargetRegistry, target_id: object) -> dict[str, object]:
126
+ """Diagnose exactly the primary index lock; never accept a lock pathname."""
127
+ target = targets.target(target_id)
128
+ lock = target.primary_worktree / ".git" / "index.lock"
129
+ if not lock.parent.is_dir() or not _contained(_resolved(lock.parent), target.containment_root):
130
+ raise HostAdminTargetError("HOST_ADMIN_GIT_LOCK_AMBIGUOUS")
131
+ if lock.is_symlink():
132
+ raise HostAdminTargetError("HOST_ADMIN_GIT_LOCK_ESCAPE")
133
+ active_owner = False
134
+ if lock.exists():
135
+ try:
136
+ probe = subprocess.run(("lsof", "--", str(lock)), check=False,
137
+ capture_output=True, text=True)
138
+ active_owner = probe.returncode == 0 and bool(probe.stdout.strip())
139
+ except OSError:
140
+ # No owner probe never authorizes a mutation; repair remains
141
+ # removed, while this bounded diagnostic remains available.
142
+ active_owner = False
143
+ return {"target_id": target.target_id, "lock": str(lock), "exists": lock.exists(),
144
+ "active_owner": active_owner, "repairable": False}
145
+
146
+
147
+ def remove_worktree(data_root: Path, targets: HostAdminTargetRegistry,
148
+ target_id: object, worktree_id: object) -> dict[str, object]:
149
+ """Gate legacy removal after registration/inventory checks; deletion is removed."""
150
+ try:
151
+ target = targets.target(target_id); worktree = targets.worktree(target_id, worktree_id)
152
+ inventory = worktree_inventory(targets, target_id)
153
+ row = next((item for item in inventory["worktrees"] if item["worktree_id"] == worktree_id), None)
154
+ if not isinstance(row, dict) or not row["present"]:
155
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_TARGET_STALE")
156
+ if worktree == target.primary_worktree or row["primary"]:
157
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_PRIMARY_PROTECTED")
158
+ # A dirty worktree is never an administrative cleanup candidate. A
159
+ # Git index lock is the bounded active-owner signal available without
160
+ # process discovery; ambiguity fails closed.
161
+ status = subprocess.run(("git", "-C", str(worktree), "status", "--porcelain"),
162
+ check=False, capture_output=True, text=True)
163
+ if status.returncode != 0:
164
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_STATUS_UNAVAILABLE")
165
+ if status.stdout.strip():
166
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_DIRTY")
167
+ if (worktree / ".git" / "index.lock").exists():
168
+ raise HostAdminTargetError("HOST_ADMIN_WORKTREE_ACTIVE")
169
+ _audit(data_root, "host_admin_worktree_removal_refused", target_id=target_id, outcome="UNSUPPORTED_REMOVED")
170
+ return {"outcome": "UNSUPPORTED_REMOVED", "worktree_id": worktree_id}
171
+ except HostAdminTargetError as error:
172
+ _audit(data_root, "host_admin_worktree_removal_rejected", target_id=target_id, outcome=str(error))
173
+ raise
174
+
175
+
176
+ def repair_git_lock(data_root: Path, targets: HostAdminTargetRegistry, target_id: object) -> dict[str, object]:
177
+ """Gate legacy repair after exact diagnosis; arbitrary lock deletion is removed."""
178
+ try:
179
+ diagnosis = diagnose_git_lock(targets, target_id)
180
+ if not diagnosis["exists"]:
181
+ raise HostAdminTargetError("HOST_ADMIN_GIT_LOCK_ABSENT")
182
+ if diagnosis["active_owner"]:
183
+ raise HostAdminTargetError("HOST_ADMIN_GIT_LOCK_ACTIVE")
184
+ _audit(data_root, "host_admin_git_lock_repair_refused", target_id=target_id, outcome="UNSUPPORTED_REMOVED")
185
+ return {"outcome": "UNSUPPORTED_REMOVED", "target_id": target_id}
186
+ except HostAdminTargetError as error:
187
+ _audit(data_root, "host_admin_git_lock_repair_rejected", target_id=target_id, outcome=str(error))
188
+ raise
189
+
190
+
191
+ def diagnostics(data_root: Path) -> dict[str, object]:
192
+ root = installation_root(data_root); usage = shutil.disk_usage(root)
193
+ runtime = managed_codex_runtime.inspect(root)
194
+ state = runtime.get("state") if isinstance(runtime, dict) else "UNKNOWN"
195
+ return {"scope": "HOST_ADMIN", "root_kind": "EP_SERVER_INSTALLATION",
196
+ "disk": {"total_bytes": usage.total, "used_bytes": usage.used, "free_bytes": usage.free},
197
+ "managed_codex_runtime": {"state": state}, "registered_targets": 0,
198
+ "mutations_supported": False, "project_authority": False,
199
+ "execution_authority": False, "queue_authority": False}
@@ -0,0 +1,231 @@
1
+ """Fail-closed Level 1 health checks for the local Engineering Execution Host.
2
+
3
+ This module intentionally validates only the host's own configuration, runtime
4
+ and evidence services. It never inspects a target repository or prompt.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import asdict, dataclass
10
+ from datetime import datetime, timezone
11
+ import json
12
+ import os
13
+ from pathlib import Path
14
+ import re
15
+ import shutil
16
+ import sqlite3
17
+ import tempfile
18
+ from time import monotonic
19
+
20
+ from .component_logging import component_logger
21
+ from .platform_api import PlatformConfiguration, PlatformConfigurationError
22
+ from .platform_version import EngineeringPlatformManifest
23
+ from .storage import open_storage
24
+ from .drift_diagnostics import evidence_for_checks, guidance, persist as persist_drift_evidence
25
+ from .providers import LocalProcessProvider
26
+
27
+
28
+ DEFAULT_MINIMUM_FREE_BYTES = 1_073_741_824
29
+ MINIMUM_FREE_BYTES_ENVIRONMENT = "ENGINEERING_PLATFORM_PREFLIGHT_MIN_FREE_BYTES"
30
+ TELEMETRY_ENABLED_ENVIRONMENT = "ENGINEERING_PLATFORM_TELEMETRY_PERSISTENCE"
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class HostPreflightCheck:
35
+ identifier: str
36
+ outcome: str
37
+ reason: str
38
+ recovery: str
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class HostPreflightResult:
43
+ outcome: str
44
+ execution_host: str
45
+ version: str
46
+ bootstrap_contract: str
47
+ runtime_path: str | None
48
+ runtime_version: str | None
49
+ timestamp: str
50
+ duration_ms: int
51
+ checks: tuple[HostPreflightCheck, ...]
52
+ drift_evidence: tuple[dict[str, str], ...] = ()
53
+ resume_guidance: dict[str, object] | None = None
54
+
55
+ def payload(self, run_id: str | None = None) -> dict[str, object]:
56
+ result = asdict(self)
57
+ result["checks"] = [asdict(check) for check in self.checks]
58
+ result["run_id"] = run_id
59
+ return result
60
+
61
+
62
+ def _check(identifier: str, passed: bool, reason: str, recovery: str) -> HostPreflightCheck:
63
+ return HostPreflightCheck(identifier, "PASS" if passed else "FAIL", reason, recovery)
64
+
65
+
66
+ _RUNTIME_VERSION = re.compile(r"\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?")
67
+
68
+
69
+ def _runtime_version(output: str) -> str | None:
70
+ """Keep only the compact version token reported by the managed runtime."""
71
+ match = _RUNTIME_VERSION.search(output.strip())
72
+ return match.group(0) if match else None
73
+
74
+
75
+ def _minimum_free_bytes() -> int:
76
+ value = os.environ.get(MINIMUM_FREE_BYTES_ENVIRONMENT, str(DEFAULT_MINIMUM_FREE_BYTES))
77
+ try:
78
+ parsed = int(value)
79
+ except ValueError:
80
+ return -1
81
+ return parsed if parsed >= 0 else -1
82
+
83
+
84
+ def _telemetry_enabled() -> bool:
85
+ return os.environ.get(TELEMETRY_ENABLED_ENVIRONMENT, "true").strip().casefold() not in {"0", "false", "no"}
86
+
87
+
88
+ def _writable(path: Path) -> bool:
89
+ if not path.is_dir():
90
+ return False
91
+ try:
92
+ descriptor, temporary = tempfile.mkstemp(prefix=".preflight-", dir=path)
93
+ os.close(descriptor)
94
+ Path(temporary).unlink(missing_ok=True)
95
+ return True
96
+ except OSError:
97
+ return False
98
+
99
+
100
+ def _persist(root: Path, result: HostPreflightResult, run_id: str | None) -> None:
101
+ directory = root / ".engineering" / "status"
102
+ if not directory.is_dir() or not _writable(directory):
103
+ return
104
+ payload = json.dumps(result.payload(run_id), separators=(",", ":"), sort_keys=True) + "\n"
105
+ try:
106
+ descriptor, temporary = tempfile.mkstemp(prefix=".host-preflight-", dir=directory)
107
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
108
+ handle.write(payload)
109
+ handle.flush()
110
+ os.fsync(handle.fileno())
111
+ os.replace(temporary, directory / "host_preflight.json")
112
+ except OSError:
113
+ try:
114
+ Path(temporary).unlink(missing_ok=True)
115
+ except UnboundLocalError:
116
+ pass
117
+
118
+
119
+ def execute(root: Path, *, run_id: str | None = None) -> HostPreflightResult:
120
+ """Run Level 1 checks and persist bounded evidence without claiming work."""
121
+ started = monotonic()
122
+ timestamp = datetime.now(timezone.utc).isoformat()
123
+ checks: list[HostPreflightCheck] = []
124
+ configuration = None
125
+ try:
126
+ configuration = PlatformConfiguration.load(root)
127
+ checks.append(_check("configuration", True, "Required host configuration is readable.", "No action required."))
128
+ except PlatformConfigurationError:
129
+ checks.append(_check("configuration", False, "Required host configuration is unavailable.", "Restore a valid Engineering Platform configuration."))
130
+
131
+ manifest: EngineeringPlatformManifest | None = None
132
+ try:
133
+ manifest = EngineeringPlatformManifest.load(Path(__file__).with_name("ENGINEERING_PLATFORM_VERSION.json"))
134
+ checks.append(_check("host_identity", True, "Execution Host identity, version and bootstrap contract are available.", "No action required."))
135
+ except Exception:
136
+ checks.append(_check("host_identity", False, "Execution Host identity or bootstrap contract is unavailable.", "Restore the Engineering Platform version manifest."))
137
+
138
+ directories = (
139
+ ("status", configuration.resolver(root).resolve_status_store() if configuration else None),
140
+ ("reports", configuration.resolver(root).resolve_report_store() if configuration else None),
141
+ ("logs", configuration.resolver(root).resolve_log_store() if configuration else None),
142
+ ("inbox-processing", configuration.resolver(root).resolve_workspace_store() / "inbox-processing" if configuration else None),
143
+ )
144
+ for name, path in directories:
145
+ path = path if path is not None else root / ".engineering" / name
146
+ checks.append(_check(f"directory_{name}", path.is_dir(), f"Runtime directory {name} is available." if path.is_dir() else f"Runtime directory {name} is missing.", f"Create and secure .engineering/{name} before accepting work."))
147
+ if path.is_dir():
148
+ writable = _writable(path)
149
+ checks.append(_check(f"writable_{name}", writable, f"Runtime directory {name} is writable." if writable else f"Runtime directory {name} is not writable.", f"Restore write access to .engineering/{name}."))
150
+
151
+ threshold = _minimum_free_bytes()
152
+ if threshold < 0:
153
+ checks.append(_check("disk_space", False, "Configured free-disk threshold is invalid.", f"Set {MINIMUM_FREE_BYTES_ENVIRONMENT} to a non-negative byte value."))
154
+ else:
155
+ free = shutil.disk_usage(root).free
156
+ checks.append(_check("disk_space", free >= threshold, "Sufficient free disk space is available." if free >= threshold else "Free disk space is below the configured host threshold.", "Free disk space or lower the configured host preflight threshold."))
157
+
158
+ runtime_path: str | None = None
159
+ runtime_version: str | None = None
160
+ try:
161
+ executable = str(configuration.resolver(root).resolve_runtime()) if configuration is not None else None
162
+ runtime_path = executable
163
+ except PlatformConfigurationError:
164
+ executable = None
165
+ checks.append(_check("runtime_executable", bool(executable), "Configured runtime executable is available." if executable else "Configured runtime executable is unavailable.", "Install or expose the Codex CLI on the Execution Host PATH."))
166
+ if executable:
167
+ try:
168
+ invoked = LocalProcessProvider().execute(root, (executable, "--version"))
169
+ available = invoked.returncode == 0
170
+ if available:
171
+ runtime_version = _runtime_version(invoked.stdout)
172
+ except OSError:
173
+ available = False
174
+ checks.append(_check("runtime_invocation", available, "Configured runtime executable is invokable." if available else "Configured runtime executable cannot be invoked.", "Repair the Codex CLI installation before accepting work."))
175
+
176
+ if _telemetry_enabled():
177
+ try:
178
+ connection = open_storage(root)
179
+ try:
180
+ connection.execute("BEGIN IMMEDIATE")
181
+ connection.rollback()
182
+ finally:
183
+ connection.close()
184
+ checks.append(_check("telemetry_storage", True, "Telemetry SQLite storage is accessible and writable.", "No action required."))
185
+ except (OSError, sqlite3.DatabaseError, RuntimeError):
186
+ checks.append(_check("telemetry_storage", False, "Telemetry SQLite storage is unavailable.", "Restore local SQLite evidence storage before accepting work."))
187
+
188
+ try:
189
+ # Preflight has no legacy watcher logger. File Inbox is the canonical
190
+ # transport identity when the Server publishes a CENTRAL log binding.
191
+ component_logger(root, "file_inbox_ingress")
192
+ checks.append(_check("structured_logging", True, "Structured logging initializes successfully.", "No action required."))
193
+ except Exception:
194
+ checks.append(_check("structured_logging", False, "Structured logging cannot initialize.", "Restore the local logging destination before accepting work."))
195
+
196
+ outcome = (
197
+ "FAIL"
198
+ if any(check.outcome == "FAIL" for check in checks)
199
+ else "WARNING"
200
+ if any(check.outcome == "WARNING" for check in checks)
201
+ else "PASS"
202
+ )
203
+ drift_evidence = persist_drift_evidence(root, evidence_for_checks(
204
+ checks, stage="Execution Host Preflight", repository=str(root.resolve())
205
+ ))
206
+ result = HostPreflightResult(
207
+ outcome,
208
+ configuration.platform.name if configuration else "Engineering Platform",
209
+ manifest.platform_version if manifest else "unavailable",
210
+ manifest.bootstrap_contract if manifest else "unavailable",
211
+ runtime_path,
212
+ runtime_version,
213
+ timestamp,
214
+ round((monotonic() - started) * 1000),
215
+ tuple(checks),
216
+ drift_evidence,
217
+ guidance(drift_evidence),
218
+ )
219
+ _persist(root, result, run_id)
220
+ return result
221
+
222
+
223
+ def latest(root: Path) -> dict[str, object]:
224
+ """Return only safe, compact preflight evidence for the dashboard/report."""
225
+ try:
226
+ payload = json.loads((root / ".engineering" / "status" / "host_preflight.json").read_text(encoding="utf-8"))
227
+ except (OSError, json.JSONDecodeError):
228
+ return {}
229
+ if not isinstance(payload, dict):
230
+ return {}
231
+ return {key: payload[key] for key in ("outcome", "timestamp", "duration_ms", "execution_host", "version", "bootstrap_contract", "runtime_path", "runtime_version", "checks", "drift_evidence", "resume_guidance", "run_id") if key in payload}
@@ -0,0 +1,122 @@
1
+ """Crash-safe relocation of the one canonical platform-data directory.
2
+
3
+ The data root is one unit of persistence. Splitting the database and File
4
+ Inbox across arbitrary folders made a restore impossible to reason about, so
5
+ the legacy per-resource relocation requests are deliberately retired.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ from pathlib import Path
12
+ from uuid import uuid4
13
+
14
+
15
+ class RelocationError(ValueError):
16
+ """A requested local relocation cannot be safely completed."""
17
+
18
+
19
+ _PENDING = "runtime/pending-platform-data-relocation.json"
20
+
21
+
22
+ def _directory(value: object) -> Path:
23
+ if not isinstance(value, str) or not value.strip():
24
+ raise RelocationError("LOCATION_REQUIRED")
25
+ path = Path(value).expanduser()
26
+ if not path.is_absolute() or not path.is_dir() or not os.access(path, os.W_OK | os.X_OK):
27
+ raise RelocationError("LOCATION_NOT_WRITABLE")
28
+ return path.resolve()
29
+
30
+
31
+ def _write_json_atomically(path: Path, value: dict[str, str]) -> None:
32
+ path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
33
+ candidate = path.with_name(f".{path.name}.{uuid4().hex}")
34
+ try:
35
+ candidate.write_text(json.dumps(value, sort_keys=True), encoding="utf-8")
36
+ candidate.chmod(0o600)
37
+ os.replace(candidate, path)
38
+ finally:
39
+ candidate.unlink(missing_ok=True)
40
+
41
+
42
+ def _pending_path(data_root: Path) -> Path:
43
+ return data_root.resolve() / _PENDING
44
+
45
+
46
+ def _destination(root: Path, directory: object) -> Path:
47
+ parent = _directory(directory)
48
+ target = parent / root.name
49
+ if target == root or root in target.parents or target in root.parents:
50
+ raise RelocationError("PLATFORM_DATA_DESTINATION_INVALID")
51
+ return target
52
+
53
+
54
+ def request(data_root: Path, kind: str, directory: object) -> dict[str, str]:
55
+ """Persist one whole-platform move for the next clean Server startup."""
56
+ if kind != "PLATFORM_DATA":
57
+ raise RelocationError("RELOCATION_KIND_RETIRED")
58
+ root = data_root.resolve()
59
+ if not (root / "engineering.db").is_file():
60
+ raise RelocationError("PLATFORM_DATA_UNAVAILABLE")
61
+ destination = _destination(root, directory)
62
+ if destination.exists() and destination.resolve() != root:
63
+ raise RelocationError("PLATFORM_DATA_DESTINATION_EXISTS")
64
+ pending = _pending_path(root)
65
+ if pending.exists():
66
+ raise RelocationError("RELOCATION_ALREADY_PENDING")
67
+ _write_json_atomically(pending, {"kind": kind, "directory": str(_directory(directory))})
68
+ return {"previous": str(root), "value": str(destination)}
69
+
70
+
71
+ def relocate_platform_data(data_root: Path, directory: object) -> dict[str, str]:
72
+ """Move the entire data root, retaining its stable launchd entry path.
73
+
74
+ launchd continues to start the stable original path. That path becomes a
75
+ symlink only after the complete directory rename succeeds, so the DB,
76
+ inbox, artifacts and configuration never end up on different volumes.
77
+ """
78
+ original = Path(data_root).expanduser()
79
+ root = original.resolve()
80
+ parent = _directory(directory)
81
+ # A repeated restart may replay the same request through the stable
82
+ # launchd symlink. Recognize that exact completed move before applying
83
+ # the nested-destination guard below.
84
+ destination = parent / original.name
85
+ if original.is_symlink() and destination.exists() and original.resolve() == destination.resolve():
86
+ return {"previous": str(root), "value": str(destination.resolve())}
87
+ if destination == root or root in destination.parents or destination in root.parents:
88
+ raise RelocationError("PLATFORM_DATA_DESTINATION_INVALID")
89
+ if not root.is_dir() or not (root / "engineering.db").is_file():
90
+ raise RelocationError("PLATFORM_DATA_UNAVAILABLE")
91
+ if destination.exists():
92
+ raise RelocationError("PLATFORM_DATA_DESTINATION_EXISTS")
93
+ destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
94
+ try:
95
+ os.replace(root, destination)
96
+ # A later relocation starts through the stable, already-symlinked
97
+ # launch path. Its old link is now dangling and must be replaced.
98
+ if original.is_symlink():
99
+ original.unlink()
100
+ original.symlink_to(destination, target_is_directory=True)
101
+ except Exception:
102
+ if destination.exists() and not original.exists():
103
+ os.replace(destination, original)
104
+ raise
105
+ return {"previous": str(root), "value": str(destination.resolve())}
106
+
107
+
108
+ def apply_pending(data_root: Path) -> dict[str, str] | None:
109
+ """Perform a durable whole-directory request before writers are started."""
110
+ pending = _pending_path(data_root)
111
+ if not pending.exists():
112
+ return None
113
+ try:
114
+ request_data = json.loads(pending.read_text(encoding="utf-8"))
115
+ kind, directory = request_data["kind"], request_data["directory"]
116
+ if kind != "PLATFORM_DATA":
117
+ raise RelocationError("RELOCATION_KIND_RETIRED")
118
+ result = relocate_platform_data(data_root, directory)
119
+ except (KeyError, TypeError, json.JSONDecodeError) as error:
120
+ raise RelocationError("RELOCATION_REQUEST_INVALID") from error
121
+ _pending_path(data_root).unlink(missing_ok=True)
122
+ return {**result, "kind": "PLATFORM_DATA"}
@@ -0,0 +1,89 @@
1
+ """Ephemeral factual-deduplication rules for one primary provider invocation.
2
+
3
+ The ledger deliberately contains fact identifiers and freshness only. It never
4
+ accepts source text, paths, command arguments, tool output, conclusions, or
5
+ reviewer advice, and is rendered only into the primary-provider prompt.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+
13
+ RUN_STABLE = "RUN-STABLE"
14
+ MUTABLE = "MUTABLE"
15
+ BOUNDARY_SENSITIVE = "BOUNDARY-SENSITIVE"
16
+
17
+ _FACT_FRESHNESS = {
18
+ "repository_identity": RUN_STABLE,
19
+ "repository_status": MUTABLE,
20
+ "git_ancestry": MUTABLE,
21
+ "pull_request_state": BOUNDARY_SENSITIVE,
22
+ "source_inspection": MUTABLE,
23
+ "test_surface": MUTABLE,
24
+ "validation_surface": BOUNDARY_SENSITIVE,
25
+ "finalization_state": BOUNDARY_SENSITIVE,
26
+ "reconciliation_state": BOUNDARY_SENSITIVE,
27
+ }
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class InvocationInvestigationLedger:
32
+ """A small, non-persistent checklist of facts usable in one invocation."""
33
+
34
+ completed: frozenset[str] = frozenset()
35
+
36
+ def record(self, *facts: str) -> "InvocationInvestigationLedger":
37
+ """Record only known fact identifiers after a real narrow check."""
38
+ unknown = set(facts).difference(_FACT_FRESHNESS)
39
+ if unknown:
40
+ raise ValueError("Unknown investigation fact identifier.")
41
+ return InvocationInvestigationLedger(self.completed.union(facts))
42
+
43
+ def reusable(self, fact: str) -> bool:
44
+ """Return whether the fact is currently established in this invocation."""
45
+ if fact not in _FACT_FRESHNESS:
46
+ raise ValueError("Unknown investigation fact identifier.")
47
+ return fact in self.completed
48
+
49
+ def invalidate(self, boundary: str) -> "InvocationInvestigationLedger":
50
+ """Fail closed at mutation and lifecycle boundaries.
51
+
52
+ RUN-STABLE identity remains valid. Every other fact must be checked
53
+ again after any boundary that could have changed repository or remote
54
+ state. This is intentionally conservative: a caller may always do a
55
+ real check sooner when freshness is uncertain.
56
+ """
57
+ if boundary not in {
58
+ "repository_mutation",
59
+ "validation",
60
+ "pull_request_mutation",
61
+ "merge",
62
+ "finalization",
63
+ "repository_cleanup",
64
+ "freshness_uncertain",
65
+ }:
66
+ raise ValueError("Unknown freshness boundary.")
67
+ return InvocationInvestigationLedger(
68
+ frozenset(
69
+ fact for fact in self.completed if _FACT_FRESHNESS[fact] == RUN_STABLE
70
+ )
71
+ )
72
+
73
+ def to_prompt_dict(self) -> dict[str, object]:
74
+ """Return an identifier-only primary prompt projection."""
75
+ return {
76
+ "scope": "one_primary_provider_invocation",
77
+ "persistence": "none",
78
+ "completed_fact_ids": sorted(self.completed),
79
+ "fact_freshness": dict(_FACT_FRESHNESS),
80
+ "invalidating_boundaries": [
81
+ "repository_mutation",
82
+ "validation",
83
+ "pull_request_mutation",
84
+ "merge",
85
+ "finalization",
86
+ "repository_cleanup",
87
+ "freshness_uncertain",
88
+ ],
89
+ }