Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
4a5bfec
test(opencode): expose missing provider failure envelope
seonghobae Sep 12, 2026
a7a4f78
test(opencode): require owned telemetry quality lane
seonghobae Sep 12, 2026
14f3740
fix(opencode): preserve bounded provider failure causes
seonghobae Sep 12, 2026
4341566
fix(ci): pair review dispatch with exact blob pin
seonghobae Sep 12, 2026
10cd412
test(opencode): follow failure envelope authority
seonghobae Sep 12, 2026
187f9fc
test(opencode): reject credential-shaped failure metadata
seonghobae Sep 12, 2026
0e7f7e4
fix(opencode): suppress credential-shaped failure fields
seonghobae Sep 12, 2026
7f9489e
test(opencode): reject prose-spoofed failure causes
seonghobae Sep 12, 2026
2b78ea6
test(opencode): reject excessively deep gateway envelopes
seonghobae Sep 12, 2026
2e2d61d
test(opencode): reproduce deep gateway recursion
seonghobae Sep 12, 2026
fe035a8
fix(opencode): derive failure class from structured receipt
seonghobae Sep 12, 2026
76194e1
test(opencode): bind causal classes to structured fields
seonghobae Sep 12, 2026
ab44b39
style(opencode): normalize regression test spacing
seonghobae Sep 12, 2026
fc13c6c
test(opencode): reject unproven identifier provenance
seonghobae Sep 12, 2026
a8eb135
fix(opencode): require allowlisted receipt identifiers
seonghobae Sep 12, 2026
d062bc1
test(opencode): require receipt identifier allowlists
seonghobae Sep 12, 2026
d44c8b3
test(opencode): fail closed on unproven route identities
seonghobae Sep 12, 2026
b383d7e
style(opencode): remove obsolete regex dependency
seonghobae Sep 12, 2026
ac647df
docs(opencode): state receipt provenance boundary
seonghobae Sep 12, 2026
f1179a4
docs(opencode): doctor unproven identity handling
seonghobae Sep 12, 2026
4c96d60
docs(opencode): record identity provenance gap
seonghobae Sep 12, 2026
ba20074
test(opencode): reject deeply nested failure events
seonghobae Sep 12, 2026
ae49bc3
fix(opencode): fail closed on deeply nested events
seonghobae Sep 12, 2026
5d408ce
test(opencode): reject unproven exception identities
seonghobae Sep 12, 2026
6de920e
fix(opencode): suppress unproven exception identities
seonghobae Sep 12, 2026
8f38a3b
fix(opencode): enforce bounded tail and JSON depth
seonghobae Sep 12, 2026
be1d52a
test(opencode): align bounded-tail and synthetic-secret fixtures
seonghobae Sep 12, 2026
1b2b1a3
test(opencode): require structured failure causes
seonghobae Sep 12, 2026
79f2ee1
test(security): scope synthetic provider token allowlist
seonghobae Sep 12, 2026
f537c34
fix(opencode): align bounded tail to complete JSONL events
seonghobae Sep 12, 2026
cc570f0
test(opencode): cover complete-line tail parsing
seonghobae Sep 12, 2026
e8e3ba2
refactor(opencode): remove unreachable payload check
seonghobae Sep 12, 2026
442216b
test(opencode): close depth and status coverage branches
seonghobae Sep 12, 2026
e4a06af
fix(opencode): preserve aligned bounded tail record
seonghobae Sep 12, 2026
2b0b52b
test(opencode): cover exactly aligned bounded tail
seonghobae Sep 12, 2026
4e68a81
docs(opencode): carry provider failure decision forward
seonghobae Sep 12, 2026
62e935f
test(opencode): reject contradictory receipt authorities
seonghobae Sep 12, 2026
2e07208
fix(opencode): fail closed on contradictory receipt authority
seonghobae Sep 12, 2026
f4f0166
style(opencode): remove trailing test blank line
seonghobae Sep 12, 2026
b1f3ac2
fix(opencode): authenticate bounded failure causes
seonghobae Sep 12, 2026
2a0154b
fix(security): classify OpenCode synthetic token history
seonghobae Sep 12, 2026
87510bb
fix(opencode): preserve bounded successor evidence
seonghobae Sep 12, 2026
b450e1c
fix(security): restore exact synthetic fixture classification
seonghobae Sep 12, 2026
646f3fd
test(security): bind synthetic fixture classification
seonghobae Sep 12, 2026
b386b47
test(security): preserve conjunctive leak classification
seonghobae Sep 12, 2026
c3937d0
test(opencode): fail closed across gateway body aliases
seonghobae Sep 12, 2026
3df808c
fix(opencode): reconcile every gateway body authority
seonghobae Sep 12, 2026
77d0263
docs(opencode): qualify control-plane references
seonghobae Sep 12, 2026
8f05458
fix(security): keep synthetic-secret allowlist self-nonmatching
seonghobae Sep 12, 2026
9cbc4a2
style(opencode): normalize test separation
seonghobae Sep 12, 2026
69d2c15
test(security): verify leak rule stays self-nonmatching
seonghobae Sep 12, 2026
009cc96
fix(opencode): preserve attempt phase within each body
seonghobae Sep 12, 2026
b3044ff
test(opencode): cover malformed mapping and alias paths
seonghobae Sep 12, 2026
5a7f9c3
test(opencode): cover malformed gateway mapping branches
seonghobae Sep 12, 2026
86863a6
test(opencode): reject malformed body authority override
seonghobae Sep 12, 2026
3c43dd1
fix(opencode): keep malformed gateway cause fail-closed
seonghobae Sep 12, 2026
07af79a
test(opencode): reject present malformed body aliases
seonghobae Sep 12, 2026
f163887
fix(opencode): distinguish missing and null body aliases
seonghobae Sep 12, 2026
8f1d645
test(opencode): cover present malformed body aliases
seonghobae Sep 12, 2026
6faee54
test(opencode): keep regression in canonical suite
seonghobae Sep 12, 2026
646315a
fix(security): anchor OpenCode synthetic token allowlist
seonghobae Sep 12, 2026
bb183e4
fix(security): scope synthetic allowlist to exact secret
seonghobae Sep 12, 2026
af6de73
test(opencode): reproduce reviewed failure-envelope authority gaps
seonghobae Sep 12, 2026
5fb9c98
fix(opencode): preserve protocol layers in failure authority
seonghobae Sep 12, 2026
f506694
test(opencode): bind reviewed authority repairs to owner suite
seonghobae Sep 12, 2026
e7c58c0
test(opencode): retire duplicate review regression file
seonghobae Sep 12, 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
28 changes: 28 additions & 0 deletions .github/workflows/agent-review-runtime-quality-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ on:
- "docs/doctoring/noema-review-token-lifetime.md"
- "docs/product-technical-gap-baseline.md"
- ".github/workflows/opencode-review-dispatch.yml"
- "scripts/ci/run_opencode_review_model_pool.sh"
- "scripts/ci/opencode_failure_envelope.py"
- "tests/test_opencode_model_pool_runner.py"
- "tests/test_opencode_failure_envelope.py"
- "docs/doctoring/opencode-provider-failure-envelope.md"
- "scripts/ci/ensure_rust_llvm19.sh"
- "tests/test_opencode_rust_coverage_toolchain_contract.py"
- "scripts/ci/materialize_base_javascript_packages.py"
Expand Down Expand Up @@ -185,6 +190,11 @@ jobs:
noema_suite=true
;;
.github/workflows/opencode-review-dispatch.yml|\
scripts/ci/run_opencode_review_model_pool.sh|\
scripts/ci/opencode_failure_envelope.py|\
tests/test_opencode_model_pool_runner.py|\
tests/test_opencode_failure_envelope.py|\
docs/doctoring/opencode-provider-failure-envelope.md|\
scripts/ci/ensure_rust_llvm19.sh|\
tests/test_opencode_rust_coverage_toolchain_contract.py|\
scripts/ci/materialize_base_javascript_packages.py|\
Expand Down Expand Up @@ -357,6 +367,24 @@ jobs:
python -m pytest -q tests/test_javascript_materializer_docstrings.py
python -m compileall -q scripts/ci/materialize_base_javascript_packages.py tests/test_javascript_materializer_docstrings.py

