diff --git a/examples/project/first-connect-contract-smoke.py b/examples/project/first-connect-contract-smoke.py index 2303439a37..afcbca503d 100644 --- a/examples/project/first-connect-contract-smoke.py +++ b/examples/project/first-connect-contract-smoke.py @@ -13,13 +13,21 @@ from __future__ import annotations import json +import os import subprocess import sys import tempfile +from collections.abc import Iterator +from contextlib import contextmanager from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] +# These source-owned oracles must use the same checkout as the CLI below. +sys.path.insert(0, str(REPO_ROOT)) +from tests.control_plane.codex_checkpoint_fixture import read_cli_policy_payload # noqa: E402 +from tests.managed_effect_runtime_fixture import stop_disposable_effect_runtimes # noqa: E402 + GENERIC_GOAL_ID = "fresh-generic-connect" DOMAIN_GOAL_ID = "fresh-domain-connect" FIRST_TODO_ID = "fresh-first-delivery" @@ -50,7 +58,31 @@ def run_cli(registry: Path, runtime: Path, *args: str) -> dict: text=True, capture_output=True, ) - return json.loads(result.stdout) + # Native navigation names the current capture; it is not the policy. This + # test oracle verifies the complete recovery without claiming model reads. + return read_cli_policy_payload(result.stdout, returncode=result.returncode) + + +@contextmanager +def _isolated_runtime(root: Path) -> Iterator[None]: + """Keep every CLI child's temporary runtime inside this smoke's owner.""" + settings = {"TMPDIR": str(root), "TEMP": str(root), "TMP": str(root), "LOOPX_USAGE_PING": "0"} + previous = {key: os.environ.get(key) for key in settings} + previous_tempdir = tempfile.tempdir + try: + os.environ.update(settings) + tempfile.tempdir = str(root) + yield + finally: + try: + stop_disposable_effect_runtimes(root) + finally: + tempfile.tempdir = previous_tempdir + for key, value in previous.items(): + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value def initialize_project(root: Path, name: str) -> tuple[Path, Path]: @@ -121,7 +153,10 @@ def connect_generic(root: Path, runtime: Path) -> tuple[Path, Path, str]: def main() -> int: - with tempfile.TemporaryDirectory(prefix="loopx-first-connect-") as tmp: + with ( + tempfile.TemporaryDirectory(prefix="loopx-first-connect-") as tmp, + _isolated_runtime(Path(tmp)), + ): root = Path(tmp) runtime = root / "runtime" project, registry, state_text = connect_generic(root, runtime) diff --git a/skills/loopx-self-repair/references/repair-patterns.md b/skills/loopx-self-repair/references/repair-patterns.md index bc95573fe9..6e860b7840 100644 --- a/skills/loopx-self-repair/references/repair-patterns.md +++ b/skills/loopx-self-repair/references/repair-patterns.md @@ -154,6 +154,7 @@ teaches a reusable control-plane lesson. | `future_monitor_heartbeat_liveness_overreach` | A valid future-scheduled monitor repeatedly enters `frontier_exhausted_monitor_lane` or `dead_monitor_repeat` even though it is not due and no real monitor execution occurred. | generated heartbeat guard command, trigger `current_time_iso`, quota `heartbeat_receipt`, monitor Todo `next_due_at`, run-history `quota_monitor_poll` rows, concrete Todo/target identity, and monitor mode. | Future wait state was collapsed into empty-frontier exhaustion, while distinct heartbeat turn ids were treated as monitor executions and lowered the dead-monitor threshold. | Add typed `future_monitor_wait` and `due_monitor_execution` frontier rules. Keep future monitors quiet/no-spend until due; count `dead_monitor_repeat` only from unchanged due/external executions carrying a concrete Todo or target identity. Heartbeat turn ids remain idempotency/liveness evidence and never reduce the real execution threshold. | | `replan_context_delivery_gap` | A replan obligation is visible, but a weak protocol-following model ignores or mis-executes a manual evidence-log read ritual, then spends turns debugging ACK/read order instead of choosing a new direction. | current obligation id, host-projected `replan_context_v0`, compact coverage ledger, delivery receipt, typed action packet, selected model tool action, semantic writeback receipt, and successor turn boundary. | Evidence access was modeled as an agent CLI obligation even though the control plane already owned the ledger; read execution and semantic use were conflated. A separate Todo-add then refresh ACK also let the model execute the successor in the replan turn. | Have the host prefetch and project bounded evidence coverage into quota. Treat the delivery receipt as context delivery only; require the model's real next action to produce an accepted typed semantic delta bound to the current obligation. When the delta is a runnable successor, bind the exact obligation on the Todo write itself and return `end_current_heartbeat`; do not require a second ACK or run the successor in that turn. Remove the standalone evidence command and generated read rituals. Reuse the typed replan context for the core Goal, dense scoped decision evidence, repetition reduction and exact history-reference reads. Keep replan selection independent of the routine display window, and validate novelty against complete available history even when the readable context is truncated; reject malformed schemas and unavailable references instead of treating them as empty evidence. Preserve the durable history and historical receipt decoder, not a compatibility command. Cover real quota→model action→Todo/refresh CLI behavior plus missing/wrong obligation identity. | | `machine_cli_capture_projection_gap` | A native hook or non-model JSON consumer treats context navigation as the effective decision and denies ready work because a top-level admission field is absent. | Original child argv/runtime profile; outer schema versus the same immutable captured Core decision; parent/child context settings; real Core ready, user-gate and zero-quota cases. | Model-facing context transport wrapped the formerly inline machine payload. A locator is not a policy decision; a locale/codec repair alone cannot restore this path. | Use the existing machine-output contract only for the non-model child process, retaining Core gates, identity, UTF-8 and environment isolation. Reuse the established per-child `LOOPX_CONTEXT_DELIVERY=off`; do not disable model context globally or interpret navigation `ok` as admission. Actual model consumers must follow the original readers and retain current bytes/digests. Validate ready, user-gate and zero-quota behavior with parent context on/off unchanged; distinguish source, installed-host and live-model qualification. | +| `native_policy_test_consumer_navigation` | A source-owned policy smoke intentionally exercises native output but raises `KeyError` on an admission field, or mistakes navigation `ok` for decision readiness. | Original CLI result and the same current immutable recovery, unchanged semantic assertions, and full connection/own-Todo readback. | The test helper decoded only outer JSON and treated the model-facing navigation envelope as the policy. This differs from the machine-output host adapter in `machine_cli_capture_projection_gap`. | Reuse the existing test-only `read_cli_policy_payload` oracle to verify the current complete recovery; preserve inline results, nonzero exits, physical-file/digest checks and all original semantic assertions. Keep native output enabled for this qualification. Test generic/domain connection and the caller's own first Todo through the real CLI, plus failed/inline/native and damaged-reference cases. Isolate temporary runtimes and telemetry before child invocation and retire only authenticated test-owned runtimes before removing their directory. The oracle proves test observations, not model retention, execution authority or whole-Goal benefit. | | `replan_settlement_binding_projection_gap` | A replan packet and selected Todo are both visible, so an agent combines `--todo-id` with `--replan-obligation-id`, alternates between them after rejection, or performs the Todo-bound refresh but omits the matching spend. | Original quota receipt identity, selected Todo, semantic obligation id, interaction settlement plan, projected refresh/spend commands, and accepted semantic ACK. | The semantic obligation target and causal settlement identity were adjacent but unlabeled, while one boolean conflated direct obligation binding with whether a full settlement chain was required. | Keep exactly one causal settlement binding. For a turn-scoped executable plan, project a domain-local typed replan settlement contract that labels the selected Todo or Todo-less obligation as the binding and keeps the replan id as a separate semantic target when necessary. Todo-bound and directly bound replan writes both project material refresh followed by spend; never combine their CLI flags. Keep unscoped diagnostic reads compact and non-executable. Cover TS projection, hot-path envelope, real Todo-bound/Todo-less CLI chains, output budget, and in-flight delivery continuity. | | `native_goal_todoless_replan_reentry_gap` | A native visible Goal completes all advancement Todos, semantic closeout derives a Todo-less autonomous replan obligation, and the next unbound quota read projects a bare refresh with no Turn identity or spend chain. | Native Goal runtime profile, selected Todo absence, replan obligation id, interaction CLI actions before and after Turn creation, and settlement identity. | Native-Goal Turn re-entry recognized only selected Todos as actionable settlement bindings and ignored a valid Todo-less replan obligation. | Treat either a selected Todo or a valid replan obligation as a native-Goal settlement binding. When no Turn or settlement plan exists, project only the exact `quota should-run ... --begin-turn` re-entry. After execution, require the obligation-bound refresh and spend chain; keep generic unscoped diagnostic behavior unchanged. | | `replan_meta_successor_churn` | An autonomous replan repeatedly adds and completes obligation-bound advancement Todos whose only action is to replan, re-arm, wait for the host, or report no new direction; Todo count grows while executable targets and evidence do not. | current obligation and acceptance gaps, generated replan action packet, bound Todo `action_kind`/`target_key`/Explore refs, semantic ACK, Todo lifecycle, and compact progress fingerprints. | A planning instruction was compiled into a runnable successor command, while Todo authoring and ACK validation treated obligation identity alone as proof of executable semantic change. | Generate a successor command only from a concrete bounded frontier with a typed action and stable target. Require the same semantic binding at Todo write and ACK time; generic vision/frontier replans must resolve through a typed progress or coverage-backed terminal outcome instead of creating a meta Todo. Cover packet generation, write rejection, ACK rejection, and a real quota→model→CLI successor re-entry. |