reviewgate 0.1.0__tar.gz
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.
- reviewgate-0.1.0/.code-review-graph/.gitignore +3 -0
- reviewgate-0.1.0/.code-review-graph/graph.db +0 -0
- reviewgate-0.1.0/.github/workflows/agentboard-review.yml +100 -0
- reviewgate-0.1.0/.github/workflows/ci.yml +48 -0
- reviewgate-0.1.0/.gitignore +11 -0
- reviewgate-0.1.0/BENCHMARK.md +163 -0
- reviewgate-0.1.0/CONTRIBUTING.md +70 -0
- reviewgate-0.1.0/LICENSE +5 -0
- reviewgate-0.1.0/PKG-INFO +305 -0
- reviewgate-0.1.0/README.md +276 -0
- reviewgate-0.1.0/ROADMAP.md +134 -0
- reviewgate-0.1.0/bench/report.py +83 -0
- reviewgate-0.1.0/examples/paired_run.py +91 -0
- reviewgate-0.1.0/examples/run_fk_graph.py +89 -0
- reviewgate-0.1.0/examples/run_reliability_5x.py +124 -0
- reviewgate-0.1.0/examples/run_repo_review.py +97 -0
- reviewgate-0.1.0/examples/run_repo_review_llm.py +70 -0
- reviewgate-0.1.0/examples/run_review.py +135 -0
- reviewgate-0.1.0/examples/run_review_composite_fk.py +136 -0
- reviewgate-0.1.0/examples/run_review_fix.py +108 -0
- reviewgate-0.1.0/examples/run_review_perfile.py +83 -0
- reviewgate-0.1.0/examples/run_text_review.py +38 -0
- reviewgate-0.1.0/pyproject.toml +59 -0
- reviewgate-0.1.0/review_board_run2.html +723 -0
- reviewgate-0.1.0/review_board_run3.html +675 -0
- reviewgate-0.1.0/scripts/render_pr_comment.py +116 -0
- reviewgate-0.1.0/src/agentboard/__init__.py +62 -0
- reviewgate-0.1.0/src/agentboard/agents/__init__.py +0 -0
- reviewgate-0.1.0/src/agentboard/agents/critic_agent.py +174 -0
- reviewgate-0.1.0/src/agentboard/agents/fix_agent.py +98 -0
- reviewgate-0.1.0/src/agentboard/agents/fix_with_test_agent.py +135 -0
- reviewgate-0.1.0/src/agentboard/agents/gap_auditor.py +166 -0
- reviewgate-0.1.0/src/agentboard/agents/openai_agent.py +140 -0
- reviewgate-0.1.0/src/agentboard/agents/openai_explainer.py +77 -0
- reviewgate-0.1.0/src/agentboard/agents/peer_reviewer.py +184 -0
- reviewgate-0.1.0/src/agentboard/agents/reviewer_agent.py +253 -0
- reviewgate-0.1.0/src/agentboard/cli.py +771 -0
- reviewgate-0.1.0/src/agentboard/config.py +296 -0
- reviewgate-0.1.0/src/agentboard/dataset.py +192 -0
- reviewgate-0.1.0/src/agentboard/demo/__init__.py +10 -0
- reviewgate-0.1.0/src/agentboard/demo/target/demo.test.js +14 -0
- reviewgate-0.1.0/src/agentboard/demo/target/order_tool.js +22 -0
- reviewgate-0.1.0/src/agentboard/demo/target/package.json +7 -0
- reviewgate-0.1.0/src/agentboard/fingerprint.py +62 -0
- reviewgate-0.1.0/src/agentboard/graph.py +186 -0
- reviewgate-0.1.0/src/agentboard/ingestion/__init__.py +0 -0
- reviewgate-0.1.0/src/agentboard/ingestion/intent.py +48 -0
- reviewgate-0.1.0/src/agentboard/ingestion/output_invariants.py +113 -0
- reviewgate-0.1.0/src/agentboard/ingestion/pr_diff.py +111 -0
- reviewgate-0.1.0/src/agentboard/ingestion/repo_adapter.py +36 -0
- reviewgate-0.1.0/src/agentboard/ingestion/tech_detect.py +119 -0
- reviewgate-0.1.0/src/agentboard/ingestion/text_adapter.py +27 -0
- reviewgate-0.1.0/src/agentboard/interfaces.py +85 -0
- reviewgate-0.1.0/src/agentboard/loop.py +203 -0
- reviewgate-0.1.0/src/agentboard/personas.py +103 -0
- reviewgate-0.1.0/src/agentboard/proposal_cache.py +147 -0
- reviewgate-0.1.0/src/agentboard/review.py +185 -0
- reviewgate-0.1.0/src/agentboard/state.py +121 -0
- reviewgate-0.1.0/src/agentboard/verifiers/__init__.py +0 -0
- reviewgate-0.1.0/src/agentboard/verifiers/assertion_lint.py +59 -0
- reviewgate-0.1.0/src/agentboard/verifiers/finding_verifier.py +575 -0
- reviewgate-0.1.0/src/agentboard/verifiers/pytest_verifier.py +114 -0
- reviewgate-0.1.0/src/agentboard/verifiers/schema_verifier.py +53 -0
- reviewgate-0.1.0/src/agentboard/verifiers/transition_verifier.py +208 -0
- reviewgate-0.1.0/src/agentboard/verifiers/vitest_verifier.py +353 -0
- reviewgate-0.1.0/src/agentboard/whiteboards/__init__.py +0 -0
- reviewgate-0.1.0/src/agentboard/whiteboards/flow_adapter.py +314 -0
- reviewgate-0.1.0/src/agentboard/whiteboards/html_adapter.py +104 -0
- reviewgate-0.1.0/src/agentboard/whiteboards/tldraw_adapter.py +28 -0
- reviewgate-0.1.0/tests/test_audit_wiring.py +174 -0
- reviewgate-0.1.0/tests/test_config_preflight.py +207 -0
- reviewgate-0.1.0/tests/test_dataset.py +118 -0
- reviewgate-0.1.0/tests/test_determinism.py +202 -0
- reviewgate-0.1.0/tests/test_env_scrub.py +61 -0
- reviewgate-0.1.0/tests/test_failure_classification.py +58 -0
- reviewgate-0.1.0/tests/test_gate_e2e.py +166 -0
- reviewgate-0.1.0/tests/test_injection_placement.py +92 -0
- reviewgate-0.1.0/tests/test_loop.py +55 -0
- reviewgate-0.1.0/tests/test_multitarget.py +60 -0
- reviewgate-0.1.0/tests/test_openai_agent.py +66 -0
- reviewgate-0.1.0/tests/test_pnpm_pin.py +69 -0
- reviewgate-0.1.0/tests/test_proposal_cache.py +104 -0
- reviewgate-0.1.0/tests/test_sandbox_trust.py +231 -0
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: agentboard review
|
|
2
|
+
|
|
3
|
+
# Advisory pre-merge review: an LLM proposes edge-case tests, a deterministic
|
|
4
|
+
# gate executes them against this PR's code, and the evidence lands as a PR
|
|
5
|
+
# comment. Never blocking: confirmed gaps live in the comment, not the exit
|
|
6
|
+
# code. A human decides.
|
|
7
|
+
#
|
|
8
|
+
# Fork PRs are skipped by design: they cannot access OPENAI_API_KEY (repo
|
|
9
|
+
# secrets are withheld from forks), and that is correct; do not work around
|
|
10
|
+
# it.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
pull_request:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
pull-requests: write
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
review:
|
|
21
|
+
# Same-repo PRs only: forks have no access to the key.
|
|
22
|
+
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
29
|
+
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
|
|
34
|
+
- uses: actions/setup-node@v4
|
|
35
|
+
with:
|
|
36
|
+
node-version: "22"
|
|
37
|
+
|
|
38
|
+
- name: Install agentboard
|
|
39
|
+
# In agentboard's own repo this installs the PR's code (true
|
|
40
|
+
# dogfooding); in any other repo the local install fails fast and
|
|
41
|
+
# the fallback pulls the published tool.
|
|
42
|
+
run: pip install -e . 2>/dev/null || pip install git+https://github.com/anp0429/agentboard
|
|
43
|
+
|
|
44
|
+
- name: Pick a reviewable target from the PR's changed files
|
|
45
|
+
id: target
|
|
46
|
+
env:
|
|
47
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
48
|
+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
49
|
+
run: |
|
|
50
|
+
target=$(git diff --name-only "$BASE_SHA...$HEAD_SHA" \
|
|
51
|
+
| grep -E '\.(ts|tsx|js|jsx|mjs)$' \
|
|
52
|
+
| grep -vE '\.test\.|\.spec\.|/tests?/|__tests__' \
|
|
53
|
+
| head -1 || true)
|
|
54
|
+
echo "target=$target" >> "$GITHUB_OUTPUT"
|
|
55
|
+
if [ -z "$target" ]; then
|
|
56
|
+
echo "No reviewable source change in this PR; skipping quietly."
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
- name: Review
|
|
60
|
+
if: steps.target.outputs.target != ''
|
|
61
|
+
env:
|
|
62
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
63
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
64
|
+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
65
|
+
# Filenames are PR-controlled data. Passing through env (not inline
|
|
66
|
+
# expression interpolation) keeps shell metacharacters inert.
|
|
67
|
+
TARGET: ${{ steps.target.outputs.target }}
|
|
68
|
+
run: |
|
|
69
|
+
agentboard review \
|
|
70
|
+
--repo . \
|
|
71
|
+
--target "$TARGET" \
|
|
72
|
+
--base "$BASE_SHA" \
|
|
73
|
+
--head "$HEAD_SHA" \
|
|
74
|
+
--json-out agentboard-run.json \
|
|
75
|
+
--board agentboard-board.html
|
|
76
|
+
|
|
77
|
+
- name: Render comment
|
|
78
|
+
if: steps.target.outputs.target != ''
|
|
79
|
+
run: python3 scripts/render_pr_comment.py agentboard-run.json > agentboard-comment.md
|
|
80
|
+
|
|
81
|
+
- name: Post or update the sticky comment
|
|
82
|
+
if: steps.target.outputs.target != ''
|
|
83
|
+
uses: actions/github-script@v7
|
|
84
|
+
with:
|
|
85
|
+
script: |
|
|
86
|
+
const fs = require("fs");
|
|
87
|
+
const body = fs.readFileSync("agentboard-comment.md", "utf8");
|
|
88
|
+
const marker = "<!-- agentboard-review -->";
|
|
89
|
+
const { owner, repo } = context.repo;
|
|
90
|
+
const issue_number = context.payload.pull_request.number;
|
|
91
|
+
const { data: comments } = await github.rest.issues.listComments(
|
|
92
|
+
{ owner, repo, issue_number, per_page: 100 });
|
|
93
|
+
const mine = comments.find(c => c.body && c.body.includes(marker));
|
|
94
|
+
if (mine) {
|
|
95
|
+
await github.rest.issues.updateComment(
|
|
96
|
+
{ owner, repo, comment_id: mine.id, body });
|
|
97
|
+
} else {
|
|
98
|
+
await github.rest.issues.createComment(
|
|
99
|
+
{ owner, repo, issue_number, body });
|
|
100
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install package and test dependencies
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e .
|
|
29
|
+
pip install pytest
|
|
30
|
+
|
|
31
|
+
# The verifier/gate is unit-testable without any API key — that's the point.
|
|
32
|
+
- name: Run unit tests (no API key required)
|
|
33
|
+
env:
|
|
34
|
+
PYTHONPATH: src
|
|
35
|
+
run: python -m pytest tests/ -q
|
|
36
|
+
|
|
37
|
+
lint:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
- name: Install ruff
|
|
45
|
+
run: pip install ruff
|
|
46
|
+
- name: Lint
|
|
47
|
+
run: ruff check src/ tests/ examples/
|
|
48
|
+
continue-on-error: true # advisory for now; tighten after first green run
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Benchmark
|
|
2
|
+
|
|
3
|
+
Can agentboard find a real bug in code it has never seen, from an intent
|
|
4
|
+
that does not name the bug? This measures that, on recent merged bugfix PRs
|
|
5
|
+
from active TypeScript repositories, and publishes the misses.
|
|
6
|
+
|
|
7
|
+
## Method
|
|
8
|
+
|
|
9
|
+
For each row:
|
|
10
|
+
|
|
11
|
+
1. Pick a bugfix PR that is already merged into an active repo.
|
|
12
|
+
2. Check out the PR's **parent** commit — the code exactly as it was before
|
|
13
|
+
the fix. The bug is present.
|
|
14
|
+
3. Run agentboard with a **neutral intent** that describes what the module
|
|
15
|
+
is for, never what the bug is. PR titles telegraph the answer, so the PR
|
|
16
|
+
and its tests are ground truth, not input.
|
|
17
|
+
4. Score the confirmed gaps against the fix, by reading source.
|
|
18
|
+
|
|
19
|
+
The intent discipline is the whole experiment. "recursively merge an object
|
|
20
|
+
with default values" is a fair description of defu; "prevent prototype
|
|
21
|
+
pollution via `__proto__`" would be handing over the answer. If a skeptic
|
|
22
|
+
can argue the intent leaked the bug, the row does not count.
|
|
23
|
+
|
|
24
|
+
No row uses the bug agentboard was originally developed against
|
|
25
|
+
(supabase/mcp #317). Training on your test set is not a benchmark; #317
|
|
26
|
+
appears only as a disclosed reference case in the README.
|
|
27
|
+
|
|
28
|
+
Every gap in this table was adjudicated by reading the fix diff or the
|
|
29
|
+
source at the parent commit. The auditor's advisory calls were **not**
|
|
30
|
+
trusted as scores — see the auditor-inversion note below for why that
|
|
31
|
+
matters.
|
|
32
|
+
|
|
33
|
+
## Results
|
|
34
|
+
|
|
35
|
+
Tool version `e175535`. 12 distinct bugs across 8 repos (two rows are
|
|
36
|
+
security-axis twins). Zero environment failures.
|
|
37
|
+
|
|
38
|
+
| # | Repo | PR | Target module | Outcome |
|
|
39
|
+
|---|------|----|--------------|---------|
|
|
40
|
+
| s1 | supabase/mcp | #269 | content-api graphql | in-area catch |
|
|
41
|
+
| s2 | supabase/mcp | #329 | management-api errors | miss (4 clean false positives) |
|
|
42
|
+
| r1 | unjs/ufo | #335 | url base join/strip | missed #335, **re-found #360** |
|
|
43
|
+
| r2 | unjs/ufo | #313 | url base prefix match | **strict catch** |
|
|
44
|
+
| r3 | unjs/defu | #156 | recursive default merge | **strict catch** (`__proto__` pollution) |
|
|
45
|
+
| r4 | unjs/pathe | #246 | path resolve | **strict catch** (UNC authority) |
|
|
46
|
+
| r5 | unjs/pathe | #241 | path parse | in-area catch (node divergence) |
|
|
47
|
+
| r6 | pmndrs/jotai | #3354 | store subscribe | miss (subtle async) |
|
|
48
|
+
| r7 | pmndrs/jotai | #3326 | atomWithStorage | miss (component harness) |
|
|
49
|
+
| r8 | vueuse/vueuse | #5525 | useFetch | **in-area catch + 2 bonus bugs** |
|
|
50
|
+
| r9 | TanStack/query | #10812 | devtools sort | **strict catch** |
|
|
51
|
+
| r10 | colinhacks/zod | #5898 | object catchall | miss (wrong-remedy assertion) |
|
|
52
|
+
|
|
53
|
+
Security-axis twins: r3s (defu) reproduced the strict catch and added a
|
|
54
|
+
nested `__proto__` variant the default axis missed; r10s (zod) missed the
|
|
55
|
+
same way the default did.
|
|
56
|
+
|
|
57
|
+
**Summary: 8 of 12 rows produced a real confirmed bug. 4 were exact strict
|
|
58
|
+
catches (ufo #313, defu #156, pathe #246, query #10812). r8 over-delivered:
|
|
59
|
+
pointed at vueuse before a known fix, it caught the fix's neighborhood and
|
|
60
|
+
two additional real bugs the PR never touched (a falsy-`initialData` bug
|
|
61
|
+
from `||` where `??` was meant, and a header-array-merge bug). 4 rows
|
|
62
|
+
missed. 0 environment failures.**
|
|
63
|
+
|
|
64
|
+
### The two bonus bugs (r8)
|
|
65
|
+
|
|
66
|
+
vueuse `useFetch`, at the parent of #5525, neutral intent "fetch a URL
|
|
67
|
+
reactively with abort and refetch support":
|
|
68
|
+
|
|
69
|
+
- `const data = shallowRef<T | null>(initialData || null)` — `||` coerces a
|
|
70
|
+
valid falsy `initialData` (`0`, `''`, `false`) to `null`. Should be `??`.
|
|
71
|
+
- `headersToObject` only handles `Headers` instances, silently dropping
|
|
72
|
+
array-form `HeadersInit` (`[['authorization', ...]]`).
|
|
73
|
+
|
|
74
|
+
Neither is what #5525 fixed. Both are real, both were found from a neutral
|
|
75
|
+
intent, both have an executed failing test attached.
|
|
76
|
+
|
|
77
|
+
## The auditor inverted, twice — and that is the point
|
|
78
|
+
|
|
79
|
+
The auditor is a second model (Claude) that reads the source and flags
|
|
80
|
+
confirmed gaps it believes assert something the code never promised. It is
|
|
81
|
+
**advisory**: it never changes a verdict.
|
|
82
|
+
|
|
83
|
+
On two rows it called a **real strict catch** a false positive:
|
|
84
|
+
|
|
85
|
+
- **r2 (ufo #313):** the code matched `/api` as a prefix of `/api-v2`. The
|
|
86
|
+
auditor called the failing test a wrong assumption.
|
|
87
|
+
- **r9 (query #10812):** the comparator `(a, b) => a < b ? 1 : -1` never
|
|
88
|
+
returns `0` for ties, violating the comparator contract — the exact thing
|
|
89
|
+
#10812 fixed. The auditor flagged it a false positive **and cited the
|
|
90
|
+
buggy line as evidence**, mistaking the bug for the contract.
|
|
91
|
+
|
|
92
|
+
A calibration pass (a false-positive call must now quote the source line it
|
|
93
|
+
relies on, or it downgrades) made the auditor's output more useful but did
|
|
94
|
+
**not** stop this: it can cite the buggy code as if that code were the
|
|
95
|
+
specification. This is the benchmark's most important finding, and it is the
|
|
96
|
+
thesis proving itself inside the tool. The judging model was confidently
|
|
97
|
+
wrong. Execution was right. That is exactly why the verdict comes from the
|
|
98
|
+
gate and never from a model — the auditor is a lead, not a ruling, and every
|
|
99
|
+
gap in this table was adjudicated by a human reading source.
|
|
100
|
+
|
|
101
|
+
## Misses, in daylight
|
|
102
|
+
|
|
103
|
+
- **s2 (supabase #329):** four gaps, all false positives — the proposals
|
|
104
|
+
asserted `.length` on a formatted string result. The real fix (a 403
|
|
105
|
+
org-scoping error message) was never approached. The auditor correctly
|
|
106
|
+
flagged all four.
|
|
107
|
+
- **r6 (jotai #3354):** a subscriber-notification bug that only manifests
|
|
108
|
+
after a nested `store.set` with sub/unsub inside a write. Too subtle for
|
|
109
|
+
the proposer; two false positives instead.
|
|
110
|
+
- **r7 (jotai #3326):** a React component target. The proposer wrote React
|
|
111
|
+
Testing Library tests with wrong DOM assumptions; the gate correctly
|
|
112
|
+
classified them `broken_test` rather than gaps. Complex component harnesses
|
|
113
|
+
are a real reviewer-capability limit.
|
|
114
|
+
- **r10 (zod #5898):** the `__proto__` catchall bug is present, but the
|
|
115
|
+
proposer asserted the wrong remedy (expected `__proto__` as a visible data
|
|
116
|
+
key) rather than the real defect (prototype pollution). The bug class was
|
|
117
|
+
right, the assertion was wrong. Same bug class as defu #156, opposite
|
|
118
|
+
outcome — see below.
|
|
119
|
+
|
|
120
|
+
## Assertion quality is the frontier
|
|
121
|
+
|
|
122
|
+
defu #156 and zod #5898 are both `__proto__` bugs. defu's proposal asserted
|
|
123
|
+
*the prototype was not polluted* and caught the bug. zod's asserted
|
|
124
|
+
*`__proto__` should appear as a data key* and missed it, producing a false
|
|
125
|
+
positive on a real defect. Same vulnerability, opposite result, decided
|
|
126
|
+
entirely by what the model chose to assert. Improving assertion quality —
|
|
127
|
+
not reaching the topic — is the open problem this benchmark surfaces, and it
|
|
128
|
+
is the training signal behind the roadmap's model work.
|
|
129
|
+
|
|
130
|
+
## Determinism receipts
|
|
131
|
+
|
|
132
|
+
Every run prints a fingerprint over its verdicts. Six rows were run on two
|
|
133
|
+
separate days, through a proposal-cache hit and a changed advisory layer,
|
|
134
|
+
and reproduced byte-identical fingerprints:
|
|
135
|
+
|
|
136
|
+
| Row | fingerprint (both runs) |
|
|
137
|
+
|-----|-------------------------|
|
|
138
|
+
| s1 | `d64b434d0833afcf` |
|
|
139
|
+
| s2 | `3811dc33363f9751` |
|
|
140
|
+
| r1 | `6e9bb41299792a83` |
|
|
141
|
+
| r3 | `b6a7bd31e37e5bb7` |
|
|
142
|
+
| r4 | `35d6c88385a680c2` |
|
|
143
|
+
| r10 | `f7214bf3b971ad1c` |
|
|
144
|
+
|
|
145
|
+
The auditor changed between the two runs; the fingerprints did not, because
|
|
146
|
+
the auditor is advisory and never enters the verdict. When verdict-side code
|
|
147
|
+
changed, every row was rerun on one tool version rather than mixing.
|
|
148
|
+
|
|
149
|
+
## Reproduce
|
|
150
|
+
|
|
151
|
+
Each row is a fresh checkout at the parent commit, `--base HEAD` (empty
|
|
152
|
+
change, stranger-mode review), a neutral intent, and the auditor on:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
git clone <repo> && cd <repo> && git checkout <parent-sha>
|
|
156
|
+
agentboard review --repo . --target <file> --tests <tests> \
|
|
157
|
+
--head HEAD --base HEAD --intent "<neutral intent>" \
|
|
158
|
+
--audit-model claude-sonnet-5 --json-out run.json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Parent SHAs, targets, and neutral intents for all rows are in
|
|
162
|
+
`bench/run_bench.sh`. Environment failures, when they occur, are reported as
|
|
163
|
+
failures, never retried until green.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contributing to agentboard
|
|
2
|
+
|
|
3
|
+
Thanks for looking. agentboard is a review gate with one non-negotiable idea:
|
|
4
|
+
**a model may propose, but only executed tests decide.** Contributions are
|
|
5
|
+
welcome as long as they hold that line.
|
|
6
|
+
|
|
7
|
+
## The invariants (do not break these)
|
|
8
|
+
|
|
9
|
+
These are the whole reason the tool is trustworthy. A change that violates one
|
|
10
|
+
will not be merged, however useful it looks otherwise.
|
|
11
|
+
|
|
12
|
+
1. **The verdict is deterministic and model-free.** No LLM sits in the
|
|
13
|
+
pass/fail path. A behavior becomes a `confirmed_gap` only if a proposed test
|
|
14
|
+
compiles, runs, and fails its assertion on the real code.
|
|
15
|
+
2. **A garbage test cannot manufacture a finding.** A test that crashes or
|
|
16
|
+
fails to load is classified against the test (`broken_test`), never against
|
|
17
|
+
the code under review. Only a named assertion failure is a gap.
|
|
18
|
+
3. **The auditor is advisory.** A second model may flag a likely false
|
|
19
|
+
positive, with a quoted source line. It never changes a verdict. It has been
|
|
20
|
+
wrong (see `BENCHMARK.md`); the gate has the final word, always.
|
|
21
|
+
4. **Per-finding isolation.** Every proposed test runs against a clean checkout
|
|
22
|
+
of the repo; no finding sees another's injected test.
|
|
23
|
+
5. **The engine knows nothing about GitHub.** CI and MCP are adapters over the
|
|
24
|
+
`--json-out` schema. Keep PR-shaped concepts out of the core.
|
|
25
|
+
|
|
26
|
+
If your change touches the gate, the classifier, or the cache key, add a test
|
|
27
|
+
that pins the behavior. `tests/` has examples of the style, including
|
|
28
|
+
falsifier invariants (an impossible test must always read as a real failure).
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
git clone https://github.com/anp0429/agentboard
|
|
34
|
+
cd agentboard
|
|
35
|
+
pip install -e ".[dev]"
|
|
36
|
+
PYTHONPATH=src python -m pytest tests/ -q
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The demo runs with no API key and exercises the deterministic gate:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
agentboard demo
|
|
43
|
+
agentboard demo --fixed
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
A live review needs `OPENAI_API_KEY` (reviewer) and, for the auditor,
|
|
47
|
+
`ANTHROPIC_API_KEY`. Reviews on real repos run vitest, so Node is required for
|
|
48
|
+
those; the Python test suite does not need it.
|
|
49
|
+
|
|
50
|
+
## Before you open a PR
|
|
51
|
+
|
|
52
|
+
- `PYTHONPATH=src python -m pytest tests/ -q` passes.
|
|
53
|
+
- `ruff check src/ tests/` is clean (advisory today, tightening over time).
|
|
54
|
+
- New behavior has a test. New verdict-path behavior has a test that would fail
|
|
55
|
+
without your change.
|
|
56
|
+
- If you changed anything the benchmark exercises, say so; `BENCHMARK.md`
|
|
57
|
+
documents the method and the honest misses, and we keep it honest.
|
|
58
|
+
|
|
59
|
+
## What is especially welcome
|
|
60
|
+
|
|
61
|
+
- New `RepoProfile` presets or `.agentboard.toml` recipes for repos that need
|
|
62
|
+
scoping (multiple vitest projects, per-package monorepos).
|
|
63
|
+
- A pytest gate (the current gate is vitest-only; `PytestVerifier` exists but
|
|
64
|
+
speaks the older protocol).
|
|
65
|
+
- Benchmark rows: a merged bugfix PR, run at its parent commit with a neutral
|
|
66
|
+
intent, scored honestly including misses.
|
|
67
|
+
|
|
68
|
+
## Reporting a security issue
|
|
69
|
+
|
|
70
|
+
Please use GitHub's private vulnerability reporting rather than a public issue.
|