Skip to content

Commit 0eb351e

Browse files
committed
Merge remote-tracking branch 'origin/main' into codex/quota-goalref-owner-fence-clean
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com> # Conflicts: # loopx/cli_commands/turn.py
2 parents 9baac7c + 4fc30f1 commit 0eb351e

76 files changed

Lines changed: 3629 additions & 1004 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/PULL_REQUEST_TEMPLATE.md‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,42 @@ concrete gap and consumer. These author facts are independently reviewed.
1414
- Observable before → after, with the validation row that proves it:
1515
- Issue/task and intended base: <!-- Use Closes only for the issue actually completed; otherwise Related to. -->
1616

17+
## Author Declaration
18+
19+
<!--
20+
Who wrote this change, and what it was implemented against. A reviewer may be a
21+
different operator's agent, working from a different host and context: this
22+
section is the only place it can learn both without guessing, and unlike the
23+
rest of the body it is published attribution rather than a reviewed claim. Keep
24+
it to one short line plus the spec rows; do not paste runtime identifiers,
25+
endpoints, credentials or internal routing detail, and never claim a
26+
verification you did not run.
27+
-->
28+
29+
- Written by: <!-- model_agent or human_operator; for an agent, the model and provider in ordinary product-family wording; keep it to one line -->
30+
31+
### Implemented against
32+
33+
<!-- The accepted specification this change was built for: an accepted RFC,
34+
accepted contract/protocol document, the linked issue or task, or a
35+
maintainer-agreed review frame. Give the exact file path or public link and the
36+
revision, so a reviewer can open the same text. One row per criterion the
37+
specification states, using its own section or identifier when it has one.
38+
Disposition: implemented | deferred | out_of_scope | not_met — a not_met row
39+
blocks approval and needs its gap and repair. Write "no written specification;
40+
the request in this PR is the basis" when none exists. Ignore aspirational or
41+
future properties; they are not obligations.
42+
-->
43+
44+
- Specification and revision:
45+
- Criteria:
46+
47+
| Criterion (spec clause) | Disposition | Symbol / path | Test or command |
48+
| --- | --- | --- | --- |
49+
| | | | |
50+
51+
- Self-check before submission: <!-- What you ran, what you read, and what you deliberately left out. Separate what you verified from what you assumed; "none" with a reason is valid. -->
52+
1753
## Scope And Continuation
1854

1955
<!-- A scoped fix may be complete while the parent program remains open.

‎.github/workflows/release-artifacts.yml‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -295,22 +295,18 @@ jobs:
295295
workflow-skills --uninstall --skills-dir "${skills_dir}" \
296296
> "${RUNNER_TEMP}/loopx-workflow-skills-uninstall.json"
297297
"${RUNNER_TEMP}/loopx-wheel/bin/python" - \
298-
"${RUNNER_TEMP}/loopx-workflow-skills-uninstall.json" <<'PY'
298+
"${RUNNER_TEMP}/loopx-workflow-skills-uninstall.json" \
299+
"${RUNNER_TEMP}/loopx-workflow-skills-install.json" <<'PY'
299300
import json
300301
from pathlib import Path
301302
import sys
302303
303304
payload = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
304305
assert payload["ok"] is True, payload
305-
assert sorted(payload["result"]["removed"]) == [
306-
"loopx",
307-
"loopx-benchmark",
308-
"loopx-doc-registry",
309-
"loopx-pr-program",
310-
"loopx-pr-review",
311-
"loopx-project",
312-
"loopx-self-repair",
313-
], payload
306+
installed = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))
307+
expected = installed["after"]["required_skill_ids"]
308+
assert expected and installed["after"]["ready"] is True, installed
309+
assert sorted(payload["result"]["removed"]) == sorted(expected), payload
314310
PY
315311
316312
- name: Exercise release contract smoke

‎AGENTS.md‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,22 @@ while planning. Inspect existing settings and capability editors before calling
249249
a configuration change backend-only; include necessary companion work in the
250250
same delivery plan, reusing the existing configuration owner and projection.
251251