- name: Verify OpenCode provider failure envelope
if: steps.affected_suites.outputs.opencode == 'true'
run: |
set -euo pipefail
PYTHONPATH=. python -m pytest -q \
--cov=scripts.ci.opencode_failure_envelope \
--cov-branch \
--cov-fail-under=100 \
tests/test_opencode_failure_envelope.py \
tests/test_opencode_model_pool_runner.py
python -m interrogate --fail-under 100 \
scripts/ci/opencode_failure_envelope.py
python -m compileall -q \
scripts/ci/opencode_failure_envelope.py \
tests/test_opencode_failure_envelope.py \
tests/test_opencode_model_pool_runner.py
bash -n scripts/ci/run_opencode_review_model_pool.sh

- name: Verify exact-head path policy and syntax
if: steps.affected_suites.outputs.strix == 'true'
env:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,7 @@ jobs:
ContextualWisdomLab/.github:scripts/ci/pr_head_replay_guard.py | \
ContextualWisdomLab/.github:scripts/ci/pr_review_merge_scheduler.py | \
ContextualWisdomLab/.github:scripts/ci/run_opencode_review_model_pool.sh | \
ContextualWisdomLab/.github:scripts/ci/opencode_failure_envelope.py | \
ContextualWisdomLab/.github:scripts/ci/opencode_review_normalize_output.py | \
ContextualWisdomLab/.github:scripts/ci/strix_quick_gate.sh | \
ContextualWisdomLab/.github:scripts/ci/validate_opencode_failed_check_review.sh | \
Expand All @@ -2649,6 +2650,7 @@ jobs:
ContextualWisdomLab/.github:tests/test_materialize_base_javascript_packages.py | \
ContextualWisdomLab/.github:tests/test_opencode_agent_contract.py | \
ContextualWisdomLab/.github:tests/test_opencode_model_pool_runner.py | \
ContextualWisdomLab/.github:tests/test_opencode_failure_envelope.py | \
ContextualWisdomLab/.github:tests/test_pr_head_replay_guard.py | \
ContextualWisdomLab/.github:tests/test_pr_review_fix_scheduler_coverage.py | \
ContextualWisdomLab/.github:tests/test_pr_review_merge_scheduler.py | \
Expand Down
10 changes: 10 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,13 @@ regexes = [
'''gh[pousr]_(?:1234567890abcdef(?:1234)?|abcdef1234567890abcdef1234567890abcdef|installation_token_value|user_token_value|server_token_value|runner_token_value|placeholder_token_with_underscores_123|[a-z]{16}|[a-z]{20}|[a-z]{30}|[a-z]{38})''',
'''github_pat_11AAAAA_(?:abcdefg|abcdefg1234567890|[A-Za-z]{7}_[a-z]{7}|[A-Za-z]{7}_[a-z]{17})''',
]

