Skip to content

ci(integration): Add tiered L0-L3 integration gates with scope planner and codex review - #802

Merged
Yiminnn merged 14 commits into
mainfrom
integration-tiered-ci
Jun 18, 2026
Merged

Yiminnn merged 14 commits into
mainfrom
integration-tiered-ci

Conversation

@Yiminnn

@Yiminnn Yiminnn commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements the ENG-265 plan (#799). Splits the single integration-eval.yml into four scope-aware test levels plus a deterministic review pack, so light checks run per commit and the heaviest integration check runs only when a PR is final — scoped to the components a change can affect, fanned across a DeepSeek-first agent roster, and graded by a fail-closed deterministic verdict with an advisory-stricter-only Codex before/after-equivalence reviewer on top.

Level Trigger Runs Required
L0 test.yml every PR/push (no keys) ruff + ty + pytest (incl. new stdlib planner/filter/rubric tests) + audit + concurrency ✅
L1 integration-light.yml every PR (cheap secret-free detect-scope self-skips to a green no-op) 1 scoped smoke rollout + agent-judge ✅
L2 integration-scope.yml every PR + dispatch; real work when labeled integration:medium (cheap detect-scope no-op otherwise) targeted matrix cells over the changed area (docker/daytona, skill modes, network + cheat lanes), representative DeepSeek roster subset for broad changes ✅
L3 integration-final-review.yml manual workflow_dispatch full scope matrix (full DeepSeek roster) → deterministic review pack + Codex before/after-equivalence verdict final gate

Every level always triggers (no on: paths filter); a secret-free detect-scope job computes from the diff whether real work is needed and otherwise reports SUCCESS as a green no-op, so each check can be made an unconditionally required branch-protection check.

Key design (grilled to closure)

  • Trust boundary: the planner, grader, harness, agent configs, and review skill always load from trusted origin/main; only src/benchflow (code-under-test) comes from the PR head — a PR can't weaken its own gate. Plain pull_request.
  • Fail-closed verdict: the deterministic review pack (build_integration_review_pack.py over rubric_checks.py) is the required gate, emitting verdict.md = mergeable | mergeable-with-quarantines | not mergeable. An unreadable plan, a missing required slot, or any not-mergeable gate fails closed; the pack exits non-zero. Codex is an advisory-stricter-only before/after-equivalence signal (worst(deterministic, codex)): it can downgrade mergeable → not mergeable but never upgrade, and itself fails closed to not mergeable (codex unavailable) if the binary/auth/output is missing.
  • Golden-truth baseline: before/after reward-band parity (schema + lifecycle + reward-BAND, not bit-identity) against the HuggingFace SkillsBench leaderboard main run (openhands · deepseek-v4-flash) via check_skillsbench_harbor_parity — apples-to-apples with our lane. Covers 6/9 tasks; the other 3 (absent from the leaderboard's DeepSeek runs) band-compare NA and fall back to oracle determinism + the Codex equivalence verdict. rerun-base only for scope=expanded.
  • Scope → set → config planner: the deterministic stdlib-only integration_matrix.py maps changed paths → one of 7 named task-sets (citation / low-smoke / low-3 / medium-3 / high-3 / nine / expanded) + unioned axes (skill modes, docker/daytona, scope-gated network lane, cheat lane). scope=auto derives from the diff; explicit --scope overrides. Fail-closed hard cell ceiling (caps.max_cells, rejected_overflow + exit 2, never a silent drop) and an aggregate-concurrency clamp (per_agent_concurrency × distinct daytona agents ≤ 24). DeepSeek flash/pro tiering by task difficulty.
  • Rubric: rubric_checks.py operationalizes the benchflow-experiment-review skill — R-REAL realness, V-TAMPER verifier-tamper (reusing agent_judge._scan_verifier_tamper, folded fail-closed into realness), V-NETWORK static network-posture, P-REWARD/P-SCHEMA docker↔daytona parity, R-TELEMETRY — honest about deterministic vs codex/residual.

Agent roster, models & judge (DeepSeek-first)

  • DeepSeek-first roster (9 → 7 agents). The broad "affects every agent" lanes fan a DeepSeek-only roster (deepseek_roster = openhands, pi-acp, openclaw, opencode, mimo), all on deepseek/deepseek-v4-flash (promoted to deepseek-v4-pro on hard tasks via deepseek_tiering). mimo moved off xiaomi/mimo-v2.5 onto DeepSeek (closes the XIAOMI gap).
  • Gated natives. codex-acp (native OpenAI gpt-5.4-nano) and claude-agent-acp (Bedrock anthropic-messages claude-haiku) cannot run on DeepSeek (OpenAI-Responses / anthropic-messages protocol walls), so they are gated: they appear in the matrix only via affected-agent (a PR touching their own adapter — codex_config.py → codex-acp, claude*.py → claude-agent-acp), paired with the DeepSeek baseline, never in the default broad fan.
  • Dropped. gemini (native Google GenerateContent) and harvey-lab-harness (OpenAI Responses API) are dropped entirely — neither can run on DeepSeek. caps.max_agents lowered 9 → 7.
  • Two-tier fanout. Broad changes to shared agent infra (agent-runtime-infra rule: registry/protocol/install/credentials/env/errors/acp) or provider/LLM-proxy routing fan a representative DeepSeek subset (roster_subset = openhands, pi-acp, opencode + baseline) at L2 auto-on-push; the full DeepSeek roster runs at L3/expanded/nine. The full-roster check precedes the subset/affected-agent branches so promoting an infra change to L3 fans the full roster (not the L2 subset).
  • Judge on DeepSeek-v4 only. The agent-judge and the review-pack per-rollout reader run on DeepSeek-v4 only: judge_model = deepseek-v4-flash recorded as metadata, and at runtime select_integration_provider exports BENCHFLOW_JUDGE_MODEL=openai/deepseek-v4-flash (routed via the OpenAI-compatible chat-completions surface). agent_judge.DEFAULT_JUDGE_MODEL changed from gemini-3.1-flash-lite to openai/deepseek-v4-flash; GEMINI_API_KEY is no longer load-bearing on the default path.

Credential-aware emission & matrix guards

  • Credential-aware filter (filter_credentialed_cells.py, runs in the plan job under the pypi-internal-preview environment): drops any cell whose agent+model credential (per resolve_agent_env) is absent into skipped_uncredentialed as a documented skip, not a red slot, so un-keyed agents never spin up a false-red sandbox. Fails open (passes the matrix through unchanged) if the benchflow import fails. Recognizes both missing-credential shapes: missing API key (<KEY> required … not set) and missing base URL (requires <KEY> to build the provider base URL) — the latter catches a missing DEEPSEEK_BASE_URL that would otherwise red-fail the DeepSeek baseline at the first LLM call.
  • Empty-matrix green no-op guard. A fully-filtered (empty) matrix sets has_cells=false and skips run-matrix + review-pack as a green no-op with a warning, instead of hard-failing fromJson([]) ("matrix must define at least one combination") into a false not mergeable (PR review r3438339786).

Fail-closed gates, drift checker & ADRs (ported from #799)

  • Fail-closed verifier-tamper gate. agent_judge.realness_issues now folds the mechanically-detected tamper signal (evidence.flagged_actions from _scan_verifier_tamper) into the judge-independent realness gate: any flagged write/delete/chmod of a score-defining file hard-fails the gate even when the LLM judge is absent or lenient (ADR-0002 Task A1, surfaced as V-TAMPER / R-REAL).
  • Config↔manifest drift checker. run_suite.load_suite now calls _consistency.config_drifts: if a sibling configs/ dir exists and any config disagrees with suites/release.yaml (agent membership both directions, model pins, order-insensitive task includes, task source {repo,path,ref}), the suite load raises SuiteError instead of producing a quietly inconsistent plan. No-op when configs/ is absent (synthetic test manifests). Caught a real defect this branch shipped (configs/mimo.yaml with no manifest axis → fixed by axes.agents.experimental:[mimo]).
  • ADRs + glossary. ADR-0001 (lanes execute as matrix cells, not pytest markers; release.yaml is a declarative backlog, not a gating path), ADR-0002 (cheap fail-closed tamper regex ships now; authoritative producer-side hash deferred), ADR-0003 (V-NETWORK is a static scope-gated declaration check today; runtime egress conformance deferred, blocked on build_egress_override not yet in main), plus a docs/integration-tiers.md §12 glossary. Network vocabulary aligned to the authoritative NetworkMode enum (no-network / allowlist / public).

Hardening fixes

  • L3 Codex auth via repo OPENAI_API_KEY. The fail-closed L3 Codex reviewer now authenticates with the durable, revocable repo-level OPENAI_API_KEY (written as an apikey auth.json, like codex login --api-key), instead of a rotating personal CODEX_AUTH_JSON OAuth blob. Precedence: CODEX_AUTH_JSON → OPENAI_API_KEY/CODEX_API_KEY → pre-existing on-host auth.json; otherwise still fails closed. No separate org secret needs creating.
  • Bootstrap guards. L1/L2 short-circuit should_run=false to a green no-op when the trusted base branch doesn't yet contain integration_matrix.py (bootstrap PRs).
  • Grader e2e bug fixes (surfaced by a real reward-1.0 rollout wrongly graded not mergeable): R-TELEMETRY now reads production timing from top-level started_at/finished_at + timing.total (fixing a false telemetry failure), and the stale-slot check no longer conflates the skillsbench task-source sha with the benchflow PR head_sha (param renamed head_sha → expected_source_sha; with no pin no slot is marked stale, since the workflow runs at HEAD).

Verified

  • ✅ Daytona↔Docker parity audit passed on real infra (oracle scores 1.0, identical reward on both backends).
  • ✅ Leaderboard baseline fetch validated end-to-end (hf download … --revision main); band-compare via check_skillsbench_harbor_parity.
  • ✅ Stdlib planner / filter / rubric / review-pack test suites pass, ruff clean, all workflows valid YAML — including end-state planner assertions (agents == 7 with gemini/harvey absent; broad fan == deepseek_roster; gated natives only via affected-agent; _matrix_agents ordering regression) and the credential-filter fail-open / missing-API-key / missing-base-URL coverage.
  • ✅ Real e2e run of the ci(integration): Add tiered L0-L3 integration gates with scope planner and codex review #802 pipeline (planner → openhands+deepseek rollout → grader) on PR fix(providers): harden LiteLLM proxy env against inherited FastAPI docs vars #794's diff: a reward-1.0 rollout previously mis-graded not mergeable now grades all-gates-green → mergeable.

Test plan

  • L0 test.yml lane runs ruff + ty + pytest (incl. new stdlib planner/filter/rubric/review-pack tests) green
  • Deterministic review pack exits non-zero on not mergeable; planner exits 2 + sets rejected_overflow on cell-ceiling overflow
  • Verifier-tamper realness gate fails closed without the LLM judge; config-drift checker raises SuiteError on a manifest mismatch
  • Daytona↔Docker reward parity confirmed on real infra; leaderboard main baseline fetch + band-compare confirmed
  • Credential filter: fail-open pass-through, missing-API-key drop, and missing-base-URL (DEEPSEEK_BASE_URL) recognition unit-covered
  • Live L1 rollout on a real PR (scoped smoke + DeepSeek agent-judge) produces a green verdict end-to-end in CI
  • Live L2 scoped matrix (broad change → DeepSeek roster_subset; affected-agent change → gated native + baseline) emits and runs the expected cells, with un-keyed cells documented-skipped (not red)
  • Empty-matrix guard exercised in CI: a fully-filtered matrix reports has_cells=false green no-op (no fromJson([]) failure)
  • L3 manual workflow_dispatch final gate: full DeepSeek roster matrix → review pack + Codex equivalence verdict, with Codex authed via repo OPENAI_API_KEY
  • Branch protection: mark L0 / L1 / L2 required

Follow-ups / admin

  • L3 Codex auth: uses the existing repo OPENAI_API_KEY (written as an apikey auth.json) — no new secret required; fail-closed until resolvable.
  • Branch protection: mark L0 / L1 / L2 required.
  • Deferred (small src changes, one coordinated additive rollout-contract schema bump): producer-side verifier_files_mutated: bool; runtime egress V-NETWORK-CONFORM lane (blocked on build_egress_override in main); network_mode result.json serialization.

Relates to #799 (the ENG-265 plan / ADRs); supersedes #799's full 9-agent gemini/harvey roster and gemini judge.

symphony-bot added 2 commits June 18, 2026 02:24
…r and codex review

Refactor the single integration-eval.yml into four scope-aware test levels
plus a deterministic review pack, implementing the ENG-265 plan (#799).

- L0 (test.yml): unchanged static/unit + a concurrency block.
- L1 integration-light.yml: per-PR scoped smoke rollout + agent-judge gate.
- L2 integration-scope.yml: scope-gated matrix (docker/daytona, skill modes,
  network + cheat lanes) selected from the diff.
- L3 integration-final-review.yml: manual final gate; deterministic review pack
  plus a codex before/after-equivalence reviewer (fail-closed).

New trusted-main CI infrastructure:
- .github/scripts/integration_matrix.py: deterministic 7-set scope planner
  (citation/low-smoke/low-3/medium-3/high-3/nine/expanded), hard cell ceiling,
  aggregate-concurrency cap, DeepSeek flash/pro tiering by task difficulty.
- tests/integration/rubric_checks.py + .github/scripts/build_integration_review_pack.py:
  rubric gates (realness, skill loading, verifier isolation, parity, capability
  attribution) operationalizing the benchflow-experiment-review skill; fail-closed
  verdict (mergeable | mergeable-with-quarantines | not mergeable).
- .github/scripts/codex_review.py: codex-exec reviewer (auth.json), advisory and
  able only to make the verdict stricter; cheap per-rollout DeepSeek reads.
- Reward-band parity against the HuggingFace SkillsBench leaderboard main run
  (openhands deepseek-v4-flash) as golden truth.
- docs/integration-tiers.md + docs/integration-review-rubric.md.

Security: planner/grader/harness always load from trusted main; only
src/benchflow code-under-test comes from the PR head; plain pull_request
(internal-PR-only). 65 stdlib tests pass, ruff clean.
…ecker + ADRs (port #799)

Ports the verified-valuable pieces of the ENG-265 plan PR (#799) into the
implementation, so #799 can be closed without losing the decisions or code.

- Fail-closed verifier tamper (ADR-0002): a mechanically-detected verifier-file
  mutation is now included in agent_judge.realness_issues, so the realness gate
  hard-fails on tamper even when the LLM judge is absent/lenient (previously it
  was only surfaced to the judge as advisory). TDD:
  test_realness_gate_fails_closed_on_verifier_tamper (red -> green).
- Config<->manifest drift checker: tests/integration/_consistency.py +
  test_integration_consistency.py, wired into run_suite.load_suite. Catches a
  drift this branch shipped (configs/mimo.yaml with no manifest axis); fixed by
  adding the experimental:[mimo] agent axis to suites/release.yaml.
- ADRs: docs/adr/0001-0003 (lane execution home, verifier-tamper, network_mode
  conformance), with Context corrected to #802's reality and the deferred work
  (producer-side hash, verifier_files_mutated field, runtime egress conformance
  lane blocked on benchflow.sandbox._egress) recorded. Plus the conformance-vs-
  identity glossary aligned to task/config.py NetworkMode.

ruff clean; 77 stdlib tests pass.
… e2e on a real rollout

End-to-end run of the #802 pipeline (planner -> openhands+deepseek rollout ->
grader) on PR #794's diff produced a real reward-1.0 rollout that the grader
wrongly graded "not mergeable". Two bugs:

- R-TELEMETRY false-failed: the production schema adapter read timing from
  run_config / timing.{started_at,ended_at} (the flat-fixture shape), but a real
  result.json records started_at/finished_at at the TOP LEVEL with per-phase
  seconds under timing.total. Adapter now reads those; R-TELEMETRY passes.
- Stale-slot false-positive: classify_slots compared the rollout's task-source
  sha (the skillsbench task-repo commit) against the benchflow head_sha (the PR
  commit) — unrelated repos, so every real rollout read "stale". Staleness now
  compares only against an explicit task-source pin (plan.source_sha); absent a
  pin it is not fabricated (the workflow guarantees freshness by running at HEAD).

Verified: the same real rollout now grades all-gates-green -> verdict
"mergeable". Regression tests added (production top-level timing; task-source vs
head_sha not conflated; stale via source_sha pin). 79 stdlib tests, ruff clean.
@Yiminnn
Yiminnn marked this pull request as ready for review June 18, 2026 04:54
@Yiminnn

Yiminnn commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Ready for review — ported #799 + e2e-validated on a real rollout

Ported from #799 (now closed), TDD: fail-closed verifier-tamper gate (agent_judge.realness_issues), config↔manifest drift checker (_consistency.py + experimental:[mimo] axis), and ADR-0001/0002/0003 + glossary.

End-to-end validated against PR #794 (fix(providers): harden LiteLLM proxy):

  1. Planner classified fix(providers): harden LiteLLM proxy env against inherited FastAPI docs vars #794's diff → scope=custom, network lane, 4 cells (jax+data-to-d3 flash, weighted-gdp-calc pro via tiering, citation-check allowlist variant). ✅
  2. Ran a real openhands+deepseek-v4-flash rollout of jax-computing-basics on Docker → reward 1.0, 21 tool calls, 478K tokens, full ACP/LLM trajectories. ✅
  3. Ran the grader (rubric_checks + build_integration_review_pack) over the real artifacts → it initially mis-graded the healthy run, surfacing two real bugs (now fixed in 45d5cd4):
    • R-TELEMETRY read timing from the flat-fixture shape; real result.json stores started_at/finished_at top-level + timing.total.
    • stale-slot compared the rollout's skillsbench task-source sha against the benchflow head_sha (unrelated repos) → always "stale".
  4. Re-ran: all gates green → verdict mergeable. ✅

Regression tests added for both. 79 stdlib tests pass, ruff clean. Commits: 7d593bd (tiers) · d5715be (#799 port) · 45d5cd4 (e2e fixes).

Before merge: add CODEX_AUTH_JSON to pypi-internal-preview (L3 Codex is fail-closed without it); set branch protection to require L0/L1/L2.

@greptile-apps

greptile-apps Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the single integration-eval.yml with a four-tier gating system (L0–L3) plus a deterministic review pack, scoped to the components a change can affect and fanned across a DeepSeek-first agent roster. It introduces the scope planner (integration_matrix.py), credential-aware cell filter, rubric grader (rubric_checks.py), review-pack builder, and an advisory-stricter-only Codex equivalence reviewer on top of a fail-closed deterministic verdict.

  • L0/L1/L2 gates (test.yml, integration-light.yml, integration-scope.yml): run unconditionally with a secret-free detect-scope short-circuit so each can be an unconditionally-required branch-protection check; the empty-matrix guard prevents false fromJson([]) failures when credentials filter all cells.
  • L3 gate (integration-final-review.yml): workflow_dispatch-only, full DeepSeek roster → deterministic pack + required fail-closed Codex reviewer whose verdict composes as worst(deterministic, codex); the head_sha→expected_source_sha rename eliminates a false-stale slot classification, and the R-TELEMETRY timing fix corrects a previously mis-graded reward-1.0 rollout.
  • Supporting changes: verifier-tamper signal folded into realness_issues as a judge-independent hard fail; config↔manifest drift checker raises SuiteError on inconsistency; DEFAULT_JUDGE_MODEL moved from Gemini to openai/deepseek-v4-flash.

Confidence Score: 4/5

The deterministic gate is structurally sound and fail-closed; the L3 Codex gate has an unresolved credential routing problem flagged in a prior thread that causes it to permanently emit not mergeable (codex unavailable) on every dispatch.

The core planner, credential filter, and rubric grader are well-designed with comprehensive test coverage. The new finding here — _parse_codex_verdict returning the first matching verdict instead of the worst across all candidates — only affects the advisory codex layer and cannot produce a false mergeable at the deterministic gate. The dominant risk comes from the L3 Codex gate credential bleed issue identified in a prior review thread that has not been resolved in this branch.

integration-final-review.yml and codex_review.py together form the L3 required gate — the credential routing between select_integration_provider.py and the codex subprocess needs the most attention before this gate can be relied upon.

Important Files Changed

Filename Overview
.github/scripts/codex_review.py New L3 codex reviewer: first-match verdict parsing can miss stricter signals in multi-verdict output; greedy DOTALL regex and DeepSeek credential bleed already flagged in previous threads.
.github/scripts/integration_matrix.py New deterministic 7-set scope planner; uncaught CalledProcessError on git-diff failure already flagged in a previous thread.
.github/workflows/integration-final-review.yml New L3 manual final-review gate; the DeepSeek credential bleed breaking the required Codex gate was flagged in a previous thread and remains the dominant risk.
.github/workflows/integration-scope.yml New L2 scoped integration gate; has_cells empty-matrix guard correctly prevents false fromJson([]) failures; advisory codex step also affected by DeepSeek credential bleed but continue-on-error limits impact.
.github/workflows/integration-light.yml New L1 smoke gate; correctly separates detect-scope (no secrets) from the credentialed rollout job; hardcoded smoke task and provider selection look sound.
.github/scripts/filter_credentialed_cells.py Credential filter correctly handles both missing-API-key and missing-base-URL message shapes; fail-open design on import failure is sound.
.github/scripts/build_integration_review_pack.py Deterministic review-pack builder; slot classification, parity checks, and fail-closed verdict computation look correct; the head_sha→expected_source_sha rename eliminates a false-stale classification bug.
tests/integration/rubric_checks.py New rubric grader; R-TELEMETRY timing fix and verifier-tamper fold into realness gate are well-structured; lazy-import discipline for benchflow is correctly maintained.
tests/integration/_consistency.py Config↔manifest drift checker; bidirectional membership check and model-pin validation are correct; no-op on absent configs/ dir is safe.
tests/integration/agent_judge.py DEFAULT_JUDGE_MODEL switched from gemini to openai/deepseek-v4-flash; verifier-tamper flagged_actions folded into realness_issues as a judge-independent hard fail.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    PR[Pull Request / Push] --> L0

    subgraph L0["L0 — test.yml (every PR/push, no keys)"]
        L0_ruff[ruff + ty]
        L0_pytest[pytest incl. planner/rubric/filter tests]
        L0_audit[audit + concurrency]
    end

    PR --> L1

    subgraph L1["L1 — integration-light.yml (always required)"]
        DS[detect-scope\nno secrets, trusted main] -->|should_run=false| L1_noop[green no-op]
        DS -->|should_run=true| RS[rollout-smoke\npypi-internal-preview env\nDeepSeek baseline agent]
        RS --> AJ[agent_judge gate]
    end

    PR -->|label: integration:medium| L2

    subgraph L2["L2 — integration-scope.yml (required, gated)"]
        DS2[detect-scope\nno secrets] -->|gate_open=false| L2_noop[green no-op]
        DS2 -->|gate_open=true| PL[plan job\ncredential filter has_cells]
        PL -->|has_cells=false| L2_noop2[green no-op]
        PL -->|has_cells=true| RM[run-matrix\nDeepSeek roster subset]
        RM --> RP2[review-pack\ndeterministic verdict\nadvisory codex]
        RP2 -->|not mergeable| L2_FAIL[gate fails]
        RP2 -->|mergeable| L2_PASS[gate passes]
    end

    DISPATCH[workflow_dispatch\npr_number] --> L3

    subgraph L3["L3 — integration-final-review.yml (manual gate)"]
        PL3[plan job\ncredential filter]
        RM3[run-matrix\nfull DeepSeek roster]
        RP3[review-pack\ndeterministic grader\nCodex REQUIRED fail-closed]
        VERDICT["worst(deterministic, codex)"]
        PL3 --> RM3 --> RP3 --> VERDICT
        VERDICT -->|mergeable| L3_PASS[check-run success]
        VERDICT -->|not mergeable| L3_FAIL[check-run failure]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    PR[Pull Request / Push] --> L0

    subgraph L0["L0 — test.yml (every PR/push, no keys)"]
        L0_ruff[ruff + ty]
        L0_pytest[pytest incl. planner/rubric/filter tests]
        L0_audit[audit + concurrency]
    end

    PR --> L1

    subgraph L1["L1 — integration-light.yml (always required)"]
        DS[detect-scope\nno secrets, trusted main] -->|should_run=false| L1_noop[green no-op]
        DS -->|should_run=true| RS[rollout-smoke\npypi-internal-preview env\nDeepSeek baseline agent]
        RS --> AJ[agent_judge gate]
    end

    PR -->|label: integration:medium| L2

    subgraph L2["L2 — integration-scope.yml (required, gated)"]
        DS2[detect-scope\nno secrets] -->|gate_open=false| L2_noop[green no-op]
        DS2 -->|gate_open=true| PL[plan job\ncredential filter has_cells]
        PL -->|has_cells=false| L2_noop2[green no-op]
        PL -->|has_cells=true| RM[run-matrix\nDeepSeek roster subset]
        RM --> RP2[review-pack\ndeterministic verdict\nadvisory codex]
        RP2 -->|not mergeable| L2_FAIL[gate fails]
        RP2 -->|mergeable| L2_PASS[gate passes]
    end

    DISPATCH[workflow_dispatch\npr_number] --> L3

    subgraph L3["L3 — integration-final-review.yml (manual gate)"]
        PL3[plan job\ncredential filter]
        RM3[run-matrix\nfull DeepSeek roster]
        RP3[review-pack\ndeterministic grader\nCodex REQUIRED fail-closed]
        VERDICT["worst(deterministic, codex)"]
        PL3 --> RM3 --> RP3 --> VERDICT
        VERDICT -->|mergeable| L3_PASS[check-run success]
        VERDICT -->|not mergeable| L3_FAIL[check-run failure]
    end
Loading

Reviews (8): Last reviewed commit: "fix(integration): make the missing-base-..." | Re-trigger Greptile

Comment on lines +182 to +189
match = re.search(r"\{.*\}", raw, re.DOTALL)
if match:
try:
finding["parsed"] = json.loads(match.group(0))
except json.JSONDecodeError:
finding["parse_error"] = "deepseek finding JSON was unparseable"
else:
finding["parse_error"] = "no JSON object in deepseek finding"

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.

P2 Greedy DOTALL regex merges multiple JSON objects into one invalid span

re.search(r"\{.*\}", raw, re.DOTALL) is greedy and spans from the first { to the last } in the entire string. When the model includes any additional curly-brace content after its JSON answer (e.g. an explanatory sentence like "I observed {"key": "val"} in the trace"), the matched span covers both objects and the text between them — json.loads then raises JSONDecodeError, the finding gets parse_error, and the structured evidence fed to the codex pass 2 is lost for that rollout. The fix is a non-greedy match or an iterative approach that tries each candidate from left to right.

Comment on lines +1066 to +1074
def _changed_files_from_git(base_ref: str, head_sha: str) -> list[str]:
out = subprocess.run(
["git", "diff", "--name-only", f"{base_ref}...{head_sha}"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
check=True,
)
return [line.strip() for line in out.stdout.splitlines() if line.strip()]

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.

P2 Uncaught CalledProcessError bypasses the ScopeError handler

subprocess.run(..., check=True) raises subprocess.CalledProcessError when git diff fails (e.g. because HEAD_SHA was not successfully fetched, which is silenced by || true in the workflow). That exception propagates past the except ScopeError block in main(), producing a raw Python traceback and exit code 1 instead of a ::error:: annotation. Using check=False and raising ScopeError on failure makes the error path consistent with every other planner failure mode.

Suggested change
def _changed_files_from_git(base_ref: str, head_sha: str) -> list[str]:
out = subprocess.run(
["git", "diff", "--name-only", f"{base_ref}...{head_sha}"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
check=True,
)
return [line.strip() for line in out.stdout.splitlines() if line.strip()]
def _changed_files_from_git(base_ref: str, head_sha: str) -> list[str]:
out = subprocess.run(
["git", "diff", "--name-only", f"{base_ref}...{head_sha}"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
check=False,
)
if out.returncode != 0:
raise ScopeError(
f"git diff {base_ref}...{head_sha} failed (rc={out.returncode}): "
f"{out.stderr.strip()[:200]}"
)
return [line.strip() for line in out.stdout.splitlines() if line.strip()]

async def one(rollout: Path) -> dict:
try:
evidence = agent_judge.load_rollout_evidence(rollout)
evidence_json = json.dumps(evidence.to_dict(), indent=2)[:8000]

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.

P2 Arbitrary byte truncation can split a JSON string mid-value

json.dumps(evidence.to_dict(), indent=2)[:8000] cuts at a character boundary with no regard for JSON structure. This is embedded in the prompt as labelled "UNTRUSTED DATA" text, so the model reads it as raw text rather than parsing it — but a truncation mid-string (e.g. inside a long trajectory snippet) can produce visually misleading fragments. Truncating after a complete top-level key, or at a clean \n boundary, would produce more legible evidence.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@bingran-you bingran-you added enhancement New feature or request P1 Important debt — must fix soon, but does not block the current release. review:pending PR is ready-for-review, no reviewer engagement yet. area:eval Issue / PR lives primarily in the "eval" subsystem. area:diagnostics Issue / PR lives primarily in the "diagnostics" subsystem. labels Jun 18, 2026
@bingran-you

Copy link
Copy Markdown
Collaborator

Automation triage update (2026-06-18): pushed 2d964c6c to clear the two concrete CI blockers from the last run.

What changed:

  • Added citation-check-network to the real SkillsBench native example enumerations used by the failing test_task_check_eval_consistency path and export coverage.
  • Made L1/L2 detect-scope pass as a green bootstrap no-op when the trusted base branch does not yet contain .github/scripts/integration_matrix.py. This keeps the security model intact for future PRs: once this lands on main, later PRs still load planner/grader code only from trusted base.

Local verification on the PR branch:

  • uv run python -m pytest tests/test_task_check_eval_consistency.py::test_eval_create_enumerates_real_skillsbench_native_examples tests/test_task_export.py -q -> 24 passed
  • uv run python -m pytest tests/test_integration_matrix.py -q -> 37 passed
  • uv run ruff check tests/test_task_check_eval_consistency.py tests/test_task_export.py .github/scripts/integration_matrix.py -> clean

CI has restarted. Leaving review:pending; merge still requires green CI plus human review under repo policy.

@bingran-you

Copy link
Copy Markdown
Collaborator

Automation follow-up (2026-06-18): the pushed bootstrap fix is now verified remotely as well.

Current PR #802 checks at head 2d964c6c:

  • test passed
  • pip-audit passed
  • integration-light / detect-scope passed; rollout-smoke skipped as expected for bootstrap no-op
  • integration-scope / detect-scope passed; plan/run-matrix/review-pack skipped as expected without the medium label

Additional local validation after installing the required sandbox-daytona extra:

  • uv run python -m pytest tests/ -> 4340 passed, 12 skipped, 7 deselected
  • uv run ty check src/ -> clean
  • uv run ruff check . -> clean

No merge taken: repo policy still requires human review before main.

symphony-bot added 3 commits June 18, 2026 15:22
…ENAI_API_KEY

Drop the CODEX_AUTH_JSON requirement: a personal ChatGPT OAuth blob
(auth_mode: chatgpt) rotates and would stale-break the fail-closed L3 gate, and
exposes a personal account in a shared org secret. The reviewer now prefers the
existing repo-level OPENAI_API_KEY (durable, revocable), written by
codex_review.py as an apikey auth.json so `codex exec` uses it the same way
`codex login --api-key` would. CODEX_AUTH_JSON remains an optional fallback.

- codex_review.py: write_codex_auth writes an apikey auth.json from
  OPENAI_API_KEY / CODEX_API_KEY (precedence: full blob -> api key -> on-host
  auth.json). New test_write_codex_auth_from_openai_api_key.
- L2/L3 workflows: codex step authenticates via the repo OPENAI_API_KEY (already
  present); no CODEX_AUTH_JSON secret to create.
- docs/ADMIN_SETUP/ADRs: codex auth = OPENAI_API_KEY, no extra secret.

101 stdlib tests pass; ruff clean.
…very agent

Scope gap: the planner ran only the baseline agent (openhands) for changes that
break ALL agents — the agent registry, shared ACP/protocol/install/credential
infra, and provider/LLM-proxy routing. A specific agent file already mapped to
its agent (codex_config.py -> codex-acp + baseline), but registry.py and
providers/litellm_runtime.py silently tested openhands only.

- New `all-agents` extra -> _matrix_agents fans the full credentialed roster.
- scope_map: new `agent-runtime-infra` rule (registry/protocol/install/
  credentials/env/errors/acp) and `all-agents` on the provider/network rule.
- Specific-agent changes are unchanged (affected agent + baseline, stays cheap).
- All bounded by the hard cell ceiling: registry.py -> 9 agents/40 cells,
  providers -> 9 agents/28 cells, no overflow.

TDD regressions: test_agent_runtime_infra_fans_full_roster,
test_provider_change_fans_full_roster, test_specific_agent_change_does_not_fan_full_roster.
40 planner tests pass; ruff clean; MiniYaml-safe.
… + model policy + cred-aware emission

Refines the b4d10ea all-agents fan-out (which put the full 9-agent daytona roster
on L2's auto-on-push label trigger and assumed creds CI lacks).

- Breadth-tier: the L2 agent-runtime-infra + provider rules now emit a
  representative SUBSET (openhands + codex-acp + gemini + pi-acp); the FULL 9
  roster runs only at L3 via expanded/nine. New `roster_subset` in
  scope_defaults + an `all-agents-subset` branch in _matrix_agents.
- Model policy (empirically grounded): the openai-completions-family agents
  (openhands, openclaw, opencode, pi-acp, mimo) run on deepseek-v4-flash via the
  LiteLLM proxy — mimo on deepseek closes the XIAOMI gap; gemini/codex/harvey
  stay native (branded CLIs are protocol-locked: deepseek serves only
  openai-completions, so the protocol guard raises); claude-agent-acp routes
  through aws-bedrock's anthropic-messages surface.
- Cred-aware emission (bug fix): .github/scripts/filter_credentialed_cells.py
  drops any cell whose agent+model credential is absent (resolve_agent_env
  signal) as a documented skip — un-keyed agents no longer spin up a sandbox,
  fail, and log a false-red slot. Wired into L2 + L3. claude skips until
  AWS_BEARER_TOKEN_BEDROCK is provisioned.
- ADR-0004 records the breadth-tier + model-policy + cred-aware decisions.

112 stdlib tests pass; ruff clean; MiniYaml-safe.
Comment on lines +246 to +253
- name: Upload matrix plan
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: integration-scope-matrix
path: matrix.json
if-no-files-found: error
retention-days: 14

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.

P1 Empty matrix after credential filtering causes run-matrix job failure instead of a clean skip

The plan job first runs the planner (which determines should_run=true based on cell count > 0) and then runs filter_credentialed_cells.py, which can drop cells whose provider credentials are absent. The filtered matrix is emitted directly to the run-matrix strategy without a guard against an empty result. If all planned cells are filtered out, fromJson(needs.plan.outputs.matrix) resolves to [], and GitHub Actions will fail the run-matrix job with "The matrix must define at least one combination." The review-pack job then runs on empty artifacts and produces "not mergeable" — a false-negative verdict that blocks a PR with no actual regression. Adding an emptiness check in the emit step (setting should_run back to false and skipping downstream jobs) or inside filter_credentialed_cells.py would close this gap.

symphony-bot added 2 commits June 18, 2026 21:00
…ase-url skips

- L2/L3 workflows: add a `has_cells` output from the credential-filter step.
  When the filtered matrix is empty (no provider key for any planned cell),
  skip run-matrix + review-pack as a green no-op instead of failing
  `fromJson([])` ("matrix must define at least one combination") into a false
  'not mergeable'. Closes PR #802 review r3438339786.
- filter_credentialed_cells.py: also recognize the provider-base-url-missing
  message ("requires <KEY> to build the provider base URL") as a documented
  missing-credential skip. Previously a missing DEEPSEEK_BASE_URL slipped past
  the filter and red-failed the DeepSeek baseline agent at the first LLM call.
… gate natives)

Broad roster lanes now fan the DeepSeek roster ONLY (new `deepseek_roster` in
scope_defaults.yml). The non-DeepSeek agents cannot ride the DeepSeek proxy
(protocol walls), so they are gated rather than fanned by default:

- claude-agent-acp (Bedrock anthropic-messages) and codex-acp (OpenAI Responses)
  run ONLY via affected-agent -- a PR touching their own adapter -- paired with
  the DeepSeek baseline for before/after comparison. Never in the default fan.
- gemini (native Google GenerateContent; _NATIVE_PROTOCOL_AGENTS) and
  harvey-lab-harness (OpenAI Responses API in its _create_adapter, same wall as
  codex) are dropped from the roster entirely.
- roster 9 -> 7; caps.max_agents 9 -> 7; L2 breadth subset is now 3 DeepSeek
  reps (openhands, pi-acp, opencode).

The agent-judge runs on DeepSeek-v4 only -- no other models. judge_model is
deepseek-v4-flash (recorded per-cell metadata + local default); at runtime
select_integration_provider.py exports BENCHFLOW_JUDGE_MODEL=openai/deepseek-v4-flash,
routed via the OpenAI-compatible chat-completions surface with the DeepSeek
key/base_url. GEMINI_API_KEY is no longer load-bearing on the default path.

Docs (integration-tiers.md, ADR 0004, ADMIN_SETUP.md) and tests updated.
@Yiminnn

Yiminnn commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Update — DeepSeek-first roster + DeepSeek-only judge, plus credential-filter hardening

Pushed two commits (bbaab40..8154145); the PR description has been refreshed to reflect the whole scope.

feat(integration): DeepSeek-first roster + judge (drop gemini/harvey, gate natives) — 8154145

  • Broad lanes now fan the DeepSeek roster only (new deepseek_roster): openhands, pi-acp, openclaw, opencode, mimo.
  • claude-agent-acp (Bedrock) and codex-acp (OpenAI) are gated natives — they cannot ride the DeepSeek proxy (anthropic-messages / openai-responses protocol walls), so they run only via affected-agent (a PR touching their own adapter), never in the default fan.
  • gemini and harvey-lab-harness dropped from the roster — neither can run on DeepSeek (native Google GenerateContent; OpenAI Responses API in harvey's _create_adapter, the same wall as codex). Roster 9 → 7; caps.max_agents 9 → 7.
  • Agent-judge runs on DeepSeek-v4 only — no other models. judge_model = deepseek-v4-flash; at runtime select_integration_provider.py exports BENCHFLOW_JUDGE_MODEL=openai/deepseek-v4-flash (OpenAI-compatible chat-completions at the DeepSeek endpoint).

fix(integration): guard empty post-filter matrix and catch DeepSeek base-url skips — 197cd5f

  • Empty-matrix green no-op guard (has_cells) on L2/L3: a fully credential-filtered matrix skips run-matrix + review-pack instead of failing fromJson([]) into a false not-mergeable. Closes review r3438339786.
  • Credential filter completeness: also recognizes the missing-DEEPSEEK_BASE_URL message ("requires … to build the provider base URL") as a documented skip — previously it slipped through and red-failed the DeepSeek baseline agent at the first LLM call.

Secrets (cross-checked against pypi-internal-preview + repo): DEEPSEEK_API_KEY/DEEPSEEK_BASE_URL, AWS_BEARER_TOKEN_BEDROCK/AWS_REGION, OPENAI_API_KEY, DAYTONA_API_KEY all present; GEMINI_API_KEY added (now non-load-bearing since the judge is DeepSeek and gemini/harvey are dropped — kept as a fallback only).

Verified: stdlib planner + filter + agent-judge test suites pass, ruff clean, all workflow/config YAML valid; an end-to-end expanded plan → credential-filter run emits exactly the 5 DeepSeek agents with 0 skips.

symphony-bot added 2 commits June 18, 2026 22:15
_matrix_agents returned from the all-agents / nine-expanded / all-agents-subset
branches BEFORE the affected-agent branch, so a PR that co-changed a gated
native's adapter (codex_config.py / claude*.py -> affected-agent) AND a broad-fan
trigger (registry.py infra, or a pyproject.toml expanded-scope file) silently
dropped that native from the matrix — and affected-agent is its ONLY path. Fix:
compute the lane's base roster, then always UNION res.affected_agents onto it, so
a co-changed native still gets its cell (incl. at nine/expanded). Surfaced by the
pre-merge audit; regression test added. Fail-safe before (under-coverage, never a
false-green), correct now.
The run-matrix provider-select step exports OPENAI_*=DeepSeek into the job env so
the DeepSeek agent-judge works. But the gated-native codex-acp rollout (gpt,
OpenAI Responses) KEEPS ambient OPENAI_* (it does not recompute them in
resolve_agent_env), so it would auth its rollout against DeepSeek and fail. Pin
the REAL OpenAI key+base for codex-acp cells ONLY (L2 + L3 run-matrix) via a
matrix.cell.agent guard; DeepSeek cells keep the job env unchanged (verified
no-op: openhands/pi-acp/openclaw ignore OPENAI_*, mimo/opencode recompute their
own provider creds), and the later judge step keeps the DeepSeek OPENAI_*.
@Yiminnn

Yiminnn commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Pre-merge verification — 17-agent audit (per-fix × {thermo-nuclear, correctness, test, adversarial} + merge-readiness)

Ran a multi-agent pre-merge audit over the four recent fixes; one agent per fix applied the thermo-nuclear code-quality-review skill. Verdicts:

Fix thermo-nuclear correctness test/e2e adversarial
Empty-matrix has_cells guard ✅ pass ✅ pass ✅ pass ✅ pass
Credential-filter base-URL skips ✅ pass ✅ pass ✅ pass ✅ pass
DeepSeek-first roster + gated natives ✅ pass ⚠️ concerns ✅ pass ⚠️ concerns
DeepSeek-v4-only judge ✅ pass ✅ pass ✅ pass ✅ pass

The audit found two real (fail-safe, under-coverage) bugs in the gated-native path — both consequences of the new gating — now fixed (8154145..ad8f8d6):

  • fix: union co-changed gated natives into the broad fan — _matrix_agents returned from the broad-fan branches before affected-agent, so a PR co-changing a native's adapter (codex_config.py/claude*.py) and a broad trigger (registry.py, or an expanded-scope file) silently dropped that native — its only path. Now the lane's base roster always unions the affected agents. Regression test added; verified e2e (registry.py + codex_config.py → includes codex-acp; pyproject.toml + claude*.py → includes claude-agent-acp).
  • fix: restore real OpenAI creds for codex-acp rollout cells — the run-matrix provider-select step exports OPENAI_*=DeepSeek for the DeepSeek judge; the codex-acp rollout keeps ambient OPENAI_* and would auth against DeepSeek and fail. Pinned the real OpenAI key/base for codex-acp cells only (L2+L3) via a matrix.cell.agent guard — proven no-op for every DeepSeek cell (openhands/pi-acp/openclaw ignore OPENAI_*; mimo/opencode recompute their own provider creds in resolve_agent_env).

Everything else passed, including the thermo-nuclear structural review (no file-size / spaghetti / abstraction regressions across all four fixes). Post-fix: 93 stdlib tests pass, ruff clean, both workflows valid YAML.

Merge-readiness: ✅ ready — no code/config blockers

Verified: all load-bearing secrets present on pypi-internal-preview (DEEPSEEK_API_KEY/BASE_URL, AWS_BEARER_TOKEN_BEDROCK/AWS_REGION, DAYTONA_API_KEY, + repo OPENAI_API_KEY); all integration workflows are plain pull_request/workflow_dispatch (never pull_request_target); every secret-touching job uses environment: pypi-internal-preview; all uses: SHA-pinned; the has_cells guard is wired on all four consumers; no on: paths filter on required-check workflows; no stale agents_9 reference anywhere.

Manual steps before/after merge (GitHub-UI, not code):

  • Branch protection — mark L0 test / L1 integration-light / L2 integration-scope as required (gh api …/branches/main/protection → 404, none set yet). L3 stays dispatch-only, not required.
  • Rotate GEMINI_API_KEY (pasted in chat; now non-load-bearing — judge is DeepSeek, gemini/harvey agents dropped — so hygiene only).

Confirmed documented-as-deferred (not silently broken): V-NETWORK-CONFORM runtime-egress lane (genuinely blocked — build_egress_override absent from src/), producer-side verifier_files_mutated hash, and network_mode result.json serialization — all tracked in ADR-0002/0003 + docs/integration-tiers.md for one coordinated additive schema bump.

Comment on lines +416 to +430
# SkillsBench leaderboard submissions (native BenchFlow result.json) from
# the HF dataset + revision recorded in scope_defaults.yml -> baseline.
# The band model covers every integration task; cheap deepseek runs band-
# compare advisory-only. Best-effort: a fetch miss leaves band parity NA
# rather than failing the gate (the deterministic floor + codex still run).
id: baseline
continue-on-error: true
run: |
set -euo pipefail
vals=$(uv run python -c "import yaml;d=yaml.safe_load(open('.github/integration/scope_defaults.yml'))['baseline'];print(d['hf_repo'],d['hf_revision'],d['submission_root'],d['config_no_skill'],d['band_model'])")
read -r HF_REPO HF_REV SUB_ROOT CONFIG BAND_MODEL <<< "$vals"
DIR="$SUB_ROOT/${CONFIG}__${BAND_MODEL}"
uvx --from huggingface_hub hf download "$HF_REPO" --repo-type dataset \
--revision "$HF_REV" --include "$DIR/**/result.json" \
--local-dir baseline-root

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.

P1 L3 Codex gate broken: DeepSeek credentials bleed into the codex subprocess

select_integration_provider.py (the "Select judge provider" step above) writes OPENAI_API_KEY=<deepseek key> and OPENAI_BASE_URL=<deepseek url> to $GITHUB_ENV. Those values override the job-level env: block for all subsequent steps. The codex review step does not have step-level overrides for either variable, so codex_review.py reads the DeepSeek key from os.environ["OPENAI_API_KEY"], writes it into auth.json, and then passes env=dict(env) (including OPENAI_BASE_URL=DeepSeek) to the codex exec subprocess. Codex routes to the DeepSeek endpoint with a DeepSeek key and requests a model (e.g. o4-mini) that DeepSeek does not serve, so the call fails. The codex_verdict is None path fires on every L3 dispatch, making the required gate permanently blocked.

The analogous fix is already in the run-matrix step for codex-acp cells; the same two-variable pattern needs to be applied here. The integration-scope.yml advisory codex step has the same OPENAI_BASE_URL gap (it restores OPENAI_API_KEY but not the base URL).

symphony-bot added 3 commits June 18, 2026 22:34
…ences

Drop the docs/adr/ folder (0001-0004) and remove every dangling reference so no
link 404s: the tiers-doc intro now states the key decisions inline (cells-not-
markers, fail-closed V-TAMPER, static V-NETWORK, DeepSeek-only broad fan) instead
of linking the ADRs; the ADR markdown link and the prose "(ADR-000X)" citations
in integration-tiers.md / integration-review-rubric.md and two test docstrings
are removed. No behavior change.
…stic

test_drops_deepseek_when_base_url_missing relied on DEEPSEEK_BASE_URL being
genuinely absent, but a populated CI test job supplies a fallback base for the
baseline openhands cell, so it was KEPT and the assertion failed (false red in
L0). Patch resolve_agent_env to raise the base-URL message directly, pinning the
filter's drop+missing_key routing regardless of ambient env. Whether a bare
DEEPSEEK_BASE_URL is truly absent is benchflow's concern, not the filter's; the
message-shape recognition is also unit-covered by test_extract_missing_key_shapes.
@Yiminnn
Yiminnn merged commit e1060f6 into main Jun 18, 2026
8 checks passed
@Yiminnn
Yiminnn deleted the integration-tiered-ci branch June 18, 2026 22:54
Yiminnn added a commit that referenced this pull request Jun 20, 2026
Cross-checked the unaddressed greptile comments on the earlier integration PRs
(#802-#810); most were already fixed or stale. Three genuine ones remained:

- P1 (build_integration_review_pack): an R-OUTCOME-only deterministic reject is
  demoted to a healthy+quarantine slot, but grade["deterministic_reject"] was
  left True and serialized into agent_judge_summary.json. codex reads that and a
  "healthy slot with a deterministic reject" can spuriously push it to downgrade
  mergeable -> not mergeable. Clear the flag on demotion. + regression test.
- codex_review deepseek-finding parser: replace the greedy `{.*}` DOTALL regex
  (which merges two JSON objects into one invalid blob) with raw_decode of the
  first complete object, tolerant of trailing prose.
- integration_matrix: `git diff` runs with check=True but CalledProcessError
  bypassed the ScopeError fail-closed handler (uncaught traceback). Re-raise it
  as ScopeError so a failed/absent head_sha fails closed cleanly.

Co-authored-by: symphony-bot <symphony@benchflow.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:diagnostics Issue / PR lives primarily in the "diagnostics" subsystem. area:eval Issue / PR lives primarily in the "eval" subsystem. enhancement New feature or request P1 Important debt — must fix soon, but does not block the current release. review:pending PR is ready-for-review, no reviewer engagement yet.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants