wicked-crew-api-types 0.138.0 → 0.143.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.d.ts +521 -5
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -292,6 +292,14 @@ export interface HealthCapabilities {
292
292
  * ({@link SystemSnapshot}). ABSENT on an older daemon — show the older Health cards instead.
293
293
  */
294
294
  system?: boolean;
295
+ /**
296
+ * (api-types 0.140.0) `GET /system.attention[]` follows the one "needs you" rule (root causes with
297
+ * `blockedRunIds`, `kind`, `waitedSince`, ranked by impact) and the snapshot carries
298
+ * `unresolved[]` + `toReview`; `POST /runs/:id/resolve` is served. A skin shows
299
+ * `attention.length` as its "needs you" number only when this is true; ABSENT on an older daemon,
300
+ * which keeps its own fold.
301
+ */
302
+ attentionRanked?: boolean;
295
303
  /**
296
304
  * (api-types 0.137.0, DES-SYSTEM-CHAT) The chat history is served: `GET /chats` carries `items` +
297
305
  * `nextCursor`, `GET /chats/:id/messages` reopens a chat, `POST /chats/:id/close` ends one and keeps
@@ -303,6 +311,13 @@ export interface HealthCapabilities {
303
311
  * ABSENT on an older daemon — hide upload.
304
312
  */
305
313
  chatAttachments?: boolean;
314
+ /**
315
+ * (api-types 0.141.0, crew#1157) The read-only workflows `ChatOpenBody.workflow` runs on this
316
+ * daemon's engine — `['analyze']` on a core-ts that carries the built-in `analyze` preset, `[]` on
317
+ * one that does not. ABSENT on an older daemon (its strict schema refuses `workflow`): open a plain
318
+ * chat instead.
319
+ */
320
+ chatWorkflows?: string[];
306
321
  }
307
322
 
308
323
  /** One `GET /health.warnings[]` entry (additive; wicked-core#411 / wicked-crew#497). */
