export * from "./audit.js";
export * from "./conversation-provenance.js";
/**
 * Write doctrine: a node without at least one adjacency is noise,
 * not knowledge. `writeNodeWithEdges` is the single primitive every graph
 * writer should call; it rejects zero-relationship writes, verifies every
 * relationship target resolves before the node is created, and commits the
 * node + all edges in one managed transaction. Provenance is stamped on the
 * node as flattened `createdBy*` properties (Neo4j does not persist nested
 * maps, and flat props are queryable — `MATCH (n) WHERE n.createdBySession
 * = $id RETURN n` is the forensic entry point).
 *
 * Process provenance doctrine (widened): writes
 * targeting any label in `ACTION_PROVENANCE_LABELS` (Person, UserProfile,
 * AdminUser, Organization, LocalBusiness, CloudflareTunnel,
 * CloudflareHostname) must include at least one inbound `:PRODUCED` edge
 * whose source carries one of `:Task`, `:Conversation`, or `:Message` (the
 * label set is checked against the actual `labels()` of the target node, so
 * subtype labels like `:AdminConversation`, `:UserMessage`, `:AssistantMessage`,
 * and `:AdminMessage` all qualify). This makes every durable LLM-tool-driven
 * entity creation traversable from either:
 *   - the Task that produced it (autonomous workflows: onboarding skill,
 *     cloudflare tunnel-login, etc.), or
 *   - the Conversation/Message turn that triggered it (direct admin asks —
 *     "add Anneke Roux as person" stamps a `:PRODUCED` edge from the active
 *     `:AdminConversation` so the entity is traceable to its causal turn
 *     without forcing the agent to mint a synthetic `:Task` per ask).
 * The Task-mediated path stays canonical for autonomous workflows. Direct
 * admin asks attach via the active Conversation/Message turn to avoid
 * redundant-Task bloat. Bootstrap writes (`createdBy.agent === 'system'`)
 * are exempt — installer and lazy-create paths run as system writers.
 *
 * Rejection paths (every one emits a stderr log the admin server pipes to
 * server.log, so orphan pressure is visible per-write not just in the
 * hourly [graph-health] signal):
 *   - zero relationships          → `[graph-write] reject reason=zero-relationships`
 *   - unresolved target id        → `[graph-write] reject reason=unresolved-target`
 *   - missing provenance          → `[graph-write] warn reason=missing-provenance`
 *     (Task 580 — soft warn; write proceeds. Composer-spawned admin sessions
 *     inherit a bare env that never carries SESSION_NODE_ID, so the prior
 *     hard reject was failing every direct admin write to a gated label.)
 *   - removed-feature write       → `[graph-write] reject reason=removed-feature`
 *     (`:ReviewAlert` and `:Event {actionTool:"review-digest-compose"}` are
 *     deleted features; the gate catches doctrine-compliant writers
 *     re-introducing them. The vitest tombstone grep is the primary fence
 *     for raw `session.run("MERGE …")` callers that bypass this primitive.)
 *
 * The `createdBy.agent` field is advisory, not authoritative — it is sourced
 * from the MCP server's AGENT_SLUG env var, which is set by the trusted
 * spawning code (admin server / workflow runner). A misconfigured spawner
 * will write "unknown"; that's the signal something is wrong. Do not use
 * this field for access control — it is forensic, not a security boundary.
 */
/**
 * Labels that require an inbound `:PRODUCED` edge from a `:Task`,
 * `:Conversation`, or `:Message`. Bootstrap writes with
 * `createdBy.agent === 'system'` are exempt — that carve-out covers
 * PIN-setup `writeAdminUserAndPerson`, schema apply, and the lazy
 * `loadUserProfile` MERGE path that bypasses this primitive entirely
 * (raw Cypher in `platform/ui/app/lib/neo4j-store.ts`).
 *
 * The set is intentionally not exhaustive — labels added here become a
 * blocking gate for every LLM-tool write of that label. Add a label only
 * after every legitimate writer of it can either (a) carry a PRODUCED edge
 * from one of the accepted source families, or (b) declare itself as
 * `agent: 'system'`.
 */
