/** * Decision Memory module for CLEO BRAIN. * Uses brain.db via BrainDataAccessor for persistent storage. * * Provides functions to store, recall, search, and update decisions * with sequential ID generation (D001, D002, ...). * * @task T5155 * @epic T5149 */ import type { DecideOptions } from '../decide/client.js'; import type { DecisionSiteMode } from '../decide/site.js'; import type { BrainDecisionRow } from '../store/schema/memory-schema.js'; /** Parameters for storing a new decision. */ export interface StoreDecisionParams { type: BrainDecisionRow['type']; decision: string; rationale: string; confidence: BrainDecisionRow['confidence']; outcome?: BrainDecisionRow['outcome']; alternatives?: string[]; contextEpicId?: string; contextTaskId?: string; contextPhase?: string; /** * Relative or absolute path to the ADR document on disk. * * @see T1826 Decision Storage Consolidation */ adrPath?: string; /** * ID of the `brain_decisions` row this decision supersedes. * * When provided, the referenced row's `supersededBy` is updated and its * `confirmationState` is set to `'superseded'`. */ supersedes?: string; /** * Lifecycle state in the confirmation workflow. * * Defaults to `'proposed'` for new rows. */ confirmationState?: BrainDecisionRow['confirmationState']; /** * Who approved / originated this decision. * * Defaults to `'agent'` for new rows. */ decidedBy?: BrainDecisionRow['decidedBy']; /** * T992: Internal flag — when true, bypasses the verifyAndStore gate. * Set only by storeVerifiedCandidate in extraction-gate.ts to avoid * infinite recursion (gate → storeVerifiedCandidate → storeDecision → gate). * External callers MUST NOT set this flag. */ _skipGate?: boolean; /** * Explicitly request the full conflict validation: the generative (T1828) * check and rejection below the confidence threshold. Without it an ADR * write still runs the System One contradiction site advisorily (T12715): * no generative model call, never rejects. */ validateWithLlm?: boolean; } /** Parameters for searching decisions. */ export interface SearchDecisionParams { type?: BrainDecisionRow['type']; confidence?: BrainDecisionRow['confidence']; outcome?: BrainDecisionRow['outcome']; query?: string; limit?: number; } /** Parameters for listing decisions. */ export interface ListDecisionParams { limit?: number; offset?: number; } /** * Result shape returned by {@link validateDecisionConflicts}. * * @task T1828 */ export interface DecisionValidationResult { /** Near-duplicate or collision entries found (by decision ID). */ collisions: string[]; /** Decisions that contradict the candidate (by decision ID). */ contradictions: string[]; /** Supersession-graph integrity violations detected. */ supersession_graph_violations: string[]; /** Overall validator confidence (0.0–1.0). */ confidence: number; } /** * Options for {@link validateDecisionConflicts}: the System One contradiction * check (T12493). Every field is optional; production callers pass only * `projectRoot`. */ export interface ValidateDecisionConflictsOptions { /** Explicit mode; overrides `decide.sites.decisionContradiction` when a provider is configured. */ mode?: DecisionSiteMode; /** Explicit opt-in for the generative (T1828) check; overrides `decide.generativeFallback.decisionContradiction`. */ llmTier?: boolean; /** Provider, connection, budget, cache and audit wiring forwarded to `decide()`. Tests inject a stub here. */ decide?: DecideOptions; /** Project root for config lookup and the audit sink. */ projectRoot?: string; /** Bound on the whole generative path, ms. Default {@link GENERATIVE_CONTRADICTION_TIMEOUT_MS}; tests shorten it. */ generativeTimeoutMs?: number; } /** Word-Jaccard score at which a prior decision counts as a near-duplicate collision. */ export declare const DECISION_COLLISION_THRESHOLD = 0.65; /** * The collision heuristic's similarity between two decisions: Jaccard over * the sets of words of 4+ characters in `decision + ' ' + rationale`, * lower-cased. A score at or above {@link DECISION_COLLISION_THRESHOLD} is a * collision. Exported for the T12495 benchmark, which scores the same * heuristic the store path runs. * * @param a - One decision's text and rationale. * @param b - The other decision's text and rationale. * @returns Similarity in [0, 1]. */ export declare function decisionWordJaccard(a: { readonly decision: string; readonly rationale: string; }, b: { readonly decision: string; readonly rationale: string; }): number; /** * Validate a candidate decision for collision, contradiction, and supersession- * graph integrity using the dialectic LLM evaluator. * * ## Scope * * Only runs for ADR-typed writes (where `adrPath` is provided on the params). * Non-ADR writes skip validation entirely. `storeDecision` runs it on every * ADR write (T12715): advisorily with `llmTier: false` by default (the System * One site only — shadow unless promoted, off without a provider; never * rejects), and in full — generative check and rejection — only when * `validateWithLlm: true` is explicitly supplied. * * ## Env skip * * When `process.env.CLEO_ENV === 'test'`, returns a synthetic passing result * (`confidence: 1.0`, empty violation arrays) immediately so that unit test * suites that do not want to make real LLM calls are not affected. * * ## Contradiction check (T12493) * * 1. System One: ONE `decide()` request asking how each of the top 3 prior * decisions (by word-Jaccard score) relates to the candidate — a `choice` * of `contradicts | supersedes | refines | unrelated` — bounded at * 300 ms end to end. Mode comes from * `decide.sites.decisionContradiction`: `shadow` (the default once a * provider is configured) audits the answers and acts on the heuristic; * `on` acts on them when every answer is confident. Unconfigured → `off`, * no network call. Contradictions come only from typed answers. * 2. Generative fallback (T1828): `evaluateDialectic()`, whose prose insights * are scanned for decision ids. It runs only when the decision did not act * and `decide.generativeFallback.decisionContradiction` resolves true. When * the key is unset it is on in every mode except `on` (unconfigured, `off` * and `shadow` keep today's behaviour; only `on` replaces it). The whole * path, backend resolution included, is bounded at 15 s. * * When neither answers, confidence is the deterministic result * (1.0 minus 0.15 per collision), so writes are never silently blocked due to * infrastructure absence. * * ## Rejection * * If `confidence < threshold` (default 0.7, configurable via * `decisions.validatorConfidenceThreshold` in `.cleo/config.json`), * the caller MUST throw {@link DecisionValidatorFailedError}. * * @param params - The store params for the candidate decision. * @param existingDecisions - Snapshot of existing decisions for conflict checking. * @param options - System One mode, generative opt-in and `decide()` wiring (T12493). * @returns Validation result with conflict lists and overall confidence. * * @task T1828 * @task T12493 */ export declare function validateDecisionConflicts(params: Pick, existingDecisions: Pick[], options?: ValidateDecisionConflictsOptions): Promise; /** * Advisory contradiction check for an ADR write without `validateWithLlm` * (T12715): runs the `memory.decision-contradiction` System One site with the * generative tier off. In `shadow` (the default once a provider is * configured) the site only audits its answers; in `on` a confident * contradiction is logged as a warning. Unconfigured → `off`, no network * call. Never throws and never blocks the write (registry: "Advisory: a * contradiction is reported, never blocks the write"). * * @param projectRoot - Project root for the brain accessor, config and audit. * @param params - The decision being stored. * @param options - Test wiring forwarded to {@link validateDecisionConflicts}. * @returns The contradicting decision ids that were reported (empty when none). * * @task T12715 */ export declare function adviseDecisionConflicts(projectRoot: string, params: Pick, options?: Pick): Promise; /** * Store a new decision or update an existing one if a duplicate is found. * Duplicate detection: same decision text (case-insensitive). * * @task T5155 */ export declare function storeDecision(projectRoot: string, params: StoreDecisionParams): Promise; /** * Recall a specific decision by ID. * * @task T5155 */ export declare function recallDecision(projectRoot: string, id: string): Promise; /** * Search decisions by type, confidence, outcome, and/or free-text query. * Query searches across decision + rationale fields using LIKE. * * @task T5155 */ export declare function searchDecisions(projectRoot: string, params?: SearchDecisionParams): Promise; /** * List decisions with pagination. * * @task T5155 */ export declare function listDecisions(projectRoot: string, params?: ListDecisionParams): Promise<{ decisions: BrainDecisionRow[]; total: number; }>; /** * Update the outcome of a decision after learning from results. * * @task T5155 */ export declare function updateDecisionOutcome(projectRoot: string, id: string, outcome: BrainDecisionRow['outcome']): Promise; //# sourceMappingURL=decisions.d.ts.map