Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
03f08ed
fix(reviewer): bind failed checks to actionable source evidence
seonghobae Sep 4, 2026
182d63e
test(reviewer): require one RCA per failed check
seonghobae Sep 4, 2026
6ff7954
fix(reviewer): model exact failed-check source binding
seonghobae Sep 4, 2026
2ad138f
fix(reviewer): bind each failed check to its own RCA
seonghobae Sep 4, 2026
bd364a0
test(reviewer): bind actionable RCA to exact check
seonghobae Sep 4, 2026
20c35e7
fix(reviewer): require exact failed-check identity in RCA
seonghobae Sep 4, 2026
2361b76
test(reviewer): cover exact failed-check causal binding
seonghobae Sep 4, 2026
1f7d76d
docs(reviewer): document failed-check causal binding
seonghobae Sep 4, 2026
2238410
docs(reviewer): make failed-check RCA contract code-current
seonghobae Sep 4, 2026
0a6fac8
feat(reviewer): enforce actionable finding contract (#549)
seonghobae Sep 4, 2026
b2d2853
docs(reviewer): align sandbox contract with actionable findings
seonghobae Sep 4, 2026
7d4aa92
docs(reviewer): document actionable finding publication
seonghobae Sep 4, 2026
e924c46
Merge fix/codegraph-smoke-semantic-gate into failed-check RCA
seonghobae Sep 4, 2026
8a30e4a
Merge fix/codegraph-smoke-semantic-gate into failed-check RCA
seonghobae Sep 4, 2026
ba480c8
Merge current CodeGraph provenance authority into failed-check RCA
seonghobae Sep 4, 2026
eae8803
Merge current CodeGraph response-classification authority into failed…
seonghobae Sep 4, 2026
dd5c0f0
test(reviewer): inherit lifecycle-prefixed empty-result regression
seonghobae Sep 4, 2026
3e2615f
fix(reviewer): inherit lifecycle-aware CodeGraph classification
seonghobae Sep 4, 2026
ebe554a
style(reviewer): preserve stacked gate structure after restack repair
seonghobae Sep 4, 2026
df7f499
docs(reviewer): inherit semantic empty-result prefix contract
seonghobae Sep 4, 2026
b31de77
merge: restack failed-check RCA on current CodeGraph gate
seonghobae Sep 4, 2026
e4adc92
merge: restack failed-check RCA on reviewer fixture repair
seonghobae Sep 4, 2026
8d0f949
docs(reviewer): carry symbol-seeded recovery contract into failed-che…
seonghobae Sep 4, 2026
39adb66
merge: restack failed-check lane on symbol-seeded reviewer recovery
seonghobae Sep 4, 2026
482e773
merge: restack failed-check lane on unambiguous CodeGraph recovery
seonghobae Sep 4, 2026
97227ab
merge: inherit bounded CodeGraph recovery coverage
seonghobae Sep 4, 2026
1d8fbdf
merge: inherit lifecycle-safe CodeGraph recovery
seonghobae Sep 4, 2026
dd405f1
merge: inherit exact-whitespace CodeGraph recovery
seonghobae Sep 4, 2026
b61daf1
docs(reviewer): preserve exact-whitespace retrieval contract
seonghobae Sep 4, 2026
3d76ab1
merge: inherit code-current CodeGraph recovery docs
seonghobae Sep 4, 2026
ca300fe
fix(reviewer): preserve exact CodeGraph path scope in failed-check lane
seonghobae Sep 4, 2026
39325bd
docs(reviewer): inherit exact CodeGraph path scope contract
seonghobae Sep 4, 2026
fababd1
test(reviewer): inherit long CodeGraph path identity regression
seonghobae Sep 4, 2026
ef046ed
merge: inherit exact CodeGraph path identity prerequisite
seonghobae Sep 4, 2026
1a2ec03
test(reviewer): inherit CodeGraph scope coverage guard
seonghobae Sep 4, 2026
19c24b4
merge: inherit CodeGraph scope coverage prerequisite
seonghobae Sep 4, 2026
3fdfc1c
docs(reviewer): compose exact long-path recovery with actionable find…
seonghobae Sep 4, 2026
f0ed4b2
merge: inherit exact long-path CodeGraph recovery
seonghobae Sep 4, 2026
32cf314
fix(reviewer): inherit CodeGraph environment isolation
seonghobae Sep 5, 2026
581e5ca
test(reviewer): preserve CodeGraph environment isolation
seonghobae Sep 5, 2026
7c039a8
test(reviewer): inherit ambient CodeGraph authority regression
seonghobae Sep 5, 2026
4df310b
docs(reviewer): retain CodeGraph ambient-authority boundary
seonghobae Sep 5, 2026
99b168e
merge: restack failed-check evidence on CodeGraph isolation
seonghobae Sep 5, 2026
19ebf00
fix(reviewer): preserve actionability while excluding self-check
seonghobae Sep 5, 2026
d3c69c5
test(reviewer): retain self-check cycle regression
seonghobae Sep 5, 2026
70d160e
test(reviewer): retain isolated CodeGraph home regression
seonghobae Sep 5, 2026
a61cc29
fix(reviewer): preserve causal logs with isolated CodeGraph home
seonghobae Sep 5, 2026
491ecad
docs(reviewer): compose actionability with self-check and isolated home
seonghobae Sep 5, 2026
626670d
merge: inherit reviewer self-check and isolated-home prerequisite
seonghobae Sep 5, 2026
61599f8
docs(reviewer): compose complete CodeGraph recovery contract
seonghobae Sep 5, 2026
13749c1
merge: inherit complete CodeGraph recovery boundary
seonghobae Sep 5, 2026
6d9626e
test(reviewer): inherit independent check evidence RED
seonghobae Sep 5, 2026
2c041db
fix(reviewer): compose independent check evidence boundary
seonghobae Sep 5, 2026
1160aca
docs(reviewer): compose independent evidence cycle rule
seonghobae Sep 5, 2026
76c5d70
merge: inherit independent evidence prerequisite
seonghobae Sep 5, 2026
3bc5449
fix(reviewer): preserve distinct deterministic findings
seonghobae Sep 5, 2026
10f4241
test(reviewer): retain distinct deterministic finding evidence
seonghobae Sep 5, 2026
08720c9
merge: compose deterministic finding identity prerequisite
seonghobae Sep 5, 2026
db1b6a6
test(reviewer): inherit CodeGraph probe-budget boundary
seonghobae Sep 5, 2026
5b6bdc8
merge: restack #548 on #546 reviewer prerequisite
seonghobae Sep 5, 2026
5bf6ed6
merge: restack #548 on complete CodeGraph recovery
seonghobae Sep 5, 2026
dcb961a
fix(reviewer): preserve complete CodeGraph primary scope
seonghobae Sep 5, 2026
fed0831
docs(reviewer): retain exact CodeGraph scope in actionable lane
seonghobae Sep 5, 2026
52804b1
merge: restack #548 on complete CodeGraph primary scope
seonghobae Sep 5, 2026
76d20ff
merge(reviewer): compose symlink-safe CodeGraph seed boundary
seonghobae Sep 5, 2026
852fae2
merge(reviewer): inherit symlink-parent recovery regression
seonghobae Sep 5, 2026
a80493d
merge(reviewer): document symlink-free recovery on #548
seonghobae Sep 5, 2026
51b3bf8
merge: restack #548 on symlink-safe CodeGraph seed boundary
seonghobae Sep 5, 2026
0b7b911
merge: restack #548 on review-wait cycle repair
seonghobae Sep 5, 2026
c5ed0cf
merge: restack #548 on complete symbol-map recovery
seonghobae Sep 5, 2026
abaf95c
merge: restack #548 on physical CodeGraph checkout provenance
seonghobae Sep 5, 2026
86038ef
merge: restack #548 on exact CodeGraph path identity
seonghobae Sep 5, 2026
0a039bf
merge: restack #548 on Unicode CodeGraph scope parity
seonghobae Sep 5, 2026
7cbdeee
merge: restack #548 on executable CodeGraph retry semantics
seonghobae Sep 5, 2026
fa93ba3
merge: restack #548 on physical Docker checkout provenance
seonghobae Sep 5, 2026
19315d9
merge: restack #548 on complete reviewer context
seonghobae Sep 5, 2026
a7066ea
merge: restack #548 on fail-before-execution reviewer scope
seonghobae Sep 5, 2026
6f57924
fix(reviewer): preserve prompt-data boundary in failed-check lane
seonghobae Sep 5, 2026
7e2522e
merge: restack #548 on JSON-scope reviewer recovery
seonghobae Sep 5, 2026
24c9993
merge: restack #548 on JSON-safe symbol recovery
seonghobae Sep 5, 2026
1209874
docs(reviewer): merge JSON-safe seed contract into #548
seonghobae Sep 5, 2026
bb7aacf
merge: restack #548 on reviewer recovery documentation
seonghobae Sep 5, 2026
dd73533
merge: restack #548 on exact Linux path identity prerequisite
seonghobae Sep 5, 2026
65a256b
test(reviewer): align #548 deterministic identity fixture
seonghobae Sep 5, 2026
bb8fe78
merge: restack #548 on reviewer hosted-RED repair
seonghobae Sep 5, 2026
d3b42ac
merge: restack #548 on reviewer docstring repair
seonghobae Sep 5, 2026
4d8f314
test(reviewer): cover failed-check edge branches
seonghobae Sep 5, 2026
2fa21a1
merge: restack #548 on protected reviewer truth
seonghobae Sep 6, 2026
a0823f1
merge(context-fabric): restack failed-check evidence on protected con…
seonghobae Sep 6, 2026
6551a86
test(reviewer): expose non-exact finding line admission
seonghobae Sep 6, 2026
5c20453
fix(reviewer): require exact positive finding lines
seonghobae Sep 6, 2026
02ec900
chore(reviewer): keep line-contract repair minimal
seonghobae Sep 6, 2026
3cb7261
merge: converge failed-check evidence onto protected #533 truth
seonghobae Sep 6, 2026
75f93fd
merge: converge failed-check evidence onto protected #552 truth
seonghobae Sep 6, 2026
049a57d
merge: restack reviewer evidence after #527 trust integration
seonghobae Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions docs/noema-agent-sandbox-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,17 @@ The driver returns JSON:
"findings": [
{
"severity": "critical | high | medium | low | info",
"priority": "P1 | P2 | P3",
"path": "relative/path",
"line": 1,
"evidence": "log, SARIF, test, or source reference",
"recommendation": "specific fix"
"check_name": "exact current-head failed check name | null",
"evidence": "log, SARIF, test, source, or other independently checkable reference",
"evidence_type": "nearby_implementation | matching_existing_example | cross_file_counterpart | current_official_docs | failed_check_or_log",
"observable_impact": "specific user or operator consequence",
"trigger": "concrete condition that exposes the issue",
"recommendation": "smallest specific fix",
"regression_command": "one exact single-line command or test target",
"suggested_diff": "optional replacement text | null"
}
],
"suggested_patch_ref": "optional artifact path or branch",
Expand All @@ -63,6 +70,22 @@ The driver returns JSON:
}
```

`check_name` is optional for ordinary source, SARIF, dependency, and review-thread
findings. When a finding is offered as the causal RCA for a failed current-head
check, it must equal that exact check name. A failed check remains `blocked`
unless it has its own blocking-severity finding on a current-head changed path
with a positive source line; one finding cannot authorize multiple failed
checks.

Every finding is actionable data rather than prose-only advice. Priority,
evidence type, observable impact, trigger, smallest fix, and an exact regression
command are required. A `regression_command` cannot contain a newline or Markdown
backtick. `suggested_diff` is optional, but when present it cannot contain a
Markdown fence and must anchor to a right-side line in the exact PR diff before
publication. Valid replacement text is published through GitHub's inline review
`comments` payload as a suggestion rather than only being displayed in the
top-level review body.

Noema-issued installation tokens are used only after the sandboxed agent has a
bounded verdict to publish. The token scope is limited to the target repository
and central review workflow permissions.
Expand Down Expand Up @@ -150,6 +173,12 @@ failure and blocks strict approval.
a failure came from missing evidence, dependency vulnerability, image
verification, image vulnerability, CodeGraph failure, sandbox timeout,
attestation creation/verification, model exhaustion, or GitHub API rejection.
- Each ordinary failed current-head check either has its own exact-name,
changed-path, positive-line blocking RCA or keeps the verdict `blocked`;
another failed check's finding cannot satisfy that evidence requirement.
- Each finding carries priority, evidence type, observable impact, trigger,
smallest fix, and one exact regression command; any proposed replacement text
must be fence-safe and exact-diff-anchorable before GitHub receives it.
- Medium-or-higher dependency and sandbox-image findings from OSV, Trivy, and
dependency-review are remediated by package/image bump or source change, not
by gate weakening.
Expand Down Expand Up @@ -186,10 +215,12 @@ privileged publication plane.

The judgement plane is implemented as the Python package
`reviewer/noema_reviewer` (a PydanticAI `ReviewAgent` driver). It returns the
JSON verdict contract above, enforces strict-evidence blocking and
MEDIUM-or-higher dependency downgrade around the model, preserves reviewed PR
comments and current check conclusions, records containerized CodeGraph status,
and publishes only against the live exact head after attested manifest
verification. The Noema Worker (`src/`) remains the token-exchange boundary
only. Reviewer code ships with 100% line and branch coverage and 100% docstring
coverage; the Worker release gate remains `npm run release:verify`.
JSON verdict contract above, enforces strict-evidence blocking, exact per-check
failed-check RCA binding, actionable finding validation, exact-diff suggestion
anchoring, and MEDIUM-or-higher dependency downgrade around the model. It
preserves reviewed PR comments and current check conclusions, records
containerized CodeGraph status, and publishes only against the live exact head
after attested manifest verification. The Noema Worker (`src/`) remains the
token-exchange boundary only. Reviewer code is required to retain 100% line and
branch coverage and 100% docstring coverage; the Worker release gate remains
`npm run release:verify`.
100 changes: 68 additions & 32 deletions reviewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,46 @@ Division of responsibility:

## Contract

The verdict shape is the JSON contract from the sandbox plan:
The verdict shape is the JSON contract from the sandbox plan. Each finding
carries structured actionability rather than relying on free-form prose:

```json
{
"verdict": "approve | request_changes | blocked",
"summary": "…",
"findings": [{"severity": "critical|high|medium|low|info", "path": "…", "line": 1, "evidence": "…", "recommendation": "…"}],
"findings": [{
"severity": "critical|high|medium|low|info",
"priority": "P1|P2|P3",
"path": "…",
"line": 1,
"check_name": "exact failed check name | null",
"evidence": "…",
"evidence_type": "nearby_implementation|matching_existing_example|cross_file_counterpart|current_official_docs|failed_check_or_log",
"observable_impact": "…",
"trigger": "…",
"recommendation": "smallest fix",
"regression_command": "one exact single-line command",
"suggested_diff": "optional replacement text | null"
}],
"suggested_patch_ref": null,
"blocked_reasons": [],
"confidence": "high | medium | low"
}
```

`check_name` is optional for ordinary source, SARIF, dependency, and review-thread
findings. A finding offered as the RCA for a failed current-head check must bind
to that exact check name. The deterministic gate requires each ordinary failed
check to have its own blocking-severity finding on a current-head changed path
with a positive line; one unrelated or differently bound finding cannot clear
another failed check.

`regression_command` cannot contain newlines or Markdown backticks. A
`suggested_diff` cannot contain a Markdown fence and is accepted only when its
`path:line` is a right-side anchor in the exact PR diff. Accepted replacement
text is sent through GitHub's inline review `comments` payload as a suggestion,
not merely printed in the top-level review body.

The following guarantees are enforced deterministically around the LLM
(`gating.py`), so they hold regardless of what the model says:

Expand Down Expand Up @@ -70,7 +97,7 @@ The following guarantees are enforced deterministically around the LLM
a repository probe. The primary explore query preserves each selected changed
path in full instead of truncating individual path identities; it admits at
most 80 changed files and 24,079 aggregate characters. The manifest retains
bounded current-head file content for every selected file through that same
bounded current-head file context for every selected file through that same
80-file canonical scope; above 80 files both semantic scope and changed-file
context fail closed rather than reviewing a historical 12-file prefix.
Exceeding either exact-scope budget fails closed instead of querying a prefix.
Expand All @@ -91,40 +118,46 @@ The following guarantees are enforced deterministically around the LLM
unchanged lookalike path become a retrieval seed. The node output never
counts as review evidence by itself; deleted, unresolved, symlinked-component,
unindexed, or symbol-less paths leave the original empty result fail closed.
The local host-process CodeGraph fallback also builds a closed execution
environment instead of copying the parent environment: only `PATH` and locale
discovery variables may be propagated; `HOME`, `TEMP`, `TMP`, and `TMPDIR`
are replaced by one fresh per-command private temporary directory and
`NO_COLOR=1` is set explicitly. Process injection, host user configuration/
credentials, ambient temporary-directory capabilities, credential-helper/
socket, container/Kubernetes, proxy, arbitrary workflow, and provider
variables such as `NODE_OPTIONS`, `GIT_ASKPASS`, `SSH_AUTH_SOCK`,
The local host-process CodeGraph fallback builds a closed execution
environment instead of copying the parent environment: only `PATH` and
locale discovery variables may be propagated; `HOME`, `TEMP`, `TMP`, and
`TMPDIR` are replaced by one fresh per-command private temporary directory
and `NO_COLOR=1` is set explicitly. Process injection, host user
configuration/credentials, ambient temporary-directory capabilities,
credential-helper/socket, container/Kubernetes, proxy, arbitrary workflow,
and provider variables such as `NODE_OPTIONS`, `GIT_ASKPASS`, `SSH_AUTH_SOCK`,
`DOCKER_CONFIG`, `KUBECONFIG`, and `HTTPS_PROXY` are not ambient CodeGraph
authority. Production central review still uses the separately attested no-
network sandbox; this host fallback does not replace that isolation boundary.
The production `DockerCodeGraphRunner` now owns the same semantic wrapper and
passes both the exact symbol probe and any symbol-seeded second `explore`
through its verified no-network container boundary. It extracts only the
trusted sandbox copy receipt and sole explore stdout section before semantic
classification, so setup/status bytes cannot satisfy the strict gate and an
empty production explore cannot silently fall back to a host CodeGraph
authority. Production central review still uses the separately attested
no-network sandbox; this host fallback does not replace that isolation
boundary. The production `DockerCodeGraphRunner` owns the same semantic
wrapper and passes both the exact symbol probe and any symbol-seeded second
`explore` through its verified no-network container boundary. It extracts
only the trusted sandbox copy receipt and sole explore stdout section before
semantic classification, so setup/status bytes cannot satisfy the strict gate
and an empty production explore cannot silently fall back to a host CodeGraph
process.
2. **MEDIUM-or-higher dependency findings can't ride out on an approve.** An
unresolved OSV/Trivy/dependency-review finding at MEDIUM+ downgrades an
approval to `request_changes` with the finding attached — the org rule is
"remediate by bump, not gate weakening".
3. **Current-head failures remain blocking.** Failed GitHub Checks and
MEDIUM-or-higher code-scanning/SARIF alerts deterministically downgrade an
approval and retain their exact job, rule, path, and bounded log evidence.
4. **Reviewer independence cannot deadlock.** The exact reviewer check names
3. **Current-head failures remain blocking until causally mapped.** Every
ordinary failed GitHub Check remains `blocked` unless its exact check name is
bound to its own current-head changed-file, positive-line blocking RCA.
Check-run names or workflow URLs are not synthesized into source findings.
MEDIUM-or-higher code-scanning/SARIF alerts remain deterministic findings.
4. **Suggestions must be executable review artifacts.** Suggested replacement
text is rejected before publication if GitHub cannot attach it to the exact
right side of the reviewed diff; fence injection and multiline regression
commands fail schema validation.
5. **Reviewer independence cannot deadlock.** The exact reviewer check names
`noema-review` and `opencode-review`, plus the downstream
`metadata-only gate evaluation`, are excluded from Noema's deterministic
failed-check gate because they cannot be prerequisites for the review that
produces them. This cycle exception cannot satisfy strict evidence by itself:
at least one current-head check outside that reviewer-dependent set must be
observed. Similarly named checks remain blocking, as do every other failed
check and unresolved non-outdated inline thread.
5. **Long reviews stay useful.** The production provider request timeout
`metadata-only gate evaluation`, are excluded from Noema's failed-check RCA
gate because they cannot be prerequisites for the review that produces them.
This cycle exception cannot satisfy strict evidence by itself: at least one
current-head check outside that reviewer-dependent set must be observed.
Similarly named checks remain blocking, as do every other failed check and
unresolved non-outdated inline thread.
6. **Long reviews stay useful.** The production provider request timeout
defaults to 5,400 seconds and provider 429/5xx responses receive bounded SDK
retries. Production failover belongs inside `contextual-orchestrator`; Noema
does not sequentially try the next model. Publication re-reads the live PR
Expand All @@ -133,8 +166,11 @@ The following guarantees are enforced deterministically around the LLM
The GitHub manifest fetch covers all inline review threads (including resolved
and outdated state), submitted review bodies, conversation comments, failed
current-head workflow logs, current-head code-scanning alerts, and open
Dependabot package advisories. Evidence-fetch errors are part of the manifest,
not silent empty lists.
Dependabot package advisories. Failed-check log collection derives an Actions
Job id only from an exact repository-bound GitHub `details_url`; a Check Run id
is never reused as a Job id. If the Actions log cannot be obtained, collection
falls back to the same Check Run's bounded annotations. Evidence-fetch errors
are part of the manifest, not silent empty lists.

The driver sits behind the small `ReviewAgent` protocol, so the sandbox plan's
"Codex, OpenCode, PydanticAI, or another driver" swap is a one-line change.
Expand Down
4 changes: 3 additions & 1 deletion reviewer/noema_reviewer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from .agent import PydanticAIReviewAgent, ReviewAgent, build_agent
from .manifest import ReviewManifest
from .models import Confidence, Finding, ReviewVerdict, Severity, Verdict
from .models import Confidence, EvidenceType, Finding, Priority, ReviewVerdict, Severity, Verdict
from .patch_image_validation import (
DockerPatchValidatorImageRunner,
PatchValidatorImageProfile,
Expand All @@ -35,6 +35,7 @@
"Confidence",
"DockerPatchValidationRunner",
"DockerPatchValidatorImageRunner",
"EvidenceType",
"Finding",
"PatchValidationProfile",
"PatchValidationRequest",
Expand All @@ -45,6 +46,7 @@
"PatchValidatorImageResult",
"PatchValidatorImageStatus",
"PydanticAIReviewAgent",
"Priority",
"ReviewAgent",
"ReviewManifest",
"ReviewVerdict",
Expand Down
13 changes: 10 additions & 3 deletions reviewer/noema_reviewer/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@
"regressions from that evidence only. Approve when no blocking issue is "
"supported by the evidence. Use request_changes only for concrete, "
"evidence-backed blocking issues, and cite the log, SARIF, test, or source "
"line for each finding. Use blocked when required evidence is missing rather "
"than guessing. Never approve while an unresolved MEDIUM-or-higher "
"dependency finding is present; require a package bump instead."
"line for each finding. For every failed check, read its current-head log or "
"annotation, trace the failure to an exact repository path and positive line, "
"set finding.check_name to that exact current-head check name, and state "
"P1/P2/P3 priority, evidence type, observable impact, trigger, smallest fix, "
"and an exact regression command in the finding. Include minimal replacement "
"text in suggested_diff when the cited line can be fixed directly; one finding "
"must not stand in for multiple failed checks. A check name, workflow URL, or "
"synthetic .github/checks path is not actionable. Use blocked when logs cannot "
"support that mapping rather than guessing. Never approve while an unresolved "
"MEDIUM-or-higher dependency finding is present; require a package bump instead."
)


Expand Down
Loading