Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (
Conflict-scope roots fail closed when the immediate parent directory is a symbolic link.
OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md).
nonnest2 hourly NVIDIA NIM repair is a thin caller at minute 16. See [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md).

OpenCode may repair only trusted `path:line` bindings on LLM probes that already carry an independent proof and source-line digest. See [`docs/doctoring/opencode-llm-review-publication.md`](docs/doctoring/opencode-llm-review-publication.md).

The materialization contract is also covered by [`docs/doctoring/exact-artifact-sbom-attestation.md`](docs/doctoring/exact-artifact-sbom-attestation.md).
5 changes: 5 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ sequenceDiagram
- Required review workflows execute **base-branch** scripts. A PR that edits
those workflows cannot widen its own `pull_request_target` token.
- Reviewer agents stay `edit: deny`. They judge; they do not implement.
- OpenCode remains the review reasoner. Deterministic code may repair only
trusted `path:line` source-line digest bindings on LLM probes; it never
invents a hypothesis, observed result, or verdict.
- Sandbox helpers copy the workspace, drop secret environment values unless
explicitly allowlisted by **name**, and run subprocesses with `shell=False`.
- Logs and review receipts redact credential shapes (tokens, bearer values,
Expand Down Expand Up @@ -145,6 +148,8 @@ trusted `uv` exporter is downloaded from the literal GitHub Releases URL for
contract.
- [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md)
— current increment's repair-worker decision and APA 7th citations.
- [`docs/doctoring/opencode-llm-review-publication.md`](docs/doctoring/opencode-llm-review-publication.md)
— LLM probe publication without inventing observed proof.
- [`docs/doctoring/fast-mlsirm-hourly-review-caller.md`](docs/doctoring/fast-mlsirm-hourly-review-caller.md)
— product-specific psychometric repair heartbeat and scientific gates.
- [`docs/doctoring/exact-artifact-sbom-attestation.md`](docs/doctoring/exact-artifact-sbom-attestation.md)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Semantic Versioning where the repository publishes a release.
- Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109).
- Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109).
- Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories.
- Published substantive OpenCode LLM probes when they already carried an independent proof and exact source-line digest but omitted a duplicated `path:line` citation, so NVIDIA NIM / OpenCode review evidence is no longer discarded as `NO_CONCLUSION`.
- Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367).
- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context.
- Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics.
Expand Down
5 changes: 4 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ This is the ContextualWisdomLab **organization-wide `.github` special repository
**OpenCode judges PRs; GitHub Actions performs mechanical updates and merges.** OpenCode approval is
evidence-gated (changed files, CodeGraph evidence, Change Flow DAG, test/coverage/docstring evidence,
an actually-executed PoC via `scripts/ci/sandboxed_verify.py` or `scripts/ci/sandboxed_web_e2e.py`,
split `Developer experience:` / `User experience:` sections). The scheduler updates a PR branch only
split `Developer experience:` / `User experience:` sections). Deterministic
code may repair only trusted `path:line` bindings on LLM probes that already
carry an independent proof and source-line digest; it never invents observed
results. The scheduler updates a PR branch only
when the latest review is approved, no current-head check has failed, and GitHub reports the PR as
behind. The mechanical merge scheduler itself never synthesizes a fix: it gives `DIRTY`/`CONFLICTING`
PRs repair guidance. A separate edit-capable autofix flow
Expand Down
45 changes: 45 additions & 0 deletions docs/doctoring/opencode-llm-review-publication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# OpenCode LLM review publication

## Decision

OpenCode remains the review reasoner. Deterministic code may repair only the
serialization binding between an LLM-authored adversarial probe's structured
`path`/`line` and the SHA-256 of that exact immutable current-head source line.
It must not create or alter the hypothesis, counterexample, observed result,
outcome, finding, or verdict.

## Root cause

Production run `31310130263` invoked NVIDIA NIM and OpenCode free models, but
several substantive control blocks were discarded even when they carried an exact
source-line receipt because the prose omitted the duplicated `path:line` citation.
Noema is intentionally dispatched only after an exact-head OpenCode approval,
so this publication failure suppressed both review identities.

## Safety boundary

Repair is attempted only when original model evidence already contains an
independent proof class and an observed result. The trusted current-head tree
must resolve the structured path and line. A path whose POSIX parts include
`..` is left unchanged (CWE-22; MITRE, n.d.). Changed-file, source-tree,
runtime-receipt, duplicate-probe, outcome, finding-location, coverage,
language, and publication gates still run afterward. Unsupported prose
continues to return `NO_CONCLUSION`.

## Verification

The regression suite proves canonical path/line repair only when an exact receipt
already exists, refusal to invent an observed result, rejection of missing or mismatched
receipts, and preservation of malformed and
unverifiable shapes, full normalizer behavior, branch coverage, docstrings,
compileability, and a clean worktree.

