Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
264fe49
fix(chat): keep manager provider wiring at the composition root
loopx-agent Oct 29, 2026
edf2b89
fix(update): generate standalone bootstrap from shared grammar owners
loopx-agent Oct 29, 2026
6e9449b
fix(host): use a supported managed Chat restart seam
loopx-agent Oct 29, 2026
5a61ac0
test(delegation): reuse authenticated parent-owned runtime cleanup
loopx-agent Oct 29, 2026
522ff80
test(delegation): retain explicit cleanup through the shared owner
loopx-agent Oct 29, 2026
f84ba93
fix(quota): keep decided refusals in the typed envelope path
loopx-agent Oct 29, 2026
59dfc17
test(context): follow native references before asserting page coverage
loopx-agent Oct 29, 2026
aafa458
test(heartbeat): retain complete timed-wait and dispatch obligations
loopx-agent Oct 29, 2026
b848557
test(budget): qualify complete thin prompts at the supported scope
loopx-agent Oct 29, 2026
fb62878
fix(update): read artifact and operation metadata as UTF-8
loopx-agent Oct 29, 2026
0d88309
test(lark): patch the owning manager snapshot provider
loopx-agent Oct 29, 2026
12d2630
test(context): keep the worker advertised recovery scope
loopx-agent Oct 29, 2026
0ca7c03
docs(contributing): list the runtime snapshot workflow
loopx-agent Oct 29, 2026
13d748b
test(quota): preserve collection failures without runtime reentry
loopx-agent Oct 29, 2026
4a2426e
test(install): verify declared sibling skill resources
loopx-agent Oct 29, 2026
5cbdfd9
merge: combine the context recovery qualification repairs
loopx-agent Oct 29, 2026
3e2423b
merge: reuse the reviewed parent-owned delegation fixture
loopx-agent Oct 29, 2026
c4241a4
fix(quota): compact decided monitor refusals without runtime reentry
loopx-agent Oct 29, 2026
b11980b
test(quota): follow the active presentation transport owner
loopx-agent Oct 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ touch, mention it in the PR instead of fixing it there.
| `postgresql-integration.yml` | control-plane or npm lockfile paths | no | PostgreSQL authority store and service on a temporary instance |
| `package-smoke.yml` | extension package paths | no | extension packages install, entrypoints, and example schemas |
| `release-artifacts.yml` | `loopx/`, packaging, and lockfile paths | no | release identity and a release build from this source |
| `runtime-snapshots.yml` | runtime artifact, installer, and updater paths | no | qualified, revision-addressed runtime archives and the main channel pointer |
| `ark-turn.yml` | Turn driver and collaboration paths | no | optional Ark Turn package, stdio MCP, and DSH parity |
| `memt-turn.yml` | optional MemT package, Turn driver, lock, and packaging paths | no | explicit optional dependency installation, complete adapter workflow, stdio MCP, and driver binding |
| `dsh-plugin.yml` | DSH plugin and distribution workflow paths | no | Linux/Windows package install and uninstall, typed host contracts, and Linux real LoopX/web runtime admission |
Expand Down
10 changes: 10 additions & 0 deletions docs/architecture/rfcs/monorepo-distribution-split-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,16 @@ records both edges. Existing Ark/JEV private edges remain migration debt and
receive no new exemption. The facade forwards existing behavior; it must not
copy candidate, acceptance, process-lifetime or locking decisions.

The independently installed Codex provider-routing host uses
`loopx.extensions.chat_service_guard` for its existing authorized restart of
managed Chat consumers. The facade exports only `managed_chat_activation_guard`
and `RuntimeActivationDeferred` from the current runtime activation owner.
Accepted-work observation, exact service identity and the ingress lock stay
with that owner; the package neither reads private Goal state nor copies the
decision. Missing or unsupported Core defers the service restart. The no-service
path remains independent of Core. This one supported public edge is pinned;
it grants no authority to stop a service or add other kernel imports.

The stdio relay cancels its owned process group on parent EOF, SIGTERM or
SIGINT and waits for the existing supervisor's cleanup before exiting. POSIX
process-group behavior and Windows best-effort tree cleanup retain their
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ MemT 只使用这两个公开模块,不能直接 import executor 或其他内
边。Ark/JEV 的既有私有边仍是迁移积压,不新增豁免。facade 只转发现有行为,
不能复制候选、验收、进程生命周期或文件锁决策。

