-
Notifications
You must be signed in to change notification settings - Fork 3k
docs(review): tell the agents drive and mock-provider exist, and how a fix's test earns its place #8369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs(review): tell the agents drive and mock-provider exist, and how a fix's test earns its place #8369
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -588,6 +588,22 @@ A finding an A/B settled carries \`Source: [probe]\` like any other run-produced | |||||
|
|
||||||
| It writes the \`run:\` script **verbatim** as an executable and reports what the runner would have supplied: the effective \`env:\` with all three levels merged and each key's level named, every \`\${{ … }}\` site listed **unevaluated** — that list is precisely what you have to stub, because the command refuses to invent values for it — the resolved \`shell\` and \`working-directory\`, and the commands the script invokes. Stubbing and input are yours: shim \`gh\`/\`curl\` onto \`PATH\`, export the env, run it, observe. **Combined with \`base-tree\`, a workflow A/B is two invocations** — extract the same step from both trees, feed both the same input, diff what each would have done. That is how the strongest workflow finding in this pipeline's history was produced: the real composer step from both arms, a stubbed \`gh\`, and a byte-for-byte comparison against a comment the workflow had actually posted. Three limits worth knowing before you spend the step: a \`uses:\` step has no \`run:\` and is refused rather than simulated; a step NAME that two steps in the job share is refused as ambiguous rather than resolved to the first, so pass the index (which is what an A/B wants anyway — the two trees must select the same step, and a name that moved between them is exactly how they stop doing that); and the \`invokes\` list is a labelled heuristic — the verbatim script beside it is the authority. | ||||||
|
|
||||||
| **When the claim is about what the product DOES at runtime, drive it — two commands make that mechanical.** A finding about behaviour ("this hangs when the provider 429s", "the retry never fires", "the daemon answers before it is ready") is settled by running the built product and watching, and the two halves that used to be hand-written every time are now commands. | ||||||
|
|
||||||
| \`\`\`bash | ||||||
| "\${QWEN_CODE_CLI:-qwen}" review mock-provider --responder <a module you write> \\ | ||||||
| --log <plan dir>/mock.jsonl --ttl 600 --out <plan dir>/mock.json & | ||||||
| until [ -s <plan dir>/mock.json ]; do sleep 0.1; done # its port is in that report | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The readiness wait uses fractional
Suggested change
中文说明就绪等待使用了小数 — qwen3.8-max-preview via Qwen Code /review |
||||||
| "\${QWEN_CODE_CLI:-qwen}" review drive --cwd <the worktree> --script <what to run> \\ | ||||||
|
wenshao marked this conversation as resolved.
|
||||||
| --ready <a command polled until it exits 0> --timeout 300 --out <plan dir>/drive.json | ||||||
| \`\`\` | ||||||
|
|
||||||
| \`mock-provider\` serves \`/v1/chat/completions\` (OpenAI) and \`/v1/messages\` (Anthropic) on an OS-assigned port it reports back, and appends every request to a JSONL log; your responder module exports \`respond(req)\` returning \`{text}\`, \`{tool, args}\` or \`{status, body}\`, and never has to get SSE framing right. **It serves for the whole \`--ttl\` and returns only when that expires** — so background it and wait, as above; run sequentially it is already shut down by the time the next line starts. Its report is written once the port is bound, which is what makes the file's appearance a readiness signal rather than a guess, and the TTL is the only thing that ends it — set it to bound the drive, not to match it. **The log is the A/B evidence** — drive the same script against the PR worktree and the \`base-tree\` path, then diff the two request sequences; a difference is evidence, a reading is not. | ||||||
|
|
||||||
| \`drive\` owns the three things that used to be guesswork, and its \`outcome\` is what you rule on, never the captured text alone: \`completed\` carries the script's own \`exitCode\` and is the only value that licenses a behavioural claim; \`not-ready\` means the readiness probe never passed, so **nothing was driven and nothing observed is evidence either way**; \`timed-out\` and \`overflowed\` mean the capture is PARTIAL — a partial capture is not evidence that the run produced nothing; \`unavailable\` (no tmux) is an environment gap and explicitly not a finding. Pass \`--ready\` for anything that binds a port: without it the drive starts immediately, and an empty capture reads as "the feature does not work" when it means "the daemon had not finished starting". | ||||||
|
|
||||||
| For anything that is not one of those two wires — the project's own HTTP service, an MCP server, an OAuth endpoint — stand it up yourself and let \`drive\` own the lifecycle. | ||||||
|
|
||||||
| **When the claim is about GITHUB's behaviour, neither tree can settle it — only GitHub can.** A claim like "this encoding renders identically and can never ping", "GitHub strips this tag", "this markdown shape closes the fold" is about the comment pipeline's parser, sanitizer allowlist and notification path, none of which exist in this environment — a local markdown library is a model of GitHub, and judging a sanitizer claim against a model of the authority is exactly the parser-divergence failure under review. Measured live: an \`@\` → \`@\` defusal read as sound in every local trace, and GitHub's real renderer registered the mention and fired the notification. So: | ||||||
|
|
||||||
| - **If the environment variable \`QWEN_REVIEW_SCRATCH_REPO\` is set** (an \`owner/repo\` the user designated for disposable test posts), you may adjudicate on the real renderer: post the payload as an issue comment there — \`gh api repos/$QWEN_REVIEW_SCRATCH_REPO/issues/<n>/comments -f body=@<file>\` against an issue you created there for this purpose — read it back with \`-H "Accept: application/vnd.github.html+json"\`, and rule on the returned HTML (and, for mention claims, the timeline events). The observation is the verdict; quote it. This is the ONLY write destination other than \`submit\`'s that any part of this review may touch, it is user-designated, and nothing about the PR under review, its code, or its authors may appear in what you post there — post the minimal payload shape, not the report. | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The documented
mock-providerreadiness wait has no failure escape hatch. If the responder module fails to load, or forgets to exportrespond,startMockProviderthrows beforeserver.listen(mock-provider.ts:492,497-500); the handler catches, writes one stderr line, setsexit 1, and never writes--out(mock-provider.ts:718-734). The backgrounded job dies in milliseconds, butuntil [ -s mock.json ]can never succeed, so the agent's shell step hangs until its tool timeout — with the only diagnostic (the stderr line) invisible, because the agent is polling a file, not watching the job. The adjacent claim "the TTL is the only thing that ends it" is also false on this path. — Failure scenario: a responder with a syntax error →startMockProviderthrows → no--outwritten → theuntilloop spins to the tool timeout with no visible error.A bounded, liveness-checked wait fails loud instead of hanging:
中文说明
文档里
mock-provider的就绪等待没有失败退出路径。如果 responder 模块加载失败,或忘记导出respond,startMockProvider会在server.listen之前 抛出异常(mock-provider.ts:492、497-500);handler 捕获后只写一行 stderr、置exit 1,并且永远不会写--out(mock-provider.ts:718-734)。后台进程几毫秒内就死了,但until [ -s mock.json ]永远无法成功,于是 agent 的 shell 步骤会一直挂到工具超时 —— 而唯一的诊断(那行 stderr)不可见,因为 agent 在轮询文件而非监视进程。旁边那句“TTL 是唯一能结束它的东西”在此路径下也不成立。— 失败场景:responder 有语法错误 →startMockProvider抛出 → 不写--out→until循环一直转到工具超时,且看不到任何错误。带边界、带存活检查的等待会大声失败而非挂起(见上方代码块)。— qwen3.8-max-preview via Qwen Code /review