wicked-crew-api-types 0.35.0 → 0.36.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 +480 -11
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -282,6 +282,34 @@ export interface AgentSession {
282
282
  * now; a joined `AgentSession.cost` is a follow-up once that store exists.
283
283
  */
284
284
  created_at?: number;
285
+ /**
286
+ * The interactive DOCUMENT this run answered (wave 6, F-4R2-006 root fix; api-types 0.36.0) —
287
+ * daemon-joined at DTO assembly on `GET /runs` and `GET /runs/:id` from the interactive seams'
288
+ * handoff ledgers (the system of record for "this handoff was answered by this run"), so a skin
289
+ * no longer parses `extra_write_roots` for it. `GET /runs?doc=<id>` filters on it. `null` =
290
+ * genuinely not a document run; ABSENT = a pre-0.36 daemon. A document chip renders only on
291
+ * `typeof === 'string'`.
292
+ */
293
+ document_id?: string | null;
294
+ /**
295
+ * Wave 6 (F-7R2-013): the run branch the worktree was minted on (`wicked/<run id>`, sanitized) —
296
+ * recorded by the engine when the worktree is ready and durable past its reap, so
297
+ * `GET /runs/:id/diff` serves the run's work from the branch (`source: 'branch'`) once the
298
+ * worktree is gone. Absent for an unbound run and on an engine predating wave 6 (the daemon then
299
+ * derives `wicked/<id>` itself).
300
+ */
301
+ run_branch?: string;
302
+ /** Wave 6 (F-7R2-013): the commit the worktree was minted FROM (`runBaseResolved.baseCommit`) —
303
+ * the branch diff's base. Absent for an unbound run, a reused worktree, or an older engine (the
304
+ * daemon then uses the branch's merge-base with the default branch). */
305
+ base_commit?: string;
306
+ /** Wave 6 (F-7R2-013): when the run reached a TERMINAL status, unix millis. A COMPLETED run's
307
+ * worktree is RETAINED from here until archive or the engine's retention window elapses
308
+ * (`WICKED_COMPLETED_WORKTREE_KEEP_DAYS`, default 14). Absent on a live run and on older engines. */
309
+ finished_at?: number;
310
+ /** Wave 6 (F-7R2-006): the seats BENCHED for this run — never convened, never a failover or
311
+ * judge target. Absent (never `[]`) when none / on an older engine. */
312
+ benched_seats?: BenchedSeat[];
285
313
  }
286
314
 
287
315
  /** An ordered unit of work within a run (`WorkUnit`). */
@@ -434,6 +462,17 @@ export interface RosterSeat {
434
462
  * cheaply (keychain-backed seats, unknown seat keys). Absent on a daemon predating the field.
435
463
  */
436
464
  auth?: SeatAuth;
465
+ /**
466
+ * Where `auth` came from (api-types 0.36.0, F-A45-006): `seat-stderr` — the seat ITSELF reported
467
+ * no credential (a council ballot's "No API key found", a worker's 401, an authentication ACP
468
+ * fallback) within the last 30 minutes with no ok output since, which OVERRIDES the credential-
469
+ * file probe (`signed_in`) — the fresh rig's pi read `signed_in: true` off an empty `auth.json`
470
+ * while every ballot failed. Absent = the probe decided (and since 0.36.0 the probe itself needs
471
+ * a credential-SHAPED file, never mere presence).
472
+ */
473
+ auth_source?: 'seat-stderr';
474
+ /** Present with `auth_source: 'seat-stderr'`: the seat's own words, bounded. */
475
+ auth_evidence?: string;
437
476
  /** Present when `auth` is `not_required`: the free tier the seat answers on. */
438
477
  free_tier?: string;
439
478
  /**
@@ -523,6 +562,21 @@ export interface RunDiff {
523
562
  diff: string;
524
563
  /** The diff exceeded the 1 MB output cap and was cut. */
525
564
  truncated: boolean;
565
+ /**
566
+ * Where the diff was read from (wave 6, F-7R2-013; api-types 0.36.0): `worktree` — the live run
567
+ * worktree (staged + unstaged + untracked; the pre-0.36 answer); `branch` — the run's retained
568
+ * `wicked/<id>` branch in the REGISTERED repository, diffed against its base, served when the
569
+ * engine has reaped the worktree (a completed run) so the files view never goes dark at
570
+ * completion. A pre-0.36 daemon omits the field and answers 409 for a reaped worktree; 409 now
571
+ * means "no worktree AND no run branch" (nothing was ever committed for the run).
572
+ */
573
+ source?: 'worktree' | 'branch';
574
+ /** `source: 'branch'` — the run branch the diff was read from. */
575
+ branch?: string;
576
+ /** `source: 'branch'` — the base commit the branch was diffed against: the engine's recorded
577
+ * `AgentSession.base_commit` when it has one, else the branch's merge-base with the default
578
+ * branch; `?base=<ref>` overrides it with a plain in-repo ref. */
579
+ base?: string;
526
580
  }
527
581
 
528
582
  /** The daemon's cached open-gate record (`GET /runs/:id/gate`, DES-STUDIO-001 §3.3). */