## References

MITRE. (n.d.). *CWE-22: Improper limitation of a pathname to a restricted
directory ('path traversal')*. Retrieved August 13, 2026, from
https://cwe.mitre.org/data/definitions/22.html

National Institute of Standards and Technology. (2020). *Security and privacy
controls for information systems and organizations* (NIST Special Publication
800-53 Rev. 5). https://doi.org/10.6028/NIST.SP.800-53r5
6 changes: 3 additions & 3 deletions requirements-pip-audit-ci-hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ packaging==26.2 \
# via
# pip-audit
# pip-requirements-parser
pip==26.1.2 \
--hash=sha256:382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab \
--hash=sha256:f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605
pip==26.2.1 \
--hash=sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e \
--hash=sha256:f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f
# via pip-api
pip-api==0.0.34 \
--hash=sha256:8b2d7d7c37f2447373aa2cf8b1f60a2f2b27a84e1e9e0294a3f6ef10eb3ba6bb \
Expand Down
77 changes: 77 additions & 0 deletions scripts/ci/opencode_review_normalize_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,82 @@ def adversarial_probe_source_receipt_error(
return ""


def repair_adversarial_probe_source_bindings(value: dict[str, Any]) -> dict[str, Any]:
"""Canonicalize only the trusted path and line citation of LLM probes.

The model remains solely responsible for the hypothesis, counterexample,
observed proof, outcome, finding, and verdict. Repair runs only when the
original model evidence already names an independent proof class, an
observed result, and the exact valid source-line digest from the immutable
current-head tree. Missing or mismatched digests remain rejected.
"""
validation = value.get("adversarial_validation")
if not isinstance(validation, dict):
return value
probes = validation.get("probes")
if not isinstance(probes, list):
return value

repaired_probes: list[Any] = []
changed = False
for probe in probes:
if not isinstance(probe, dict):
repaired_probes.append(probe)
continue
path_value = probe.get("path")
line_value = probe.get("line")
evidence_value = probe.get("evidence")
if (
not isinstance(path_value, str)
or not path_value.strip()
or isinstance(line_value, bool)
or not isinstance(line_value, int)
or line_value <= 0
or not isinstance(evidence_value, str)
or not evidence_value.strip()
):
repaired_probes.append(probe)
continue

normalized_path = path_value.strip()
if ".." in PurePosixPath(normalized_path).parts:
repaired_probes.append(probe)
continue
receipt_error = adversarial_probe_source_receipt_error(
evidence_value,
normalized_path,
line_value,
)
if receipt_error:
repaired_probes.append(probe)
continue
digest = SOURCE_LINE_RECEIPT_RE.findall(evidence_value)[0].casefold()

lexical_evidence = SOURCE_LINE_RECEIPT_RE.sub("", evidence_value).strip()
receipt_bound_evidence = (
f"{lexical_evidence} source-line-sha256={digest}"
).strip()
if adversarial_evidence_rejection_reason(receipt_bound_evidence, ""):
repaired_probes.append(probe)
continue

canonical_evidence = (
f"{lexical_evidence} Trusted current-head source binding at "
f"{normalized_path}:{line_value}; source-line-sha256={digest}"
).strip()
Comment thread
seonghobae marked this conversation as resolved.
repaired_probes.append(
{**probe, "path": normalized_path, "evidence": canonical_evidence}
)
changed = True
Comment thread
seonghobae marked this conversation as resolved.

if not changed:
return value
return {
**value,
"adversarial_validation": {**validation, "probes": repaired_probes},
}
Comment thread
seonghobae marked this conversation as resolved.


def adversarial_validation_error(
value: Any,
*,
Expand Down Expand Up @@ -1267,6 +1343,7 @@ def reject(reason: str) -> None:
return reject("APPROVE cannot contain findings")
if result == "REQUEST_CHANGES" and not findings:
return reject("REQUEST_CHANGES requires at least one finding")
value = repair_adversarial_probe_source_bindings(value)
adversarial_error = adversarial_validation_error(
value.get("adversarial_validation"),
result=result,
Expand Down
4 changes: 2 additions & 2 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1506,8 +1506,8 @@ assert_pr_review_merge_scheduler_uses_github_actions_bot_token() {
assert_file_contains "$workflow_file" "github.event_name == 'pull_request_target' && format('pr-{0}', github.event.pull_request.number)" "scheduler scopes pull_request_target concurrency to the active PR"
assert_file_contains "$workflow_file" "github.event_name == 'workflow_run' && github.event.workflow_run.pull_requests[0].number && format('pr-{0}', github.event.workflow_run.pull_requests[0].number)" "scheduler scopes workflow_run concurrency to the completed review PR"
assert_file_contains "$workflow_file" "github.event_name == 'schedule' && format('schedule-{0}', github.event.schedule)" "scheduler isolates the 15-minute organization sweep from the separate 30-minute scheduled scan"
assert_file_contains "$workflow_file" "github.event_name == 'repository_dispatch' && github.run_id" "scheduler keeps manual queue scans isolated per run"
assert_file_contains "$workflow_file" "cancel-in-progress: \${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request_review' || github.event_name == 'repository_dispatch' }}" "scheduler cancels stale PR/review/manual queue scans instead of accumulating merge/update attempts"
assert_file_contains "$workflow_file" "github.event_name == 'repository_dispatch' && github.event.client_payload.target_repository != '' && github.event.client_payload.pr_number != ''" "scheduler scopes targeted manual queue scans to the requested PR"
assert_file_contains "$workflow_file" "cancel-in-progress: \${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request_review' || github.event_name == 'repository_dispatch' || (github.event_name == 'workflow_run' && !github.event.workflow_run.pull_requests[0].number) }}" "scheduler cancels stale PR/review/manual queue scans instead of accumulating merge/update attempts"
assert_file_contains "$workflow_file" "timeout-minutes: 60" "organization sweep has enough headroom to finish the complete repository walk"
assert_file_contains "$workflow_file" "ORG_SWEEP_TRIGGER_REVIEWS: \${{ github.event_name == 'schedule' ||" "scheduled organization sweeps retry missing current-head OpenCode reviews"
assert_file_contains "$workflow_file" "ORG_SWEEP_ENABLE_AUTO_MERGE: \${{ github.event_name == 'schedule' ||" "scheduled organization sweeps merge approved current heads"
Expand Down
81 changes: 81 additions & 0 deletions tests/test_opencode_review_normalize_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -2797,3 +2797,84 @@ def test_main_logs_the_exact_control_rejection_reason(tmp_path, capsys):
stderr = capsys.readouterr().err
assert "CONTROL_REJECTED candidate=1" in stderr
assert "adversarial probe 1 evidence must state the observed proof result" in stderr


def test_valid_control_repairs_trusted_model_probe_source_bindings(
tmp_path, monkeypatch
):
"""Substantive LLM probes survive formatting drift without weaker evidence."""
require_adversarial_validation(tmp_path, monkeypatch, "scripts/ci/example.py")
validation = adversarial_validation()
for probe in validation["probes"]:
probe["evidence"] = (
"Focused regression command passed and disproved the adversarial hypothesis. "
+ source_line_receipt(f"line {probe['line']}")
)

normalized = norm.valid_control(
control(adversarial_validation=validation),
expected_head_sha="head",
expected_run_id="run",
expected_run_attempt="attempt",
)

assert normalized is not None
for index, probe in enumerate(normalized["adversarial_validation"]["probes"]):
line = 7 + index
assert f"scripts/ci/example.py:{line}" in probe["evidence"]
assert source_line_receipt(f"line {line}") in probe["evidence"]
assert probe["evidence"].count("source-line-sha256=") == 1


def test_probe_binding_repair_does_not_invent_independent_observation(
tmp_path, monkeypatch
):
"""Canonical source binding cannot turn unsupported model prose into approval."""
require_adversarial_validation(tmp_path, monkeypatch, "scripts/ci/example.py")
validation = adversarial_validation()
for index, probe in enumerate(validation["probes"]):
probe["evidence"] = (
f"Description at scripts/ci/example.py:{7 + index} repeats the hypothesis. "
+ source_line_receipt(f"line {7 + index}")
)
reasons = []

assert (
norm.valid_control(
control(adversarial_validation=validation),
expected_head_sha="head",
expected_run_id="run",
expected_run_attempt="attempt",
rejection_reasons=reasons,
)
is None
)
assert any("executed command" in reason for reason in reasons)


@pytest.mark.parametrize(
"validation",
[
None,
{"probes": None},
{"probes": [None]},
{"probes": [{"path": 7, "line": 1, "evidence": "command passed"}]},
{"probes": [{"path": "scripts/ci/example.py", "line": True, "evidence": "command passed"}]},
{"probes": [{"path": "scripts/ci/example.py", "line": 0, "evidence": "command passed"}]},
{"probes": [{"path": "scripts/ci/example.py", "line": 7, "evidence": 9}]},
{"probes": [{"path": "missing.py", "line": 7, "evidence": "command passed"}]},
{
"probes": [
{
"path": "../secrets/key.py",
"line": 7,
"evidence": "command passed",
}
]
},
],
)
def test_probe_binding_repair_preserves_unrepairable_shapes(validation):
"""Malformed, unsafe, or unverifiable model evidence remains unchanged."""
candidate = control(adversarial_validation=validation)
assert norm.repair_adversarial_probe_source_bindings(candidate) is candidate
Loading