/** * The `/api/v1/testing/*` surface (crew-testing) — the wire behind the studio's Testing page: * RUN the governance evals (does the steering corpus actually catch the behaviors it claims * to?), IMPORT a named eval corpus for later runs, and TRIGGER a campaign recon * (`POST /testing/recon` — governed runs over the operator's brief, fanned per repo by the * multiscope wire; the evals routes stay STORE-scoped and take no repo/project fields). * * Thin by design, like `governance-steering.ts`: validation is zod (strict, unknown keys named — * the FINDING-031 doctrine); the evals themselves are the ENGINE's (`governanceEvals` pushes * every sample through the same decide path enforcement runs, over a read-only connection to * the steering store — the daemon computes no verdict of its own), and the report is the * engine's serde output passed through VERBATIM (snake_case field names — the pinned crew/studio * wire contract; the steering wave shipped a drift because each side guessed, so neither side * reshapes it). Corpus import writes through the engine's knowledge seam under the * `evals:` scope — the daemon never opens a store itself. * * Error posture mirrors the steering surface: a build whose engine addon predates the evals * bindings answers 501 (`GovernanceEvalsUnsupportedError` — "upgrade the engine"; wicked-core-ts * 0.7.5 carries them, 0.7.4 does not), never 400 ("fix your request") — and never a crash: this * daemon must serve both routes honestly against the released 0.7.4 addon. */ import type { FastifyInstance, FastifyRequest } from 'fastify'; import { z } from 'zod'; import { type CoreAdapter } from '../core/adapter.js'; import type { Actor, EvalRunPerTypeCount, GovernanceEvalReport, SteeringType } from '../core/types.js'; import type { AuditLog } from './audit.js'; import { type RunTimingIndex } from './run-timing-index.js'; import type { EvalRunStore } from './eval-store.js'; import type { GroupIndex } from './group-index.js'; import type { ProjectBus } from '../projects/events.js'; import type { MembershipIndex } from '../projects/membership-index.js'; /** How long `POST /testing/recon` waits on a fan's engine launch before it acks 202 (crew#471). */ export declare const RECON_ACK_WAIT_MS = 2000; import { ImportEvalCorpusSchema } from './eval-sample.js'; export { ImportEvalCorpusSchema }; export declare const RunGovernanceEvalsSchema: z.ZodObject<{ type: z.ZodOptional>; corpus: z.ZodOptional; }, "strict", z.ZodTypeAny, { type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined; corpus?: string | undefined; }, { type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined; corpus?: string | undefined; }>; export declare const TestingReconSchema: z.ZodObject<{ problem: z.ZodString; projectId: z.ZodOptional; repoRefs: z.ZodOptional>; ungated: z.ZodOptional; clisJson: z.ZodOptional; channel: z.ZodOptional>; actor: z.ZodOptional; }, "strict", z.ZodTypeAny, { problem: string; projectId?: string | undefined; clisJson?: string | undefined; ungated?: boolean | undefined; actor?: string | undefined; channel?: "cli" | "studio" | "api" | undefined; repoRefs?: string[] | undefined; }, { problem: string; projectId?: string | undefined; clisJson?: string | undefined; ungated?: boolean | undefined; actor?: string | undefined; channel?: "cli" | "studio" | "api" | undefined; repoRefs?: string[] | undefined; }>; export declare const TestingAuthorSchema: z.ZodObject<{ problem: z.ZodString; projectId: z.ZodOptional; repoRefs: z.ZodOptional>; ungated: z.ZodOptional; deliver: z.ZodOptional>; clisJson: z.ZodOptional; channel: z.ZodOptional>; actor: z.ZodOptional; }, "strict", z.ZodTypeAny, { problem: string; deliver?: "pr" | "none" | undefined; projectId?: string | undefined; clisJson?: string | undefined; ungated?: boolean | undefined; actor?: string | undefined; channel?: "cli" | "studio" | "api" | undefined; repoRefs?: string[] | undefined; }, { problem: string; deliver?: "pr" | "none" | undefined; projectId?: string | undefined; clisJson?: string | undefined; ungated?: boolean | undefined; actor?: string | undefined; channel?: "cli" | "studio" | "api" | undefined; repoRefs?: string[] | undefined; }>; /** Returned when `clisJson` names a seat key that is not present in the current roster (#631). */ export declare const SEAT_UNAVAILABLE_REASON = "clisJson names a council seat that is not available in the current roster \u2014 check GET /roster for available seats and omit clisJson to use the default"; /** * Returns `SEAT_UNAVAILABLE_REASON` if `clisJson` is provided and contains a seat `key` that is * not in `roster`; returns `null` when the override is acceptable (or absent). Invalid JSON is * treated as an unavailable-seat error so the caller hears a clear 400 rather than an engine fault. */ export declare function validateClisJson(clisJson: string | undefined, roster: unknown[]): string | null; export interface TestingRoutesDeps { audit: AuditLog; actorOf: (req: FastifyRequest & { actor?: Actor; }) => Actor; /** The default council roster for the recon/author runs (already parsed) — the steering-author * idiom. `registerRoutes` supplies the roster WITH crew's standing (`council_eligible` …), which * the adapter translates into the engine's per-seat `health` at launch (`core/engine-roster.ts`) * and which the author response's `plan.seats` is derived from. */ roster: () => unknown[]; /** The launch-time group index (`RunGroup` on `GET /campaigns`) — an author run is filed under * its repo's `qe-tests-` label so the Test landing sees it from launch (F-7R2-014). * Optional so route-unit tests can omit it; `registerRoutes` always supplies it. */ groupIndex?: GroupIndex; /** The membership plumbing POST /runs uses for projectId filing (index tag + post-commit event). * Optional so route-level unit tests can omit it; `registerRoutes` always supplies it. */ projects?: { bus: ProjectBus | null; index: MembershipIndex; }; /** The run→launch-time index (home command-center run metrics) — so a recon fan's `run.launched` * entries stamp `created_at` LIVE, not only after a restart re-hydrates the trail (Copilot #466). * Optional so route-unit tests can omit it; `registerRoutes` always supplies it. */ runTimingIndex?: RunTimingIndex; /** The eval RUN history store — every `POST /testing/evals/run` is recorded here (best-effort) * so `GET /testing/evals[/:id]` can serve a real history. Optional so route-level unit tests * that never touch the eval routes can omit it; `registerRoutes` always supplies it. */ evalStore?: EvalRunStore; } /** * Derive the per-steering-type rollup from a report's results — the same four counts as the * report summary, grouped by `sample.steering_type`, so the Evals dashboard's "which type carries * the gaps" view is a stored field rather than a per-request recompute over the full results. */ export declare function perTypeRollup(results: GovernanceEvalReport['results']): Partial>; export declare function registerTestingRoutes(app: FastifyInstance, adapter: CoreAdapter, deps: TestingRoutesDeps): void; //# sourceMappingURL=testing.d.ts.map