import type { ClassifiedSection, ClassifierOutput, OrphanCandidate } from "../lib/section-types.js";
import { type ConversationSource } from "../lib/conversation-normalisers/types.js";
import type { InlineRewriteCandidate, InlineRewriteDeferred } from "../lib/compiled-truth-revision.js";
export declare function deriveSectionBodies(sections: ReadonlyArray<Pick<ClassifiedSection, "sourceStart" | "sourceEnd" | "body">>, cachedText: string, sourceKey?: string): string[];
export declare const RESERVED_SECTION_PROPERTY_KEYS: ReadonlySet<string>;
/**
 * Drop reserved writer-owned keys from an agent-supplied `section.properties`
 * bag. When any keys are stripped, emit one grep-able log line naming the
 * keys and the context (attachmentId or conversationIdentity:archiveSha256)
 * so the operator can attribute the smuggle attempt to a specific ingest.
 *
 * Mirrors the Task 465 `agent body suppressed` log shape — a quiet strip
 * with a loud trail. Returns a new object; never mutates the input.
 */
export declare function stripReservedSectionProperties(properties: Record<string, unknown>, ctx: {
    kind: string;
    identity: string;
}): Record<string, unknown>;
export interface IngestParams {
    accountId: string;
    /**
     * Document-path identity. Set when the parent is a file/URL/obsidian page —
     * the writer takes the document path (anchor edges, related entities,
     * extract cache, first-ingest semantics).
     *
     * Exactly one of `attachmentId` or `conversationIdentity` must be set.
     */
    attachmentId?: string;
    /**
     * Conversation-path identity. Set when the parent is a chat transcript —
     * the writer takes the conversation-document path (delta-append after
     * cursor lookup, :PARTICIPANT_IN edges, archiveSha256 cleanup-on-rebuild,
     * no anchor / related discovery).
     *
     * Exactly one of `attachmentId` or `conversationIdentity` must be set.
     * The presence of `conversationIdentity` selects the conversation path,
     * which MERGEs the parent under `:ConversationArchive` (Task 397). The
     * `attachmentId` path MERGEs under `:KnowledgeDocument`.
     */
    conversationIdentity?: string;
    documentSummary: string;
    /**
     * Element ID of the anchor node (UserProfile / LocalBusiness / Person /
     * Organization). Anchor identity is parameter input — never inferred.
     * Unused on the conversation-document path (chat participants attach via
     * :PARTICIPANT_IN, not via anchor edges) — pass any non-empty string.
     */
    anchorNodeId: string;
    /** Anchor's primary label, used in the per-section MATCH for edge creation. */
    anchorLabel: string;
    /** Sections returned by memory-classify, in reading order. */
    sections: ClassifiedSection[];
    /** Document-level edges (e.g. PARTY edges off KnowledgeDocument). */
    documentEdges?: ClassifierOutput["documentEdges"];
    /** Orphan candidates: nodes the classifier could not edge naturally. */
    orphanCandidates?: OrphanCandidate[];
    /** Visibility scope for all created nodes. Required. */
    scope: string;
    /** Original URL for web-sourced documents. Absent for file uploads. */
    sourceUrl?: string;
    /** Provenance discriminator: "upload" (default) or "web". */
    sourceType?: string;
    /** LLM-extracted topic keywords (from memory-classify). */
    documentKeywords?: string[];
    /** User-supplied keywords (verbatim, normalised, deduplicated with documentKeywords). */
    userKeywords?: string[];
    /** Session UUID for provenance stamping. */
    sessionId?: string;
    /** SHA-256 of THIS export's transcript bytes. Cleanup discriminator: only
     *  chunks stamped with this sha256 are dropped on re-ingest, so delta
     *  re-imports of newer exports leave prior chunks untouched. */
    archiveSha256?: string;
    /** Original archive filename (basename, e.g. `_chat.txt`). Stamped on the
     *  parent + every chunk for operator audit. */
    archiveSourceFile?: string;
    /** Content hash of the LAST message ingested in this run (cursor advance).
     *  Stamped on the :ConversationArchive parent so the next delta-append run
     *  finds the cursor. */
    lastIngestedMessageHash?: string;
    /** ISO 8601 dateSent of the last message ingested. Stamped on the parent
     *  for the noop-reason message ("no new messages since <lastIngestedMessageAt>"). */
    lastIngestedMessageAt?: string;
    /** Operator-confirmed participant elementIds (:Person / :AdminUser) for
     *  this conversation. Used to MERGE :PARTICIPANT_IN edges off the parent
     *  on every ingest (idempotent). */
    participantElementIds?: string[];
    /** Conversation source enum. Required when `conversationIdentity` is set;
     *  ignored on the document path. Stamped on the :ConversationArchive parent
     *  and every :Section chunk so downstream queries can filter by source
     *  without inferring from archiveSourceFile. The set is closed — see
     *  `CONVERSATION_SOURCES`. */
    source?: ConversationSource;
    /** sub-scope E — per-session checkpointing.
     *
     *  When the bin calls `memoryIngest` once per session (instead of once per
     *  archive), the cleanup-by-archiveSha256 step must run only on the FIRST
     *  session of a run. Otherwise session N+1's call would delete session N's
     *  just-written chunks (same conversationIdentity + same archiveSha256).
     *
     *  sub-scope B — additionally gated on the bin's `--rebuild`
     *  flag. Without `--rebuild`, re-issuing the bin on the same export bytes
     *  is a no-op; the bin sets `cleanupPriorChunks=false` for every session.
     *  With `--rebuild`, the bin sets `cleanupPriorChunks=true` only on the
     *  first session. Ignored on the document path. */
    cleanupPriorChunks?: boolean;
    /** Task 468 — per-session index used by the conversation-archive path to
     *  locate the per-session turnText tempfile written by the bin
     *  (`conversation-archive-ingest.mjs`). The writer constructs the file path
     *  via `turnTextCachePath({ conversationIdentity, archiveSha256,
     *  sessionIndex })`, reads it, and slices `:Section.body` server-side from
     *  the loaded text. Required on the conversation-document path; ignored on
     *  the document path. Integer >= 1. */
    sessionIndex?: number;
    /** sub-scope A — stable title for the conversation-document parent.
     *  Computed once per ingest by the bin from `(source, ownerName,
     *  otherParticipantNames, firstMessageAt, lastMessageAt)`. Written ON
     *  CREATE; on MATCH the existing `title` is preserved (COALESCE) so
     *  re-ingests never overwrite a stable label. UI display-helpers prefer
     *  `title` over `summary` for conversation-document rows — the per-session
     *  counter strings that used to lock `summary` to "Session 1/N: …" are
     *  gone. Ignored on the document path. */
    archiveTitle?: string;
    /**
     * When true, after writing sections and edges, run the inline
     * compiled-truth reconciliation gate: count MENTIONS/REFERENCES edges
     * from the new document (KD and its sections) to existing entities
     * that have `compiledTruth`. Entities above `inlineRewriteThreshold`
     * and outside the 7-day cooldown are returned as `inlineRewriteCandidates`
     * in the result. Disabled by default.
     */
    inlineRewrite?: boolean;
    /**
     * When `inlineRewrite` is true, bypass the 7-day per-entity cooldown on
     * `compiledTruthUpdatedAt`. All entities above threshold are returned as
     * candidates regardless of when their truth was last rewritten.
     */
    forceRewrite?: boolean;
    /**
     * Minimum count of MENTIONS or REFERENCES edges from the new source
     * (KnowledgeDocument + its sections) to an existing entity for that
     * entity to qualify as an inline-rewrite candidate. Default: 2.
     */
    inlineRewriteThreshold?: number;
}
/** Per-kind count breakdown the writer returns to the skill. */
export interface KindBreakdown {
    /** Section kind → count (e.g. {"Position": 4, "Chapter": 12, "Other": 1}). */
    [kind: string]: number;
}
/** Per-edge-type count breakdown for anchor edges. */
export interface EdgeBreakdown {
    /** Edge type → count (e.g. {"HAS_POSITION": 4, "ATTENDED": 1, "PARTY": 2}). */
    [edgeType: string]: number;
}
export interface IngestResult {
    documentNodeId: string;
    /** Total :Section nodes written. */
    sectionCount: number;
    /** Per-section-kind count breakdown — drives the post-write chat narrative. */
    kindBreakdown: KindBreakdown;
    /** Per-anchor-edge-type count breakdown — drives the post-write chat narrative. */
    edgeBreakdown: EdgeBreakdown;
    /** Related entities created or merged (Organization, Person, DefinedTerm). */
    relatedCount: number;
    /** Standalone nodes created (Project). */
    standaloneCount: number;
    /** Orphan candidates surfaced from the classifier — NOT written, just relayed. */
    orphanCandidates: OrphanCandidate[];
    documentSummary: string;
    keywords?: string[];
    /** sub-scope E — count of prior conversation-document :Section chunks
     *  deleted by the cleanup-by-archiveSha256 step. Always 0 unless the
     *  caller passed `cleanupPriorChunks=true`. The bin surfaces this as a
     *  heartbeat WARN line so a destructive `--rebuild` is operator-visible
     *  (defence-in-depth — `--rebuild` is the only legitimate trigger). */
    cleanedPriorChunks?: number;
    /**
     * Entities above the MENTIONS/REFERENCES threshold that qualify for
     * inline compiled-truth rewrite. Populated only when `inlineRewrite=true`.
     * Dispatch the `compiled-truth-rewriter` specialist for each entity
     * before the calling skill returns — pass `nodeId` and optionally
     * an `operatorHint` if the document suggests a correction.
     */
    inlineRewriteCandidates?: InlineRewriteCandidate[];
    /**
     * Entities above threshold that were skipped because their
     * `compiledTruthUpdatedAt` is within the 7-day cooldown and
     * `forceRewrite` was not set. These remain candidates for the next
     * dream-cycle run.
     */
    inlineRewriteDeferred?: InlineRewriteDeferred[];
}
export declare function memoryIngest(params: IngestParams): Promise<IngestResult>;
//# sourceMappingURL=memory-ingest.d.ts.map