Skip to content

Commit 49c27db

Browse files
chore: sync workflow templates
Automated merge of sync PR Sync hash: 17c429d63604
2 parents b8158be + c92a3ec commit 49c27db

2 files changed

Lines changed: 63 additions & 9 deletions

File tree

scripts/langchain/pr_verifier.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -842,12 +842,9 @@ def evaluate_pr_multiple(
842842
) -> list[EvaluationResult]:
843843
change_type = _classify_change_type(_bounded_diff_for_classification(diff))
844844
runner = ComparisonRunner.from_environment(context, diff, model1, model2)
845-
families = {_provider_family(provider) for _, provider, _ in runner.clients}
846-
if len(runner.clients) < 2 or len(families) < 2:
847-
result = _fallback_evaluation(
848-
"unverified: compare mode requires two cross-family verifier judges; "
849-
f"available families: {', '.join(sorted(families)) or 'none'}."
850-
)
845+
is_valid, error_message = _validate_comparison_clients(runner.clients)
846+
if not is_valid:
847+
result = _fallback_evaluation(error_message)
851848
result.change_type = change_type
852849
return [result]
853850
results: list[EvaluationResult] = []
@@ -869,6 +866,47 @@ def _provider_family(provider: str) -> str:
869866
return label.split("/", 1)[0].strip() or "unknown"
870867

871868

869+
def _get_provider_families(clients: list[tuple[object, str, str]]) -> set[str]:
870+
"""Extract the set of unique provider families from a list of clients.
871+
872+
Args:
873+
clients: List of (client, provider, model) tuples.
874+
875+
Returns:
876+
Set of provider family names (e.g., {"openai", "anthropic"}).
877+
"""
878+
return {_provider_family(provider) for _, provider, _ in clients}
879+
880+
881+
def _validate_comparison_clients(clients: list[tuple[object, str, str]]) -> tuple[bool, str]:
882+
"""Validate that client list is sufficient for cross-family comparison.
883+
884+
Args:
885+
clients: List of (client, provider, model) tuples.
886+
887+
Returns:
888+
Tuple of (is_valid, error_message).
889+
is_valid is True if there are >= 2 clients from >= 2 different provider families.
890+
error_message describes the reason if validation fails.
891+
"""
892+
families = _get_provider_families(clients)
893+
if len(clients) < 2:
894+
family_str = ", ".join(sorted(families)) or "none"
895+
return (
896+
False,
897+
f"unverified: compare mode requires two cross-family verifier judges; "
898+
f"available families: {family_str}.",
899+
)
900+
if len(families) < 2:
901+
family_str = ", ".join(sorted(families)) or "none"
902+
return (
903+
False,
904+
f"unverified: compare mode requires two cross-family verifier judges; "
905+
f"available families: {family_str}.",
906+
)
907+
return True, ""
908+
909+
872910
def _normalize_text(text: str) -> str:
873911
cleaned = re.sub(r"\s+", " ", text.strip().lower())
874912
return cleaned

scripts/validate_run_contract.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,20 @@ def validate_envelope(
261261
return report
262262

263263

264+
def _find_participant(registry: dict[str, Any], repo: str) -> dict[str, Any] | None:
265+
"""Look up a participant by repo in the registry. Returns None if not found."""
266+
return _find_entry(registry, repo)
267+
268+
269+
def _is_missing_envelope_a_failure(entry: dict[str, Any] | None) -> bool:
270+
"""Decide whether a missing envelope should fail (True) or skip (False).
271+
272+
An emitting or conformant participant MUST have an envelope; all others
273+
(absent, candidate, none, planned) are opt-in skip.
274+
"""
275+
return entry is not None and entry.get("status") in EMITTING_STATUSES
276+
277+
264278
def missing_envelope_report(registry: dict[str, Any], repo: str, run_json: Path) -> Report:
265279
"""Decide what a MISSING run envelope means for ``repo``.
266280
@@ -274,10 +288,10 @@ def missing_envelope_report(registry: dict[str, Any], repo: str, run_json: Path)
274288
is never failed just for lacking an envelope) without silencing a real
275289
regression in an active participant.
276290
"""
277-
entry = _find_entry(registry, repo)
291+
entry = _find_participant(registry, repo)
278292
report = Report(repo=repo, role=entry.get("role", "") if entry else "")
279-
is_active_participant = entry is not None and entry.get("status") in EMITTING_STATUSES
280-
if is_active_participant:
293+
294+
if _is_missing_envelope_a_failure(entry):
281295
assert entry is not None
282296
report.fail(
283297
f"{repo} is an active backplane participant "
@@ -406,9 +420,11 @@ def _self_smoke(schema_dir: Path, registry_path: Path) -> int:
406420
True,
407421
)
408422
)
423+
# Unsafe raw payload fixtures must fail without echoing sensitive values.
409424
for inv in (
410425
"missing_cost.json",
411426
"unsafe_rows_inline.json",
427+
"unsafe_prompt_inline.json",
412428
"artifact_not_in_manifest.json",
413429
"bad_identity_ref.json",
414430
):

0 commit comments

Comments
 (0)