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.
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,172 @@
1
+ """Server-owned lifecycle for the bounded Tailnet Console relay.
2
+
3
+ The relay is an access adapter only: it forwards the Tailnet listener to the
4
+ installed Server's loopback Console. It owns no submission, project, File
5
+ Inbox, Action or run state.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ from html import escape
11
+ from pathlib import Path
12
+ import shutil
13
+ from urllib.error import URLError
14
+ from urllib.request import urlopen
15
+
16
+ from .platform_components import PLATFORM_COMPONENT_BY_ID
17
+ from .providers import LaunchdProvider, LocalProcessProvider
18
+ from .resources import package_path
19
+
20
+
21
+ RUNTIME_DIRECTORY = "runtime"
22
+ RELAY_BINARY_FILENAME = "engineering-dashboard-relay"
23
+ # This identifier is retained solely to migrate an already installed legacy
24
+ # relay. The canonical component model is the only active lifecycle owner.
25
+ LEGACY_RELAY_LABEL = "com.djconnect.engineering-dashboard-relay"
26
+
27
+
28
+ class RelayCutoverError(RuntimeError):
29
+ """Fail-closed error for the exact relay identity cutover."""
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class PreCutoverState:
34
+ legacy_plist_present: bool
35
+ legacy_loaded: bool
36
+ legacy_process_active: bool
37
+ legacy_functional_probe: bool | None
38
+
39
+
40
+ def _definition_label() -> str:
41
+ label = PLATFORM_COMPONENT_BY_ID["dashboard_relay"].lifecycle_label
42
+ if not label:
43
+ raise RuntimeError("Dashboard Relay has no canonical lifecycle label.")
44
+ return label
45
+
46
+
47
+ def relay_binary(data_root: Path) -> Path:
48
+ """Return the installation-owned relay binary path, never a checkout path."""
49
+ return data_root.resolve() / RUNTIME_DIRECTORY / RELAY_BINARY_FILENAME
50
+
51
+
52
+ def build_relay(data_root: Path) -> Path:
53
+ """Compile the package-owned relay into the Server installation runtime."""
54
+ compiler = shutil.which("swiftc")
55
+ if compiler is None:
56
+ raise RuntimeError("Swift compiler is unavailable; Dashboard Relay cannot start.")
57
+ binary = relay_binary(data_root)
58
+ binary.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
59
+ completed = LocalProcessProvider().execute(
60
+ data_root.resolve(), (compiler, str(package_path("dashboard_supervisor.swift")), "-o", str(binary)),
61
+ )
62
+ if completed.returncode:
63
+ raise RuntimeError("Dashboard Relay compilation failed.")
64
+ binary.chmod(0o700)
65
+ return binary
66
+
67
+
68
+ def launch_agent_path() -> Path:
69
+ return Path.home() / "Library" / "LaunchAgents" / f"{_definition_label()}.plist"
70
+
71
+
72
+ def legacy_launch_agent_path() -> Path:
73
+ """Return the one retired relay plist that may be migrated."""
74
+ return Path.home() / "Library" / "LaunchAgents" / f"{LEGACY_RELAY_LABEL}.plist"
75
+
76
+
77
+ def relay_functional_probe() -> bool:
78
+ """Perform the bounded, token-free relay health check used for commit."""
79
+ try:
80
+ with urlopen("http://127.0.0.1:8765/health", timeout=2) as response: # noqa: S310 -- fixed loopback endpoint
81
+ return 200 <= response.status < 300
82
+ except (OSError, URLError):
83
+ return False
84
+
85
+
86
+ def pre_cutover_state(launchd: LaunchdProvider, *, probe=relay_functional_probe) -> PreCutoverState:
87
+ """Capture the non-secret legacy state that rollback must restore exactly."""
88
+ legacy = legacy_launch_agent_path()
89
+ loaded = launchd.inspect(LEGACY_RELAY_LABEL)
90
+ runtime = launchd.runtime_status(LEGACY_RELAY_LABEL) if loaded else None
91
+ active = bool(runtime and runtime.qualified)
92
+ return PreCutoverState(legacy.is_file(), loaded, active, probe() if active else None)
93
+
94
+
95
+ def _unload_and_verify(launchd: LaunchdProvider, label: str, plist: Path, *, code: str) -> None:
96
+ if not launchd.inspect(label):
97
+ return
98
+ launchd.uninstall(plist)
99
+ if launchd.inspect(label):
100
+ raise RelayCutoverError(code)
101
+
102
+
103
+ def _restore_legacy(launchd: LaunchdProvider, state: PreCutoverState, legacy: Path, neutral: Path, *, probe=relay_functional_probe) -> None:
104
+ """Restore exactly the captured legacy loaded state after neutral is absent."""
105
+ _unload_and_verify(launchd, _definition_label(), neutral, code="ROLLBACK_NEUTRAL_UNLOAD_UNVERIFIED")
106
+ neutral.unlink(missing_ok=True)
107
+ if state.legacy_loaded:
108
+ if not state.legacy_plist_present:
109
+ raise RelayCutoverError("ROLLBACK_LEGACY_PLIST_MISSING")
110
+ launchd.install(LEGACY_RELAY_LABEL, legacy)
111
+ if not launchd.inspect(LEGACY_RELAY_LABEL):
112
+ raise RelayCutoverError("ROLLBACK_LEGACY_LOAD_UNVERIFIED")
113
+ restored = launchd.runtime_status(LEGACY_RELAY_LABEL).qualified
114
+ if restored != state.legacy_process_active:
115
+ raise RelayCutoverError("ROLLBACK_LEGACY_PROCESS_STATE_MISMATCH")
116
+ if state.legacy_functional_probe is True and not probe():
117
+ raise RelayCutoverError("ROLLBACK_LEGACY_FUNCTIONAL_PROBE_FAILED")
118
+ elif launchd.inspect(LEGACY_RELAY_LABEL):
119
+ raise RelayCutoverError("ROLLBACK_LEGACY_STATE_MISMATCH")
120
+
121
+
122
+ def render_launch_agent(binary: Path) -> Path:
123
+ """Render the one canonical Relay LaunchAgent from an installed binary."""
124
+ destination = launch_agent_path()
125
+ destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
126
+ destination.write_text(
127
+ f'<?xml version="1.0" encoding="UTF-8"?><plist version="1.0"><dict><key>Label</key><string>{_definition_label()}</string><key>ProgramArguments</key><array><string>{escape(str(binary))}</string></array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/></dict></plist>',
128
+ encoding="utf-8",
129
+ )
130
+ return destination
131
+
132
+
133
+ def install(data_root: Path, *, probe=relay_functional_probe) -> dict[str, str]:
134
+ """Install the canonical relay and retire its single migration source.
135
+
136
+ The commit point is after neutral loaded/process/functional proof. Before
137
+ that point the untouched legacy plist and captured lifecycle state are the
138
+ sole rollback authority.
139
+ """
140
+ binary = build_relay(data_root)
141
+ plist = render_launch_agent(binary)
142
+ launchd = LaunchdProvider()
143
+ legacy = legacy_launch_agent_path()
144
+ state = pre_cutover_state(launchd, probe=probe)
145
+ if launchd.inspect(_definition_label()):
146
+ raise RelayCutoverError("NEUTRAL_ALREADY_LOADED")
147
+ if state.legacy_loaded:
148
+ _unload_and_verify(launchd, LEGACY_RELAY_LABEL, legacy, code="LEGACY_UNLOAD_UNVERIFIED")
149
+ try:
150
+ launchd.install(_definition_label(), plist)
151
+ if not launchd.inspect(_definition_label()):
152
+ raise RelayCutoverError("NEUTRAL_LOAD_UNVERIFIED")
153
+ if not launchd.runtime_status(_definition_label()).qualified:
154
+ raise RelayCutoverError("NEUTRAL_PROCESS_UNHEALTHY")
155
+ if not probe():
156
+ raise RelayCutoverError("NEUTRAL_FUNCTIONAL_PROBE_FAILED")
157
+ except Exception as error:
158
+ _restore_legacy(launchd, state, legacy, plist, probe=probe)
159
+ raise RelayCutoverError("RELAY_CUTOVER_ROLLED_BACK") from error
160
+ # Commit point: legacy is proven inactive, and neutral is loaded, active,
161
+ # and functionally healthy. Only now may the migration source be retired.
162
+ if state.legacy_plist_present:
163
+ legacy.unlink()
164
+ return {"component": "dashboard_relay", "binary": str(binary), "launch_agent": str(plist)}
165
+
166
+
167
+ def uninstall() -> dict[str, str]:
168
+ """Remove only the canonical relay LaunchAgent; Server data is untouched."""
169
+ plist = launch_agent_path()
170
+ LaunchdProvider().uninstall(plist)
171
+ plist.unlink(missing_ok=True)
172
+ return {"component": "dashboard_relay", "launch_agent": str(plist)}
@@ -0,0 +1,122 @@
1
+ """macOS LaunchAgent lifecycle for the installed EP Server.
2
+
3
+ The Server remains the lifecycle and CENTRAL authority. This module only
4
+ installs one fixed per-user supervisor for its foreground ``serve`` command;
5
+ it never starts a second daemon or accepts arbitrary commands.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ import os
11
+ from pathlib import Path
12
+ import plistlib
13
+ import platform
14
+ import subprocess
15
+ import sys
16
+ from typing import Callable, Mapping, Sequence
17
+
18
+
19
+ LABEL = "com.engineeringplatform.server"
20
+ DEFAULT_PATH = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
21
+
22
+
23
+ class ServerServiceError(ValueError):
24
+ """Raised when the bounded EP Server service cannot be managed safely."""
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class ServicePaths:
29
+ data_root: Path
30
+ launch_agents_dir: Path
31
+
32
+ @property
33
+ def plist_path(self) -> Path:
34
+ return self.launch_agents_dir / f"{LABEL}.plist"
35
+
36
+ @property
37
+ def log_dir(self) -> Path:
38
+ return self.data_root / "runtime"
39
+
40
+ @property
41
+ def stderr_log(self) -> Path:
42
+ return self.log_dir / "server-launchagent.err.log"
43
+
44
+
45
+ def default_paths(data_root: Path, home: Path | None = None) -> ServicePaths:
46
+ return ServicePaths(data_root.resolve(), (home or Path.home()).expanduser() / "Library" / "LaunchAgents")
47
+
48
+
49
+ def _domain() -> str:
50
+ return f"gui/{os.getuid()}"
51
+
52
+
53
+ Runner = Callable[[Sequence[str]], subprocess.CompletedProcess[str]]
54
+
55
+
56
+ def _launchctl(arguments: Sequence[str], runner: Runner | None = None) -> subprocess.CompletedProcess[str]:
57
+ if platform.system() != "Darwin":
58
+ raise ServerServiceError("EP Server LaunchAgent lifecycle is supported only on macOS.")
59
+ return (runner or (lambda command: subprocess.run(command, capture_output=True, text=True, check=False)))(["launchctl", *arguments])
60
+
61
+
62
+ def _installed_interpreter(candidate: str | Path | None = None) -> Path:
63
+ # Preserve a virtual-environment launcher symlink. Resolving it would
64
+ # turn ``<venv>/bin/python`` into its base interpreter, which no longer
65
+ # has the EP package installed when launchd invokes it.
66
+ executable = Path(candidate or sys.executable).expanduser().absolute()
67
+ if not executable.is_file() or not os.access(executable, os.X_OK):
68
+ raise ServerServiceError("The EP Server interpreter is not an executable installed runtime.")
69
+ return executable
70
+
71
+
72
+ def plist_payload(paths: ServicePaths, interpreter: Path) -> dict[str, object]:
73
+ return {
74
+ "Label": LABEL,
75
+ "ProgramArguments": [str(interpreter), "-m", "engineering_platform.server", "serve", "--data-root", str(paths.data_root)],
76
+ "WorkingDirectory": str(paths.data_root),
77
+ "RunAtLoad": True,
78
+ "KeepAlive": {"SuccessfulExit": False},
79
+ "ProcessType": "Background",
80
+ "EnvironmentVariables": {
81
+ "PATH": DEFAULT_PATH,
82
+ "PYTHONNOUSERSITE": "1",
83
+ "PYTHONSAFEPATH": "1",
84
+ "EP_SERVER_DATA_ROOT": str(paths.data_root),
85
+ },
86
+ "StandardOutPath": "/dev/null",
87
+ "StandardErrorPath": str(paths.stderr_log),
88
+ }
89
+
90
+
91
+ def write_plist(paths: ServicePaths, interpreter: Path) -> Path:
92
+ paths.launch_agents_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
93
+ paths.log_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
94
+ content = plistlib.dumps(plist_payload(paths, interpreter), fmt=plistlib.FMT_XML, sort_keys=True)
95
+ temporary = paths.plist_path.with_suffix(".plist.tmp")
96
+ temporary.write_bytes(content)
97
+ temporary.chmod(0o644)
98
+ os.replace(temporary, paths.plist_path)
99
+ paths.plist_path.chmod(0o644)
100
+ return paths.plist_path
101
+
102
+
103
+ def install(data_root: Path, *, interpreter: str | Path | None = None, home: Path | None = None,
104
+ runner: Runner | None = None) -> Mapping[str, str]:
105
+ paths = default_paths(data_root, home)
106
+ if not paths.data_root.is_dir() or not (paths.data_root / "server.json").is_file():
107
+ raise ServerServiceError("EP Server must be initialized before its LaunchAgent is installed.")
108
+ plist = write_plist(paths, _installed_interpreter(interpreter))
109
+ result = _launchctl(("bootstrap", _domain(), str(plist)), runner)
110
+ if result.returncode and "service already loaded" not in (result.stderr or "").lower():
111
+ raise ServerServiceError("Unable to bootstrap EP Server LaunchAgent.")
112
+ return {"state": "installed", "label": LABEL, "plist": str(plist), "data_root": str(paths.data_root), "stderr_log": str(paths.stderr_log)}
113
+
114
+
115
+ def uninstall(data_root: Path, *, home: Path | None = None, runner: Runner | None = None) -> Mapping[str, str]:
116
+ paths = default_paths(data_root, home)
117
+ if paths.plist_path.exists():
118
+ result = _launchctl(("bootout", _domain(), str(paths.plist_path)), runner)
119
+ if result.returncode and not any(marker in (result.stderr or "").lower() for marker in ("could not find service", "no such process", "not found")):
120
+ raise ServerServiceError("Unable to unload EP Server LaunchAgent.")
121
+ paths.plist_path.unlink(missing_ok=True)
122
+ return {"state": "uninstalled", "label": LABEL, "plist": str(paths.plist_path), "data_root": str(paths.data_root)}
@@ -0,0 +1,135 @@
1
+ """Canonical, bounded engineering-status model and atomic projections."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ import tempfile
10
+
11
+ from .agent_state import redact_diagnostic
12
+ from .platform_version import EngineeringPlatformManifest
13
+ from .storage import open_storage, store_projection
14
+
15
+ SCHEMA_VERSION = 1
16
+
17
+
18
+ def build(manifest: EngineeringPlatformManifest, **values: object) -> dict[str, object]:
19
+ """Build the sole status payload; callers cannot publish arbitrary content."""
20
+ payload = {
21
+ "schema_version": SCHEMA_VERSION,
22
+ "platform_version": manifest.platform_version,
23
+ "watcher_version": manifest.watcher_version,
24
+ "dashboard_version": manifest.dashboard_version,
25
+ "inbox_protocol": manifest.inbox_protocol,
26
+ "watcher_state": "WATCHER_IDLE",
27
+ "current_phase": None,
28
+ "current_action": None,
29
+ "run_id": None,
30
+ "job_id": None,
31
+ "runner_pid": None,
32
+ "submitted_filename": None,
33
+ "prompt_title": None,
34
+ "last_executed_filename": None,
35
+ "last_executed_title": None,
36
+ "last_executed_run": None,
37
+ "last_executed_phase": None,
38
+ "blocking_predecessor_run": None,
39
+ "blocking_predecessor_phase": None,
40
+ "blocking_predecessor_filename": None,
41
+ "blocking_predecessor_title": None,
42
+ "predecessor_recovery_action": None,
43
+ "received_timestamp": None,
44
+ "elapsed_seconds": 0,
45
+ "queue_depth": 0,
46
+ "queue_items": [],
47
+ "repair_iteration": 0,
48
+ "implementation_pr": None,
49
+ "finalization_pr": None,
50
+ "reconciliation_pr": None,
51
+ "implementation_state": None,
52
+ "finalization_state": None,
53
+ "validation_summary": None,
54
+ "merge_status_check": None,
55
+ "repository_state": "MERGED_RECONCILED",
56
+ "workspace_state": "WORKSPACE_READY",
57
+ "owner_authorized": False,
58
+ "resume_available": False,
59
+ "latest_report": None,
60
+ "latest_completed_run": None,
61
+ "diagnostic": None,
62
+ "last_update": datetime.now(timezone.utc).isoformat(),
63
+ }
64
+ payload.update({key: value for key, value in values.items() if key in payload})
65
+ payload["diagnostic"] = (
66
+ redact_diagnostic(str(payload["diagnostic"])) if payload["diagnostic"] else None
67
+ )
68
+ return payload
69
+
70
+
71
+ def publish(root: Path, payload: dict[str, object]) -> None:
72
+ """Persist canonical watcher state, then publish derived JSON/Markdown."""
73
+ root.mkdir(mode=0o700, parents=True, exist_ok=True)
74
+ # Production callers pass ``<repository>/.engineering/status``. Keep
75
+ # the public projector usable for an isolated status directory too (for
76
+ # recovery/export tooling), without accidentally resolving its datastore
77
+ # at filesystem root.
78
+ repository_root = (
79
+ root.parent.parent
80
+ if root.name == "status" and root.parent.name == ".engineering"
81
+ else root
82
+ )
83
+ connection = open_storage(repository_root)
84
+ try:
85
+ store_projection(connection, "watcher_status", payload)
86
+ finally:
87
+ connection.close()
88
+ markdown = "\n".join(
89
+ (
90
+ "# Engineering Platform",
91
+ "",
92
+ "## Current State",
93
+ f"`{payload['watcher_state']}` — `{payload['current_phase'] or 'idle'}`",
94
+ "",
95
+ "## Active Job",
96
+ f"Run: `{payload['run_id'] or 'none'}` ",
97
+ f"File: `{payload['submitted_filename'] or 'none'}` ",
98
+ f"Prompt: `{payload['prompt_title'] or 'none'}`",
99
+ f"Queue: `{payload['queue_depth']}`",
100
+ "",
101
+ "## Pull Requests",
102
+ f"Implementation: `{payload['implementation_pr'] or 'none'}` ",
103
+ f"Finalization: `{payload['finalization_pr'] or 'none'}`",
104
+ f"Reconciliation: `{payload['reconciliation_pr'] or 'none'}`",
105
+ "",
106
+ "## Repository",
107
+ f"Repository: `{payload['repository_state']}` ",
108
+ f"Workspace: `{payload['workspace_state']}`",
109
+ "",
110
+ "## Authorization",
111
+ f"Owner-authorized: `{payload['owner_authorized']}`; release and deployment authority: `absent`",
112
+ "",
113
+ "## Latest Report",
114
+ f"`{payload['latest_report'] or 'none'}`",
115
+ "",
116
+ "## Predecessor Gate",
117
+ f"Blocking run: `{payload['blocking_predecessor_run'] or 'none'}` ",
118
+ f"Blocking prompt: `{payload['blocking_predecessor_title'] or payload['blocking_predecessor_filename'] or 'none'}` ",
119
+ str(payload["predecessor_recovery_action"] or "none"),
120
+ "",
121
+ "## Diagnostic",
122
+ str(payload["diagnostic"] or "none"),
123
+ "",
124
+ )
125
+ )
126
+ for name, content in (
127
+ ("status.json", json.dumps(payload, indent=2, sort_keys=True) + "\n"),
128
+ ("status.md", markdown),
129
+ ):
130
+ descriptor, temporary = tempfile.mkstemp(prefix=f".{name}.", dir=root)
131
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
132
+ handle.write(content)
133
+ handle.flush()
134
+ os.fsync(handle.fileno())
135
+ os.replace(temporary, root / name)
@@ -0,0 +1,34 @@
1
+ """Fail-closed recognition of a stale rolling-status preflight block."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+
6
+ from .agent_state import TransactionState
7
+
8
+
9
+ _ROLLING_RECORDS = re.compile(r"\brolling(?:\s+status)?\s+records?\b", re.IGNORECASE)
10
+ _STALE_STATUS_INDICATOR = re.compile(
11
+ r"\b(?:finalization|reconcil(?:e|iation|ed)|pending|stale|state)\b",
12
+ re.IGNORECASE,
13
+ )
14
+
15
+
16
+ def is_stale_rolling_status_block(state: TransactionState) -> bool:
17
+ """Recognize only the no-PR preflight block eligible for Finalization.
18
+
19
+ Diagnostics are advisory and are never delivery evidence. They merely
20
+ identify the already blocked, no-PR transaction for the existing dedicated
21
+ governance-only Finalization path. Any run-scoped PR evidence, a different
22
+ terminal state, or an unrelated diagnostic remains fail-closed.
23
+ """
24
+ diagnostic = state.diagnostic or ""
25
+ return (
26
+ state.phase == "BLOCKED"
27
+ and state.terminal_condition == "external_blocked"
28
+ and state.transaction_kind == "IMPLEMENTATION"
29
+ and state.pull_request is None
30
+ and state.implementation_pull_request is None
31
+ and state.finalization_pull_request is None
32
+ and bool(_ROLLING_RECORDS.search(diagnostic))
33
+ and bool(_STALE_STATUS_INDICATOR.search(diagnostic))
34
+ )