/** * The roster crew hands the ENGINE (`LaunchOptions.clisJson`) vs the roster crew serves the STUDIO * (`GET /roster`) — one seat, two audiences, and the fields must not leak across (wave 6, the crew * half of F-7R2-006). * * `GET /roster` decorates every registry seat with crew's own readings: runtime `health` * (`{status: 'active', since, lastErrorAt?}` — seat-health.ts; `inactive` is no longer produced), `signed_in`, `auth`, * `free_tier(_source)`, `council_eligible` + `council_ineligible_reason` (seat-standing.ts; * `council_bench` is gone — R5b — though the stripper below still names it, so a seat from an older * daemon's roster cannot round-trip it into the engine). The studio's launch form round-trips those seats into `clisJson` verbatim, * which was fine while the engine ignored every unknown field — but the wave-6 engine grew its own * `AgenticCli.health: Option` (the launcher's usability verdict * that benches a seat for the run). Same key, different shape: a round-tripped crew `health` * (`{status: …}`) would fail the engine's deserializer with "missing field `usable`" and refuse the * launch. So the boundary translates: * * - crew's standing fields are STRIPPED (they are the studio's, not the engine's); * - `council_eligible` + `work_eligible` become the engine's `health` (crew#916, wicked-core#572: * the seat's two roles are independent, so neither alone benches it): either `true` ⇒ * `{usable: true}` (the engine reads the record's own `enabled_for_council` / * `seat_eligible_for_work` for which role); neither `true` and one `false` (the daemon serves both, * so: both `false`) ⇒ `{usable: false, reason}` — the seat * is BENCHED for the run (never convened, never a failover or judge target, named in * `unitDistributed.degradedReason`); otherwise no `health` (unknown — the engine treats the seat * as eligible until it fails authentication in the run); * - a seat that already carries an ENGINE-shaped `health` (`usable` is a boolean) is kept as sent. * * An engine predating the field ignores `health` (the `AgenticCli` deserializer has no * `deny_unknown_fields`), so the stamp is additive there and effective on the wave-6 engine. */ import type { CampaignDef } from './types.js'; /** The crew-only readings `GET /roster` adds to a registry seat — never handed to the engine. */ export declare const CREW_ONLY_SEAT_FIELDS: ReadonlySet; /** The engine's `AgenticCli.health` (wicked-core `SeatHealth`, wave 6). */ export interface EngineSeatHealth { usable: boolean; reason?: string; } /** * The SHORT bench reason the engine renders inline — `"codex (signed out — launcher)"` in * `unitDistributed.degradedReason` — derived from the standing readings themselves (seat-standing.ts * `seatStanding` decides `council_eligible` / `work_eligible`; this names the one cause in two or * three words), falling back to the first clause of the standing's own reason for a cause this table * does not know (a shared gate — signed out, benched — leads both reasons, so the council's is the * gate's whenever one holds). */ export declare function shortBenchReason(seat: Record): string | undefined; /** One seat translated for the engine (see the module doc). Non-object entries pass through so the * engine reports its own parse error rather than crew inventing one. */ export declare function toEngineSeat(seat: unknown): unknown; /** Translate a whole roster. */ export declare function toEngineRoster(seats: readonly unknown[]): unknown[]; /** * Translate a `clisJson` string for the engine. A string that does not parse to a JSON array is * returned UNCHANGED — the engine's own "invalid clisJson" refusal is the honest answer, not a * crew-side rewrite of something crew could not read. */ export declare function engineRosterJson(clisJson: string): string; /** * Translate a `CampaignDef` for the engine (F-086). Every node's `run_spec.clis` goes through * {@link toEngineRoster} — the ONLY seat list the def carries (`CampaignDef` has no def-level * roster; `campaigns/plan.ts` stamps the roster per node). `CoreAdapter.launchCampaign` used to * `JSON.stringify(def)` verbatim, so a def built from `rosterWithStanding()` (`POST /testing/recon`) * reached core-ts ≥ 0.7.22 (wicked-core#449) with crew's `health {status}` intact and the engine * refused it ("defJson is not a valid CampaignDef: missing field `usable`") — the campaign seam now * translates exactly as `launchRun` does through {@link engineRosterJson}. * * Non-mutating: the caller's def, nodes and run_specs are left as built (the route's audit record * and the recon response read them after the launch). A node whose `clis` is not an array passes * through unchanged so the engine reports its own parse error, the {@link engineRosterJson} rule. */ export declare function engineCampaignDef(def: CampaignDef): CampaignDef; /** `POST /runs` 409 `code` when the engine refuses a launch for want of an eligible seat (crew#556). */ export declare const NO_ELIGIBLE_SEAT_CODE: "no_eligible_seat"; /** The remedy in operator terms — the engine's own closing clause, plus where the standing shows. */ export declare const NO_ELIGIBLE_SEAT_REMEDY: string; /** * wicked-core#461's typed `NoEligibleSeat` intake refusal, as its Display reaches crew through the * napi rejection: `no eligible seat for : — sign a seat in, or add one, before * launching`. The engine raises it synchronously at `launch_run` when the plan needs a seat and every * seat of a non-empty roster was benched by the launcher (`health.usable: false` — crew's * `council_eligible: false`, stamped by {@link toEngineRoster}); nothing is persisted, nothing * reaches the wire. The napi seam carries only the message, so the recogniser is the message's * shape (the `isEngineStateHomeRefusal` rule); a message of any other shape is not this refusal. */ export declare function parseNoEligibleSeat(message: string): { runId: string; benched: string; } | null; /** The typed 409 body (`NoEligibleSeatBody` in wicked-crew-api-types) for a recognised refusal. */ export declare function noEligibleSeatBody(message: string, refused: { runId: string; benched: string; }): { error: string; code: typeof NO_ELIGIBLE_SEAT_CODE; runId: string; benched: string; remedy: string; }; /** The seat keys of a roster the ENGINE would convene — every seat with a role and not benched by its `health`. */ export declare function eligibleSeatKeys(seats: readonly unknown[]): string[]; //# sourceMappingURL=engine-roster.d.ts.map