/** * Candidate Intake Contract — M7 schema and interface definitions. * * Defines the intake boundary: input/output schemas, the ledger entry * contract, the LedgerAdapter interface, and intake error codes. * * Implementation logic (CandidateIntakeService) lives in m7-03. * * Non-goals (M7): * - No pain signal auto-trigger (M8) * - No legacy evolution-worker deletion (M9) * - No promote to active principle * - No direct ledger write from SqliteDiagnosticianCommitter * * ============================================================================= * FIELD PROVENANCE MAP * ============================================================================= * * Every field in LedgerPrincipleEntry flows from exactly one origin: * * │ Field │ Origin │ Reliability │ * │-------------------|----------------------------------|-------------│ * │ id │ Service-generated (UUID v4) │ Always │ * │ title │ Extracted from artifact │ Always │ * │ text │ Extracted from artifact │ Always │ * │ triggerPattern │ Extracted from artifact │ Optional │ * │ action │ Extracted from artifact │ Optional │ * │ status │ Fixed: 'probation' │ Always │ * │ evaluability │ Fixed: 'weak_heuristic' │ Always │ * │ sourceRef │ Constructed: candidate:// │ Always │ * │ artifactRef │ Constructed: artifact:// │ Optional │ * │ taskRef │ Constructed: task:// │ Optional │ * │ createdAt │ Service-generated (ISO 8601) │ Always │ * * ============================================================================= * LEDGER PRINCIPLE ENTRY — 18 FIELD DEFAULT VALUES * ============================================================================= * * When the intake service expands a LedgerPrincipleEntry into a full * LedgerPrinciple, it applies these defaults (m7-03): * * id: Generated UUID v4 * title: From artifact extraction * text: From artifact extraction * triggerPattern: null (absent if not extracted) * action: null (absent if not extracted) * status: 'probation' * evaluability: 'weak_heuristic' * sourceRef: 'candidate://' * artifactRef: 'artifact://' (if artifactId known) * taskRef: null (absent in M7; M8+ may populate) * createdAt: new Date().toISOString() * * -- M7 does NOT set (M8/M9 concerns): * promotedAt: undefined * promotedBy: undefined * archivedAt: undefined * archivedBy: undefined * archivedReason: undefined * experimentTags: undefined * principleNotes: undefined * reviewCycle: undefined */ import { type Static } from '@sinclair/typebox'; export declare const CandidateIntakeInputSchema: import("@sinclair/typebox").TObject<{ candidateId: import("@sinclair/typebox").TString; workspaceDir: import("@sinclair/typebox").TString; }>; export type CandidateIntakeInput = Static; export declare const CandidateIntakeOutputSchema: import("@sinclair/typebox").TObject<{ candidateId: import("@sinclair/typebox").TString; artifactId: import("@sinclair/typebox").TString; ledgerRef: import("@sinclair/typebox").TString; status: import("@sinclair/typebox").TLiteral<"consumed">; }>; export type CandidateIntakeOutput = Static; /** * Ledger principle entry written during candidate intake. * * Provenance annotations (@provenance): * * @provenance id — Service-generated UUID v4. Never from artifact. * Generated by: CandidateIntakeService (m7-03). * * @provenance title — Extracted from artifact by CandidateIntakeService. * Sourced from: artifact principle text/title. * * @provenance text — Extracted from artifact by CandidateIntakeService. * Sourced from: artifact principle body content. * * @provenance triggerPattern — Extracted from artifact (optional). * @nullable null when artifact provides no trigger. * * @provenance action — Extracted from artifact (optional). * @nullable null when artifact provides no action. * * @provenance status — Fixed value. Always 'probation' on intake. * Never from artifact. Governed by promotion gate (M8). * * @provenance evaluability — Fixed value. Always 'weak_heuristic' on intake. * Never from artifact. Governed by evaluation strategy (M8). * * @provenance sourceRef — Constructed by service. Idempotency key. * Format: `candidate://` * @provenance Always constructed from input candidateId. * NOT derived from artifact artifactId (D-11). * * @provenance artifactRef — Constructed by service, only if artifactId known. * Format: `artifact://` * @provenance Derived from artifactId in intake input. * @nullable Omit from entry when artifactId is not available. * @tag traceability — NOT an idempotency key. * * @provenance taskRef — Constructed by service (optional, M7 not populated). * Format: `task://` * @provenance Reserved for M8+ task linking. * @nullable Omit from entry in M7. * @tag traceability — NOT an idempotency key. * * @provenance createdAt — Service-generated ISO 8601 timestamp. * Generated by: CandidateIntakeService (m7-03). * NOT from artifact. */ export declare const LedgerPrincipleEntrySchema: import("@sinclair/typebox").TObject<{ id: import("@sinclair/typebox").TString; title: import("@sinclair/typebox").TString; text: import("@sinclair/typebox").TString; triggerPattern: import("@sinclair/typebox").TOptional; action: import("@sinclair/typebox").TOptional; status: import("@sinclair/typebox").TLiteral<"probation">; evaluability: import("@sinclair/typebox").TLiteral<"weak_heuristic">; sourceRef: import("@sinclair/typebox").TString; artifactRef: import("@sinclair/typebox").TOptional; taskRef: import("@sinclair/typebox").TOptional; createdAt: import("@sinclair/typebox").TString; }>; export type LedgerPrincipleEntry = Static; /** * Reduced recommendation shape consumed by CandidateIntakeService. * * This is the simplified form extracted from `candidate.sourceRecommendationJson` * (canonical) or `artifact.contentJson` (legacy fallback). All fields are * optional because the intake service applies its own fallbacks (e.g. `text` * falls back to `candidate.description`). Do NOT confuse with the richer * `DiagnosticianRecommendation` in diagnostician-output.ts (different contract). * * rc-1/rc-2 (ERR-001/ERR-005): values parsed from DB/LLM JSON are untrusted and * MUST pass `validateRecommendation()` before use. Never cast directly. */ export interface Recommendation { title?: string; text?: string; triggerPattern?: string; action?: string; abstractedPrinciple?: string; } export declare function isRecord(value: unknown): value is Record; /** * Validate an untrusted parsed value as a {@link Recommendation}. * * Mirrors the `validateReplayReport` pattern (ConsoleLifecycleDatasource.ts): * returns the narrowed value, or `null` when the shape is wrong. Callers decide * the failure policy (the intake service falls back / throws INPUT_INVALID). * * Rules: * - root must be a plain object (rejects arrays, null, primitives) * - every recognized field, when present, must be a string * * This is intentionally lenient about *which* fields are present — the intake * service treats all of them as optional and applies its own fallbacks. It is * strict only about *types*: a number where a string is expected is rejected. * * rc-1 (treat parsed JSON as unknown) / rc-2 (no `as` bypass) — ERR-001/ERR-005. */ export declare function validateRecommendation(raw: unknown): Recommendation | null; /** * Error codes for candidate intake operations. * * @error INPUT_INVALID — Input validation failed (missing/invalid fields). * @error CANDIDATE_NOT_FOUND — Candidate ID does not exist in workspace. * @error ARTIFACT_NOT_FOUND — Artifact ID does not exist in workspace. * @error CANDIDATE_ALREADY_CONSUMED — Ledger entry exists for this candidate; * returned as idempotent success (D-10), * NOT an error. This code is reserved for * data-corruption detection: DB claims * consumed but no ledger entry found. * @error LEDGER_WRITE_FAILED — Ledger write operation failed. */ export declare const INTAKE_ERROR_CODES: { readonly CANDIDATE_NOT_FOUND: 'candidate_not_found'; readonly CANDIDATE_ALREADY_CONSUMED: 'candidate_already_consumed'; readonly ARTIFACT_NOT_FOUND: 'artifact_not_found'; readonly LEDGER_WRITE_FAILED: 'ledger_write_failed'; readonly INPUT_INVALID: 'input_invalid'; }; /** * Candidate intake error with structured code and optional context. * * Use INTAKE_ERROR_CODES for the code value. * * @example * throw new CandidateIntakeError(INTAKE_ERROR_CODES.CANDIDATE_NOT_FOUND, 'Candidate cand-1 not found'); * * @example * throw new CandidateIntakeError(INTAKE_ERROR_CODES.LEDGER_WRITE_FAILED, 'Ledger write failed', { cause: err }); */ export declare class CandidateIntakeError extends Error { readonly code: (typeof INTAKE_ERROR_CODES)[keyof typeof INTAKE_ERROR_CODES]; readonly context?: Record | undefined; constructor(code: (typeof INTAKE_ERROR_CODES)[keyof typeof INTAKE_ERROR_CODES], message: string, context?: Record | undefined); } /** * Abstraction for writing probation principles to the ledger. * Implementations write to file-based ledger (openclaw-plugin) or test doubles. * * Design notes: * - LedgerAdapter is defined in principles-core (shared contract). * - Implementations live in openclaw-plugin (principle-tree-ledger adapter). * - The interface uses LedgerPrincipleEntry (11-field contract), NOT the * full LedgerPrinciple (18+ fields). Full expansion happens inside * the adapter's writeProbationEntry implementation (m7-02). */ export interface LedgerAdapter { /** * Write a probation principle entry to the ledger. * * Implementation requirements (m7-02): * 1. Expand the 11-field LedgerPrincipleEntry into a full LedgerPrinciple * by applying the documented default values (see LedgerPrincipleEntrySchema * block above and the 18-field default values list). * 2. Call addPrincipleToLedger(stateDir, ledgerPrinciple). * 3. Return the LedgerPrincipleEntry as-is (passthrough for idempotency tracking). * * @param entry — Full LedgerPrincipleEntry with id and createdAt already populated * by the intake service. The adapter does NOT generate these fields. * @returns The same entry (passthrough) for ledgerRef construction by the caller. * @throws CandidateIntakeError with code LEDGER_WRITE_FAILED if the write fails. */ writeProbationEntry(entry: LedgerPrincipleEntry): LedgerPrincipleEntry; /** * Check if a ledger entry already exists for a given candidate. * * **Matching rule (D-11):** Scan `tree.principles` for an entry whose * `sourceRef` field matches `'candidate://'`. * * NOT artifact-based: one artifact can produce multiple candidates (M5). * Each candidate must have its own unique ledger entry retrievable by this method. * Using artifactRef as the key would cause collisions when a single artifact * generates N candidates — all N entries would share the same artifactRef, * making existsForCandidate ambiguous. * * @param candidateId — The candidate ID to check for existing ledger entries. * @returns The existing LedgerPrincipleEntry if found, null otherwise. */ existsForCandidate(candidateId: string): LedgerPrincipleEntry | null; } //# sourceMappingURL=candidate-intake.d.ts.map