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,276 @@
1
+ """One-shot, evidence-gated repair for a human-authored pull request.
2
+
3
+ This is deliberately separate from the managed execution lifecycle. It never
4
+ claims an Inbox item, resumes a transaction, merges a pull request, or creates
5
+ a pull request. It may only add one host-owned commit to the exact current
6
+ head of an eligible same-repository pull request.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ from datetime import datetime, timezone
13
+ import json
14
+ import os
15
+ from pathlib import Path
16
+ import re
17
+ import tempfile
18
+
19
+ from .central_database import capacity_reserve_from_environment
20
+ from .worktree_tooling import WorktreeToolingError, prepare as prepare_worktree_tooling
21
+ from .codex_capacity import read_remaining_percent
22
+ from .provider_readiness import failures as provider_readiness_failures
23
+ from .providers import CodexCliProvider, GitHubProvider, GitProvider
24
+
25
+
26
+ FAILED_CONCLUSIONS = frozenset({"ACTION_REQUIRED", "CANCELLED", "FAILURE", "STARTUP_FAILURE", "TIMED_OUT"})
27
+ SUCCESSFUL_CONCLUSIONS = frozenset({"NEUTRAL", "SKIPPED", "SUCCESS"})
28
+ STATE_DIRECTORY = Path(".engineering") / "status" / "pr-check-repairs"
29
+
30
+
31
+ class PullRequestCheckRepairError(RuntimeError):
32
+ """The request is unsafe, stale, or cannot be admitted."""
33
+
34
+
35
+ def _repository(root: Path) -> str:
36
+ remote = GitProvider().execute(root, "git", "remote", "get-url", "origin")
37
+ match = re.search(r"github\.com[:/]([^/\s]+)/([^/\s]+?)(?:\.git)?$", remote.stdout.strip()) if remote.returncode == 0 else None
38
+ if not match:
39
+ raise PullRequestCheckRepairError("pr_check_repair_unavailable")
40
+ return f"{match.group(1)}/{match.group(2)}"
41
+
42
+
43
+ def _state_path(root: Path, number: int, sha: str) -> Path:
44
+ return root / STATE_DIRECTORY / f"{number}-{sha}.json"
45
+
46
+
47
+ def _read_state(root: Path, number: int, sha: str) -> dict[str, object] | None:
48
+ try:
49
+ value = json.loads(_state_path(root, number, sha).read_text(encoding="utf-8"))
50
+ except (OSError, json.JSONDecodeError):
51
+ return None
52
+ return value if isinstance(value, dict) else None
53
+
54
+
55
+ def attempted(root: Path, number: int, sha: object) -> bool:
56
+ """Whether this exact remote head already consumed its one repair action."""
57
+ return isinstance(sha, str) and bool(re.fullmatch(r"[0-9a-f]{40}", sha)) and _read_state(root, number, sha) is not None
58
+
59
+
60
+ def failed_check_names(checks: object) -> list[str]:
61
+ """Return bounded terminal failures from GitHub's check-rollup shape."""
62
+ if not isinstance(checks, list):
63
+ return []
64
+ return [
65
+ str(check.get("name") or check.get("context") or "required check").strip()[:160]
66
+ for check in checks if isinstance(check, dict)
67
+ and str(check.get("conclusion") or check.get("state") or "").upper() in FAILED_CONCLUSIONS
68
+ ]
69
+
70
+
71
+ def _write_state(root: Path, number: int, sha: str, payload: dict[str, object]) -> None:
72
+ path = _state_path(root, number, sha)
73
+ path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
74
+ descriptor, temporary = tempfile.mkstemp(prefix=".pr-check-repair-", suffix=".json", dir=path.parent)
75
+ try:
76
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
77
+ json.dump(payload, handle, sort_keys=True)
78
+ handle.write("\n")
79
+ handle.flush()
80
+ os.fsync(handle.fileno())
81
+ os.replace(temporary, path)
82
+ finally:
83
+ Path(temporary).unlink(missing_ok=True)
84
+
85
+
86
+ def check_summary(checks: object) -> tuple[list[str], bool]:
87
+ """Return failed names and whether the GitHub check projection is stable."""
88
+ if not isinstance(checks, list) or not checks:
89
+ return [], False
90
+ failed = failed_check_names(checks)
91
+ terminal = True
92
+ for check in checks:
93
+ if not isinstance(check, dict):
94
+ return [], False
95
+ conclusion = str(check.get("conclusion") or check.get("state") or "").upper()
96
+ status = str(check.get("status") or "").upper()
97
+ if conclusion not in FAILED_CONCLUSIONS | SUCCESSFUL_CONCLUSIONS or (status and status != "COMPLETED"):
98
+ terminal = False
99
+ return failed, terminal
100
+
101
+
102
+ def repair_state(root: Path, number: int, sha: object) -> str | None:
103
+ """Return the durable repair state for this head, including its repair commit."""
104
+ if not isinstance(sha, str) or not re.fullmatch(r"[0-9a-f]{40}", sha):
105
+ return None
106
+ direct = _read_state(root, number, sha)
107
+ if direct is not None:
108
+ status = direct.get("status")
109
+ return str(status) if isinstance(status, str) else None
110
+ try:
111
+ candidates = (root / STATE_DIRECTORY).glob(f"{number}-*.json")
112
+ except OSError:
113
+ return None
114
+ for candidate in candidates:
115
+ try:
116
+ value = json.loads(candidate.read_text(encoding="utf-8"))
117
+ except (OSError, json.JSONDecodeError):
118
+ continue
119
+ if isinstance(value, dict) and value.get("commit_sha") == sha:
120
+ status = value.get("status")
121
+ return str(status) if isinstance(status, str) else None
122
+ return None
123
+
124
+
125
+ def current_evidence(root: Path, number: int) -> dict[str, object]:
126
+ """Read the exact mutable PR evidence used for admission and projection."""
127
+ if isinstance(number, bool) or number < 1:
128
+ raise PullRequestCheckRepairError("pr_check_repair_invalid_request")
129
+ repository = _repository(root)
130
+ try:
131
+ payload = GitHubProvider().github(
132
+ "pr", "view", str(number), "--repo", repository,
133
+ "--json", "number,state,isDraft,headRefOid,headRefName,baseRefName,headRepository,statusCheckRollup",
134
+ )
135
+ pull_request = json.loads(payload)
136
+ except (RuntimeError, OSError, json.JSONDecodeError) as error:
137
+ raise PullRequestCheckRepairError("pr_check_repair_unavailable") from error
138
+ if not isinstance(pull_request, dict) or pull_request.get("number") != number:
139
+ raise PullRequestCheckRepairError("pr_check_repair_unavailable")
140
+ sha, branch = pull_request.get("headRefOid"), pull_request.get("headRefName")
141
+ head_repository = pull_request.get("headRepository")
142
+ head_repository_name = head_repository.get("nameWithOwner") if isinstance(head_repository, dict) else None
143
+ failed_checks, terminal = check_summary(pull_request.get("statusCheckRollup"))
144
+ eligible = (
145
+ str(pull_request.get("state") or "").upper() == "OPEN"
146
+ and pull_request.get("isDraft") is not True
147
+ and isinstance(sha, str) and bool(re.fullmatch(r"[0-9a-f]{40}", sha))
148
+ and isinstance(branch, str) and bool(branch)
149
+ and head_repository_name == repository
150
+ and terminal and bool(failed_checks)
151
+ )
152
+ state = _read_state(root, number, sha) if isinstance(sha, str) else None
153
+ attempted = state is not None
154
+ return {
155
+ "number": number, "repository": repository, "head_sha": sha, "branch": branch,
156
+ "failed_checks": failed_checks, "checks_terminal": terminal,
157
+ "eligible": eligible and not attempted,
158
+ "repair_state": str(state.get("status")) if state else None,
159
+ }
160
+
161
+
162
+ def admit(root: Path, number: int) -> dict[str, object]:
163
+ """Atomically reserve exactly one repair attempt for the current PR SHA."""
164
+ evidence = current_evidence(root, number)
165
+ if not evidence["eligible"]:
166
+ raise PullRequestCheckRepairError("pr_check_repair_not_eligible")
167
+ missing = provider_readiness_failures(root, require_github=True)
168
+ if missing:
169
+ raise PullRequestCheckRepairError("pr_check_repair_provider_not_ready")
170
+ remaining = read_remaining_percent()
171
+ reserve = capacity_reserve_from_environment()
172
+ if remaining is None or remaining <= reserve:
173
+ raise PullRequestCheckRepairError("pr_check_repair_capacity_unavailable")
174
+ sha = str(evidence["head_sha"])
175
+ payload = {
176
+ "status": "QUEUED", "number": number, "head_sha": sha,
177
+ "branch": evidence["branch"], "failed_checks": evidence["failed_checks"],
178
+ "created_at": datetime.now(timezone.utc).isoformat(),
179
+ }
180
+ _write_state(root, number, sha, payload)
181
+ return evidence
182
+
183
+
184
+ def mark_dispatch_failed(root: Path, number: int, sha: str) -> None:
185
+ state = _read_state(root, number, sha)
186
+ if state and state.get("status") == "QUEUED":
187
+ _write_state(root, number, sha, {**state, "status": "FAILED", "error": "pr_check_repair_dispatch_failed", "completed_at": datetime.now(timezone.utc).isoformat()})
188
+
189
+
190
+ def _command(root: Path, *arguments: str) -> str:
191
+ completed = GitProvider().execute(root, "git", *arguments)
192
+ if completed.returncode:
193
+ raise PullRequestCheckRepairError("pr_check_repair_failed")
194
+ return completed.stdout.strip()
195
+
196
+
197
+ def _prepare_worktree_tooling(worktree: Path) -> None:
198
+ """Install locked Playwright tooling before an EP-created worktree is used.
199
+
200
+ A linked worktree does not share ``node_modules`` with its source checkout.
201
+ When this repository declares the browser suite, ``npm ci`` is therefore a
202
+ required local preparation step, not a best-effort validation fallback.
203
+ """
204
+ try:
205
+ prepare_worktree_tooling(worktree)
206
+ except WorktreeToolingError:
207
+ raise PullRequestCheckRepairError("pr_check_repair_worktree_tooling_unavailable")
208
+
209
+
210
+ def run(root: Path, number: int, sha: str) -> None:
211
+ """Execute the already-admitted repair in an isolated, disposable worktree."""
212
+ state = _read_state(root, number, sha)
213
+ if not state or state.get("status") != "QUEUED":
214
+ raise PullRequestCheckRepairError("pr_check_repair_not_eligible")
215
+ evidence = current_evidence(root, number)
216
+ # The durable reservation intentionally makes ``eligible`` false. Fresh
217
+ # remote evidence must nevertheless still identify this exact failed head.
218
+ if (
219
+ evidence.get("head_sha") != sha
220
+ or evidence.get("branch") != state.get("branch")
221
+ or not evidence.get("checks_terminal")
222
+ or not evidence.get("failed_checks")
223
+ ):
224
+ raise PullRequestCheckRepairError("pr_check_repair_stale")
225
+ branch = str(state["branch"])
226
+ _write_state(root, number, sha, {**state, "status": "RUNNING", "started_at": datetime.now(timezone.utc).isoformat()})
227
+ worktree = Path(tempfile.mkdtemp(prefix=f"ep-pr-{number}-", dir=root / ".engineering"))
228
+ worktree.rmdir()
229
+ try:
230
+ _command(root, "fetch", "origin", branch)
231
+ _command(root, "worktree", "add", "--detach", str(worktree), sha)
232
+ _prepare_worktree_tooling(worktree)
233
+ prompt = (
234
+ f"Repair only the failed GitHub checks for pull request #{number}.\n"
235
+ f"Current head SHA: {sha}. Failed checks: {', '.join(str(item) for item in state['failed_checks'])}.\n"
236
+ "Work only in this isolated worktree. Inspect the failed-check evidence and make the smallest focused source or test correction. "
237
+ "Do not change the pull request scope. Do not create commits, push, open or merge a pull request, alter GitHub settings, or use destructive Git commands. "
238
+ "Run focused verification where practical. Finish with the working tree containing only the proposed repair."
239
+ )
240
+ result = CodexCliProvider().invoke(
241
+ worktree, ("codex", "exec", "--sandbox", "workspace-write", "-C", str(worktree), prompt),
242
+ )
243
+ if result.returncode:
244
+ raise PullRequestCheckRepairError("pr_check_repair_agent_failed")
245
+ if _command(worktree, "rev-parse", "HEAD") != sha:
246
+ raise PullRequestCheckRepairError("pr_check_repair_scope_conflict")
247
+ if not _command(worktree, "status", "--porcelain", "--untracked-files=all"):
248
+ raise PullRequestCheckRepairError("pr_check_repair_no_change")
249
+ _command(worktree, "diff", "--check")
250
+ _command(worktree, "add", "--all")
251
+ _command(worktree, "commit", "-m", f"fix(ci): repair failed checks for PR #{number}")
252
+ commit = _command(worktree, "rev-parse", "HEAD")
253
+ _command(worktree, "push", "--force-with-lease=refs/heads/" + branch + ":" + sha, "origin", "HEAD:refs/heads/" + branch)
254
+ _write_state(root, number, sha, {**state, "status": "SUBMITTED", "commit_sha": commit, "submitted_at": datetime.now(timezone.utc).isoformat()})
255
+ except PullRequestCheckRepairError as error:
256
+ _write_state(root, number, sha, {**state, "status": "FAILED", "error": str(error), "completed_at": datetime.now(timezone.utc).isoformat()})
257
+ finally:
258
+ try:
259
+ if worktree.exists() and not _command(worktree, "status", "--porcelain", "--untracked-files=all"):
260
+ _command(root, "worktree", "remove", "--", str(worktree))
261
+ except PullRequestCheckRepairError:
262
+ pass
263
+
264
+
265
+ def main() -> int:
266
+ parser = argparse.ArgumentParser()
267
+ parser.add_argument("--root", required=True, type=Path)
268
+ parser.add_argument("--pull-request", required=True, type=int)
269
+ parser.add_argument("--head-sha", required=True)
270
+ arguments = parser.parse_args()
271
+ run(arguments.root.resolve(), arguments.pull_request, arguments.head_sha)
272
+ return 0
273
+
274
+
275
+ if __name__ == "__main__":
276
+ raise SystemExit(main())
@@ -0,0 +1,278 @@
1
+ """Fail-closed recovery of missing historical Managed pull-request evidence.
2
+
3
+ This tool is intentionally operator-invoked and dry-run by default. It never
4
+ creates, edits, merges, or closes a pull request. It can only link a missing
5
+ checkpoint field after the live GitHub record exactly matches the checkpointed
6
+ branch and merge commit for that role.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ from dataclasses import dataclass, replace
12
+ from datetime import datetime, timezone
13
+ import json
14
+ import os
15
+ from pathlib import Path
16
+ import tempfile
17
+ from typing import Callable, Iterable
18
+
19
+ from .agent_state import StateError, TransactionState
20
+ from .execution_models import PullRequestEvidence
21
+ from .execution_repository import GhCliClient, GitHubClient
22
+ from .providers import GitProvider
23
+ from .storage import EngineeringStorageError, open_storage
24
+
25
+
26
+ ROLES = ("IMPLEMENTATION", "FINALIZATION")
27
+ ACTOR = "operator_pr_evidence_backfill"
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class BackfillDecision:
32
+ run_id: str
33
+ role: str
34
+ outcome: str
35
+ reason: str
36
+ pull_request: int | None = None
37
+ expected_branch: str | None = None
38
+ expected_merge_commit: str | None = None
39
+
40
+ def report(self) -> dict[str, object]:
41
+ return {
42
+ "run_id": self.run_id,
43
+ "role": self.role.lower(),
44
+ "outcome": self.outcome.lower(),
45
+ "reason": self.reason,
46
+ "pull_request": self.pull_request,
47
+ "expected_branch": self.expected_branch,
48
+ "expected_merge_commit": self.expected_merge_commit,
49
+ }
50
+
51
+
52
+ def _now() -> str:
53
+ return datetime.now(timezone.utc).isoformat()
54
+
55
+
56
+ def _role_evidence(state: TransactionState, role: str) -> tuple[int | None, str | None, str | None]:
57
+ if role == "IMPLEMENTATION":
58
+ return state.implementation_pull_request, state.implementation_branch, state.implementation_merge_commit
59
+ return state.finalization_pull_request, state.finalization_branch, state.finalization_merge_commit
60
+
61
+
62
+ def _candidate_decision(
63
+ state: TransactionState, role: str, github: GitHubClient, repository: str | None,
64
+ main_contains: Callable[[str], bool | None],
65
+ ) -> BackfillDecision:
66
+ recorded_pr, branch, merge_commit = _role_evidence(state, role)
67
+ base = dict(run_id=state.run_id, role=role, expected_branch=branch, expected_merge_commit=merge_commit)
68
+ if state.execution_mode != "MANAGED":
69
+ return BackfillDecision(outcome="SKIPPED", reason="not_managed_execution", **base)
70
+ if repository is None or state.repository != repository:
71
+ return BackfillDecision(outcome="SKIPPED", reason="repository_evidence_unavailable_or_mismatched", **base)
72
+ if not state.terminal:
73
+ return BackfillDecision(outcome="SKIPPED", reason="run_not_terminal", **base)
74
+ if recorded_pr is not None:
75
+ return BackfillDecision(outcome="SKIPPED", reason="pull_request_already_recorded", pull_request=recorded_pr, **base)
76
+ if not branch or not merge_commit:
77
+ return BackfillDecision(outcome="SKIPPED", reason="checkpoint_evidence_incomplete", **base)
78
+ try:
79
+ evidence = github.pull_request_for_head_branch(branch)
80
+ except Exception:
81
+ return BackfillDecision(outcome="SKIPPED", reason="github_evidence_unavailable", **base)
82
+ if evidence is None:
83
+ return BackfillDecision(outcome="SKIPPED", reason="pull_request_not_found_for_checkpoint_branch", **base)
84
+ if not _exact_match(evidence, branch, merge_commit):
85
+ return BackfillDecision(outcome="SKIPPED", reason="github_evidence_does_not_exactly_match_checkpoint", **base)
86
+ contained = main_contains(merge_commit)
87
+ if contained is None:
88
+ return BackfillDecision(outcome="SKIPPED", reason="repository_merge_evidence_unavailable", **base)
89
+ if not contained:
90
+ return BackfillDecision(outcome="SKIPPED", reason="merge_commit_not_in_origin_main", **base)
91
+ return BackfillDecision(outcome="APPLIED", reason="exact_github_branch_and_merge_evidence", pull_request=evidence.number, **base)
92
+
93
+
94
+ def _exact_match(evidence: PullRequestEvidence, branch: str, merge_commit: str) -> bool:
95
+ return (
96
+ evidence.state == "MERGED"
97
+ and evidence.head_branch == branch
98
+ and evidence.base_branch == "main"
99
+ and evidence.merge_commit == merge_commit
100
+ )
101
+
102
+
103
+ def _load_states(root: Path, run_id: str | None) -> Iterable[TransactionState]:
104
+ connection = open_storage(root, create=False)
105
+ try:
106
+ if run_id:
107
+ rows = connection.execute("SELECT payload FROM engineering_transactions WHERE run_id=?", (run_id,)).fetchall()
108
+ else:
109
+ rows = connection.execute("SELECT payload FROM engineering_transactions ORDER BY run_id").fetchall()
110
+ finally:
111
+ connection.close()
112
+ for (payload,) in rows:
113
+ try:
114
+ yield TransactionState.from_dict(json.loads(payload))
115
+ except (StateError, TypeError, json.JSONDecodeError):
116
+ # A malformed checkpoint is never eligible for recovery. There is
117
+ # no safe run id to write against, so it remains database evidence.
118
+ continue
119
+
120
+
121
+ def _current_repository(root: Path) -> str | None:
122
+ result = GitProvider().execute(root, "git", "remote", "get-url", "origin")
123
+ if result.returncode:
124
+ return None
125
+ value = result.stdout.strip().removesuffix(".git")
126
+ if value.startswith("git@github.com:"):
127
+ value = value.removeprefix("git@github.com:")
128
+ elif value.startswith("https://github.com/"):
129
+ value = value.removeprefix("https://github.com/")
130
+ return value if value.count("/") == 1 else None
131
+
132
+
133
+ def _origin_main_contains(root: Path, commit: str) -> bool | None:
134
+ """Refresh only the remote-tracking ref; never change the checkout or branch."""
135
+ provider = GitProvider()
136
+ if provider.execute(root, "git", "fetch", "origin", "main").returncode:
137
+ return None
138
+ result = provider.execute(root, "git", "merge-base", "--is-ancestor", commit, "origin/main")
139
+ return result.returncode == 0
140
+
141
+
142
+ def _updated_state(state: TransactionState, decision: BackfillDecision) -> TransactionState:
143
+ if decision.role == "IMPLEMENTATION":
144
+ return replace(state, implementation_pull_request=decision.pull_request)
145
+ return replace(state, finalization_pull_request=decision.pull_request)
146
+
147
+
148
+ def _record_skip(root: Path, decision: BackfillDecision, *, observed_at: str) -> None:
149
+ connection = open_storage(root)
150
+ try:
151
+ connection.execute(
152
+ "INSERT INTO execution_pr_evidence_backfills(run_id,pr_role,outcome,reason,pr_number,expected_branch,expected_merge_commit,observed_at,actor) VALUES(?,?,?,?,?,?,?,?,?)",
153
+ (decision.run_id, decision.role, decision.outcome, decision.reason, decision.pull_request,
154
+ decision.expected_branch, decision.expected_merge_commit, observed_at, ACTOR),
155
+ )
156
+ finally:
157
+ connection.close()
158
+
159
+
160
+ def _write_projection(directory: Path, state: TransactionState) -> None:
161
+ """Refresh the compatibility JSON only after the canonical commit succeeds."""
162
+ directory.mkdir(mode=0o700, parents=True, exist_ok=True)
163
+ target = directory / f"{state.run_id}.json"
164
+ descriptor, temporary = tempfile.mkstemp(prefix=f".{state.run_id}.", suffix=".tmp", dir=directory)
165
+ try:
166
+ os.fchmod(descriptor, 0o600)
167
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
168
+ json.dump(state.to_dict(), handle, indent=2, sort_keys=True)
169
+ handle.write("\n")
170
+ handle.flush()
171
+ os.fsync(handle.fileno())
172
+ os.replace(temporary, target)
173
+ os.chmod(target, 0o600)
174
+ except OSError:
175
+ try:
176
+ os.unlink(temporary)
177
+ except FileNotFoundError:
178
+ pass
179
+ raise
180
+
181
+
182
+ def _apply(root: Path, state: TransactionState, decision: BackfillDecision, *, observed_at: str) -> BackfillDecision:
183
+ """Atomically persist the exact verified link and its audit record."""
184
+ connection = open_storage(root)
185
+ updated: TransactionState | None = None
186
+ try:
187
+ connection.execute("BEGIN IMMEDIATE")
188
+ row = connection.execute("SELECT payload FROM engineering_transactions WHERE run_id=?", (state.run_id,)).fetchone()
189
+ if not row:
190
+ decision = replace(decision, outcome="SKIPPED", reason="checkpoint_disappeared", pull_request=None)
191
+ else:
192
+ current = TransactionState.from_dict(json.loads(row[0]))
193
+ current_pr, current_branch, current_merge = _role_evidence(current, decision.role)
194
+ if (
195
+ current.execution_mode != "MANAGED" or not current.terminal
196
+ or current_pr is not None
197
+ or current_branch != decision.expected_branch
198
+ or current_merge != decision.expected_merge_commit
199
+ ):
200
+ decision = replace(decision, outcome="SKIPPED", reason="checkpoint_changed_since_verification", pull_request=None)
201
+ else:
202
+ updated = _updated_state(current, decision)
203
+ encoded = json.dumps(updated.to_dict(), separators=(",", ":"), sort_keys=True)
204
+ connection.execute(
205
+ "UPDATE engineering_transactions SET payload=?,phase=?,updated_at=CURRENT_TIMESTAMP WHERE run_id=?",
206
+ (encoded, updated.phase, updated.run_id),
207
+ )
208
+ connection.execute(
209
+ "INSERT OR IGNORE INTO execution_lifecycle_events(run_id,phase,checkpoint,recorded_at) VALUES(?,?,?,CURRENT_TIMESTAMP)",
210
+ (updated.run_id, updated.phase, encoded),
211
+ )
212
+ connection.execute(
213
+ "INSERT INTO execution_pr_evidence_backfills(run_id,pr_role,outcome,reason,pr_number,expected_branch,expected_merge_commit,observed_at,actor) VALUES(?,?,?,?,?,?,?,?,?)",
214
+ (decision.run_id, decision.role, decision.outcome, decision.reason, decision.pull_request,
215
+ decision.expected_branch, decision.expected_merge_commit, observed_at, ACTOR),
216
+ )
217
+ connection.execute("COMMIT")
218
+ except (EngineeringStorageError, StateError, OSError, ValueError, json.JSONDecodeError):
219
+ connection.execute("ROLLBACK")
220
+ raise
221
+ finally:
222
+ connection.close()
223
+ if updated is not None:
224
+ try:
225
+ _write_projection(root / ".engineering" / "engineering-runs", updated)
226
+ except OSError:
227
+ return replace(decision, reason="exact_evidence_applied_projection_refresh_failed")
228
+ return decision
229
+
230
+
231
+ def backfill(root: Path, *, apply: bool = False, run_id: str | None = None,
232
+ github: GitHubClient | None = None, repository: str | None = None,
233
+ main_contains: Callable[[str], bool | None] | None = None) -> dict[str, object]:
234
+ """Inspect or atomically backfill exact historical Managed PR evidence."""
235
+ client = github or GhCliClient()
236
+ repository = repository if repository is not None else _current_repository(root)
237
+ checked_merges: dict[str, bool | None] = {}
238
+
239
+ def current_main_contains(commit: str) -> bool | None:
240
+ if commit not in checked_merges:
241
+ check = main_contains or (lambda value: _origin_main_contains(root, value))
242
+ checked_merges[commit] = check(commit)
243
+ return checked_merges[commit]
244
+
245
+ decisions: list[BackfillDecision] = []
246
+ for state in _load_states(root, run_id):
247
+ for role in ROLES:
248
+ decision = _candidate_decision(state, role, client, repository, current_main_contains)
249
+ if apply:
250
+ if decision.outcome == "APPLIED":
251
+ decision = _apply(root, state, decision, observed_at=_now())
252
+ else:
253
+ _record_skip(root, decision, observed_at=_now())
254
+ decisions.append(decision)
255
+ applied = sum(item.outcome == "APPLIED" for item in decisions)
256
+ skipped = len(decisions) - applied
257
+ return {"mode": "apply" if apply else "dry_run", "applied": applied, "skipped": skipped, "decisions": [item.report() for item in decisions]}
258
+
259
+
260
+ def build_parser() -> argparse.ArgumentParser:
261
+ parser = argparse.ArgumentParser(description=__doc__)
262
+ parser.add_argument("--apply", action="store_true", help="persist only exact, verified evidence matches")
263
+ parser.add_argument("--run-id", help="limit recovery to one canonical run id")
264
+ return parser
265
+
266
+
267
+ def main(argv: list[str] | None = None) -> int:
268
+ args = build_parser().parse_args(argv)
269
+ try:
270
+ report = backfill(Path.cwd().resolve(), apply=args.apply, run_id=args.run_id)
271
+ except EngineeringStorageError as error:
272
+ raise SystemExit(f"PR-evidence recovery could not safely access storage: {error}") from error
273
+ print(json.dumps(report, indent=2, sort_keys=True))
274
+ return 0
275
+
276
+
277
+ if __name__ == "__main__": # pragma: no cover - module entry point
278
+ raise SystemExit(main())