@@ -681,17 +735,40 @@ export interface CoreEvent {
681
735
  hasValidatorPin?: boolean;
682
736
  executor_type?: string;
683
737
  executorType?: string;
684
- // unitDistributed enrichment fields
738
+ // unitDistributed enrichment fields — the wire spelling is camelCase (event_to_json; see
739
+ // UnitDistributedEvent, api-types 0.36.0); the snake_case variants are kept for older relays.
740
+ routingMethod?: string;
685
741
  routing_method?: string;
686
742
  agreement_pct?: number | null;
687
743
  returned?: number | null;
744
+ seated?: number | null;
688
745
  dissent?: number | null;
746
+ degradedReason?: string | null;
689
747
  degraded_reason?: string | null;
748
+ seatConstraint?: string | null;
749
+ /** `gateEvaluated` (wave 6, F-7R2-005): `true` when NOTHING gated the unit — render as UNGATED. */
750
+ ungated?: boolean;
751
+ /** `gateEvaluated` (wave 6): why, when `ungated`. */
752
+ ungatedReason?: string | null;
753
+ /** `gateEvaluated` (wave 6, #449 @ 9e11685): why the deterministic layer is absent / why no judge ran. */
754
+ floorNote?: string | null;
755
+ judgeSkippedReason?: string | null;
756
+ /** `repoChecksEvaluated` (wave 6): the sandbox level, and why the sandbox / check detection failed. */
757
+ sandboxLevel?: string;
758
+ sandboxError?: string | null;
759
+ detectError?: string | null;
760
+ /** `workerToolCallDenied` (wave 6, F-7R2-012): the refused command / the remedy / the unit's role. */
761
+ command?: string;
762
+ remedy?: string;
763
+ role?: string;
764
+ /** `runBaseResolved` (wave 6, F-7R2-013): the run branch the worktree was minted on. */
765
+ runBranch?: string;
690
766
  // councilConvened / councilDeliberated / councilVoted (live deliberation) — camelCase
691
767
  // per event_to_json
692
768
  clis?: string[];
693
769
  consensus?: boolean;
694
- agreementPct?: number;
770
+ /** councilConvened/Deliberated/Voted: a number; `unitDistributed` (api-types 0.36.0): `number | null`. */
771
+ agreementPct?: number | null;
695
772
  votes?: number;
696
773
  /** councilDeliberated: the completed ballot number (1-based). */
697
774
  round?: number;
@@ -957,6 +1034,28 @@ export interface GateEvaluatedEvent {
957
1034
  * pick, `false` when the judge fell back to the single default runner (prompt-only independence).
958
1035
  * `null` when no judge ran or the seat is unknown. */
959
1036
  judgeDistinct: boolean | null;
1037
+ /**
1038
+ * Wave 6 (F-7R2-005, api-types 0.36.0): `true` when NOTHING gated this unit — no deterministic
1039
+ * floor (no pinned validator, and the repo-checks floor did not apply), no agent judge, and an
1040
+ * EMPTY evaluator-policy selection — the exact default-allow shape run b86c14c1 passed seven times.
1041
+ * A consumer MUST render it as UNGATED, never as "pass", and a narrator must never say "checks
1042
+ * ran" without a `repoChecksEvaluated` for the same unit. Absent on an engine predating wave 6
1043
+ * (read `=== true`); `false` on a gated unit.
1044
+ */
1045
+ ungated?: boolean;
1046
+ /** WHY, when `ungated` — each absent layer and its cause (`"no judge: no eligible judge seat
1047
+ * distinct from creator \`claude\` (roster: claude; benched: codex (signed out))"`). `null` when
1048
+ * gated; absent on an older engine. */
1049
+ ungatedReason?: string | null;
1050
+ /** Wave 6 (wicked-core#449 @ 9e11685, api-types 0.36.0): WHY the deterministic layer is absent —
1051
+ * set whenever `hasDeterministicFloor` is `false` on an agent unit, judge or not (`"no pinned
1052
+ * validator; the repo-checks floor did not apply: the tree was not changed"`). `null` when a
1053
+ * floor ran; absent on an older engine. */
1054
+ floorNote?: string | null;
1055
+ /** Wave 6: WHY no judge was convened for a unit that WANTED one (its tree changed and no pinned
1056
+ * validator gated it) — `"no eligible judge seat distinct from creator \`claude\` (roster: …;
1057
+ * benched: …)"`. `null` when a judge ran or none was wanted; absent on an older engine. */
1058
+ judgeSkippedReason?: string | null;
960
1059
  }
961
1060
 
962
1061
  /** Foundation wave: session started with enriched context. */
@@ -1024,6 +1123,12 @@ export type AcpFallbackKind =
1024
1123
  | 'binary_unavailable'
1025
1124
  | 'session_died'
1026
1125
  | 'auth_required'
1126
+ /** Wave 6 (F-7R2-019, api-types 0.36.0): the ACP handshake was REFUSED for authentication — the
1127
+ * seat's account, not its binary (`pi-acp` existed; pi answered 401). The engine benches the seat
1128
+ * for the run and does NOT attempt the single-shot wrapped fallback (it fails the same way). */
1129
+ | 'auth_failed'
1130
+ /** Wave 6 — the seat reported no credential at all (`unauthenticated`); same bench, same no-retry. */
1131
+ | 'unauthenticated'
1027
1132
  | 'governance_requires_wrapped'
1028
1133
  | 'read_only_requires_wrapped'
1029
1134
  | (string & {});
@@ -1264,8 +1369,19 @@ export type RepoChecksEvaluatedEvent = {
1264
1369
  attempt: number;
1265
1370
  passed: boolean;
1266
1371
  criterion: string;
1372
+ /** The checks that RAN. EMPTY means "0 checks detected" — a consumer must say so, never "checks
1373
+ * ran"; since wave 6 the frame says WHY (`detectError`, `sandboxError`). */
1267
1374
  checks: RepoCheckRun[];
1268
1375
  skipped: string[];
1376
+ /** Wave 6 (wicked-core#449 @ 9e11685, api-types 0.36.0): the sandbox level the checks ran under
1377
+ * (`bwrap`, `sandbox-exec`, `none`, …). Absent on an older engine. */
1378
+ sandboxLevel?: string;
1379
+ /** Wave 6: why the sandbox could not be armed, when it could not (`null` when it was). */
1380
+ sandboxError?: string | null;
1381
+ /** Wave 6: why check DETECTION failed (an unreadable `package.json`, a manifest with no
1382
+ * `typecheck`/`lint`/`test` script, …) — the reason an empty `checks` is empty; `null` when
1383
+ * detection succeeded. */
1384
+ detectError?: string | null;
1269
1385
  };
1270
1386
 
1271
1387
  // ── wicked-core#431 gate / deliver evidence (F-3R2-013 / -010 / -009; api-types 0.33.0) ──────────
@@ -1404,6 +1520,11 @@ export type RunBaseResolvedEvent = {
1404
1520
  fetched: boolean;
1405
1521
  lifted: boolean;
1406
1522
  note: string | null;
1523
+ /** Wave 6 (F-7R2-013, api-types 0.36.0): the run branch the worktree was minted on
1524
+ * (`wicked/<run id>`, sanitized), recorded on the session as `run_branch` beside `base_commit`
1525
+ * so the run's diff is servable from the branch once the worktree is reaped. Absent on an
1526
+ * engine predating wave 6. */
1527
+ runBranch?: string;
1407
1528
  };
1408
1529
 
1409
1530
  /** The gate-evidence events (wicked-core F-036/F-039, extended by wicked-core#431 — api-types 0.33.0
@@ -1411,12 +1532,45 @@ export type RunBaseResolvedEvent = {
1411
1532
  * {@link EvaluatorToolCallDeniedEvent}) as a discriminated union for consumers that narrow on `type`;
1412
1533
  * they also flow through the permissive {@link CoreEvent}. {@link RunBaseResolvedEvent} is
1413
1534
  * session-level evidence and stands on its own. */
1535
+ /**
1536
+ * Wave 6 (F-7R2-012, api-types 0.36.0) — a WORKER seat asked to run a REMOTE-WRITING command
1537
+ * (`git push`, `gh pr create|merge|edit|comment`, a `gh api` mutation, `gh release`, …) and the
1538
+ * engine REFUSED it: delivery is performed by the run's deliver phase (which lifts, re-verifies,
1539
+ * pushes and opens the PR so the ledger records it), never by a creator or evaluator seat. Emitted
1540
+ * on both carriers: the ACP permission bridge (`carrier: 'acp'`) answers the seat's permission
1541
+ * request with its reject option; the wrapped carrier's PreToolUse gate hook (`carrier:
1542
+ * 'wrapped_cli'`) blocks the call and the fold replays the record at the gate. A refusal costs the
1543
+ * seat one tool call, never the unit — the seat continues with `remedy`. Spelled exactly as
1544
+ * wicked-core's `CoreEvent::to_json` emits it. `type` alias on purpose (relays through the
1545
+ * `CoreEvent`-typed seams unchanged).
1546
+ */
1547
+ export type WorkerToolCallDeniedEvent = {
1548
+ type: 'workerToolCallDenied';
1549
+ session: string;
1550
+ ord: number;
1551
+ attempt: number;
1552
+ /** The registry seat key. */
1553
+ cli: string;
1554
+ /** `'acp'` | `'wrapped_cli'`; open-ended for a future carrier. */
1555
+ carrier: 'acp' | 'wrapped_cli' | (string & {});
1556
+ /** The unit's role (`creator` | `evaluator` | `neutral`). */
1557
+ role: 'creator' | 'evaluator' | 'neutral' | (string & {});
1558
+ /** The tool the seat invoked (`Bash`, `bash`, `shell`, …). */
1559
+ tool: string;
1560
+ /** The command text the seat sent. */
1561
+ command: string;
1562
+ reason: string;
1563
+ /** What the seat was told to do instead ("delivery is performed by the run's deliver phase"). */
1564
+ remedy: string;
1565
+ };
1566
+
1414
1567
  export type GateEvidenceEvent =
1415
1568
  | EvaluatorMutatedWorktreeEvent
1416
1569
  | RepoChecksEvaluatedEvent
1417
1570
  | WorktreeRestoredEvent
1418
1571
  | DeliverLiftEvaluatedEvent
1419
- | EvaluatorToolCallDeniedEvent;
1572
+ | EvaluatorToolCallDeniedEvent
1573
+ | WorkerToolCallDeniedEvent;
1420
1574
 
1421
1575
  // ── P2 decisions-full observability events (wicked-core EVT-001/012/013) ────
1422
1576
 
@@ -1488,17 +1642,64 @@ export interface UnitPlannedEvent {
1488
1642
  executor_type: 'agent' | 'tool';
1489
1643
  }
1490
1644
 
1491
- /** Foundation wave: a unit was distributed with full routing detail. */
1645
+ /**
1646
+ * Foundation wave: a unit was distributed with full routing detail.
1647
+ *
1648
+ * WIRE SPELLING (api-types 0.36.0, crew#533 follow-through): the engine's `CoreEvent::to_json` and
1649
+ * the napi frames spell these fields camelCase — `routingMethod`, `agreementPct`, `returned`,
1650
+ * `seated`, `dissent`, `degradedReason`, `seatConstraint` — exactly as `wicked-core-ts`'s own
1651
+ * `UnitDistributedEventJson` declares them; `packages/crew/tests/wire-contract.test.ts` pins this
1652
+ * interface against that type AND against a recorded frame. Pre-0.36 this interface declared the
1653
+ * snake_case spellings, which the engine never emitted — a consumer reading `degraded_reason` got
1654
+ * `undefined` and rendered a benched council as whole. The snake_case names stay for ONE minor as
1655
+ * `@deprecated` optional aliases (a normalising relay may still produce them); consumers read the
1656
+ * camelCase names. Every camelCase `Option` field is emitted unconditionally: `null`, never absent.
1657
+ */
1492
1658
  export interface UnitDistributedEvent {
1493
1659
  type: 'unitDistributed';
1494
1660
  session: string;
1495
1661
  ord: number;
1662
+ /** The roster key of the assigned seat. */
1496
1663
  cli: string;
1497
- routing_method: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
1498
- agreement_pct: number | null;
1664
+ /** How the seat was chosen: the council verdict, a degrade to the first candidate, an
1665
+ * evaluator ≠ creator reassignment, or a deterministic tool execution. */
1666
+ routingMethod: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
1667
+ agreementPct: number | null;
1668
+ /** Ballots that came back. Read against `seated`. */
1499
1669
  returned: number | null;
1670
+ /** Seats CONVENED for the council that produced this assignment (`null` = unknown / not a council). */
1671
+ seated: number | null;
1500
1672
  dissent: number | null;
1501
- degraded_reason: string | null;
1673
+ /**
1674
+ * WHY the routing was degraded. Since wave 6 (F-7R2-006) the engine sets it on EVERY routing arm
1675
+ * whenever the eligible seat set is smaller than the configured roster — `"4 of 5 seats benched:
1676
+ * codex (signed out — launcher), pi (unauthenticated — ballot), …"` — not only for its `degraded`
1677
+ * arm, so a council that held on a fraction of its seats reads as degraded. `null` when whole.
1678
+ */
1679
+ degradedReason: string | null;
1680
+ /** WHY the candidate seats were narrowed BEFORE the council voted (core#401): a non-portable
1681
+ * skill constrained the unit to a claude seat. `null` when every roster seat was a candidate. */
1682
+ seatConstraint: string | null;
1683
+ /** @deprecated api-types 0.36.0 — the engine emits `routingMethod`; removed in 0.37. */
1684
+ routing_method?: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
1685
+ /** @deprecated api-types 0.36.0 — the engine emits `agreementPct`; removed in 0.37. */
1686
+ agreement_pct?: number | null;
1687
+ /** @deprecated api-types 0.36.0 — the engine emits `degradedReason`; removed in 0.37. */
1688
+ degraded_reason?: string | null;
1689
+ }
1690
+
1691
+ /** One seat the wave-6 engine BENCHED for a run (`AgentSession.benched_seats`, F-7R2-006): never
1692
+ * convened, never a failover or judge target, named in `unitDistributed.degradedReason`. */
1693
+ export interface BenchedSeat {
1694
+ /** The roster key. */
1695
+ cli: string;
1696
+ /** Why — the launcher's words (`signed out`) or the engine's classification (`not_logged_in`,
1697
+ * `unauthenticated`). */
1698
+ reason: string;
1699
+ /** Who benched it: `launcher` (the roster's health probe — crew's `council_eligible`), `ballot`
1700
+ * (a council seat failure), `worker` (a unit's worker failed with an auth refusal), `judge`
1701
+ * (the seat failed while judging another unit — wicked-core#449 @ 9e11685). */
1702
+ source: 'launcher' | 'ballot' | 'worker' | 'judge' | (string & {});
1502
1703
  }
1503
1704
 
1504
1705
  // ── Worker injection + reassignment events (core#93) ──────────────────────────
@@ -1962,8 +2163,40 @@ export interface SkillsManifestResponse {
1962
2163
  root: string;
1963
2164
  /** The VERIFIED published snapshot `current` resolves to, or `null` before the first publish.
1964
2165
  * `path` is the absolute REAL path of `snapshots/<gen>` — byte-identical to the one input the
1965
- * engine is handed (`WICKED_SKILLS_SNAPSHOT`; design v3.1 §2). */
1966
- current: { gen: number; path: string } | null;
2166
+ * engine is handed (`WICKED_SKILLS_SNAPSHOT`; design v3.1 §2). `rules` / `drift` (api-types
2167
+ * 0.36.0, F-083 / crew#535) ride beside it on a daemon ≥ 0.7.30 — absent on an older one. */
2168
+ current: {
2169
+ gen: number;
2170
+ path: string;
2171
+ /** The portability rules the generation was published under vs the rules this daemon runs:
2172
+ * `recorded` is `null` for a generation predating the identity (0.7.29 and earlier);
2173
+ * `stale: true` = they differ and the daemon raised `skills.stale-rules`. */
2174
+ rules?: {
2175
+ recorded: PortabilityRulesIdentity | null;
2176
+ running: PortabilityRulesIdentity;
2177
+ stale: boolean;
2178
+ };
2179
+ /** The rows whose portability derives differently under the running rules than the snapshot
2180
+ * recorded — the `skills.stale-rules` warning names up to five; the list carries the rest.
2181
+ * `recorded.reasons` is `null` for a row written before per-reason portability (0.34.0). */
2182
+ drift?: SnapshotRowDrift[];
2183
+ } | null;
2184
+ }
2185
+
2186
+ /** The identity of a portability-rule table (api-types 0.36.0, F-083): its version and the
2187
+ * sha256 of the committed parity fixture (`tests/fixtures/portability_rules.json`). */
2188
+ export interface PortabilityRulesIdentity {
2189
+ version: number;
2190
+ sha256: string;
2191
+ }
2192
+
2193
+ /** One snapshot row whose portability the RUNNING rules derive differently than the snapshot
2194
+ * recorded (api-types 0.36.0, F-083) — see `SkillsManifestResponse.current.drift`. */
2195
+ export interface SnapshotRowDrift {
2196
+ name: string;
2197
+ recorded: { portable: boolean; reasons: SkillPortabilityReason[] | null };
2198
+ /** What the RUNNING rules derive for the row — the same per-reason shape `SkillEntry.portability` carries. */
2199
+ derived: SkillPortability;
1967
2200
  }
1968
2201
 
1969
2202
  export interface SkillFileEntry {
@@ -2565,6 +2798,148 @@ export interface TestingReconResponse {
2565
2798
  projectAttachError?: string;
2566
2799
  }
2567
2800
 
2801
+ // ── The governed test-authoring launch (wave 6; api-types 0.36.0) ──────────────────────────────
2802
+
2803
+ /**
2804
+ * The id of the governed test-authoring workflow the daemon serves (`GET /workflows` lists it, not
2805
+ * `is_system` — an operator-selectable work mode): recon (`wicked-garden-qe` plan) → author
2806
+ * (creator, evidence-floor pinned, `wicked-garden-qe` author) → verify (a TOOL phase that RUNS every
2807
+ * produced test under the repository's own harness — vitest/jest/pytest/Playwright — and FAILS the
2808
+ * unit when one fails or was never executed) → review (evaluator ≠ creator, `wicked-garden-qe`
2809
+ * review) → the ENGINE's deliver phase (appended per run; never a worker's `gh pr create`).
2810
+ * F-7R2-003/004/005/012/014/015 + acceptance R4-r2.
2811
+ */
2812
+ export type QeAuthorTestsWorkflowId = 'qe-author-tests';
2813
+
2814
+ /**
2815
+ * Body of `POST /testing/author` — the Testing page's "New test". Same scope wire as
2816
+ * {@link TestingReconBody} (`repoRefs` and/or `projectId`, resolved server-side), but the scope
2817
+ * MUST resolve to ≥ 1 repo (a test-authoring run writes into a repository; an unscoped author is a
2818
+ * 400). One governed `qe-author-tests` run per resolved repo, each filed under the repo's
2819
+ * `qe-tests-<repo name>` label group (`RunGroup` on `GET /campaigns`).
2820
+ */
2821
+ export interface TestingAuthorBody {
2822
+ /** The operator's intent — what to test — verbatim; the run's problem statement. */
2823
+ problem: string;
2824
+ /** The project to FILE the runs into. Alone: the scope is the project's `crew.repo` members. */
2825
+ projectId?: string;
2826
+ /**
2827
+ * The repos to author into (registry id or name). With `projectId`, THIS is the scope and the
2828
+ * project is the filing only (a NARROWED project scope — studio #263 F-4): the runs are filed
2829
+ * into the project without inheriting its other repo members, so a skin with repo chips names
2830
+ * the repos and the project once instead of fanning one `POST /runs` per repo (one deliver/PR
2831
+ * each). Unlike {@link TestingReconBody}, where both fields union. The 201 says which was used
2832
+ * (`scope`).
2833
+ */
2834
+ repoRefs?: string[];
2835
+ /** EXPLICITLY launch unattended (no intake gate). Default `false`: each run pauses at its intake
2836
+ * gate (`before:1`) with the plan on the table before any unit runs. */
2837
+ ungated?: boolean;
2838
+ /** `pr` (default) — the ENGINE's deliver phase opens the PR; `none` — the tests stay on the run
2839
+ * branch (`delivery: 'stranded'` on the wire, liftable via `POST /runs/:id/deliver`). */
2840
+ deliver?: 'pr' | 'none';
2841
+ }
2842
+
2843
+ /** One planned phase as the intake gate shows it — derived from the workflow DEFINITION. */
2844
+ export interface WorkflowPlanPhase {
2845
+ id: string;
2846
+ kind: StageKindPhase;
2847
+ role: PhaseRole;
2848
+ executor: 'agent' | 'tool';
2849
+ /** The garden skill the phase routes through (`wicked-garden-qe`), `null` for a tool phase. */
2850
+ skillRef: string | null;
2851
+ /** `auto` | `human` (unconditional confirm) | `human_if_not_pass` (a not-pass verdict escalates). */
2852
+ gate: 'auto' | 'human' | 'human_if_not_pass';
2853
+ executesCode: boolean;
2854
+ /** `true` for the phase the ENGINE appends and owns (the deliver phase) — not in the def. */
2855
+ engine?: boolean;
2856
+ }
2857
+
2858
+ /** The plan the intake gate shows (F-7R2-008): the phases in order + the seats a council may
2859
+ * pick from (the launcher's eligible roster — benched seats excluded). */
2860
+ export interface WorkflowPlan {
2861
+ workflow: string;
2862
+ phases: WorkflowPlanPhase[];
2863
+ seats: string[];
2864
+ }
2865
+
2866
+ /** One launched authoring run and the label group it was filed under. */
2867
+ export interface TestingAuthorRun {
2868
+ runId: string;
2869
+ repoRef: string;
2870
+ /** `qe-tests-<repo name>` — the `RunGroup.label` on `GET /campaigns`. */
2871
+ label: string;
2872
+ }
2873
+
2874
+ /**
2875
+ * The `POST /testing/author` 201 body. `runIds` is the source of truth (one per resolved repo in
2876
+ * the caller's order); `runId` is its first entry. `plan` is what the intake card renders before
2877
+ * approval; `gate` says whether the runs paused there. `campaignRegistered` is always `false`: an
2878
+ * author launch is filed as label groups, never an engine campaign (campaign nodes are
2879
+ * engine-launched and would not receive the daemon's deliver composition).
2880
+ */
2881
+ export interface TestingAuthorResponse {
2882
+ runId: string;
2883
+ runIds: string[];
2884
+ workflow: QeAuthorTestsWorkflowId;
2885
+ runs: TestingAuthorRun[];
2886
+ gate: 'before:1' | 'none';
2887
+ deliver: 'pr' | 'none';
2888
+ plan: WorkflowPlan;
2889
+ /** How the repos were chosen: `repoRefs` — the named repos (a `projectId`, when given, was the
2890
+ * filing only); `project` — the project's `crew.repo` members. Absent on a daemon predating it. */
2891
+ scope?: 'repoRefs' | 'project';
2892
+ campaignRegistered: false;
2893
+ }
2894
+
2895
+ /** One produced test file as the verify phase judged it. */
2896
+ export interface TestSetFile {
2897
+ path: string;
2898
+ /** `playwright` | `playwright-python` | `vitest` | `jest` | `pytest` | `python` | `unknown`. */
2899
+ harness: string;
2900
+ status: 'passed' | 'failed' | 'not-executed';
2901
+ }
2902
+
2903
+ /**
2904
+ * A registered TEST SET (wave 6, F-7R2-014; api-types 0.36.0) — the produced tests of a terminal
2905
+ * `qe-author-tests` run, read back from its verify phase's `QE-VERIFY` report and recorded as a
2906
+ * durable `testing.testset.registered` audit entry the daemon hydrates at boot. Served as
2907
+ * `CampaignsListResponse.test_sets` — what the Test landing counts. Deny-dominates: a run whose
2908
+ * verify phase FAILED registers too (`verified: false`, counts intact) so a red set is shown, never
2909
+ * hidden; a run that never reached its verdict registers with zero counts and `plan: null`.
2910
+ */
2911
+ export interface TestSet {
2912
+ /** `testset-<run id>` — one set per producing run. */
2913
+ id: string;
2914
+ run_id: string;
2915
+ workflow_id: QeAuthorTestsWorkflowId;
2916
+ /** The `RunGroup.label` the launch filed the run under, when it did. */
2917
+ label?: string;
2918
+ repo_ref: string | null;
2919
+ repo_name?: string;
2920
+ /** Unix millis. */
2921
+ registered_at: number;
2922
+ /** The producing run's terminal status. */
2923
+ run_status: SessionStatus | (string & {});
2924
+ /** The verify unit's status (`done` | `rejected` | …); `null` when the run never planned one. */
2925
+ verify_status: string | null;
2926
+ /** `true` ONLY when the verify phase passed: ≥ 1 produced test, every one executed and green,
2927
+ * the repository checks green, the PLAN present. */
2928
+ verified: boolean;
2929
+ files: TestSetFile[];
2930
+ produced: number;
2931
+ executed: number;
2932
+ passed: number;
2933
+ failed: number;
2934
+ not_executed: number;
2935
+ /** The produced `tests/PLAN-*.md`, `null` when none was produced. */
2936
+ plan: string | null;
2937
+ /** The harnesses the produced tests ran under (unique, first-use order). */
2938
+ harnesses: string[];
2939
+ /** The delivered PR, when the engine's deliver phase opened one. */
2940
+ deliverUrl?: string;
2941
+ }
2942
+
2568
2943
  // ── Governance claims (crew#40/43) ─────────────────────────────────────────────
2569
2944
 
2570
2945
  /**
@@ -3329,6 +3704,12 @@ export interface InteractiveStatusPosted {
3329
3704
  message?: string;
3330
3705
  /** The edit seam stamps the handoff version it is answering. */
3331
3706
  version?: number;
3707
+ /** Wave 6 (F-4R2-005 root fix; api-types 0.36.0): the governed run this narration is about, so a
3708
+ * skin keys the thread per run. Absent on a pre-launch status and on a pre-0.36 daemon. */
3709
+ run_id?: string;
3710
+ /** Wave 6: the unit (ord) the line narrates — the latest unit-scoped engine frame's `ord`, so a
3711
+ * skin renders one council at a time. Absent before the first unit-scoped frame. */
3712
+ unit_ord?: number;
3332
3713
  }
3333
3714
 
3334
3715
  /**
@@ -3357,6 +3738,62 @@ export interface InteractiveDocSummary {
3357
3738
  projectId: string;
3358
3739
  }
3359
3740
 
3741
+ /**
3742
+ * `GET /api/v1/interactive/docs` (api-types 0.36.0, studio #263) — every interactive document across
3743
+ * projects, listed by the DAEMON from disk WITHOUT spawning a bridge: each project's docs root
3744
+ * (the per-project `interactiveRoot` binding, else `WICKED_INTERACTIVE_ROOT`, else the default
3745
+ * root / its `projects/<id>` partition), each slug-named child carrying a `versions.json`, read by
3746
+ * the bridge's own `listDocs` rules — plus what only the daemon knows: the seams that answered
3747
+ * the document and the governed runs they launched (the handoff ledgers). The per-project
3748
+ * `GET /projects/:id/interactive/api/docs` spawns one bridge per project (≈60 s cold start) — a
3749
+ * skin must never fan that out on mount; this is the listing it mounts with. `?includeRetired=1`
3750
+ * lists tombstoned rows too.
3751
+ */
3752
+ export interface InteractiveDocsListing {
3753
+ /** Newest first (by `updatedAt`), then by name. */
3754
+ docs: InteractiveDocIndexRow[];
3755
+ /** Project docs roots the daemon could not read (or a partition its containment walk refused),
3756
+ * with the reason — never silently dropped. `[]` when every root was readable. */
3757
+ unreachable: InteractiveDocsUnreachable[];
3758
+ }
3759
+
3760
+ /** The seams that can answer a document (the handoff ledgers). */
3761
+ export type InteractiveSeamKind = 'draft' | 'edit' | 'chat' | 'demo' | (string & {});
3762
+
3763
+ /** One document on the daemon-wide listing (api-types 0.36.0). */
3764
+ export interface InteractiveDocIndexRow {
3765
+ /** The project whose docs root holds the document. A root SHARED by several projects (an
3766
+ * explicit `interactiveRoot` binding, or `WICKED_INTERACTIVE_ROOT` applying to all) lists once,
3767
+ * under the first project in listing order (the synthesized `default` first). */
3768
+ projectId: string;
3769
+ /** The doc name (slug). */
3770
+ name: string;
3771
+ /** Manifest `kind`; a manifest without one lists as `doc`. */
3772
+ kind: 'doc' | 'html' | 'source' | 'demo' | (string & {});
3773
+ /** Head version; `null` when the manifest carries none. */
3774
+ head: number | null;
3775
+ /** Lineage size. */
3776
+ versions: number;
3777
+ /** ISO-8601 of the head (last) version, or `null` when the lineage is empty. */
3778
+ updatedAt: string | null;
3779
+ /** Present only on a retired (tombstoned) row, listed only with `?includeRetired=1`. */
3780
+ retired?: true;
3781
+ /** ISO-8601 retirement timestamp; present with `retired`. */
3782
+ retiredAt?: string;
3783
+ /** The seams that answered this document, from the handoff ledgers (`[]` = none yet). */
3784
+ kinds: InteractiveSeamKind[];
3785
+ /** The governed runs those seams launched for it (ledger order) — the doc ↔ run binding. */
3786
+ runs: string[];
3787
+ }
3788
+
3789
+ /** A project docs root the listing could not read (api-types 0.36.0). */
3790
+ export interface InteractiveDocsUnreachable {
3791
+ projectId: string;
3792
+ /** The resolved root, or `null` when the containment walk refused the partition before resolving one. */
3793
+ root: string | null;
3794
+ error: string;
3795
+ }
3796
+
3360
3797
  /**
3361
3798
  * One normalized entry of the merged project activity feed
3362
3799
  * (`GET /projects/:id/activity`, ADR §5.2): core events of member runs/chats
@@ -3491,9 +3928,22 @@ export interface ChatSeatOutcome {
3491
3928
  * REQUESTED seat (`clis`) the engine refused (`ChatSeatOutcome.ok: false`, its `error` repeated
3492
3929
  * here as `reason`). One list for the scope card and the thread to read.
3493
3930
  */
3931
+ /**
3932
+ * Why a seat was not seated (api-types 0.36.0, F-A45-011): `auth` — signed out (the probe, or the
3933
+ * seat's own "no credential" report); `scope` — the scoped-chat admission rule; `bench` — benched by
3934
+ * this daemon's recent councils; `budget` — the engine did not warm it within its dispatch budget
3935
+ * (the seat timed out or was dropped at dispatch); `engine` — the engine refused it with its own
3936
+ * reason. Open-ended so a newer daemon's source parses in an older skin.
3937
+ */
3938
+ export type ChatRefusalSource = 'auth' | 'scope' | 'bench' | 'budget' | 'engine' | (string & {});
3939
+
3494
3940
  export interface ChatSeatRefusal {
3495
3941
  cliKey: string;
3496
3942
  reason: string;
3943
+ /** api-types 0.36.0 (F-A45-011): the cause class. Absent on a daemon predating the field. Since
3944
+ * 0.36.0 EVERY requested-or-defaulted seat that is not in `seats` as warm has an entry — a seat
3945
+ * the engine DROPPED at dispatch (absent from `seats` altogether) included, never a silent gap. */
3946
+ source?: ChatRefusalSource;
3497
3947
  }
3498
3948
 
3499
3949
  /** `POST /chats` → 201. */
@@ -3522,6 +3972,8 @@ export type ChatSeatRefusedFrame = {
3522
3972
  chat: string;
3523
3973
  cliKey: string;
3524
3974
  reason: string;
3975
+ /** api-types 0.36.0 (F-A45-011): the cause class — see {@link ChatRefusalSource}. */
3976
+ source?: ChatRefusalSource;
3525
3977
  project_id?: string;
3526
3978
  };
3527
3979
 
@@ -3551,6 +4003,10 @@ export interface ChatDetailResponse {
3551
4003
  seats: string[];
3552
4004
  /** The scope recorded at open; `null` for a chat this daemon did not open (or after a restart). */
3553
4005
  scope: ChatScope | null;
4006
+ /** The seats refused at open (api-types 0.36.0, F-A45-011) — the same list the 201 carried, so
4007
+ * the admission copy survives a reload; `null` for a chat this daemon did not open; absent on a
4008
+ * daemon predating the field. */
4009
+ refused?: ChatSeatRefusal[] | null;
3554
4010
  }
3555
4011
 
3556
4012
  // ── Project code graph (DES-PROJECT-001; the co-located multi-repo graph) ──────
@@ -3945,6 +4401,9 @@ export interface RunGroup {
3945
4401
  export interface CampaignsListResponse {
3946
4402
  campaigns: Campaign[];
3947
4403
  groups: RunGroup[];
4404
+ /** The registered test sets (wave 6, F-7R2-014; api-types 0.36.0 — ADDITIVE: a pre-0.36 daemon
4405
+ * omits it). Newest first. See {@link TestSet}. */
4406
+ test_sets?: TestSet[];
3948
4407
  }
3949
4408
 
3950
4409
  /**
@@ -4239,8 +4698,18 @@ export interface DiagnosticsSkillsFinding {
4239
4698
  * (`error`, api-types 0.29.0) = `manifest.json` could not be read when diagnostics were taken
4240
4699
  * (corrupt, unreadable, or the root no longer the one the store bound) — reported as
4241
4700
  * `config-error` with the cause instead of the stale boot outcome; the exported engine input is
4242
- * unchanged until the daemon restarts. */
4243
- kind: 'skills.fallback' | 'skills.blocked' | 'skills.config' | 'skills.source' | 'skills.manifest';
4701
+ * unchanged until the daemon restarts; `skills.stale-rules` (`warning`, api-types 0.36.0, F-083 /
4702
+ * crew#535) = the CURRENT generation was published under OTHER portability rules than the daemon
4703
+ * now runs — accepted (the snapshot is never rewritten; the runtime stays `published`), the rows
4704
+ * that now derive differently are named (`SkillsManifestResponse.current.drift`), and a publish
4705
+ * records the running rules and clears it. */
4706
+ kind:
4707
+ | 'skills.fallback'
4708
+ | 'skills.blocked'
4709
+ | 'skills.config'
4710
+ | 'skills.source'
4711
+ | 'skills.manifest'
4712
+ | 'skills.stale-rules';
4244
4713
  severity: 'warning' | 'error';
4245
4714
  message: string;
4246
4715
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.35.0",
3
+ "version": "0.36.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",