252-
Before PR handoff, verify the affected user interaction, state readback and
253-
feedback, including the packaged frontend when shipped. State which entry
254-
points changed and the validation performed. If no frontend change is needed,
255-
give a concrete, verified reason; if companion work remains, label delivery
256-
partial and link it. These are agent-owned completion checks, not new approval
257-
gates.
252+
Every new or materially extended caller-facing capability must enter the
253+
shipped frontend through an existing appropriate surface: users can discover
254+
its purpose, perform the authorized user operation, see unavailable/error states,
255+
and read back the result. A CLI command, catalog row, static description or
256+
"copy this command" button alone does not complete frontend delivery. Reuse the
257+
same typed owner; frontend presence does not require a duplicate configuration
258+
switch or automatic execution of privileged tools. Internal helpers and providers
259+
belong to their owning capability's interaction rather than a separate screen.
260+
261+
Before PR handoff, validate that journey in the packaged frontend alongside the
262+
real owning rule/backend, including a relevant failure or recovery case. State
263+
which frontend/Lark/CLI entrypoints changed and what was verified. A staged CLI
264+
or backend prerequisite may be proposed as partial, with its remaining frontend
265+
journey and linked owner; do not mark the capability complete or use "developer
266+
only" as an automatic exemption. These are agent-owned completion checks, not
267+
new approval gates.
258268

259269
## UI Design Standard
260270

‎apps/presentation/dashboard/src/features/personal-workspace/machine-configuration-settings.tsx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { PerformanceDiagnosisPanel } from "./performance-diagnosis-panel";
12
import { UsageStatisticsSettings } from "./usage-statistics-settings";
23
import { useEffect, useMemo, useState } from "react";
34
import { AlertTriangle, Check, Code2, RefreshCw, RotateCcw, ShieldCheck, Trash2 } from "lucide-react";
@@ -322,23 +323,25 @@ export function MachineConfigurationSettings({ section, onChanged }: { section:
322323
}
323324
}
324325

326+
const diagnosis = section === "other" ? <PerformanceDiagnosisPanel /> : null;
325327
if (busy === "load") {
326-
return <div className="personal-machine-loading" role="status">{t("common.loading")}</div>;
328+
return <>{diagnosis}<div className="personal-machine-loading" role="status">{t("common.loading")}</div></>;
327329
}
328330
if (!inspection) {
329-
return <section className="personal-capability-error" role="alert">
331+
return <>{diagnosis}<section className="personal-capability-error" role="alert">
330332
<AlertTriangle aria-hidden size={18} />
331333
<span><strong>{t("machine.loadError")}</strong><small>{error}</small></span>
332334
<button onClick={() => void retryLoad()} type="button"><RefreshCw aria-hidden size={15} />{t("capabilities.retry")}</button>
333-
</section>;
335+
</section></>;
334336
}
335337
if (!selected) {
336-
return <p className="personal-capability-empty">{t("machine.capabilityEmpty")}</p>;
338+
return <>{diagnosis}<p className="personal-capability-empty">{t("machine.capabilityEmpty")}</p></>;
337339
}
338340

