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/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` 钉住。 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"]]