Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
7632b4f
test(ci): require semantic CodeGraph smoke evidence
seonghobae Sep 3, 2026
caf58ab
fix(ci): fail closed on empty CodeGraph smoke retrieval
seonghobae Sep 3, 2026
fc26787
test(reviewer): reject empty CodeGraph semantic evidence
seonghobae Sep 3, 2026
4bdbd86
fix(reviewer): fail closed on empty CodeGraph semantics
seonghobae Sep 3, 2026
1f842a6
docs(reviewer): define empty CodeGraph semantics as missing evidence
seonghobae Sep 3, 2026
bc56698
test(reviewer): reject initialization-only CodeGraph evidence
seonghobae Sep 3, 2026
4284c4c
test(reviewer): reject empty CodeGraph explore payload
seonghobae Sep 3, 2026
6f7ba0c
fix(reviewer): require non-empty CodeGraph explore context
seonghobae Sep 3, 2026
f4f6379
test(reviewer): require labelled CodeGraph explore evidence
seonghobae Sep 3, 2026
957dc55
test(reviewer): preserve current CodeGraph collector compatibility
seonghobae Sep 3, 2026
148cea6
fix(reviewer): keep semantic gate compatible with live collector
seonghobae Sep 3, 2026
eeafc5f
test(reviewer): align semantic evidence with live collector shape
seonghobae Sep 3, 2026
1a74404
test(reviewer): use semantic CodeGraph evidence in full manifest fixture
seonghobae Sep 3, 2026
964cadc
test(reviewer): keep truncated-diff fixture otherwise complete
seonghobae Sep 3, 2026
d9e4bba
test(reviewer): label semantic output at production CLI boundary
seonghobae Sep 3, 2026
2cef887
fix(reviewer): label CodeGraph explore output at CLI boundary
seonghobae Sep 3, 2026
ad64bef
test(reviewer): require provenance-labelled semantic evidence
seonghobae Sep 3, 2026
d658949
fix(reviewer): require provenance-labelled CodeGraph semantics
seonghobae Sep 3, 2026
a901e2e
test(reviewer): fail closed on unlabelled collector output
seonghobae Sep 3, 2026
acf6c9f
docs(reviewer): align semantic evidence and blocked exit code
seonghobae Sep 3, 2026
e9bfc79
test(reviewer): require collector-owned CodeGraph provenance
seonghobae Sep 3, 2026
3c710ef
test(reviewer): reproduce unlabelled sandbox semantic evidence
seonghobae Sep 3, 2026
d47f35a
fix(reviewer): label sandbox CodeGraph semantic evidence
seonghobae Sep 3, 2026
fa0e9e9
test(reviewer): align sandbox protocol with semantic provenance
seonghobae Sep 3, 2026
a1246fc
test(reviewer): bind semantic provenance to runner contract
seonghobae Sep 3, 2026
5a63f85
fix(reviewer): preserve sandbox section provenance
seonghobae Sep 3, 2026
8c657b0
test(reviewer): restore unlabelled collector rejection contract
seonghobae Sep 3, 2026
d28619e
fix(reviewer): restore sandbox-owned section provenance
seonghobae Sep 3, 2026
745c0d4
test(reviewer): reject prelude CodeGraph marker spoof
seonghobae Sep 3, 2026
e2a066e
fix(reviewer): bind semantics to final explore section
seonghobae Sep 3, 2026
58d5876
test(reviewer): reject truncation-only semantic evidence
seonghobae Sep 3, 2026
fb3510e
fix(reviewer): require retained semantic bytes
seonghobae Sep 3, 2026
6ecaef7
test(reviewer): fail closed on malformed truncation-only evidence
seonghobae Sep 4, 2026
836447e
test(reviewer): close semantic runner coverage edges
seonghobae Sep 4, 2026
24c59f4
fix(reviewer): reject annotation-shaped empty semantics
seonghobae Sep 4, 2026
9cbe181
test(reviewer): reject labelled status-only CodeGraph output
seonghobae Sep 4, 2026
04dcb83
fix(reviewer): reject status-only CodeGraph explore evidence
seonghobae Sep 4, 2026
a17108a
fix(reviewer): reject annotation-only CodeGraph evidence
seonghobae Sep 4, 2026
2ef8c3f
test(reviewer): bind empty result to final CodeGraph section
seonghobae Sep 4, 2026
4295c7f
fix(reviewer): bind empty result to final CodeGraph section
seonghobae Sep 4, 2026
db27981
docs(reviewer): document final CodeGraph evidence authority
seonghobae Sep 4, 2026
2f4561b
fix(reviewer): reject section-split empty evidence
seonghobae Sep 4, 2026
d339b2a
test(reviewer): reject self-labelled CodeGraph provenance
seonghobae Sep 4, 2026
2b697d7
test(reviewer): require unambiguous CodeGraph provenance
seonghobae Sep 4, 2026
83d17f3
fix(reviewer): bind CodeGraph provenance to wrapper output
seonghobae Sep 4, 2026
e77099b
fix(reviewer): fail closed on ambiguous CodeGraph provenance
seonghobae Sep 4, 2026
d022de8
docs(reviewer): document wrapper-owned CodeGraph provenance
seonghobae Sep 4, 2026
e064e07
Merge remote-tracking branch 'origin/main' into pr546
seonghobae Sep 4, 2026
356db1f
test(reviewer): reject sanitized raw marker as semantic evidence
seonghobae Sep 4, 2026
b146781
fix(reviewer): drop sanitized raw-only provenance markers
seonghobae Sep 4, 2026
669a7af
docs(reviewer): define raw-marker-only evidence as empty
seonghobae Sep 4, 2026
3d79848
docs(reviewer): fix exit-code formatting
seonghobae Sep 4, 2026
895b4fc
test(reviewer): reject embedded CodeGraph provenance marker
seonghobae Sep 4, 2026
401c3ab
fix(reviewer): require line-exact CodeGraph provenance marker
seonghobae Sep 4, 2026
966c618
test(reviewer): reject raw marker annotation as semantics
seonghobae Sep 4, 2026
40f2edb
fix(reviewer): reject raw marker annotations as context
seonghobae Sep 4, 2026
5a83559
test(reviewer): reject whitespace-obscured empty CodeGraph result
seonghobae Sep 4, 2026
628c29d
fix(reviewer): normalize empty-result whitespace before admission
seonghobae Sep 4, 2026
2f89f4b
docs(reviewer): document whitespace-normalized empty evidence
seonghobae Sep 4, 2026
401ffe1
test(reviewer): reject embedded raw CodeGraph marker evidence
seonghobae Sep 4, 2026
0b5c4f9
fix(reviewer): discard raw marker-contaminated CodeGraph lines
seonghobae Sep 4, 2026
2678085
docs(reviewer): document raw marker-contaminated line rejection
seonghobae Sep 4, 2026
24ef486
docs(reviewer): fix exit-code contract formatting
seonghobae Sep 4, 2026
95c4418
test(reviewer): preserve semantic context beside empty-result text
seonghobae Sep 4, 2026
3b3e4cd
fix(reviewer): scope empty-result classification to response prefix
seonghobae Sep 4, 2026
b36c4a2
docs(reviewer): distinguish empty-result response from source text
seonghobae Sep 4, 2026
4335707
test(reviewer): reject lifecycle-prefixed empty CodeGraph result
seonghobae Sep 4, 2026
91a32e5
fix(reviewer): ignore lifecycle banners before empty CodeGraph result
seonghobae Sep 4, 2026
4f734b2
docs(reviewer): define semantic empty-result prefix
seonghobae Sep 4, 2026
a20ea30
test(reviewer): align self-labelled CodeGraph expectation
seonghobae Sep 4, 2026
04896a8
test(reviewer): require indexed-symbol recovery for path-only CodeGra…
seonghobae Sep 4, 2026
7e69ae8
fix(reviewer): seed empty CodeGraph explore from indexed changed-file…
seonghobae Sep 4, 2026
55ef2b5
test(reviewer): preserve exact changed-file boundaries for CodeGraph …
seonghobae Sep 4, 2026
fdb13ca
test(reviewer): reject non-current paths as CodeGraph symbol seeds
seonghobae Sep 4, 2026
5ec6df1
fix(reviewer): bind CodeGraph symbol recovery to exact current-head p…
seonghobae Sep 4, 2026
6a10701
docs(reviewer): document symbol-seeded empty-explore recovery
seonghobae Sep 4, 2026
9e31052
test(reviewer): reject ambiguous changed-path recovery
seonghobae Sep 4, 2026
50a62ac
fix(reviewer): fail closed on ambiguous CodeGraph path boundaries
seonghobae Sep 4, 2026
05edafa
docs(reviewer): record ambiguous path fail-closed boundary
seonghobae Sep 4, 2026
3874a09
test(reviewer): cover bounded CodeGraph path recovery
seonghobae Sep 4, 2026
0180991
test(reviewer): expose lifecycle-prefixed CodeGraph recovery miss
seonghobae Sep 4, 2026
08283d4
fix(reviewer): recover CodeGraph misses behind lifecycle banners
seonghobae Sep 4, 2026
29fa384
docs(reviewer): define lifecycle-prefixed empty-result recovery
seonghobae Sep 4, 2026
364591e
test(reviewer): preserve exact whitespace in CodeGraph path recovery
seonghobae Sep 4, 2026
1e66b05
fix(reviewer): preserve exact changed-path whitespace during CodeGrap…
seonghobae Sep 4, 2026
ca71e88
docs(reviewer): document exact-whitespace CodeGraph path recovery
seonghobae Sep 4, 2026
0705e7d
test(reviewer): preserve long CodeGraph changed-path identity
seonghobae Sep 4, 2026
45c161c
fix(reviewer): preserve exact CodeGraph changed-path scope
seonghobae Sep 4, 2026
b84a819
docs(reviewer): document exact CodeGraph path scope budget
seonghobae Sep 4, 2026
8c6d63a
test(reviewer): cover exact CodeGraph aggregate scope guard
seonghobae Sep 4, 2026
531418c
test(reviewer): prove long CodeGraph paths remain recoverable
seonghobae Sep 4, 2026
444164e
fix(reviewer): recover exact long CodeGraph paths within bounded probes
seonghobae Sep 4, 2026
9a115ca
test(reviewer): cover bounded long-path segmentation probes
seonghobae Sep 4, 2026
9606032
docs(reviewer): document exact long-path recovery probe budget
seonghobae Sep 4, 2026
2e30a18
test(reviewer): reject ambient CodeGraph process authority
seonghobae Sep 5, 2026
64f9bd6
fix(reviewer): isolate CodeGraph subprocess environment
seonghobae Sep 5, 2026
1a39aca
test(reviewer): align CodeGraph least-authority fixture
seonghobae Sep 5, 2026
63dba0f
docs(reviewer): record CodeGraph ambient-authority boundary
seonghobae Sep 5, 2026
94638b1
test(reviewer): isolate CodeGraph home authority
seonghobae Sep 5, 2026
1e5ac9c
test(reviewer): expose self-check deadlock
seonghobae Sep 5, 2026
7205f34
fix(reviewer): exclude in-flight Noema self-check
seonghobae Sep 5, 2026
421cc0b
fix(reviewer): isolate CodeGraph home authority
seonghobae Sep 5, 2026
756217f
docs(reviewer): record self-check and isolated-home boundaries
seonghobae Sep 5, 2026
0141ae9
test(reviewer): reject partial CodeGraph symbol recovery
seonghobae Sep 5, 2026
9dba467
fix(reviewer): fail closed on partial CodeGraph seed scopes
seonghobae Sep 5, 2026
e651ef3
docs(reviewer): make symbol recovery completeness explicit
seonghobae Sep 5, 2026
71d8f95
test(reviewer): require independent current-head check evidence
seonghobae Sep 5, 2026
4d64e14
fix(reviewer): require independent current-head check evidence
seonghobae Sep 5, 2026
0e7ab93
docs(reviewer): bind cycle exception to independent evidence
seonghobae Sep 5, 2026
0b5628b
test(reviewer): retain distinct deterministic finding evidence
seonghobae Sep 5, 2026
1b314bd
fix(reviewer): preserve distinct deterministic findings
seonghobae Sep 5, 2026
6fcb58f
test(reviewer): align CodeGraph probe-budget boundary
seonghobae Sep 5, 2026
36630f2
test(reviewer): require complete symbol seed coverage
seonghobae Sep 5, 2026
3cddc10
fix(reviewer): fail closed on incomplete symbol seeds
seonghobae Sep 5, 2026
7495a71
test(reviewer): align symbol probe recovery contract
seonghobae Sep 5, 2026
2a6bfdd
test(reviewer): fail closed above CodeGraph file scope budget
seonghobae Sep 5, 2026
2b41e76
fix(reviewer): fail closed above CodeGraph file scope budget
seonghobae Sep 5, 2026
f5bee97
docs(reviewer): document exact CodeGraph file scope budget
seonghobae Sep 5, 2026
551b0d7
test(reviewer): reject symlinked parent CodeGraph seeds
seonghobae Sep 5, 2026
a199f9a
fix(reviewer): reject symlinked CodeGraph path traversal
seonghobae Sep 5, 2026
7f716f9
docs(reviewer): define symlink-free CodeGraph seed boundary
seonghobae Sep 5, 2026
d46e653
test(reviewer): expose self-dependent Noema wait
seonghobae Sep 5, 2026
8222133
fix(reviewer): exclude self-dependent Noema check from evidence wait
seonghobae Sep 5, 2026
fe4386a
test(reviewer): fail closed on truncated symbol-map recovery
seonghobae Sep 5, 2026
e0811e9
fix(reviewer): reject partial symbol-map recovery
seonghobae Sep 5, 2026
74ca6f4
test(reviewer): reject symlinked checkout root for CodeGraph seed
seonghobae Sep 5, 2026
b90c21b
fix(reviewer): reject symlinked CodeGraph checkout roots
seonghobae Sep 5, 2026
be9f83c
test(reviewer): cover symlinked checkout ancestor provenance
seonghobae Sep 5, 2026
1741178
docs(reviewer): bind CodeGraph recovery to physical checkout root
seonghobae Sep 5, 2026
664b9e7
test(codegraph): preserve exact sandbox changed-path identity
seonghobae Sep 5, 2026
ebbc748
fix(codegraph): preserve exact sandbox changed-path identity
seonghobae Sep 5, 2026
4b96b40
test(codegraph): expose Unicode scope budget mismatch
seonghobae Sep 5, 2026
5eee256
fix(codegraph): align Unicode scope budget with reviewer
seonghobae Sep 5, 2026
cfacdba
test(reviewer): prove CodeGraph retry prompt needs fresh sandbox
seonghobae Sep 5, 2026
4fcacd1
fix(reviewer): execute distinct CodeGraph retry prompts
seonghobae Sep 5, 2026
9e9db27
chore(reviewer): preserve sandbox source newline
seonghobae Sep 5, 2026
742f363
test(reviewer): prove production sandbox can symbol-seed retry
seonghobae Sep 5, 2026
51c9440
fix(reviewer): inject CodeGraph runner through semantic recovery
seonghobae Sep 5, 2026
387b0d1
fix(reviewer): add isolated CodeGraph symbol probe
seonghobae Sep 5, 2026
c441571
fix(reviewer): keep semantic recovery inside Docker boundary
seonghobae Sep 5, 2026
1651705
test(reviewer): bind central Docker runner to semantic retry
seonghobae Sep 5, 2026
9696bea
test(reviewer): align retry cache with semantic Docker output
seonghobae Sep 5, 2026
286ac31
test(reviewer): align Docker sandbox fixtures with semantic envelope
seonghobae Sep 5, 2026
d34c2f0
test(reviewer): cover isolated symbol probe path boundary
seonghobae Sep 5, 2026
9f205b8
test(reviewer): cover semantic Docker recovery boundary
seonghobae Sep 5, 2026
3739ea7
docs(reviewer): bind symbol recovery to production Docker runner
seonghobae Sep 5, 2026
fc0585c
test(reviewer): reject redirected Docker source roots
seonghobae Sep 5, 2026
9f93d99
fix(reviewer): bind Docker sandbox to physical checkout root
seonghobae Sep 5, 2026
b2f91c8
test(reviewer): reject ambient CodeGraph temp capability
seonghobae Sep 5, 2026
15ff51c
fix(reviewer): isolate CodeGraph temp capability
seonghobae Sep 5, 2026
377f237
test(reviewer): require complete context through canonical scope
seonghobae Sep 5, 2026
406c2f9
fix(reviewer): retain full canonical changed-file context
seonghobae Sep 5, 2026
4a7f140
docs(reviewer): align manifest scope and temp isolation
seonghobae Sep 5, 2026
f12c9ab
docs(changelog): record reviewer context liveness repair
seonghobae Sep 5, 2026
f18b665
test(reviewer): fail closed before oversized CodeGraph execution
seonghobae Sep 5, 2026
fed98d0
fix(reviewer): reject oversized CodeGraph scope before execution
seonghobae Sep 5, 2026
af0e59c
test(reviewer): reject filename prompt injection in CodeGraph scope
seonghobae Sep 5, 2026
d439058
fix(reviewer): isolate changed filenames as prompt data
seonghobae Sep 5, 2026
1dbe078
test(reviewer): preserve symbol recovery for JSON changed scope
seonghobae Sep 5, 2026
a785cd4
fix(reviewer): recover symbols from canonical JSON scope
seonghobae Sep 5, 2026
244a029
test(reviewer): keep recovery seeds as untrusted prompt data
seonghobae Sep 5, 2026
b6c3702
fix(reviewer): encode empty-recovery seeds as untrusted JSON
seonghobae Sep 5, 2026
1a407c1
docs(reviewer): document JSON-safe recovery seeds
seonghobae Sep 5, 2026
1d9e8e5
docs(reviewer): fix exit-code markup
seonghobae Sep 5, 2026
3328f7b
test(codegraph): preserve leading backslash Git path identity
seonghobae Sep 5, 2026
04376e2
fix(codegraph): keep Linux backslash filenames byte-exact
seonghobae Sep 5, 2026
b84f0e5
test(reviewer): align deterministic finding identity contract
seonghobae Sep 5, 2026
6e5df50
test(reviewer): cover fail-closed CodeGraph admission edges
seonghobae Sep 5, 2026
95144d5
fix(reviewer): remove unreachable legacy path branch
seonghobae Sep 5, 2026
7d3de5a
fix(reviewer): document bound semantic runner
seonghobae Sep 5, 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
87 changes: 87 additions & 0 deletions .github/codegraph/sandbox-node-runner.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env node
import { pathToFileURL } from "node:url";
import {
BUNDLED_CODEGRAPH_ENTRYPOINT,
BUNDLED_CODEGRAPH_NODE,
MAX_CHANGED_SCOPE_CHARS,
copyInputTree,
runBoundedCommand,
} from "./sandbox-runner.mjs";

