diff --git a/examples/control_plane/shared-runtime-material-projection-smoke.py b/examples/control_plane/shared-runtime-material-projection-smoke.py index 2acbb2fa11..a315869694 100644 --- a/examples/control_plane/shared-runtime-material-projection-smoke.py +++ b/examples/control_plane/shared-runtime-material-projection-smoke.py @@ -344,8 +344,8 @@ def exercise_route_edges(root: Path) -> None: write_target(target_a, source_registry=ambiguous_registry, goal=ambiguous_goal) write_target(target_b, source_registry=ambiguous_registry, goal=ambiguous_goal) os.environ["LOOPX_RUNTIME_ROOT"] = str(target_a) - original_default = route_module.select_default_runtime_root - route_module.select_default_runtime_root = lambda: target_b + original_default = route_module.paths.DEFAULT_RUNTIME_ROOT + route_module.paths.DEFAULT_RUNTIME_ROOT = target_b try: ambiguous = record_operator_gate( ambiguous_registry, @@ -353,7 +353,7 @@ def exercise_route_edges(root: Path) -> None: sync_global=True, ) finally: - route_module.select_default_runtime_root = original_default + route_module.paths.DEFAULT_RUNTIME_ROOT = original_default if original_runtime is None: os.environ.pop("LOOPX_RUNTIME_ROOT", None) else: diff --git a/examples/core-control-plane-diagrams-smoke.py b/examples/core-control-plane-diagrams-smoke.py index 6ce4080db2..c4c170874f 100644 --- a/examples/core-control-plane-diagrams-smoke.py +++ b/examples/core-control-plane-diagrams-smoke.py @@ -47,7 +47,7 @@ def main() -> None: assert "Core Pattern Map" in docs["interaction-catalog.md"] assert "State Definitions" in docs["state-definitions.md"] assert "Canonical State Bodies" in docs["state-definitions.md"] - assert "Derived Runtime States" in docs["state-definitions.md"] + assert "Runtime Decisions, Phases, And Read Conditions" in docs["state-definitions.md"] assert "State Machines" in docs["state-machine.md"] for section in ( "Todo Lifecycle Machine", diff --git a/examples/fresh-clone-quickstart-smoke.py b/examples/fresh-clone-quickstart-smoke.py index 6ab746185f..9b391cb591 100644 --- a/examples/fresh-clone-quickstart-smoke.py +++ b/examples/fresh-clone-quickstart-smoke.py @@ -148,7 +148,7 @@ def main() -> int: assert "loopx-project.github.io/loopx/install.sh" in bootstrap["archive_fallback_install_command"], bootstrap assert "loopx doctor" in bootstrap["install_repair_command"], bootstrap assert (project / ".loopx" / "registry.json").is_file(), bootstrap - assert (project / ".codex" / "goals" / GOAL_ID / "ACTIVE_GOAL_STATE.md").is_file(), bootstrap + assert (project / ".loopx" / "goals" / GOAL_ID / "ACTIVE_GOAL_STATE.md").is_file(), bootstrap registry = project / ".loopx" / "registry.json" status = run_loopx("--registry", str(registry), "status", cwd=project, env=cli_env) diff --git a/examples/loopx-chat-actions-smoke.py b/examples/loopx-chat-actions-smoke.py index 45a45fdeae..14d35d35ae 100644 --- a/examples/loopx-chat-actions-smoke.py +++ b/examples/loopx-chat-actions-smoke.py @@ -393,7 +393,8 @@ def assert_http_action_api(root: Path) -> None: ) assert history_after_goal["goals"][0]["display_name"] == "New Goal", history_after_goal assert new_goal["coordination"]["registered_agents"] == ["codex"], new_goal - new_state = state_path.parent.parent / "new-goal" / "ACTIVE_GOAL_STATE.md" + assert new_goal["state_file"] == ".loopx/goals/new-goal/ACTIVE_GOAL_STATE.md", new_goal + new_state = registry_path.parent.parent / new_goal["state_file"] assert new_state.exists(), new_state new_state_text = new_state.read_text(encoding="utf-8") assert new_state_text.count("Verify the new Goal projection") == 1 diff --git a/examples/multi-goal-same-repo-smoke.py b/examples/multi-goal-same-repo-smoke.py index 03774f2d84..1a53af9281 100644 --- a/examples/multi-goal-same-repo-smoke.py +++ b/examples/multi-goal-same-repo-smoke.py @@ -153,7 +153,9 @@ def main() -> int: assert "project_local_goal_state_not_detected" in external_map["residual_risks"], external_map registry = json.loads(registry_path.read_text(encoding="utf-8")) - registry["goals"][2]["state_file"] = f".codex/goals/{MAIN_GOAL}/ACTIVE_GOAL_STATE.md" + registry["goals"][2]["state_file"] = next( + goal["state_file"] for goal in registry["goals"] if goal["id"] == MAIN_GOAL + ) registry_path.write_text(json.dumps(registry, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") duplicate_payload = run_cli(root, registry_path, "registry", check=False) assert duplicate_payload["ok"] is False, duplicate_payload diff --git a/examples/project/bootstrap-force-preserve-todos-smoke.py b/examples/project/bootstrap-force-preserve-todos-smoke.py index d1a464fe86..69bd8dceec 100644 --- a/examples/project/bootstrap-force-preserve-todos-smoke.py +++ b/examples/project/bootstrap-force-preserve-todos-smoke.py @@ -35,7 +35,6 @@ def main() -> int: with tempfile.TemporaryDirectory(prefix="loopx-bootstrap-preserve-") as tmp: project = Path(tmp) / "project" project.mkdir() - state_file = project / ".codex/goals/bootstrap-preserve-fixture/ACTIVE_GOAL_STATE.md" initial = run_cli( "bootstrap", @@ -49,6 +48,8 @@ def main() -> int: ) assert initial["ok"] is True, initial assert initial["state_action"] == "created", initial + state_file = Path(initial["state_file"]) + assert state_file == (project / ".loopx/goals/bootstrap-preserve-fixture/ACTIVE_GOAL_STATE.md").resolve() todo_state = "# Active Goal State\n\n## Agent Todo\n\n- [ ] Preserve this during reconnect.\n" state_file.write_text(todo_state, encoding="utf-8") diff --git a/loopx/chat_agent.py b/loopx/chat_agent.py index d3bdba3a1e..97720aff59 100644 --- a/loopx/chat_agent.py +++ b/loopx/chat_agent.py @@ -13,7 +13,7 @@ from pathlib import Path from typing import Any, Callable, Iterator -from .chat_activity import CodexActivitySteps +from .presentation.codex_activity import CodexActivitySteps from .chat import ( CHAT_AGENT_RESPONSE_SCHEMA_VERSION, CHAT_REVIEW_CLOSE_TAG, diff --git a/loopx/help_surface.py b/loopx/help_surface.py index 67e10046ff..12e143a0f0 100644 --- a/loopx/help_surface.py +++ b/loopx/help_surface.py @@ -330,6 +330,10 @@ def register_command_reference(subparsers: argparse._SubParsersAction) -> None: }, {"command": "loopx multi-agent", "purpose": "Launch visible role-scoped Codex TUI agents."}, {"command": "loopx canary", "purpose": "Plan or run catalog-informed smoke profiles."}, + { + "command": "loopx performance-diagnosis --help", + "purpose": "Plan an explicit local capture or inspect an existing profile without executing or uploading it.", + }, { "command": "loopx promotion-readiness", "purpose": "Record release-scoped canary readiness evidence in the shared runtime ledger.", diff --git a/loopx/presentation/README.md b/loopx/presentation/README.md index 391c4849a6..01a49912d4 100644 --- a/loopx/presentation/README.md +++ b/loopx/presentation/README.md @@ -19,6 +19,11 @@ Python code that starts as a user-visible capability may keep a thin facade under `loopx.capabilities.*`, but the reusable display implementation should live here. +`codex_activity.py` projects Codex host items into redacted, owner-visible Turn +steps. It owns display normalization only; step completion does not establish +Goal acceptance or execution authority. The Chat adapter consumes this projection +without exposing a separate top-level module. + ## Explore Result Layer Only the display side of software-exploration topology belongs here: diff --git a/loopx/chat_activity.py b/loopx/presentation/codex_activity.py similarity index 100% rename from loopx/chat_activity.py rename to loopx/presentation/codex_activity.py diff --git a/man/loopx.1 b/man/loopx.1 index f512ee7866..daab1ab594 100644 --- a/man/loopx.1 +++ b/man/loopx.1 @@ -273,6 +273,9 @@ Launch visible role\-scoped Codex TUI agents. \fBloopx canary\fR Plan or run catalog\-informed smoke profiles. .TP +\fBloopx performance\-diagnosis \-\-help\fR +Plan an explicit local capture or inspect an existing profile without executing or uploading it. +.TP \fBloopx promotion\-readiness\fR Record release\-scoped canary readiness evidence in the shared runtime ledger. .TP diff --git a/tests/test_chat_activity.py b/tests/test_chat_activity.py index 9b0b142a6b..2713dfc4c3 100644 --- a/tests/test_chat_activity.py +++ b/tests/test_chat_activity.py @@ -7,7 +7,7 @@ import pytest from pathlib import Path -from loopx.chat_activity import ( +from loopx.presentation.codex_activity import ( COMMAND_VERBS, REASONING_UPDATE_INTERVAL_SEC, STEP_KINDS,