# Implementation Plan: Eval: Trajectory & Matching

**Branch**: `023-eval-trajectory-matching` | **Date**: 2026-03-23 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/023-eval-trajectory-matching/spec.md`

## Summary

Implement the `swink-agent-eval` crate's trajectory collection, golden-path comparison, efficiency scoring, and response matching subsystems. The crate already exists with all source files in place. This plan covers verification, gap analysis, and test coverage hardening against the spec's acceptance scenarios, edge cases, and functional requirements.

## Technical Context

**Language/Version**: Rust 1.88 (edition 2024)
**Primary Dependencies**: `swink-agent` (core types: `AgentEvent`, `ContentBlock`, `AssistantMessage`, `Cost`, `Usage`, `ModelSpec`, `StopReason`), `serde`/`serde_json` (serialization), `tokio`/`tokio-util` (async runtime, `CancellationToken`), `futures` (stream combinators), `regex` (response pattern matching), `sha2` (audit hashes), `thiserror` (error types), `tracing` (diagnostics), `uuid` (IDs)
**Storage**: N/A (in-memory types; `FsEvalStore` for optional JSON persistence — covered by spec 024)
**Testing**: `cargo test -p swink-agent-eval` + integration tests in `eval/tests/`
**Target Platform**: Any platform supporting `tokio` (Linux, macOS, Windows)
**Project Type**: Library crate (`swink-agent-eval`)
**Performance Goals**: Linear-time trajectory collection and matching. No artificial limits on trajectory size.
**Constraints**: `#[forbid(unsafe_code)]`, clippy pedantic/nursery clean, no provider-specific dependencies.
**Scale/Scope**: Handles trajectories up to thousands of invocations per run. Single eval set can contain hundreds of cases.

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

| Principle | Status | Notes |
|---|---|---|
| I. Library-First | PASS | `swink-agent-eval` is an independent crate. Depends only on `swink-agent` core types. No reverse dependencies. |
| II. Test-Driven Development | PASS | Existing unit tests in each module. Integration tests in `eval/tests/`. Plan adds spec-driven acceptance tests. |
| III. Efficiency & Performance | PASS | Linear-time algorithms. No unnecessary allocations. `HashSet` for dedup in efficiency scoring. |
| IV. Leverage the Ecosystem | PASS | Uses `regex`, `sha2`, `serde_yaml` (optional). No hand-rolled alternatives. |
| V. Provider Agnosticism | PASS | Consumes `AgentEvent` stream — no provider-specific types. |
| VI. Safety & Correctness | PASS | `#[forbid(unsafe_code)]`, clippy pedantic/nursery enforced. Custom fn panics handled via `catch_unwind` (in response matcher — see gap below). |
| Crate count | PASS | `eval` is one of the seven permitted workspace members. |
| MSRV | PASS | 1.88, edition 2024. |

**Gate result: ALL PASS** — no violations.

## Project Structure

### Documentation (this feature)

```text
specs/023-eval-trajectory-matching/
├── spec.md              # Feature specification (clarified 2026-03-23)
├── plan.md              # This file
├── research.md          # Phase 0: gap analysis
├── data-model.md        # Phase 1: entity relationships
├── quickstart.md        # Phase 1: usage guide
├── contracts/           # Phase 1: public API contracts
└── tasks.md             # Phase 2 output (generated by /speckit.tasks)
```

### Source Code (repository root)

```text
eval/
├── Cargo.toml
├── src/
│   ├── lib.rs            # Public API re-exports
│   ├── types.rs          # RecordedToolCall, TurnRecord, Invocation, EvalCase, EvalSet, results
│   ├── trajectory.rs     # TrajectoryCollector, BudgetGuard
│   ├── match_.rs         # TrajectoryMatcher, MatchMode (Exact/InOrder/AnyOrder)
│   ├── efficiency.rs     # EfficiencyEvaluator
│   ├── response.rs       # ResponseMatcher, ResponseCriteria
│   ├── evaluator.rs      # Evaluator trait, EvaluatorRegistry
│   ├── score.rs          # Score, Verdict
│   ├── error.rs          # EvalError
│   ├── budget.rs         # BudgetEvaluator (spec 024, but tested here)
│   ├── runner.rs         # EvalRunner, AgentFactory (spec 024)
│   ├── store.rs          # EvalStore, FsEvalStore (spec 024)
│   ├── audit.rs          # AuditedInvocation (spec 024)
│   ├── gate.rs           # GateConfig, GateResult (spec 024)
│   └── yaml.rs           # YAML loading (feature-gated, spec 024)
└── tests/
    ├── common/mod.rs     # Shared test helpers
    ├── match_.rs         # Trajectory matching integration tests
    ├── efficiency.rs     # Efficiency scoring integration tests
    ├── response.rs       # Response matching integration tests
    ├── score.rs          # Score/Verdict integration tests
    ├── budget.rs         # Budget evaluation integration tests
    ├── store.rs          # FsEvalStore integration tests
    ├── gate.rs           # Gate integration tests
    ├── audit.rs          # Audit integration tests
    └── yaml.rs           # YAML loading integration tests
```

**Structure Decision**: Single crate within the existing workspace. All 023-scoped code lives in `eval/src/` files: `trajectory.rs`, `match_.rs`, `efficiency.rs`, `response.rs`, `types.rs`, `score.rs`, `evaluator.rs`. Tests in `eval/tests/` and inline `#[cfg(test)]` modules.

## Complexity Tracking

No violations to justify.
