Skip to content

Enhance documentation, fix bugs, and add new task plugins - #28

Closed
myrfy001 wants to merge 59 commits into
masterfrom
next-app
Closed

Enhance documentation, fix bugs, and add new task plugins#28
myrfy001 wants to merge 59 commits into
masterfrom
next-app

Conversation

@myrfy001

Copy link
Copy Markdown
Collaborator

No description provided.

myrfy001 and others added 30 commits July 15, 2026 22:05
- star-history 改用 <picture> 支持暗/亮主题自适应
- 新增 Academic Research/学术研究 章节,包含 arXiv 引用和 arxiv-paper 分支说明
- 新增 Contributing/如何贡献 章节,指向 CONTRIBUTING.md

Co-Authored-By: deepseek-v4-pro <deepseek-ai@claude-code-best.win>
…ter 并行提示

- 扩展 DIAGNOSTIC_GLOBS 覆盖 E 阶段产物(perf_report.json, perf-server.*.log)和
  retrospective.md,确保 planner 能看到 perf 失败的根因
- 新增 _render_e_failure() 给出结构化的 E 失败描述和诊断文件绝对路径
- _prev_logs_section() 自动发现 prev-iter 中的诊断文件,不再硬编码 C_test 文件名
- 新增 IMPLEMENT_PARALLEL_HINT 指导 implementer 用并行子 agent 同时写多个独立文件
- NOTEBOOKS_HINT 明确子 agent 禁令仅针对阅读(不针对写作)

Co-Authored-By: deepseek-v4-pro <deepseek-ai@claude-code-best.win>
新增 `find-low-hanging-kernel` 任务插件:输入 Chrome tracing + 模型目录 + 推理框架源码树,
自动生成可审计的执行流图(节点 = kernel 调用,含 source_ref/tensor shapes/stats/confidence),
并标记优化空间最大的低垂果实。插件完全位于 `metainfer/tasks/find_low_hanging_kernel/` 下,
复用 StateStore / AgentPool / SubAgentManager / TokenBudget 共享基础设施。

主要阶段(每阶段使用全新 Agent 实例,Step 1/2/3 均为多 agent 交叉验证):
- P1 code_analysis: 3-agent 池(arch/quant/runtime tracer)+ 综合 agent
- P2 tracing_analysis: 确定性 trace parser + 3-agent 池(stat/source/shape analyst)
- P3 graph_build + graph_validate: 5-worker 持久 AgentPool,每轮 3 节点分组语义校验
  + 确定性完整性检查,支持循环 fix;validation/round_NN/ 留存审计产物
- P4 visualize: 把 graph JSON 内联进 ELK+SVG HTML 模板,独立文件 + WebUI iframe 双形态

附带的其他改动:
- 共享层:`metainfer/orchestrator/requirements.py`(统一 req_field 读取,
  终结 requirements.json 嵌套/扁平多路径读取反模式);`server/liveness.py`
- 其他 task 包(calc_value/opt_kernel/gen_infer_framework/gen_cpp_infer_framework)
  切换到共享 requirements 读取层;CLAUDE.md 记录数据一致性权威源规约

测试:39 个新插件测试全绿;mock-based 端到端 + resume + integrity + pool 收敛均覆盖。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…从 registry 剥离

bug 现场:worker21 上的 orchestrator 已经死了(orchestrator.pid 里 finished_at 已盖戳、
exit_hint="reaped-by-kill-on-dead-pid",run.json 也明确 finished=true / final_status=stopped),
但跑在另一台机器上的 WebUI 还显示 Kill 按钮可点。

根因:LocalLauncher.status() 只有在 pid 为 None 时才认 finished_at;pid 字段非空时
直接走 validate_pid_started_at 做本机 /proc 探测。多节点 NFS 架构下,本机 /proc 永远
看不到兄弟节点上的进程——本机 os.kill(pid, 0) 撞上 PID 复用就会误判为 alive。

修复:把 finished_at 短路判断提前。pid 文件里只要 finished_at 已盖戳,进程必然没了
(这条字段由 orchestrator graceful exit / launcher._reap_dead_pid_file / spawn 失败
清理路径盖戳,每一条都意味着进程确实退出);只有 finished_at 缺失时才回落到本机
/proc 探测,覆盖 SIGKILL / OOM 等没来得及盖戳的硬死场景。

顺带做的 SSOT 整治(同一类问题):
- registry.json 不再缓存 pid / started_at / finished_at——这三处存储曾经各自被不同
  代码路径选择性同步,没有任何派生函数,必然漂移。registry 现在只存身份字段
  (id/type/label/state_dir/workspace_dir/created_at/launcher),所有进程状态查询
  只走 launcher.status() 读 orchestrator.pid。
- liveness scan 不再用 registry.pid 做 pre-filter(已经是 None 了),改为无差别
  对每个 task 调 status(),符合"进程状态只有 orchestrator.pid 一个权威源"。