function boundedDiagnostic(output, maximum = 1000) {
const compact = String(output).trim() || "no diagnostic output";
if (compact.length <= maximum) {
return compact;
}
return `${compact.slice(0, maximum)} [truncated ${compact.length - maximum} characters]`;
}

export function validateRepositoryRelativePath(rawPath) {
if (typeof rawPath !== "string" || rawPath.length === 0) {
throw new Error("CodeGraph node path is required");
}
if (rawPath.includes("\0")) {
throw new Error("CodeGraph node path must not contain NUL characters");
}
if (Array.from(rawPath).length > MAX_CHANGED_SCOPE_CHARS) {
throw new Error("CodeGraph node path exceeds the bounded input contract");
}
// This runner is Linux-only. Backslash is therefore a legal Git filename byte,
// not a path separator; rejecting it would rewrite the admitted changed-path identity.
if (rawPath.startsWith("/")) {
throw new Error("CodeGraph node path must be repository-relative");
}
const parts = rawPath.split("/");
if (parts.some((part) => part === "" || part === "." || part === "..")) {
throw new Error("CodeGraph node path must not traverse repository boundaries");
}
return rawPath;
}

export async function runCodeGraphNode(rawPath) {
const relativePath = validateRepositoryRelativePath(rawPath);
const projectRoot = "/workspace/project";
await copyInputTree("/input", projectRoot);
const environment = {
PATH: "/usr/local/bin:/usr/bin:/bin",
HOME: "/workspace/home",
XDG_CACHE_HOME: "/workspace/cache",
CODEGRAPH_NO_UPDATE_CHECK: "1",
CODEGRAPH_HOST_PPID: String(process.ppid),
DO_NOT_TRACK: "1",
NO_COLOR: "1",
};
const runtimeFlags = [
"--liftoff-only",
"--disable-warning=ExperimentalWarning",
BUNDLED_CODEGRAPH_ENTRYPOINT,
];

for (const args of [["init", "-i"], ["sync"]]) {
await runBoundedCommand(
BUNDLED_CODEGRAPH_NODE,
[...runtimeFlags, ...args],
{ cwd: projectRoot, env: environment },
);
}
return runBoundedCommand(
BUNDLED_CODEGRAPH_NODE,
[...runtimeFlags, "node", "--file", relativePath, "--symbols-only"],
{ cwd: projectRoot, env: environment },
);
}

