-
Notifications
You must be signed in to change notification settings - Fork 3k
feat(review): require an executed witness on every confirmed Critical #9065
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
Changes from all commits
8c4df33
4855a8a
55ac5a2
b6e8f34
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 |
|---|---|---|
|
|
@@ -83,6 +83,13 @@ export interface Finding { | |
| shortSummary: string; | ||
| /** The concrete trigger and wrong outcome — the finding's evidence. */ | ||
| failureScenario: string; | ||
| /** | ||
| * The executed evidence that settled the verdict (a probe's two sides, an | ||
| * A/B's quoted pair, a sweep count) — or the verifier's | ||
| * `not run — <reason>` line. Carried as data so the report and the comment | ||
| * bodies quote one recorded string instead of transcribing it twice more. | ||
| */ | ||
| witness?: string; | ||
| suggestedFix?: string; | ||
| /** Free-form kebab-case tag (`correctness`, `security`, `test-coverage`, …). */ | ||
| category?: string; | ||
|
|
@@ -351,6 +358,11 @@ export function validateFindings(raw: unknown): Finding[] { | |
| const shortSummary = | ||
| asString(o, 'shortSummary') ?? asString(o, 'short_summary'); | ||
|
|
||
| // `witness` round-trips for the same reason `outcomeNote` does: the Step 4 | ||
| // witness rule attaches it once, and the report and the comment bodies read | ||
| // it back out of the artifact instead of transcribing the evidence again. | ||
| const witness = asString(o, 'witness'); | ||
|
|
||
| return { | ||
| id, | ||
| severity, | ||
|
|
@@ -361,6 +373,7 @@ export function validateFindings(raw: unknown): Finding[] { | |
| ? compressSummary(shortSummary) | ||
| : compressSummary(summary), | ||
| failureScenario, | ||
| ...(witness ? { witness } : {}), | ||
|
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] R1-3: The Web Shell artifact renderer — the documented second consumer of this artifact shape ( 中文说明[建议] R1-3:Web Shell 工件渲染器——该工件格式的、有文档记载的第二个消费者( — qwen3.8-max via Qwen Code /review (v0.21.11)
Collaborator
Author
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. Fixed in 4855a8a: |
||
| ...(asString(o, 'suggestedFix') || asString(o, 'suggested_fix') | ||
| ? { | ||
| suggestedFix: (asString(o, 'suggestedFix') ?? | ||
|
|
@@ -507,6 +520,45 @@ export function holdCriticalsFailingOnBase( | |
| return { findings: out, held, readjudicated }; | ||
| } | ||
|
|
||
| /** | ||
| * The witness rule's machine half. Step 4 demands that a confirmed Critical | ||
| * carry its executed evidence — the `witness` field, holding either the | ||
| * observed output or the verifier's `not run — <reason>` line — and promises | ||
| * the demotion is mechanical. This is the mechanism, in the same place the | ||
| * test-delta holdback lives: a high-confidence Critical from the one | ||
| * non-deterministic source that arrives with no witness is filed at low | ||
| * confidence — terminal-only, never posted. Only `source: 'review'` is | ||
| * judged: a `[build]`/`[test]`/`[lint]`/`[probe]` finding IS a run's output, | ||
| * so its witness is constitutive, not an attachment. Nothing is deleted and | ||
| * nothing is raised; the appended sentence names the rule that moved it and | ||
| * the way back (attach the witness, or say why none could run). Idempotent by | ||
| * construction — a demoted finding re-fed through `--input` is already low | ||
| * confidence and is not touched again. | ||
| */ | ||
| export function holdUnwitnessedCriticals(findings: readonly Finding[]): { | ||
| findings: Finding[]; | ||
| unwitnessed: string[]; | ||
| } { | ||
| const unwitnessed: string[] = []; | ||
| const out = findings.map((f) => { | ||
| if ( | ||
| f.severity !== 'Critical' || | ||
| f.confidence !== 'high' || | ||
| f.source !== 'review' || | ||
| f.witness !== undefined | ||
| ) { | ||
| return f; | ||
| } | ||
| unwitnessed.push(f.id); | ||
| return { | ||
| ...f, | ||
| confidence: 'low' as Confidence, | ||
| failureScenario: `${f.failureScenario}\n\nFiled at low confidence by the witness rule: this confirmed Critical arrived with neither a witness (the executed evidence that settled the verdict) nor a \`not run — <reason>\` line. Attach either and it stands at high confidence again.`, | ||
| }; | ||
| }); | ||
| return { findings: out, unwitnessed }; | ||
| } | ||
|
|
||
| const WORKSPACE_IN_COMMAND_RE = /--workspace="([^"]+)"/; | ||
|
|
||
| /** | ||
|
|
@@ -888,6 +940,8 @@ export const findingsCommand: CommandModule = { | |
| shared, | ||
| )); | ||
| } | ||
| const witnessHold = holdUnwitnessedCriticals(findings); | ||
| findings = witnessHold.findings; | ||
|
Comment on lines
+943
to
+944
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] Missing handler-level integration test for the witness rule — the Failure scenario: If the 中文说明建议 缺少 witness 规则的处理程序级别集成测试—— 失败场景:如果 — deepseek-v4-flash via Qwen Code /review (v0.21.10)
Collaborator
Author
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. Added in b6e8f34: the handler-boundary test feeds an unwitnessed Critical and a witnessed sibling through |
||
| const report = buildReport(findings); | ||
|
|
||
| const target = resolve(out); | ||
|
|
@@ -909,6 +963,14 @@ export const findingsCommand: CommandModule = { | |
| `findings: ${h.id} held back from Critical — test-delta measured ${h.file} as failing on the merge base too`, | ||
| ); | ||
| } | ||
| // The witness rule's demotions get the same disclosure: a confidence this | ||
| // command lowered must name the finding and the rule, or the demotion | ||
| // reads as the reviewer's own judgement. | ||
| for (const id of witnessHold.unwitnessed) { | ||
| writeStderrLine( | ||
| `findings: ${id} filed at low confidence — a confirmed Critical carried neither a witness nor a 'not run' reason (Step 4's witness rule)`, | ||
| ); | ||
| } | ||
| // A hold that was weighed and reversed is a decision, and a decision this | ||
| // command declined to overrule is exactly as reportable as one it made. | ||
| for (const r of readjudicated) { | ||
|
|
||
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] R1-1: The witness demotion is promised as mechanical — SKILL.md: "deliberately mechanical, the same shape as the
— [unverified]tag"; this file's verify brief: "This is mechanical downstream"; DESIGN.md: "the enforcement shape is borrowed from the— [unverified]tag" — but no code anywhere readswitness: the sort exists only as Step 4 prose for the orchestrating model. The precedent being borrowed HAS a machine half (compose-review scans the findings file for surviving— [unverified]tags, caps the verdict, and posts a disclosure count) that this change does not carry over;validateFindingsdefaults an omittedconfidencetohigh— the fail-open direction for this rule — and this same command already mechanically demotes Criticals via the test-delta holdback, so the pattern is local. — Failure scenario: a verifier confirms a Critical and argues in prose instead of returning awitness:/not run —line; the orchestrator, sorting findings against a ~1300-line SKILL.md, misses the demotion (or omitsconfidence, silently defaulted tohigh); nothing between Step 4 and Step 7 inspectswitness, so the unwitnessed Critical posts as a blocker without executed evidence — the exact failure mode this PR exists to prevent — with no count or telemetry showing whether the sort ran. Fix: enforce at the posting boundary — compose-review (besidefindings-unverified-at-compose) or the findings command counts/demotes witness-less high-confidence Criticals — or soften the "mechanical" / "borrowed enforcement shape" wording to name the orchestrator sort as the only enforcer.中文说明
[建议] witness 降级被承诺为机械执行——SKILL.md:"deliberately mechanical, the same shape as the
— [unverified]tag";verify brief:"This is mechanical downstream";DESIGN.md:"the enforcement shape is borrowed from the— [unverified]tag"——但没有任何代码读取witness:这个分检只存在于编排模型执行的 Step 4 文字里。被借用的先例有机器的一半(compose-review 会扫描 findings 文件中残留的— [unverified]标记、封顶裁决并发布披露计数),本改动没有带上这一半;validateFindings把缺省的confidence默认为high——对此规则是 fail-open 的方向——而同一个命令已经通过 test-delta 抑制机械地降级过 Critical,模式就在本地。失败场景:verifier 确认了一个 Critical 却用文字论证、没有返回witness:/not run —行;编排器在约 1300 行的 SKILL.md 背景下做分检时漏掉了降级(或没写confidence,被静默默认为high);Step 4 到 Step 7 之间没有任何东西检查witness,于是没有实测证据的 Critical 以 blocker 身份发布——正是本 PR 要防止的失效模式——且没有任何计数或遥测显示分检是否执行过。修复:在发布边界强制——compose-review(在findings-unverified-at-compose旁边)或 findings 命令统计并降级缺少 witness 的高置信 Critical;或者把 "mechanical" / "borrowed enforcement shape" 的措辞弱化为"编排器分检是唯一执行者"。— qwen3.8-max via Qwen Code /review (v0.21.11)
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.
Fixed in 4855a8a, at the boundary you named as local precedent:
qwen review findingsnow runsholdUnwitnessedCriticalsbeside the test-delta holdback — a high-confidence[review]-source Critical with nowitnessis demoted to low confidence at canonicalization, each named on stderr, and the appended sentence tells the reader which rule moved it and the way back. Deterministic sources are exempt (their witness is constitutive), and the hold is idempotent on re-feed. SKILL.md and DESIGN.md now describe the machine half instead of only promising one; acompose-review-level cap stays follow-up.(已修:findings 规范化处代码强制降级,逐条 stderr 披露;确定性来源豁免;重复喂入幂等。)