/** * "Considered · set aside · cited (unchecked)" (DES-decision-capture §4.7, DC-S7). * * - **Considered** = the engine's `considerRules({projects:[project]}).in_force` for the turn's or * unit's project (project rules + global ones). On an engine without the binding, the global * rules alone, and the Consideration says so (`source: 'global-only'`). * - **Set aside** = the engine's `set_aside` (out of scope / replaced / retired) plus crew's own * pending candidates for that project — decisions `offered` but not yet confirmed. * - **Cited (unchecked)** = every `[rule:]` the persisted reply or step wrote. An id in the * in-force set is "cited by the step — unchecked"; any other id is unverified. It is NEVER * summed into a "followed" count (B4): advisory rules never decide, so nothing here can know * whether a rule was followed — DES-rule-check supplies that verdict. * * The same object answers `GET /chats/:id/turns/:turnId/considered` and * `GET /runs/:id/units/:unitKey/considered?attempt=`, and one `wicked.crew.rule.considered` fact * (counts and ids, never words) is emitted when a turn or a unit attempt lands — keyed per turn * and per (run, ord, attempt), so a re-dispatch is its own record (review N5). */ import { RULE_CITED_LABEL, extractRuleCitations } from '../api/chat-citations.js'; import type { ChatTranscriptStore } from '../api/chat-transcripts.js'; import type { ConformanceRule, Consideration, SessionView } from '../core/types.js'; import { type DecisionBusEmit } from './events.js'; import type { DecisionLedger } from './ledger.js'; import { rulesPreface } from './rules-text.js'; export { RULE_CITED_LABEL, extractRuleCitations, rulesPreface }; /** What the service needs from the engine; every method optional so a partial stub never throws. */ export interface ConsiderAdapter { projectRulesSupported?(): boolean; listConformanceRules?(): Promise; considerRules?(query: { projects?: string[]; steering_type?: string; }): Promise<{ in_force: ConformanceRule[]; set_aside: Array<{ id: string; statement: string; reason: 'out_of_scope' | 'replaced' | 'retired'; }>; }>; sessionsDetail?(): Promise; workOutput?(unitId: string): Promise; } export interface InForceRead { rules: ConformanceRule[]; setAside: Array<{ id: string; statement: string; reason: 'out_of_scope' | 'replaced' | 'retired'; }>; source: Consideration['source']; } /** * The in-force rules for a project. `considerRules` when the engine has it; else the global, * non-retired rules; else (no engine read at all) nothing, said as `unavailable`. Never throws. */ export declare function readInForce(adapter: ConsiderAdapter, projectId: string | null, log?: (m: string) => void): Promise; export interface ConsiderationDeps { adapter: ConsiderAdapter; /** Crew's own pending candidates (`offered`) become `not_confirmed` set-asides. Absent = none. */ ledger?: DecisionLedger; /** The chat turn's persisted replies. Absent = no chat considerations. */ transcripts?: ChatTranscriptStore; projectOf: (id: string) => string | undefined; emit?: DecisionBusEmit | null; log?: (msg: string) => void; } export declare class ConsiderationService { private readonly deps; /** chat → the rule ids its seats have been told about (the statement at open, then every preface). */ private readonly seen; constructor(deps: ConsiderationDeps); private log; inForceFor(projectId: string | null): Promise; /** The in-force ids, or `null` when no engine read was possible (a citation then stays unchecked). */ inForceIds(projectId: string | null): Promise | null>; /** The chat opened with these rules in its statement. */ noteChatOpen(chat: string, rules: ReadonlyArray): void; /** * The preface the next send carries, or `null`: the rules in force now that the seats have not * been told about. A chat this daemon did not open (a restart) is SEEDED on its first send — * nothing is known about what its seats were told, so the current set stands in for the open * statement and that send carries no preface; a rule that lands after the seed is new to the * seats and IS prefaced on the send after (codex r1, wording fixed: "seeded, then prefaced"). */ prefaceForSend(chat: string, opts?: { inForce?: ReadonlyArray; }): Promise; /** * {@link prefaceForSend} in two steps: the preface now, the bookkeeping ("told") only when the * caller's send is ACCEPTED (`commit`). A send the engine refuses — a path not at its turn gate, * a proposal that fails — must not consume the fresh rules, or the retry delivers nothing * (codex on #808 r2, 7). The seed of an unknown chat is recorded at once: nothing was told, * and the current set stands in for the open statement either way. */ pendingPreface(chat: string, opts?: { inForce?: ReadonlyArray; }): Promise<{ preface: string | null; commit: () => void; }>; chatClosed(chat: string): void; private notConfirmed; private build; /** The Consideration of one chat turn, or `null` when the transcript holds no such turn. */ forChatTurn(chat: string, turnId: string): Promise; /** The Consideration of one unit attempt (`unitKey` as `resolveUnit` accepts it), or `null`. */ forUnit(runId: string, unitKey: string, attempt?: number): Promise; private emit; /** A chat turn's replies all landed: compute and emit. Never throws. */ onChatTurn(chat: string, turnId: string): Promise; /** A unit attempt's output was captured: compute and emit. Never throws. */ onUnitCaptured(runId: string, ord: number, attempt: number): Promise; } //# sourceMappingURL=consider.d.ts.map