@@ -1757,6 +1772,17 @@ export interface GateDecision {
1757
1772
  * deliver step and at every other gate. QE acceptance is never waived by it — a run that
1758
1773
  * requires it still needs its PASS before delivery. Engine: wicked-core-ts after 0.15.6. */
1759
1774
  | 'operator_judgment'
1775
+ /** (j4-gates) SKIP QE ACCEPTANCE at a gate, with `approve: true` and the written reason in
1776
+ * `amend` — required, non-empty (a 400 otherwise); no `amendScope` or `plan`. The launch's
1777
+ * `skipQeAcceptance`, given later: the run's QE decision becomes `skipped` by the operator
1778
+ * ("QE acceptance skipped by operator: <reason>"), labelled on the run, every later gate and the
1779
+ * delivery. The engine answers three gates: the gate before the deliver step (the delivery goes
1780
+ * without a QE PASS; {@link GateDecisionResult} `delivery.qeAcceptance.status: 'skipped'`), the
1781
+ * escalation gate of a unit only the isolated QE reviewer denied (the unit counts), and a failed
1782
+ * repo-checks floor's gate with a QE layer behind it (the gate re-opens on the floor alone, where
1783
+ * `operator_judgment` then applies). Refused (409, gate left open) at every other gate and on a
1784
+ * run that does not require QE acceptance. Engine: wicked-core-ts after 0.16.3. */
1785
+ | 'skip_qe'
1760
1786
  /** (core#820) A `consent` gate's choice from its dry-run plan (`awaitingHuman.choices`), with
1761
1787
  * `approve: true`: `consent:worker` (the default), `consent:operator`, …; `reject` declines. */
1762
1788
  | `consent:${string}`;
@@ -6684,6 +6710,14 @@ export interface ChatOpenBody {
6684
6710
  primary?: string;
6685
6711
  /** (api-types 0.137.0, DES-SYSTEM-CHAT) The page the chat was started on, for the history list. */
6686
6712
  startedOn?: ChatStartedOn;
6713
+ /**
6714
+ * (api-types 0.141.0, crew#1157) Run every turn of this chat as a READ-ONLY workflow: `analyze`
6715
+ * answers questions about the repositories in scope from the code graph and the files, each claim
6716
+ * cited, changing nothing. The chat seats ONE helper (`primary`, else the first eligible), asks for
6717
+ * no reviewer, never delivers, and its seats propose no work. A name chats do not run is a 400; an
6718
+ * engine without it is a 409. Send it only when `GET /health.capabilities.chatWorkflows` names it.
6719
+ */
6720
+ workflow?: string;
6687
6721
  }
6688
6722
 
6689
6723
  /** The scope a `POST /chats` caller may name (api-types 0.39.0, studio#323 R4). */
@@ -6831,6 +6865,8 @@ export interface ChatOpenResponse {
6831
6865
  * field; a daemon between #641 and #650 emitted it only when `refused` was non-empty.
6832
6866
  */
6833
6867
  singleSeat?: ChatSingleSeatDegradation;
6868
+ /** (api-types 0.141.0, crew#1157) The workflow every turn runs, when the open named one. */
6869
+ workflow?: string;
6834
6870
  }
6835
6871
 
6836
6872
  /** `POST /chats/:id/messages` → 202. */
@@ -8277,7 +8313,9 @@ export interface NoEligibleSeatBody {
8277
8313
  export type SystemState = 'ok' | 'degraded' | 'down' | 'unknown' | 'off';
8278
8314
 
8279
8315
  /** The Nerve Center light: `red` when work is blocked, `yellow` when something needs a look but
8280
- * work still flows, `green` when `attention[]` is empty. Derived from `attention[]` only. */
8316
+ * work still flows, `green` when `attention[]` is empty. Derived from `attention[]` only.
8317
+ * (api-types 0.140.0, `capabilities.attentionRanked`) `green` ONLY when `attention[]` AND
8318
+ * `unresolved[]` are both empty: unresolved work alone reads `yellow`. */
8281
8319
  export type SystemLevel = 'green' | 'yellow' | 'red';
8282
8320
 
8283
8321
  /** The existing action an attention item or row offers (the snapshot itself is read-only):
@@ -8307,11 +8345,36 @@ export interface SystemSnapshot {
8307
8345
  budgetMs: number;
8308
8346
  /** How long assembling it took, in ms. */
8309
8347
  tookMs: number;
8310
- /** `red` iff some attention item is `red`, else `yellow` iff any item, else `green`. */
8348
+ /** `red` iff some attention item is `red`, else `yellow` iff any item, else `green`. (api-types
8349
+ * 0.140.0, `capabilities.attentionRanked`) `yellow` also when `unresolved[]` is not empty: `green`
8350
+ * only when both are empty. */
8311
8351
  level: SystemLevel;
8312
8352
  /** Every item that needs a look, worst first (red before yellow, then by how many runs it
8313
- * blocks, then infra › cli › run › governance). Empty when all is clear. */
8353
+ * blocks, then infra › cli › run › governance). Empty when all is clear.
8354
+ *
8355
+ * (api-types 0.140.0, `capabilities.attentionRanked`) The ONE "needs you" list: each item is one
8356
+ * root cause holding work up right now, either because work cannot move until a person acts
8357
+ * (`kind: 'prevents'`) or because the system itself slows it (`kind: 'slows'`). One cause that
8358
+ * holds several runs is ONE item naming them in `blockedRunIds`. Superseded runs, answered asks,
8359
+ * failed runs older than 7 days, benches with an alternative and pending proposals are not in it
8360
+ * (the first three move to `unresolved[]`; proposals are `toReview`). Sorted by runs held, then
8361
+ * prevents before slows, then a component (infra, or no seat at all) before one run's own cause,
8362
+ * then the longest wait, then the units left. Its length is the number. */
8314
8363
  attention: SystemAttentionItem[];
8364
+ /**
8365
+ * (api-types 0.140.0) Work nobody has resolved: failed runs not retried and not archived,
8366
+ * superseded runs still open, asks parked at their turn gate past a day. Each carries what it cost
8367
+ * and how to resolve it (retry, archive with a reason, or close as superseded). Never counted in
8368
+ * `attention[]`, never dropped by age. ABSENT on an older daemon.
8369
+ */
8370
+ unresolved?: SystemUnresolvedItem[];
8371
+ /** (api-types 0.140.0) `unresolved[]`'s summed cost: `costUsd` is `null` when no item's cost is
8372
+ * known; `costKnown` says how many items carried one. ABSENT on an older daemon. */
8373
+ unresolvedSpend?: { costUsd: number | null; tokens: { input: number; output: number } | null; costKnown: number };
8374
+ /** (api-types 0.140.0) Pending proposals waiting on review: shown as "N to review", never in the
8375
+ * "needs you" number (no run waits on them). `null` when the queue did not answer in time. ABSENT
8376
+ * on an older daemon. */
8377
+ toReview?: number | null;
8315
8378
  /** One entry per CLI on the roster, in roster order. */
8316
8379
  clis: SystemCli[];
8317
8380
  /** Every unfinished run (not completed / cancelled / failed), worst first:
@@ -8338,6 +8401,72 @@ export interface SystemAttentionItem {
8338
8401
  target: SystemTarget;
8339
8402
  /** The one existing action that helps, or `null`. */
8340
8403
  action: SystemAction | null;
8404
+ /** (api-types 0.140.0) `prevents`: work cannot move until someone acts; `slows`: the system
8405
+ * slows it (host load). ABSENT on an older daemon. */
8406
+ kind?: 'prevents' | 'slows';
8407
+ /** (api-types 0.140.0) The runs this one cause holds (`blocks` is its length). For a `slows`
8408
+ * item, the runs whose next step it slows. ABSENT on an older daemon. */
8409
+ blockedRunIds?: string[];
8410
+ /** (api-types 0.140.0) ISO-8601 of the oldest open gate among the held runs (the gate's
8411
+ * arrival, never the run's launch); a failed run's end; `null` when unknown. ABSENT on an older
8412
+ * daemon. */
8413
+ waitedSince?: string | null;
8414
+ /** (api-types 0.140.0) Units not yet done across the held runs. ABSENT on an older daemon. */
8415
+ unitsLeft?: number;
8416
+ }
8417
+
8418
+ /** (api-types 0.140.0) Why a run is in `unresolved[]`. `failed`: it failed and was neither retried
8419
+ * (`retry_of`) nor archived; `superseded`: a retry or a later completed run with the same repo,
8420
+ * workflow and title replaced it, but it is still open or unarchived; `parked`: an ask waits at its
8421
+ * turn gate past a day. */
8422
+ export type SystemUnresolvedWhy = 'failed' | 'superseded' | 'parked';
8423
+
8424
+ /** (api-types 0.140.0) The ways to resolve an unresolved run: `retry` (`POST /runs {retryOf}`),
8425
+ * `archive` (`POST /runs/:id/resolve {action: 'archive', reason}`, a reason is required) and
8426
+ * `close_superseded` (`POST /runs/:id/resolve {action: 'superseded', by}`). */
8427
+ export type SystemResolveKind = 'retry' | 'archive' | 'close_superseded';
8428
+
8429
+ /** (api-types 0.140.0) One run nobody has resolved (`SystemSnapshot.unresolved[]`). */
8430
+ export interface SystemUnresolvedItem {
8431
+ /** `unresolved:<runId>`. */
8432
+ id: string;
8433
+ runId: string;
8434
+ title: string;
8435
+ /** (api-types 0.142.0) The run's repo (`repo_ref`) and workflow, so a skin can group look-alike items; `null` when none. ABSENT before. */
8436
+ repo?: string | null;
8437
+ workflow?: string | null;
8438
+ /** The engine's status. */
8439
+ status: string;
8440
+ why: SystemUnresolvedWhy;
8441
+ /** Plain words ("failed 9 days ago", "superseded by 6f11390c, which delivered"). */
8442
+ reason: string;
8443
+ /** The run that superseded it, for `why: 'superseded'`. */
8444
+ supersededBy?: string;
8445
+ /** ISO-8601 of when it stopped moving (its end, or its gate's arrival); `null` when unknown. */
8446
+ since: string | null;
8447
+ /** What it cost. `costUsd`/`tokens` are `null` when the run's log carried no usage frame (or was
8448
+ * not read yet); `wallMs` is launch to end (or to now while open), `null` for an undated run. */
8449
+ cost: { costUsd: number | null; tokens: { input: number; output: number } | null; wallMs: number | null };
8450
+ /** The resolutions that apply, best first. */
8451
+ actions: SystemResolveKind[];
8452
+ }
8453
+
8454
+ /** (api-types 0.140.0) `POST /runs/:id/resolve`: resolve an unresolved run. `archive` needs a
8455
+ * non-blank `reason` (a blank or missing one is a 400); `superseded` names the run that replaced it
8456
+ * in `by` (an existing run, not itself). A run parked at a gate is stopped first, then archived; a
8457
+ * run that is executing is refused (409). The archive note keeps the reason. */
8458
+ export type ResolveRunRequest =
8459
+ | { action: 'archive'; reason: string }
8460
+ | { action: 'superseded'; by: string; reason?: string };
8461
+
8462
+ export interface ResolveRunResponse {
8463
+ runId: string;
8464
+ action: 'archive' | 'superseded';
8465
+ archived: true;
8466
+ /** The run was parked at a gate and was stopped before it was archived. */
8467
+ cancelled: boolean;
8468
+ /** The archive note written (`resolved: <reason>` or `superseded by <id>[: <reason>]`). */
8469
+ note: string;
8341
8470
  }
