@qwen-code/qwen-code 0.21.2 → 0.21.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/docs/configuration/settings.md +41 -38
- package/bundled/qc-helper/docs/features/channels/github.md +7 -0
- package/bundled/qc-helper/docs/features/channels/gitlab.md +6 -0
- package/bundled/qc-helper/docs/features/code-review.md +78 -23
- package/bundled/qc-helper/docs/features/commands.md +2 -0
- package/bundled/qc-helper/docs/features/hooks.md +115 -18
- package/bundled/qc-helper/docs/features/memory.md +27 -0
- package/bundled/qc-helper/docs/features/skills.md +46 -1
- package/bundled/qc-helper/docs/features/sub-agents.md +42 -9
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +7 -7
- package/bundled/qc-helper/docs/qwen-serve.md +21 -1
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +13 -13
- package/bundled/qc-helper/docs/support/troubleshooting.md +6 -1
- package/bundled/review/DESIGN.md +167 -32
- package/bundled/review/SKILL.md +156 -32
- package/chunks/{MaxSizedBox-TQBQ247P.js → MaxSizedBox-OJR636GP.js} +40 -38
- package/chunks/{StandaloneSessionPicker-2HPTKCLX.js → StandaloneSessionPicker-AMMBF5UY.js} +62 -59
- package/chunks/{acp-startup-profiler-2C4A5ZTJ.js → acp-startup-profiler-3RICG2YW.js} +2 -2
- package/chunks/{acpAgent-PS6EDGH3.js → acpAgent-M57LVIQA.js} +662 -560
- package/chunks/{agent-VDOUB35F.js → agent-PE37ARLM.js} +36 -34
- package/chunks/{agent-headless-EO53EFS2.js → agent-headless-45ASME4R.js} +36 -34
- package/chunks/{anthropicContentGenerator-OFHSZJBF.js → anthropicContentGenerator-WCBYB6JG.js} +337 -27
- package/chunks/{artifact-tool-RDN2W7ND.js → artifact-tool-TBOYEKTY.js} +2 -2
- package/chunks/{askUserQuestion-OZERWH5R.js → askUserQuestion-23Y5WZFJ.js} +2 -2
- package/chunks/{bridge-W7AZSRZQ.js → bridge-K3ZRPO4D.js} +42 -40
- package/chunks/{ca-6W3SK7OQ.js → ca-4OJN75WT.js} +46 -5
- package/chunks/{channel-management-service-5S7YCWX5.js → channel-management-service-IXJ2MZTS.js} +7 -7
- package/chunks/{channel-settings-store-JFVRSNER.js → channel-settings-store-PEAR3IME.js} +43 -41
- package/chunks/{channel-worker-group-OVWGYMZS.js → channel-worker-group-NDG4WOOZ.js} +8 -8
- package/chunks/{channel-worker-manager-H55GKOQA.js → channel-worker-manager-ZCW6UW34.js} +8 -8
- package/chunks/{channel-worker-supervisor-CABBXYHK.js → channel-worker-supervisor-ATGFTZRN.js} +4 -4
- package/chunks/{chunk-W3UKBMSI.js → chunk-22YFMJBW.js} +84 -8
- package/chunks/{chunk-6MPDY6ZG.js → chunk-24ER7UV4.js} +1 -1
- package/chunks/{chunk-QDK4F2N5.js → chunk-2DNKEBXY.js} +1 -1
- package/chunks/{chunk-D6MDRSZ6.js → chunk-2LZCLQIS.js} +22 -11
- package/chunks/{chunk-JYBU6YUE.js → chunk-2M5N3DHY.js} +1 -1
- package/chunks/{chunk-KR32NIAN.js → chunk-2MI7ZTRT.js} +10 -10
- package/chunks/{chunk-LHKCY7DY.js → chunk-2UISUFHQ.js} +3 -3
- package/chunks/{chunk-JXVC2PL3.js → chunk-33FNCQSY.js} +2 -2
- package/chunks/{chunk-NBD76HUW.js → chunk-3LGZEYOF.js} +2 -2
- package/chunks/{chunk-CO2U743O.js → chunk-3MWNROHB.js} +4 -4
- package/chunks/{chunk-E2BHWIDT.js → chunk-3RXUYQJI.js} +6 -2
- package/chunks/{chunk-E5Z2AVNV.js → chunk-3SH53ANB.js} +0 -11
- package/chunks/{chunk-LYI2PZDK.js → chunk-3XF4WT3B.js} +2 -2
- package/chunks/{chunk-N4ACHWNH.js → chunk-432XCUHF.js} +1 -1
- package/chunks/{chunk-FNDXMN7I.js → chunk-4AGGSHCH.js} +774 -205
- package/chunks/{chunk-DUNI4EBW.js → chunk-4K3RV3OA.js} +80 -50
- package/chunks/{chunk-L2E5GFAG.js → chunk-4LKVQFHM.js} +2 -2
- package/chunks/{chunk-YDLJGZHL.js → chunk-4NFY2S7N.js} +0 -33
- package/chunks/{chunk-JLZ3RBQG.js → chunk-5JPVOYWA.js} +144 -11
- package/chunks/{chunk-6TAASXWL.js → chunk-5VYFXHY2.js} +3 -3
- package/chunks/{chunk-EU5TBFJI.js → chunk-6NE5NTHJ.js} +2 -2
- package/chunks/{chunk-XQK4XXTN.js → chunk-6O5DVH27.js} +1 -1
- package/chunks/{chunk-2RFKHEXL.js → chunk-6PLDPT2C.js} +1 -1
- package/chunks/{chunk-3APUUXRF.js → chunk-A5YZ3FA2.js} +2 -1
- package/chunks/{chunk-SHN4KHDK.js → chunk-A6SX5TAH.js} +3 -3
- package/chunks/{chunk-SZ3KHTDR.js → chunk-AKA24BGO.js} +1 -1
- package/chunks/{chunk-Q3T5KA2V.js → chunk-BFHXDAR7.js} +1 -1
- package/chunks/{chunk-L55JWS76.js → chunk-BGXZBI5B.js} +1 -1
- package/chunks/{chunk-P5VC5USY.js → chunk-BKGA75MU.js} +1 -1
- package/chunks/{chunk-2KKCCLPT.js → chunk-BKXTHMOZ.js} +1 -1
- package/chunks/{chunk-V4XNUDPE.js → chunk-BSKUTHLO.js} +15 -7
- package/chunks/{chunk-MM7TH7ZM.js → chunk-CFDR3GNL.js} +18 -3
- package/chunks/{chunk-E2FN6SM7.js → chunk-CIUUYB23.js} +5 -5
- package/chunks/{chunk-A7Y5H4TX.js → chunk-D2GPKXCQ.js} +7 -7
- package/chunks/{chunk-JCJ7LKNA.js → chunk-DIEFUBV6.js} +1644 -1570
- package/chunks/{chunk-GL4JOZXU.js → chunk-DSGJLHM3.js} +4 -4
- package/chunks/{chunk-675H6PLP.js → chunk-DYA25Y7U.js} +1 -1
- package/chunks/{chunk-3I6DUGQD.js → chunk-E4WHKETF.js} +32 -4
- package/chunks/{chunk-CU47KXB5.js → chunk-EGYJRIDF.js} +6 -6
- package/chunks/{chunk-6CQWRWUC.js → chunk-EIMKVOSF.js} +3 -3
- package/chunks/{chunk-QTERJVPZ.js → chunk-EKTCKZV5.js} +1 -0
- package/chunks/{chunk-NHFEMWAZ.js → chunk-FF75UUB2.js} +1 -1
- package/chunks/{chunk-L32VV3ZJ.js → chunk-FG63DZQA.js} +12 -12
- package/chunks/{chunk-FCYYAB4S.js → chunk-FHPKHXHT.js} +3 -3
- package/chunks/{chunk-GJ2GBPBD.js → chunk-FXVHVCNA.js} +5 -5
- package/chunks/{chunk-56Z7QEAQ.js → chunk-GMSBXEH4.js} +16 -16
- package/chunks/chunk-GOFAQQZA.js +132 -0
- package/chunks/{chunk-YUFIEIWC.js → chunk-GTM6IHBB.js} +2 -2
- package/chunks/{chunk-HIVKI6O6.js → chunk-H35Q5CEG.js} +9 -7
- package/chunks/{chunk-FJ5WUMUQ.js → chunk-H36SETQS.js} +1 -1
- package/chunks/{chunk-AUOULH6Q.js → chunk-H6FIBBXK.js} +1610 -2196
- package/chunks/{chunk-VEMNQMHA.js → chunk-H6ZYP74A.js} +5 -13
- package/chunks/{chunk-TTJZAIFP.js → chunk-HEBW74ZW.js} +3 -3
- package/chunks/{chunk-6FMJLI5M.js → chunk-HFVW54NL.js} +41 -6
- package/chunks/{chunk-44F4LBWZ.js → chunk-HIXVWF7I.js} +56 -18
- package/chunks/{chunk-EQNUDTL6.js → chunk-HUIQ4FYC.js} +2 -2
- package/chunks/{chunk-5NNHICSA.js → chunk-I7JDGNG6.js} +3 -3
- package/chunks/{chunk-PVNQRENX.js → chunk-IF6K42YJ.js} +1 -1
- package/chunks/{chunk-PJOHNFIY.js → chunk-IWGTGH4G.js} +5 -5
- package/chunks/{chunk-B4AJNNOL.js → chunk-J26HHFI5.js} +1 -1
- package/chunks/{chunk-CNTR4GR6.js → chunk-JELIWHXD.js} +1 -1
- package/chunks/{chunk-V25K5ID7.js → chunk-K2J5JZ6B.js} +1 -1
- package/chunks/{chunk-IGTHU3T4.js → chunk-KKN2IE7Q.js} +1 -1
- package/chunks/{chunk-TZTAV5RH.js → chunk-KVUBYJDM.js} +2 -2
- package/chunks/{chunk-3F2WDAV6.js → chunk-KXWERR6P.js} +14 -14
- package/chunks/{chunk-JJPKFJBT.js → chunk-L7FTDKCD.js} +3 -3
- package/chunks/chunk-LBOVL47Y.js +29 -0
- package/chunks/{chunk-FS674JW4.js → chunk-LBWNSLJK.js} +3 -3
- package/chunks/{chunk-I5BT7ADR.js → chunk-LGT3YMLN.js} +4 -4
- package/chunks/{chunk-UV6KF7T3.js → chunk-LZV2BZPL.js} +3 -3
- package/chunks/{chunk-P755N4CS.js → chunk-M5LIY7Y6.js} +6 -6
- package/chunks/{chunk-YGE3IXJP.js → chunk-M744OFVE.js} +1 -1
- package/chunks/{chunk-NTDH4IML.js → chunk-MCXMWLFT.js} +7 -7
- package/chunks/chunk-MISUEWB4.js +8749 -0
- package/chunks/{chunk-TEGJSJDF.js → chunk-MOHAWIAW.js} +2 -2
- package/chunks/{chunk-KXDONCPU.js → chunk-MTR4JWQJ.js} +4 -4
- package/chunks/{chunk-RSVPYAGK.js → chunk-MUEJ4R3E.js} +5 -5
- package/chunks/{chunk-PCK4B6LR.js → chunk-N42C2FU3.js} +1 -1
- package/chunks/{chunk-WWCMSZII.js → chunk-NW57GHNL.js} +71 -7
- package/chunks/{chunk-PQNHRFJC.js → chunk-NYX53SV4.js} +0 -2
- package/chunks/{chunk-QARJNL2V.js → chunk-O2ZYHG33.js} +5 -4
- package/chunks/{chunk-V7RNNPGC.js → chunk-P5Y23G2L.js} +18 -1
- package/chunks/{chunk-GURGAJTX.js → chunk-PDDYAXL2.js} +4 -1
- package/chunks/chunk-PWCQRLM5.js +1170 -0
- package/chunks/{chunk-VMX5RZQH.js → chunk-Q3G5L5KF.js} +18 -9
- package/chunks/{chunk-DQ2O5QOJ.js → chunk-QDWLUXKP.js} +1 -1
- package/chunks/chunk-QL4TN4HS.js +59 -0
- package/chunks/{chunk-E6CJ2SMM.js → chunk-QMBEW7EW.js} +2 -2
- package/chunks/{chunk-U4VTUMMK.js → chunk-QONSRAEV.js} +1 -1
- package/chunks/{chunk-DEEABGH2.js → chunk-QPSYIV2O.js} +3320 -536
- package/chunks/{chunk-Q5WZTTWE.js → chunk-QWDVZH24.js} +6 -8
- package/chunks/{chunk-2LEOZTBT.js → chunk-QWW6I2UO.js} +111 -26
- package/chunks/{chunk-LOY7RWQG.js → chunk-QYPT3QUD.js} +3 -3
- package/chunks/{chunk-6PQPKTXP.js → chunk-R7XNRHYD.js} +1 -1
- package/chunks/{chunk-7SJN2IWT.js → chunk-RCXCGZG6.js} +5 -5
- package/chunks/{chunk-HX6RLYUO.js → chunk-RL6J3BPE.js} +4 -4
- package/chunks/{chunk-Z3S5EMOW.js → chunk-RPYYTL7E.js} +60 -12
- package/chunks/{chunk-MB32MS4U.js → chunk-RR224BUP.js} +215 -174
- package/chunks/{chunk-H6I4PGRV.js → chunk-SKSF3LGQ.js} +4 -4
- package/chunks/{chunk-77V3VIKL.js → chunk-SQ3YD5MI.js} +9 -9
- package/chunks/{chunk-CBBP4BMC.js → chunk-SRY26X4H.js} +72 -206
- package/chunks/{chunk-RDJOB6S3.js → chunk-TXABHVZD.js} +1 -1
- package/chunks/{chunk-R2XWGR75.js → chunk-TYERNYH4.js} +2 -2
- package/chunks/chunk-TZTBZ25J.js +222 -0
- package/chunks/{chunk-45IOTAUS.js → chunk-U25CMJYY.js} +1 -1
- package/chunks/{chunk-7ULQIS27.js → chunk-UEJESCS7.js} +1 -1
- package/chunks/{chunk-HC45LTEN.js → chunk-UH7Z7Y45.js} +1 -1
- package/chunks/{chunk-CPZAH673.js → chunk-UKZEXS6K.js} +2 -0
- package/chunks/{chunk-54YCNSK5.js → chunk-UQDFEU47.js} +4113 -10152
- package/chunks/{chunk-XP4L6KS3.js → chunk-URN76TKR.js} +2 -2
- package/chunks/{chunk-XUGZYLDH.js → chunk-UWSXFI6E.js} +1 -1
- package/chunks/{chunk-AOHY3QJ3.js → chunk-VA5NLVPT.js} +3 -3
- package/chunks/{chunk-PZEXDV3H.js → chunk-VUNRNRN6.js} +71 -43
- package/chunks/{chunk-FANRZEAJ.js → chunk-VWOVHOTT.js} +1 -1
- package/chunks/{chunk-QTHQ6Z5X.js → chunk-WK4TJUEA.js} +1 -1
- package/chunks/{chunk-ZPZ7ZJEE.js → chunk-WUC6ZFXO.js} +1 -1
- package/chunks/{chunk-7KAXXBER.js → chunk-WY2ENRDN.js} +3 -3
- package/chunks/{chunk-TIRRPCFS.js → chunk-X6QNZOTC.js} +1 -1
- package/chunks/{chunk-KWHKHSIS.js → chunk-X6WUYMOV.js} +8 -8
- package/chunks/{chunk-IIUGIWWY.js → chunk-XC2VAFVZ.js} +1 -1
- package/chunks/{chunk-D4HTUMGX.js → chunk-XC656O42.js} +3 -3
- package/chunks/{chunk-RG64CDT2.js → chunk-XMJO6C44.js} +131 -48
- package/chunks/{chunk-ZMOJ7ISP.js → chunk-XUMAD5IT.js} +1 -1
- package/chunks/{chunk-THVU3RNH.js → chunk-YAVY33G4.js} +1 -1
- package/chunks/{chunk-YANIWTRZ.js → chunk-YPUHMQXV.js} +1 -1
- package/chunks/{chunk-QCXGC7QB.js → chunk-YU6TBRTA.js} +3 -3
- package/chunks/{chunk-OFZKFPYG.js → chunk-YWMDTMAU.js} +3 -3
- package/chunks/{chunk-DSFHVTWD.js → chunk-YXEVDA66.js} +2 -2
- package/chunks/{chunk-JE2CEOBO.js → chunk-ZGSUFIL5.js} +4 -4
- package/chunks/{chunk-BBIQAX4V.js → chunk-ZJES4C3I.js} +30 -18
- package/chunks/{computer-use-5QWCFNKD.js → computer-use-UJMK6JQU.js} +36 -34
- package/chunks/{config-utils-WADIDWGG.js → config-utils-7COTJMWK.js} +4 -4
- package/chunks/{contextCommand-4Z7T7TUM.js → contextCommand-4YABGF4S.js} +40 -38
- package/chunks/{core-runtime-6N4EFC2Q.js → core-runtime-7M4VM3DA.js} +36 -34
- package/chunks/{create-sub-session-AEREHZBQ.js → create-sub-session-HOFDW4N7.js} +39 -37
- package/chunks/{create-sub-session-62YZWVAY.js → create-sub-session-J32WC64U.js} +2 -2
- package/chunks/{cron-create-6E7GIQTG.js → cron-create-HMFSHIAR.js} +4 -4
- package/chunks/{cron-delete-JD26XY3W.js → cron-delete-ZJFHOX57.js} +4 -4
- package/chunks/{cron-list-CUWFB44G.js → cron-list-ZEX2NBMN.js} +4 -4
- package/chunks/{daemon-PCNCI5YU.js → daemon-CCIX4BMG.js} +47 -6
- package/chunks/{daemon-status-provider-DDF7C5M7.js → daemon-status-provider-W2U5Q3J5.js} +47 -45
- package/chunks/{daemon-trust-policy-Q4KSOJTR.js → daemon-trust-policy-IFICWPXP.js} +42 -40
- package/chunks/{daemon-trust-policy-monitor-V6FTE3IY.js → daemon-trust-policy-monitor-GX7EO6FW.js} +42 -40
- package/chunks/{de-SY6O76BF.js → de-A6TI4LBB.js} +46 -5
- package/chunks/{deferred-core-runtime-GHJ5GQHK.js → deferred-core-runtime-U36OOOKE.js} +36 -34
- package/chunks/display-image-VS3TXYQH.js +184 -0
- package/chunks/{dist-ZHXOBXDN.js → dist-3BMEUGTG.js} +1 -1
- package/chunks/{dist-26BIMQT6.js → dist-4KAX7CCL.js} +289 -27
- package/chunks/{dist-OAOC5OV4.js → dist-7JGAAQSC.js} +2 -2
- package/chunks/{dist-SL2LUMML.js → dist-A7H2KKUC.js} +1 -1
- package/chunks/{dist-2PERFI23.js → dist-DPPHJAVL.js} +3 -3
- package/chunks/{dist-PVEAFLHY.js → dist-HVBMEYWK.js} +1 -1
- package/chunks/{dist-ULIG4M5H.js → dist-NEBRI7WO.js} +67 -15
- package/chunks/{dist-WGMNT3JQ.js → dist-SFQ34F4M.js} +24 -6
- package/chunks/{earlyInputCapture-TQXLLISD.js → earlyInputCapture-5ZWDH3SB.js} +37 -35
- package/chunks/{edit-FJEUV6KZ.js → edit-J7SW6UP6.js} +36 -34
- package/chunks/{en-NBK3JKCE.js → en-L4UQDLWW.js} +57 -6
- package/chunks/{enter-worktree-7GE3TZ4P.js → enter-worktree-NRLOHRB6.js} +36 -34
- package/chunks/{enterPlanMode-KR5TMPCJ.js → enterPlanMode-GDSTEFSM.js} +36 -34
- package/chunks/{environment-SWL3CMB3.js → environment-KHYEKG5W.js} +39 -37
- package/chunks/{errors-XQE7BGZV.js → errors-VNLAJV3O.js} +39 -37
- package/chunks/{exit-worktree-CHKTYNCV.js → exit-worktree-ARVID7DF.js} +36 -34
- package/chunks/{exitPlanMode-QYAG6LWX.js → exitPlanMode-4ZFY7KUH.js} +36 -34
- package/chunks/{fast-path-Z2K7W6DC.js → fast-path-KA65VREJ.js} +9 -5
- package/chunks/{fr-4KG5V7UT.js → fr-QF7RI5ZE.js} +46 -5
- package/chunks/{gemini-YU4XKEDG.js → gemini-5PMCNPF7.js} +149 -90
- package/chunks/{geminiContentGenerator-ZZX6NBO4.js → geminiContentGenerator-NFSYJ4HA.js} +6 -6
- package/chunks/{glob-VYF5CXSX.js → glob-F3EAUDAX.js} +36 -34
- package/chunks/{goal-tools-HGO6VXPB.js → goal-tools-SPQ5M6D3.js} +3 -3
- package/chunks/{grep-5DP5ZUTW.js → grep-UJMPVZER.js} +36 -34
- package/chunks/{handleAutoUpdate-UVBJ56DL.js → handleAutoUpdate-MG4FRZPN.js} +42 -40
- package/chunks/{i18n-UQNYHEUD.js → i18n-EVHV4ZF3.js} +38 -36
- package/chunks/{image-gen-WHPIZNWF.js → image-gen-UC7XVHI7.js} +9 -9
- package/chunks/{initializer-GMIICF4W.js → initializer-O5B6HUBI.js} +43 -41
- package/chunks/{installationInfo-4MGG4WVI.js → installationInfo-2LIKCNVX.js} +37 -35
- package/chunks/{ja-F3GSQXMF.js → ja-URQESVGW.js} +46 -5
- package/chunks/{keychain-token-storage-IKO4G53C.js → keychain-token-storage-7BT4TQ2A.js} +2 -2
- package/chunks/{kittyProtocolDetector-MBRTDRBK.js → kittyProtocolDetector-BFLAKYXH.js} +1 -1
- package/chunks/{list-CPN2W334.js → list-BPKIE3Z4.js} +45 -43
- package/chunks/{list-agents-PXJ7ZUFB.js → list-agents-TWEGRJWO.js} +2 -2
- package/chunks/{loadedSettingsAdapter-ZQAV5NDO.js → loadedSettingsAdapter-NGLFF4V4.js} +42 -40
- package/chunks/{loggingContentGenerator-5E7W4IEP.js → loggingContentGenerator-7TFESRG5.js} +52 -37
- package/chunks/{loop-wakeup-Y26NQZ5I.js → loop-wakeup-6LLEOQYV.js} +5 -5
- package/chunks/{ls-ONQTTMQR.js → ls-H5WX22VK.js} +4 -4
- package/chunks/{lsp-YGHHRGMD.js → lsp-G6FXYEIS.js} +2 -2
- package/chunks/{managed-npm-update-MKKAXYXA.js → managed-npm-update-CLZGGV7F.js} +39 -37
- package/chunks/{mcp-V5NTJF6X.js → mcp-X5OZOOXX.js} +42 -40
- package/chunks/{monitor-CO3ASY6E.js → monitor-TGSVSAZZ.js} +36 -34
- package/chunks/nonInteractiveCli-GUMJ5JLG.js +150 -0
- package/chunks/{notebook-edit-Z7AEE6FM.js → notebook-edit-EZISE7IC.js} +36 -34
- package/chunks/{openaiContentGenerator-CA3MQOP3.js → openaiContentGenerator-ZAKS5A6P.js} +18 -18
- package/chunks/{pidfile-NL7MKDRU.js → pidfile-PCMBX4LR.js} +37 -35
- package/chunks/{processUtils-PB5K2DYH.js → processUtils-2CSVE5BW.js} +2 -2
- package/chunks/{pt-EQ33KWEN.js → pt-EEEQXRUI.js} +46 -5
- package/chunks/{qwenContentGenerator-JYFNDCOS.js → qwenContentGenerator-S3H6PIC4.js} +42 -40
- package/chunks/{qwenOAuth2-W2ALKQDD.js → qwenOAuth2-MNU425VE.js} +8 -8
- package/chunks/{read-file-IEOR5H5W.js → read-file-HXJXHBI6.js} +10 -10
- package/chunks/{read-mcp-resource-U2IJN5HM.js → read-mcp-resource-DRZSI3HE.js} +2 -2
- package/chunks/{record-artifact-MGPJ7EG4.js → record-artifact-IPIRWMFY.js} +3 -3
- package/chunks/{resumeHistoryUtils-BNBTP5AS.js → resumeHistoryUtils-4QAMC2S6.js} +44 -42
- package/chunks/{ripGrep-UMQODKEB.js → ripGrep-MCETPF2E.js} +36 -34
- package/chunks/{ru-7OZAUKGG.js → ru-WGZDYQAB.js} +46 -5
- package/chunks/{run-qwen-serve-RN2R6QQW.js → run-qwen-serve-3NMODTXV.js} +219 -55
- package/chunks/{runtime-QFJ2MJF5.js → runtime-AQOV7DVP.js} +49 -45
- package/chunks/{scheduler-AMYUFOZI.js → scheduler-DN7SZ6ZE.js} +36 -34
- package/chunks/{sdk-exporters-http-4BQANSJ6.js → sdk-exporters-http-IKNWQJNV.js} +2 -2
- package/chunks/{sdk-impl-Z4VXWVFX.js → sdk-impl-7CUUMQDB.js} +2 -2
- package/chunks/{send-message-PMP4ATVM.js → send-message-HGCVVDTZ.js} +5 -4
- package/chunks/{serve-EIIYJVX3.js → serve-WZB45HVT.js} +42 -40
- package/chunks/{server-EP2LLAPD.js → server-GOTZFEEZ.js} +616 -387
- package/chunks/{session-GMPZBLOW.js → session-23LOFLWN.js} +149 -87
- package/chunks/{settings-LN7RNKBS.js → settings-LI2ORVXC.js} +41 -39
- package/chunks/{shell-EM2OWU5X.js → shell-GLC6OP3C.js} +36 -34
- package/chunks/{skill-T5VPSK73.js → skill-C7W6M4GO.js} +27 -14
- package/chunks/{skill-settings-GMR3GMNY.js → skill-settings-W25NCK5I.js} +41 -39
- package/chunks/{spawnChannel-YPCU62DI.js → spawnChannel-OHJLEBLD.js} +38 -36
- package/chunks/{standalone-update-JAKIM2NF.js → standalone-update-E4V5V7WT.js} +39 -37
- package/chunks/{startInteractiveUI-YETQWGYF.js → startInteractiveUI-FKILLW7Q.js} +1815 -1034
- package/chunks/{syntheticOutput-D7E6ZFKR.js → syntheticOutput-EYL7DWO7.js} +3 -3
- package/chunks/{task-create-NFCYD43L.js → task-create-CSCEG4SM.js} +10 -9
- package/chunks/{task-list-TAVMGEVD.js → task-list-6CVQPORX.js} +6 -6
- package/chunks/{task-stop-ZDF2UJRM.js → task-stop-Y5ZTFVRX.js} +2 -2
- package/chunks/{task-update-6L7LHGEX.js → task-update-C52LNFU5.js} +10 -9
- package/chunks/{team-create-LFJ6HGNY.js → team-create-HBIJ7NHT.js} +36 -34
- package/chunks/{team-delete-DPGGRQBU.js → team-delete-CE7DC53R.js} +6 -6
- package/chunks/{team-plan-approval-C2KLSDGO.js → team-plan-approval-IBJOKS4J.js} +36 -34
- package/chunks/terminal-image-renderer-BOQJPVLB.js +89 -0
- package/chunks/{theme-manager-JQ3ZGBP5.js → theme-manager-NSS7VLUD.js} +37 -35
- package/chunks/{todoWrite-2UO5G6G6.js → todoWrite-YKAA57W2.js} +107 -36
- package/chunks/{tool-search-FAZBFRJZ.js → tool-search-DEAS54VG.js} +13 -12
- package/chunks/{total-session-admission-5CALIVYO.js → total-session-admission-4LWTX3WD.js} +43 -41
- package/chunks/{trustedFolders-KOPSP44S.js → trustedFolders-NF3J2TA7.js} +38 -36
- package/chunks/{update-relaunch-6QL2TICS.js → update-relaunch-WUHRH5V3.js} +5 -5
- package/chunks/{updateCheck-4Q6RIKFW.js → updateCheck-7EG4BLBH.js} +41 -39
- package/chunks/{useAutoAcceptIndicator-Q5BMKZV3.js → useAutoAcceptIndicator-ZRV56GVP.js} +46 -44
- package/chunks/{validateNonInterActiveAuth-GKOC5F6Z.js → validateNonInterActiveAuth-WC2FPE3I.js} +86 -84
- package/chunks/{version-VSATY2LD.js → version-6SS7KCUP.js} +1 -1
- package/chunks/{web-fetch-JCLKL6NL.js → web-fetch-Y5QQMPKA.js} +13 -13
- package/chunks/{web-search-DSQTFUBX.js → web-search-QKKEU723.js} +8 -8
- package/chunks/{workflow-M6QAVKVJ.js → workflow-PWIU6Q2M.js} +418 -304
- package/chunks/{workspace-providers-status-YKLTLMJA.js → workspace-providers-status-B2DM6FNK.js} +45 -43
- package/chunks/{workspace-registration-store-5DMGKU64.js → workspace-registration-store-7Y33TTHJ.js} +2 -2
- package/chunks/{workspace-registry-PTYUSYXX.js → workspace-registry-TSNJKLPC.js} +43 -41
- package/chunks/{workspace-service-25ML3T47.js → workspace-service-4I2QHDX4.js} +50 -48
- package/chunks/{workspace-skills-status-YKZWOYRX.js → workspace-skills-status-HVXNWVGR.js} +44 -42
- package/chunks/{workspace-trust-reconciler-5FI2S3OS.js → workspace-trust-reconciler-RDBBGMWP.js} +49 -47
- package/chunks/{write-file-AY7VLP5X.js → write-file-RQ4DG5RY.js} +36 -34
- package/chunks/{zh-H3YDK5QW.js → zh-72XPUG5P.js} +54 -6
- package/chunks/{zh-TW-JYCP7XUA.js → zh-TW-LTB4SRH3.js} +54 -6
- package/chunks/{zoom-image-S4LJZMD5.js → zoom-image-O5YCB7WN.js} +10 -10
- package/cli.js +32 -48
- package/locales/ca.js +60 -4
- package/locales/de.js +62 -4
- package/locales/en.js +76 -6
- package/locales/fr.js +64 -4
- package/locales/ja.js +61 -4
- package/locales/pt.js +60 -4
- package/locales/ru.js +63 -4
- package/locales/zh-TW.js +67 -6
- package/locales/zh.js +67 -6
- package/package.json +3 -3
- package/web-shell/assets/{arc-xjArKHU2.js → arc-Bd7d781i.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-BgrQDNYG.js → architectureDiagram-3BPJPVTR-CpnOJqNE.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-CXxWC-1_.js → blockDiagram-GPEHLZMM-NxVTiWnk.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-Dx1tLm3v.js → c4Diagram-AAUBKEIU-BWT75l82.js} +1 -1
- package/web-shell/assets/channel-A434sWK5.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-CBxjogVR.js → chunk-2J33WTMH-Dzz03hk6.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-izb-rY5W.js → chunk-4BX2VUAB-DRF-egfm.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-NzLyvSb8.js → chunk-55IACEB6-Co15vq5x.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-DVyKb0dl.js → chunk-727SXJPM-DHSUk1J7.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-BtqL7NzB.js → chunk-AQP2D5EJ-Br8u_E2R.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-iNpdKIO0.js → chunk-FMBD7UC4-DXbPTnqF.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-DI7cbFmX.js → chunk-ND2GUHAM-BleQdi4d.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-3Y_-xFYs.js → chunk-QZHKN3VN-CqgBf-95.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CwPuhldB.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CwPuhldB.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A--raRatZn.js → cose-bilkent-S5V4N54A-WS7b13Yg.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-B8SU70mO.js → dagre-BM42HDAG-v_55ki8o.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-ewgoakXo.js → diagram-2AECGRRQ-DaYAjbdK.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-Bm_JLTnS.js → diagram-5GNKFQAL-D_Hy-L64.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-DEIUjUy9.js → diagram-KO2AKTUF-dB06cZyD.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-C2Wmrpj-.js → diagram-LMA3HP47-DzSluD4F.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-CtYe6bFx.js → diagram-OG6HWLK6-Cvb6CeXQ.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-DfpHcWLV.js → erDiagram-TEJ5UH35-7eB2Hmov.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-CAiUhio5.js → flowDiagram-I6XJVG4X-B08iGCw_.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CYc7ezr4.js → ganttDiagram-6RSMTGT7-BgsrCHq-.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-70lbkcRS.js → gitGraphDiagram-PVQCEYII-DQLurQ2i.js} +1 -1
- package/web-shell/assets/{index-Ww86nT9f.js → index-B_1Z0Mgr.js} +1 -1
- package/web-shell/assets/index-Bi1dP2mU.css +5 -0
- package/web-shell/assets/index-DJ-z1Oba.js +1756 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-C7e8DWPa.js → infoDiagram-5YYISTIA-DXZGO8qB.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BYLr2op-.js → ishikawaDiagram-YF4QCWOH-g7gbuH2w.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-hEibAHKX.js → journeyDiagram-JHISSGLW-euefICGn.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-F2rt8Uhp.js → kanban-definition-UN3LZRKU-Dws8-mjG.js} +1 -1
- package/web-shell/assets/{linear-DPhyNezd.js → linear-C63F0tyh.js} +1 -1
- package/web-shell/assets/{mermaid.core-ZUtnug0n.js → mermaid.core-fLrhp_4-.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DDWcMoi8.js → mindmap-definition-RKZ34NQL-qRkydfT-.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-CTRKzw1_.js → pieDiagram-4H26LBE5-BZ0wQaKN.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-CAEwYG_z.js → quadrantDiagram-W4KKPZXB-Fjq6GbSZ.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-CRjnH9D9.js → requirementDiagram-4Y6WPE33-CqWvjLHU.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-LPQT_sOd.js → sankeyDiagram-5OEKKPKP-VcXX6PVZ.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-Ht2Iqvb0.js → sequenceDiagram-3UESZ5HK-BJSRtxFr.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CIUdqOXu.js → stateDiagram-AJRCARHV-Dt9zUwmZ.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CCxQt56w.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-BcilneZF.js → timeline-definition-PNZ67QCA-DQwlNRws.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BljwiiH1.js → vennDiagram-CIIHVFJN-DwxjUEtQ.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-DeKjkYjq.js → wardley-L42UT6IY-D3QdMSpJ.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-L3U1H7KG.js → wardleyDiagram-YWT4CUSO-BddN8oK8.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-IJnWsgMT.js → xychartDiagram-2RQKCTM6-BUNuBrRJ.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-4KP2F2TE.js +0 -82
- package/chunks/chunk-HGT6JR3U.js +0 -177
- package/chunks/nonInteractiveCli-ZJYEOO7U.js +0 -148
- package/web-shell/assets/channel-B1cyk94G.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BpBYZoRE.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BpBYZoRE.js +0 -1
- package/web-shell/assets/index-C1k3PDuU.css +0 -5
- package/web-shell/assets/index-DZLIXILO.js +0 -1750
- package/web-shell/assets/insert-DmRbh9Rv.svg +0 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BmqqQZ6w.js +0 -1
package/bundled/review/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: review
|
|
3
|
-
description: Review changed code for correctness, security, code quality, and performance. Use when the user asks to review code changes, a PR, or specific files. Invoke with `/review`, `/review <pr-number>`, `/review <file-path>`,
|
|
4
|
-
argument-hint: '[pr-number|file-path] [--effort low|medium|high] [--comment]'
|
|
3
|
+
description: Review changed code for correctness, security, code quality, and performance. Use when the user asks to review code changes, a PR, or specific files. Invoke with `/review`, `/review <pr-number>`, `/review <file-path>`, `/review <pr-number> --comment` to post inline comments on the PR, or `/review --fix` to apply the findings to your working tree. Add `--effort low|medium|high` to trade depth for speed (defaults to high for PRs, medium for local changes).
|
|
4
|
+
argument-hint: '[pr-number|file-path] [--effort low|medium|high] [--comment] [--fix]'
|
|
5
5
|
allowedTools:
|
|
6
6
|
- task
|
|
7
7
|
- run_shell_command
|
|
@@ -59,13 +59,14 @@ It prints a JSON verdict; use it **verbatim**:
|
|
|
59
59
|
- `target` — `{type: "pr-number", number}` | `{type: "pr-url", url, host, owner, repo, number}` | `{type: "file", path}` | `{type: "local"}`. A `pr-url` arrives validated and canonicalized (scheme/host lowercased, query and fragment dropped, the number required to end its path segment — `/pull/42oops` is not PR 42) with host/owner/repo/number extracted; do not re-classify tokens by hand. A token that merely looks like a URL is refused with a warning and reported in `extraTokens`, never guessed into a target.
|
|
60
60
|
- `effort` + `effortSource` — the resolved level after defaults (**high** for PR targets, **medium** for local/file) and the `--comment` override (an **effective** `--comment` forces `high`; an ignored one on a non-PR target changes nothing). Do not re-derive it.
|
|
61
61
|
- `comment.requested` / `comment.effective` — `effective` is what gates Step 7; `requested && !effective` means the user asked on a non-PR target, and the warning for that is already in `warnings`.
|
|
62
|
+
- `fix.requested` / `fix.effective` — `--fix` is `--comment` reflected, and gated on the opposite target. `--comment` writes to a **pull request**, so it needs one; `--fix` writes to a **working tree**, so it needs one that outlives the review. A PR review's tree is the ephemeral worktree `fetch-pr` creates and Step 9 deletes, so `--fix` on a PR target is ignored with a warning — edits there are discarded minutes later, and reporting findings as "fixed" into a directory that no longer exists is worse than not fixing them. `effective` is what gates Step 6B. An effective `--fix` also floors the effort at **medium**: it edits the user's files, and low runs no verification, so applying an unverified finding is the same mistake as posting one, aimed at their working tree instead of a pull request. It does not force **high** — medium's findings are verified, and the reverse audit high adds hunts for findings that are _missing_, which is not what deciding whether to apply one turns on.
|
|
62
63
|
- `warnings` — surface every entry to the user, word for word.
|
|
63
64
|
- `extraTokens` / `unknownFlags` — leftover input the parser refused to guess about; mention them to the user rather than silently dropping them.
|
|
64
65
|
|
|
65
66
|
What each level runs:
|
|
66
67
|
|
|
67
|
-
- **low** — quick pass. You read the diff yourself and report up to
|
|
68
|
-
- **medium** — **balanced**: the high pipeline with its most expensive passes removed. It runs the parallel review agents (Step 3A/3B) over a **reduced dimension set** — issue fidelity (Agent 0, PR targets only), correctness (Agents 1a/1b/1c), **security (Agent 2)**, quality (
|
|
68
|
+
- **low** — quick pass. You read the diff yourself, walking it once per **angle** — `plan.budget.inlineAngles` directed angles (3-6, scaled by diff size) plus a gap sweep when the budget asks for one, all in this context — and report up to 10 unverified findings (Step 3C). No subagents, no build/test, no verification, no reverse audit, no PR posting, no incremental cache, no project rules. The angle rotation is what makes a subagent-free tier worth running: one undirected read converges on the most visibly suspicious hunk and leaves the rest of the diff unexamined, and that is the pass this replaces.
|
|
69
|
+
- **medium** — **balanced**: the high pipeline with its most expensive passes removed. It runs the parallel review agents (Step 3A/3B) over a **reduced dimension set** — issue fidelity (Agent 0, PR targets only), correctness (Agents 1a/1b/1c), **security (Agent 2)**, quality (Agents 3a/3b/3c), performance (Agent 4), **test coverage (Agent 5)**, and **build & test (Agent 7)** — followed by a **single verification pass** (Step 4). It loads and enforces project rules (Step 2) and runs `comment-status` like high. It **skips** the adversarial-persona agents (6a/6b/6c), the diff-specialist finders (Agent 8), the **reverse audit** (Step 5), the incremental cache, and PR posting (`--comment` still forces high). Findings are **verified** (Step 4 ran — they are not "unverified" the way low's are), but without the reverse-audit second pass. Reach for it when high is too slow/expensive but a real bug-catching review is still needed: it keeps the two things that reliably catch bugs cheaply — the finder fan-out and `build-test` (which mechanically catches compile/test failures) — and drops the depth passes with the lowest marginal yield. Measured against high on the same PR it lands at roughly **one-third to one-half** the time and tokens. It reliably catches mechanical defects (compile errors, failing tests) and obvious correctness bugs, but is **not an exhaustive correctness audit** — a subtle Critical that only the reverse audit or the adversarial personas would surface can slip; for a security-sensitive or pre-release review, use `--effort high`.
|
|
69
70
|
- **high** — the full pipeline: parallel review agents (Step 3A/3B — the full dimension set including security, test-coverage, the adversarial personas 6a/6b/6c, and Agent 8), verification (Step 4), iterative reverse audit (Step 5), PR submission (Step 7), incremental cache (Step 8).
|
|
70
71
|
|
|
71
72
|
At every effort level, the mechanics of obtaining the diff — worktree flow, diff capture, base resolution, chunk plan — are shared: the truncation and wrong-base traps this step exists for do not care how fast you want the answer. The _reviewed range_ can still differ: the incremental cache is a high-only feature, so a high re-review of a previously-reviewed PR may scope to `lastCommitSha..HEAD` while a low/medium pass (which never consults the cache) always reviews the full PR diff.
|
|
@@ -113,12 +114,12 @@ Based on the parsed `target.type`:
|
|
|
113
114
|
|
|
114
115
|
Guessing the owner/repo here is not a recoverable mistake — dogfooding this skill against its own PR, the model inferred the fork from the branch's push target, `fetch-pr` answered "Could not resolve to a PullRequest", and the review stopped before reading a line of code. If `gh repo view` and the remote scan disagree, or no remote matches, say so and stop rather than picking one.
|
|
115
116
|
|
|
116
|
-
Read `.qwen/tmp/qwen-review-pr-<n>-fetch.json` for: `worktreePath`, `baseRefName`, `headRefName`, `fetchedSha` (use as the **HEAD commit SHA** for Step 7), `isCrossRepository`, `diffStat` (files / additions / deletions), and `prDescriptionHasHan` (the PR description contains Chinese — every posted inline comment must then be bilingual; see Step 7). If the command fails (auth, network, PR not found), inform the user and stop.
|
|
117
|
+
Read `.qwen/tmp/qwen-review-pr-<n>-fetch.json` for: `worktreePath`, `baseRefName`, `headRefName`, `fetchedSha` (use as the **HEAD commit SHA** for Step 7), `isCrossRepository`, `diffStat` (files / additions / deletions), `emptyDiff` (**stop here**: the branch tree is byte-identical to its merge base — the work already landed or was superseded; tell the user and recommend close-as-superseded instead of fanning out agents over zero hunks), `collapsedFromUpstream` (disclose in the summary: overlapping merged PRs have collapsed this one to a residual — the review scope is the recomputed diff, and body claims about the rest are description-of-history, which Agent 0 should read accordingly), and `prDescriptionHasHan` (the PR description contains Chinese — every posted inline comment must then be bilingual; see Step 7). If the command fails (auth, network, PR not found), inform the user and stop.
|
|
117
118
|
|
|
118
119
|
Worktree isolation: all subsequent steps (agents, build/test) operate inside `worktreePath`, not the user's working tree. Cache and reports (Step 8) are written to the **main project directory**, not the worktree.
|
|
119
120
|
|
|
120
121
|
- **Incremental review check** (high effort only — neither low nor medium consults or updates the cache): if `.qwen/review-cache/pr-<n>.json` exists, read `lastCommitSha` and `lastModelId`. Compare to `fetchedSha` from the fetch report and the current model ID (`{{model}}`):
|
|
121
|
-
- If SHAs differ → continue with the worktree just created. Compute the incremental diff (`git diff <lastCommitSha>..HEAD` inside the worktree) and use as the review scope; if the cached commit was rebased away, fall back to the full diff and log a warning.
|
|
122
|
+
- If SHAs differ → continue with the worktree just created. Compute the incremental diff (`git diff <lastCommitSha>..HEAD` inside the worktree) and use as the review scope; if the cached commit was rebased away, fall back to the full diff and log a warning. **Also read the cache's `findings` ledger** (older caches have none — then there is nothing to track): these are the previous round's findings with their ids, and Step 6 owes each of them a ruling this round.
|
|
122
123
|
- If SHAs match **and** model matches **and** `--comment` was NOT specified → inform the user "No new changes since last review", run `"${QWEN_CODE_CLI:-qwen}" review cleanup pr-<n>` to remove the worktree just created, and stop.
|
|
123
124
|
- If SHAs match **and** model matches **but** `--comment` WAS specified → run the full review anyway. Inform the user: "No new code changes. Running review to post inline comments."
|
|
124
125
|
- If SHAs match **but** model differs → continue. Inform: "Previous review used {cached_model}. Running full review with {{model}} for a second opinion."
|
|
@@ -182,6 +183,7 @@ Read from it:
|
|
|
182
183
|
- `diffLines`, `diffChars`, and `srcDiffLines` / `testDiffLines` / `docsDiffLines` / `generatedDiffLines`
|
|
183
184
|
- `chunks[]` — contiguous, non-overlapping line ranges tiling the whole diff. Each entry has `id`, `startLine`, `endLine` (1-based, inclusive), `lines`, `chars`, an `oversized` flag, and `files[]` naming the source files and new-side line ranges it covers. A chunk with `oversized: true` may exceed what one `read_file` call returns.
|
|
184
185
|
- `files[]` — per-file `kind` (`source` / `test` / `generated`), `hunks[]` new-side ranges (Step 7 validates comment anchors against these), `addedRanges[]` and `diffRange` (present only on `heavy` files — the exact lines the PR wrote, and where that file's own diff lives, so an invariant agent can see what was deleted), change counts, and the `heavy` flag
|
|
186
|
+
- `budget` — how much walking the **size-elastic** parts of this run owe, derived from `srcDiffLines` the same way the topology gate is, and recorded here rather than passed as a flag so every reader sees one number. `inlineAngles` and `sweep` scope Step 3C's low pass; `specialistCap` is the Agent 8 ceiling (**0** below 80 source lines — "one domain dominates the diff" is a judgement, and a judgement made about forty lines finds a dominant domain every time, because forty lines are usually all one thing); `verifyShard` is Step 4's findings-per-verifier. **It never scales a dimension away** — which agents a review owes is the roster's answer and the roster reads `effort`, so a size input cannot become a back door into shrinking coverage. Nothing here is yours to override: a budget the caller can inflate is a budget that gets inflated. **A plan with no `budget` field** (written by an older CLI — the version-skew this skill has already measured once) falls back to the pre-budget flat behaviour, which errs toward more coverage, never less: walk all six angles, run the sweep, cap Agent 8 at 2, shard verification at 8.
|
|
185
187
|
|
|
186
188
|
A chunk is read with `read_file(file_path=diffPathAbsolute, offset=startLine - 1, limit=endLine - startLine + 1)` — `offset` is 0-based.
|
|
187
189
|
|
|
@@ -230,9 +232,9 @@ If `diffPath` is `null` (merge-base could not be resolved), fall back to giving
|
|
|
230
232
|
- **`srcDiffLines` ≤ 500 and `diffLines` ≤ 3200** — use the dimension fan-out in Step 3A.
|
|
231
233
|
- **otherwise** — use the territory × dimension fan-out in Step 3B, and inform the user: "This is a large changeset (N source lines of M total, K chunks). The review may take a few minutes."
|
|
232
234
|
|
|
233
|
-
Test code is where diff size lies. Across this repo's last 40 merged PRs the median diff is **41% test code**, and a third of them are more than half tests. Prose and lockfiles are excluded for the same reason — a translation PR carries no runtime risk. Markdown _inside a source tree_ still counts as source: this skill is one such file. A change of 173 production lines that ships 489 lines of new tests is a small change; carving it into territories spends most of the reviewers on test files and leaves the production code with **one** agent instead of the
|
|
235
|
+
Test code is where diff size lies. Across this repo's last 40 merged PRs the median diff is **41% test code**, and a third of them are more than half tests. Prose and lockfiles are excluded for the same reason — a translation PR carries no runtime risk. Markdown _inside a source tree_ still counts as source: this skill is one such file. A change of 173 production lines that ships 489 lines of new tests is a small change; carving it into territories spends most of the reviewers on test files and leaves the production code with **one** agent instead of the twelve lenses it deserves ("lenses" = the diff-reading dimension agents: the fourteen minus Issue Fidelity and Build & Test, which read the issue and run commands rather than reviewing the diff). Territory fan-out earns its keep when there is a lot of _risky_ code to divide, not a lot of _lines_.
|
|
234
236
|
|
|
235
|
-
The second clause is an attention bound, not a risk one: past roughly 3200 diff lines, asking the
|
|
237
|
+
The second clause is an attention bound, not a risk one: past roughly 3200 diff lines, asking the thirteen diff-reading agents each to read the whole diff dilutes them all, and the chunk topology's base cost (`ceil(diffLines / 400) + 4` diff-reading agents, before invariant and specialized ones — Build & Test reads no diff) crosses that count nearer 3 600. The gate stays at 3 200 rather than moving with the roster: fanning out slightly _before_ the crossover errs toward one accountable reader per line, which is the property 3B is bought for, and a gate that drifts every time a dimension is split or merged is a gate nobody can reason about. It is not a guarantee of fewer calls — a heavy file adds `3` invariant agents and a dominant domain up to `2` specialized finders, so a barely-over-the-line changeset can cost more under 3B than 3A; what 3B buys at that size is one accountable reader per line instead of thirteen diluted ones. It is the safety valve for a changeset dominated by tests or generated files.
|
|
236
238
|
|
|
237
239
|
Either way the chunk plan covers **every** line — tests and generated files included. What changes is how many reviewers are assigned and what each is asked to do, not what gets read.
|
|
238
240
|
|
|
@@ -270,9 +272,9 @@ Use **Step 3A** or **Step 3B** as the topology gate in Step 1 decided. The dimen
|
|
|
270
272
|
|
|
271
273
|
## Step 3A: Dimension fan-out (small source change)
|
|
272
274
|
|
|
273
|
-
Launch **
|
|
275
|
+
Launch **14 agents** for same-repo **PR** reviews (Agent 1 has three procedural variants 1a/1b/1c, Agent 3 has three checklist slices 3a/3b/3c, and Agent 6 has three persona variants 6a/6b/6c — each variant counts as a separate parallel agent), plus up to 2 optional diff-specialized finders (Agent 8) when the diff's domain calls for them. For cross-repo lightweight **PR** mode launch **12 agents** — skip Agent 7 (Build & Test) and Agent 1c (Cross-file tracer), since there is no local codebase to build, test, or grep. (Agent 8 finders need only the diff, so the up-to-2 option applies in every mode — lightweight and local included.) Lightweight mode also degrades Agents 1a and 1b, whose briefs assume a source tree: tell them they have the diff ONLY — 1a reviews hunks without enclosing-function reads, and 1b, when it cannot find a deleted invariant re-established because the evidence would live outside the diff, reports the candidate at `Confidence: low` and says the re-establishment could not be checked, instead of asserting it is missing. Step 4's verifiers operate under the same limit, so lightweight-mode findings that depend on unseen source must stay low-confidence (terminal-only) rather than becoming public blockers. **Agent 0 (Issue Fidelity) runs only when the review target is a PR** — a local-diff or file-path review has no PR and no linked issue, so skip Agent 0 and launch **13 agents** (Agents 1a–7). Each agent should focus exclusively on its dimension. (Agent counts are maxima: on a diff with no removed or replaced lines, Agent 1b has nothing to audit and is skipped — one fewer agent.)
|
|
274
276
|
|
|
275
|
-
**At medium effort, launch the reduced set:** skip the three adversarial personas (Agents 6a/6b/6c) and the Agent 8 diff-specialists, launching Agents 0 (PR targets only), 1a, 1b, 1c, 2,
|
|
277
|
+
**At medium effort, launch the reduced set:** skip the three adversarial personas (Agents 6a/6b/6c) and the Agent 8 diff-specialists, launching Agents 0 (PR targets only), 1a, 1b, 1c, 2, 3a, 3b, 3c, 4, 5, and 7 — **11 agents** for a same-repo PR, **10** for a local-diff or file-path review (no Agent 0), **9** for cross-repo lightweight (drop Agent 7 and 1c too, as above). Everything else about 3A is identical — the briefs, the `working_dir` pin, the whiff check, coverage; medium changes only which dimensions launch, not how any agent runs. **Build the roster with `agent-prompt --roster`** — it reads the effort the plan recorded at Step 1 (`plan.effort`), so on a medium plan it omits 6a/6b/6c from the roster it prints (Agent 8 was never in it) and you launch exactly these agents. `check-coverage` (Step 3D) reads the **same** `plan.effort` and requires exactly these too — no flag to pass, and no way for the roster you launched and the gate that checks it to disagree. (The effort lives in the plan, not in a flag, on purpose: a roster a caller could shrink by omitting a flag is a roster that gets shrunk. If Step 1 recorded no effort, the full roster is required, personas included — the fail-safe, not a medium review.)
|
|
276
278
|
|
|
277
279
|
**Do not write these prompts, and do not ask for them one at a time. One call builds all of them:**
|
|
278
280
|
|
|
@@ -284,7 +286,7 @@ Launch **12 agents** for same-repo **PR** reviews (Agent 1 has three procedural
|
|
|
284
286
|
|
|
285
287
|
**Redirected to a file, then `read_file` it, paging until `isTruncated` is false** — the same rule as every other large output in this skill: shell output truncates at 30 000 characters, and a large plan's roster exceeds that, which would silently swallow the middle blocks. The output is self-checking: blocks are numbered `agent k of N` and the file ends with an `end of roster` line — if any `k` is missing or the end line is absent, rebuild just those blocks with `--chunk <id>` / `--role <r>` (every prompt is also recorded on disk regardless).
|
|
286
288
|
|
|
287
|
-
It prints one labelled block per required agent — which roles this review owes is read out of the plan, so the paragraph above is the _why_ and the roster is the _list_ — and **each block goes to its agent verbatim**, all launched in one response. To rebuild a single agent's prompt (a relaunch after Step 3D): `--role <role>` in place of `--roster`; the roles are `0`, `1a`, `1b`, `1c`, `2`, `
|
|
289
|
+
It prints one labelled block per required agent — which roles this review owes is read out of the plan, so the paragraph above is the _why_ and the roster is the _list_ — and **each block goes to its agent verbatim**, all launched in one response. To rebuild a single agent's prompt (a relaunch after Step 3D): `--role <role>` in place of `--roster`; the roles are `0`, `1a`, `1b`, `1c`, `2`, `3a`, `3b`, `3c`, `4`, `5`, `6a`, `6b`, `6c`, `7`.
|
|
288
290
|
|
|
289
291
|
**What it prints is short — a few hundred characters — and it is short on purpose.** It names the agent's role, points at the **brief file** the command just wrote, and lists the `read_file` calls for the diff. The brief itself — the dimension, the finding format, the severity definitions, the project rules — is on disk, and the agent reads it, exactly as it reads the diff. That is not an optimisation. Asked to paste a 4 652-character prompt to each of twelve agents, a real run delivered **2 893** characters of one: it kept the head, added a preamble of its own, and cut nineteen hundred characters out of the middle. Then it read the coverage check's refusal, concluded that "the agents clearly did their job", skipped `compose-review`, and filed an **Approve it had written itself**. What you are asked to carry is now small enough that you will carry it. Copy it; do not retype it. (Agent 8, when you launch one, is the exception — its brief is the one you write, so give it `--whole-diff` and append your domain brief.)
|
|
290
292
|
|
|
@@ -322,7 +324,7 @@ Everything below still governs what the agent is asked to do; the command builds
|
|
|
322
324
|
- **An instruction to page.** Ordinary chunks are sized to fit one un-truncated read, but a chunk whose `oversized` flag is set is a single hunk that offered no safe place to cut, and its `chars` can exceed one read's ~25 000. Tell the agent: if the read comes back with `isTruncated`, keep calling `read_file` with a larger `offset` until it has the whole range. An agent that returns a `Covered:` receipt for a range it only half read makes the coverage guarantee a lie — which is worse than not having one.
|
|
323
325
|
- **What to do when paging cannot help.** A chunk whose `maxLineChars` exceeds ~25 000 contains a single line longer than one read returns — a minified bundle, a base64 blob. Paging starts every page at a line boundary, so the tail of that line is unreachable by any `offset`. Such a chunk MUST NOT be receipted as covered. Tell the agent to return, instead of the receipt: `Uncoverable: chunk <id> — line exceeds the read limit`. Report those chunks to the user in Step 6 and do not let the verdict be Approve on their strength.
|
|
324
326
|
- Permission to read the **full source files** it covers (via `read_file` on the worktree path) whenever a hunk's correctness depends on code outside the hunk. Diff context lines are three lines deep; state invariants are not. A source file over ~25 000 characters comes back with `isTruncated` set — page through it rather than reasoning from the first screenful.
|
|
325
|
-
- The review focus: it owns **all** of Agents 1a, 1b, and 2–6's dimensions (line-by-line correctness with the language-pitfall and wrapper-routing checks, the removed-behavior audit of its own deleted lines, security, code
|
|
327
|
+
- The review focus: it owns **all** of Agents 1a, 1b, and 2–6's dimensions (line-by-line correctness with the language-pitfall and wrapper-routing checks, the removed-behavior audit of its own deleted lines, security, all three code-quality slices — reuse/duplication, altitude and abstraction fit, sibling consistency and clarity — performance, test coverage, and the three adversarial personas) **for its territory only**. Two duties are whole-diff agents, not chunk duties, because a chunk agent is structurally blind to them: **cross-file tracing (Agent 1c)** — it cannot see a caller that lives in another chunk — and the **cross-chunk half of removed-behavior (Agent 1b)** — it cannot see that its deleted export's replacement, three files away, quietly changed a default. Audit the deletions in your own territory; do not conclude a deletion is unreplaced merely because the replacement is not in your range.
|
|
326
328
|
- **The severity definitions from the finding format below, verbatim.** A chunk agent owns the test-coverage dimension with no dedicated agent to calibrate it, and an uncalibrated agent files "zero test coverage" as Critical. It has happened.
|
|
327
329
|
- Project-specific rules from Step 2 (if any).
|
|
328
330
|
|
|
@@ -400,9 +402,9 @@ Agent 2 (Security) — WHIFF (returned "No issues found." with no evidence
|
|
|
400
402
|
|
|
401
403
|
A check you perform silently is a check you skip, and this one has been skipped: dogfooded against this skill's own PR, Agent 0 returned in **6 seconds** having made **one tool call**, and the review went on to print "All chunks were successfully reviewed and covered" and **Approve**. The roll-call is what makes that impossible to miss — you cannot write the artifact line for an agent that named no artifact, and a `WHIFF` line you have written is a `WHIFF` you must then act on (relaunch once; on a second bare return, record the dimension in `unreviewedDimensions`, which forbids the Approve).
|
|
402
404
|
|
|
403
|
-
**The whole-diff agents have no receipt, so this is the only check they get: an agent that returns near-instantly with almost no output did not do its job, and its silence is indistinguishable from "found nothing".** This is not hypothetical — in dogfooding an invariant agent on a heavy file returned in 11 seconds having emitted a few hundred tokens, while its sibling agents ran for minutes; the whiffing agent happened to own the checklist half that held the run's most serious defect, and nothing flagged the miss. Apply the check to **every agent that owes no receipt** — in 3B, the whole-diff agents (Agent 0, **1b**, 1c, Agent 7, the invariant agents, the test-coverage matrix, Agent 8); in 3A, **all of them**, since no 3A agent emits a receipt (Agents 0, 1a, 1b, 1c, 2,
|
|
405
|
+
**The whole-diff agents have no receipt, so this is the only check they get: an agent that returns near-instantly with almost no output did not do its job, and its silence is indistinguishable from "found nothing".** This is not hypothetical — in dogfooding an invariant agent on a heavy file returned in 11 seconds having emitted a few hundred tokens, while its sibling agents ran for minutes; the whiffing agent happened to own the checklist half that held the run's most serious defect, and nothing flagged the miss. Apply the check to **every agent that owes no receipt** — in 3B, the whole-diff agents (Agent 0, **1b**, 1c, Agent 7, the invariant agents, the test-coverage matrix, Agent 8); in 3A, **all of them**, since no 3A agent emits a receipt (Agents 0, 1a, 1b, 1c, 2, 3a, 3b, 3c, 4, 5, 6a, 6b, 6c, 7, and Agent 8 if launched). A whiffing 3A dimension agent is exactly as invisible as a whiffing invariant agent, and the same one-line fix applies. For each such agent, sanity-check that its return is substantive: it names the specific fields/callers/lines it walked, or it explicitly says "No issues found" **after** describing what it examined. For **Agent 7** the evidence is the build/test **commands it ran and their outcomes** — a Build & Test return that names no command whiffed even if it says "build passed", and after its second whiff record `build-and-test` in `unreviewedDimensions` like any other dimension: a zero-finding run whose deterministic verification never actually ran must not certify on its silence. A legitimately empty scope also passes — Agent 0 on a feature PR with no linked issue returns "No issues found — scope empty" plus the evidence it checked (empty `closingIssuesReferences`, no referenced issue, not a bugfix), and that is a complete answer, not a whiff; do not relaunch it. What fails the check is a bare "No issues found" with no evidence of any walk or scope determination, or a response conspicuously shorter and faster than its peers — relaunch that one agent before Step 4, **once**. The relaunch is capped at one attempt per agent: if the second return is also bare, do not spin — take it, and record that agent's dimension in an **`unreviewedDimensions`** list. (The finding format tells every agent to return `No issues found — <what you examined>`; an agent that ignores that twice is not going to comply on the third ask.) A silent whole-diff agent is the Step-3A/3B equivalent of a chunk with no receipt — **and it is treated like one**: `unreviewedDimensions` is carried into Step 6's "Not reviewed" section, it **forbids an Approve** (a dimension nobody reviewed cannot be certified clean, exactly as an uncoverable chunk cannot), and Step 7 serializes it in the review body (compose-review's `unreviewedDimensions` input), named alongside any uncoverable chunks. A run that silently drops Security or the cross-chunk removed-behavior audit and then posts LGTM is the failure this whole check exists to prevent; noting the gap in the terminal and approving anyway would only move it.
|
|
404
406
|
|
|
405
|
-
**Step 3A has no receipts, and must not.** There every dimension agent walks every chunk, so "exactly one receipt per chunk" would demand either none or one per diff-reading agent —
|
|
407
|
+
**Step 3A has no receipts, and must not.** There every dimension agent walks every chunk, so "exactly one receipt per chunk" would demand either none or one per diff-reading agent — thirteen, or up to fifteen when Agent 8 launches (every agent except Build & Test reads the diff). Territory ownership is a Step 3B idea. **What Step 3A does not lack is coverage** — that is Step 3D's job on both paths, and it needs no receipt from anyone: it reads the lines each agent was pointed at out of the prompt the CLI built, and the diff reads out of the harness's transcript. A receipt was only ever a sentence the agent typed. (For a while the two were confused, and 3A reviews were told nobody had read them. See Step 3D.) What Step 3A shares is the uncoverable rule, and that needs no agent at all: **a chunk is uncoverable iff its `maxLineChars` exceeds ~25 000**, which the orchestrator reads straight out of the plan before launching anything. Compute that list up front on both paths, carry it into Step 6, and let a Step 3B agent's `Uncoverable` receipt add to it rather than be the only source of it.
|
|
406
408
|
|
|
407
409
|
**Do not let precision suppress recall in this step.** The "if you're unsure, do NOT report it" rule in the Exclusion Criteria applies to **Suggestion** and **Nice to have** findings. A suspected **Critical** must always be reported, marked `low confidence` if uncertain — Step 4's verifier decides. A Critical dropped here is dropped irreversibly; a Critical dropped there is at least reviewed by a second agent.
|
|
408
410
|
|
|
@@ -440,39 +442,66 @@ An agent that finds nothing must say so **and say what it walked** — `No issue
|
|
|
440
442
|
| `1b` | **Removed-behavior audit.** Owns the `-` lines, which exist only in the diff — the post-change tree carries no trace of what was deleted. For each removal: what invariant did it enforce, and where is that re-established? Includes removed or renamed _exports_ (compared to their replacement as **behaviour, not names**), changed _literals_ a distant consumer matches on by shape (marker strings, keys, codes, regex text), and whether a rename/format/schema change handles the data that **already exists** (migration / split-brain). |
|
|
441
443
|
| `1c` | **Cross-file tracer** (needs a local tree). Owns the whole cross-file walk. _Consumer direction_: grep every caller of every changed export and check it against the new contract. _Producer direction_: for every field the diff **adds**, grep its **read sites** — a live path reading a field the diff never populates is Critical, and nothing in the build will tell you. |
|
|
442
444
|
| `2` | **Security.** Injection, XSS, SSRF, path traversal, authn/authz bypass, secrets in logs, weak crypto, hardcoded credentials. Includes **option/argument injection into subprocess calls** — a user-controlled positional that starts with `-` or is `.`/`..` becomes a git/gh flag or pathspec (`--output=`, `-f`, `checkout .`); `execFile` does not stop it — validate the value against the subcommand grammar (a ref/name allowlist, reject a leading `-`); a `--` separator ends option parsing but does **not** neutralize a pathspec (`checkout -- .` still discards changes), so the value allowlist is the fix. |
|
|
443
|
-
| `
|
|
445
|
+
| `3a` | **Reuse & duplication.** Does the codebase already have this? Greps the shared/utility modules and adjacent files for the _behaviour_ (a literal, an error string, a regex — not a plausible function name), and **names the existing helper to call instead**; a duplication finding that names nothing is not a finding. Also owns **dead code the diff leaves behind**. |
|
|
446
|
+
| `3b` | **Altitude & abstraction fit.** Is each change at the right depth — or a bandaid on shared infrastructure, a downstream compensation for an upstream bug, or a new abstraction serving a single call site? **Names the depth the change should live at**, and the blast radius on the other callers. |
|
|
447
|
+
| `3c` | **Consistency & clarity.** **Sibling consistency** — a guard/validation one member of a parallel family has but its twin lacks (asymmetric failure; if the missing guard is on untrusted input, a security bug, not a nit) — plus convention drift measured against a cited local example, misleading names and comments, and needless complexity in the added code. |
|
|
444
448
|
| `4` | **Performance & efficiency.** N+1s, leaks, needless re-renders, bad data structures, bundle size. **Reproduces the PR's claimed numbers** rather than trusting them — confirms a cheap deterministic claim (bundle bytes, tree-shake) or flags an unreproducible/unsubstantiated benchmark as unverified. |
|
|
445
449
|
| `5` | **Test coverage.** Specific untested paths in the diff, never "coverage is low"; a missing test is a Suggestion. **Mutation-tests the tests the diff adds/changes** — a test that stays green when the code under it is broken is vacuous — a Suggestion, Critical only when it asserts the opposite, was weakened in-diff, or lets a named incorrect behaviour ship (report the behaviour, not the gap). |
|
|
446
450
|
| `6a` `6b` `6c` | **Undirected audit, three personas** — attacker, 3 AM oncall, six-months-later maintainer. The framings force diverse paths; the union of what they find is the point, so all three run. |
|
|
447
|
-
| `7` | **Build & test verification** (needs a local tree). Runs _one_ build and _one_ test command, and the **test-efficacy probe** — which reverts the diff's source, keeps its tests, and reports the ones that pass anyway,
|
|
451
|
+
| `7` | **Build & test verification** (needs a local tree). Runs _one_ build and _one_ test command, and the **test-efficacy probe** — which reverts the diff's source, keeps its tests, and reports the ones that pass anyway, deletes individual added safety statements (mutants) to find the ones no test notices, and reverts individual **hunks** one at a time to find the changes no test turns on. Its evidence is the commands it ran. `Source: [build]` / `[test]`, never `[review]`. |
|
|
448
452
|
| `test-matrix` | **Test coverage matrix** (Step 3B). Maps each behavioural change to the test that exercises it — the pairing a territory agent cannot see, because it holds either the implementation or the test, rarely both. |
|
|
449
453
|
| `invariant-a` `invariant-b` `invariant-c` | **Whole-file invariants** on a `heavy` file, one checklist slice each: (a) mutable fields, timers, collections; (b) retry counters, ignored return values, error taxonomies; (c) config fields, early returns. |
|
|
450
454
|
|
|
455
|
+
**Why code quality is three agents.** It was one, holding six unrelated checks — reuse, sibling symmetry, altitude, abstraction fit, conventions, dead code — which is the shape this skill already refuses two rows down. The invariant agents were split three ways on measured evidence (PR #6457's `QQChannel.ts`: one agent holding the whole eight-item checklist found **one** of that file's five invariant-class defects; the same model split three ways found **all five**), because a long checklist is not a task an agent does six times — it is a task it does once, well, and then stops. Nothing in that measurement was specific to invariants, and the quality checklist was the other place the same shape survived. The seam is where the questions genuinely differ: _does this already exist_ (3a), _is it at the right depth_ (3b), _does it match what surrounds it_ (3c). All three run at medium as well as high — dropping two slices would not save a lens, it would restore the failure the split fixed.
|
|
456
|
+
|
|
451
457
|
Two things the command's briefs carry that no orchestrator should be relaying by hand, and that a hand-written prompt has never once included: the **Exclusion Criteria** (what is not a finding — the whole precision control), and the rules that make an **anchor** resolvable (prefer added lines; a removed line cannot be anchored; a bare `}` matches everywhere).
|
|
452
458
|
|
|
459
|
+
**And one the briefs now carry against the Exclusion Criteria: the recall rule.** The exclusions are a filter on what _kind_ of thing is a finding. Read as a confidence bar — which is how an agent under a "silence is better than noise" constitution reads them — they license dropping anything half-believed, and that drop is invisible: no later stage sees a candidate that was never filed. Every stage this skill has after the finders (dedup, Step 4 verification, the reverse audit, the confidence split that keeps low-confidence findings off the pull request) exists to **remove** wrong findings; none of them can **add** a missing one. So each finder's brief now states the split explicitly — file every candidate whose failure scenario you can name, at `Confidence: low` if unsure; do not stay silent because another lens might catch it; the scenario gate itself is unchanged. It goes to the finders only. The Step 4 verifier does **not** get it: telling the stage whose job is removing wrong findings to keep everything it cannot rule out would disable the precision half of the pipeline.
|
|
460
|
+
|
|
453
461
|
**Path-scoped rules.** Some files have failure modes no dimension would think to ask about — a GitHub Actions workflow reads as configuration, and the reviewer who treats it as configuration misses `pull_request_target` checking out the contributor's code with a write token. `agent-prompt` appends a checklist for such a file to the brief of every code-reviewing agent **whose territory actually contains one**. It is additive to the project's own rules, never a replacement, and it is silent on a diff that triggers none.
|
|
454
462
|
|
|
455
|
-
### Agent 8: Diff-specialized finders (0
|
|
463
|
+
### Agent 8: Diff-specialized finders (0 to `plan.budget.specialistCap` agents, optional; high effort only — medium skips them)
|
|
456
464
|
|
|
457
465
|
The fixed dimensions are domain-blind. When a diff concentrates in a domain with a recognizable failure grammar — a reconnect/backoff state machine, a module loader, a cron scheduler, a wire-protocol codec, a cache layer, a data migration — write 1–2 additional finder briefs specialized to that domain and launch them alongside the standard set, labeled `Agent 8a/8b: <domain> angle`.
|
|
458
466
|
|
|
459
467
|
**This is the one brief you write**, so it is the one place `--role` does not help: build the diff-reading block with `"${QWEN_CODE_CLI:-qwen}" review agent-prompt --plan <plan> --whole-diff` and append your domain brief to it. A specialized brief names the domain's specific invariants to walk, the way the invariant checklist does for a rewritten file. Examples: for a module loader — resolution order, ESM/CJS interop, circular-import timing, cache invalidation; for reconnect logic — state flags reset on every exit path, backoff growth and cap, timer cancellation on teardown, buffered-data loss when a retry is abandoned.
|
|
460
468
|
|
|
461
|
-
Rules: at most
|
|
469
|
+
Rules: at most `plan.budget.specialistCap` — which is **0 below 80 source lines**, so on a small diff there is no ruling to make and you launch none regardless of how concentrated it looks; launch none when no domain stands out (the common case — most diffs get zero). They are not in the roster, so nothing will ask for them. Their findings are `Source: [review]`, use the standard finding format including the failure scenario, and go through Step 4 verification like any other finding.
|
|
462
470
|
|
|
463
471
|
### What Agent 7's results mean downstream
|
|
464
472
|
|
|
465
|
-
Build and test results are **deterministic facts**. A code-caused failure skips Step 4 verification — the `[build]` / `[test]` source tag is how it is recognised as pre-confirmed. An environment/setup failure (a missing dependency, a tool not installed) is informational only and must not affect the verdict. Test-efficacy findings are deterministic in the same way, and likewise pre-confirmed.
|
|
473
|
+
The efficacy report's `harnessValidated` is the probe kit's own control, and it has THREE values: `false` means an injected always-failing test left the runner green, every would-be survivor was re-classed inconclusive (counted in `mutants.skippedForControl` / `hunks.skippedForControl`, which is NOT the budget running out), and the terminal should say the probe harness could not be validated rather than implying clean coverage; `null` means the control produced no verdict — either it never ran (no green baseline, no candidates, no budget, an unreadable probe file) or it ran and died before answering (its deadline killed it, the runner could not be spawned), which the outer catch leaves as `null` rather than as a fabricated `false`. Say which of the two the report supports rather than "the control never ran", because for the second it did. Neither validated nor refuted either way, so a survivor stands but unconfirmed; only `true` licenses reading a survivor as a coverage gap. Build and test results are **deterministic facts**. A code-caused failure skips Step 4 verification — the `[build]` / `[test]` source tag is how it is recognised as pre-confirmed. An environment/setup failure (a missing dependency, a tool not installed) is informational only and must not affect the verdict. Test-efficacy findings are deterministic in the same way, and likewise pre-confirmed.
|
|
474
|
+
|
|
475
|
+
When the PR side's tests fail, Agent 7's brief has it **measure** the attribution rather than judge it by path: `base-tree` + `test-delta` rerun the same failed commands on the built merge base and diff the failing **file sets**. `netNew` (fails on the PR side only) is the PR's own failure by measurement — a Critical even in a file the diff never touched; `shared` (fails on base too) is pre-existing by measurement — never filed, even in a file the diff rewrote. Counts are deliberately not compared: a flaky suite fails different test names between two runs of the same tree, so the file-set difference is the signal and an empty `netNew` is the strongest "pre-existing" statement available. Where the delta cannot rule — no merge base, an unparsed failure, a timed-out base rerun, a base rerun that failed without naming any failing file (it did not measure the base), or a command the whole-command budget could not fit — the old path judgment stands, and the report names each case with its own reason rather than folding them into one.
|
|
466
476
|
|
|
467
477
|
If the probe reports `inconclusive`, that is **not a finding and must never be reported as one**: reverting the source often breaks the test's own compile, and a runner that collected nothing is not a test catching a regression. Note it in the terminal and move on.
|
|
468
478
|
|
|
469
479
|
## Step 3C: Inline pass (low effort)
|
|
470
480
|
|
|
471
|
-
At low effort there are no subagents: you are the finder, in this context. The diff is still read via the chunk plan — `read_file` per chunk range, paging oversized chunks; the read-cap rules from Step 1 apply unchanged, and chunks whose `maxLineChars` exceeds the read cap are uncoverable here exactly as in 3A. (For a file-path review of an unchanged file there is no plan — read the whole file, paging until `isTruncated` is false, per Step 1's no-diff branch.) (**Medium is not an inline pass** — it runs the Step 3A/3B fan-out and Step 4 verification like high, minus the reverse audit; see the effort table and Step 3.)
|
|
481
|
+
At low effort there are no subagents: you are the finder, in this context, and you walk the diff once per angle rather than once in total. The diff is still read via the chunk plan — `read_file` per chunk range, paging oversized chunks; the read-cap rules from Step 1 apply unchanged, and chunks whose `maxLineChars` exceeds the read cap are uncoverable here exactly as in 3A. (For a file-path review of an unchanged file there is no plan — read the whole file, paging until `isTruncated` is false, per Step 1's no-diff branch.) (**Medium is not an inline pass** — it runs the Step 3A/3B fan-out and Step 4 verification like high, minus the reverse audit; see the effort table and Step 3.)
|
|
482
|
+
|
|
483
|
+
**Directed angles, then a sweep — not one pass.** A single undirected read of a diff is the weakest thing this skill can do, and it was what low did: one walk, self-censoring under the "silence is better than noise" constitution, capped at 8. What replaces the subagent fan-out at this level is not fewer readers — it is **the same reader, rotated**. Fan-out along the dimension is what buys recall in 3A; at low you buy the same thing by walking the diff once per angle, in this context, sequentially. It costs no subagent, no build, no verification, and no worktree; it costs turns, and it is still an order of magnitude cheaper than medium.
|
|
484
|
+
|
|
485
|
+
The angles below are the ones that pay at hunk-only depth — every one of them can be answered from the diff text plus its context lines, because low reads nothing else. **Walk the first `plan.budget.inlineAngles` of them, in the order listed, one at a time**, and surface **up to 6 candidates each**. The order is not arbitrary and the budget is what makes it load-bearing: A, B and C are always walked, because each is defined by _how_ it walks rather than by a topic and each is answerable on a diff of any size; D, E and F unlock as the diff grows, one per 60 source lines, because a wrapper that routes wrongly, a helper duplicated across files, and a sibling that lost its guard all need enough code present to be visible at all. Do not merge them into a single "look for bugs" read: that is the pass this replaces, and it converges on whichever hunk looks most suspicious while nine-tenths of the diff goes unexamined.
|
|
486
|
+
|
|
487
|
+
- **A — line-by-line.** Every hunk, every changed line. What input, state, timing or platform makes this line wrong? Inverted or wrong conditions, off-by-one, null/undefined deref where nearby lines show the value can be absent, falsy-zero (`if (x)` where `0` or `''` is valid), a missing `await`, wrong-variable copy-paste, an error swallowed by a `catch` that should propagate, unescaped regex metacharacters.
|
|
488
|
+
- **B — removed behaviour.** Every line the diff **deletes or replaces**. Name the invariant it enforced, then look for where the new code re-establishes it. A removed guard, a dropped error path, a narrowed validation, a deleted test that covered a real case. When the re-establishment would live outside the diff you cannot check it — report at `Confidence: low` and say so; do not assert it is missing.
|
|
489
|
+
- **C — language pitfalls.** The classic footguns of this diff's language and framework, and only instances the diff **introduces**: JS falsy-zero, `==` coercion, a closure capturing a loop variable; Python mutable default arguments and late-binding closures; Go nil-map writes and range-variable capture; SQL string interpolation; timezone/DST arithmetic; float equality; integer division.
|
|
490
|
+
- **D — wrapper and proxy routing.** When the diff adds or changes a type that wraps another — a cache, proxy, decorator, adapter — check that every method routes to the **wrapped instance** and not back through a registry, session or global (a caching provider whose `delegate` field resolves through `session.get(...)` instead of `delegate.get(...)` re-enters its own cache or recurses), and that the wrapper forwards every method its callers actually use.
|
|
491
|
+
- **E — reuse and dead code.** New code that re-implements a helper **visible in the diff or its context** (low does not grep), the same block pasted into two files in this one change, and code the diff leaves unreachable: a function, branch, export or import nothing reaches once this lands.
|
|
492
|
+
- **F — sibling consistency.** Where the diff touches one member of a parallel family — sibling loaders, the arms of a switch, the handlers of a route table, two functions that build the same command — and the family's other members are **also visible in the diff**, check that a guard, validation, cleanup or shape-check present in one is present in all. The missing half is a latent asymmetric failure.
|
|
472
493
|
|
|
473
|
-
**
|
|
494
|
+
**Then one sweep, when `plan.budget.sweep` is true.** On a diff small enough to hold entirely in view the sweep is skipped, and that is not a saving grace-noted in passing — a second reader of the same few hunks _is_ the first reader, and "what did the first pass not get to" has no answer when the first pass got to all of it. Otherwise, take a further pass, in this same context, as a fresh reviewer who has been handed the deduplicated candidate list. Re-read the hunks looking **only for what is not already on it** — do not re-derive, re-confirm or re-argue anything already there; the job is gaps. What a first pass reliably misses: code that was **moved or extracted** and dropped a guard or an anchor on the way; second-tier footguns (a default evaluated once at definition time, a lock whose scope shrank, a predicate method with a side effect, iteration order relied on but not guaranteed); setup/teardown asymmetry in tests; a config default that flipped. Up to **6 more** candidates. If nothing new, return nothing from the sweep — do not pad it.
|
|
474
495
|
|
|
475
|
-
|
|
496
|
+
**Pool and deduplicate — do not re-judge.** Merge near-duplicates only: same defect, same location, same reason keeps one, at the highest severity any copy carried. Do not run a verification pass over your own candidates and do not drop one because you are no longer sure — low is explicitly an unverified tier, it says so in its own label, and a candidate you delete here is one no later stage can recover. Sort by severity. Cap: **10 findings**, most severe first.
|
|
497
|
+
|
|
498
|
+
**Do not read full source files, do not grep the codebase, do not run anything.** That restriction is what makes low cheap, and it is also why the angles above are the ones they are. Project rules are not loaded at low (Step 2 is skipped).
|
|
499
|
+
|
|
500
|
+
**Say which angles you walked.** End the pass with one line per angle walked, naming what it examined — `B — 3 deleted hunks in submit.ts and parse-args.ts; both guards re-established at the new call site` — the same evidence-bearing return every subagent owes in 3A. This is the only check low has: nothing here reads a transcript, so a pass that skipped four angles and reported two findings is indistinguishable from a clean diff unless it says so. If the union of the passes you ran yields fewer than `min(files_changed, 3)` candidates, treat that as a signal you stopped early and re-walk the angles you finished fastest — **but do not invent findings to reach it**; a genuinely clean small diff legitimately produces none, and reports none.
|
|
501
|
+
|
|
502
|
+
Low uses the standard finding format, including **Failure scenario**, and the reporting gate applies unchanged: a Suggestion with no concrete scenario or cost is dropped; a suspected Critical you cannot pin down is kept with `Confidence: low`. The recall rule the fan-out briefs carry applies to you here too — you are the finder, so file every candidate whose scenario you can name rather than withholding the half-believed ones.
|
|
503
|
+
|
|
504
|
+
(Why this is prose and not a subcommand, unlike every other prompt in this skill: there is no second party to relay it to. The delivery checks exist because a prompt built for a _subagent_ has to survive being copied by the orchestrator, and measurably does not. At low the orchestrator **is** the agent, and this document is already in its context — there is no copy to drift.)
|
|
476
505
|
|
|
477
506
|
Then skip Steps 4 and 5 entirely and go to Step 6 with these adjustments:
|
|
478
507
|
|
|
@@ -480,6 +509,7 @@ Then skip Steps 4 and 5 entirely and go to Step 6 with these adjustments:
|
|
|
480
509
|
- Emit **no verdict** — no Approve / Request changes / Comment, and skip the open-Criticals re-check (that gate defends a verdict this pass does not claim). Chunks that are uncoverable by `maxLineChars` are still listed under "Not reviewed".
|
|
481
510
|
- Follow-up tip: "Tip: run `/review <target> --effort medium` for a verified balanced review, or `--effort high` for the full verified review." For a local review with findings, also offer the `fix these issues` tip.
|
|
482
511
|
- Step 7 never runs — `--comment` forces high effort, and if the user asks to "post comments" after a quick pass, decline and point at `--effort high` (unverified findings must not be posted publicly).
|
|
512
|
+
- Step 6B never runs either, and cannot: an effective `--fix` floors the effort at medium (Step 1), so no low pass is ever a `--fix` run. If the user asks to apply the findings after a quick pass, the same reasoning as posting applies with the target changed — editing their files on the strength of an unverified finding is the mistake, not publishing it — so point at `/review --fix`, which re-runs at medium and produces findings a verifier has ruled on.
|
|
483
513
|
- In Step 8, save the report (marked with the effort level) but do **not** write the incremental cache — a quick pass must never make a later full review report "No new changes since last review". Step 9 cleanup runs as usual.
|
|
484
514
|
|
|
485
515
|
## Step 4: Deduplicate, verify, and aggregate (high and medium effort)
|
|
@@ -490,7 +520,7 @@ Before verification, merge findings that refer to the same issue (same file, sam
|
|
|
490
520
|
|
|
491
521
|
### Batch verification
|
|
492
522
|
|
|
493
|
-
Launch verification agents that between them receive **all** non-pre-confirmed findings. **Up to
|
|
523
|
+
Launch verification agents that between them receive **all** non-pre-confirmed findings. **Up to `plan.budget.verifyShard` findings per agent** (8), so `ceil(N / verifyShard)` agents, launched together in one response. It is flat rather than size-derived on purpose: it is a fact about how much a verifier can re-trace before its quality collapses on the tail of its list, which is a property of the verifier and not of the diff. It lives in the budget so it has one home instead of being restated here and in whatever reads it.
|
|
494
524
|
|
|
495
525
|
A single verifier for every finding was cheaper, but on a large review it becomes the most context-starved agent in the pipeline: it must re-read code for each of 30-60 findings inside one context window, and its quality collapses on the tail of the list. Sharding keeps each verifier's job small; the cost is still far below one-agent-per-finding.
|
|
496
526
|
|
|
@@ -509,6 +539,12 @@ Write this shard's findings to a file — each with its file, line, issue and fa
|
|
|
509
539
|
|
|
510
540
|
The brief holds the method the orchestrator used to spell out here and that a paraphrase kept dropping: trace the failure scenario through the real code rather than voting on the finding's prose; engage the diff's own documented intent before calling a documented change a regression (the rule a run skipped when it auto-posted a false "leaks tokens" Critical); the one-way, quote-the-contradiction bar on **rejecting a Critical**; and — when a finding's claim is **runnable** and the repo has a fast unit harness (`vitest`/`jest`/`pytest`) — the option to **write and run a probe** and let the observed behaviour, not a re-reading, settle the verdict. That last one earns its place: measured on this repo, the strongest model traced a real double-execute (`!git push` firing twice) and called it correct; a probe that runs the path reports `sendShellCommand called twice` and the guessing stops. The brief makes the probe evidence rather than theatre with two hard rules — a mandatory self-check that the probe **flips** between buggy and correct, and leaving the tree exactly as found (no probe file, no fix edit, reaches the diff or build). A finding a probe confirmed carries `Source: [probe]`, which `compose-review` treats as deterministic (a run produced it), exactly like `[build]`/`[test]`. Read the brief to know what a verdict means; do not re-derive it here.
|
|
511
541
|
|
|
542
|
+
The brief also carries the **render-adjudication capability**: when the user has set `QWEN_REVIEW_SCRATCH_REPO` (an `owner/repo` designated for disposable test posts), a verifier facing a claim about GitHub's own rendering — mention defusal, tag stripping, fold behaviour — may post the minimal payload to that repo and read back GitHub's rendered HTML (`Accept: application/vnd.github.html+json`), because a local markdown library is only a model of GitHub and a claim about the authority cannot be settled against a model of it. Without the setting, such claims cap at low confidence / `cannot tell` rather than being "confirmed" off an approximation. This is the one narrowly-scoped exception to the no-writes rule, and Step 7 names it.
|
|
543
|
+
|
|
544
|
+
The brief also carries the **A/B capability**, which is the probe's counterpart for a claim that a probe structurally cannot settle. A probe runs the PR's code and answers "what does it do now"; it cannot answer "and what did it do before". A whole class of finding is exactly that difference — "this changes the output format", "this only adds a field", "cancelled and failed used to be indistinguishable" — and recovering the old behaviour by reading the diff is the step that goes wrong quietly, because the new lines are always present and always look right. So a verifier facing a comparative claim can run `qwen review base-tree`, which builds the merge base in a sibling worktree, and then run the same input on both sides and quote both outputs. Until this existed, `mergeBaseSha` was used for exactly one thing — choosing the diff range — and no step in this pipeline had ever built the code the PR is a change _to_. It costs an install and a build (reused across the review once built), so it is spent per finding rather than per review, and an unavailable base (no merge base, a stale one, a base that will not compile) is a fact about the harness that never becomes a finding against the PR.
|
|
545
|
+
|
|
546
|
+
The brief also carries **`extract-step`**, which is the A/B's counterpart for a claim about a **workflow**. A `run:` script is a shell program that happens to live inside YAML, and reviewing one in place fails in a way reading normal code does not: the body is indented inside a block scalar, the `env:` that decides its behaviour is spread over three levels — workflow, job, step, nearest wins, and two of them sit nowhere near the step — and every `${{ … }}` is a hole the reader silently fills in. `qwen review extract-step` lifts the script out **verbatim** as an executable and reports what the runner would have supplied around it: the merged three-level `env:` with each key's level named, every `${{ … }}` site listed unevaluated (the stub list — the command refuses to invent values), the resolved `shell` and `working-directory`, and a heuristic list of invoked commands. What to stub and what to feed it stays with the verifier, which is the judgment half; with `base-tree`, the two arms of a workflow A/B become two invocations. A `uses:` step has no `run:` and is refused rather than simulated.
|
|
547
|
+
|
|
512
548
|
**After verification:** remove all rejected findings. Separate confirmed findings into two groups: high-confidence and low-confidence. Low-confidence findings appear **only in terminal output** (under "Needs Human Review") and are **never posted as PR inline comments** — this preserves the "Silence is better than noise" principle for PR interactions.
|
|
513
549
|
|
|
514
550
|
### Pattern aggregation
|
|
@@ -629,12 +665,22 @@ List every chunk that returned `Uncoverable` in Step 3, with the files it spans,
|
|
|
629
665
|
|
|
630
666
|
If there are none of these, omit this section.
|
|
631
667
|
|
|
668
|
+
### Previous round's findings (incremental re-review only)
|
|
669
|
+
|
|
670
|
+
The ledger has two sources, in priority order: **the PR itself** — `pr-context` recovers the machine ledger embedded in this account's last posted review and renders it as the "Previous /review round (machine ledger)" section (also written beside the context file as `qwen-review-pr-<n>-prev-ledger.json`) — and, as fallback for rounds that never posted, the local cache. The PR copy is authoritative because it survives what the cache cannot: CI, another machine, a fresh clone. **This ruling section runs at medium effort too** — recovering the ledger costs nothing (pr-context already fetched the reviews), and a re-review that ignores what it told the author last round is the amnesia this exists to end; medium still writes no cache and posts nothing, exactly as before. When either source loaded a ledger, this review is **round N+1 of the same PR**, and the single most useful thing it can tell the reader is what happened to round N's findings — a re-reviewer who only lists new findings leaves the author to diff two reports by hand. Rule on **every** ledger entry against the code at the reviewed commit, exactly the way the open-Criticals re-check below rules (trace the mechanism; the diff containing a fix is not the same claim as the defect no longer firing):
|
|
671
|
+
|
|
672
|
+
- **fixed** — the mechanism can no longer fire. Say so, by id, in one line: `R1-2 fixed by <what>`. Do not re-report it as a finding. The sibling-entrance rule from the re-check below applies here unchanged: for a divergence-class entry, `fixed` is a ruling about the family's entrances, checked one by one — a still-open sibling becomes a fresh `R<round>-<n>` entry, never a reason to withhold the original's `fixed`.
|
|
673
|
+
- **still stands** — re-report it **under its original id**, updating the location if the code moved. It keeps its severity; a still-standing Critical blocks exactly as a new one would. Write that id into the re-report itself, immediately after the severity marker — `**[Critical]** R1-2: <the claim>` — and into the body entry if it cannot be anchored (`R1-2 <the claim>`). That prefix is not decoration: `compose-review` reads it back out of the comment when it builds the marker, and it is the only way an id survives into the machine ledger the next round recovers. Omit it and the same claim comes back renumbered, which is exactly what carrying the id forward exists to prevent.
|
|
674
|
+
- **cannot tell** — say so by id; a previous-round _Critical_ you cannot rule on joins `cannotTellCriticals` (it caps like any undecided blocker), a Suggestion is just disclosed.
|
|
675
|
+
|
|
676
|
+
Render the rulings as a short table at the top of the Findings section — id, one-line title, this round's status — so the report reads as a continuation, the way a human reviewer's round-2 comment opens with "M1 is fixed". The incremental scope rule does not conflict with this: the _diff_ reviewed is `lastCommitSha..HEAD`, but a ledger ruling reads the code at HEAD, which every agent already has.
|
|
677
|
+
|
|
632
678
|
### Before an Approve or a zero-Critical verdict: re-check the open Criticals
|
|
633
679
|
|
|
634
680
|
A `C=0` outcome — Approve, or a Comment with no Critical — is a claim that nothing blocks the merge. It is not the default you fall back to when your own agents surfaced nothing. **If Step 1 set the context-unavailable state** (`pr-context` failed — lightweight or same-repo), there is no context file to read: skip the walk below, record every existing Critical as `cannot tell` by construction, and carry that into the verdict — which the Step 7 invariant already caps at `COMMENT`. Otherwise, take **each live blocker already on the PR — from every comment-bearing section of the context file: "Open inline comments", "Blockers to re-check", "Review summaries", and "Already discussed" (both its inline threads and its issue-level comments)** — and check it against the code as it stands at the reviewed commit. Select **semantically, not by the literal marker**: a `**[Critical]**` prefix qualifies, but so does any body that asserts a blocking defect in other words — a "Critical findings could not be anchored" preamble, an explicit must-fix claim (legacy body-only blockers were emitted markerless, and one such review is exactly what a marker filter once discarded). When unsure whether a body asserts a blocker, re-check it — the cost is one ruling; the alternative is certifying a merge past it. ("Already discussed" stays in scope even though `pr-context` now promotes blocker-bearing bodies out of it: `carriesBlockerSignal` is a **fail-safe floor, not a ceiling** — it recognises the phrasings we have seen, not every phrasing that exists, and a blocker worded around all of them still settles there. That section's "do NOT re-report" header governs duplicate-_reporting_ by the finder agents; it does not exempt a body from this re-check. Read it with the same eyes you bring to the promoted section.) Review-level bodies matter because an unmappable or 422-relocated blocker lives **only** there — and the context file now carries them **in full**: `pr-context` renders every meaningful review body whole under "Review summaries" (no more 240-character snippets), and pulls every blocker-bearing body — replied inline thread or issue comment, marker or no marker — into the "Blockers to re-check" section, rendered in full, because a reply alone never settles a blocker. So the re-check usually needs no separate fetch: read those sections under the file's untrusted-data preamble, paging with `offset`/`limit` until `isTruncated` is false. **For the status half of each INLINE-thread ruling — is the anchor outdated, did the anchored file change since the blocker was filed, which commits touched it — read Step 1's `comment-status` report instead of fetching per-comment metadata**: its `code.touchedBy` list is the candidate "fixed by" commits to read, and `changedSinceComment: false` (with no head drift) tells you the anchored file is untouched since the blocker — so a claimed fix, if any, must live in some OTHER file, and the mechanism-read below is still owed either way. Two scope limits, both deliberate: the report exists only **when Step 1 wrote it** (worktree mode, fetch succeeded — a lightweight-mode run still walks this re-check and re-derives status facts the old way), and it indexes **inline threads only** — an issue-level or review-level blocker (the #6486 shape) has no entry there and keeps the context-file walk as its sole source. The report never substitutes for reading the code: it routes the read, it does not rule. Review summaries and blocker bodies are rendered in full; the Open and Already-discussed sections use one-line snippets, and **every snippet the renderer cut carries its own `_(truncated — fetch …)_` note naming the exact, already-filled-in command for the rest** — a candidate blocker whose snippet was cut is ruled on only after running that fetch; ruling on the visible prefix alone is the fail-closed violation. Run any such fetch **redirected to a file, never into the terminal** (Shell returns only an approximately 4 000-character model preview for output beyond its 30 000-character persistence trigger, which would re-truncate the very body being completed): append `--jq .body > .qwen/tmp/qwen-review-{target}-body-<id>.md` to the command the note names, then `read_file` that file, paging until `isTruncated` is false, before ruling. **Fail closed either way:** a body you could not read whole — the capped tail unfetched, or the single-object fetch failing (auth, rate limit, network) — is `cannot tell`, not "no Critical in it": it goes to compose-review's `cannotTellCriticals` input, which serializes it and caps the event at `COMMENT`; a blocker you could not read is never approved past. A reply alone does not retire a blocker — "I disagree" or "wontfix" is a reply, which is exactly why `pr-context` quarantines blocker-bearing threads in their own section instead of letting them settle into "Already discussed". Only the code decides: a blocker counts as closed exactly when the re-check below lands on "fixed by this diff", never because the thread has an answer. Record one verdict per blocker:
|
|
635
681
|
|
|
636
682
|
- **still stands** — the defect is present in the code you just read. It blocks: the event is `REQUEST_CHANGES`, and the finding goes inline (or into the body if it cannot be anchored).
|
|
637
|
-
- **fixed by this diff** — you traced the blocker's **mechanism** through the code as it now stands and it can no longer fire. Say nothing; do not re-report it. A GitHub thread can read `isResolved: false, isOutdated: false` for a bug a later commit fixed on an adjacent line — the flag tracks the anchored line, not the fix, so the flag is not evidence either way. Only the code is.
|
|
683
|
+
- **fixed by this diff** — you traced the blocker's **mechanism** through the code as it now stands and it can no longer fire. Say nothing; do not re-report it. A GitHub thread can read `isResolved: false, isOutdated: false` for a bug a later commit fixed on an adjacent line — the flag tracks the anchored line, not the fix, so the flag is not evidence either way. Only the code is. **And "the mechanism" means the FAMILY, not the one input the fix answered**: when the blocker is a divergence-class defect — a parser bypass, an escaping hole, a filter gap — enumerate the sibling entrances to the same mechanism and check each one at the reviewed commit before ruling `fixed`. A live six-round dogfood is the caution: the fix closed the fence-shaped door into a raw-HTML block, and the code-span door beside it — same divergence, adjacent syntax — stayed open; a re-check that tested only the reported input ruled `fixed` over a hole one backtick away. A sibling entrance you found still open is a **new finding** (report it), and the original blocker is still `fixed` only if its own input is closed — the two rulings are separate, and conflating them is how the second hole ships unreviewed.
|
|
638
684
|
|
|
639
685
|
**"The diff adds a fix" is not the same claim as "the defect can no longer fire", and this verdict requires the second one.** A fix's new lines are in the diff, but whether they _work_ frequently turns on code the diff never touches — a sibling subscriber, a registry entry, a dispatch order, a global binding, a default in a caller three files away. Read the diff alone and you see a plausible fix and rule it good. **So: name the mechanism the blocker claims, then name what now stops it. If that stopping condition lives outside the diff, go read it at the reviewed commit — a blocker in "Blockers to re-check" carries a `Referenced code` list extracted from its own body whenever it names a file, and the locations on it that the PR does not touch are precisely the ones this rule is about.** If you did not read them, you do not have this verdict; you have `cannot tell`. A blocker that cites no file gets no list, and hands you no shortcut: trace the mechanism through the code yourself, on the same terms.
|
|
640
686
|
|
|
@@ -661,6 +707,30 @@ Two failure modes this closes, both observed in this repo's own dogfood: reporti
|
|
|
661
707
|
|
|
662
708
|
**You do not read its output or decide anything from it — `compose-review` does.** It derives the report's path from the plan (the pr-numbered name above, next to the plan; `qwen-review-script-lint.json` for a local review), reads it as the sole authority, and turns it into the verdict itself: a finding on a **changed line** above cosmetic `style` becomes a **pre-confirmed `[lint]` Critical** that needs no verifier (the tool already ran); an **uninstalled or crashed** checker becomes **unreviewed scope** that caps a would-be Approve; a **deferred** checker — a workflow's embedded `run:` shell, which `actionlint` would lint but whose output this env cannot trust — is **disclosed in the body on every verdict (including Approve) but does not cap**, because it is a tool limitation, not a gap the author can close; and — the proof it ran — a diff that carries an executable script but produced **no readable report** is itself unreviewed (fail closed). That is the whole reason it runs here rather than inside an agent: neither the blocker nor its severity depends on a model, and skipping the command cannot slip an Approve past the fail-closed gate. It is harmless when the diff has no scripts (it reports "nothing to lint"), and it must write to the derived path or `compose-review` will not find it.
|
|
663
709
|
|
|
710
|
+
### The Test Plan check (deterministic — you run it, not an agent)
|
|
711
|
+
|
|
712
|
+
**For a PR review, rule on the claims the author already wrote down.** A Test Plan is the one place in a pull request where the author states, in their own words, what they ran and what they saw — a list of falsifiable assertions, handed to the reviewer for free. Nothing in this pipeline read it. `pr-context` renders the PR body, but its consumer is Agent 0, whose question is root-cause fidelity ("is this the right fix for the linked issue?"), not "the author says 471 tests pass — do they?". So a Test Plan could name a file the diff never adds, invoke an npm script that does not exist, or report a count from three commits ago, and the review would approve around it.
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
"${QWEN_CODE_CLI:-qwen}" review test-plan \
|
|
716
|
+
--plan <the plan report from Step 1> \
|
|
717
|
+
--pr <pr_number> --repo <owner>/<repo> \
|
|
718
|
+
--worktree <worktreePath> \
|
|
719
|
+
--build-test <Agent 7's build-test report, when this review produced one> \
|
|
720
|
+
--out <the plan report's directory>/qwen-review-pr-<n>-test-plan.json
|
|
721
|
+
# GitHub Enterprise: add --host <host> — it fetches the PR description.
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
Run it on a same-repo **PR** review only. A **local** or **file** review has no PR body, and a cross-repo **lightweight** review has no worktree to resolve paths against; the command is skipped in both, and `compose-review` expects nothing from it there.
|
|
725
|
+
|
|
726
|
+
**You do not read its output or decide anything from it — `compose-review` does**, from the path derived off the plan, exactly as it does for `script-lint`. What it rules on, and what it deliberately refuses to:
|
|
727
|
+
|
|
728
|
+
- A **path** the Test Plan names that is in neither the diff nor the tree at the reviewed commit is `contradicted` — the sentence describes a commit that is not this one. A path that exists but the diff does not touch is fine: "ran the existing suite at X" is a legitimate thing to write.
|
|
729
|
+
- An **npm script** the Test Plan tells the reviewer to run that no workspace manifest defines is `contradicted` — the Test Plan cannot be followed. A command this review actually ran is settled by its exit code instead, which outranks the manifest lookup.
|
|
730
|
+
- A **test count** that differs from what this review's suites reported is `differs`, and **never** `contradicted`. A count is only falsifiable against the suite the author meant, and a Test Plan almost never says which one; `build-test` runs the subset of workspaces the diff touched, which is frequently a different set. Ruling "471 ≠ 472, contradiction" off that mismatch would file a defect on arithmetic the command cannot do. Both numbers are reported side by side, and the reader decides.
|
|
731
|
+
|
|
732
|
+
**None of it blocks, and none of it caps.** A Test Plan defect is not a code defect — the diff is unaffected — and the verdict is about the code. The notes are disclosed in the body on every event including Approve, the same disclosed-but-not-capping treatment a deferred checker gets, and for the same reason: an author cannot fix "you wrote a sentence I could not check", so it must never become a permanent cap.
|
|
733
|
+
|
|
664
734
|
### Verdict
|
|
665
735
|
|
|
666
736
|
**You do not decide the verdict, and you do not write it. Ask for it:**
|
|
@@ -690,20 +760,59 @@ The rules it applies — so you can read the line it gives you, not so you can a
|
|
|
690
760
|
|
|
691
761
|
**The `FIX:` lines on stderr are that repair, spelled out.** For every repairable gap it capped on, `compose-review` prints one `FIX:` line naming the command — with this run's plan path already substituted. The parts that vary per agent stay as selectors: take `<id>`, `<r>` and `<path>` from the labels in the same report (never paste a literal `<...>` into a shell — it parses as a redirection), and add the `--rules` file whenever Step 2 loaded one. Execute them — **one repair round, then `compose-review` again**. If the same gap survives the round, stop: the cap stands, post with it, and disclose the gap. Do not loop repairs hoping for a different verdict, and do not skip the round and post a capped verdict the FIX lines could have lifted — both are the same failure, choosing the verdict over the evidence, in opposite directions.
|
|
692
762
|
|
|
763
|
+
### The findings, as data
|
|
764
|
+
|
|
765
|
+
**Write the findings artifact before you do anything else with them.** Everything that matters in this pipeline is a computed artifact — the diff plan, the coverage report, the resolved anchors, the verdict — and the findings were the one exception: prose in a terminal, re-typed into the Step 8 report, re-typed again into the Step 7 review JSON. Three transcriptions of the same list, and this skill's history is a catalogue of what transcription costs (a Critical that changed severity between two sections of one review; an aggregate that arrived at `resolve-anchors` with its per-location anchors dropped and took the whole batch down).
|
|
766
|
+
|
|
767
|
+
Write every confirmed finding — high and low confidence alike — as a JSON array, then:
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
"${QWEN_CODE_CLI:-qwen}" review findings \
|
|
771
|
+
--input .qwen/tmp/qwen-review-{target}-findings-in.json \
|
|
772
|
+
--out .qwen/tmp/qwen-review-{target}-findings.json
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
**One finding, one name.** A high-effort PR review also writes the incremental cache's cross-round `findings` ledger (Step 8), whose ids are `R<round>-<n>` — use those same ids here: a finding that will enter the ledger gets its `R<round>-<n>` as the artifact `id`, and a carried-forward finding keeps the id it already has. Two id schemes for one finding is how "R1-2" in next round's report and "f7" in this round's outcome ledger turn out to be the same defect that nobody can join.
|
|
776
|
+
|
|
777
|
+
Each entry carries `id` (unique — outcomes and resolved anchors both join on it), `severity`, `confidence`, `source`, `summary`, `failureScenario`, and either `file`/`line`/`anchor` or, for a pattern aggregate, a `locations[]` array with **one entry per location** (`suggestedFix`, `category` and `shortSummary` are optional; `shortSummary` is derived from `summary` when absent). The command validates the shape, refuses a duplicate id, refuses a finding with no failure scenario, sorts by severity → confidence → file → line → id, and writes counts nobody then recomputes by hand. Read the artifact for the numbers you quote in the Summary. This is a **canonicalization**, not a gate: it does not decide the verdict — `compose-review` does that, from the same findings — and it does not run at low effort, where the pass is unverified and emits no verdict.
|
|
778
|
+
|
|
779
|
+
### Step 6B: Apply the findings (`--fix`)
|
|
780
|
+
|
|
781
|
+
**Run this only when the Step 1 verdict says `fix.effective` is true.** A requested-but-ineffective `--fix` (a PR target) has already produced its warning in Step 1; say nothing further and move on.
|
|
782
|
+
|
|
783
|
+
Apply each finding to the working tree with the `edit` tool — Criticals and the reuse/simplification/consistency findings alike. **Skip** any finding whose fix would change intended behaviour, would require changes well outside the reviewed diff, or that you judge on a second look to be a false positive. Note the skip; do not argue with it in prose.
|
|
784
|
+
|
|
785
|
+
Then record what happened to **every** finding — one of `fixed`, `skipped`, or `no_change_needed` — as a JSON array of `{id, outcome, note?}`, and merge it back:
|
|
786
|
+
|
|
787
|
+
```bash
|
|
788
|
+
"${QWEN_CODE_CLI:-qwen}" review findings \
|
|
789
|
+
--input .qwen/tmp/qwen-review-{target}-findings-in.json \
|
|
790
|
+
--outcomes .qwen/tmp/qwen-review-{target}-outcomes.json \
|
|
791
|
+
--out .qwen/tmp/qwen-review-{target}-findings.json \
|
|
792
|
+
--print
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
**The command refuses a ledger that does not account for every finding**, and that refusal is the whole reason it exists. A fixer that applies six of nine findings and reports six has not lied about any one of them — it has silently shortened the list, and the reader has no way to see the three that fell off. It also refuses an outcome for an id this review never produced, which is what a ledger built against the wrong list looks like. If it exits non-zero, the ledger is wrong, not the check: complete it and run it again.
|
|
796
|
+
|
|
797
|
+
The three words are three different claims and are not interchangeable. `fixed` — the edit is in the tree. `skipped` — the finding is real and you did not apply it; the note says why, and the reader still owes it attention. `no_change_needed` — the finding was wrong or the code already handled it; it comes **off** the reader's plate. Collapsing `skipped` into `no_change_needed` is how a review quietly retracts a finding it could not fix.
|
|
798
|
+
|
|
799
|
+
Report the outcome counts in the terminal summary, and list each `skipped` finding with its reason. **Do not re-run Steps 1–6** to check your own work: a re-review of a tree you just edited is a new review of different code, and its verdict is not this review's.
|
|
800
|
+
|
|
693
801
|
Append a follow-up tip after the verdict (high and medium effort — only a **low** quick pass emits no verdict and uses Step 3C's tip instead; its "post comments" follow-up is declined per Step 3C). At **medium**, also add: "Tip: run `/review <target> --effort high` for the full verified review (adds the reverse audit, the adversarial personas, and Agent 8 — and can certify Approve)." Choose the rest based on remaining state:
|
|
694
802
|
|
|
695
|
-
- **Local review with unfixed findings
|
|
803
|
+
- **Local review with unfixed findings** (Step 6B did not run — `--fix` was not passed): "Tip: type `fix these issues` to apply fixes interactively, or re-run with `/review --fix` to have the review apply and account for them itself."
|
|
804
|
+
- **Local review where Step 6B ran**: offer no fix tip — the findings already carry outcomes. If any came back `skipped`, say so with their reasons instead.
|
|
696
805
|
- **PR review with findings** (only if `--comment` was NOT specified — if `--comment` was set, comments are already being posted in Step 7, so this tip is unnecessary): "Tip: type `post comments` to publish findings as PR inline comments." (Do NOT offer "fix these issues" for PR reviews — the worktree is cleaned up after the review, so interactive fixing is not possible.)
|
|
697
806
|
- **PR review, zero findings** (only if `--comment` was NOT specified): "Tip: type `post comments` to approve this PR on GitHub."
|
|
698
807
|
- **Local review, all clear** (Approve or all issues fixed): "Tip: type `commit` to commit your changes."
|
|
699
808
|
|
|
700
|
-
If the user responds with "fix these issues" (local review only), use the `edit` tool to fix each remaining finding interactively based on the suggested fixes from the review — do NOT re-run Steps 1-6.
|
|
809
|
+
If the user responds with "fix these issues" (local review only), use the `edit` tool to fix each remaining finding interactively based on the suggested fixes from the review — do NOT re-run Steps 1-6. This is the same work Step 6B does; when the review has a findings artifact, record the outcomes into it the same way (`review findings --outcomes`) rather than leaving the list and the tree disagreeing about what was applied.
|
|
701
810
|
|
|
702
811
|
If the user responds with "post comments" (or similar intent like "yes post them", "publish comments"), proceed directly to Step 7 using the findings already collected — do NOT re-run Steps 1-6.
|
|
703
812
|
|
|
704
813
|
## Step 7: Submit PR review
|
|
705
814
|
|
|
706
|
-
**The whole rule in one sentence, so it survives even when the rest is compressed away: never run a `gh` command that writes to the pull request — `qwen review submit` is the only write path in this skill, and it refuses when the run is not authorised.** Everything below only spells out what "writes" covers so a compressor cannot quietly narrow it to a single API route. It is **every write path to the PR**, not one: no `gh api repos/.../pulls/<n>/reviews` (not to submit, not to "test" an anchor), no `gh pr comment`, no `gh pr review`, no `gh issue comment`, no `gh api` with POST/PATCH/PUT/DELETE against the PR's `issues/*` or `pulls/*` endpoints, and no editing or deleting existing comments. **You do not author PR-facing prose at all** — `compose-review` computes the review body from structured state (the verdict, the downgrade reasons, the body-Criticals), and there is no free-text field to pass through it; a free-form note you want to add is a note for the **terminal summary**, which the user reads, not for the pull request. The only text that reaches the PR is that computed body plus the inline finding comments, and both ride the one sanctioned write below. Dogfooded the hard way: a run that had lost these instructions to four context compressions decided its findings were "all duplicates", never called submit, and hand-posted a consolidated summary with `gh pr comment` — a write with no authorisation gate, no downgrade semantics, no `posted` fact, and no completion line; nothing downstream could tell it had happened. `cleanup` now audits the review window and flags issue comments by the reviewing account (submit never posts one — see Step 9), so that bypass is at least named in the terminal — a tripwire, not permission. The one write in this skill lives behind a check:
|
|
815
|
+
**The whole rule in one sentence, so it survives even when the rest is compressed away: never run a `gh` command that writes to the pull request — `qwen review submit` is the only write path in this skill, and it refuses when the run is not authorised.** Everything below only spells out what "writes" covers so a compressor cannot quietly narrow it to a single API route. It is **every write path to the PR**, not one: no `gh api repos/.../pulls/<n>/reviews` (not to submit, not to "test" an anchor), no `gh pr comment`, no `gh pr review`, no `gh issue comment`, no `gh api` with POST/PATCH/PUT/DELETE against the PR's `issues/*` or `pulls/*` endpoints, and no editing or deleting existing comments. (One narrowly-scoped carve-out exists and it does not touch the PR: the Step 4 render-adjudication check may post a minimal payload to the repo the **user designated** in `QWEN_REVIEW_SCRATCH_REPO` — that repo, that check, nothing else; absent the setting there is no carve-out at all, and nothing about the PR, its code, or its authors is ever posted there.) **You do not author PR-facing prose at all** — `compose-review` computes the review body from structured state (the verdict, the downgrade reasons, the body-Criticals), and there is no free-text field to pass through it; a free-form note you want to add is a note for the **terminal summary**, which the user reads, not for the pull request. The only text that reaches the PR is that computed body plus the inline finding comments, and both ride the one sanctioned write below. Dogfooded the hard way: a run that had lost these instructions to four context compressions decided its findings were "all duplicates", never called submit, and hand-posted a consolidated summary with `gh pr comment` — a write with no authorisation gate, no downgrade semantics, no `posted` fact, and no completion line; nothing downstream could tell it had happened. `cleanup` now audits the review window and flags issue comments by the reviewing account (submit never posts one — see Step 9), so that bypass is at least named in the terminal — a tripwire, not permission. The one write in this skill lives behind a check:
|
|
707
816
|
|
|
708
817
|
```bash
|
|
709
818
|
"${QWEN_CODE_CLI:-qwen}" review submit \
|
|
@@ -860,12 +969,12 @@ Rationale: an inline comment is the only place GitHub renders a ` ```suggestion
|
|
|
860
969
|
{
|
|
861
970
|
"path": "src/file.ts",
|
|
862
971
|
"line": 42,
|
|
863
|
-
"body": "**[Critical]** issue description — Failure scenario: <trigger> → <wrong outcome>\n\n```suggestion\nfix code\n```\n\n_— YOUR_MODEL_ID via Qwen Code /
|
|
972
|
+
"body": "**[Critical]** issue description — Failure scenario: <trigger> → <wrong outcome>\n\n```suggestion\nfix code\n```\n\n_— YOUR_MODEL_ID via Qwen Code /review (v{{cliVersion}})_",
|
|
864
973
|
},
|
|
865
974
|
{
|
|
866
975
|
"path": "src/other.ts",
|
|
867
976
|
"line": 88,
|
|
868
|
-
"body": "**[Suggestion]** recommended improvement — Concrete cost: <what is duplicated/wasted/fragile>\n\n```suggestion\nimproved code\n```\n\n_— YOUR_MODEL_ID via Qwen Code /
|
|
977
|
+
"body": "**[Suggestion]** recommended improvement — Concrete cost: <what is duplicated/wasted/fragile>\n\n```suggestion\nimproved code\n```\n\n_— YOUR_MODEL_ID via Qwen Code /review (v{{cliVersion}})_",
|
|
869
978
|
},
|
|
870
979
|
],
|
|
871
980
|
"state": {
|
|
@@ -904,7 +1013,7 @@ The verdict is a computed fact and this is the second place it must not be re-de
|
|
|
904
1013
|
|
|
905
1014
|
When `startLine === line`, emit only `"line"` — a single-line comment needs no side (it defaults to `RIGHT`, which is what every comment here is). Do **not** send `start_line` on its own: the multi-line form that omits `start_side` is the one shape of this feature that fails, and it fails by discarding every inline blocker in the review.
|
|
906
1015
|
|
|
907
|
-
- Comment body format: `**[Critical]** issue description — Failure scenario: <trigger> → <wrong outcome>\n\n```suggestion\nfix\n```\n\n_— YOUR_MODEL_ID via Qwen Code /
|
|
1016
|
+
- Comment body format: `**[Critical]** issue description — Failure scenario: <trigger> → <wrong outcome>\n\n```suggestion\nfix\n```\n\n_— YOUR_MODEL_ID via Qwen Code /review (v{{cliVersion}})_` — use the `**[Suggestion]**` prefix for Suggestion-level findings so the author can tell blockers from recommendations at a glance. The `description` MUST carry the finding's concrete failure scenario (the trigger and the wrong outcome, or the concrete cost) — a posted comment that says only what to change, without why it fails, has lost the evidence the finder was required to produce. The prefix must be the **first thing in the body** and the footer must be present: `.github/workflows/qwen-autofix.yml` keys off both to keep Suggestion findings out of the autofix loop. Changing either string silently makes the autofix bot start applying non-blocking suggestions.
|
|
908
1017
|
- The model name is declared at the top of this prompt. You MUST include it in every footer. Do NOT omit the model name.
|
|
909
1018
|
- Use ` ```suggestion ` for one-click fixes; regular code blocks if fix spans multiple locations.
|
|
910
1019
|
- Only ONE comment per unique issue.
|
|
@@ -943,10 +1052,12 @@ Create the `.qwen/reviews/` directory if it doesn't exist. **For PR worktree mod
|
|
|
943
1052
|
Report content should include:
|
|
944
1053
|
|
|
945
1054
|
- Review timestamp and target description
|
|
1055
|
+
- **Provenance — the commits and the toolchain.** The head SHA reviewed (`fetchedSha` from the fetch report) and the base it was diffed against (`mergeBaseSha`), plus the platform and the Node/npm versions the gates ran on, and one line per gate with its result (`build`, `test`, `script-lint`, `test-efficacy`, `test-plan` — ran / clean / failed / skipped, and why). A saved report is read by someone who cannot re-derive what it was about: without the SHA pair a "Verdict: Approve" names no commit, so it can be neither checked against the PR nor distinguished from an approval of a different head; and without the gate line a reader cannot tell a gate that passed from one that never ran. Both facts are already in reports this run has open — copy them, do not re-measure.
|
|
946
1056
|
- Effort level the review ran at (low / medium / high; **low** findings are marked unverified — medium and high verify them in Step 4)
|
|
947
1057
|
- Diff statistics (files changed, lines added/removed) — omit if reviewing a file with no diff
|
|
948
1058
|
- Build & test results (Agent 7 output summary) — high and medium effort
|
|
949
|
-
- All findings with verification status
|
|
1059
|
+
- All findings with verification status. Read them out of the findings artifact `qwen review findings` wrote (`.qwen/tmp/qwen-review-{target}-findings.json`) rather than re-typing them from the terminal — a third transcription of the same list is a third chance for a severity to drift, which has happened inside a single review.
|
|
1060
|
+
- **Per-finding outcomes, when Step 6B ran** — `fixed` / `skipped` / `no_change_needed`, with the reason for every `skipped`. The artifact already carries them; a `--fix` run whose archive does not say which findings were applied is a report that reads as if all of them were.
|
|
950
1061
|
- Verdict (high and medium effort — a low quick pass claims none; a medium verdict never exceeds Comment, since it runs no reverse audit — see Step 5)
|
|
951
1062
|
|
|
952
1063
|
**The report's verdict is not yours to type.** `compose-review` printed the exact `Verdict:` line in Step 6 and persisted the same line as `verdictLine` inside `.qwen/tmp/qwen-review-{target}-composed.json` — copy either, verbatim. Do not reconstruct it from `event` + `cappedBy`: a presubmit downgrade also depends on fields that pair does not carry, and a rebuilt line can differ from the computed one. (And not `$(jq …)`: a `jq` binary is not guaranteed on the host, and a substitution that fails leaves the archived verdict blank or literal — worse than absent, because it looks written.)
|
|
@@ -967,11 +1078,24 @@ If reviewing a PR **at high effort**, update the review cache for incremental re
|
|
|
967
1078
|
"lastCommitSha": "<HEAD SHA captured in Step 1>",
|
|
968
1079
|
"lastModelId": "{{model}}",
|
|
969
1080
|
"lastReviewDate": "<ISO timestamp>",
|
|
1081
|
+
"round": <N — 1 on a first review, previous round + 1 after>,
|
|
970
1082
|
"findingsCount": <number>,
|
|
971
|
-
"verdict": "<verdict>"
|
|
1083
|
+
"verdict": "<verdict>",
|
|
1084
|
+
"findings": [
|
|
1085
|
+
{
|
|
1086
|
+
"id": "R<round>-<n>",
|
|
1087
|
+
"severity": "Critical | Suggestion",
|
|
1088
|
+
"file": "<path>",
|
|
1089
|
+
"line": <number>,
|
|
1090
|
+
"title": "<one line — enough for the next round to re-locate the claim>",
|
|
1091
|
+
"status": "open"
|
|
1092
|
+
}
|
|
1093
|
+
]
|
|
972
1094
|
}
|
|
973
1095
|
```
|
|
974
1096
|
|
|
1097
|
+
The cache is the FALLBACK copy of the ledger — the authoritative one rides the posted review body itself: `compose-review` embeds a machine-readable marker (an HTML comment, invisible on the PR page) carrying this round's findings and round number, and the next round's `pr-context` reads it back wherever it runs. A run that posts therefore persists its ledger even when this cache write is skipped; a run that does not post has only this cache, which is exactly why the cache remains. The `findings` ledger is what lets the **next** run open with "R1-2 is fixed" instead of a from-scratch list (see Step 6's previous-round section). Write every **newly confirmed high-confidence** finding under a fresh `R<round>-<n>` id, and carry a still-standing previous entry forward **under the id it already has** — the whole payoff is that `R1-2` names the same claim in every round, so a finding that survives is re-reported, never renumbered — while a finding ruled `fixed` this round leaves the ledger (the report said so; the cache is for what the next round must check, not history). Low-confidence and terminal-only findings stay out: the ledger holds claims this review stands behind, because next round re-asserts each one by id.
|
|
1098
|
+
|
|
975
1099
|
3. Ensure `.qwen/reviews/` and `.qwen/review-cache/` are ignored by `.gitignore` — a broader rule like `.qwen/*` also satisfies this. Only warn the user if those paths are not ignored at all.
|
|
976
1100
|
|
|
977
1101
|
## Step 9: Clean up
|