- reconcile 不再写自己的简化版 _write_pid_file_finished,复用 launcher._reap_dead_pid_file
  单一 reap 路径,保证 UI 拿到的死亡信号一致(run.json + timeline + pid 三处同步更新)。

测试:
- 新增 metainfer/server/tests/test_launcher_status.py,4 个直接测试 LocalLauncher.status()
  的 case:包括专门覆盖本 bug 的"pid=当前 Python 进程 + finished_at 已盖"用例(旧逻辑
  会返回 running=True)。
- 更新 test_liveness.py 适配 registry 不再缓存 pid 的新规约。

CLAUDE.md 同步更新数据一致性权威源表 + 反模式清单。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
1. req.get("answers")/req.get("form") 嵌套回退统一到 req_field()
   - 17 处分布在 11 个文件的嵌套回退全部替换为 req_field()/req_field_int()
   - 覆盖 target_model(8)/max_iterations(3)/perf_prompts_path(2)/
     oracle_prompts_path(2)/target_hardware(1)/max_validator_rounds(1)

2. _render_req() 重复逻辑消除
   - gen_infer_framework/gen_cpp_infer_framework/opt_kernel 三个 prompts.py
     里完全相同的格式化逻辑统一到 requirements.py::req_summary_lines()

3. 数据竞态修复
   - 新增 server/filelock.py (跨进程 fcntl.flock 上下文管理器)
   - timeline.jsonl: orchestrator(state.py) + WebUI(state_reader.py) 双写加锁
   - token_budget.json: orchestrator(_persist) + WebUI(routes.py) 双写加锁
   - run.json: launcher._update_run_stopped() 加锁
   - orchestrator.pid: launcher/routes.py 直接 write_text → tmp+replace 原子写

4. 其他
   - requirements.py 新增 req_summary_lines() 共享格式化函数

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
新增 `port-model` 任务插件(task_type: port-model):给定已有模型支持的源框架
和需要添加支持的目标框架(vLLM/SGLang/TensorRT-LLM/TGI),在目标框架中实现
该模型的适配(模型端口)。

五阶段线性 pipeline:
- P1_model_analysis:单 Agent 分析模型架构(config.json + 权重结构 + 特殊层)
- P2_source_analysis:分析源框架中该模型的注册方式(入口/自定义层/权重映射/前向链)
- P3_target_analysis:分析目标框架注册模式(找模板/列文件/diff 计划)
- P4_implement:在目标框架中实现模型支持并产出 patch
- P5_test:boot 源/目标框架服务,对比输出,LLM-judge 判定正确性;失败时回到 P4 修复(最多 3 retry)