[[allowlists]]
description = "OpenCode synthetic unknown-provenance token used only by confidentiality regressions."
condition = "AND"
regexTarget = "secret"
paths = [
'''(^|/)tests/test_opencode_failure_envelope\.py$''',
'''(^|/)tests/test_opencode_model_pool_runner\.py$''',
]
regexes = ['''^BYTEZ_TEST_SECRET_[1]234567890$''']
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Preserve bounded phase, reason, HTTP status, and duration evidence for OpenCode gateway failures while suppressing raw provider content and unverified provider/model identifiers and capping failure input.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
### OpenCode failures retain bounded causal telemetry

- `run_opencode_review_model_pool.sh` now measures each failed invocation and
delegates its diagnostic to `opencode_failure_envelope.py`. The parser reads
only the final 16 KiB of the OpenCode error stream and up to 16 KiB of the gateway's
canonical `error.detail` receipt. Failure class comes only from allowlisted
structured status/reason semantics and validated HTTP status. Phase uses a
fixed public enum; provider, exception, and served model remain `unknown`
until an immutable CO receipt/catalog proves their provenance. Raw prose and
lexically valid unknown identifiers cannot influence or enter diagnostics.
Oversized, contradictory, deeply nested, malformed, or missing fields fail
closed; a malformed canonical body also suppresses outer status/reason
authority, and review exhaustion remains nonzero.
The dedicated runtime-quality lane now owns the runner, parser, and fixtures
with 100% statement/branch and public-doc coverage. Refs #2112.

### Failed-check finding names the Strix sandbox instead of the gateway