独立安装的 Codex provider-routing host 通过
`loopx.extensions.chat_service_guard` 接入其已有、已获授权的托管 Chat consumer
重启。facade 只转出现有 runtime activation owner 的
`managed_chat_activation_guard` 与 `RuntimeActivationDeferred`。已接受工作观察、
准确服务身份和 ingress lock 仍由该 owner 负责;包不读取私有 Goal 状态,
也不复制决策。Core 缺失或不支持时延期重启;没有托管服务的路径仍不依赖 Core。
import ratchet 只记录这一条受支持公开边;它不授予停止服务或增加其他内核 import 的权限。

stdio relay 在父进程 EOF、SIGTERM 或 SIGINT 时取消所持进程组,并等待已有
监督器完成回收再退出。POSIX 进程组行为与 Windows 尽力而为的进程树回收仍沿用
原资格边界。这是进程监督,不是沙箱;操作者选择的工具只保有原先获准的效果。
Expand Down
2 changes: 1 addition & 1 deletion examples/blocker-push-runtime-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def main() -> int:
# current compact sentence instead of the retired per-shell phrasing.
assert "reuse the value on retries" in compact_prompt, prompt
assert "obey projected replan/stop, never wake counts" in compact_prompt, prompt
assert "re-enter guard." in compact_prompt, prompt
assert "re-enter as instructed, do/verify authorized work." in compact_prompt, prompt
assert "2 stalls->replan" not in compact_prompt, prompt
assert "Exact monitor settlement=no refresh/spend" in compact_prompt, prompt
assert "Admitted work: settlement_plan even if artifacts unchanged" in compact_prompt, prompt
Expand Down
7 changes: 3 additions & 4 deletions examples/control_plane/heartbeat_prompt_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ def normalized(text: str) -> str:


def prompt_budget_text(text: str) -> str:
return text.replace(GOAL_ID, "<GOAL_ID>").replace(
str(ACTIVE_STATE),
"<ACTIVE_GOAL_STATE_PATH>",
)
# Normalize the complete path before its Goal substring, matching the
# independently declared authored-guidance measurement contract.
return text.replace(str(ACTIVE_STATE), "<ACTIVE_STATE>").replace(GOAL_ID, "<GOAL_ID>")


def assert_prompt_budget(label: str, text: str) -> None:
Expand Down
6 changes: 5 additions & 1 deletion examples/export-frontstage-share-bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ async function copyHomepage(siteDir, base) {
await cp(buildDir, siteDir, { force: true, recursive: true });
await rm(buildDir, { force: true, recursive: true });
await copyFile(resolve(repoRoot, installerScriptPath), resolve(siteDir, "install.sh"));
await copyFile(resolve(repoRoot, "loopx/cli_commands/update_artifact.py"), resolve(siteDir, "update-artifact.py"));
const bootstrap = run(resolveTestPython(), ["-c",
"from loopx.cli_commands.update_artifact import standalone_source; print(standalone_source(), end='')"], {
capture: true, cwd: repoRoot,
});
await writeFile(resolve(siteDir, "update-artifact.py"), bootstrap, "utf8");
}