关键约束:
- model_dir / source_framework_dir 对所有 Agent 只读(prompt + orchestrator 双层防护)
- Agent 仅可在 target_framework_dir 内写入
- 产物:model_port.patch + test_results.json + 三个 memory/*.md 分析文档

测试:19 个新插件测试全绿(form 注册 + phase 状态机 + MockAgentManager 端到端 + resume)。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
附带多项积累修复:
- launcher: spawn 后立即写 placeholder orchestrator.pid,避免启动窗口期内 status() 返回 not-running
- subagent_manager: 检测 ccb "No conversation found" stale session 错误,自动 drop resume_session_id 重试
- calc_value: viz.html 注入 TASK_ID / COMPUTE_URL header,修复 WebUI iframe 内 agent 误读 URL 的问题;迭代面板加 max-height 滚动
- gen_infer_framework: 新增 ASYNC_NONBLOCK_MANDATE 提示,修复 implementer 在 async handler 里同步调 tokenizer 导致 event loop 卡死的 12-iteration death spiral;面板加 max-height 防止超长 iteration 列表撑爆页面

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
- pipeline.py: A-H 8 阶段状态机(bootstrap 4 phase + 优化循环 4 phase),无重试上限
- harness.py: correctness + performance 测试 harness 模板与子进程执行引擎
- kernel_library.py: 内核库——加权排名、选择、淘汰、迭代追踪
- phases.py: 完整 Transition 表、Phase 分类、前端 graph payload
- prompts.py: 6 个 agent prompt,AMD DCU/gfx928 warp_size=64 适配
- 前端: 状态图渲染、内核库面板(可滚动代码预览)、独立 detail 视图
- 100 个单元测试
Restructure the native C++ knowledge base, add deterministic plan and implementation gates, strengthen correctness/performance validation, and preserve resumable task lifecycle state.
新增 `POST /api/calc-theoretical-value/{task_id}/control` 端点,接受:
- rerun_step: 指定 step(S0_rough..S4_visualize),kill orchestrator → 删除该 step
  及所有后续 step 输出 → restart orchestrator 从缺失处恢复
- kill / restart: 与 sys-shell 一致的通用控制操作

前端 calc-viz-tab 每个已完成 step 旁增加 ↻ re-run 按钮,带操作结果反馈。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
主要内容:

1. port-model 任务完整落地:
   - 6 阶段状态机 (P1 权重分析 → P2 框架分析 fan-out → P3 架构师 →
     P4 精简框架 → P5 验证 → P6 移植),含 bounce/repair 自循环
   - 编排器 + CLI + plugin + QA + state readers + /control 端点
   - WebUI: 6 tab 视图、phase summary 浮窗、P6 batch verdict 渲染、
     Live agents 默认 tab 可见 (Elapsed/Last output 用于判断卡死)
   - 26 个单测覆盖 happy path + 各种 repair loop

2. Form Widget Registry (sys_shell 架构改造):
   - 内建 widget 拆出独立文件,统一注册到 form-registry
   - 插件通过 form-overrides.js + importmap_entries 自包含扩展,
     其他 task 包零改动 (port-model 的 kv-list-path-notes 落地验证)

3. P5/P6 改 batch 验证协议:
   - 3-prompt batch (珠峰 / 国旗 / 体温),一次 forward 同时跑
   - Verdict 改 batch[] + verifier_judgment,LLM 语义判断替代字符匹配
   - Hidden-state dump 改 per-row 布局 (dumps/row0|row1|row2/)

4. Prompt 加 execution discipline:
   - 全局禁 Sleep / 禁 background 轮询 / 禁自我验证 sub-agent
   - 阶段级 sub-agent 权限 (P1/P3/P5 禁, P2/P4/P6 允)

5. 关键 bug 修复:
   - launcher._write_pid_file_placeholder 漏 import json (NameError on spawn)
   - pipeline._do_p2 未 mkdir workdir → FileNotFoundError
   - MockAgentManager 现在校验 workdir 存在,与真 Popen 契约对齐

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…HTTP routes

Module A (fs_primitives): atomic_write_json/text, link_claim, read_claim,
break_claim with optional lease-secret verification, touch_heartbeat /
is_stale_heartbeat, generate_secret. All cross-host coordination uses os.link
(atomic on NFS); no fcntl.flock across hosts.

Module B (worker_registry): WorkerRecord dataclass with int-keyed GPU
topology; register_worker writes SSOT JSON + touches initial heartbeat;
read_worker/list_workers derive alive state from heartbeat mtime. Webui
restart-safe — no in-memory caches.

Module B.5: cluster_routes.py with GET /api/cluster/workers and
GET /api/cluster/workers/{node_id}, mounted in app.create_app().

Tests: 19 fs_primitive tests (incl. concurrent link_claim race proving
unique-winner), 8 worker_registry tests (incl. cold-restart invariant).

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Module C (scoreboard): acquire_gpus atomically links N GPU slot claims in
sorted order with rollback on partial failure and jitter backoff. Returns a
LeaseToken with secret; release_gpus verifies secret per slot. renew_lease
updates the sibling .meta.json (claim files are immutable post-link).
force_release and reap_expired_claims share a single reap path (mirrors
CLAUDE.md launcher invariant); reaper also requires holder heartbeat to be
stale before breaking a lease-expired claim, avoiding premature reap of
workers mid-renew.

Module C.5: GET /api/cluster/scoreboard and POST /api/cluster/scoreboard/force-release
added to cluster_routes.

Tests: 12 scoreboard tests including concurrent same-slot unique-winner,
multi-slot rollback, cross-set no-double-hold under contention, opposite-order
no-deadlock, lease expiry + reap, secret verification, force_release cancel marker.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Module D (mqueue): submit_job builds the job dir in tmp + os.replace so
consumers never see a partial directory. consume_next_job uses link_claim on
<job_dir>/claimed to ensure exactly-one-worker wins; skips cancelled and
already-claimed jobs. write_result/read_result round-trip via tmp+replace
under replies/<orch>/<job_id>.result.json. reap_orphaned_submissions force-
releases GPU slots and writes synthetic worker_dead/timeout results past
timeout+grace — no auto-requeue (decision: surface as failure). reset_queue
and reset_reply_queue for admin/debug.

Tests: 15 mqueue tests covering round-trip, consume race (unique winner),
producer-crash tolerance (partial tmp dir skipped), cancel.marker pre-cancel,
orphan reaper paths (worker_dead result, skip-existing-result, scoreboard
slot release).

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Module E (worker daemon): WorkerDaemon runs a single-threaded main loop that
touches heartbeat every 15s, polls inbox, and spawns per-job supervisor
threads (bounded by max_concurrent_jobs semaphore). Supervisor thread runs
jobs.run_job and writes result back via mqueue.write_result. SIGTERM/SIGINT
graceful shutdown drains in-flight jobs.

Module E.2 (jobs): run_job spawns subprocess with start_new_session=True for
process-group isolation. Script jobs run via 'bash script.sh'; agent jobs run
via ccb with prompt piped to stdin (mirrors SubAgentManager._build_command).
CUDA_VISIBLE_DEVICES derived from job.gpu_slots filtered to own node.

Module E.3-E.5: stdout/stderr fds opened in append-binary and passed to Popen
for streaming. Watchdog thread polls cancel.marker + deadline; on trigger
SIGTERMs process group → 5s grace → SIGKILL. Results finalized via
mqueue.write_result in the supervisor (worker does NOT release GPU slots —
orchestrator owns the LeaseToken and releases in its finally).

Module E.6: 'python -m metainfer.worker' CLI; honors METAINFER_NODE_ID /
METAINFER_ROOT.

Module E.7: FakeWorker in metainfer/testing/fake_worker.py — in-process
stand-in for tests; injectable handler replaces subprocess execution.

Tests: 10 daemon tests covering script success, env-var passthrough,
CUDA_VISIBLE_DEVICES, timeout escalation, cancel.marker (pre-existing +
mid-run), FakeWorker end-to-end.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Module F (sdk): RemoteJob context manager wraps acquire_gpus + submit_job +
inline-reaper-while-polling + release_gpus in finally. submit_script /
submit_agent convenience wrappers. submit_pp2_ranks for PP2 distributed
testing — injects RANK/NODE_RANK/LOCAL_RANK/WORLD_SIZE/NNODES/
NPROC_PER_NODE/MASTER_ADDR/MASTER_PORT env. tail_stdout / tail_stderr for
live log access.

Key correctness fix: collect_result runs reap_orphaned_submissions every 5s
while waiting, so dead-worker jobs surface as status=worker_dead instead of
blocking until timeout.

Module F.3: metainfer-cluster CLI with subcommands: workers ls/show,
scoreboard show/force-release, queue submit/ls/reset, tail stdout|stderr.

Tests: 7 SDK tests covering blocking result, no-GPU path, slot acquire/
release, acquire-failure (TimeoutError, no leak), inline reaper surfacing
worker_dead, log tailing, non-blocking submit.

71 total tests in cluster/ + worker/ pass.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…ontend

Module G (admin): GET /api/cluster/jobs lists submitted jobs across one or
all worker inboxes; GET /api/cluster/jobs/{w}/{j}/{stdout|stderr}?offset=N
tails live log bytes. list_jobs() iteration logic bug fixed (was mis-walking
the inbox tree when worker_node_id=None).

Module G.1-G.3 (frontend): ClusterOverview view polls workers + scoreboard
with Force release buttons; ClusterJobDetail tails stdout/stderr with
auto-scroll; main.js gets a 'Cluster' topbar button that toggles the
workspace between task-detail and cluster views. Both views registered in
index.html importmap.

Tests: 10 admin endpoint tests covering list workers, scoreboard listing,
force-release (including 400 on missing fields), list jobs, log tailing
(incl. offset + 404 + 400 on invalid stream).

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…in evolve_kernel

Adds the worker-multiselect shell widget and a `worker_nodes` field to the
evolve_kernel/port_model forms. evolve_kernel's perf phase now routes through
the cluster SDK (submit_script) when worker_nodes is configured, falling back
to local subprocess otherwise.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…d testing

When worker_nodes is configured (≥2 for PP2), inject a distributed-testing
guidance block into the P5/P6 prompts teaching the agent how to use the
cluster SDK (submit_pp2_ranks) to launch the framework across two workers.
Agent still owns the decision of whether to actually use distributed mode.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…f failures

run_perf_test now surfaces worker_status (done/timeout/worker_dead/cancelled/
failed) in its result dict for the remote path. The evolve_kernel pipeline
emits a 'worker_failure' timeline event when status indicates a worker-side
failure, so WebUI / debugging can distinguish worker-side issues from
kernel-logic issues.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…wiring

- evolve_kernel/test_remote_perf.py: verifies run_perf_test remote path
  parses JSON from worker stdout and surfaces worker_dead status.
- port_model/test_distributed_p5.py: verifies PipelineConfig.worker_nodes,
  _parse_worker_nodes (list/csv/empty), and that P5/P6 prompts inject the
  PP2 distributed-testing block only when ≥2 workers are configured.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…l marker

E2E tests in metainfer/tests/e2e/:
- test_remote_job_flow: full submit→run→result with GPU slot lifecycle
- test_pp2_contention: concurrent cross-node acquisition (no deadlock)
- test_worker_crash: dead worker surfaces quickly via inline reaper
- test_admin_force_kill: HTTP force-release frees slot + writes cancel.marker
- test_webui_restart: cluster state survives WebUI cold restart

Also fixes the /api/cluster/scoreboard/force-release endpoint to pass
cancel_job_dir so the worker's job subprocess gets SIGTERM'd.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…md SSOT

- docs/multi-node-architecture.md: human developer reference covering
  cluster/ layout, NFS-safe link-claim algorithm, deadlock-free sorted
  acquisition, lease+reaper rules, single-reap-path invariant.
- docs/agent-sdk-guide.md: agent-facing SDK cookbook (submit_script,
  submit_agent, submit_pp2_ranks, log tailing, error patterns, status
  codes). Required reading for agents touching evolve_kernel/port_model.
- CLAUDE.md: extend SSOT table with cluster/ entries (worker record,
  heartbeat, scoreboard claim, job spec/result/logs) and add cluster-
  specific anti-patterns (cross-host flock, second reaper, rewriting
  heartbeat JSON, mutating immutable claim files, worker-held leases).
- Production code: 100% public-symbol docstring coverage in
  metainfer/cluster/* and metainfer/worker/*.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Adds a "Multi-node setup" section to both README.md and README_CN.md
covering how to start a worker daemon on a remote GPU node, how workers
register/liveness via cluster/, how the WebUI Cluster tab surfaces them,
and the metainfer-cluster admin CLI snippets. References the existing
docs/multi-node-architecture.md and docs/agent-sdk-guide.md for depth.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…nstraints

Restructure the P6 prompt around a real iterative workflow instead of a
one-shot launch. The previous prompt told the agent to "add a code path
behind an env var" in a single sentence, which produced 10 blind retry
launches when sglang's aiter/tilelang fp8 kernels rejected gfx928.

Changes:

* prompts.py: add _launch_constraints_block helper that reads the optional
  req.launch_constraints textarea and injects user-supplied model-specific
  guidance (sglang flags, memory facts, "PP2 must combine with lazy
  loading") into P5/P6 prompts. Generic — port_model itself hardcodes no
  framework names.

* prompts.py: rewrite p6_port_engine_prompt body with a structured inner
  loop (LAUNCH -> DIAGNOSE -> REPLACE -> RELAUNCH -> INFER -> DUMP-CMP ->
  BISECT -> STOP), an ordered operator replacement strategy hierarchy
  (framework-native flag -> Triton -> pure torch -> P4 reference impl),
  an "operator unsupported on my hardware" diagnostic section, and an
  explicit dump-driven bisection procedure. Extend the verdict schema
  with inner_attempts and operator_replacements[] fields.

* prompts.py: add format_prev_p6_verdict helper that renders the previous
  iteration's verdict into a structured handover block (reason, similarity
  summary, inner_attempts, operator_replacements list) so the next P6
  iteration continues from known progress instead of starting blind.

* pipeline.py::_do_p6: hand the next P6 iter the structured rendering of
  the previous verdict instead of just verdict.reason one-liner.

* form.yaml: add optional launch_constraints textarea.

* test_distributed_p5.py: add 4 tests for launch_constraints injection.

* test_p6_iterative_loop.py: 15 tests covering the inner-loop playbook,
  verdict schema, and format_prev_p6_verdict rendering (incl. malformed
  input handling).

Total port_model tests: 39 -> 54, all green.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
The rerun_step /control handler was unconditionally unlinking
memory/p1_weight_analysis.md and memory/p3_consolidated_spec.md on
every rerun, even when the user only asked to re-run P6. This broke
P6 resume — _do_p6 reads the canonical P3 spec from memory/, so the
next P6 invocation would logic_fail with "P3 consolidated spec
missing" unless the caller manually restored the file.

Fix: only unlink each memory artifact when start_idx is at or below
that artifact's producing phase (p1 for p1_weight_analysis, p3 for
p3_consolidated_spec). Re-running P6 (start_idx=5) now leaves P1/P3
canonicals untouched.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
myrfy001 and others added 29 commits July 23, 2026 22:59
The P6 prompt body is one big f-string. The line
  dumps/row{0,1,2}/layer_<NNN>_<checkpoint>.npy
was getting evaluated by Python as a set literal and rendered as
"dumps/row(0, 1, 2)/..." — confusing notation. Rewrite the line as
explicit row0/row1/row2 list so there's no brace interpolation to
trip over. Cosmetic — the bisection section's row<R> mentions already
disambiguated the layout, but the literal is now correct.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Previously list_claims only emitted rows for slots that had a .claim file
(held slots). On an idle cluster that meant the WebUI scoreboard panel
rendered blank — users couldn't tell "no GPUs registered" apart from
"GPUs all free".

Now joins worker topology with live claims and emits one row per known
GPU, status "free" or "held". Free rows carry topology (name, memory)
and empty holder/job_id; held rows include claim metadata + lease
remaining. Orphaned claims (claim file for a GPU not in topology) are
still surfaced so they can be released.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Problem: in a multi-node setup (orchestrator on worker A, WebUI on
worker B), the WebUI's liveness scan read orchestrator.pid, saw a live
pid, and probed its local /proc/<pid>. The pid doesn't exist on B →
validate_pid_started_at returned False → exit_hint="pid-dead" → liveness
falsely reaped a still-running remote orchestrator, marking the task
"stopped" while it continued crunching on A.

Fix:
- write_pid_file (orchestrator side) records socket.gethostname()
- _write_pid_file_placeholder (WebUI spawn side) does the same — the
  orchestrator is a local child of the WebUI under LocalLauncher
- status() returns running=True, exit_hint="remote-pid-unchecked" when
  the pid file's hostname != current host. finished_at stamped by the
  remote node on real exit is the only authoritative death signal.
- kill() returns False without false-reaping when pid is on another host

Two regression tests pin the multi-node behavior.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…ter SDK

Two coupled changes that unblock PP2+TP-style multi-node porting.

SDK (metainfer.cluster.sdk):
- PP2RankSpec now accepts gpu_indices: List[int] for multi-GPU TP per rank.
  gpu_idx (singular) kept for back-compat; resolved_slots() unifies them.
- submit_pp2_ranks computes NPROC_PER_NODE / TP_SIZE_PER_NODE / WORLD_SIZE
  from the actual slot counts instead of hardcoding WORLD_SIZE=2 and
  NPROC_PER_NODE=1. Single-GPU ranks (the old API shape) still work
  unchanged.

Prompt (port_model._distributed_block):
- Soft "you may use the cluster SDK" → hard "every end-to-end launch
  MUST span all worker_nodes". A single-node smoke test is no longer an
  acceptable final verdict when worker_nodes is configured.
- Updated example to use gpu_indices=[...] and explicit tp_per_rank
  read from launch_constraints (no hardcoded count in the framework).
- Added explicit verification checklist before writing verdict_*.json:
  scoreboard claims on every worker, both ranks produced results,
  init_process_group evidence in logs.

The framework itself stays model-agnostic — task-specific TP/PP counts
keep flowing through launch_constraints. The change only removes the
implicit "1 GPU per worker" bias that was leading agents to fall back
to single-node.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
The previous _distributed_block wording permitted "transient
single-node probes" inside the inner port-test loop. In practice
the agent exploited this loophole: after a PP2 launch failure, it
fell back to run_sglang_offline.py with pp_size=1 on a single node
to "make progress", then declared a verdict based on that local run.

That defeats the entire purpose of configuring worker_nodes — the
user asked for cross-node validation, and a single-node verdict
doesn't reflect whether the port actually works on the configured
topology.

Close the loophole:
  - Rephrase: EVERY framework launch (incl. diagnostic, smoke,
    boot-only) MUST span all workers while worker_nodes is set.
  - Explicitly forbid writing or invoking single-node launchers
    (run_*_offline.py with pp_size=1, etc.) while worker_nodes
    is configured.
  - Mandate the failure path: persistent cross-node failures must
    surface as outcome=logic_fail with cross-node evidence, NOT
    silently downgrade to single-node.
  - Mirror the prohibition in the single-worker case (no local
    orchestrator-side launches either).

Framework generality preserved: nothing in the prompt assumes a
specific PP/TP configuration — task-specific topology continues to
come from launch_constraints.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
Bug: register_worker was unconditional overwrite. A daemon started
with METAINFER_NODE_ID=worker21 on host worker25 would silently
overwrite the real worker21 record (hostname=worker21, ip=10.18.17.66)
with worker25's identity (hostname=worker25, ip=10.18.17.73). This
corrupted PP2 rendezvous (MASTER_ADDR resolved to the wrong host)
and scoreboard slot ownership maps.

The previous design assumed "node_id IS the truth" — whoever claims
a node_id owns it. That assumption fails when an operator mis-sets
METAINFER_NODE_ID via env or copy-paste. Identity must be anchored
to something the daemon can't lie about: the host it actually runs on.

Fix: register_worker now compares the new registration's hostname
against the existing record. If they differ, it refuses the overwrite
and writes a workers/<id>.conflict.<ts>.json sidecar with forensic
details. The worker daemon catches WorkerIdentityConflict at startup
and exits non-zero with a clear FATAL message, so the failure surfaces
in systemd / kubectl / the operator's terminal instead of silently
corrupting cluster state.

Recovery path for legitimate re-homing is preserved and explicit:
operator must delete workers/<id>.json first. This makes the
re-homing visible in filesystem history rather than silent.

Tests:
  - 3 new in test_worker_registry: hostname drift rejected, cold
    restart on same host allowed, explicit re-home after JSON delete
    allowed.
  - Updated test_sdk + test_daemon fixtures: removed redundant
    pre-registration that conflicted with FakeWorker.register().

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
The Live Agents panel previously showed only summary metadata (name,
role, phase, elapsed, last-output-age) — enough to see *that* an agent
was alive but not *what* it was doing. During long-running tasks the
operator couldn't tell whether an agent was productive or heading in
the wrong direction without SSHing in to read raw logs.

Each agent row is now expandable. Clicking fetches the agent's recent
stream-json activity (assistant text + tool_use calls + tool_result
summaries) via a new endpoint and renders it inline, auto-refreshing
every 5s while expanded. Falls back to raw .log tail if the
.events.jsonl sibling is missing.

Backend:
  - state_reader.read_agent_tail(state_dir, agent_name, max_events)
    parses the .events.jsonl, extracts the last N meaningful events
    (text blocks + tool_use names/inputs + tool_result briefs),
    skips system/meta lines. Returns found=False if agent isn't in
    the current agents.json snapshot (caller 404s).
  - GET /api/sys-shell/{task_id}/agents/{agent_name}/tail?max_events=N

Frontend:
  - api.getAgentTail(taskId, agentName)
  - AgentsPanel now takes a taskId prop and renders expandable rows
    via AgentRow + AgentTailRow. Polls tail every 5s while expanded.
  - Styles in styles.css for the expand cell, tail container, and
    per-event tags (text/tool/result) with distinct colors.

Tests: 5 new in test_state_reader.py covering missing agent, empty
log, structured parse, max_events cap, raw-log fallback. All 18
tests pass.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
The orchestrator subprocess inherits the WebUI's env, but if the WebUI
was started with cwd=root (no env var), paths.root_dir() in the child
re-captures cwd-at-import as state_dir — diverging from the WebUI and
from worker daemons started with an explicit METAINFER_ROOT. Sub-agents
then guess wrong fallback paths and write claims/inbox under the
install tree, where no worker ever sees them.

Pin METAINFER_ROOT=str(paths.root_dir()) at both layers:
  - launcher.start: orchestrator subprocess env
  - subagent_manager._build_env: ccb child env (belt-and-suspenders so
    agents never need os.environ.setdefault guessing)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
…time()

Liveness false-positive: validate_pid_started_at compares the pid
file's started_at against /proc/<pid>/stat field 22 (kernel start
ticks since boot). write_pid_file was writing time.time() at the
moment of the call — which lands 1–3s AFTER the kernel actually
forked the process (Python startup + orchestrator imports). When
that skew exceeded the 2s tolerance, the liveness scanner concluded
a live orchestrator was dead and reaped it: stamping finished_at,
flipping run.json to stopped, and freezing the WebUI.

Fix: read the actual kernel starttime via pid_start_time(os.getpid())
and write that. Now validate_pid_started_at compares two identical
sources → no skew, no false reap. The placeholder writer in
launcher.py is unchanged (its 2s tolerance covers spawn→write_pid_file
delay) but gets a clarifying comment.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
- Drop max_events from 50 → 10 so the panel shows the operator a
  glance-friendly "what's the agent doing right now" slice instead
  of a scrolling dump.
- Replace light-mode fallback (#fafafa on .agents-tail-row > td and
  #555 on .evt-tag.text) with the actual --bg-elev / --accent tokens
  so the expanded row blends with the rest of the dark UI instead
  of flashing white. Added a left border to the tail block for
  visual separation from the row above.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
… profiler analysis

Adds a new task type that profiles models across multiple batch sizes using
sglang's bench_one_batch_server with torch profiler, then analyzes the traces
for kernel hotspots, TFLOPS/MFU, operator-to-model-structure mapping, fuse
opportunities, and LLM-powered optimization hints.

5-phase linear pipeline: MAPPING -> BENCHMARK -> ANALYZE -> HINTS -> SUMMARIZE.

Design doc: docs/sglang_trace_analyze-design.md (grilled by architecture review).

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…table schema

- Wire structure_mapper and flops_calculator into pipeline ANALYZE phase
- Add all 17 design fields to kernel_table.json (model_layer, tflops_actual,
  mfu, bound, bandwidth_gb_s, input_dims, confidence)
- Fix classifier priority for HIP/CK kernel names (CK-GEMM, CustomAllReduce,
  MLA, MoE, ElementWise)
- Add CPU-op-based model layer inference fallback (no call stacks in trace)
- Extract CK GEMM tile dimensions (MT<N>x<N>x<N>) for FLOPs estimation
- Add 3-tab frontend: Summary Overview / Batch Detail / Optimization Hints
- Register detail_view_module + extra_stylesheets in WebPlugin
- Fix trace_parser to accept str paths (not just Path)

End-to-end verified: DeepSeek V4 INT8 TP8 BS=8 decode analysis on K100.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
Add --reasoning-parser deepseek-v4 and --tool-call-parser deepseekv4
to match upstream /workspace/sglang/scripts/run_traces.py params.
Without these, sglang may use incorrect model config parser on startup.

Verified: upstream run_traces.sh also SIGSEGVs with CUDA Graph ON on
K100 — this is a sglang fork bug, not a parameter mismatch.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
- Real _build_mapping: parse trace with CPU op correlation, call
  structure_mapper to classify all kernel→layer mappings
- Configurable profile steps in bench_config.json (not hardcoded 500/50)
- BENCHMARK failure is non-fatal: ANALYZE falls back to mapping traces
- ANALYZE auto-discovers traces in sglang timestamp subdirectories
- run_benchmark.py uses configurable profile_start_step/profile_steps

Verified: full 5-phase pipeline (MAPPING→BENCHMARK→ANALYZE→HINTS→
SUMMARIZE) completes with final_status=success even when formal
benchmark SIGSEGVs (sglang K100 fork CUDA Graph bug).

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…ph state

Always appended "graph" regardless of --disable-cuda-graph. Now uses
"nograph" for mapping runs, matching upstream run_traces.py behavior.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
vllm::cross_device_reduce_2stage_pcie is the TP allreduce kernel on
K100 HIP. Previously classified as Other (63.8% of GPU time with
CUDA Graph ON), now correctly classified as Reduce.

Verified: CUDA Graph bug fixed upstream, formal run produces traces.
GPU time drops from 7.09s (no graph) to 0.57s (graph ON, 12.4x),
throughput 5.63 → 19.71 tok/s (3.5x). Bottleneck shifts from
Reduce (71.9%) to GEMM (46.5%).

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
Previously required caller to source HIP/K100 environment variables
externally. Now _setup_env() applies them at startup, matching
/workspace/sglang/scripts/run_traces.sh exactly.

Key fixes:
- SGLANG_OPT_USE_HIP_INT8_SCALED_MM: true → 0
- Added SGLANG_OPT_USE_LMSLIM_INT8_QUANT=1
- Added SGLANG_OPT_USE_W8A8_MARLIN_GEMM=1

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…hart, search

Replace single-page layout with 3-tab dashboard:
- Dashboard: stat cards (GPU time, bottleneck %, MFU, CUDA Graph),
  CSS donut chart for category breakdown, bottleneck detail card,
  compute/memory bound visualization, overlap status, top kernels preview
- Kernel Table: search bar + category filter, all 11 columns with
  confidence badges, sortable and filterable
- Hints: bottleneck analysis with auto-generated suggestions,
  fuse pattern matches, AI optimization hints

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…e tiering

Kernel names that unambiguously identify op type (CK GEMM, flash_attn,
fused_moe, NCCL, w8a8, cross_device_reduce, topk radix/gather) now get
"high" confidence without requiring call stacks.

Result: 82.4% of GPU time covered by high-confidence mappings.
Low confidence restricted to generic elementwise/memory kernels (17.6%).

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
… fuse panels

Dashboard now includes six analysis sections:
- TFLOPS & Bandwidth table: actual vs theoretical peak per kernel
- Model Structure → Operator Mapping: layer↔kernel groupings with
  confidence distribution, showing which model layers produce which
  GPU operators
- Fuse Opportunities: rule-based pattern matches with estimated savings
- Inefficiency Radar: kernels with high time + low MFU ranked by waste
- Roofline Analysis: ops/byte vs ridge point visualization
- Category donut chart + Compute/Memory bound + Bottleneck detail

Mapping data fetched via /mapping API, confidence stats shown inline.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…om filename

- _find_trace_dir: search formal traces (bs_N/timestamp/) before
  mapping fallback, so ANALYZE uses CUDA Graph ON traces when available
- Detect CUDA Graph from trace filename (_graph_ vs _nograph_) instead
  of relying on gap count heuristic in overlap detector

Result: Dashboard shows CUDA Graph: ON (green) when formal traces
are used, OFF (red) only for mapping-only runs.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…ncy analysis

Dashboard additions:
- MFU Distribution: histogram across 7 buckets (0-5%, 5-10%, ..., 90-100%)
  with avg/median stats, showing how efficiently the GPU is used
- Top by Invocation Count: kernels ranked by call frequency, helping
  identify "death by a thousand cuts" patterns where many small
  invocations could be batched

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
…ing trace

- _merge_mapping_tflops: cross-reference formal trace kernel table with
  mapping trace (CUDA Graph OFF) to fill in tflops_actual, mfu, bound,
  bandwidth_gb_s per kernel by name matching
- Fix flops_calculator to preserve small TFLOPS values from CK GEMM tiles
- _is_formal_trace: detect CUDA Graph status from trace filename

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
Auto-generates 5 insight cards from analysis data:
- Dominant kernel alert (single kernel >30% GPU time)
- CUDA Graph status assessment
- Category concentration warning (>50% in one category)
- Top-3 kernels summary with category + time_pct
- MFU data availability note with actionable next step

Cards use icon + color coding (red/yellow/green) for quick scanning.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
- Replace LLM stub with rule-based hint generation from kernel table,
  overlap, and fuse data. Generates 2-5 suggestions with difficulty
  rating, estimated saving %, and category.
- Add executive summary banner at top of Dashboard: one-line summary
  of CUDA Graph status, bottleneck, and top optimization opportunities.
- Fix hint collection to use full kernel list (not just top-3) for
  accurate category aggregation.

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
@myrfy001 myrfy001 closed this Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants