fix(827): gate D4 launcher fixture
This commit is contained in:
@@ -24,6 +24,12 @@ from pathlib import Path
|
|||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
|
|
||||||
HERE = Path(__file__).resolve().parent
|
HERE = Path(__file__).resolve().parent
|
||||||
|
# WI-2 is deliberately kept in its reviewed worktree until the release package
|
||||||
|
# contains the gated launcher. This harness pins the source it will execute;
|
||||||
|
# falling back to the released `mosaic` binary is forbidden.
|
||||||
|
GATED_WI_ROOT = HERE.parents[3].parent / "stack-827-probe3"
|
||||||
|
GATED_WI_HEAD = "abd2791f59b3f06f46dd08e55298ced72f6aa7c2"
|
||||||
|
GATED_LAUNCHER = GATED_WI_ROOT / "packages/mosaic/framework/tools/lease-broker/launch-runtime.py"
|
||||||
|
|
||||||
|
|
||||||
class PiRpc:
|
class PiRpc:
|
||||||
@@ -220,6 +226,30 @@ export default function register(pi: ExtensionAPI): void {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def gated_launcher_precondition(root: Path, socket_path: Path, environment: dict[str, str]) -> None:
|
||||||
|
"""Refuse to launch unless the exact WI launcher binds this run's fixture."""
|
||||||
|
|
||||||
|
if environment.get("MOSAIC_LEASE_BROKER_SOCKET") != str(socket_path):
|
||||||
|
raise RuntimeError("D4 precondition: lease broker socket is not this fixture")
|
||||||
|
if socket_path.parent != root or root.parent != Path(tempfile.gettempdir()):
|
||||||
|
raise RuntimeError("D4 precondition: fixture socket is outside this run's temporary root")
|
||||||
|
try:
|
||||||
|
head = subprocess.check_output(
|
||||||
|
["git", "-C", str(GATED_WI_ROOT), "rev-parse", "HEAD"], text=True
|
||||||
|
).strip()
|
||||||
|
launcher_source = GATED_LAUNCHER.read_text(encoding="utf-8")
|
||||||
|
except (OSError, subprocess.CalledProcessError) as error:
|
||||||
|
raise RuntimeError("D4 precondition: gated WI launcher is unavailable") from error
|
||||||
|
if head != GATED_WI_HEAD:
|
||||||
|
raise RuntimeError(f"D4 precondition: gated WI head mismatch: {head}")
|
||||||
|
|
||||||
|
register = launcher_source.find('"action": "register_anchor"')
|
||||||
|
execute = launcher_source.find("execute(command[0], command, environment)")
|
||||||
|
fixture_socket = launcher_source.find('source_environment["MOSAIC_LEASE_BROKER_SOCKET"]')
|
||||||
|
if register < 0 or execute < 0 or register >= execute or fixture_socket < 0:
|
||||||
|
raise RuntimeError("D4 precondition: launcher is not register-before-exec fixture-bound")
|
||||||
|
|
||||||
|
|
||||||
def assert_d4(records: list[dict[str, Any]]) -> dict[str, object]:
|
def assert_d4(records: list[dict[str, Any]]) -> dict[str, object]:
|
||||||
lifecycle = [record for record in records if record.get("event") == "runtime_generation_bump"]
|
lifecycle = [record for record in records if record.get("event") == "runtime_generation_bump"]
|
||||||
promotion = next(record for record in records if record.get("event") == "probe_lease_promoted")
|
promotion = next(record for record in records if record.get("event") == "probe_lease_promoted")
|
||||||
@@ -293,20 +323,6 @@ def run_once(index: int) -> Path:
|
|||||||
extension = root / "d4_extension.ts"
|
extension = root / "d4_extension.ts"
|
||||||
write_extension(extension)
|
write_extension(extension)
|
||||||
|
|
||||||
broker = subprocess.Popen(
|
|
||||||
[
|
|
||||||
sys.executable,
|
|
||||||
str(HERE / "p3_generation_broker.py"),
|
|
||||||
"--socket",
|
|
||||||
str(socket_path),
|
|
||||||
"--log",
|
|
||||||
str(generation_log),
|
|
||||||
],
|
|
||||||
text=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT,
|
|
||||||
)
|
|
||||||
wait_path(socket_path)
|
|
||||||
environment = os.environ.copy()
|
environment = os.environ.copy()
|
||||||
# Do not let the gated launcher inherit or fall back to its live/default
|
# Do not let the gated launcher inherit or fall back to its live/default
|
||||||
# broker. Both its registration handshake and D4 lifecycle use this one
|
# broker. Both its registration handshake and D4 lifecycle use this one
|
||||||
@@ -321,10 +337,30 @@ def run_once(index: int) -> Path:
|
|||||||
"PI_SKIP_VERSION_CHECK": "1",
|
"PI_SKIP_VERSION_CHECK": "1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
# Must run before the fixture broker or Pi process is launched. It proves
|
||||||
|
# the launcher registers before exec and can only read this fixture socket.
|
||||||
|
gated_launcher_precondition(root, socket_path, environment)
|
||||||
|
broker = subprocess.Popen(
|
||||||
|
[
|
||||||
|
sys.executable,
|
||||||
|
str(HERE / "p3_generation_broker.py"),
|
||||||
|
"--socket",
|
||||||
|
str(socket_path),
|
||||||
|
"--log",
|
||||||
|
str(generation_log),
|
||||||
|
],
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
)
|
||||||
|
wait_path(socket_path)
|
||||||
pi = PiRpc(
|
pi = PiRpc(
|
||||||
[
|
[
|
||||||
"mosaic",
|
sys.executable,
|
||||||
"yolo",
|
str(GATED_LAUNCHER),
|
||||||
|
"--runtime",
|
||||||
|
"pi",
|
||||||
|
"--",
|
||||||
"pi",
|
"pi",
|
||||||
"--mode",
|
"--mode",
|
||||||
"rpc",
|
"rpc",
|
||||||
|
|||||||
Reference in New Issue
Block a user