From 6df74d25d3b5d2d755ff4a4673ef95a8b89d5665 Mon Sep 17 00:00:00 2001 From: tzhouam Date: Wed, 23 Sep 2026 11:27:00 +0800 Subject: [PATCH 1/2] Guide release transitions and CI attribution during rebase Teach live module and debug prompts to verify release pins together, audit adjacent upstream API contracts, and compare exact failure causes against recent main and branch builds. Keep parent-parity prompt goldens intact and document the operator handoff. Signed-off-by: tzhouam --- README.md | 12 ++++++ adapters/vllm_omni/rebase/prompt_data.yaml | 38 +++++++++++++++++-- .../templates/module_rebase.live.prompt.tmpl | 21 +++++++++- .../engine/steps/rebase_v3.py | 3 +- .../rebase_engine/module_rebase.py | 3 +- .../rebase_engine/prompt_builder.py | 3 ++ test/test_adapter_knowledge.py | 24 +++++++++--- 7 files changed, 93 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a106a979d..245778edb 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,18 @@ tip,即 tag `v0.28.0` = `2cf0a691`,并校验预编译 wheel 可用): 构建;对 schedule-only 流水线,按 adapter 声明 (`rebase.ci.ignore_branch_filters`)直接创建构建。 +**上游正式发版后的收尾**:冻结 release tag 的完整 SHA,核对 CI/生产镜像、 +ROCm/XPU 变体、Python 依赖范围和源码安装文档指向同一版本。仅在正式产物仍需要时 +保留候选版的临时 wheel/依赖修补;既有发布版示例维持其原配 vLLM 版本, +独立发版的平台 pin 要单独核实。模块导入检查 +不能证明所有构造函数和运行路径兼容:对照已安装的目标 vLLM API,审查 Omni 的 +override、必填输出字段、dummy/profile/capture 与异步输出转换,并用真实上游类写 +小型回归测试。远端 CI 只对精确提交下结论;按具体 traceback 和测试节点比较最近 +main/分支构建。如果 main 构建早于刚合入的改动,还要追溯该改动,再决定失败归属。 +延迟超阈值但正确性通过的结果单独记录并复测,不直接归为功能回归。 +合并目标仓库的最新 main 后,还要复核 PR review/comment 与安装文档;最终 +说明和 Buildkite 结果必须对应实际推送的同一个 commit。 + ## 快速上手 3 · 更新知识库 上游发版或目录变化后,用 `imupdate` 把**结构事实**(模型清单、registry、 diff --git a/adapters/vllm_omni/rebase/prompt_data.yaml b/adapters/vllm_omni/rebase/prompt_data.yaml index 1235a2eec..20b74de13 100644 --- a/adapters/vllm_omni/rebase/prompt_data.yaml +++ b/adapters/vllm_omni/rebase/prompt_data.yaml @@ -6,10 +6,42 @@ # doc/DRIFT_TRIAGE.md for the pre-cutover decision — do NOT "fix" one side # to match the other here. template: module_rebase.prompt.tmpl -# live variant: identical except the two prose references to the retired -# shell wrapper name imx-omni-pytest instead (recorded divergence — the -# parity template above stays parent-verbatim for the byte-equality pin) +# live variant: wrapper-name fixes plus release/API checks. The parity +# template above stays parent-verbatim for the byte-equality pin. template_live: module_rebase.live.prompt.tmpl +# Live debug guidance may evolve without changing the pinned parent-parity +# prompt/goldens. The old template remains the comparison fixture below. +debug_prompt_template_live: | + ## Debug: fix failing test for module `{module}` + + ### Test + {test_path} + + ### Traceback + ``` + {traceback} + ``` + + ### Your task + 1. Find the first causal traceback and every failed test in this job. Group + jobs by failure signature, not job label; one startup error can fail + several jobs, and one job can contain independent failures. + 2. Compare the exact traceback and test node with recent main and branch + builds when those logs are available. If main's last build predates a + merged main change, inspect that change before calling the failure a + rebase regression. Separate assertion failures, latency-only failures, + cancellation, and broken reporting steps. Record unknown attribution + when evidence is insufficient; do not weaken thresholds or skip tests. + 3. Read the target vLLM API and `git show origin/main:` for Omni intent. + Fix the smallest confirmed rebase-specific cause. After a startup API + fix, inspect adjacent constructor, override, result-field, dummy-run, + and async-output contracts that the first crash could have masked. + 4. Reproduce with a targeted test using the real upstream API when possible, + then run the owning suite. Report the exact validated commit and whether + a new remote CI build has reached a terminal result. + 5. Write MODULE_DONE {module} to the signal file only after verification. + + MODULE={module} # command template for PYTEST_COMMANDS / IMPORT_CHECK lines; goldens set this # to the parent's run_module_pytest.sh path to prove byte-parity, live runs diff --git a/adapters/vllm_omni/rebase/templates/module_rebase.live.prompt.tmpl b/adapters/vllm_omni/rebase/templates/module_rebase.live.prompt.tmpl index 2a5819950..b9ae783b4 100644 --- a/adapters/vllm_omni/rebase/templates/module_rebase.live.prompt.tmpl +++ b/adapters/vllm_omni/rebase/templates/module_rebase.live.prompt.tmpl @@ -22,6 +22,25 @@ Goal: make `{OMNI_FILES}` compatible with upstream while preserving vllm-omni in 7. **No-op fail-fast:** if output unchanged across **two** consecutive repair attempts, stop. 8. Repeated identical `TypeError` / ctor args on one stack → **one** kwargs/wiring fix, then re-verify. +## Release transition and adjacent API checks (live rebase) +- If the target is a published vLLM release, compare its tag SHA with the + commit-pinned wheel and container tags before retaining any temporary wheel, + torch/FlashInfer, or ABI repair block. Keep a repair only when the released + artifact still needs it. Check CI and production images, ROCm/XPU variants, + Python dependency bounds, and source-install docs as one version set. Keep + already published Omni/version examples paired with their historical vLLM; + leave separately released platform pins alone unless their matching release + exists. +- Import and signature checks do not exercise every override. For a changed + upstream class or `execute_model`/output path, compare *all* Omni constructors, + overridden method signatures, required result fields, and conversions with + the installed target API. Include dummy/profile/capture and async-output paths + before declaring a startup fix complete. Use a CPU regression against the + real upstream constructor or method, then run the owning test suite. +- When a test fixture bypasses `__init__`, initialize newly required fields in + that fixture to the real disabled-feature defaults. Do not add production + fallbacks solely to satisfy an incomplete mock. + **Engine / unpack:** Fix return-shape, kwargs, ordering at the real omni engine boundary; keep `shutdown` kwargs in sync with upstream. **Diffusion / subprocess:** `StageDiffusionProc died during handshake` → full worker traceback; handshake/init vs OOM; one controlled retry if GPU contention is plausible. @@ -265,4 +284,4 @@ OUT_OF_SCOPE_EDITS: If tests still fail after {MAX_DEBUG_RETRIES}, write a **detailed, self-contained** failure summary to: `{SIGNAL_DIR}/module.{MODULE_KEY}.fail` -and stop. The orchestrator reads this file to diagnose failures, so include: (a) the failing command and exit code, (b) last 20 lines of traceback/error output, (c) out-of-scope edits attempted (if any), and (d) remaining root cause. \ No newline at end of file +and stop. The orchestrator reads this file to diagnose failures, so include: (a) the failing command and exit code, (b) last 20 lines of traceback/error output, (c) out-of-scope edits attempted (if any), and (d) remaining root cause. diff --git a/src/infermatrix_copilot/engine/steps/rebase_v3.py b/src/infermatrix_copilot/engine/steps/rebase_v3.py index 5904481d8..5502c0907 100644 --- a/src/infermatrix_copilot/engine/steps/rebase_v3.py +++ b/src/infermatrix_copilot/engine/steps/rebase_v3.py @@ -1146,7 +1146,8 @@ async def _run_debug_agent(ctx: StepContext, manifest: dict, module: str, tools = build_rebase_tools( defs, paths, _build_backends(ctx, manifest, repo_root, target)) prompt = build_debug_prompt(module or slug, traceback_text, - data.debug_prompt_template, slug) + data.debug_prompt_template_live + or data.debug_prompt_template, slug) agent_log = ctx.run_dir / "agents" / f"debug-{slug}.log" agent_log.parent.mkdir(parents=True, exist_ok=True) ctx.trace.record("debug_attempt", slug=slug, module=module, diff --git a/src/infermatrix_copilot/rebase_engine/module_rebase.py b/src/infermatrix_copilot/rebase_engine/module_rebase.py index acaa89615..f1ff2da87 100644 --- a/src/infermatrix_copilot/rebase_engine/module_rebase.py +++ b/src/infermatrix_copilot/rebase_engine/module_rebase.py @@ -307,7 +307,8 @@ async def _attempt(p: str, *, require_plan_review: bool = True) -> dict: debug_attempts += 1 debug_prompt = build_debug_prompt( module, result.get("text", ""), - prompt_data.debug_prompt_template, "") + prompt_data.debug_prompt_template_live + or prompt_data.debug_prompt_template, "") result = await _attempt(debug_prompt, require_plan_review=not gate_passed) gate_passed = gate_passed or bool(result.get("plan_done")) diff --git a/src/infermatrix_copilot/rebase_engine/prompt_builder.py b/src/infermatrix_copilot/rebase_engine/prompt_builder.py index ba49a1049..30c9ee993 100644 --- a/src/infermatrix_copilot/rebase_engine/prompt_builder.py +++ b/src/infermatrix_copilot/rebase_engine/prompt_builder.py @@ -33,6 +33,7 @@ class ModulePromptData: template_live: str = "" pytest_wrapper_live: str = "" debug_prompt_template: str = "" + debug_prompt_template_live: str = "" module_vllm_paths: Mapping[str, str] = field(default_factory=dict) module_omni_files: Mapping[str, str] = field(default_factory=dict) module_test_map: Mapping[str, Sequence[str]] = field(default_factory=dict) @@ -49,6 +50,8 @@ def load(cls, rebase_data_dir: Path) -> "ModulePromptData": template_live=data.get("template_live", ""), pytest_wrapper_live=data.get("pytest_wrapper_live", ""), debug_prompt_template=data.get("debug_prompt_template", ""), + debug_prompt_template_live=data.get( + "debug_prompt_template_live", ""), module_vllm_paths=data.get("module_vllm_paths", {}), module_omni_files=data.get("module_omni_files", {}), module_test_map=data.get("module_test_map", {}), diff --git a/test/test_adapter_knowledge.py b/test/test_adapter_knowledge.py index 5aaf92258..b94b96a84 100644 --- a/test/test_adapter_knowledge.py +++ b/test/test_adapter_knowledge.py @@ -82,22 +82,35 @@ def test_debug_prompt_matches_parent_golden(): assert ours == (GOLDENS / "debug_prompt.txt").read_text() +def test_live_debug_prompt_carries_rebase_attribution(prompt_data): + live = build_debug_prompt( + "worker_runner", "TypeError: RopeState", + prompt_data.debug_prompt_template_live, "tests/worker_v2/test_state.py") + assert "TypeError: RopeState" in live + assert "failure signature" in live + assert "main's last build predates a" in live + assert "adjacent constructor, override, result-field" in live + + def test_templates_are_parent_verbatim(): - """Every shipped template byte-equals the parent's (they are DATA; any - edit belongs upstream of a fresh copy + golden refresh, not here).""" + """Parity templates match the parent; live additions are bounded.""" parent = Path("/data/zhoutaichang/copilot/vllm-omni-rebase-agent/agent/templates") if not parent.is_dir(): pytest.skip("parent checkout not present on this machine") for tmpl in sorted((REBASE_DATA / "templates").iterdir()): if ".live." in tmpl.name: - # the ONE recorded exception: the live variant differs from its - # parity sibling only in the wrapper-name prose (pinned below) + # Live guidance is intentionally outside the parent-parity pin. continue assert tmpl.read_bytes() == (parent / tmpl.name).read_bytes(), tmpl.name live = (REBASE_DATA / "templates" / "module_rebase.live.prompt.tmpl") parity = (REBASE_DATA / "templates" / "module_rebase.prompt.tmpl") + live_text = live.read_text() + start = live_text.index("## Release transition and adjacent API checks") + end = live_text.index("**Engine / unpack:**", start) + assert "real upstream constructor" in live_text[start:end] + without_live_guidance = live_text[:start] + live_text[end:] diff = [(a, b) for a, b in zip(parity.read_text().splitlines(), - live.read_text().splitlines()) if a != b] + without_live_guidance.splitlines()) if a != b] assert len(diff) == 2 assert all("imx-omni-pytest" in b and "run_module_pytest" in a for a, b in diff) @@ -385,6 +398,7 @@ def on_module_result(self, module, result): debug_req = retry_client.requests[2]["messages"][0]["content"] assert debug_req.startswith("## Debug: fix failing test for module") assert "half done, ran out of road" in debug_req + assert "failure signature" in debug_req # the debug turn ADVERTISED the gated tools (gate persisted as passed) assert "edit_file" in [x["name"] for x in retry_client.requests[2]["tools"]] From a9e433ea0a6a2d31ca51bf025baf696cc170137e Mon Sep 17 00:00:00 2001 From: tzhouam Date: Tue, 29 Sep 2026 09:44:56 +0800 Subject: [PATCH 2/2] Document the live debug prompt in the rebase specs The previous commit made both debug-agent call sites prefer the adapter's debug_prompt_template_live and fall back to the parent-parity template, but left the rebase_engine and engine/steps/rebase_v3 spec pages unverified, so check_spec_freshness --strict failed CI. Record the selection rule in both pages and re-verify them. Signed-off-by: tzhouam Co-Authored-By: Claude Opus 5.5 --- doc/architecture/SPEC/engine/steps/rebase_v3.md | 4 +++- doc/architecture/SPEC/rebase_engine.md | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/architecture/SPEC/engine/steps/rebase_v3.md b/doc/architecture/SPEC/engine/steps/rebase_v3.md index 840a68dee..37b6fa3ed 100644 --- a/doc/architecture/SPEC/engine/steps/rebase_v3.md +++ b/doc/architecture/SPEC/engine/steps/rebase_v3.md @@ -1,6 +1,6 @@ # engine/steps/rebase_v3.py —— 规范 - + `LOC ~2204 · step 库(v3 rebase 装配层) · refactor-status: oversized` @@ -60,6 +60,8 @@ step —— 薄的受治理 wrapper,substate-first、类型化失败、发布 unstaged+untracked 字节+mode+symlink)→ 复跑/本地验证 → patch policy;自动 patch 不得修改 assertion/tolerance,test 文件编辑必须有明确本地 passed。 被拒、验证失败或策略违规的尝试**回滚**。 +- debug agent 的 prompt 与 `rebase_module` 同源选择:`debug_prompt_template_live` + 优先,缺省回落 `debug_prompt_template`。 - 空/损坏 manifest ⇒ `manifest_empty`(push gate 阻塞,绝不空洞通过); 不可运行的命令归 STRUCTURAL —— 绝不借 bash rc=0 假通过。 - **A5**:一切仓库知识来自 adapter manifest;parity 词汇泄漏上限 14, diff --git a/doc/architecture/SPEC/rebase_engine.md b/doc/architecture/SPEC/rebase_engine.md index e4e154a34..e0365eafd 100644 --- a/doc/architecture/SPEC/rebase_engine.md +++ b/doc/architecture/SPEC/rebase_engine.md @@ -1,6 +1,6 @@ # rebase_engine/ —— 规范 - + `LOC ~7500(26 个模块) · repo-rebase-v3 的原生 rebase 引擎 · refactor-status: ok` @@ -31,7 +31,7 @@ | `path_sync.py` | 模块路径图同步 + manifest modules 段重写 + L2 决定应用 | | `phase1_steps.py` | phase-1 组合(归类 + 路径同步),父级报告文件名不变 | | `plan_review.py` | L4 计划评审后端(注入的 LLM client,父级形状的结果) | -| `prompt_builder.py` | 模块/调试 prompt 渲染 —— 等输入下与父级字节一致(golden 钉住) | +| `prompt_builder.py` | 模块/调试 prompt 渲染 —— 等输入下与父级字节一致(golden 钉住);`*_live` 变体不受 parity 钉 | | `push_gate.py` | 推送闸裁决:结构性 vs 断言失败的确定性分类(Rev 8 §2.3) | | `push_to_ci.py` | commit+push-to-CI 编排:preflight、WAL 卫生、C4 双闸、单一传输 | | `push_wal.py` | 推送 WAL:先落盘的 intent、精确 OID 三分对账、回滚数据 | @@ -98,6 +98,8 @@ runner/LLM/CI client 全部可注入 —— 每个模块都能离线测试。 坐标随 round 持久化,供恢复和审计使用。 - 自动 debug agent 不能修改 assertion/tolerance oracle;任何 test 文件编辑只有 在对应本地验证明确 passed 时才可进入远端重试。拒绝的尝试由调用方恢复快照。 +- 调试 prompt 优先用 adapter 的 `debug_prompt_template_live`,缺省才回落到父级 + `debug_prompt_template`;后者保持父级原文,作为 parity golden 的比较基准。 - **A5** —— 全包仓库中立:仓库值经 `WheelSpec`/`PinSpec`/`ManifestSpec`/ `ModulePromptData`/`tool_schemas.json`/hooks 注入;`test_repo_neutral_core` 钉住。