Skip to content

Develop - #6

Merged
ANUBprad merged 83 commits into
mainfrom
develop
Aug 26, 2026
Merged

Develop#6
ANUBprad merged 83 commits into
mainfrom
develop

Conversation

@ANUBprad

Copy link
Copy Markdown
Owner

No description provided.

- MetricResult contract codified: raw score in metric-native units,
  normalized_score always [0,1] higher-is-better, errors carry no
  meaningful score, version must match definition
- MetricDefinition gains ScoreDirection + default_threshold
- MetricResult.passed_against() threshold semantics (inclusive)
- All embedding-metric failure paths now set explicit error instead
  of silent zero scores marked as success
- token_usage/cost/latency: missing measurement metadata is an
  explicit error, no more fabricated perfect scores
- tool_call_correctness: absent tool_calls data is an explicit
  error instead of a vacuous 1.0 pass
- embedding metrics record embedding_model in execution metadata
- new test_score_contract.py enforces the contract across all 22
  registered metrics with deterministic fakes
…rovider

- new OpenAIEmbeddingAdapter mapping SDK embedding responses through
  the existing map_embedding_response mapper
- OpenAIProvider now implements the EmbeddingProvider contract and
  declares EMBEDDING / EMBEDDING_DIMENSIONS capabilities
- adapter honors EmbeddingOptions (dimensions, encoding_format)
- tests cover SDK response mapping, options passthrough, error
  propagation, capability declaration, and provider delegation
- ExecutionMetadata gains embedding_provider/embedding_model config
- MetricDispatchStage resolves the embedding provider through the
  ProviderRegistry (explicit name, or fallback to an embedding-
  capable chat provider); unregistered names degrade to per-metric
  errors instead of crashing dispatch
- Temporal activities inject the embedding-capable provider for
  embedding-backed metrics
- run metadata serialization now round-trips judge and embedding
  configuration (judge fields were previously dropped on reload)
- wiring tests prove registry resolution, fallback, degradation,
  and real metric execution over the injected boundary
- JudgeResponse gains explicit error field; provider failures and
  malformed judge output now surface as errors instead of silent
  zero scores with fabricated confidence
- strict structured-output validation: JSON object with numeric
  score/confidence required; regex score-extraction fallbacks
  removed entirely (they invented scores from prose)
- out-of-range values clamped and documented, raw output preserved
  for debugging on parse failures
- judge token usage cost-accounted through the default cost
  calculator (unknown pricing yields 0.0 without failing the call)
- llm_judge_base maps judge errors to explicit metric error results
  while keeping raw output, tokens, and rubric/prompt versions
- new judge hardening test suite; existing metric tests updated to
  return structured verdicts
- shared deterministic fakes: scripted embedding vectors and judge
  verdicts at the provider boundary
- embedding metrics proven against exact trigonometry (identical ->
  1.0, orthogonal -> 0.0, 45 degrees -> 1/sqrt(2)); previous tests
  were vacuous (both texts embedded to the same mock vector)
- all 9 judge metrics parametrized: verdict propagation with
  confidence/model/tokens metadata, malformed verdict -> explicit
  error, provider failure -> explicit error
- deterministic metrics pinned to exact formula outputs (token
  ratios, latency-at-threshold = 0.0, cost-at-cap = 0.0, length
  triangle profile)
- JudgeEngine now records the model actually used by the provider
  when no explicit judge model is configured
