agent-evaluate-v2-contract 0.1.0

Vendored Evaluate v2 transport contract for agent-infra-sdk
Documentation
//! HTTP contract for the Agent Evaluate domain application.
//!
//! Evaluate owns exactly one immutable registration unit — the **Snapshot** —
//! which carries its cases, each case's evaluators and the execution spec.
//! Everything else it stores is a reference (trace, sandbox, model) or a
//! judgement (metric, verdict, report).
//!
//! # Layering
//!
//! ```text
//! agent-evaluate-contract   paths + DTOs        (this crate)
//! agent-evaluate-domain     pure domain logic
//! agent-evaluate-adapter-*  SQL / Infra SDK
//! agent-evaluate-server     router + auth + bin
//! ```

pub mod admin;
pub mod analysis;
pub mod binding;
pub mod catalog;
pub mod driver;
pub mod evaluator;
pub mod execution;
pub mod report;
pub mod run;

pub use admin::*;
pub use analysis::*;
pub use binding::*;
pub use catalog::*;
pub use driver::*;
pub use evaluator::*;
pub use execution::*;
pub use report::*;
pub use run::*;

use serde::{Deserialize, Serialize};

pub const SERVICE_NAME: &str = "agent-evaluate";
pub const DEFAULT_PORT: u16 = 5150;
pub const AUDIENCE: &str = "agent-evaluate";

/// Identifier length cap shared by every product identifier. Matches the
/// indexable prefix of a `VARCHAR(191)` column under `utf8mb4`.
pub const MAX_RESOURCE_ID_CHARS: usize = 191;

// ── Limits ────────────────────────────────────────────────────────────
// Every bound is enforced by the domain layer, never by the storage engine
// discovering it the hard way.

pub const MAX_CASES_PER_SNAPSHOT: usize = 2_000;
pub const MAX_EVALUATORS_PER_CASE: usize = 16;
pub const MAX_TURNS_PER_CASE: usize = 64;
pub const MAX_FIXTURES_PER_CASE: usize = 64;
pub const MAX_FIXTURE_BYTES: usize = 256 * 1024;
pub const MAX_INCLUDES_PER_SNAPSHOT: usize = 32;
pub const MAX_SNAPSHOTS_PER_BINDING: usize = 32;
pub const MAX_JUDGES_PER_EVALUATOR: usize = 5;
pub const MAX_PAGE_SIZE: usize = 200;
pub const DEFAULT_PAGE_SIZE: usize = 50;

/// Ephemeral snapshot policy (design §15.1). Temporary assets must never
/// enter a long-lived dependency graph, so they are also barred from
/// bindings and includes.
pub const DEFAULT_EPHEMERAL_TTL_MS: i64 = 24 * 60 * 60 * 1_000;
pub const MAX_EPHEMERAL_TTL_MS: i64 = 7 * 24 * 60 * 60 * 1_000;
pub const MAX_EPHEMERAL_SNAPSHOTS_PER_PROJECT: usize = 50;
pub const MAX_EPHEMERAL_CASES_PER_PROJECT: usize = 5_000;

// ── Paths ─────────────────────────────────────────────────────────────

pub const HEALTH_PATH: &str = "/health";
pub const READY_PATH: &str = "/readyz";

pub const SNAPSHOTS_PATH: &str = "/internal/v1/evaluate/snapshots";
pub const SNAPSHOTS_LIST_PATH: &str = "/internal/v1/evaluate/snapshots/list";
pub const SNAPSHOTS_GET_PATH: &str = "/internal/v1/evaluate/snapshots/get";

pub const BINDINGS_PATH: &str = "/internal/v1/evaluate/bindings";
pub const BINDINGS_LIST_PATH: &str = "/internal/v1/evaluate/bindings/list";
pub const BINDINGS_GET_PATH: &str = "/internal/v1/evaluate/bindings/get";
pub const BINDINGS_DELETE_PATH: &str = "/internal/v1/evaluate/bindings/delete";

pub const RUNS_PATH: &str = "/internal/v1/evaluate/runs";
pub const OPERATIONS_PATH: &str = "/internal/v1/evaluate/operations";
pub const RUN_CASES_PATH: &str = "/internal/v1/evaluate/runs/cases";
pub const CANCEL_RUN_PATH: &str = "/internal/v1/evaluate/runs/cancel";

pub const DRIVER_CLAIM_PATH: &str = "/internal/v1/evaluate/driver/cases/claim";
pub const DRIVER_RENEW_PATH: &str = "/internal/v1/evaluate/driver/cases/renew";
pub const DRIVER_SUBMIT_PATH: &str = "/internal/v1/evaluate/driver/cases/submit";

pub const ANALYSIS_CLAIM_PATH: &str = "/internal/v1/evaluate/analysis/tasks/claim";
pub const ANALYSIS_SUBMIT_PATH: &str = "/internal/v1/evaluate/analysis/tasks/submit";
pub const ANALYSIS_RERUN_PATH: &str = "/internal/v1/evaluate/analysis/rerun";

pub const REPORT_GET_PATH: &str = "/internal/v1/evaluate/reports/get";
pub const REPORT_COMPARE_PATH: &str = "/internal/v1/evaluate/reports/compare";

pub const METRIC_HEALTH_PATH: &str = "/internal/v1/evaluate/metrics/health";
pub const METRIC_CANDIDATES_PATH: &str = "/internal/v1/evaluate/metrics/candidates";

pub const REVIEWS_PATH: &str = "/internal/v1/evaluate/reviews";
pub const REVIEWS_CLAIM_PATH: &str = "/internal/v1/evaluate/reviews/claim";
pub const REVIEWS_COMPLETE_PATH: &str = "/internal/v1/evaluate/reviews/complete";

pub const ADMIN_SNAPSHOTS_PATH: &str = "/internal/v1/evaluate/admin/snapshots";
pub const ADMIN_SNAPSHOTS_LIST_PATH: &str = "/internal/v1/evaluate/admin/snapshots/list";
pub const ADMIN_SNAPSHOTS_GET_PATH: &str = "/internal/v1/evaluate/admin/snapshots/get";
pub const ADMIN_SNAPSHOTS_PUBLISH_PATH: &str = "/internal/v1/evaluate/admin/snapshots/publish";
pub const ADMIN_SNAPSHOTS_DEPRECATE_PATH: &str = "/internal/v1/evaluate/admin/snapshots/deprecate";
pub const ADMIN_SNAPSHOTS_EXPORT_PATH: &str = "/internal/v1/evaluate/admin/snapshots/export";
pub const ADMIN_SNAPSHOTS_IMPORT_PATH: &str = "/internal/v1/evaluate/admin/snapshots/import";
pub const ADMIN_JUDGE_ALLOWLIST_PATH: &str = "/internal/v1/evaluate/admin/judge-allowlist";
pub const ADMIN_OVERVIEW_PATH: &str = "/internal/v1/evaluate/admin/overview";
pub const ADMIN_RUNS_PATH: &str = "/internal/v1/evaluate/admin/runs";
pub const ADMIN_BINDINGS_PATH: &str = "/internal/v1/evaluate/admin/bindings";

/// Tenant/project scope derived from a verified identity. Callers never get
/// to assert their own scope in a request body.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct EvalScope {
    pub tenant_id: String,
    pub project_id: String,
}

impl EvalScope {
    pub fn new(tenant_id: impl Into<String>, project_id: impl Into<String>) -> Self {
        Self {
            tenant_id: tenant_id.into(),
            project_id: project_id.into(),
        }
    }
}

/// Error body shared by every non-2xx response.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiError {
    pub status: u16,
    pub code: String,
    pub message: String,
}