8342
8471
 
8343
8472
  // ── clis[] ──
@@ -8464,8 +8593,9 @@ export interface SystemRun {
8464
8593
  /** The thresholds the verdict used (from `workerStallMinutes`). */
8465
8594
  quietAfterMs: number;
8466
8595
  stallAfterMs: number;
8467
- /** The open gate or question, when the run waits on one. */
8468
- gate?: { interactionId: string | null; ord: number | null; kind: string | null; prompt: string | null };
8596
+ /** The open gate or question, when the run waits on one. `receivedAt` (api-types 0.140.0): ISO-8601
8597
+ * of the gate's arrival; `null`/ABSENT when unknown. */
8598
+ gate?: { interactionId: string | null; ord: number | null; kind: string | null; prompt: string | null; receivedAt?: string | null };
8469
8599
  /** ISO-8601 the run was launched, when known. */
8470
8600
  createdAt: string | null;
8471
8601
  }
@@ -11713,6 +11843,187 @@ export interface LearnTopicsResponse {
11713
11843
  topics: LearnTopic[];
11714
11844
  }
11715
11845
 
11846
+ // ── workflow schedules + the run review (DES-RUNS-REVIEW-001) ─────────────────────────────────
11847
+ // `/api/v1/schedules`: any workflow on a cadence (the default entry reviews recent work every 48 h).
11848
+ // `/api/v1/insights`: every review of recent work, its numbers and what happened to each recommendation.
11849
+
11850
+ /** A schedule's last outcome: `launched` while its run is open; `refused` = the launch failed. */
11851
+ /** `launching` = the run id is reserved and the engine is being asked; it holds the slot across a restart. */
11852
+ export type ScheduleOutcome = 'launching' | 'launched' | 'refused' | 'completed' | 'failed' | 'cancelled' | 'skipped';
11853
+
11854
+ /** One workflow schedule (`GET /schedules`). */
11855
+ export interface WorkflowSchedule {
11856
+ /** Kebab-case; the default entry is `review-recent-work`. */
11857
+ id: string;
11858
+ workflow: string;
11859
+ /** Interval, 24..2160 hours. */
11860
+ everyHours: number;
11861
+ enabled: boolean;
11862
+ /** Projects the run covers; empty = all. */
11863
+ projectIds: string[];
11864
+ repoRef: string | null;
11865
+ problem: string | null;
11866
+ /** ISO-8601. Missed intervals coalesce into one launch; a schedule whose last run is open is skipped. */
11867
+ nextDueAt: string;
11868
+ lastRunId: string | null;
11869
+ lastRunAt: string | null;
11870
+ lastOutcome: ScheduleOutcome | null;
11871
+ /** Why the last attempt was skipped or refused, in plain words; null after a launch. */
11872
+ lastNote: string | null;
11873
+ /** Consecutive refused launches (backoff = min(2^failures, 24) h). */
11874
+ failures: number;
11875
+ createdAt: string;
11876
+ updatedAt: string;
11877
+ /** The `review-recent-work` schedule only: the latest review's date and outcome. */
11878
+ lastReview?: { runId: string; launchedAt: string; endedAt: string | null; status: InsightsReviewStatus } | null;
11879
+ }
11880
+
11881
+ export interface SchedulesResponse {
11882
+ schedules: WorkflowSchedule[];
11883
+ }
11884
+
11885
+ /** `PUT /schedules/:id` (human-only). */
11886
+ export interface SchedulePutBody {
11887
+ workflow: string;
11888
+ everyHours: number;
11889
+ enabled?: boolean;
11890
+ projectIds?: string[];
11891
+ repoRef?: string | null;
11892
+ problem?: string | null;
11893
+ }
11894
+
11895
+ /** `POST /schedules/:id/run` ("Run it now", human-only): 409 when its last run is still going or another run works. */
11896
+ export interface ScheduleRunResponse {
11897
+ runId: string;
11898
+ schedule: WorkflowSchedule;
11899
+ }
11900
+
11901
+ export type InsightsMetricId = 'pass_rate' | 'override_rate' | 'unresolved_rate' | 'time_to_pr' | 'floor_minutes' | 'wait_on_people' | 'spend' | 'retries';
11902
+ /** `too-few` = below the minimum sample (n < 5) in the window or the baseline: no trend is called. */
11903
+ export type InsightsVerdict = 'too-few' | 'no-change' | 'improved' | 'regressed';
11904
+ export type InsightsRecommendationKind = 'steering-rule' | 'memory' | 'setting' | 'issue' | 'resolve-stale';
11905
+ export type InsightsReviewStatus = 'running' | 'completed' | 'failed' | 'cancelled';
11906
+
11907
+ export interface InsightsInterval {
11908
+ lo: number;
11909
+ hi: number;
11910
+ }
11911
+
11912
+ /** A sample: a rate (Wilson 95 % interval) or a median (bootstrap 95 % interval, with p75/p90). */
11913
+ export interface InsightsSampleStat {
11914
+ n: number;
11915
+ value: number | null;
11916
+ interval: InsightsInterval | null;
11917
+ p75?: number | null;
11918
+ p90?: number | null;
11919
+ }
11920
+
11921
+ export interface InsightsMetricDef {
11922
+ id: InsightsMetricId;
11923
+ label: string;
11924
+ kind: 'rate' | 'median';
11925
+ unit: 'ratio' | 'minutes' | 'usd' | 'count';
11926
+ higherIsBetter: boolean;
11927
+ }
11928
+
11929
+ export interface InsightsRecommendation {
11930
+ /** `<review run id>:<candidate id>`. */
11931
+ id: string;
11932
+ candidate: string;
11933
+ kind: InsightsRecommendationKind;
11934
+ title: string;
11935
+ evidence: {
11936
+ line: string;
11937
+ runs: Array<{ id: string; title: string }>;
11938
+ metric?: InsightsMetricId;
11939
+ segment?: string;
11940
+ n: number;
11941
+ value?: number | null;
11942
+ baseline?: number | null;
11943
+ interval?: InsightsInterval | null;
11944
+ };
11945
+ expectedEffect: string;
11946
+ confidence: 'high' | 'medium' | 'low';
11947
+ /** What evidence would change our mind. */
11948
+ changeMind: string;
11949
+ /** Crew's ranking key: runs affected + hours at stake + dollars at stake. */
11950
+ impact: number;
11951
+ basis: 'notable' | 'pattern';
11952
+ action: {
11953
+ setting?: string;
11954
+ issue?: { repoRef: string | null; title: string; body: string };
11955
+ runs?: string[];
11956
+ proposal?: { kindType: string; content: string; severity?: string };
11957
+ };
11958
+ state: 'new' | 'accepted' | 'dismissed';
11959
+ reason: string | null;
11960
+ decidedAt: string | null;
11961
+ /** The approve-queue proposal filed for a steering-rule or memory recommendation. */
11962
+ proposalId: string | null;
11963
+ proposalError: string | null;
11964
+ }
11965
+
11966
+ export interface InsightsReview {
11967
+ runId: string;
11968
+ trigger: 'schedule' | 'manual';
11969
+ scheduleId: string | null;
11970
+ launchedAt: string;
11971
+ endedAt: string | null;
11972
+ status: InsightsReviewStatus;
11973
+ window: { startMs: number; endMs: number };
11974
+ baselineWindows: Array<{ startMs: number; endMs: number }>;
11975
+ projectIds: string[];
11976
+ summary: string | null;
11977
+ /** false = the seat wrote no usable report; crew's own wording is shown, labelled "not interpreted". */
11978
+ interpreted: boolean;
11979
+ totals: Record<string, number> | null;
11980
+ /** The all-runs metrics of this review: one point per metric on the trend lines. */
11981
+ series: Array<{ metric: InsightsMetricId; window: InsightsSampleStat; baseline: InsightsSampleStat; verdict: InsightsVerdict }>;
11982
+ /** What got better, and what is working. */
11983
+ improvements: Array<{ metric: InsightsMetricId; segment: string; line: string }>;
11984
+ regressions: Array<{ metric: InsightsMetricId; segment: string; line: string }>;
11985
+ /** At most five, ranked by impact. */
11986
+ recommendations: InsightsRecommendation[];
11987
+ watching: Array<{ id: string; title: string; line: string }>;
11988
+ error: string | null;
11989
+ }
11990
+
11991
+ /** `GET /insights`: the review history, newest first. */
11992
+ export interface InsightsResponse {
11993
+ reviews: InsightsReview[];
11994
+ /** Recommendations nobody has accepted or dismissed yet, across the history. */
11995
+ newRecommendations: number;
11996
+ running: boolean;
11997
+ lastReview: { runId: string; launchedAt: string; endedAt: string | null; status: InsightsReviewStatus } | null;
11998
+ metrics: InsightsMetricDef[];
11999
+ /** Below this n no trend is called. */
12000
+ minSample: number;
12001
+ }
12002
+
12003
+ /** What studio opens on Accept: the proposal (approval stays in the approve queue), a settings section, a
12004
+ * prefilled new-issue page, or the runs list filtered to these runs. */
12005
+ export type InsightsAcceptTarget =
12006
+ | { kind: 'proposal'; proposalId: string }
12007
+ | { kind: 'settings'; section: string }
12008
+ | { kind: 'issue'; repoRef: string | null; title: string; body: string; url: string | null }
12009
+ | { kind: 'runs'; runIds: string[] }
12010
+ | { kind: 'none' };
12011
+
12012
+ /** `POST /insights/recommendations/:id/accept` (human-only). */
12013
+ export interface AcceptRecommendationResponse {
12014
+ recommendation: InsightsRecommendation;
12015
+ open: InsightsAcceptTarget;
12016
+ }
12017
+
12018
+ /** `POST /insights/recommendations/:id/dismiss` (human-only). A proposal-backed one rejects its proposal. */
12019
+ export interface DismissRecommendationBody {
12020
+ reason: string;
12021
+ }
12022
+
12023
+ export interface DismissRecommendationResponse {
12024
+ recommendation: InsightsRecommendation;
12025
+ }
12026
+
11716
12027
  // ── MCP inspector bridge (DES-MCP-INSPECTOR-001 §3) ───────────────────────────────────────────