- judge results record executing provider name (configured name or
  the resolved provider's identity)
- embedding results record embedding_provider alongside
  embedding_model
- score-contract tests now enforce provenance metadata for all
  judge and embedding metrics
correct, incorrect, irrelevant, hallucinated, valid-structured,
invalid-structured, context-grounded, ungrounded — all synthetic,
version-controlled inputs with invariant tests
- run all 22 registered metrics over the eight canonical fixtures via
  ProviderInvocation -> MetricDispatch -> Aggregation -> Persistence,
  fakes only at the chat/embedding provider boundary
- fix measurement metrics rejecting string metadata produced by the
  real invocation stage (tokens/cost/latency now coerce numeric
  strings, still error on garbage)
- fix judge model provenance collapsing to 'None' when judge config
  carries no explicit model
- schema_validation accepts JSON-string schemas from pipeline metadata
- MetricEngine stamps run_id/item_id onto results for attribution
'relevance' computed the identical prompt-response cosine similarity as
'answer_relevance' under a second public name, doubling reporting
surface with no semantic difference. Removed honestly rather than
renamed: use 'answer_relevance'.
Measured with a counting provider: evaluating the four embedding
metrics on one item previously issued 8 embed round-trips for 4 unique
texts. A per-MetricInput cache in EmbeddingMetric cuts this to 4
(50% fewer provider calls) and ~2x wall-clock improvement at realistic
latency, with scores bit-identical to the uncached path.
…er (B.4)

- Deterministic evaluation fingerprinting (SHA-256)
- Environment capture for reproducibility (git hash, requirements)
- Provider call accounting (target/judge/embedding breakdown)
- Cost/latency/token tracking with type-safe accounting
- Model comparison with metric-level deltas
- Golden evaluation suite with deterministic expectations
- Metric invariant tests (NaN, infinity, range, directionality)
- Benchmark runner with regression detection
- Replay trace serialization consistency tests
- Embedding call reuse regression protection
- 238 new tests, all passing
- Add domain contracts: AdaptiveCampaign aggregate, CampaignRound,
  TargetExecution, AttackEffectiveness, CampaignBudget, AttackLineage,
  CampaignResult, CampaignState enum, MutationPhase enum
- Add TargetExecutor: routes attack prompts to providers via
  ProviderRegistry → ChatProvider.chat()
- Add AttackEvaluator: combines MetricEngine + safety scoring for
  effectiveness evaluation
- Add MutationStrategySelector: adaptive strategy selection with
  exploration/exploitation/adaptive phases
- Add AdaptiveCampaignEngine: orchestrates the full campaign loop
  (Attack → Target Execution → Response → Effectiveness Evaluation →
  Mutation/Strategy Selection → Next Attack → Campaign Result)
- Add 48 deterministic integration tests covering all components
- All tests pass (1766 passed, 558 skipped), ruff clean, mypy clean
… metrics, evaluator, integration tests

B.6: Agent / Trajectory Evaluation — first working implementation.

New files:
- app/agents/domain/trajectory.py: AgentTrajectory, TrajectoryStep, ToolCallRecord, LLMCallRecord, TrajectoryMetrics, compute_trajectory_metrics
- app/agents/domain/tool_execution.py: ToolDefinition, ToolRegistry, SafeToolExecutor
- app/agents/runtime/trajectory_recorder.py: TrajectoryRecorder for building trajectories during execution
- app/agents/runtime/agent_loop.py: AgentLoop — LLM ↔ tool interaction loop with provider integration
- app/evaluation/metrics/trajectories/: TrajectoryCompletenessMetric, TrajectoryEfficiencyMetric, TrajectoryErrorRecoveryMetric, TrajectoryToolSelectionMetric
- app/evaluation/metrics/trajectories/evaluator.py: TrajectoryEvaluator orchestrating trajectory evaluation via MetricEngine
- tests/agents/trajectory/test_trajectory_evaluation.py: 38 deterministic integration tests proving the full path

Proven path: AGENT TASK → AGENT EXECUTION → MODEL ACTION → TOOL CALL → TOOL RESULT → NEXT ACTION → FINAL RESPONSE → COMPLETE TRAJECTORY → TRAJECTORY METRICS → PERSISTED EVALUATION RESULT

Test results: 1804 passed, 558 skipped (async), 0 failures. Ruff clean, mypy clean.
- Replaced stubbed _invoke_step with execute_run_sync using AgentLoop
- Added execute_sync wrapper to AgentLoop for synchronous callers
- Updated AgentRuntimeCoordinator to delegate to AgentLoop in one call
- Updated tests to match new AgentExecutor signature

B.7 Audit Fix: Path C now has real LLM execution instead of hardcoded stubs
- Added execute_agent_loop_activity that runs the full LLM ↔ tool loop
- Added configure_agent_provider_registry for worker startup
- Replaced step-by-step lifecycle loop with single activity call
- Added ExecuteAgentLoopInput/Result dataclasses

B.7 Audit Fix: Path C Temporal workflow now executes real AI, not just lifecycle updates
…zation

- conversation_history is tuple[dict], not str — serialize to role:content format
- Fixed default value from [-1] to empty tuple
- MetricInput.response now receives proper string representation

B.7 Audit Fix: trajectory evaluator no longer passes raw list as response string
- Removed app/providers/contracts/audio.py (no implementations)
- Removed app/providers/contracts/vision.py (no implementations)
- Updated contracts __init__.py to remove stale exports

B.7 Audit: dead code cleanup, no production references
- Resource was created after first provider was already set
- Now create provider with resource from the start
- Single trace.set_tracer_provider call instead of two

B.7 Audit Fix: OpenTelemetry no longer silently overwrites its own provider
- Added PrometheusMiddleware that records REQUEST_COUNT and REQUEST_LATENCY
- Metrics were registered but never incremented — now they produce data
- /metrics endpoint continues to work as before

B.7 Audit Fix: Prometheus metrics are now reachable and operational
- agent_trajectory.py: removed index=True from run_id (duplicate of explicit Index)
- attack_run.py: removed index=True from status (duplicate of explicit Index)
Deleted:
- tests/providers/runtime/test_cache.py
- tests/providers/runtime/test_context.py
- tests/providers/runtime/test_health.py
- tests/providers/selection/ (entire directory)

Test regression: 1772 passed, 524 skipped, 0 failures
(135 tests removed - all tested dead code)
- Add GET /replay/regression/{baseline_run_id}/{current_run_id} endpoint
- Add MetricRegressionResponse and RegressionResultResponse schemas
- Add replay/comparison/regression API methods to frontend client
- Add TypeScript types for replay, comparison, and regression data
- Add verdict column to run list with color-coded badges
- Show verdict prominently in run details header
- Connect cancel button with real API call
- Connect retry button with real API call
- Add compare button for completed runs
- Create ReplayViewer component showing item execution traces
- Display prompt, provider response, metric scores per item
- Show timing, cost, and error information
- Integrate into run details page for completed runs
- Create /runs/compare page for side-by-side run comparison
- Display provider, model, winner, and confidence
- Show per-metric deltas with baseline vs comparison scores
- Support URL params for pre-filling run IDs
- Create RegressionResultView component for regression analysis
- Show verdict, regression count, error count, fingerprint compatibility
- Display per-metric analysis with status, scores, and reasoning
- Integrate into comparison page
- Remove hardcoded mock safety scores and attack scenarios
- Wire cancel button to real api.cancelAttackRun() with invalidation
- Add clickable links to attack definition IDs
- Add evaluation run link when present
- Add back-to-runs navigation
- Add status color for failed state
- Remove unused useCallback and Play imports from run details
- Remove unused Button import from comparison page
- Type compareRuns query with TraceComparison return type
- Fix compute_fingerprint call in api/replay.py to use keyword args
- Fix analyze_regression call to pass .fingerprint strings not objects
- Fix redis_repository.py type stubs for sadd/srem/smembers
- Fix attack_evaluator.py dict type parameter
- Fix agents/router.py total_steps -> max_steps
- Fix cli/__init__.py: rewrite _run_compare to use async session factory,
  fix metrics dict type annotation, compute fingerprint from config
…ory files

- Fix import sorting in test_campaign_engine.py
- Remove unused imports in test_kernel.py, test_campaign_engine.py
- Fix loop variable and .items() usage in test_campaign_engine.py
- Reformat trajectory_tool_selection.py, test_trajectory_evaluation.py
- Format dashboard page, redteam run details, compare page
- Format replay viewer, regression result components
- Format API TypeScript types
- Format agent workflow, trajectory recorder, trajectory domain
- Format trajectory evaluator and metric implementations
- Format migration and results files
Register finalize_run_integrity_activity and execute_agent_loop_activity
in the ActivityRegistry. These activities were defined and called by their
respective workflows but never registered, causing runtime failures when
the worker tried to execute them.
…or Temporal activities

The agent Temporal activities (execute_agent_loop_activity and lifecycle
activities) require a configured session factory and provider registry.
These were never wired during bootstrap, causing RuntimeError at
runtime when the worker tried to execute agent workflows.
…ties

Add bounded retry policies (max 3 attempts) to all Temporal activities
with exponential backoff. Activities are categorized by failure mode:

- Lifecycle activities (queue/start/complete/fail/cancel): idempotent
  state transitions, retry for transient DB errors.
- Item execution: retry for transient provider failures (rate limits,
  network), activity has internal idempotency checks.
- Agent loop: bounded to 2 attempts (long-running), retry only for
  transient infrastructure errors.
- Persistence/integrity: retry for transient DB and I/O errors.

Non-retryable error types (ValueError, KeyError) prevent infinite
retries on invalid input.
…liability

16 tests covering:
- P0-1: finalize_run_integrity_activity registration in ActivityRegistry
- P0-2: execute_agent_loop_activity registration in ActivityRegistry
- P1-1: Agent session factory and provider registry configuration
- P1-2: Explicit retry policies in evaluation and agent workflows
- Container registration verification (all 18 activities registered)
P0-3: The shared API client request() function never read the access
token from localStorage. All authenticated API calls were sent without
Authorization headers, causing 401 responses from the backend.

- Read token from localStorage key 'redops-access-token'
- Add 'Authorization: Bearer <token>' header when token exists
- Omit header when token is absent (preserves public endpoint behavior)

P0-4: SSE stream URLs stripped /api/v1 from BASE_URL via .replace(),
producing URLs like /runs/{id}/events/stream instead of
/api/v1/runs/{id}/events/stream. The backend mounts all routes under
/api/v1, so SSE connections hit 404.

- Use BASE_URL directly for SSE URLs (includes /api/v1)
- Replace native EventSource with fetch-based AuthenticatedEventSource
  to support Authorization headers (native EventSource cannot set
  custom headers)
- AuthenticatedEventSource implements EventSource interface (onmessage,
  onerror, close) for drop-in compatibility with existing consumers
11 tests covering:
- Authorization Bearer header sent when token exists in localStorage
- Authorization header omitted when token is absent
- No fabricated Authorization header for missing token
- SSE streamEvents URL contains /api/v1 prefix
- SSE streamProgress URL contains /api/v1 prefix
- SSE connection includes Authorization header via fetch-based reader
- SSE connection omits Authorization when token missing
Resolve merge conflicts from origin/main revert (cee7dfd) while
preserving all B.1-B.12.2 develop work.

Conflicts resolved by keeping develop versions:
- backend/app/agents/api/router.py (config-based task_queue)
- backend/app/api/evaluation_run.py (config-based task_queue)
- backend/app/infrastructure/composition/container.py (full activity registry)
- backend/app/infrastructure/observability/prometheus.py (middleware imports)
- backend/tests/integration/test_temporal_queue_alignment.py (existing tests)

Restored from develop (deleted by main revert):
- opencode.md
- backend/tests/integration/test_provider_registration.py
- backend/tests/integration/test_provider_resolution.py

Reverted harmful auto-merged changes:
- backend/app/core/config.py (keep provider credential fields)
- backend/app/infrastructure/composition/bootstrap.py (keep DatabaseEngine init)
- backend/app/main.py (keep app = create_app() instance)
- docker/docker-compose.yml (keep newer temporal-admin-tools tag)

Accepted beneficial changes from main:
- README.md and Dockerfile: uvicorn --factory pattern
- Alembic migrations: added status index, normalized revision IDs
- frontend/.gitignore: removed duplicate entries
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 981055cd-d19b-484b-96d7-9751b55e08a9


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Remove 4 unused type: ignore suppressions:
- redis_repository.py: sadd, srem, smembers (3x [misc])
- api/replay.py: aioredis.from_url (1x [no-untyped-call])

CI reports these as [unused-ignore] because current redis-py stubs
properly type these async methods.
…mpare

Extract search-params-consuming logic into CompareContent component
and wrap it with React.Suspense in ComparePage. This satisfies
Next.js App Router requirement that useSearchParams() must be
inside a Suspense boundary.

Preserves existing behavior: URL query parameters
?baseline=<id>&comparison=<id> continue to work.
…now() in evaluation workflow

Temporal workflow sandbox rejects datetime.now() because workflow
execution must be deterministic. Replace both started_at and
completed_at timestamps with workflow.now() which provides the
deterministic workflow time API.

Also register finalize_run_integrity_activity in the integration
test worker so the full workflow chain executes correctly.
CI has no .env file so APP_SECRET_KEY defaults to empty string,
causing PyJWT to reject HMAC signing in test_create_access_token.
Add a session-scoped autouse fixture that sets a test-only key
and clears the cached AppConfig before any test runs.
@ANUBprad
ANUBprad merged commit 472433e into main Aug 26, 2026
5 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.2.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant