Repository navigation
refactor(work-items): compose whole-Goal task maps in TypeScript - #6602
loopx-agent merged 7 commits into
Conversation
Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>
Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>
Author validation — exact head
|
| Backend / display | Exit base/head | Fixture SHA-256 | Normalized full HTTP SHA-256 |
|---|---|---|---|
| file / current | 0 / 0 | 2ba8aa5c097234dfc163b6c8bed54b3c56a6831756714ff855c7030db169820f |
9eaa7b8ef57c41513e0972f787cfa4f83827a73772989e573b0110f85b3410e7 |
| file / missing | 0 / 0 | fff75ac388ccbae7e12ed676d977c4e8264473a49b47c9a8232db6390101fe8a |
a6159f39e7904e342d75c7b6e4681304ac620e34abaf0118e462096b78150293 |
| sqlite / current | 0 / 0 | 150949190d5323cb3c6f1cb8f73c55b1511d89849a53640637b2c738d7e2d497 |
c4f2ab484859169e7f4c4e294099d9052233b573d8c029e611edc1c97d6f2f98 |
| sqlite / missing | 0 / 0 | a32b13d9ee89d0cf4222993deaafbc372d9e53a8ecbb93d91d8a533d16dd9a5e |
a090c9b8d51155b99cff13bcf5f1bf1b4bedb844ebd38592e2879368a47d0d5d |
Each arm: 64 pairs; one map request per HTTP on both revisions; 36 total runtime requests per HTTP on both; restart parity and unchanged logical canonical Todos/provider revision, registry and available Markdown bytes. Source, ordinary installed wheel and installed sdist also passed the same four-arm full-object comparison at samples=0; all six changed production files match source/archive/install bytes. The deliberate physical TS mutation gate ? "gate" → gate ? "deliverable" in a copy of this exact candidate failed the same HTTP harness: exit 1, AssertionError: file-current. Unmodified baseline/head exit 0. Environment startup failures were not counted as mutation sensitivity.
Migration economics (same final merge-base classification)
| Field | Final merge-base receipt |
|---|---|
| Canonical owner | Before: TS owned Goal topology; Python owned map kind, metadata visibility and map assembly. After: projectGoalTaskMap composes those rules with the existing topology owner in-process. Python has no map-policy fallback. Shared source/text/state/SHA identity codecs remain single Python owners. |
| Legacy semantic code deleted | task_graph.py: 66 gross deleted product lines, including adapter reshaping/moves; this is not 66 retired rule LOC. The removed rule/header blocks total 20 lines: 2 schema/cap constants, gate classification (1), identity-prefix choice (1), kind selection (3), metadata visibility (2), edge descriptors (3), public map return/header (8). Shared codec implementations are not counted as retired. |
| Bridge code added | Conservative gross classification: 65 added product lines: 49 Python adapter lines in build_goal_task_map and imports, 13 native wire/identity descriptor lines (request/result tags, request validation, index and compatibility descriptors), 2 snapshot allowlist entries, 1 existing dispatcher replacement. This retains one compatibility adapter; it adds no effect name, daemon or per-field RPC. |
| Cross-runtime calls | Actual GET /api/chat/delivery-review?goal_id=release-demo: map composition 1→1; 36→36 total runtime requests per HTTP in all four fixture arms. Empty/repeated/restarted map reads still use one composer request. Restart/readback parity passes; no write/replay transaction is introduced. |
| Product-code net change | Six production files: +100/−68 = +32 lines. Validation separately: +353/−1 = +352. Docs separately: +24/−5 = +19. No generated file/dependency change. The temporary net increase is disclosed; policy deletion, not total LOC, is the payoff. |
| Migration scaffolding | No product dual-run or retained Python oracle. Three test files pin durable public semantics. Disposable baseline, distribution and mutation harnesses are outside product code; the public replay recipe below is evidence, not a runtime dependency. |
| Facade exit | build_goal_task_map remains for Chat delivery-review's source/renderability, public-safe text, shared _task_graph_todo_state and _task_graph_node_id. Delete it with the remaining build_task_graph_projection/shared Todo-source consumers once their exact text/state/stable-ID contracts have one native owner. Do not duplicate those codecs in this increment. |
| Correctness and performance | Full real HTTP parity against immutable baseline, File/SQLite × present/missing Markdown, repeated reads, managed-runtime restart, unchanged canonical Todos/revision and source bytes; same harness rejects a physical gate→deliverable native mutation. Normal wheel/sdist and installed files match all six product sources. Matched HTTP and cold/warm/memory measurements below. |
Performance receipt
| Backend / display | Baseline p50 / p95 ms | Candidate p50 / p95 ms |
|---|---|---|
| file / current | 188.317 / 219.908 | 66.660 / 91.262 |
| file / missing | 189.681 / 211.080 | 67.189 / 80.468 |
| sqlite / current | 213.423 / 268.769 | 88.232 / 111.476 |
| sqlite / missing | 209.084 / 247.175 | 86.764 / 106.523 |
Warm typed p50/p95 0.477/0.998 ms (200); complete map 0.631/1.165 ms; cold complete adapter 262.477/352.485 ms (12 starts). Daemon RSS 102.10→103.66 MiB after 200 requests. Full HTTP improvement includes one existing request-scoped code fingerprint; all provider requests remain. No full-CLI claim for this HTTP-only consumer. No budget was raised.
Final checks / scope
206 targeted Python tests; 23 native topology/snapshot tests; full control-plane typecheck; full semantic vocabulary smoke; Ruff/diff checks; normal wheel/sdist; frontend build and raw-response parser; independent clean-code/test/docs guards passed. No entire repository suite, Windows/macOS, PostgreSQL, real-model journey or merged-main combination qualification. GitHub CI is queued/in progress at posting; it is not included in these local results. Coverage is sufficient for this read-only map increment; it does not complete graph/source retirement, provider promotion or the parent migration. No new mutation authority or default.
Bounded public-safe source replay recipe
Prerequisites: Git, uv, CPython 3.13 and Node.js 22.22.3 on PATH. From the repository, create disposable checkouts. Save the two code blocks below as http_receiver.py and qualify.py in the generated replay directory. They use synthetic state only.
replay_root=$(mktemp -d)
export LOOPX_GOAL_MAP_REPLAY="$replay_root"
git worktree add --detach "$replay_root/base" e11e859e8bc70bb8292b90c7523f05f8f604c16e
git worktree add --detach "$replay_root/head" 0441f5e600d8934a4e59d8a1b21a422510bade54
uv sync --project "$replay_root/head" --extra testGenerate the process descriptors after saving the scripts:
import json, os
from pathlib import Path
root = Path(os.environ["LOOPX_GOAL_MAP_REPLAY"])
python = str(root / "head/.venv/bin/python")
variants = {label: {"python": python, "pythonpath": str(root / label),
"expected": str(root / label / "loopx")}
for label in ("base", "head")}
(root / "source-variants.json").write_text(json.dumps(variants))cd "$replay_root/head"
uv run --extra test python "$replay_root/qualify.py" "$replay_root/head" "$replay_root" "$replay_root/source-variants.json" 64
uv run --extra test python -c 'from loopx.control_plane.effect_runtime import restart_effect_runtime; restart_effect_runtime(wait_for_exit=True)'Receiver (http_receiver.py):
"""Disposable real API receiver with observation at the existing runtime boundary."""
from collections import Counter
import json
import os
from pathlib import Path
import sys
import threading
import time
import loopx
from loopx.chat_server import ChatHTTPServer, ChatRequestHandler
from loopx import chat_status_api
from loopx.control_plane import effect_runtime
registry, runtime, expected = map(Path, sys.argv[1:4])
assert Path(loopx.__file__).resolve().is_relative_to(expected.resolve()), loopx.__file__
counts = Counter()
native_ms, projection_ms, sizes = [], [], []
actual_request = effect_runtime.effect_runtime_request
actual_map = chat_status_api.build_goal_task_map
def observed_request(method, params, **kwargs):
counts[method] += 1
started = time.perf_counter()
result = actual_request(method, params, **kwargs)
if method == "work_item.task_graph.goal_topology":
native_ms.append((time.perf_counter() - started) * 1000)
sizes.append(len(json.dumps(params, separators=(",", ":")).encode()))
return result
def observed_map(**kwargs):
started = time.perf_counter()
result = actual_map(**kwargs)
projection_ms.append((time.perf_counter() - started) * 1000)
return result
effect_runtime.effect_runtime_request = observed_request
chat_status_api.build_goal_task_map = observed_map
server = ChatHTTPServer(("127.0.0.1", 0), ChatRequestHandler)
server.registry_path = registry
server.runtime_root_override = str(runtime)
server.runtime_root = runtime
server.scan_roots = []
server.limit = 20
server.selected_goal_id = None
server.verbose = False
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
print(json.dumps({"port": server.server_address[1], "module": loopx.__file__}), flush=True)
try:
for command in sys.stdin:
operation = command.strip()
if operation == "stop":
break
if operation == "reset":
counts.clear(); native_ms.clear(); projection_ms.clear(); sizes.clear()
print("{}", flush=True)
elif operation == "stats":
print(json.dumps({"counts": counts, "native_ms": native_ms,
"projection_ms": projection_ms, "request_bytes": sizes}), flush=True)
elif operation == "restart":
print(json.dumps(effect_runtime.restart_effect_runtime(wait_for_exit=True)), flush=True)
else:
raise ValueError("unsupported qualification control")
finally:
server.shutdown()
thread.join(timeout=5)
server.server_close()
effect_runtime.restart_effect_runtime(wait_for_exit=True)Driver (qualify.py):
"""Disposable baseline/source/distribution HTTP qualification; keep raw output local."""
import hashlib
import http.client
import importlib.util
import json
import os
from pathlib import Path
import select
import statistics
import subprocess
import sys
import time
source, output = map(Path, sys.argv[1:3])
sys.path.insert(0, str(source))
variants = json.loads(Path(sys.argv[3]).read_text())
samples = int(sys.argv[4])
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
loaded = importlib.util.module_from_spec(spec)
spec.loader.exec_module(loaded)
return loaded
fixture_api = module("goal_map_fixture", source / "tests/test_delivery_review.py")
canonical = module("goal_map_canonical", source / "tests/control_plane/canonical_authority_fixture.py")
from loopx.control_plane.todos.active_state_todo_parser import parse_todo_source
from loopx.control_plane.todos.todo_summary import canonical_todo_read_record, structured_todo_item
from loopx.control_plane.coordination.runtime_shadow import build_todo_runtime_shadow_projection
from loopx.control_plane.coordination.local_authority import read_canonical_todos_if_promoted
class Receiver:
def __init__(self, name, variant, registry, runtime):
temp = output / "receiver-runtime" / name
temp.mkdir(parents=True, exist_ok=True)
self.log = (output / (name + ".stderr")).open("w")
env = {**os.environ, "PYTHONPATH": variant.get("pythonpath", ""), "TMPDIR": str(temp),
"LOOPX_USAGE_PING": "0", "NODE_OPTIONS": "--experimental-sqlite"}
self.process = subprocess.Popen([variant["python"], str(output / "http_receiver.py"),
str(registry), str(runtime), variant["expected"]], cwd=output, env=env,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=self.log, text=True, bufsize=1)
self.port = self.receive()["port"]
def receive(self):
assert select.select([self.process.stdout], [], [], 90)[0], "receiver timed out"
line = self.process.stdout.readline()
assert line, "receiver exited before its response"
return json.loads(line)
def control(self, command):
self.process.stdin.write(command + "\n"); self.process.stdin.flush()
return self.receive()
def get(self):
started = time.perf_counter()
connection = http.client.HTTPConnection("127.0.0.1", self.port, timeout=90)
connection.request("GET", "/api/chat/delivery-review?goal_id=release-demo")
response = connection.getresponse()
payload = json.loads(response.read())
connection.close()
elapsed = (time.perf_counter() - started) * 1000
assert response.status == 200, (response.status, payload)
return payload, elapsed
def close(self):
self.process.stdin.write("stop\n"); self.process.stdin.flush()
assert self.process.wait(timeout=30) == 0
self.log.close()
def summary(values):
if not values: return None
return {"p50_ms": round(statistics.median(values), 3),
"p95_ms": round(sorted(values)[min(len(values)-1, int(len(values)*.95))], 3)}
records = []
for provider in ("file", "sqlite"):
for display in ("current", "missing"):
name = provider + "-" + display
directory = output / name
if not directory.exists():
registry, runtime = fixture_api.make_project(directory)
state = registry.parent / "ACTIVE_GOAL_STATE.md"
groups, _, _ = parse_todo_source(state.read_text())
todos = [canonical_todo_read_record(structured_todo_item(row, role=role,
source_section=row.get("source_section"))) for role, rows in groups.items() for row in rows]
canonical.initialize_canonical_authority(runtime, "release-demo",
build_todo_runtime_shadow_projection(goal_id="release-demo", todos=todos),
state_path=state, provider=provider)
if display == "missing": state.unlink()
registry, runtime = directory / "project/registry.json", directory / "runtime"
state = registry.parent / "ACTIVE_GOAL_STATE.md"
before = (registry.read_bytes(), state.read_bytes() if state.exists() else None,
read_canonical_todos_if_promoted(runtime_root=runtime, goal_id="release-demo"))
receivers = {}
try:
packets = {}
for label, variant in variants.items():
receiver = Receiver(name + "-" + label, variant, registry, runtime)
receivers[label] = receiver
packet, _ = receiver.get()
(output / f"{name}-{label}-raw.json").write_text(json.dumps(packet, indent=2))
# This field is this HTTP observation's clock, never a persisted source timestamp.
packet.pop("observed_at")
packets[label] = packet
(output / f"{name}-{label}-packet.json").write_text(json.dumps(packet, indent=2))
expected = next(iter(packets.values()))
assert all(packet == expected for packet in packets.values()), name
by_todo = {node["refs"]["todo_ids"][0]: node for node in expected["goal_map"]["nodes"]}
assert len(by_todo) == 5 and by_todo["todo_review"]["kind"] == "gate"
assert "owner_agent" not in by_todo["todo_review"]
assert by_todo["todo_design"]["state"] == "done" and by_todo["todo_integrate"]["depth"] == 1
assert len(expected["goal_map"]["edges"]) == 2 and expected["goal_map"]["limits"]["topology_complete"]
durations = {label: [] for label in receivers}
for receiver in receivers.values(): receiver.control("reset")
for iteration in range(samples):
order = list(receivers) if iteration % 2 == 0 else list(reversed(receivers))
for label in order:
packet, elapsed = receivers[label].get()
packet.pop("observed_at")
assert packet == expected, (name, label)
durations[label].append(elapsed)
stats = {label: receiver.control("stats") for label, receiver in receivers.items()}
if samples:
for report in stats.values():
assert report["counts"]["work_item.task_graph.goal_topology"] == samples
assert len(report["projection_ms"]) == len(report["native_ms"]) == samples
for label, receiver in receivers.items():
receiver.control("restart")
packet, _ = receiver.get(); packet.pop("observed_at")
assert packet == expected, (name, label, "restart")
after = (registry.read_bytes(), state.read_bytes() if state.exists() else None,
read_canonical_todos_if_promoted(runtime_root=runtime, goal_id="release-demo"))
assert after == before, name
records.append({"provider": provider, "display": display, "full_http_parity": True,
"normalization": ["observed_at"], "restart_parity": True, "provider_unchanged": True,
"observation_sha256": hashlib.sha256(json.dumps(expected,sort_keys=True).encode()).hexdigest(),
"fixture_sha256": hashlib.sha256(json.dumps(before[2],sort_keys=True).encode()).hexdigest(),
"samples": samples, "http_ms": {k: summary(v) for k,v in durations.items()},
"native_ms": {k: summary(v["native_ms"]) for k,v in stats.items()},
"projection_ms": {k: summary(v["projection_ms"]) for k,v in stats.items()},
"stats": stats, "http_samples": durations})
(output / "http-receipts.json").write_text(json.dumps(records,indent=2))
finally:
for receiver in receivers.values(): receiver.close()
print(json.dumps(records, indent=2))For the durable literal contract independently of the parity oracle, run the candidate's tests/test_delivery_review.py::test_canonical_http_goal_map_survives_repeated_reads_and_runtime_restart on both checkouts using the same candidate test file. To repeat mutation sensitivity, create a third disposable baseline checkout, copy only the candidate's six production files into it, change the single gate ? "gate" branch to gate ? "deliverable", and point a mutant receiver at that checkout; expected failure is the full HTTP mismatch above. Retain separate TMPDIRs as the receiver does; remove only the disposable worktrees created for this replay.
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max
请求修改:[P2] 本次 TypeScript 读模型迁移缺少 Accepted RFC 要求的 projection envelope。
动机
查看一个 Goal 全部任务及依赖关系的用户,需要在同一个只读入口得到稳定、可解释的任务地图。
原来 TypeScript 算拓扑、Python 再决定节点类型和地图结构;本提案把组装合到现有 TypeScript owner,重复读取和重启仍应得到同一张地图。
File/SQLite、存在或缺失 Markdown 的真实 HTTP 对比保持完整输出一致,源码和两种正常安装也一致;新读模型仍未携带规范要求的新鲜度与覆盖封套。
本次不认证 provider 晋升、完整控制面迁移、真实模型采用、其它平台或长期运行收益。
先补本次迁移的 projection_envelope;共用文本、状态和稳定 ID codec 的最终退役仍由原 selected-work graph/source 消费者迁移承担。
改动思路
沿用现有 work_items 拓扑 owner 和私有快照传输,保留仍被选中任务图使用的共用 codec,有明确收益;新增封套应复用既有 projection_envelope.ts,避免另建新鲜度规则。 当前 PR 是一个完整只读地图组装切片;必须在同一切片接上既有封套 owner 和实际消费者,不能用旧输出字节相同替代 Accepted RFC 的迁移晋升门。
正常链路是 HTTP delivery-review 读取原 canonical Todo 来源,Python 仅准备经过公共安全处理的事实,既有 TS 拓扑 owner 组合节点类型、元数据可见性、边和地图头,再由共用 codec 生成原稳定身份与显示文本。新的 request scope 固定的是一次 HTTP 的代码版本,provider、来源和权限检查仍实际执行,不能把它解释成数据缓存。元数据只在节点准入后读取;超出普通帧的完整输入走既有私有、摘要绑定的快照通道。
具体改动
head 0441f5e600d8934a4e59d8a1b21a422510bade54,实际 merge base e11e859e8bc70bb8292b90c7523f05f8f604c16e。spec_ref: docs/architecture/rfcs/typescript-control-plane-migration-v0.md;spec_revision: e11e859e8bc70bb8292b90c7523f05f8f604c16e。独立规范为该 Accepted RFC和既有任务图协议。本 PR 对 RFC 实施事实的编辑没有改变 §2.6/§6 晋升条款;fetched main 也保留它们。
| 原规范条款 | 当前判定 |
|---|---|
| Canonical owner | implemented:地图组装规则交给既有 TS owner,Python 不保留地图规则 fallback。 |
| Cross-runtime calls | implemented:四组各64对真实 HTTP,地图调用1→1,全部 runtime 请求36→36,重启读回一致。 |
| Facade exit | implemented:保留实际仍被 selected-work graph 使用的文本、状态、SHA 身份 codec;随其余消费者迁移退役。 |
| Caller-observable semantic parity | implemented:完整对象、实际 backend、正常安装及物理语义 mutation 已核。 |
| §2.6 | not_met:新 TS 读模型及外层 HTTP 都未携带 projection_envelope。 |
| §6 | not_met:打包通过,producer 尚无封套可验证 stale/unreadable/incomplete/replay 四种必需状态。 |
关键代码讲解
- build_goal_task_map 删除地图策略,保留共享来源/身份适配;第一条可展示重复记录仍优先,丢弃或未准入记录的 opaque 元数据不被求值,真实大输入测试保留120节点上限与11880省略计数。
- projectGoalTaskMap 复用已解码的拓扑、现有 relation catalog 与120节点公开上限,决定 gate/monitor/deliverable、可见字段及边;原公开 ID 与 schema 保持。当前返回处遗漏封套。
- _delivery_review 复用已有代码版本 request scope;两端 snapshot allowlist 同步扩展,未增加 daemon、每字段 RPC 或写入权威。
全提案12路径 +477/-74:产品六文件净+32、测试三文件净+352、文档三文件净+19。已核删除的是地图策略,不把所有搬动行都计作退役收益。仍有实际共用 codec 消费者,整体复制到 TS 反而产生第二份规则;这个有界保留是合理的。
对主干的风险
[P2] 新读模型需要通过已接受的封套晋升门。 真实 GET /api/chat/delivery-review?goal_id=release-demo 在 File/SQLite、显示文件存在/缺失、源码/wheel/sdist 都返回200;外层只有 ok/goal_id/observed_at/graph/goal_map/acceptance,地图内也没有 projection_envelope。实际前端 schema 和时间展示只读组装时的 observed_at。它不能代替来源读取时间、覆盖遗漏、继承最旧来源和 replay 的区分。复用既有 projection.envelope.seal,传递真实来源读取与覆盖事实并接到实际消费者;补 stale、unreadable、incomplete scope、replay 四种 producer 用例。
这是当前迁移资格缺口。基线也没有封套,已明确作为 legacy rollout 事实保留,没有把这个既存字段缺失称为新 runtime 回归;但 Accepted RFC 明确要求新迁移读模型在同一 PR 接入该 owner。仅保住旧字节不满足这条新增迁移时必须履行的条件。
独立验证:206 Python、23 TS、全 control-plane typecheck、Ruff、完整语义 smoke、前端生产构建及现有 delivery-review smoke 通过。六个产品文件在源码、正常 wheel/sdist 及两份全新安装中逐字节一致;16份真实 HTTP 响应通过实际前端 parser,错 Goal 被拒绝。四组各64对完整对象比较仅去掉 root observed_at;canonical Todos/revision、registry、显示文件保持,重启读回一致。安装副本的 gate→deliverable 物理 mutation 使同一真实 HTTP 比较明确失败,非启动失败冒充敏感性。
本机配对 p95(base→head,ms):File/current252.783→119.139,File/missing398.870→206.185,SQLite/current221.508→121.608,SQLite/missing243.671→156.303。12次冷完整适配器 p50/p95=137.772/211.681ms;200次单代码作用域 warm map p95=.550ms;RSS82.547→85.016MiB。HTTP 与微测边界分开,收益包含 fingerprint scope,不归因于 TS 搬动本身;不推导其它宿主或持续性能。
语义与 CI 对齐
复用既有公共地图/关系词汇,仅在现有 owner 内新增私有 request/result 标签;snapshot 方法名单两端同步扩展。advisory 只发现该名单扩展,其支持语法有界;full semantic smoke 通过不能证明封套义务已履行。原生 premerge 的5 direct+18 selected可执行检查通过,整体仍因本地 quality_receipt_missing 为失败状态;没有生成凭据、豁免或弱化预算。未查询或等待 CI。现有 merge conflicts 及最新 main 组合资格仍独立保留。
我的整体评价
REQUEST_CHANGES。long_horizon=preserved、user_experience=preserved 限于已实测的只读重复/重启和现有入口,零新增必要交互轮次;它们不认证长期模型使用或整个迁移完成。这个切片能集中地图策略,桥接增量有明确边界,共用 codec 暂留合理,未来改动检查已落在同一 owner 的合并 seam;当前需要完成现有封套接入。当前 PR 是一个完整只读地图组装切片;必须在同一切片接上既有封套 owner 和实际消费者,不能用旧输出字节相同替代 Accepted RFC 的迁移晋升门。
重新评审应在新精确 head 复核完整提案、来源封套四态、真实 HTTP/正常安装及原语义反例;不要求本 PR 完成无关的 parent roadmap,也不把本地 CQR/冲突 hold 代替本次具体发现。
English verdict: REQUEST_CHANGES - 0441f5e; real source/wheel/sdist HTTP parity and local costs pass, but the migrated user-facing Goal map lacks the projection envelope required by the accepted RFC §2.6/§6. Complete the existing owner/consumer integration and four producer-state regressions.
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> # Conflicts: # loopx/control_plane/effect_runtime.py # loopx/control_plane/effect_runtime_server.ts
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
动机
查看一个 Goal 的全部工作、关系及交付依据的用户和 Agent。
原来 TS 只给拓扑,Python 再组地图;迁移后的地图与 HTTP 又缺少来源封套,组装时间无法说明来源是否仍新鲜。
同一个既有页面返回稳定原任务/边及当前来源范围,过期或不可读可见、可原位刷新,导出保留原始读取时间。
不改变任务执行、claim/lease、provider 默认或验收授权;不认证完整 Agent 迁移、整个 T3 或生产采用。
其他 selected-work graph/source 消费者与用户 Agent 迁移继续由既有路线验收;本次地图切片没有新增后续任务前提。
本轮在 hhyykk 原分支补齐缺口并复核完整提案;此评审包含维护者补丁的自审,不冒称另一名独立 reviewer。
改动思路
地图规则和来源判定复用既有 TS owner,Python 保留仍有调用者的 IO 与共享 codec;外层只增加一次整批封装调用。
本次收敛既有 Goal 地图组装及来源读回,完整 Agent 迁移仍由原产品路径验收。
正常路径:Goal 概览/交付依据 → 原 canonical Todo/status 读取 → 原 TS topology/map owner → 既有 envelope owner → 已交付前端与导出。代码版本 request scope 只固定一次 HTTP 的可执行代码身份,provider 和来源仍实时读取。共享文本、状态和稳定 ID codec 仍有 selected-work graph 调用者,暂留一个 owner,并非复制一份新规则。
来源不可读时保留其他组件与原任务,地图为 null 并告警;旧来源时间不被组装或重放刷新。原刷新入口能恢复读取,不增加配置、确认或执行授权。
具体改动
精确 head:8d8f3c004f4ee9570ca218e0d3942aca5d6e2852。spec_ref=docs/architecture/rfcs/typescript-control-plane-migration-v0.md;spec_revision=83faa5bd9f7667ae104943feacdc1536a3d57f74。依据是改动前 Accepted RFC与原图协议、封套契约。候选 checkpoint 不反过来定义验收。
| 原条款 | 当前判断 |
|---|---|
| T3 | implemented:地图 kind、元数据可见性、边及形状归原 TS owner;重复 Python 地图策略退役 |
| §2.6 | implemented:地图原位 seal;外层继承 status/map 来源;前端与导出消费实际封套 |
| §5 | implemented:保留 codec 的实际消费者/退出条件、删除及桥接代价明确 |
| §6 | implemented:完整原字段对照、真实 backend/HTTP、正常分发包、四态反例与实际入口成本已执行 |
关键代码:
build_goal_task_map保留真实共享来源/身份适配,重复或未准入的 opaque 元数据不求值;仅向 native 传事实,普通帧之外仍走原私有快照,完整来源不截断。projectGoalTaskMap复用原关系与120节点准入,并用已有 seal owner 处理读取时间、未知分母、无法展示/上限/缺失关系;没有第二套新鲜度或生命周期决定。_delivery_review保留 origin、Goal 和 registry drift 边界;root 的 declared coverage 是三个交付组件及其上游范围,图内 limits 继续独立披露。fresh/complete 都不是跨来源原子快照或整 Goal 验收。- 实际前端 校验身份、披露 native flags,保留旧响应“未知”状态与原来源打开权限;真实下载包含两层封套和原读取时间。
完整提案23路径:产品9文件 +202/−79,测试/fixture7文件 +499/−9,文档/视觉7文件 +54/−5(另含三张合成截图)。没有新生产模块、依赖、配置、持久化状态或服务。当前 main 组合冲突保留两边的 snapshot 方法,最终 diff 不夹带无关 main 工作,7个贡献/merge 提交均有 DCO。
对主干的风险
原阻塞已有实际反例:整合原提案 9a41c713a330fbd65e85d2fb001fbdf5ba415bcd 成功返回 HTTP200 后,在独立“必须有封套”断言报 KeyError;同一断言在当前头通过。旧评审的正常包和微测只作为历史,以下为当前头重新执行的结果。
File/SQLite × 展示文件存在/缺失 × baseline/source/正常 wheel/正常 sdist,共 1056 次完整 HTTP 观察,每 receiver64个交替计时样本并含首次/重启读回。完整原 JSON 相等;只把既有 root observed_at 和有意新增的两层封套单列检查,没有删除领域字段、身份或拒绝细节。canonical Todo/revision、registry 和展示文件保持。六个产品运行文件及37个编译 UI 文件在源码、归档和新安装中逐字节一致。
| 完整 HTTP p95,ms | Python baseline | 当前 source | 正常 wheel | 正常 sdist |
|---|---|---|---|---|
| File / present | 165.602 | 91.299 | 101.824 | 91.325 |
| File / missing | 172.778 | 102.341 | 94.901 | 91.470 |
| SQLite / present | 158.397 | 90.284 | 90.475 | 81.120 |
| SQLite / missing | 206.022 | 103.404 | 107.023 | 104.910 |
地图仍1次请求;完整 HTTP 36→37,新增的是一次明确的整批外层 seal。收益含代码版本作用域,不归因于语言搬动本身。source native map p95为0.509–0.684ms;不把微测当成完整入口证明,也没有改动原5%/25ms要求。baseline固定 83faa5bd9f7667ae104943feacdc1536a3d57f74;它与组合 main 90932447eb5ed38a0d3fec8c57e21a62f57f849c 的相关 map/status/runtime 路径无改动,比较不借无关 main 历史改变基线。
当前51个 Python、30个 native、前端 data/export/identity smoke、两端完整 typecheck、正常 bundle/分发包、双语 RFC 及公共边界检查通过。原生 premerge 6 direct +19 selected 通过,零 hold;CQR 当前精确 scope 通过。先前 stale-CQR 的整体失败记录保留,后续执行已在同一未改源码头闭合该门。
实际打包页面使用隔离合成 File authority:正常地图读取、明确的 IO 故障注入、原位键盘刷新恢复、390px 无横向溢出、过期警告及真实 Markdown 下载均完成。故障与旧时钟是 fixture hook,不是生产故障或模型验收;未运行真实模型或升级用户 App。正常桌面、不可读/重试、手机过期来源为本实现的合成视图;普通入口不增加必要交互轮次。
语义与 CI 对齐
完整 PR advisory 识别到既有 LOCAL_SNAPSHOT_METHODS 的一个方法扩展,Python/TS 两端一致,复用原传输 owner;两层载体/范围与局部 omission reason 已记录在原协议中。full semantic 通过,原59处未证明 producer 仍保留,advisory 不是语义等价证明。无文本黑名单、benchmark 特定核心义务、新激活开关或静默 provider/default 改动。
warning 是来源披露,不是新的 must_attempt_work、额度或执行权限。普通 status 仍不触发冷地图读取,实际原 origin/Goal/身份/registry drift 拒绝保留。依 no-CI 策略未查询、等待或触发 hosted CI。Windows、PostgreSQL、实时模型、已安装 App 采用、长期 fleet 和全局冷启动/RSS 新资格未测;本次不改 PostgreSQL store/事务,不能外推这些结果。
我的整体评价
APPROVE 当前精确头。 原地图与封套缺口已补齐,原身份、角色、关系、共享 codec、只读边界及正常安装行为有实际证据;HTTP 多一次 seal 的代价已披露且完整入口成本通过。
long_horizon=preserved 限于可重复/重启找回同一原任务;user_experience=improved 限于实际来源告警、导出和原位恢复。有限未来改动检查已经应用在一个 TS 地图 owner、共享 codec 不复制和现有 showcase fixture 的小 helper 上;这不是完整 Agent 迁移或整 RFC 完成。批准与合并授权/readiness仍分开,按当前同一 head 执行最后检查。
English verdict: APPROVE - 8d8f3c0. The original native map proposal now includes the accepted source envelopes and actual UI/export/recovery consumers. Real File/SQLite source and normal wheel/sdist HTTP parity, all four paired cost arms, current risk-based premerge and exact-scope quality pass. One extra coarse seal crossing is disclosed; authority and original task identity remain unchanged. This includes self-review of maintainer repairs and does not certify broader Agent migration or production adoption.
Goal And Delivered Outcome
The whole-Goal work map split composition between native topology and Python map policy. This change moves map kind, metadata visibility, edge and header composition into the existing TypeScript owner, preserves the shared codecs that still have selected-work consumers, and completes the required source-envelope integration through the actual frontend and export.
Before: a successful delivery read exposed only its assembly time; the map and outer response lacked source freshness/coverage. After: the same readonly entry carries the existing kernel envelopes, discloses old/unreadable/partial or unknown sources, and offers same-context refresh. Existing task identities, relationships and authorization remain unchanged.
Related: #3225. Intended base:
main. This completes the bounded map/read-consumer increment, not the whole migration RFC or Agent transfer.Author Declaration
model_agent— OpenAI Codex, GPT-6 family. Maintainer repairs:model_agent— OpenAI GPT-6.1-sol, runtime-reported.docs/architecture/rfcs/typescript-control-plane-migration-v0.mdat83faa5bd9f7667ae104943feacdc1536a3d57f74, plus the existing graph and projection-envelope contracts.projectGoalTaskMapcomposes the map; replaced Python map policy retiredScope And Continuation
Validation
8d8f3c004f4ee9570ca218e0d3942aca5d6e2852.9a41c713a330fbd65e85d2fb001fbdf5ba415bcdreturns HTTP200 and fails the independent missing-envelope assertion; the repaired head passes it. Stale, unreadable, unknown/truncated scope and replay are tested through the real producer/kernel; the packaged UI verifies visible recovery and downloaded metadata.Baseline:
83faa5bd9f7667ae104943feacdc1536a3d57f74; relevant map/status/runtime paths are unchanged through integrated main90932447eb5ed38a0d3fec8c57e21a62f57f849c. Gains include executable-revision scope and are not attributed to language movement alone. Source native map p95 is 0.509–0.684 ms; this is separate from full HTTP evidence. Original 5%/25 ms requirements are retained.CI was not queried or awaited under the configured policy. Windows, PostgreSQL, live models, installed-App adoption, sustained fleet behavior and new global cold-start/RSS qualification are not claimed. This read-model increment changes no PostgreSQL store or writer transaction. The existing 59 unproven semantic producer sites remain explicitly unproven.
Frontend / Visual Evidence
Before: the existing view retained a successful-looking assembly timestamp, and an unavailable map had no same-context retry. No normal viewport layout or navigation is redesigned. After, on the same existing entry: native source validity is visible, refresh recovers the map, and downloaded Markdown preserves old source time and both envelopes.
These are current packaged-source views at the tested implementation, using disposable synthetic File authority. The IO-failure/old-clock probes are explicit fixture hooks, not live outages. Keyboard recovery and 390px overflow were checked; no model call or user App upgrade occurred. The warning uses the existing notice style; the retry is essential recovery, with no extra setup or confirmation.
Shared-authority Fixture Impact
Read projection only: no authority field, transition, capacity/retention or provider promotion change. Existing production-scale native graph fixture remains; complete 12,000-row map admission and isolated canonical File/SQLite receiver arms cover the touched projection. PostgreSQL promotion and the legacy/file/PostgreSQL three-arm rehearsal are not claimed or required by this readonly composition boundary.
中文:地图组装归同一 TS owner,补齐真实来源封套、前端披露与原位恢复;原字段、身份与授权保持。正常包和四组完整 HTTP 对照通过,多一次外层封装调用已披露;这不等于完整 Agent 迁移或整个 RFC 完成。