Skip to content
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ commit and exposed without running build hooks; a lone `--require-hashes`
directive is not trust evidence. See
[`docs/doctoring/opencode-exact-vcs-dependency-evidence.md`](docs/doctoring/opencode-exact-vcs-dependency-evidence.md).
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).

Strix `ModelBehaviorError: Tool … not found in agent strix` is retryable infrastructure, not a vulnerability finding. See [`docs/doctoring/strix-tool-protocol-fallback.md`](docs/doctoring/strix-tool-protocol-fallback.md).

All 18 product hourly review-repair callers (OriginWeave at minute 10, nonnest2 at minute 16, and 16 others) are one file, [`.github/workflows/hourly-review-repair.yml`](.github/workflows/hourly-review-repair.yml), a `github.event.schedule` lookup table rather than 18 near-copy-pasted files. See [`docs/doctoring/hourly-review-repair-single-file-consolidation.md`](docs/doctoring/hourly-review-repair-single-file-consolidation.md); the per-repository doctoring records (e.g. [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md), [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md)) remain as historical background per repository.
Organization edge runtimes use Cloudflare Pingora. Do not add or preserve active Nginx containers, packages, commands, service/config files, or Kubernetes Nginx ingress annotations/classes. Read [`docs/policies/PINGORA_EDGE_POLICY.md`](docs/policies/PINGORA_EDGE_POLICY.md) and ADR-0019 before changing HTTP edge, static-serving, ingress, TLS, or proxy deployment behavior.

Expand Down
10 changes: 10 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ flowchart TD
Labels --> Verify
```

## Strix tool-protocol fallback

When a provider emits `agents.exceptions.ModelBehaviorError: Tool <name>
not found in agent strix`, the quick gate treats that line as retryable
infrastructure and continues to a distinct configured model. It is not
scan evidence from the target repository.

## Hourly NVIDIA NIM repair gate
The metadata reconciler is convergent and mode-aware. Already-correct
descriptions/topics and legacy default-branch `/docs` Pages sites receive no
write; absent or drifted legacy Pages state is created/updated, and disabled
Expand Down Expand Up @@ -262,6 +270,8 @@ resolver conflict.
— import-only exact source dependencies for networkless coverage.
- [`docs/doctoring/fast-mlsirm-hourly-review-caller.md`](docs/doctoring/fast-mlsirm-hourly-review-caller.md)
— product-specific psychometric repair heartbeat and scientific gates.


Comment on lines +273 to +274

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 ARCHITECTURE.md introduces two blank lines inside a bulleted list

The diff inserts two blank lines (ARCHITECTURE.md) between two adjacent list items in the 'Related durable documents' section, which splits what was a single markdown list. Cosmetic only, but the author's description states these unrelated doc changes (AGENTS.md/CLAUDE.md/ARCHITECTURE.md) were meant to be removed from this lane's scope — worth confirming whether they should be present in the PR at all.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- [`docs/doctoring/exact-artifact-sbom-attestation.md`](docs/doctoring/exact-artifact-sbom-attestation.md)
— current increment's attestation decision and APA 7th citations.
- [`docs/doctoring/sandboxed-web-readiness-loopback-boundary.md`](docs/doctoring/sandboxed-web-readiness-loopback-boundary.md)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,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.
- Treat Strix `ModelBehaviorError: Tool … not found in agent strix` as retryable infrastructure so a configured fallback model can finish the required security scan instead of failing the repository as insecure.
- Bound the central Semgrep job to one `SEMGREP_IMAGE` digest for log evidence, manifest inspection, and `docker run`, so a buyer reconstructing the scan can prove the logged scanner is the scanner that ran.
- 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).
Expand Down
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ repeatable compile command.
- **Product hourly callers** stay thin. Do not hard-code OriginWeave, aFIPC, naruon, or Keyverse
into `pr-review-fix-scheduler.yml`. The model credential remains `NVIDIA_NIM_API_KEY`
on the worker, never `COPILOT_GITHUB_TOKEN`.
- **Strix tool-protocol errors** (`ModelBehaviorError: Tool … not found in agent strix`) are
retryable infrastructure. They must not be published as repository vulnerabilities.
- **Central review routes through the vendored contextual-orchestrator gateway.**
`pr-review-autofix.yml` provisions `scripts/ci/contextual_orchestrator_review_sidecar.sh`
(the five provider secrets flow into its KV; the writer runs
Expand Down
27 changes: 27 additions & 0 deletions docs/doctoring/strix-tool-protocol-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Strix tool-protocol fallback

## Incident and buyer impact

Strix can exit before producing security evidence when the selected model
emits a tool call the `strix` agent does not expose:

`agents.exceptions.ModelBehaviorError: Tool execute not found in agent strix`

The required check then failed as if the target repository were insecure,
and configured fallback models never ran.

## Decision

Classify only that exact exception class, missing-tool phrase, and agent
name `strix` as retryable infrastructure. Fallback to a distinct configured
model. Vulnerability artifacts and fallback exhaustion remain fail-closed.
Generic application errors are not matched.

## References

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

OpenAI. (2025). *OpenAI Agents SDK*.
https://openai.github.io/openai-agents-python/
19 changes: 19 additions & 0 deletions scripts/ci/strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3357,6 +3357,15 @@ is_llm_token_limit_error() {
return 1
}

# Strix's agent SDK can reject a provider response before it produces scan
# evidence when the model emits a tool call that the selected agent does not
# expose. Treat this exact SDK/provider failure as retryable so a configured
# fallback model can complete the security scan; it is not evidence from the
# target repository and must never be treated as a vulnerability.
is_model_tool_protocol_error() {
grep -Eiq 'agents\.exceptions\.ModelBehaviorError:[[:space:]]*Tool [[:alnum:]_]+ not found in agent strix' "$STRIX_LOG"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Tool name pattern only matches alphanumeric/underscore tool identifiers

The tool-name capture in the regex is [[:alnum:]_]+ (strix_quick_gate.sh). This covers the observed variants (execute, ls, agent_finish), but any future SDK tool name containing a hyphen, dot, or other character would not match and would fall through to fail-closed handling. Not a defect for the currently observed cases, but a possible completeness gap if the SDK introduces such tool names.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}
Comment on lines +3365 to +3367

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Tool-protocol regex untested for the ls variant

is_model_tool_protocol_error matches any [[:alnum:]_]+ tool name, so execute, ls, and agent_finish all classify. The added fixture only emits execute and agent_finish, so the ls case the PR cites as the motivating evidence is never exercised, and a hyphen/dot in a future tool name would not match.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +3365 to +3367

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Tool-protocol classifier does not require a separate provider marker; relies on the SDK exception prefix

is_model_tool_protocol_error (strix_quick_gate.sh) greps the entire $STRIX_LOG for agents\.exceptions\.ModelBehaviorError: Tool <name> not found in agent strix without also requiring a separate LLM_PROVIDER_ONLY_REGEX marker (unlike the timeout/connection detectors). This is deliberate and mirrors is_midstream_fallback_error (:2919), which also matches a single specific token. The pattern is anchored to the OpenAI Agents SDK exception class plus the literal agent name strix, so it is reasonably specific to trusted SDK output rather than arbitrary target-repo content. The author's PR description explicitly asks a future writer to add a RED fixture proving the classifier cannot be spoofed by unrelated application/model text and to bind it to trusted process/error context — worth confirming that follow-up, since STRIX_LOG can contain model-echoed target content. Even if spoofed, real blocking findings are still evaluated (:2601-2607, has_only_below_threshold_vulnerabilities) and fallback exhaustion fails closed, limiting the impact.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


# Detect whether the strix log contains evidence of infrastructure-level
# errors (timeout, rate-limit, transport failures) that indicate the scan
# was interrupted or incomplete. Used as a guard to prevent the
Expand All @@ -3378,6 +3387,10 @@ has_detected_infrastructure_error() {
return 0
fi

if is_model_tool_protocol_error; then
return 0
fi

if is_midstream_fallback_error; then
return 0
fi
Expand Down Expand Up @@ -4268,6 +4281,12 @@ is_model_retryable_error() {
return 0
fi

if is_model_tool_protocol_error; then
# A provider/model tool-contract failure is recoverable with a distinct
# configured model, but it is not a clean scan result.
return 0
fi
Comment on lines +4284 to +4288

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Tool-protocol errors correctly skip same-model retry and go straight to fallback

The new error class is intentionally absent from is_transient_same_model_retry_error (strix_quick_gate.sh), so a tool-contract failure does not retry the same model (which would deterministically fail again) and instead moves to a distinct configured fallback model via is_model_retryable_error (:3854-3858). This matches the intent and the test case tool-protocol-fallback-success, which expects exactly two model invocations (primary then fallback-one).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


if is_timeout_error; then
# Process and provider timeouts are not clean evidence, but they are
# recoverable across distinct fallback models. Strict provider-signal
Expand Down
38 changes: 38 additions & 0 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,8 @@ assert_opencode_review_uses_codegraph_and_contextual_orchestrator() {
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "skipping remaining attempts for this model" "opencode review skips same-model retries after context-window overflow"
assert_file_contains "$REPO_ROOT/.github/workflows/strix.yml" "exceeded your current quota" "strix wrapper neutralizes quota-only provider failures without vulnerability reports"
assert_file_contains "$REPO_ROOT/scripts/ci/strix_quick_gate.sh" "billing details" "strix quick gate classifies provider quota starvation as infrastructure"
assert_file_contains "$REPO_ROOT/scripts/ci/strix_quick_gate.sh" "is_model_tool_protocol_error" "strix quick gate retries agent tool-protocol provider failures"
assert_file_contains "$REPO_ROOT/scripts/ci/strix_quick_gate.sh" "ModelBehaviorError:[[:space:]]*Tool [[:alnum:]_]+ not found in agent strix" "strix quick gate identifies unsupported agent tool responses"
assert_file_not_contains "$workflow_file" 'timeout-minutes: 325' "opencode review target must not cap inference"
assert_file_contains "$workflow_file" 'timeout-minutes: 12' "opencode evidence preparation fails closed before it ties up the review queue"
assert_file_not_contains "$workflow_file" 'timeout-minutes: 205' "opencode model pool step must not cap inference"
Expand Down Expand Up @@ -3677,6 +3679,23 @@ REPORT
;;
esac
;;
tool-protocol-fallback-success)
case "${STRIX_LLM:-}" in
vertex_ai/tool-protocol-primary)
echo "agents.exceptions.ModelBehaviorError: Tool execute not found in agent strix"
echo "agents.exceptions.ModelBehaviorError: Tool agent_finish not found in agent strix"
exit 1
;;
vertex_ai/fallback-one)
echo "scan ok after tool-protocol fallback"
exit 0
;;
*)
echo "Error: tool-protocol fallback path unexpected (${STRIX_LLM:-})" >&2
exit 26
;;
esac
;;
openai-primary-quota-fallback-success)
case "${STRIX_LLM:-}" in
openai/quota-primary)
Expand Down Expand Up @@ -6277,6 +6296,16 @@ run_filtered_gate_case_if_requested() {
input-file-root-override-precedence)
run_input_file_root_override_takes_precedence_over_runner_temp_case
;;
tool-protocol-fallback-success)
run_gate_case "tool-protocol-fallback-success" \
"vertex_ai/tool-protocol-primary" \
"vertex_ai/fallback-one" \
"0" \
"REGEX:Strix quick scan succeeded with fallback model 'vertex_ai/fallback-one' in [0-9]+s\\." \
"2" \
"vertex_ai/tool-protocol-primary|vertex_ai/fallback-one" \
"<unset>|<unset>"
;;
vertex-without-llm-api-key)
run_vertex_without_llm_api_key_case
;;
Expand Down Expand Up @@ -10147,6 +10176,15 @@ run_gate_case_allow_provider_signal "vertex-primary-midstream-fallback-success"
"vertex_ai/midstream-primary|vertex_ai/fallback-one" \
"<unset>|<unset>"

run_gate_case "tool-protocol-fallback-success" \
"vertex_ai/tool-protocol-primary" \
"vertex_ai/fallback-one" \
"0" \
"REGEX:Strix quick scan succeeded with fallback model 'vertex_ai/fallback-one' in [0-9]+s\\." \
"2" \
"vertex_ai/tool-protocol-primary|vertex_ai/fallback-one" \
"<unset>|<unset>"

run_gate_case_allow_provider_signal "vertex-primary-midstream-retry-same-model-success" \
"vertex_ai/retry-midstream-primary" \
"vertex_ai/fallback-one vertex_ai/fallback-two" \
Expand Down
Loading