- `opencode-review-dispatch.yml`'s `emit_strix_provider_failure_finding` rendered one fixed finding for every `STRIX_PROVIDER_UNAVAILABLE` line, whose Root cause read "The contextual-orchestrator gateway or its discovered provider pool was unavailable for this run". `#1953` had just given the Strix sandbox bootstrap failure its own second verdict token (`STRIX_SANDBOX_UNAVAILABLE`) precisely because that attribution is wrong for it -- the sandbox container never reaches its Caido proxy, so the run dies before the gateway serves anything -- and this consumer re-applied the wrong attribution one step downstream, into the review findings and the failure census. The emitter now branches on the second token: a sandbox verdict gets a finding that names Strix's sandbox, says the verdict does not name the gateway, and tells the reader not to change gateway or provider configuration on its strength. A `STRIX_PROVIDER_UNAVAILABLE` line without the token keeps its existing text verbatim, so the gateway class has no regression surface. No test covered this finding text at all before (`gateway or its discovered provider pool` matched nothing under `tests/`); `tests/test_opencode_dispatch_strix_sandbox_finding.py` now runs the production emitter from the published run block and pins both directions plus the no-signal case. Refs #1953, #1935.
Expand Down
18 changes: 18 additions & 0 deletions docs/adr/0003-contextual-orchestrator-vendored-free-zdr.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,21 @@ all five, and auto-optimize routing by cost.
per-agent attempt; it changes only *which* agent gets tried next, never any
per-attempt timeout, consistent with the 2026-08-31 amendment above. No
other contextual-orchestrator behavior changes with this pin advance.

- **2026-09-12 proposed amendment: preserve redaction-safe OpenCode failure
provenance.** The OpenCode model-pool adapter must keep the gateway-owned
canonical `error.detail` receipt useful after suppressing raw provider
content. For a bounded structured error it emits only allowlisted phase,
normalized reason, HTTP status, and caller-measured duration. Provider and
served-model identifiers remain `unknown` until a versioned CO-issued
non-secret identifier contract can be validated locally. Unknown, malformed,
and absent fields become fixed `unknown`/`malformed_response`
values; arbitrary
messages, response bodies, headers, credentials, and unbounded identifiers
never reach public Actions logs. The adapter reads at most the final 16 KiB
of the JSONL failure stream, suppresses unverified identifier values, and
parses at most 16 KiB from the nested canonical gateway body. Larger gateway
bodies and deeply nested envelopes fail closed to the fixed malformed state.
This does not add a retry, timeout, provider choice, or model policy
to `.github`; contextual-orchestrator remains the owner of discovery,
routing, and failover.
74 changes: 74 additions & 0 deletions docs/doctoring/opencode-provider-failure-envelope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# OpenCode provider-failure envelope

## Problem and exact evidence

