maestro-flow 0.4.19 → 0.4.21
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/.agents/agents/workflow-collab-planner.md +4 -1
- package/.agents/agents/workflow-plan-checker.md +11 -1
- package/.agents/agents/workflow-planner.md +4 -1
- package/.agents/skills/maestro/SKILL.md +8 -5
- package/.agents/skills/maestro-analyze/SKILL.md +1 -1
- package/.agents/skills/maestro-brainstorm/SKILL.md +2 -1
- package/.agents/skills/maestro-companion/SKILL.md +533 -0
- package/.agents/skills/maestro-grill/SKILL.md +116 -0
- package/.agents/skills/maestro-plan/SKILL.md +4 -0
- package/.agents/skills/maestro-ralph/SKILL.md +11 -7
- package/.agents/skills/maestro-ralph-execute/SKILL.md +2 -1
- package/.agents/skills/maestro-swarm-workflow/SKILL.md +266 -0
- package/.agents/skills/maestro-universal-workflow/SKILL.md +563 -0
- package/.agents/skills/manage-codebase-rebuild/SKILL.md +13 -1
- package/.agents/skills/manage-codebase-refresh/SKILL.md +3 -0
- package/.agents/skills/spec-setup/SKILL.md +9 -5
- package/.agents/skills/team-adversarial-swarm/SKILL.md +235 -0
- package/.agents/skills/team-adversarial-swarm/scripts/aco.py +473 -0
- package/.agents/skills/team-adversarial-swarm/scripts/pheromone.py +144 -0
- package/.agents/skills/team-adversarial-swarm/scripts/scoring.py +92 -0
- package/.agents/skills/team-adversarial-swarm/scripts/test_aco.py +475 -0
- package/.agents/skills/team-adversarial-swarm/specs/ant-output-schema.md +115 -0
- package/.agents/skills/team-adversarial-swarm/specs/convergence-criteria.md +75 -0
- package/.agents/skills/team-adversarial-swarm/specs/pheromone-schema.md +90 -0
- package/.agents/skills/team-adversarial-swarm/specs/swarm-config-template.json +66 -0
- package/.agents/skills/team-adversarial-swarm/specs/swarm-protocol.md +105 -0
- package/.agents/skills/team-adversarial-swarm/workflows/wf-swarm-converge.js +197 -0
- package/.agents/skills/team-adversarial-swarm/workflows/wf-swarm-explore.js +194 -0
- package/.agents/skills/team-adversarial-swarm/workflows/wf-swarm-score.js +188 -0
- package/.agents/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -0
- package/.agy/agents/workflow-collab-planner.md +4 -1
- package/.agy/agents/workflow-plan-checker.md +11 -1
- package/.agy/agents/workflow-planner.md +4 -1
- package/.agy/skills/maestro/SKILL.md +8 -5
- package/.agy/skills/maestro-analyze/SKILL.md +1 -1
- package/.agy/skills/maestro-brainstorm/SKILL.md +2 -1
- package/.agy/skills/maestro-companion/SKILL.md +529 -0
- package/.agy/skills/maestro-grill/SKILL.md +116 -0
- package/.agy/skills/maestro-plan/SKILL.md +4 -0
- package/.agy/skills/maestro-ralph/SKILL.md +11 -7
- package/.agy/skills/maestro-ralph-execute/SKILL.md +2 -1
- package/.agy/skills/maestro-swarm-workflow/SKILL.md +263 -0
- package/.agy/skills/maestro-universal-workflow/SKILL.md +560 -0
- package/.agy/skills/manage-codebase-rebuild/SKILL.md +13 -1
- package/.agy/skills/manage-codebase-refresh/SKILL.md +3 -0
- package/.agy/skills/spec-setup/SKILL.md +9 -5
- package/.agy/skills/team-adversarial-swarm/SKILL.md +244 -0
- package/.agy/skills/team-adversarial-swarm/scripts/aco.py +473 -0
- package/.agy/skills/team-adversarial-swarm/scripts/pheromone.py +144 -0
- package/.agy/skills/team-adversarial-swarm/scripts/scoring.py +92 -0
- package/.agy/skills/team-adversarial-swarm/scripts/test_aco.py +475 -0
- package/.agy/skills/team-adversarial-swarm/specs/ant-output-schema.md +115 -0
- package/.agy/skills/team-adversarial-swarm/specs/convergence-criteria.md +75 -0
- package/.agy/skills/team-adversarial-swarm/specs/pheromone-schema.md +90 -0
- package/.agy/skills/team-adversarial-swarm/specs/swarm-config-template.json +66 -0
- package/.agy/skills/team-adversarial-swarm/specs/swarm-protocol.md +105 -0
- package/.agy/skills/team-adversarial-swarm/workflows/wf-swarm-converge.js +197 -0
- package/.agy/skills/team-adversarial-swarm/workflows/wf-swarm-explore.js +194 -0
- package/.agy/skills/team-adversarial-swarm/workflows/wf-swarm-score.js +188 -0
- package/.agy/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -0
- package/.claude/agents/workflow-collab-planner.md +4 -1
- package/.claude/agents/workflow-plan-checker.md +11 -1
- package/.claude/agents/workflow-planner.md +4 -1
- package/.claude/commands/maestro-analyze.md +1 -1
- package/.claude/commands/maestro-brainstorm.md +2 -1
- package/.claude/commands/maestro-companion.md +531 -0
- package/.claude/commands/maestro-grill.md +114 -0
- package/.claude/commands/maestro-plan.md +4 -0
- package/.claude/commands/maestro-ralph-execute.md +2 -1
- package/.claude/commands/maestro-ralph.md +11 -7
- package/.claude/commands/maestro-swarm-workflow.md +264 -0
- package/.claude/commands/maestro-universal-workflow.md +561 -0
- package/.claude/commands/maestro.md +8 -5
- package/.claude/commands/manage-codebase-rebuild.md +13 -1
- package/.claude/commands/manage-codebase-refresh.md +3 -0
- package/.claude/commands/spec-setup.md +9 -5
- package/.claude/skills/team-adversarial-swarm/SKILL.md +233 -0
- package/.claude/skills/team-adversarial-swarm/scripts/aco.py +473 -0
- package/.claude/skills/team-adversarial-swarm/scripts/pheromone.py +144 -0
- package/.claude/skills/team-adversarial-swarm/scripts/scoring.py +92 -0
- package/.claude/skills/team-adversarial-swarm/scripts/test_aco.py +475 -0
- package/.claude/skills/team-adversarial-swarm/specs/ant-output-schema.md +115 -0
- package/.claude/skills/team-adversarial-swarm/specs/convergence-criteria.md +75 -0
- package/.claude/skills/team-adversarial-swarm/specs/pheromone-schema.md +90 -0
- package/.claude/skills/team-adversarial-swarm/specs/swarm-config-template.json +66 -0
- package/.claude/skills/team-adversarial-swarm/specs/swarm-protocol.md +105 -0
- package/.claude/skills/team-adversarial-swarm/workflows/wf-swarm-converge.js +197 -0
- package/.claude/skills/team-adversarial-swarm/workflows/wf-swarm-explore.js +194 -0
- package/.claude/skills/team-adversarial-swarm/workflows/wf-swarm-score.js +188 -0
- package/.claude/skills/team-adversarial-swarm/workflows/wf-swarm-synthesize.js +248 -0
- package/.codex/skills/maestro/SKILL.md +7 -2
- package/.codex/skills/maestro-companion/SKILL.md +485 -0
- package/.codex/skills/maestro-grill/SKILL.md +111 -0
- package/.codex/skills/maestro-ralph/SKILL.md +11 -7
- package/.codex/skills/manage-codebase-rebuild/SKILL.md +6 -0
- package/.codex/skills/manage-codebase-refresh/SKILL.md +6 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.d.ts +36 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.js +138 -2
- package/dashboard/dist-server/dashboard/src/server/wiki/graph-analysis.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/search.js +13 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/search.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.d.ts +11 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.js +178 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/virtual-wiki-adapters.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.d.ts +1 -0
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js +39 -23
- package/dashboard/dist-server/dashboard/src/server/wiki/wiki-indexer.js.map +1 -1
- package/dashboard/dist-server/src/graph/types.d.ts +111 -0
- package/dashboard/dist-server/src/graph/types.js +2 -0
- package/dashboard/dist-server/src/graph/types.js.map +1 -0
- package/dist/src/cli.js +1 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/kg.d.ts +11 -0
- package/dist/src/commands/kg.d.ts.map +1 -0
- package/dist/src/commands/kg.js +486 -0
- package/dist/src/commands/kg.js.map +1 -0
- package/dist/src/graph/analyzers/fs-analyzer.d.ts +10 -0
- package/dist/src/graph/analyzers/fs-analyzer.d.ts.map +1 -0
- package/dist/src/graph/analyzers/fs-analyzer.js +959 -0
- package/dist/src/graph/analyzers/fs-analyzer.js.map +1 -0
- package/dist/src/graph/index.d.ts +6 -0
- package/dist/src/graph/index.d.ts.map +1 -0
- package/dist/src/graph/index.js +6 -0
- package/dist/src/graph/index.js.map +1 -0
- package/dist/src/graph/loader.d.ts +3 -0
- package/dist/src/graph/loader.d.ts.map +1 -0
- package/dist/src/graph/loader.js +12 -0
- package/dist/src/graph/loader.js.map +1 -0
- package/dist/src/graph/merger.d.ts +56 -0
- package/dist/src/graph/merger.d.ts.map +1 -0
- package/dist/src/graph/merger.js +896 -0
- package/dist/src/graph/merger.js.map +1 -0
- package/dist/src/graph/query.d.ts +7 -0
- package/dist/src/graph/query.d.ts.map +1 -0
- package/dist/src/graph/query.js +126 -0
- package/dist/src/graph/query.js.map +1 -0
- package/dist/src/graph/types.d.ts +112 -0
- package/dist/src/graph/types.d.ts.map +1 -0
- package/dist/src/graph/types.js +2 -0
- package/dist/src/graph/types.js.map +1 -0
- package/dist/src/tui/install-ui/KgVendorConfig.d.ts +7 -0
- package/dist/src/tui/install-ui/KgVendorConfig.d.ts.map +1 -0
- package/dist/src/tui/install-ui/KgVendorConfig.js +9 -0
- package/dist/src/tui/install-ui/KgVendorConfig.js.map +1 -0
- package/dist/src/utils/update-notices.js +23 -0
- package/dist/src/utils/update-notices.js.map +1 -1
- package/package.json +1 -1
- package/workflows/analyze.md +2 -1
- package/workflows/brainstorm.md +24 -1
- package/workflows/codebase-rebuild.md +141 -1
- package/workflows/codebase-refresh.md +20 -0
- package/workflows/finish-work.md +7 -2
- package/workflows/grill.md +513 -0
- package/workflows/plan.md +7 -4
- package/workflows/specs-setup.md +99 -3
- package/workflows/swarm/wf-analyze.js +347 -0
- package/workflows/swarm/wf-brainstorm.js +456 -0
- package/workflows/swarm/wf-execute.js +379 -0
- package/workflows/swarm/wf-grill.js +359 -0
- package/workflows/swarm/wf-milestone-audit.js +385 -0
- package/workflows/swarm/wf-plan.js +468 -0
- package/workflows/swarm/wf-review.js +341 -0
- package/workflows/swarm/wf-verify.js +395 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'wf-review',
|
|
3
|
+
description: 'Multi-dimension code review with 3-vote adversarial verification and multi-perspective verdict',
|
|
4
|
+
whenToUse: 'Accelerate quality-review with parallel scanning + 3-vote finding verification + 3-perspective verdict arbitration',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Scan', detail: 'Parallel dimension scanning via workflow-reviewer' },
|
|
7
|
+
{ title: 'Verify', detail: '3-vote adversarial verification per critical finding (majority wins)' },
|
|
8
|
+
{ title: 'Report', detail: '3-perspective reporters (strict/lenient/objective) + arbitrated verdict' },
|
|
9
|
+
],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const REVIEW_DIMENSIONS = [
|
|
13
|
+
{ key: 'correctness', prefix: 'COR', prompt: 'Dimension: correctness. Focus: Logic errors, off-by-one, null handling, missing error propagation, type mismatches, unhandled edge cases, broken invariants, incorrect conditions.' },
|
|
14
|
+
{ key: 'security', prefix: 'SEC', prompt: 'Dimension: security. Focus: Injection vectors (SQL/command/XSS), auth bypass, hardcoded secrets, missing input validation, data exposure in logs/errors, SSRF, IDOR, insecure crypto.' },
|
|
15
|
+
{ key: 'performance', prefix: 'PRF', prompt: 'Dimension: performance. Focus: O(n^2+) algorithms, N+1 queries, missing pagination, resource leaks (unclosed handles/streams), synchronous blocking, missing caching, bundle size impact.' },
|
|
16
|
+
{ key: 'architecture', prefix: 'ARC', prompt: 'Dimension: architecture. Focus: Layer violations (UI calling DB directly), circular dependencies, god classes/functions, inconsistent patterns, tight coupling, missing abstractions.' },
|
|
17
|
+
{ key: 'maintainability', prefix: 'MNT', prompt: 'Dimension: maintainability. Focus: Functions >50 lines, cyclomatic complexity >10, duplicated logic, unclear naming, dead code, missing error context, poor separation of concerns.' },
|
|
18
|
+
{ key: 'best-practices', prefix: 'BPR', prompt: 'Dimension: best-practices. Focus: Deprecated API usage, framework anti-patterns, inconsistent style with codebase, missing TypeScript strict checks, raw `any` types, missing documentation for public APIs.' },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const FINDING_SCHEMA = {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
dimension: { type: 'string' },
|
|
25
|
+
findings: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
id: { type: 'string' },
|
|
31
|
+
dimension: { type: 'string' },
|
|
32
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
|
|
33
|
+
title: { type: 'string' },
|
|
34
|
+
file: { type: 'string' },
|
|
35
|
+
line: { type: 'number' },
|
|
36
|
+
description: { type: 'string' },
|
|
37
|
+
suggestion: { type: 'string' },
|
|
38
|
+
evidence: { type: 'string' },
|
|
39
|
+
},
|
|
40
|
+
required: ['id', 'dimension', 'severity', 'title', 'file', 'description'],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ['dimension', 'findings'],
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const VERDICT_SCHEMA = {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
finding_id: { type: 'string' },
|
|
51
|
+
is_real: { type: 'boolean' },
|
|
52
|
+
confidence: { type: 'number', minimum: 0, maximum: 100 },
|
|
53
|
+
reasoning: { type: 'string' },
|
|
54
|
+
adjusted_severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'false-positive'] },
|
|
55
|
+
},
|
|
56
|
+
required: ['finding_id', 'is_real', 'confidence', 'reasoning'],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const PERSPECTIVE_REPORT_SCHEMA = {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
perspective: { type: 'string' },
|
|
63
|
+
verdict: { type: 'string', enum: ['APPROVE', 'REQUEST_CHANGES', 'BLOCK'] },
|
|
64
|
+
overall_quality: { type: 'number', minimum: 1, maximum: 5 },
|
|
65
|
+
rationale: { type: 'string' },
|
|
66
|
+
blocking_issues: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, title: { type: 'string' }, file: { type: 'string' }, severity: { type: 'string' } }, required: ['id', 'title'] } },
|
|
67
|
+
confidence: { type: 'number', minimum: 0, maximum: 100 },
|
|
68
|
+
},
|
|
69
|
+
required: ['perspective', 'verdict', 'overall_quality', 'rationale', 'confidence'],
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const REPORT_SCHEMA = {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
verdict: { type: 'string', enum: ['APPROVE', 'REQUEST_CHANGES', 'BLOCK'] },
|
|
76
|
+
overall_quality: { type: 'number', minimum: 1, maximum: 5 },
|
|
77
|
+
dimension_summary: {
|
|
78
|
+
type: 'array',
|
|
79
|
+
items: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
82
|
+
dimension: { type: 'string' },
|
|
83
|
+
finding_count: { type: 'number' },
|
|
84
|
+
max_severity: { type: 'string' },
|
|
85
|
+
assessment: { type: 'string' },
|
|
86
|
+
},
|
|
87
|
+
required: ['dimension', 'finding_count'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
blocking_issues: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, title: { type: 'string' }, file: { type: 'string' }, severity: { type: 'string' }, suggestion: { type: 'string' } }, required: ['id', 'title', 'file', 'severity'] } },
|
|
91
|
+
adversarial_verdict: { type: 'object', properties: { strict: { type: 'string' }, lenient: { type: 'string' }, objective: { type: 'string' }, decisive_factor: { type: 'string' } }, required: ['strict', 'lenient', 'objective', 'decisive_factor'] },
|
|
92
|
+
summary: { type: 'string' },
|
|
93
|
+
},
|
|
94
|
+
required: ['verdict', 'overall_quality', 'dimension_summary', 'blocking_issues', 'adversarial_verdict', 'summary'],
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const target = args?.target || 'changed files on current branch'
|
|
98
|
+
const scope = args?.scope || ''
|
|
99
|
+
const specs = args?.specs || ''
|
|
100
|
+
const tier = args?.tier || 'standard'
|
|
101
|
+
const dimensions = args?.dimensions
|
|
102
|
+
? REVIEW_DIMENSIONS.filter(d => args.dimensions.includes(d.key))
|
|
103
|
+
: (tier === 'quick' ? REVIEW_DIMENSIONS.slice(0, 3) : REVIEW_DIMENSIONS)
|
|
104
|
+
|
|
105
|
+
// Phase 1: Parallel dimension scanning
|
|
106
|
+
phase('Scan')
|
|
107
|
+
log(`Scanning ${dimensions.length} dimensions in parallel via workflow-reviewer...`)
|
|
108
|
+
|
|
109
|
+
const scans = await parallel(
|
|
110
|
+
dimensions.map(dim => () =>
|
|
111
|
+
agent(
|
|
112
|
+
`${dim.prompt}
|
|
113
|
+
|
|
114
|
+
Review target: ${target}
|
|
115
|
+
${scope ? 'Files to review: ' + scope : 'Find changed files via git diff and review them.'}
|
|
116
|
+
${specs ? 'Project specs/conventions: ' + specs : ''}
|
|
117
|
+
|
|
118
|
+
Process:
|
|
119
|
+
1. Read the target files (use git diff if no explicit file list)
|
|
120
|
+
2. Perform structural scan — imports, exports, function signatures, complexity indicators
|
|
121
|
+
3. Apply dimension-specific analysis rules
|
|
122
|
+
4. Classify severity: Critical (security vuln, data corruption, crash) / High (logic bug, resource leak) / Medium (code smell, maintainability) / Low (style, minor optimization)
|
|
123
|
+
5. Return only real, actionable findings with specific file paths, line numbers, and evidence
|
|
124
|
+
|
|
125
|
+
Finding IDs use format: ${dim.prefix}-{NNN}`,
|
|
126
|
+
{ label: `scan:${dim.key}`, phase: 'Scan', schema: FINDING_SCHEMA, agentType: 'workflow-reviewer' }
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
const validScans = scans.filter(Boolean)
|
|
132
|
+
const allFindings = validScans.flatMap(s => s.findings)
|
|
133
|
+
const criticalHigh = allFindings.filter(f => f.severity === 'critical' || f.severity === 'high')
|
|
134
|
+
|
|
135
|
+
log(`Found ${allFindings.length} total (${criticalHigh.length} critical/high across ${validScans.length} dimensions)`)
|
|
136
|
+
|
|
137
|
+
// Phase 2: 3-vote adversarial verification per critical/high finding
|
|
138
|
+
phase('Verify')
|
|
139
|
+
|
|
140
|
+
const confirmedFindings = []
|
|
141
|
+
const falsePositives = []
|
|
142
|
+
|
|
143
|
+
if (criticalHigh.length > 0) {
|
|
144
|
+
log(`3-vote adversarial verification of ${criticalHigh.length} critical/high findings...`)
|
|
145
|
+
|
|
146
|
+
const verified = await pipeline(
|
|
147
|
+
criticalHigh,
|
|
148
|
+
(finding) => parallel([
|
|
149
|
+
() => agent(
|
|
150
|
+
`VOTE 1 — PROSECUTOR: Argue this finding IS REAL and the severity is justified.
|
|
151
|
+
|
|
152
|
+
Finding: [${finding.severity}] ${finding.id}: ${finding.title}
|
|
153
|
+
File: ${finding.file}${finding.line ? ':' + finding.line : ''}
|
|
154
|
+
Description: ${finding.description}
|
|
155
|
+
Evidence: ${finding.evidence || 'none provided'}
|
|
156
|
+
|
|
157
|
+
Read the actual source code. Build the case that this is a genuine issue:
|
|
158
|
+
- Show the exact code path that triggers the bug/vulnerability
|
|
159
|
+
- Demonstrate the impact with a concrete scenario
|
|
160
|
+
- Argue why the severity rating is correct or should be higher
|
|
161
|
+
|
|
162
|
+
Default to is_real=true. Only say false if the code clearly doesn't have this issue.`,
|
|
163
|
+
{ label: `vote1:${finding.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }
|
|
164
|
+
),
|
|
165
|
+
() => agent(
|
|
166
|
+
`VOTE 2 — DEFENSE: Argue this finding is a FALSE POSITIVE or overstated.
|
|
167
|
+
|
|
168
|
+
Finding: [${finding.severity}] ${finding.id}: ${finding.title}
|
|
169
|
+
File: ${finding.file}${finding.line ? ':' + finding.line : ''}
|
|
170
|
+
Description: ${finding.description}
|
|
171
|
+
Evidence: ${finding.evidence || 'none provided'}
|
|
172
|
+
|
|
173
|
+
Read the actual source code. Build the case AGAINST this finding:
|
|
174
|
+
- Show handling elsewhere that mitigates the issue
|
|
175
|
+
- Demonstrate why the severity is overstated
|
|
176
|
+
- Find framework guarantees or type safety that prevents the claimed scenario
|
|
177
|
+
|
|
178
|
+
Default to is_real=false. Only confirm if you genuinely cannot find any defense.`,
|
|
179
|
+
{ label: `vote2:${finding.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }
|
|
180
|
+
),
|
|
181
|
+
() => agent(
|
|
182
|
+
`VOTE 3 — INDEPENDENT JUDGE: Evaluate this finding objectively, without bias.
|
|
183
|
+
|
|
184
|
+
Finding: [${finding.severity}] ${finding.id}: ${finding.title}
|
|
185
|
+
File: ${finding.file}${finding.line ? ':' + finding.line : ''}
|
|
186
|
+
Description: ${finding.description}
|
|
187
|
+
Evidence: ${finding.evidence || 'none provided'}
|
|
188
|
+
|
|
189
|
+
Read the actual source code. Make an independent, evidence-based assessment:
|
|
190
|
+
- Verify the claimed behavior exists in the code
|
|
191
|
+
- Check if there are mitigations the reporter missed
|
|
192
|
+
- Assess the actual severity based on real-world impact
|
|
193
|
+
|
|
194
|
+
No default bias. Judge purely on evidence. Confidence should reflect evidence strength.`,
|
|
195
|
+
{ label: `vote3:${finding.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }
|
|
196
|
+
),
|
|
197
|
+
])
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
verified.filter(Boolean).forEach((votes, i) => {
|
|
201
|
+
const finding = criticalHigh[i]
|
|
202
|
+
const validVotes = votes.filter(Boolean)
|
|
203
|
+
const realVotes = validVotes.filter(v => v.is_real)
|
|
204
|
+
const isConfirmed = realVotes.length >= 2
|
|
205
|
+
|
|
206
|
+
if (isConfirmed) {
|
|
207
|
+
const avgConfidence = Math.round(realVotes.reduce((s, v) => s + v.confidence, 0) / realVotes.length)
|
|
208
|
+
const maxSeverity = validVotes.reduce((max, v) => {
|
|
209
|
+
const order = ['false-positive', 'low', 'medium', 'high', 'critical']
|
|
210
|
+
return order.indexOf(v.adjusted_severity || finding.severity) > order.indexOf(max) ? (v.adjusted_severity || finding.severity) : max
|
|
211
|
+
}, 'low')
|
|
212
|
+
confirmedFindings.push({
|
|
213
|
+
...finding,
|
|
214
|
+
vote_count: `${realVotes.length}/${validVotes.length}`,
|
|
215
|
+
avg_confidence: avgConfidence,
|
|
216
|
+
adjusted_severity: maxSeverity,
|
|
217
|
+
verdicts: validVotes,
|
|
218
|
+
})
|
|
219
|
+
} else {
|
|
220
|
+
falsePositives.push({
|
|
221
|
+
...finding,
|
|
222
|
+
vote_count: `${realVotes.length}/${validVotes.length}`,
|
|
223
|
+
verdicts: validVotes,
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
log(`Verified: ${confirmedFindings.length} confirmed, ${falsePositives.length} false-positives (3-vote majority)`)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const lowMedFindings = allFindings.filter(f => f.severity === 'medium' || f.severity === 'low')
|
|
232
|
+
|
|
233
|
+
// Phase 3: 3-perspective report generation + arbitrated verdict
|
|
234
|
+
phase('Report')
|
|
235
|
+
|
|
236
|
+
const findingsDigest = `Confirmed findings (${confirmedFindings.length}, adversarially verified by 3-vote majority):
|
|
237
|
+
${confirmedFindings.map(f => `- [${f.adjusted_severity}] ${f.id}: ${f.title} @ ${f.file}:${f.line || '?'} (votes: ${f.vote_count}, confidence: ${f.avg_confidence}%)`).join('\n') || 'None'}
|
|
238
|
+
|
|
239
|
+
False positives filtered (${falsePositives.length}):
|
|
240
|
+
${falsePositives.map(f => `- ${f.id}: ${f.title} (votes: ${f.vote_count})`).join('\n') || 'None'}
|
|
241
|
+
|
|
242
|
+
Low/medium findings (${lowMedFindings.length}, not individually verified):
|
|
243
|
+
${lowMedFindings.map(f => `- [${f.severity}] ${f.id}: ${f.title} @ ${f.file}`).join('\n') || 'None'}`
|
|
244
|
+
|
|
245
|
+
log('Launching 3-perspective reporters (strict / lenient / objective)...')
|
|
246
|
+
|
|
247
|
+
const perspectives = await parallel([
|
|
248
|
+
() => agent(
|
|
249
|
+
`You are the STRICT REVIEWER. Apply the highest quality bar.
|
|
250
|
+
|
|
251
|
+
${findingsDigest}
|
|
252
|
+
|
|
253
|
+
Your philosophy: ANY confirmed critical/high finding warrants BLOCK. Any confirmed finding warrants REQUEST_CHANGES. Only APPROVE if zero findings exist.
|
|
254
|
+
- Rate quality conservatively
|
|
255
|
+
- List ALL confirmed findings as blocking
|
|
256
|
+
- Consider unverified medium findings as potential risks
|
|
257
|
+
|
|
258
|
+
Be strict but fair. Provide your verdict and rationale.`,
|
|
259
|
+
{ label: 'report:strict', phase: 'Report', schema: PERSPECTIVE_REPORT_SCHEMA }
|
|
260
|
+
),
|
|
261
|
+
() => agent(
|
|
262
|
+
`You are the LENIENT REVIEWER. Apply a practical, ship-focused bar.
|
|
263
|
+
|
|
264
|
+
${findingsDigest}
|
|
265
|
+
|
|
266
|
+
Your philosophy: Only BLOCK for confirmed critical findings with >80% confidence. REQUEST_CHANGES for confirmed high findings. APPROVE for everything else — medium/low findings can be addressed in follow-ups.
|
|
267
|
+
- Rate quality generously (good code is the norm)
|
|
268
|
+
- Only list truly blocking issues
|
|
269
|
+
- Unverified medium/low findings are informational
|
|
270
|
+
|
|
271
|
+
Be practical but honest. Provide your verdict and rationale.`,
|
|
272
|
+
{ label: 'report:lenient', phase: 'Report', schema: PERSPECTIVE_REPORT_SCHEMA }
|
|
273
|
+
),
|
|
274
|
+
() => agent(
|
|
275
|
+
`You are the OBJECTIVE REVIEWER. Apply evidence-based judgment.
|
|
276
|
+
|
|
277
|
+
${findingsDigest}
|
|
278
|
+
|
|
279
|
+
Your philosophy: Follow the evidence. No default bias.
|
|
280
|
+
- BLOCK: confirmed critical findings exist
|
|
281
|
+
- REQUEST_CHANGES: confirmed high findings but no critical
|
|
282
|
+
- APPROVE: no confirmed critical/high findings
|
|
283
|
+
- Quality rating based on finding density and severity distribution
|
|
284
|
+
- Weight findings by vote confidence
|
|
285
|
+
|
|
286
|
+
Be analytical and evidence-driven. Provide your verdict and rationale.`,
|
|
287
|
+
{ label: 'report:objective', phase: 'Report', schema: PERSPECTIVE_REPORT_SCHEMA }
|
|
288
|
+
),
|
|
289
|
+
])
|
|
290
|
+
|
|
291
|
+
const validPerspectives = perspectives.filter(Boolean)
|
|
292
|
+
const verdictCounts = { APPROVE: 0, REQUEST_CHANGES: 0, BLOCK: 0 }
|
|
293
|
+
validPerspectives.forEach(p => { verdictCounts[p.verdict] = (verdictCounts[p.verdict] || 0) + 1 })
|
|
294
|
+
|
|
295
|
+
const perspectiveDigest = validPerspectives.map(p =>
|
|
296
|
+
`${p.perspective}: ${p.verdict} (quality: ${p.overall_quality}/5, confidence: ${p.confidence}%)\n ${p.rationale}`
|
|
297
|
+
).join('\n\n')
|
|
298
|
+
|
|
299
|
+
log(`Perspective votes: APPROVE=${verdictCounts.APPROVE} REQUEST_CHANGES=${verdictCounts.REQUEST_CHANGES} BLOCK=${verdictCounts.BLOCK}`)
|
|
300
|
+
log('Arbitrating final verdict...')
|
|
301
|
+
|
|
302
|
+
const report = await agent(
|
|
303
|
+
`Generate the final review report by arbitrating 3 reviewer perspectives.
|
|
304
|
+
|
|
305
|
+
=== 3 REVIEWER PERSPECTIVES ===
|
|
306
|
+
${perspectiveDigest}
|
|
307
|
+
|
|
308
|
+
Vote tally: APPROVE=${verdictCounts.APPROVE}, REQUEST_CHANGES=${verdictCounts.REQUEST_CHANGES}, BLOCK=${verdictCounts.BLOCK}
|
|
309
|
+
|
|
310
|
+
=== FINDING DATA ===
|
|
311
|
+
${findingsDigest}
|
|
312
|
+
|
|
313
|
+
ARBITRATE:
|
|
314
|
+
1. The final verdict follows MAJORITY VOTE among the 3 perspectives
|
|
315
|
+
2. Tie-break rule: if split 3 ways (1-1-1), go with the OBJECTIVE reviewer
|
|
316
|
+
3. If strict and objective agree → use their verdict regardless of lenient
|
|
317
|
+
4. Calculate overall_quality as weighted average (strict .25, lenient .25, objective .50)
|
|
318
|
+
5. Record adversarial_verdict with each perspective's vote and the decisive_factor
|
|
319
|
+
6. Compile dimension_summary from scan phase data
|
|
320
|
+
7. List blocking_issues = confirmed findings with adjusted_severity critical or high
|
|
321
|
+
8. Write summary including the adversarial deliberation outcome`,
|
|
322
|
+
{ label: 'arbitrate', phase: 'Report', schema: REPORT_SCHEMA }
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
report: report,
|
|
327
|
+
confirmed: confirmedFindings,
|
|
328
|
+
false_positives: falsePositives,
|
|
329
|
+
low_findings: lowMedFindings,
|
|
330
|
+
perspectives: validPerspectives,
|
|
331
|
+
metadata: {
|
|
332
|
+
target: target,
|
|
333
|
+
dimensions_scanned: dimensions.length,
|
|
334
|
+
total_findings: allFindings.length,
|
|
335
|
+
verified_count: criticalHigh.length,
|
|
336
|
+
confirmed_count: confirmedFindings.length,
|
|
337
|
+
false_positive_count: falsePositives.length,
|
|
338
|
+
verdict_votes: verdictCounts,
|
|
339
|
+
verdict: report ? report.verdict : 'UNKNOWN',
|
|
340
|
+
},
|
|
341
|
+
}
|