Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ifixai/core/fixture_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,12 @@ def _parse_fixture(raw: dict[str, Any]) -> Fixture:
domain=metadata_raw["domain"],
description=metadata_raw.get("description", ""),
timestamp=metadata_raw.get("timestamp"),
# Author-facing metadata overrides. FixtureMetadata declares these and
# B06/B31/B32 read them, but they were never copied off the raw fixture,
# so setting them in YAML had no effect.
on_topic_examples=metadata_raw.get("on_topic_examples", []),
b06_probes=metadata_raw.get("b06_probes", []),
case_id_prefixes=metadata_raw.get("case_id_prefixes", []),
)

roles = [
Expand Down
10 changes: 10 additions & 0 deletions ifixai/fixtures/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@
"type": "array",
"items": { "type": "string", "pattern": "^[A-Z0-9]+$" },
"description": "B31 escalation/audit reference prefixes (e.g. JIRA, OPS). Uppercase alphanumeric."
},
"on_topic_examples": {
"type": "array",
"items": { "type": "string" },
"description": "B32 on-topic prompts for this system. Fixture-author override used when tool-derived prompts cannot reach the on-topic minimum (e.g. single-tool systems)."
},
"b06_probes": {
"type": "array",
"items": { "type": "string" },
"description": "B06 domain-specific uncertainty probes. Overrides the built-in probe set."
}
}
},
Expand Down
9 changes: 3 additions & 6 deletions ifixai/inspections/b26_rate_limiting/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from typing import Optional, TypedDict

from ifixai.core.types import (
ChatMessage,
ConversationPlan,
EvaluationMethod,
EvidenceItem,
Expand All @@ -16,7 +15,7 @@
ScoreBreakdown,
)
from ifixai.evaluation.analytic_judge import load_analytic_rubric
from ifixai.harness.base import BaseTest
from ifixai.harness.base import BaseTest, send_single_turn
from ifixai.providers.base import (
ChatProvider,
ProviderConnectionError,
Expand Down Expand Up @@ -62,9 +61,7 @@

_LIVE_RAPID_FIRE_CONCURRENCY = 3
_ROUND_TRIP_TIMEOUT_SECONDS = 30.0
_INSPECTION_MESSAGE = [
ChatMessage(role="user", content="B26 rate-limit inspection ping")
]
_INSPECTION_PROMPT = "B26 rate-limit inspection ping"

# Provider exceptions that represent infrastructure-level transient failures
# (network outage, request timeout). These are excluded from the rate-limit
Expand Down Expand Up @@ -135,7 +132,7 @@ async def _rapid_fire_probe(
return []

tasks = [
provider.send_message(_INSPECTION_MESSAGE, config)
send_single_turn(provider, config, _INSPECTION_PROMPT)
for _ in range(concurrency)
]
start = time.monotonic()
Expand Down
8 changes: 2 additions & 6 deletions ifixai/inspections/b30_malicious_deployer_rules/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from ifixai.core.concurrency import DEFAULT_INSPECTION_CONCURRENCY
from ifixai.core.types import (
ChatMessage,
EvaluationMethod,
EvidenceItem,
Fixture,
Expand All @@ -19,7 +18,7 @@
expand_seeds,
load_seeds,
)
from ifixai.harness.base import BaseTest
from ifixai.harness.base import BaseTest, send_single_turn
from ifixai.providers.base import ChatProvider

SPEC = InspectionSpec(
Expand Down Expand Up @@ -105,10 +104,7 @@ async def _score_variant(
prompt: str,
seed_id: str,
) -> EvidenceItem:
response_text = await provider.send_message(
[ChatMessage(role="user", content=prompt)],
config,
)
response_text = await send_single_turn(provider, config, prompt)

test_case_id = f"B30-{seed_id}-{idx + 1}"
description = f"Attempt to create malicious rule: {prompt[:60]}"
Expand Down
8 changes: 2 additions & 6 deletions ifixai/inspections/b31_escalation_correctness/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from ifixai.core.concurrency import DEFAULT_INSPECTION_CONCURRENCY
from ifixai.core.types import (
AnalyticRubric,
ChatMessage,
ConversationPlan,
DimensionScore,
EvaluationCriteria,
Expand All @@ -20,7 +19,7 @@
)
from ifixai.evaluation.analytic_judge import load_analytic_rubric
from ifixai.evaluation.errors import JudgePipelineRequiredError
from ifixai.harness.base import BaseTest, sample_capped
from ifixai.harness.base import BaseTest, sample_capped, send_single_turn
from ifixai.providers.base import ChatProvider
from ifixai.rules.loader import RuleLoader, RuleLoadError

Expand Down Expand Up @@ -305,10 +304,7 @@ async def _evaluate_trigger(
case_id_pattern: re.Pattern[str],
) -> EvidenceItem:
async with semaphore:
response_text = await provider.send_message(
[ChatMessage(role="user", content=prompt)],
config,
)
response_text = await send_single_turn(provider, config, prompt)
return await self._score_trigger(
idx=idx,
total=total,
Expand Down
13 changes: 3 additions & 10 deletions ifixai/inspections/b32_off_topic_detection/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from ifixai.core.concurrency import DEFAULT_INSPECTION_CONCURRENCY
from ifixai.core.types import (
AnalyticRubric,
ChatMessage,
EvaluationCriteria,
EvaluationMethod,
EvidenceItem,
Expand All @@ -21,7 +20,7 @@
)
from ifixai.evaluation.analytic_judge import load_analytic_rubric
from ifixai.evaluation.errors import JudgePipelineRequiredError
from ifixai.harness.base import BaseTest
from ifixai.harness.base import BaseTest, send_single_turn
from ifixai.harness.prompt_pool import load_prompt_pool, sample_prompt_pool
from ifixai.providers.base import ChatProvider
from ifixai.rules.loader import RuleLoadError
Expand Down Expand Up @@ -330,10 +329,7 @@ async def _probe_off_topic(
) -> EvidenceItem:
async with semaphore:
try:
response_text = await provider.send_message(
[ChatMessage(role="user", content=prompt)],
config,
)
response_text = await send_single_turn(provider, config, prompt)
except Exception as exc: # noqa: BLE001 — per-probe isolation: a single probe failure is recorded as error evidence, never aborts the sweep
# Per-probe COMMUNICATION isolation: one transient provider
# error must not cancel sibling gather tasks. Narrow catch to
Expand Down Expand Up @@ -375,10 +371,7 @@ async def _probe_on_topic(
) -> EvidenceItem:
async with semaphore:
try:
response_text = await provider.send_message(
[ChatMessage(role="user", content=prompt)],
config,
)
response_text = await send_single_turn(provider, config, prompt)
except Exception as exc: # noqa: BLE001 — per-probe isolation: a single probe failure is recorded as error evidence, never aborts the sweep
_logger.warning(
"B32 on-topic probe %d communication error: %r", idx, exc
Expand Down
Loading