async function main() {
try {
const output = await runCodeGraphNode(process.argv[2] ?? "");
process.stdout.write(output);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
process.stderr.write(`sandbox_error: ${boundedDiagnostic(message)}\n`);
process.exitCode = 1;
}
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
await main();
}
25 changes: 15 additions & 10 deletions .github/codegraph/sandbox-runner.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const DEFAULT_INPUT_LIMITS = Object.freeze({
maxTotalBytes: 200 * 1024 * 1024,
});
export const MAX_CHANGED_PATHS = 80;
export const MAX_CHANGED_PATH_CHARS = 300;
export const MAX_CHANGED_SCOPE_CHARS = 24_079;
export const COMMAND_TIMEOUT_MS = 180_000;
export const COMMAND_OUTPUT_LIMIT_BYTES = 128 * 1024;
export const SESSION_OUTPUT_LIMIT_BYTES = 256 * 1024;
Expand Down Expand Up @@ -246,21 +246,26 @@ export function normalizeChangedPaths(value) {
if (value.length > MAX_CHANGED_PATHS) {
throw new Error(`CodeGraph changed scope may contain at most ${MAX_CHANGED_PATHS} paths`);
}
return value.map((rawPath) => {

let scopeCharacters = 0;
return value.map((rawPath, index) => {
if (typeof rawPath !== "string") {
throw new Error("CodeGraph changed paths must contain only strings");
}
const path = rawPath.trim();
if (path.length > MAX_CHANGED_PATH_CHARS) {
throw new Error(
`CodeGraph changed paths may contain at most ${MAX_CHANGED_PATH_CHARS} characters`,
);
if (rawPath.length === 0) {
throw new Error("CodeGraph changed paths must not contain an empty path");
}
if (path.includes("\0")) {
if (rawPath.includes("\0")) {
throw new Error("CodeGraph changed paths must not contain NUL characters");
}
return path;
}).filter(Boolean);
scopeCharacters += Array.from(rawPath).length + (index === 0 ? 0 : 1);
if (scopeCharacters > MAX_CHANGED_SCOPE_CHARS) {
throw new Error(
`CodeGraph changed scope may contain at most ${MAX_CHANGED_SCOPE_CHARS} characters`,
);
}
return rawPath;
});
}

function boundedDiagnostic(output, maximum = 1000) {
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/central-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,12 @@ jobs:
"$EXPECTED_HEAD_SHA" "$live"
exit 1
fi
# These exact checks consume review evidence themselves. Waiting on
# either one here creates a cycle: Noema waits for the governance
# check while the governance check waits for Noema/OpenCode.
# These checks consume Noema/OpenCode review evidence. Waiting on
# noema-review itself, opencode-review, or the downstream metadata
# gate creates a dependency cycle instead of independent evidence.
pending="$(gh api --paginate --slurp \
"repos/${TARGET_REPOSITORY}/commits/${EXPECTED_HEAD_SHA}/check-runs?per_page=100" \
--jq '[.[].check_runs[] | select((.name != "opencode-review" and .name != "metadata-only gate evaluation") and .status != "completed") | .name] | unique | join(", ")')"
--jq '[.[].check_runs[] | select((.name != "noema-review" and .name != "opencode-review" and .name != "metadata-only gate evaluation") and .status != "completed") | .name] | unique | join(", ")')"
if [ -z "$pending" ]; then
echo "All review-independent current-head checks are complete."
exit 0
Expand Down
15 changes: 8 additions & 7 deletions .github/workflows/reviewer-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,15 @@ jobs:
assert runner(["codegraph", "sync"], source_root) == ""
assert runner(["codegraph", "status"], source_root) == ""
output = runner(
[
"codegraph",
"explore",
"Review blast radius and focused tests for example.ts",
],
["codegraph", "explore", "commercialReadiness"],
source_root,
)
if "Sandbox copied 1 files" not in output or "## codegraph explore" not in output:
raise SystemExit("CodeGraph sandbox smoke output was incomplete")
if (
"Sandbox copied 1 files" not in output
or "## codegraph explore" not in output
or "No relevant code found" in output
or "export const commercialReadiness = true;" not in output
):
raise SystemExit("CodeGraph sandbox smoke did not retrieve the indexed fixture")
print(output[:2000])
PY
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
- Noema reviewer의 strict changed-file evidence를 historical 12-file prefix에서 canonical 80-file CodeGraph scope와 일치시켰다. 13–80 file PR은 선택된 모든 current-head file context를 유지하고 81개 이상은 기존처럼 실패-폐쇄하며, local CodeGraph fallback의 `HOME`·`TEMP`·`TMP`·`TMPDIR`은 ambient host path를 상속하지 않고 실행마다 새 private temporary directory로 격리한다.
- Workflow / Task Execution은 untrusted DAG를 execution/plan identity에 결합한 detached immutable snapshot으로 승인하고, validated array bounds 안에서만 task/dependency/state evidence를 읽는다. runnable 선택은 cross-execution·foreign·duplicate·non-canonical evidence, admitted concurrency를 초과한 running state, 성공하지 않은 prerequisite 뒤에 존재하는 causally impossible executed state를 실패-폐쇄하며, 선택 결과는 reservation이나 side-effect authority가 아닌 후보임을 명시한다. Agent Runtime lifecycle·State & Checkpoint·Workflow admission은 null·throwing accessor·revoked proxy 같은 malformed runtime input의 임의 JavaScript 예외를 각 bounded-context domain error로 정규화한다.
- State & Checkpoint admission은 accepted/replay 결과와 내부 checkpoint를 모두 caller-owned alias에서 분리한 frozen snapshot으로 반환한다. TypeScript `readonly`만으로는 막을 수 없는 JavaScript 런타임 alias mutation이 승인된 checkpoint authority나 `accepted`/`replay` 분류를 사후 변경하지 못하도록 실패-폐쇄한다.
- Noema의 필수 PR 워크플로 `ci`, `reviewer-ci`, `patch-validator-image`를 부동 `ubuntu-latest` 대신 명시적 `ubuntu-24.04` GitHub-hosted runner에 고정하고, 인용 여부와 무관하게 `ubuntu-latest` 회귀를 탐지하는 계약 테스트를 추가해 pre-checkout runner-assignment stall의 repository-owned selector 원인을 제거한다. 중앙 `Security Scan`의 runner/control-plane 권한은 별도 `.github` owner 경계에 유지한다.
Expand Down Expand Up @@ -67,7 +68,7 @@
- Noema reviewer와 중앙 대기 게이트가 GitHub Check Runs API를 페이지당 100건으로 끝까지 순회하도록 보강해 기본 30건/기존 100건 이후의 실패·대기 체크가 누락되는 승인 사각지대를 제거.
- 매시간 열린 PR을 완전 pagination으로 점검하고, 신뢰된 check producer·현재 head Noema 승인·리뷰 thread·status·mergeability를 실패-폐쇄 방식으로 재검증한 뒤 SHA-bound squash merge하는 `hourly-commercial-readiness` 운영 루프를 추가. PR이 0개면 판매·인수 준비 감사를 report-only로 갱신하고 JSON artifact를 보존.
- `main`에 적용되는 GitHub active rules를 완전 pagination으로 감사하는 `governance:audit`를 추가. pull request 강제, stale approval 폐기, review thread 해결, strict·integration-pinned 필수 checks, force-push 및 branch deletion 차단이 확인되지 않으면 hourly maintainer의 모든 write action을 중단하고 감사 JSON을 보존.
- 개발 의존성 `postcss`(vitest→vite 경유 transitive)를 `^8.5.18`로 override하여 GHSA-r28c-9q8g-f849(source map 자동 로딩 경로 순회, high) 취약점을 제거. `npm audit --audit-level=high`가 다시 0건으로 통과하여 매일 실패하던 `readiness-audit` 스케줄 및 `release:verify` 게이트를 복구.
- 개발 의존성 `postcss`(vitest→vite 경유 transitive)를 `^8.5.18`로 override하여 GHSA-r28c-9q8g-f849(source map 자동 로딩 경로 순회, high) 취약점을 제거. `npm audit --audit-level=high`가 0건으로 복구하여 매일 실패하던 `readiness-audit` 스케줄 및 `release:verify` 게이트를 복구.
- API 응답 스키마를 판매형 표준으로 정비: 성공/실패 공통 구조 및 `trace_id`, `error_code` 추가.
- OIDC 검증/권한 에러를 세분화한 실패 코드로 표준화.
- 구조화 로그(`http_request`) 도입: route, status_code, latency_ms, repository, workflow_ref, oidc_sub, error_code.
Expand All @@ -88,4 +89,4 @@
- 배포 스모크가 `/health`와 `/exchange`의 no-store/nosniff 보안 헤더 및 `/exchange` 401 Bearer challenge까지 검증하도록 `smoke-readiness.sh`와 회귀 테스트를 보강.
- `/exchange` 401 응답에 `WWW-Authenticate: Bearer realm="noema"` challenge를 추가하고 인증 누락은 `invalid_request`, 잘못된 토큰은 `invalid_token`으로 구분.
- `x-request-id`/`x-correlation-id` 및 client IP 계열 헤더를 길이/문자 기준으로 제한해 로그 오염과 rate-limit key 폭주를 방지.
- `KRW 2,000,000,000` 매각 가능성 Goal 등록서, buyer due diligence index, library/submodule 경계 판단서를 추가하고 `npm run acquisition:audit`로 ARR/LOI/이전성/saleable evidence를 실패-폐쇄 방식으로 검증.
- `KRW 2,000,000,000` 매각 가능성 Goal 등록서, buyer due diligence index, library/submodule 경계 판단서를 추가하고 `npm run acquisition:audit`로 ARR/LOI/이전성/saleable evidence를 실패-폐쇄 방식으로 검증.
92 changes: 84 additions & 8 deletions reviewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,100 @@ The verdict shape is the JSON contract from the sandbox plan:
}
```

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

1. **Strict runs never pass silently.** With `--strict`, a manifest missing its
diff, changed-file context, current check conclusions, CodeGraph evidence,
or any requested GitHub evidence source returns a `blocked` verdict that
names every gap.
names every gap. Production collection emits exactly one wrapper-owned
`## codegraph explore` provenance marker and treats any raw stdout line that
contains the same marker text as marker-contaminated input: that whole line
is discarded before the trusted section is retained. Clean semantic lines
from the same output remain eligible. If raw stdout contains only marker-
contaminated lines, collection retains an empty labelled explore section
rather than letting a neutralization annotation become semantic evidence. A
strict manifest with more than one trusted explore marker is therefore
ambiguous and fails closed. Initialization/status banners, an empty labelled
explore section, unlabelled concatenated output, an explicit `No relevant
code found` semantic response prefix after known lifecycle/wrapper
annotations are removed (including irregular ASCII or Unicode whitespace),
truncation/workflow-command annotations without retained semantic bytes, and
control/punctuation-only output are not semantic review evidence. The same
words appearing later inside retained source/code context do not erase
independent semantic evidence. Setup/status bytes cannot redefine the
wrapper-owned explore boundary. When the standard changed-file explore query
returns an explicit empty result, the collector may probe the pinned
CodeGraph `node --file … --symbols-only` interface only for exact current-head
regular files whose repository-relative path can be walked from the checkout
without traversing any symlinked component. The checkout root itself must be
a physical directory whose resolved path equals its absolute path; a symlinked
checkout root or symlinked ancestor invalidates symbol recovery. A regular
file reached through a symlinked parent is not current-head evidence and
cannot seed recovery. The collector caps the structural maps and serializes
each recovered `{path,symbols}` pair as canonical JSON marked explicitly as
untrusted retrieval data before one second `explore`; neither Git filename
bytes nor repository-derived symbol text is reinserted as raw prompt
instructions. Known leading CodeGraph lifecycle/status banners are removed
only for this empty-result classification, so a banner cannot suppress
symbol-seeded recovery while arbitrary preceding output still cannot trigger
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
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.
The changed-file recovery scope removes only Noema's single query-delimiter
space and otherwise preserves filename whitespace bytes exactly, including
tabs, newlines, repeated spaces, and leading/trailing spaces. Symbol-recovery
segmentation likewise preserves the full filesystem-valid path instead of
imposing a separate per-path character cutoff. To keep ambiguous whitespace
parsing bounded, recovery admits at most 512 whitespace tokens and 4,096
candidate filesystem probes; exhausting either budget fails closed without
issuing a symbol query. Recovery is complete rather than sampled: if the
uniquely recovered changed-file scope contains more than eight files, Noema
does not take an eight-file prefix and retry. The original empty result
remains fail closed until the full selected scope can be represented within
the seed bound. Where literal spaces could be either filename bytes or inter-
path separators, symbol recovery still requires exactly one filesystem-valid
segmentation; multiple valid segmentations fail closed instead of letting an
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`,
`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
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 primary check name
`opencode-review` is ignored by Noema's deterministic failed-check gate; all
other failed checks and unresolved non-outdated inline threads remain
blocking.
4. **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
defaults to 5,400 seconds and provider 429/5xx responses receive bounded SDK
retries. Production failover belongs inside `contextual-orchestrator`; Noema
Expand All @@ -74,7 +150,7 @@ python -m noema_reviewer --repo ContextualWisdomLab/naruon --pr-number 1039 \
python -m noema_reviewer --manifest-file manifest.json
```

Exit code: `0` for approve/blocked, `2` for request_changes.
Exit code: `0` for approve, `2` for request_changes, `3` for blocked.

## Configuration

Expand Down
Loading
Loading