On 2026-09-12, `.github` PR
[`#2106`](https://github.com/ContextualWisdomLab/.github/pull/2106) at exact
head `24bb6591ab7df23558cb793b4af60c567ff9da97` reached the single required
`contextual-orchestrator/orchestrator/free` model route in OpenCode run
[`34693400612`](https://github.com/ContextualWisdomLab/.github/actions/runs/34693400612).
The request failed after the sidecar and route preflight had succeeded, but the
only surviving causal evidence was `class=provider-error`, two byte counts,
and a statement that provider content was suppressed. That was enough to keep
the review fail-closed, but not enough to distinguish queue admission, HTTP
429/5xx, request size, malformed JSON, route exhaustion, or missing serving
identity. Issue
[`#2112`](https://github.com/ContextualWisdomLab/.github/issues/2112) owns the
repair.

## Constraints

- OpenCode, Noema, and Strix keep the single `orchestrator/free` gateway route;
no provider/model/group override or paid fallback is introduced.
- Telemetry is diagnostic only. It cannot produce approval, clean evidence, a
retry, a timeout, or a merge bypass.
- Provider-controlled messages, bodies, prompts, credentials, headers, source
text, and arbitrary nested payloads never reach stdout, status text, or
annotations.
- Only exact allowlisted phase/reason enums and validated HTTP status numbers
may enter causal output. Lexically valid but unproven identifiers are not
evidence of non-secret provenance. Provider, model, and exception identities
remain `unknown` until an immutable CO receipt/catalog proves them.

## Alternatives and decision

Keeping the previous byte-count-only line was rejected because it preserves
secrecy at the cost of causal attribution. Printing the raw OpenCode event or
gateway response was rejected because public `pull_request_target` logs cannot
safely carry provider-controlled text. Adding caller-side retries or an
elapsed-time diagnosis was rejected because the gateway owns routing and the
observed five-second failure did not prove a timeout.

The selected design adds a small standard-library parser at the OpenCode
adapter boundary. It reads at most the final 16 KiB of each failure artifact,
drops an incomplete leading line, and accepts only an OpenCode `type=error`
event within an explicit 64-level structural-depth limit. From the gateway response it parses
at most 16 KiB and reads only the canonical `error.detail`/`error_detail`
receipt and its last bounded attempt. Only allowlisted structured status/reason
pairs determine failure class; contradictory pairs become `provider-error`.
Phase is emitted only when it matches a fixed public enum. Provider, exception,
and served model remain `unknown` because this consumer has no immutable CO
catalog proof that can authenticate dynamic identities. Raw
event/stderr bytes are represented only by presence and byte counts, never
passed to the causal classifier. Oversized gateway bodies, deeply nested or
malformed JSON, and malformed Unicode fail closed to bounded metadata.

## Executable evidence, risks, and effects

The production launcher fixtures cover HTTP 429/queue capacity, provider 503,
non-JSON response bodies, HTTP 413 request admission, no eligible route, absent
served-model metadata, contradictory structured causes, raw prose pollution,
unproven identifier provenance, 16 KiB overflow, excessive JSON depth, and
secret-bearing ignored fields. Unit tests cover all parser statements and
branches, and the consolidated runtime-quality workflow selects this suite
whenever the launcher, parser, fixture, or this authority record changes.

The remaining risk is semantic drift and missing identity provenance in the
gateway receipt. Unknown fields are deliberately not guessed or copied; a
future immutable CO schema/catalog change must add a failing fixture before an
identity or enum enters the allowlist. Operators can now route a
429/queue failure to capacity policy, a 5xx to the gateway/provider boundary,
a 413 to request admission, and malformed JSON to the response adapter without
reading secret-bearing bodies. Until exact-head hosted checks, independent
review, protected-main integration, and an unchanged-head replay of #2106 are
complete, this repair remains Proposed rather than released evidence.
32 changes: 32 additions & 0 deletions docs/product-technical-gap-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -3353,3 +3353,35 @@ queries the check-runs API at its own time, order-independently. The implementin
their change was safe because they had scoped it narrowly, not because they had checked for the name
collision — which is the more useful lesson: **a job name is unique only within one workflow file, and the
same name in another file can carry the opposite safety property.**

## OpenCode provider-failure causal envelope — 2026-09-12

**Status: Proposed; owner repair implemented on the issue branch, not yet
protected or released.** `ContextualWisdomLab/.github#2106@24bb6591ab7df23558cb793b4af60c567ff9da97`
had five exact-head security/runtime checks succeed, then OpenCode run
`34693400612` exhausted after emitting only `class=provider-error` and byte
counts. The absence of safe phase/provider/status/model evidence made the
failure causally ambiguous; it did not prove the separate timeout defect.

Issue `ContextualWisdomLab/.github#2112` now has an executable RED→GREEN owner repair. The OpenCode
adapter parses only the final 16 KiB error-event stream and at most 16 KiB of the canonical
gateway receipt. Only allowlisted structured status/reason pairs determine
failure class; fixed enums bound phase/reason, while provider, exception, and
served model remain `unknown` until an immutable CO receipt/catalog contract
authenticates them. Raw text, lexically valid unknown identifiers,
contradictory evidence, bodies over 16 KiB, and 10,000-level JSON all fail
closed. A malformed canonical body also suppresses outer `data.code` and HTTP
status authority instead of allowing either to override the fixed malformed
state. Production fixtures cover 429, 5xx, malformed JSON with conflicting
outer authority, 413, pool exhaustion, unproven identity, causal pollution,
and credential-shaped fields.
The previously missing CI ownership is also repaired: launcher/parser/test/doc
changes select the dedicated runtime-quality suite, which enforces 100% parser
statement/branch and public-doc coverage.

**Remaining action:** obtain exact-head hosted checks and independent review,
define and release the versioned CO identity-provenance contract before exposing
provider/model identity, merge normally to protected `main`, then replay #2106
unchanged. Only that consumer replay can show whether the next real failure
contains enough bounded causal evidence; this Proposed branch is not immutable
release or production proof.
Loading
Loading