export declare const ACTION_PROVENANCE_LABELS: ReadonlySet<string>;
/**
 * Source labels that satisfy the inbound-PRODUCED gate. The check is
 * performed against the full `labels()` array of the target node, so
 * subtype labels (`:AdminConversation`, `:UserMessage`, etc.) qualify
 * because they carry the parent `:Conversation` / `:Message` label too.
 */
export declare const PROVENANCE_SOURCE_LABELS: ReadonlySet<string>;
/**
 * Labels carrying a `CREATE VECTOR INDEX … ON (n.embedding)` in
 * platform/neo4j/schema.cypher. A node of one of these labels written with a
 * null embedding is invisible to the vector half of memory-search until a
 * manual reindex. This constant is the single runtime source of truth —
 * graph-write stays fs-free (it is bundled into the ESM payload and must not
 * read schema.cypher at runtime), so the memory-plugin drift test
 * (vector-indexed-labels-drift) pins it to the schema instead.
 */
export declare const VECTOR_INDEXED_LABELS: ReadonlySet<string>;
/**
 * Document/archive labels whose primary content is a long body. The safety-net
 * embed prefers a bounded `summary` field over the raw `body`/`text` blob for
 * these; the dedicated archive-ingest path adds the per-:Section embeddings.
 */
export declare const DOCUMENT_ARCHIVE_LABELS: ReadonlySet<string>;
import type { Session } from "neo4j-driver";
export interface GraphRelationship {
    type: string;
    direction: "outgoing" | "incoming";
    targetNodeId: string;
}
export interface CreatedBy {
    /** Agent slug (e.g. "maxy-admin", "whatsapp-public") for LLM-tool writes. */
    agent?: string;
    /** Session correlation id — same string across every node written in a conversation turn. */
    session?: string;
    /** MCP tool name ("memory-write", "contact-create", ...) for LLM-tool writes. */
    tool?: string;
    /** Subsystem name ("workflow-execute", "persist-tool-call", ...) for system writes. */
    source?: string;
}
export interface WriteNodeWithEdgesParams {
    session: Session;
    labels: string[];
    props: Record<string, unknown>;
    /** At least one relationship is required — zero-rel writes are rejected. */
    relationships: GraphRelationship[];
    createdBy: CreatedBy;
    /**
     * Override for the accountId gate. Production callers leave
     * this unset — the gate compares `props.accountId` against
     * `process.env.ACCOUNT_ID`, which the MCP server / UI server validates at
     * boot time. Tests pass an explicit value to avoid env coupling.
     * Reading from env var (instead of an on-disk dir enumeration) keeps
     * graph-write out of the `node:fs` import chain — the lib is bundled
     * transitively into the ESM payload via cloudflare-task-tracker.ts, and
     * any CJS-side fs require shims to a runtime-fatal `__require("fs")`
     * after esbuild's CJS-to-ESM conversion strips the `node:` prefix.
     */
    expectedAccountId?: string;
    /**
     * Optional embedder. When supplied and the node carries a label in
     * VECTOR_INDEXED_LABELS and `props.embedding` is absent/empty, the chokepoint
     * computes a bounded props embedding before CREATE. Injected (never imported)
     * so graph-write stays out of the node:fs / Ollama import chain. A failed
     * embed logs `[graph-write] warn reason=embed-failed` and the write proceeds —
     * a failed embed must never abort an otherwise-valid write.
     */
    embed?: (text: string) => Promise<number[]>;
}
export interface WriteNodeResult {
    nodeId: string;
    labels: string[];
    edgesCreated: number;
}
/** Stamp flattened provenance into node properties. */
export declare function stampCreatedBy(props: Record<string, unknown>, createdBy: CreatedBy): Record<string, unknown>;
/**
 * Enforce the write doctrine: node + ≥1 edge, transactional, provenance stamped.
 * The label and relationship type strings are interpolated into Cypher — the
 * caller must constrain them via Zod/schema before calling. Backticks are
 * stripped to defeat the only Cypher escape char.
 */
export declare function writeNodeWithEdges(params: WriteNodeWithEdgesParams): Promise<WriteNodeResult>;
//# sourceMappingURL=index.d.ts.map