Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ request-scope adoption separately rather than counting its gain again.

### Product conversations and asynchronous inbox

**Chat HTTP POST scope.** `ChatRequestHandler.do_POST` now joins the existing
executable-revision request scope for each complete HTTP dispatch. Session
creation/resume and other POST routes reuse one code revision across their typed
calls; the next request resolves current code again. Session, workspace grant,
provider and authority observations remain live. Background Turn workers retain
their own scope. This adds no bridge operation, semantic owner or state cache.
Real HTTP and runtime regressions qualify source admission and revoked-grant
refusal separately from installed behavior and real-model response latency.

**Public quota read scope.** `quota/should_run.py` now reuses the existing
executable-revision request scope for each complete public quota read. The
compatibility facade and global views share that lifetime instead of resolving
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ guard、格式和 typed owner。这不新增领域规则、桥接操作或数据

### 产品对话与通用异步 inbox

**Chat HTTP POST 作用域。** `ChatRequestHandler.do_POST` 现在为每次完整 HTTP
分发复用既有 executable-revision 请求作用域。Session 创建/恢复及其他 POST
路由的 typed 调用共用一个代码版本;下一次请求重新解析当前代码。Session、工作区
授权、provider 与 authority 仍实时读取。后台 Turn worker 保留自己的作用域。
这不新增桥接操作、语义 owner 或状态缓存。真实 HTTP 与 runtime 回归分别验证
源码准入和撤销授权后的拒绝;安装后行为与真实模型响应延迟仍需独立验证。

**公共 quota 读取作用域。** `quota/should_run.py` 现在为每次完整公共 quota 读取
复用既有 executable-revision 请求作用域。兼容 facade 和全局视图共用该生命周期,
不再在每次 typed 判定前重新解析代码树。已有外层作用域仍可组合;下一次独立读取
Expand Down
2 changes: 2 additions & 0 deletions loopx/chat_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
project_chat_session_snapshot,
)
from .control_plane.goals.active_state_metadata import active_state_section_text
from .control_plane.effect_runtime import effect_runtime_request_scope
from .control_plane.coordination.local_authority import LocalCoordinationAuthorityUnavailable
from .control_plane.status.ssh_host_catalog import (
SSH_HOST_CATALOG_PATH,
Expand Down Expand Up @@ -1649,6 +1650,7 @@ def do_GET(self) -> None:
return self._serve_asset(path)
self._send_error("unknown path", status=404)

@effect_runtime_request_scope()
def do_POST(self) -> None:
if not self._require_loopback_origin():
return
Expand Down
61 changes: 61 additions & 0 deletions tests/test_chat_http_runtime_scope.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""HTTP admission reuses code identity while grants and source reads stay fresh."""

import os
from pathlib import Path

import pytest

from test_chat_ordinary_project import ordinary # noqa: F401
from test_lark_private_conversations import connect
from loopx.control_plane import effect_runtime


@pytest.mark.parametrize("method", ["GET", "POST"])
def test_http_reuses_code_scan_but_rereads_revoked_grants(ordinary, monkeypatch, method): # noqa: F811
store, runtime, provider, transport = connect(ordinary)
_, _, contexts, request, capture, _, workspace = ordinary
binding = transport._binding("notes-app")
session, _ = runtime.open_session(
goal_id=None, agent_id="codex", work_dir=workspace, objective="",
mode="resume_latest", conversation_binding_id=binding["binding_id"],
source_context={"source_ref": "a" * 24, "sender_ref": binding["operator_ref"],
"private_human_message": True},
)
path = "/api/chat/sessions"
body = None
if method == "GET":
path += "?conversation_binding_id=" + binding["binding_id"]
else:
body = {"context_kind": "project", "project_ref": contexts.available()[0]["project_ref"]}
# Warm the real source hash before counting filesystem traversals.
assert request(path, body)[0] in {200, 201}
source_root = Path(effect_runtime.__file__).parent
walk = os.walk
scans = []

def counted_walk(root, *args, **kwargs):
if Path(root) == source_root:
scans.append(root)
return walk(root, *args, **kwargs)

monkeypatch.setattr(os, "walk", counted_walk)
try:
for _ in range(2):
scans.clear()
status, payload = request(path, body)
assert status == 200, payload
if method == "GET":
assert [row["session_id"] for row in payload["sessions"]] == [session["session_id"]]
else:
assert payload["resumed"] is True
assert payload["session"]["project_ref"] == body["project_ref"]
# A new HTTP request scans again; its typed calls share that scan.
assert len(scans) == 1
before = store.list_sessions()
contexts.roots = []
status, _ = request(path, body)
assert status == (409 if method == "GET" else 400)
assert store.list_sessions() == before
assert '"method": "turn/start"' not in capture.read_text()
finally:
runtime.close()
Loading