11717
12028
  // `/api/v1/mcp-inspect/sessions`: one live connection to an MCP server per session, driven by
11718
12029
  // studio's host for an `mcp-server` editor. Start, send and delete are human-only; the log is
@@ -11899,3 +12210,208 @@ export interface SearchResponse {
11899
12210
  partial: boolean;
11900
12211
  took_ms: number;
11901
12212
  }
12213
+
12214
+ // ── Default evals (DES-DEFAULT-EVALS-001; api-types 0.143.0) ─────────────────────────────────────────────
12215
+ // `/api/v1/testing/default-evals*`: the system's own judgments (needs-you, floor class, QE verdict, attribution,
12216
+ // steering firing, recall, prompt routing, normalization) scored against what really happened. One case shape for
12217
+ // every suite; real, synthetic, combined and model-labelled figures are always reported apart.
12218
+
12219
+ /** The eight inference points. */
12220
+ export type DefaultEvalSuiteId =
12221
+ | 'needs-you'
12222
+ | 'floor-class'
12223
+ | 'qe-verdict'
12224
+ | 'attribution'
12225
+ | 'steering'
12226
+ | 'recall'
12227
+ | 'archetype'
12228
+ | 'normalization';
12229
+
12230
+ export type DefaultEvalCaseSource = 'real' | 'synthetic';
12231
+
12232
+ /**
12233
+ * Who said what the answer should be. `operator`: the person's choice at a gate (or a ruling); `rule`: a
12234
+ * deterministic consistency rule over the case's own evidence; `fixture`: written into a corpus or the generator;
12235
+ * `model:<seat>`: a model labelled it because nothing else could. Model labels are reported in their own row and
12236
+ * never in the headline (DES §3, determinism).
12237
+ */
12238
+ export type DefaultEvalLabelBy = 'operator' | 'rule' | 'fixture' | `model:${string}`;
12239
+
12240
+ /** What the system answered: a class, a set (attribution), or a cluster key (needs-you merge). */
12241
+ export interface DefaultEvalAnswer {
12242
+ label?: string;
12243
+ labels?: string[];
12244
+ cluster?: string;
12245
+ }
12246
+
12247
+ export interface DefaultEvalObserved extends DefaultEvalAnswer {
12248
+ /** The classifier's own confidence in `label`, in [0, 1], when it gives one (calibration). */
12249
+ confidence?: number;
12250
+ /** `recorded`: read from the run store as the system said it then. `replay`: the current classifier, run now. */
12251
+ by: 'recorded' | 'replay';
12252
+ }
12253
+
12254
+ export interface DefaultEvalExpected extends DefaultEvalAnswer {
12255
+ by: DefaultEvalLabelBy;
12256
+ /** Why this is the answer, in a line (the operator's words, or the rule that fired). */
12257
+ why?: string;
12258
+ }
12259
+
12260
+ export interface DefaultEvalCaseEvidence {
12261
+ runId?: string;
12262
+ ord?: number;
12263
+ seq?: number;
12264
+ decisionId?: string;
12265
+ /** A repo-relative or program-relative file the case was read from (seed cases). */
12266
+ file?: string;
12267
+ }
12268
+
12269
+ export interface DefaultEvalCase {
12270
+ /** Stable identity: capture is idempotent by it. */
12271
+ id: string;
12272
+ suite: DefaultEvalSuiteId;
12273
+ source: DefaultEvalCaseSource;
12274
+ /** The project (or repo, when the run has no project) the case belongs to; `null` when neither is known. */
12275
+ project: string | null;
12276
+ /** The surface that produced `observed`, when several surfaces answer one question (needs-you). */
12277
+ surface?: string;
12278
+ /**
12279
+ * The canonical input fingerprint: two cases with the same key asked the system the same question. The
12280
+ * normalization suite compares observations per key across projects and surfaces.
12281
+ */
12282
+ inputKey: string;
12283
+ /** The case's input, small and scrubbed (no paths, no prompts beyond a title). */
12284
+ input: Record<string, unknown>;
12285
+ /** `null` when the system's answer is not known yet: a synthetic case waiting on a replay adapter. */
12286
+ observed: DefaultEvalObserved | null;
12287
+ expected: DefaultEvalExpected;
12288
+ evidence?: DefaultEvalCaseEvidence;
12289
+ /** A case from the shipped baseline (the 2026-10-27 rig capture and the needs-you ruling), not this daemon's own
12290
+ * run store. Only counted when a run asks for the baseline; always disclosed in the counts. */
12291
+ baseline?: true;
12292
+ }
12293
+
12294
+ /** A proportion with its Wilson 95 % interval. `tooFew` when n is below the minimum (DES §6). */
12295
+ export interface DefaultEvalRate {
12296
+ k: number;
12297
+ n: number;
12298
+ value: number | null;
12299
+ lo: number | null;
12300
+ hi: number | null;
12301
+ tooFew: boolean;
12302
+ }
12303
+
12304
+ export interface DefaultEvalClassScore {
12305
+ label: string;
12306
+ precision: DefaultEvalRate;
12307
+ recall: DefaultEvalRate;
12308
+ }
12309
+
12310
+ export interface DefaultEvalCalibration {
12311
+ n: number;
12312
+ /** DefaultEvalExpected calibration error over 10 equal-width bins. `null` below the calibration minimum. */
12313
+ ece: number | null;
12314
+ brier: number | null;
12315
+ tooFew: boolean;
12316
+ }
12317
+
12318
+ /** One slice of a suite's cases (real, synthetic, combined, model-labelled, or one project). */
12319
+ export interface DefaultEvalSliceScore {
12320
+ /** Cases in the slice, including those that could not be scored. */
12321
+ cases: number;
12322
+ /** Cases with no observation (a synthetic case with no replay adapter). Never counted as right or wrong. */
12323
+ unscored: number;
12324
+ /** DefaultEvalObserved matched expected: exact class, set equality, or the pair agreement for merges. */
12325
+ agreement: DefaultEvalRate;
12326
+ perClass: DefaultEvalClassScore[];
12327
+ /** Set-valued suites (attribution): micro precision / recall over the set members. */
12328
+ members?: { precision: DefaultEvalRate; recall: DefaultEvalRate };
12329
+ /** Cluster suites (needs-you merge): pairwise precision / recall over "these two are one item". */
12330
+ pairs?: { precision: DefaultEvalRate; recall: DefaultEvalRate };
12331
+ calibration?: DefaultEvalCalibration;
12332
+ }
12333
+
12334
+ export type DefaultEvalTrend = 'too-few' | 'no-change' | 'improved' | 'regressed' | 'first-run';
12335
+
12336
+ export interface DefaultEvalSuiteScore {
12337
+ suite: DefaultEvalSuiteId;
12338
+ title: string;
12339
+ /** Slices that always appear. `model` holds only model-labelled cases; the other three exclude them. */
12340
+ real: DefaultEvalSliceScore;
12341
+ synthetic: DefaultEvalSliceScore;
12342
+ combined: DefaultEvalSliceScore;
12343
+ model: DefaultEvalSliceScore;
12344
+ /** Per project (cross-project runs only), over real + synthetic. */
12345
+ byProject?: Record<string, DefaultEvalSliceScore>;
12346
+ /** Per answerer, when several surfaces answer the same question (needs-you). */
12347
+ bySurface?: Record<string, DefaultEvalSliceScore>;
12348
+ /** Against the last stored run of the same suite and scope, on the combined agreement. */
12349
+ trend: { word: DefaultEvalTrend; previous: number | null; previousRunId: string | null };
12350
+ /** Plain-words notes the suite must carry (why synthetic is unscored, which adapter is missing, …). */
12351
+ notes: string[];
12352
+ }
12353
+
12354
+ /** One input judged differently by place: the normalization drift a cross-project run surfaces. */
12355
+ export interface DefaultEvalDriftKey {
12356
+ inputKey: string;
12357
+ suite: DefaultEvalSuiteId;
12358
+ /** `project` or `surface`: what differed. */
12359
+ axis: 'project' | 'surface';
12360
+ /** place → the observed labels there (sorted, distinct). */
12361
+ observed: Record<string, string[]>;
12362
+ caseIds: string[];
12363
+ }
12364
+
12365
+ export interface DefaultEvalReport {
12366
+ id: string;
12367
+ createdAt: string;
12368
+ /** `null` = every project (a cross-project run). */
12369
+ project: string | null;
12370
+ suites: DefaultEvalSuiteScore[];
12371
+ drift: DefaultEvalDriftKey[];
12372
+ counts: { real: number; synthetic: number; modelLabelled: number; unscored: number; baseline: number };
12373
+ /** The minimum n a figure needs before it is called (and the calibration minimum). */
12374
+ minimums: { rate: number; calibration: number };
12375
+ }
12376
+
12377
+ export interface DefaultEvalSummary {
12378
+ id: string;
12379
+ createdAt: string;
12380
+ project: string | null;
12381
+ suites: Array<{ suite: DefaultEvalSuiteId; agreement: number | null; n: number; tooFew: boolean; trend: DefaultEvalTrend }>;
12382
+ drift: number;
12383
+ counts: DefaultEvalReport['counts'];
12384
+ }
12385
+
12386
+ /** `GET /testing/default-evals/suites`. */
12387
+ export interface DefaultEvalSuitesResponse {
12388
+ suites: Array<{
12389
+ id: DefaultEvalSuiteId;
12390
+ title: string;
12391
+ /** Crew can run the current classifier on a case's input (so synthetic cases are scored). */
12392
+ replay: boolean;
12393
+ /** The generator makes synthetic cases for it. */
12394
+ synthetic: boolean;
12395
+ /** Why it cannot replay, when it cannot. */
12396
+ note: string | null;
12397
+ }>;
12398
+ }
12399
+
12400
+ /** `POST /testing/default-evals/run` body. `project`: one project (or repo) id, or `"all"` (the default). */
12401
+ export interface RunDefaultEvalsBody {
12402
+ project?: string;
12403
+ suites?: DefaultEvalSuiteId[];
12404
+ /** Count the shipped baseline cases too (the 2026-10-27 rig capture and the needs-you ruling). */
12405
+ baseline?: boolean;
12406
+ }
12407
+
12408
+ /** `GET /testing/default-evals`. Newest first. */
12409
+ export interface ListDefaultEvalRunsResponse {
12410
+ runs: DefaultEvalSummary[];
12411
+ }
12412
+
12413
+ /** `GET /testing/default-evals/:id`. */
12414
+ export interface DefaultEvalDetail {
12415
+ report: DefaultEvalReport;
12416
+ cases: DefaultEvalCase[];
12417
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.138.0",
3
+ "version": "0.143.0",
4
4
  "description": "The wire contract of the wicked-crew daemon's /api/v1 REST surface and /ws CoreEvent frames \u2014 types only, zero runtime",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",