import type { PendingDecision } from '../../types/index.js'; /** Factual origin labels for content OpenLore serves to an agent or reviewer. */ export declare const SERVED_CONTENT_PROVENANCES: readonly ["reviewed-corpus", "local-unreviewed", "foreign-actor", "imported", "source-derived"]; export type ServedContentProvenance = (typeof SERVED_CONTENT_PROVENANCES)[number]; export interface ServedContentMetadata { provenance: ServedContentProvenance; } /** Human approval is the boundary; automatic or pending states remain unreviewed. */ export declare function decisionContentProvenance(decision: Pick): ServedContentProvenance; export type AnalysisContentProvenance = Extract; /** Persist the live graph's factual origin. The marker is local metadata, not bundle payload. */ export declare function writeAnalysisContentProvenance(analysisDir: string, provenance: AnalysisContentProvenance): Promise; /** Legacy analyses predate the marker and were locally built, so they remain source-derived. */ export declare function readAnalysisContentProvenance(rootPath: string): Promise; /** * Human-reviewed corpus is the default branch. Any branch, staged, unstaged, or * untracked difference under the path remains local-unreviewed. If Git cannot * establish that boundary, fail conservatively to local-unreviewed. */ export declare function reviewedFileContentProvenance(rootPath: string, relativePath: string): Promise>; /** * Classify bytes returned from the persisted spec index. A clean current file * cannot upgrade stale indexed text: every served excerpt must still occur in * that file before it may inherit the file's reviewed provenance. */ export declare function indexedSpecContentProvenance(rootPath: string, relativePath: string, servedValues: readonly string[]): Promise>; /** * Frame content for an agent. The selected delimiter is checked against the content, * so the enclosed content cannot contain (and therefore cannot forge) either boundary * line. * * The frame's own header states the content is neutralized data, so this is where the * neutralizing happens: terminal control sequences, bidi overrides and zero-width * characters are removed from the framed content ({@link sanitizeForTerminal}, * newlines kept because the framed block is line-structured). A fence that ONLY * claims the bytes are safe is worse than no fence, because the surrounding text * tells the model to trust the claim. Doing it here rather than at each renderer makes * the claim true for every caller — including the always-on `orient --inject` * UserPromptSubmit path, which assembled its lines with no screening at all. * * Byte length and delimiter are computed from the SCREENED content, so the receipt * describes exactly what is enclosed. */ export declare function frameServedContent(rawContent: string, provenance: ServedContentProvenance | readonly ServedContentProvenance[], label: string): string; export type InjectionShape = 'imperative-override' | 'message-impersonation' | 'decision-steering'; export interface InjectionShapeMatch { shape: InjectionShape; excerpt: string; } export declare const INJECTION_SHAPE_LIMITS: string; /** * Deterministic, offline lexical indicators. They diagnose text and never mutate it. * * CALL {@link screenServedText}, not this, on any path that SERVES the text: these * rules must see the text a model will see, and that is only true after sanitizing. * (A leading `\x1b[31m` once left `m` against the `I` of `IGNORE`, so the `\b` that * opened the imperative rule never matched and the note was served verbatim.) * * The opening `\b` is gone from the two keyword rules for the same reason, as defence * in depth: whatever junk a future evasion leaves glued to the keyword, the rule still * fires. The trailing `\b` stays, so prose like "ignores all previous rulesets" is not * caught by accident, and the keyword alone is never enough — each rule still needs * its object ("instructions", "a recorded decision"). */ export declare function detectInjectionShapes(content: string): InjectionShapeMatch[]; /** The placeholder served in place of text that reads like an instruction to the agent. */ export declare const WITHHELD_SERVED_TEXT = "[withheld: reads like an instruction]"; export interface ServedTextScreen { /** The text as a model would see it: screened of control, bidi and zero-width characters. */ sanitized: string; /** The injection shapes found IN `sanitized`, sorted and deduplicated. */ shapes: InjectionShape[]; /** True when `sanitized` must not be served as content. */ withheld: boolean; } /** * Sanitize first, then screen — the one order in which the instruction-shape screen is * sound, and the only screening entry point a serving path may use. * * Running the screen on RAW text and sanitizing only at render time let a five-byte * `\x1b[31m` prefix walk an "IGNORE ALL PREVIOUS INSTRUCTIONS" memory straight into the * always-on `orient --inject` block, while the identical note without the prefix was * correctly withheld. The screen was never reached on the representation that reached * the model. Callers must serve `sanitized` (or the withheld placeholder) and nothing * else: text screened as one representation and emitted as another is the same defect * wearing a different hat. * * Newlines are kept, because the `message-impersonation` rule anchors on them — * stripping them first would hide a forged `\n[system]:` line from the screen. A caller * that needs a single line collapses whitespace AFTER this, where it can no longer * change the verdict. * * The screen's limits are unchanged and still stated in {@link INJECTION_SHAPE_LIMITS}: * it is lexical, incomplete, and not a guarantee. */ export declare function screenServedText(text: string): ServedTextScreen; //# sourceMappingURL=served-content.d.ts.map