mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-11 22:53:00 +00:00
247 lines
12 KiB
Text
247 lines
12 KiB
Text
digraph CodeReview {
|
|
graph [
|
|
goal="Review the committed change with independent discovery jobs -- one single pass at low; grouped local-correctness passes, whole-change angles, and path-matched rule audits at every tier above -- verify every surviving candidate, and report only findings that pass.",
|
|
default_max_retries=0,
|
|
default_fidelity="compact",
|
|
on_failure="exit",
|
|
stall_timeout="14400s",
|
|
model_stylesheet="
|
|
{% set tiers = ['low', 'medium', 'high', 'xhigh', 'max'] %}
|
|
{% set effort = inputs.effort if inputs.effort in tiers else 'medium' %}
|
|
{% if 'kimi' in inputs.model %}
|
|
{% set finders = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'max', 'max': 'max'} %}
|
|
{% set verifiers = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'high', 'max': 'high'} %}
|
|
{% set sweeps = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'max', 'max': 'max'} %}
|
|
{% else %}
|
|
{% set finders = {'low': 'low', 'medium': 'medium', 'high': 'high', 'xhigh': 'xhigh', 'max': 'max'} %}
|
|
{% set verifiers = {'low': 'low', 'medium': 'medium', 'high': 'medium', 'xhigh': 'high', 'max': 'xhigh'} %}
|
|
{% set sweeps = {'low': 'low', 'medium': 'medium', 'high': 'high', 'xhigh': 'xhigh', 'max': 'xhigh'} %}
|
|
{% endif %}
|
|
* { model: {{ inputs.model }}; reasoning_effort: {{ finders[effort] }}; }
|
|
.grouping { model: {{ inputs.model }}; reasoning_effort: low; }
|
|
.verification { model: {{ inputs.model }}; reasoning_effort: {{ verifiers[effort] }}; }
|
|
.sweep { model: {{ inputs.model }}; reasoning_effort: {{ sweeps[effort] }}; }
|
|
"
|
|
]
|
|
rankdir=LR
|
|
|
|
start [shape=Mdiamond, label="Start"]
|
|
exit [shape=Msquare, label="Exit"]
|
|
prepare [
|
|
shape=parallelogram,
|
|
label="Resolve and size the review target",
|
|
timeout="300s",
|
|
output_schema="routing",
|
|
stdin_source="context.internal.run_id",
|
|
script="python3 -c \"import hashlib,sys; pairs=list(zip(sys.argv[1::2],sys.argv[2::2])); sys.exit(0 if pairs and all(hashlib.sha256(open(path,'rb').read()).hexdigest()==expected for path,expected in pairs) else 91)\" .fabro/workflows/code-review/scripts/code_review.py 78d239edb68be8e3db983445a786b9dca7eed6044ff4430e5581ae4c4c8466d3 .fabro/workflows/code-review/scripts/git_readonly.py 29cee508724f7bee8d73317d82fe94d0d830361476b367e4a012b70071a0e841 .fabro/workflows/code-review/scripts/publish_pr.py 35cde9006c9d079f468228498704c7c6079bff52fc790d7e2cee9505d3de9a06 .fabro/workflows/code-review/scripts/render_report.py fe432d8a53e1294b8030a54ca17b412312338e761ee751ab770e221450b53b8c .fabro/workflows/code-review/scripts/review_contract.py 8917fe7ae046cfda547f4f1240570fa295e110fd5e8d0c84c2a98719137db6fa .fabro/workflows/code-review/scripts/rule_loader.py eaa7258e5cf7b231a7a1192c9738eb2a0486480cd04ebe2059a79295040fc66e .fabro/workflows/code-review/specs/report-spec.md 7a54f72ee46f09218d18854d184a1f36875f9011877e94779c6b1f0d5dd118a9 .fabro/workflows/code-review/templates/report.html 5def570da34ca186da31781378367d70fb9c58e82f7aeec4aaf420fd348a8e61 .fabro/workflows/code-review/schemas/findings.schema.json 2f4d0a9052d5af0dad92db12a1e9d49cc91a282c4dddda495791352bf1559ed8 .fabro/workflows/code-review/schemas/verdict.schema.json de13ce02c5fd0c088640542831cc732e35dee3ddb38f89d4412f6a46fea75567 .fabro/workflows/code-review/schemas/file-groups.schema.json b53c4e1c0bbd07bbf70e83f4f3b35fd96cb880c621c7c424e95b9aea34e13d7c .fabro/workflows/code-review/prompts/finder.md.j2 86c2e6a032f7c54c1bbab1c12496a8f0d6bf48703abe6017eb175330608cf223 .fabro/workflows/code-review/prompts/verify.md.j2 cb3866240077d1bc8993b2f012a8d66a6ea61d4a9f2e88a1fefc6ef375f630e2 .fabro/workflows/code-review/prompts/sweep.md.j2 e6f89b47b11c57030a6ef7d5896ccb37dbd2a2982e9fa7eb7f2e3df73acab82c .fabro/workflows/code-review/prompts/group-files.md.j2 5b291313a1266d1d658f80ea7989cdefcd8609b6893b7197b17914d553dab041 .fabro/workflows/code-review/prompts/partials/finding-fields.md.j2 a81ee5b0ac134eb121dbf503025387c64126d3276e4673ebc836cfb62a3689fb .fabro/workflows/code-review/prompts/partials/guidance.md.j2 53bc0c40bb917288708bed1f9ba478fbd89b9790c92497762224cc752f40bef5 .fabro/workflows/code-review/prompts/partials/output-schema.md.j2 811994bb357739f2562d84f66dc05075ebe3c7f8d58034f8c25ee1c36bee996b .fabro/workflows/code-review/prompts/partials/read-only-explorer.md.j2 44a0244e7aa62fdb0dbbfdbadcffbfb640af249bae3e96895dedd5c7a33bad10 .fabro/workflows/code-review/prompts/partials/review-target.md.j2 abffeeff0e16b89a0754cd53f1833b3744494cd54ff761798b782a80467446ea .fabro/workflows/code-review/prompts/partials/safe-git-history.md.j2 4ddd8d36d5c51d7e166a6b7f1dff51b72cce0e64108cc7e892002ca909af8b3a .fabro/workflows/code-review/rules/builtin-manifest.json ecd1d77ad8c77cae153280cb775e5e5f7fa9b68925900473e7d2331af377bb49 && python3 .fabro/workflows/code-review/scripts/code_review.py prepare --review-id-stdin --mode {{ inputs.mode }} --effort {{ inputs.effort }} --scope {{ inputs.scope }} --base {{ inputs.base }} --commit {{ inputs.commit }} --range {{ inputs.range }} --model {{ inputs.model }} --guidance {{ inputs.guidance }}"
|
|
]
|
|
|
|
grouping [
|
|
label="Group target files",
|
|
class="grouping",
|
|
prompt="@prompts/group-files.md.j2",
|
|
output_schema="@schemas/file-groups.schema.json",
|
|
output_retries=2,
|
|
max_retries=2,
|
|
on_failure="route",
|
|
timeout="1800s",
|
|
project_memory=false
|
|
]
|
|
merge_grouping [
|
|
shape=parallelogram,
|
|
label="Merge the grouping proposal",
|
|
stdin_source="context.output.grouping",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge grouping",
|
|
output_schema="routing",
|
|
timeout="180s"
|
|
]
|
|
plan_finders [
|
|
shape=parallelogram,
|
|
label="Plan discovery jobs",
|
|
timeout="180s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py plan-finders"
|
|
]
|
|
|
|
finders [
|
|
shape=component,
|
|
label="Finder jobs",
|
|
for_each="context.finder_jobs",
|
|
max_parallel=10,
|
|
on_failure="succeed"
|
|
]
|
|
finder [
|
|
label="Finder job",
|
|
class="finder",
|
|
prompt="@prompts/finder.md.j2",
|
|
output_schema="@schemas/findings.schema.json",
|
|
output_retries=2,
|
|
max_retries=2,
|
|
on_failure="succeed",
|
|
timeout="7200s",
|
|
project_memory=false
|
|
]
|
|
finder_join [shape=tripleoctagon, label="Gather finder outputs"]
|
|
merge_finders [
|
|
shape=parallelogram,
|
|
label="Merge finder outputs",
|
|
stdin_source="context.parallel.results",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge finders",
|
|
output_schema="routing",
|
|
timeout="180s"
|
|
]
|
|
plan_verify [
|
|
shape=parallelogram,
|
|
label="Deduplicate, rank, and plan verification",
|
|
timeout="180s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py plan-verify"
|
|
]
|
|
|
|
verify [
|
|
shape=component,
|
|
label="Verify candidates",
|
|
for_each="context.verify_jobs",
|
|
max_parallel=24,
|
|
on_failure="succeed"
|
|
]
|
|
verifier [
|
|
label="Verify candidate",
|
|
class="verification",
|
|
prompt="@prompts/verify.md.j2",
|
|
output_schema="@schemas/verdict.schema.json",
|
|
output_retries=2,
|
|
max_retries=2,
|
|
on_failure="succeed",
|
|
timeout="3600s",
|
|
project_memory=false
|
|
]
|
|
verify_join [shape=tripleoctagon, label="Gather verdicts"]
|
|
merge_verify [
|
|
shape=parallelogram,
|
|
label="Merge verdicts",
|
|
stdin_source="context.parallel.results",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge verify",
|
|
output_schema="routing",
|
|
timeout="180s"
|
|
]
|
|
tally [
|
|
shape=parallelogram,
|
|
label="Apply verdicts and plan the sweep",
|
|
timeout="180s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py tally"
|
|
]
|
|
|
|
sweeper [
|
|
label="Gap-fill sweep",
|
|
class="sweep",
|
|
prompt="@prompts/sweep.md.j2",
|
|
output_schema="@schemas/findings.schema.json",
|
|
output_retries=2,
|
|
max_retries=2,
|
|
on_failure="route",
|
|
timeout="7200s",
|
|
project_memory=false
|
|
]
|
|
merge_sweep [
|
|
shape=parallelogram,
|
|
label="Merge sweep output",
|
|
stdin_source="context.output.sweeper",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge sweep",
|
|
output_schema="routing",
|
|
timeout="180s"
|
|
]
|
|
sweep_verify [
|
|
shape=component,
|
|
label="Verify sweep candidates",
|
|
for_each="context.sweep_verify_jobs",
|
|
max_parallel=24,
|
|
on_failure="succeed"
|
|
]
|
|
sweep_verifier [
|
|
label="Verify sweep candidate",
|
|
class="verification",
|
|
prompt="@prompts/verify.md.j2",
|
|
output_schema="@schemas/verdict.schema.json",
|
|
output_retries=2,
|
|
max_retries=2,
|
|
on_failure="succeed",
|
|
timeout="3600s",
|
|
project_memory=false
|
|
]
|
|
sweep_verify_join [shape=tripleoctagon, label="Gather sweep verdicts"]
|
|
merge_sweep_verify [
|
|
shape=parallelogram,
|
|
label="Merge sweep verdicts",
|
|
stdin_source="context.parallel.results",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge sweep_verify",
|
|
output_schema="routing",
|
|
timeout="180s"
|
|
]
|
|
|
|
final_tally [
|
|
shape=parallelogram,
|
|
label="Write the canonical review bundle",
|
|
timeout="300s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py final-tally"
|
|
]
|
|
render_report [
|
|
shape=parallelogram,
|
|
label="Derive Markdown, HTML, JSONL, and revision metadata",
|
|
timeout="300s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py render-report"
|
|
]
|
|
verify_expectations [
|
|
shape=parallelogram,
|
|
label="Verify configured report expectations",
|
|
timeout="30s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py verify-expectations --expected-min-findings '{{ inputs.expected_min_findings }}' --expected-file '{{ inputs.expected_file }}' --expected-min-rule-findings '{{ inputs.expected_min_rule_findings }}'"
|
|
]
|
|
publish_pr [
|
|
shape=parallelogram,
|
|
label="Publish findings to the reviewed PR (opt-in)",
|
|
timeout="900s",
|
|
output_schema="routing",
|
|
script="python3 .fabro/workflows/code-review/scripts/code_review.py publish-pr --post-pr '{{ inputs.post_pr }}' --pr-repo '{{ inputs.pr_repo }}' --pr-number '{{ inputs.pr_number }}' --route-severity-below '{{ inputs.route_severity_below }}' --route-categories '{{ inputs.route_categories }}' --run-url '{{ inputs.run_url }}'"
|
|
]
|
|
|
|
start -> prepare
|
|
prepare -> exit [condition="outcome=succeeded && context.empty_target=true"]
|
|
prepare -> grouping [condition="outcome=succeeded && context.use_grouping=true"]
|
|
prepare -> plan_finders [condition="outcome=succeeded && context.use_planner=true"]
|
|
prepare -> finders
|
|
|
|
grouping -> merge_grouping [condition="outcome=succeeded"]
|
|
grouping -> plan_finders
|
|
merge_grouping -> plan_finders
|
|
plan_finders -> finders
|
|
|
|
finders -> finder [fidelity="truncate"]
|
|
finder -> finder_join -> merge_finders
|
|
merge_finders -> plan_verify
|
|
|
|
plan_verify -> verify [condition="outcome=succeeded && context.run_verify=true"]
|
|
plan_verify -> tally
|
|
verify -> verifier [fidelity="truncate"]
|
|
verifier -> verify_join -> merge_verify
|
|
merge_verify -> tally
|
|
|
|
tally -> sweeper [condition="outcome=succeeded && context.run_sweep=true"]
|
|
tally -> final_tally
|
|
sweeper -> merge_sweep [condition="outcome=succeeded"]
|
|
sweeper -> final_tally
|
|
merge_sweep -> sweep_verify [condition="outcome=succeeded && context.run_sweep_verify=true"]
|
|
merge_sweep -> final_tally
|
|
sweep_verify -> sweep_verifier [fidelity="truncate"]
|
|
sweep_verifier -> sweep_verify_join -> merge_sweep_verify
|
|
merge_sweep_verify -> final_tally
|
|
|
|
final_tally -> render_report
|
|
render_report -> verify_expectations
|
|
verify_expectations -> publish_pr
|
|
publish_pr -> exit
|
|
}
|