339341
return (
340342
<section className="personal-capability-settings" data-revision={inspection?.revision}>
341343
<div>
344+
{diagnosis}
342345
{section === "steward" ? <details className="personal-capability-scope-note">
343346
<summary><ShieldCheck aria-hidden size={17} />{t("machine.liveDefault")}</summary>
344347
<p>{t("machine.liveDefaultDescription")}</p>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { useEffect, useRef, useState } from "react";
2+
import type { summarizePerformanceProfile } from "../../../../../../loopx/control_plane/capabilities/performance_profile";
3+
import { useWorkspaceI18n } from "./i18n";
4+
import "./performance-diagnosis.css";
5+
6+
type Result = ReturnType<typeof summarizePerformanceProfile>;
7+
8+
export function PerformanceDiagnosisPanel() {
9+
const { locale } = useWorkspaceI18n();
10+
const zh = locale === "zh-CN";
11+
const worker = useRef<Worker | null>(null);
12+
const input = useRef<HTMLInputElement | null>(null);
13+
const [ranking, setRanking] = useState<"self" | "inclusive">("self");
14+
const [result, setResult] = useState<Result | null>(null);
15+
const [busy, setBusy] = useState(false);
16+
const [error, setError] = useState<string | null>(null);
17+
useEffect(() => () => worker.current?.terminate(), []);
18+
19+
function clear(resetInput = true) {
20+
worker.current?.terminate(); worker.current = null;
21+
setBusy(false); setError(null); setResult(null);
22+
if (resetInput && input.current) input.current.value = "";
23+
}
24+
function inspect(file: File | undefined) {
25+
clear(false);
26+
if (!file) return;
27+
if (file.size > 16 * 1024 * 1024) {
28+
setError(zh ? "文件超过 16 MiB,请缩短采样时间。" : "Profile exceeds 16 MiB; select a shorter capture."); return;
29+
}
30+
setBusy(true);
31+
try {
32+
const active = new Worker(new URL("./performance-diagnosis-worker.ts", import.meta.url), { type: "module" });
33+
worker.current = active;
34+
const finish = (message: { result?: Result; error?: string }) => {
35+
if (worker.current !== active) return;
36+
active.terminate(); worker.current = null; setBusy(false);
37+
setResult(message.result ?? null); setError(message.error ?? null);
38+
};
39+
active.onmessage = (event: MessageEvent<{ result?: Result; error?: string }>) => finish(event.data);
40+
active.onerror = () => finish({ error: zh ? "解析进程不可用,请重试或使用 CLI 检查。" : "Profile reader unavailable; retry or inspect through the CLI." });
41+
active.postMessage(file);
42+
} catch {
43+
worker.current?.terminate(); worker.current = null;
44+
setBusy(false); setError(zh ? "浏览器无法启动解析进程。" : "This browser could not start the profile reader.");
45+
}
46+
}
47+
return <details className="personal-capability-scope-note personal-performance-diagnosis" data-testid="performance-diagnosis">
48+
<summary>{zh ? "性能诊断 · 查看本地采样" : "Performance diagnosis · inspect a local capture"}</summary>
49+
<p>{zh ? "选择 Speedscope 或 Node CPU JSON,比较独立线程的热点。文件只在浏览器内解析,不发送、不保存,不启动采样工具。" : "Choose Speedscope or Node CPU JSON to inspect each thread's hotspots. Files are processed only in this browser, never sent or saved. No profiler is started."}</p>
50+
<label>{zh ? "选择本地 profile(最多 16 MiB)" : "Choose a local profile (up to 16 MiB)"}
51+
<input accept=".json,.cpuprofile,application/json" ref={input} type="file" onChange={event => inspect(event.target.files?.[0])} />
52+
</label>
53+
<button className="personal-secondary-action" onClick={() => clear()} type="button">{zh ? "清除 / 取消" : "Clear / cancel"}</button>
54+
{busy ? <p role="status">{zh ? "正在解析,可取消…" : "Inspecting; you can cancel…"}</p> : null}
55+
{error ? <p role="alert">{zh ? "未能读取采样:" : "Could not inspect capture: "}{error}</p> : null}
56+
{result ? <div aria-live="polite">
57+
<p role="status">{zh ? `已解析 ${result.profiles.length} 份独立采样` : `Inspected ${result.profiles.length} independent profiles`}</p>
58+
<p>{zh ? "采样权重不是执行耗时、CPU 利用率或已证明的根因;包含子调用的时间有重叠,不能相加。" : "Sample weights are not task latency, CPU utilization or proven root cause. Inclusive times overlap and must not be added."}</p>
59+
<label>{zh ? "热点排序" : "Rank hotspots by"}<select value={ranking} onChange={event => setRanking(event.target.value as "self" | "inclusive")}>
60+
<option value="self">{zh ? "函数自身时间" : "Self time"}</option><option value="inclusive">{zh ? "含子调用时间" : "Inclusive time"}</option>
61+
</select></label>
62+
{result.profiles.map((profile, index) => <details key={index} open={index === 0}>
63+
<summary>{profile.name} · {profile.observed_weight_ms.toFixed(2)} ms</summary>
64+
<div className="personal-performance-hotspots"><table>
65+
<caption>{zh ? "采样热点(前 15 项)" : "Recorded hotspots (up to 15)"}</caption>
66+
<thead><tr><th>{zh ? "函数" : "Function"}</th><th>{zh ? "自身 ms" : "Self ms"}</th><th>{zh ? "含子调用 ms" : "Inclusive ms"}</th></tr></thead>
67+
<tbody>{(ranking === "self" ? profile.self_hotspots : profile.inclusive_hotspots).map((row, i) => <tr key={i}><td>{row.name}<small>{row.file ? ` · ${row.file}${row.line ? `:${row.line}` : ""}` : ""}</small></td><td>{row.self_ms.toFixed(2)}</td><td>{row.inclusive_ms.toFixed(2)}</td></tr>)}</tbody>
68+
</table></div>
69+
</details>)}
70+
</div> : null}
71+
<details><summary>{zh ? "如何采样" : "How to capture"}</summary>
72+
<p>{zh ? "由 Host 对有权限的目标执行采样;使用 CLI 生成准确 argv,安装与执行由 Host 负责。采样后回到这里选择文件。" : "Ask your Host to profile an owned target. The CLI prepares exact argv; the Host owns installation and execution. Return here to select the capture."}</p>
73+
<code>loopx performance-diagnosis plan --help</code>
74+
</details>
75+
</details>;
76+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { summarizePerformanceProfile } from "../../../../../../loopx/control_plane/capabilities/performance_profile";
2+
3+
// Raw captures stay in this browser. Parsing and aggregation never block the UI.
4+
self.onmessage = async (event: MessageEvent<File>) => {
5+
try {
6+
if (event.data.size > 16 * 1024 * 1024) throw new Error("Profile exceeds 16 MiB; select a shorter capture.");
7+
const profile: unknown = JSON.parse(await event.data.text());
8+
self.postMessage({ result: summarizePerformanceProfile({ profile, top: 15 }) });
9+
} catch (cause) {
10+
self.postMessage({ error: cause instanceof Error ? cause.message : "Could not inspect profile." });
11+
}
12+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.personal-capability-scope-note.personal-performance-diagnosis { max-height: min(440px, 40dvh); font-size: 12px; }
2+
.personal-performance-diagnosis > summary { position: sticky; top: 0; padding: 8px 0; background: var(--pw-bg); z-index: 1; }
3+
.personal-capability-scope-note.personal-performance-diagnosis p { padding-left: 0; }
4+
.personal-performance-diagnosis label { display: grid; gap: 6px; margin-block: 10px; }
5+
.personal-performance-diagnosis input, .personal-performance-diagnosis select { width: 100%; min-width: 0; min-height: 44px; padding: 8px; border: 1px solid var(--pw-line-strong); border-radius: 6px; color: var(--pw-text); background: var(--pw-card); font: inherit; }
6+
.personal-performance-diagnosis [role="alert"] { color: var(--pw-red); }
7+
.personal-performance-hotspots { overflow-x: auto; }
8+
.personal-performance-hotspots table { width: 100%; border-collapse: collapse; margin-block: 10px; }
9+
.personal-performance-hotspots th, .personal-performance-hotspots td { padding: 8px; text-align: left; border-bottom: 1px solid var(--pw-line); }
10+
.personal-performance-hotspots td:first-child { overflow-wrap: anywhere; }
11+
.personal-performance-hotspots small { display: block; color: var(--pw-muted); }

‎docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,23 @@ on September 14 at `e98191faa`; its final result and applicability to the curren
300300
candidate still need evidence. Do not call it unstarted or restart its clock
301301
solely because an unrelated source revision changed.
302302

303+
At source `613180ae`, the matched 64 KiB macOS run passes 13 rows, fails
304+
cold CLI status p95 (4.39 s against 2 s), and leaves 11 missing. The Linux
305+
storage-only run passes 12 rows with 13 missing; its smaller CLI rehearsal is
306+
not the formal CLI axis. Opt-in `performance-diagnosis` captures Python wall
307+
time, independent Node CPU, and Linux thread stacks on disposable targets.
308+
Startup, candidate scanning and waits are hypotheses to test with unchanged
309+
uninstrumented workloads; profile weights do not replace this admission failure.
310+
311+
[#5283](https://github.com/loopx-project/loopx/pull/5283) is the adjacent
312+
read-only delegation preflight optimization, not a provider implementation.
313+
Its current process-reuse candidate reports paired File/SQLite warm gains with
314+
an explicit cold-start cost; retain it for exact-head review, installed readback
315+
and real requester adoption. Qualify that repeated consumer independently from
316+
the cold-only status workload above. Keep decisions fresh at the existing TS/CLI
317+
owners; the pinned Python worker remains transport, not a new decision cache.
318+
Retire Python rules only when their TS replacement and last callers are proven.
319+
303320
Last-caller Python decision retirement can proceed independently where the TS
304321
replacement and affected real callers are proven. Whole Markdown writer removal
305322
still requires C's new-Goal/upgrade/recovery exits. Complete consumer metadata,

‎docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.zh-CN.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,20 @@ consumer lag 及保留的自然时间 soak 适用性。
220220
D2 通过或默认切换。#4224 已报告在 `e98191faa` 上于 9 月 14 日开始 soak,仍需最终
221221
结果及对当前候选的适用性证据,不能称为未开始,也不能仅因无关 source 修订就重启计时。
222222

223+
在 source `613180ae` 上,64 KiB 匹配负载的 macOS 正式测量有 13 项通过、1 项失败、
224+
11 项缺失:冷 CLI status p95 为 4.39 秒,超过 2 秒预算。Linux 的仅存储正式测量
225+
有 12 项通过、13 项缺失;小规模 CLI 演练不能替代正式 CLI 轴。按需调用的
226+
`performance-diagnosis` 已在隔离目标上采集 Python 墙钟、独立 Node CPU 和 Linux
227+
线程栈。启动、候选扫描和等待仍是待验证假设,需复跑未插桩的原负载;不能用
228+
profile 权重替换这项准入失败。
229+
230+
[#5283](https://github.com/loopx-project/loopx/pull/5283) 是相邻的只读 delegation
231+
预检优化,不是 provider 实现。当前进程复用候选报告了 File/SQLite 配对暖调用收益,
232+
同时披露冷启动成本;保留并推进精确 head 评审、安装读回和真实请求方采用。
233+
重复调用消费者与上述单次冷 status 分别验收。沿原 TS/CLI owner 读取当前决策,
234+
固定 Python worker 只作传输,不缓存权限或验收结果;TS 替代与最后调用方验证完成
235+
后再退役 Python 规则,不能凭进程复用就宣称退役或 SQLite 准入。
236+
223237
已有 TS 替代且真实受影响调用方验证完成的 Python 重复决策,可以按最后调用方独立
224238
退役;整条 Markdown writer 删除仍需 C 的新 Goal/升级/恢复出口。消费者完整
225239
metadata、freshness 和决策输入继续验收。合同检查与 attention 现在按 runtime/Goal 共享请求内已校验的完整

‎docs/development/frontend-delivery.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ mandatory acceptance source. If none applies, the task, failure and owning
2323
contract still define acceptance. Inspect current main and related work first.
2424
A passing implementation-shaped test is not an independent experience oracle.
2525

26+
Caller-facing capabilities require an appropriate shipped frontend journey,
27+
including discoverability, authorized operation, feedback and result readback.
28+
CLI-only prerequisites are partial delivery; catalog text or a command-copy
29+
button is not the journey. Reuse the typed capability owner rather than adding
30+
frontend-only decisions or a setting for a capability with no persistent policy.
31+
2632
Carry the same task through these steps:
2733

2834
1. **Compare the journey.** Write the current and proposed user steps in the

0 commit comments

Comments
 (0)