async function copyPublicSiteRoutes(siteDir) {
Expand Down
10 changes: 7 additions & 3 deletions examples/install-local-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def normal_turns_use_cli_interaction_contract(task_body: str) -> bool:
def read_installed_workflow_skill(
skill: Path, *, references: set[str]
) -> dict[str, str]:
"""Read the installed entrypoint and its complete, self-contained procedures."""
"""Read installed procedures and verify links stay in the declared bundle."""
skill_root = skill.parent.resolve()
documents = {"SKILL.md": skill.read_text(encoding="utf-8")}
linked_references = {
Expand All @@ -81,8 +81,12 @@ def read_installed_workflow_skill(
if "://" in destination or destination.startswith("#"):
continue
resource = (document.parent / destination.split("#", 1)[0]).resolve()
assert resource.is_relative_to(skill_root), (document, destination)
bundle_root = skill_root.parent
assert resource.is_relative_to(bundle_root), (document, destination)
bundled_path = resource.relative_to(bundle_root)
assert bundled_path.parts[0] in {"loopx", *PACKAGED_HOST_SKILL_IDS}, (document, destination)
assert resource.is_file(), (document, destination)
assert resource.read_bytes() == (REPO_ROOT / "skills" / bundled_path).read_bytes(), resource
return documents


Expand Down Expand Up @@ -917,7 +921,7 @@ def main() -> int:
assert "```sh\nLOOPX_TURN=<current_time_iso>\n" in payload["task_body"], payload
assert "not a command-prefix assignment" in payload["task_body"], payload
assert "obey projected replan/stop, never wake counts" in payload["task_body"], payload
assert "re-enter guard." in payload["task_body"], payload
assert "re-enter as instructed, do/verify authorized work." in payload["task_body"], payload
assert "2 stalls->replan" not in payload["task_body"], payload
assert "Exact monitor settlement=no refresh/spend" in payload["task_body"], payload
assert "Admitted work: settlement_plan even if artifacts unchanged" in payload["task_body"], payload
Expand Down
24 changes: 23 additions & 1 deletion loopx/chat_lark_api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import subprocess
from collections.abc import Mapping
from collections.abc import Callable, Mapping
from pathlib import Path
from typing import TYPE_CHECKING, Any
from urllib.parse import parse_qs, urlparse
Expand Down Expand Up @@ -46,6 +46,28 @@
from .repository_identity import normalize_repository_identity


def manager_source_scope_resolver(
server: Any, *, registry_path: Path, executor_runtime_root: Path,
) -> Callable[[dict[str, Any]], list[str] | None]:
"""Keep the default manager's native and legacy source routing together."""
from .extensions.lark.manager_routing import authorized_manager_goal_ids

def read(session):
controller = server.runtime_controller
if isinstance(session.get("steward_context"), dict):
bindings = controller.project_contexts.conversation_bindings
if bindings is None:
raise ValueError("Steward conversation bindings are unavailable")
return bindings.steward_scope(session)
return authorized_manager_goal_ids(
build_lark_goal_topic_runtime_snapshot(
registry_path=server.registry_path, runtime_root_override=server.runtime_root_override,
), session, runtime_root=controller.coordination_runtime_root,
registry_path=registry_path, executor_runtime_root=executor_runtime_root,
)
return read


def _compact_text(value: Any, *, limit: int = 600) -> str:
return " ".join(str(value or "").split())[:limit].strip()

Expand Down
3 changes: 2 additions & 1 deletion loopx/chat_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1921,7 +1921,8 @@ def serve_chat(
)
server.chat_store = ChatSessionStore(runtime_root)
server.action_store = ChatActionStore(runtime_root / "chat" / "actions")
from .presentation.request_control_api import bound_steward_inventory_scope, manager_source_scope_resolver
from .presentation.request_control_api import bound_steward_inventory_scope
from .chat_lark_api import manager_source_scope_resolver
manager_scope = manager_source_scope_resolver(server,
registry_path=resolved_registry_path, executor_runtime_root=runtime_root)

Expand Down
94 changes: 4 additions & 90 deletions loopx/cli_commands/quota.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
from pathlib import Path
from typing import Any

from .quota_presentation import (
_project_quota_cli_payload as _project_quota_cli_payload,
_quota_renderer as _quota_renderer,
)
from .quota_capture import (
bind_capture_selection_transport, capture_decision, handoff_decision,
handle_native_context_command, handle_replan_view, prepare_quota_capture, native_context_capture_view,
Expand All @@ -26,17 +30,11 @@
from ..capabilities.repository_change_window import (
repository_delivery_interaction_hook,
)
from ..control_plane.effect_runtime import EffectRuntimeRejected
from ..control_plane.coordination.local_authority import CanonicalAuthorityRequired
from ..control_plane.goals.first_party_host_admission import (
capture_first_party_host_goal_ref,
)
from ..control_plane.goals.source_session_registry_state import exact_goal_ref
from ..control_plane.quota.cli_projection import (
compact_quota_monitor_poll_cli_payload,
compact_quota_plan_cli_payload,
compact_quota_should_run_cli_payload,
)
from ..control_plane.quota.effect_program import SettlementIdentity
from ..control_plane.quota.error_codes import (
CloseoutQueryUnavailableError,
Expand All @@ -60,20 +58,6 @@
reconcile_existing_heartbeat_receipt_for_turn,
render_existing_heartbeat_receipt_payload,
)
from ..control_plane.quota.turn_envelope import build_turn_envelope
from ..presentation.renderers.quota_event_markdown import (
render_quota_monitor_poll_markdown,
render_quota_slot_preview_markdown,
)
from ..presentation.renderers.quota_markdown import (
render_quota_markdown,
render_quota_scheduler_ack_markdown,
render_quota_scheduler_failure_markdown,
render_quota_should_run_markdown,
)
from ..presentation.renderers.turn_envelope_markdown import (
render_turn_envelope_markdown,
)
from ..quota import (
build_quota_plan,
record_quota_monitor_poll,
Expand Down Expand Up @@ -184,24 +168,6 @@ def _effective_spend_turn_instance_id(
return payload_turn_id


def _quota_renderer(
args: argparse.Namespace,
*,
failure: bool = False,
) -> Callable[[dict[str, object]], str]:
command = args.quota_command
if not failure and bool(getattr(args, "turn_envelope", False)):
return render_turn_envelope_markdown
return {
"should-run": render_quota_should_run_markdown,
"monitor-poll": render_quota_monitor_poll_markdown,
"scheduler-ack": render_quota_scheduler_ack_markdown,
"scheduler-ack-current": render_quota_scheduler_ack_markdown,
"scheduler-fail-current": render_quota_scheduler_failure_markdown,
"spend-slot": render_quota_slot_preview_markdown,
"void-slot": render_quota_slot_preview_markdown,
}.get(command, render_quota_markdown)


def _dispatch_quota_turn_start_hooks(
args: argparse.Namespace,
Expand Down Expand Up @@ -300,58 +266,6 @@ def _attach_turn_start_hook_dispatch(
payload["turn_start_capability_hook_dispatch"] = {
key: value for key, value in dispatch.items() if key != "contexts"
}
def _project_quota_cli_payload(
payload: dict[str, object],
args: argparse.Namespace,
detail_sections: frozenset[str],
scheduler_context: object,
*,
captured_decision_path: str | None = None,
) -> dict[str, object]:
"""Project successful decisions; failed requests retain their diagnostic.

Optional presentation must not call a runtime that failed during collection.
A rejected envelope likewise retains the already-decided facts (issue #3687).
"""
from ..control_plane.effect_program import reject_retired_quota_format

reject_retired_quota_format(payload)
if payload.get("ok") is False:
# Failure reporting must not reenter the runtime that just failed.
# Keep the decided diagnostic, including its original recovery/receipt.
if bool(getattr(args, "turn_envelope", False)):
return {**payload, "turn_envelope_skipped": "quota request failed; original diagnostic retained"}
return payload
if not bool(getattr(args, "turn_envelope", False)):
if args.quota_command in {"status", "plan"}:
return compact_quota_plan_cli_payload(payload, detail_sections=detail_sections)
if args.quota_command == "should-run":
if captured_decision_path and "vision" not in detail_sections:
from ..control_plane.quota.turn_envelope import _turn_envelope_result
payload = _turn_envelope_result("replan_cli_view", payload=payload)
return compact_quota_should_run_cli_payload(
payload,
include_todo_summary_detail="agent-todos" in detail_sections,
include_user_todo_summary_detail="user-todos" in detail_sections,
include_goal_boundary_detail="goal-boundary" in detail_sections,
include_vision_detail="vision" in detail_sections,
)
if args.quota_command == "monitor-poll":
return compact_quota_monitor_poll_cli_payload(
payload, include_decision_detail="decisions" in detail_sections,
)
return payload
try:
return build_turn_envelope(
payload,
scheduler_execution_context=scheduler_context,
captured_decision_path=captured_decision_path,
)
except EffectRuntimeRejected as envelope_error:
degraded = dict(payload)
degraded["turn_envelope_skipped"] = str(envelope_error)[:200]
return degraded


def _emit_quota_result(
payload: dict[str, object],
Expand Down
109 changes: 109 additions & 0 deletions loopx/cli_commands/quota_presentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Quota CLI presentation transport; TypeScript retains decision ownership."""
from __future__ import annotations

import argparse
from collections.abc import Callable, Mapping

from ..control_plane.effect_runtime import EffectRuntimeRejected
from ..control_plane.quota.turn_envelope import build_turn_envelope
from ..control_plane.quota.cli_projection import (
compact_quota_monitor_poll_cli_payload,
compact_quota_plan_cli_payload,
compact_quota_should_run_cli_payload,
)

from ..presentation.renderers.quota_event_markdown import (
render_quota_monitor_poll_markdown,
render_quota_slot_preview_markdown,
)

from ..presentation.renderers.quota_markdown import (
render_quota_markdown,
render_quota_scheduler_ack_markdown,
render_quota_scheduler_failure_markdown,
render_quota_should_run_markdown,
)

from ..presentation.renderers.turn_envelope_markdown import (
render_turn_envelope_markdown,
)

def _quota_renderer(
args: argparse.Namespace,
*,
failure: bool = False,
) -> Callable[[dict[str, object]], str]:
command = args.quota_command
if not failure and bool(getattr(args, "turn_envelope", False)):
return render_turn_envelope_markdown
return {
"should-run": render_quota_should_run_markdown,
"monitor-poll": render_quota_monitor_poll_markdown,
"scheduler-ack": render_quota_scheduler_ack_markdown,
"scheduler-ack-current": render_quota_scheduler_ack_markdown,
"scheduler-fail-current": render_quota_scheduler_failure_markdown,
"spend-slot": render_quota_slot_preview_markdown,
"void-slot": render_quota_slot_preview_markdown,
}.get(command, render_quota_markdown)


def _project_quota_cli_payload(
payload: dict[str, object],
args: argparse.Namespace,
detail_sections: frozenset[str],
scheduler_context: object,
*,
captured_decision_path: str | None = None,
) -> dict[str, object]:
"""Project decided contracts; failed collection retains its diagnostic.

Optional presentation must not call a runtime that failed during collection.
A rejected envelope likewise retains the already-decided facts (issue #3687).
"""
from ..control_plane.effect_program import reject_retired_quota_format

reject_retired_quota_format(payload)
if payload.get("ok") is False and not isinstance(payload.get("interaction_contract"), Mapping):
if (not bool(getattr(args, "turn_envelope", False))
and getattr(args, "quota_command", None) == "monitor-poll"
and isinstance(payload.get("before"), Mapping)):
# A refused poll still has its decided before snapshot. Its
# existing compaction is pure and does not reenter the runtime.
return compact_quota_monitor_poll_cli_payload(
payload, include_decision_detail="decisions" in detail_sections,
)
# A collection failure has no decided contract and must not reenter
# its unavailable runtime. Decided refusals still need signed views.
# Keep the decided diagnostic, including its original recovery/receipt.
if bool(getattr(args, "turn_envelope", False)):
return {**payload, "turn_envelope_skipped": "quota request failed; original diagnostic retained"}
return payload
if not bool(getattr(args, "turn_envelope", False)):
if args.quota_command in {"status", "plan"}:
return compact_quota_plan_cli_payload(payload, detail_sections=detail_sections)
if args.quota_command == "should-run":
if captured_decision_path and "vision" not in detail_sections:
from ..control_plane.quota.turn_envelope import _turn_envelope_result
payload = _turn_envelope_result("replan_cli_view", payload=payload)
return compact_quota_should_run_cli_payload(
payload,
include_todo_summary_detail="agent-todos" in detail_sections,
include_user_todo_summary_detail="user-todos" in detail_sections,
include_goal_boundary_detail="goal-boundary" in detail_sections,
include_vision_detail="vision" in detail_sections,
)
if args.quota_command == "monitor-poll":
return compact_quota_monitor_poll_cli_payload(
payload, include_decision_detail="decisions" in detail_sections,
)
return payload
try:
return build_turn_envelope(
payload,
scheduler_execution_context=scheduler_context,
captured_decision_path=captured_decision_path,
)
except EffectRuntimeRejected as envelope_error:
degraded = dict(payload)
degraded["turn_envelope_skipped"] = str(envelope_error)[:200]
return degraded
Loading
Loading