/**
 * Cypher fragment that excludes trashed nodes for the given alias.
 *
 * Mirrors the platform's soft-delete model: a node is trashed if it
 * carries the `:Trashed` label OR a non-null `deletedAt` timestamp.
 * Inlined here (Task 473) instead of imported from
 * `platform/lib/graph-trash` — the cross-package import path did not
 * survive `tsc` emit (the `rootDir: "src"` config collapsed
 * `../../../../../platform/...` to `../../...`, pointing the dist
 * file at a non-existent location and crashing the MCP on boot). The
 * predicate is one line; copying it costs less than the build coupling.
 */
export function notTrashed(alias) {
    return `(NOT \`${alias}\`:Trashed AND \`${alias}\`.deletedAt IS NULL)`;
}
/**
 * Shared corpus-filter clauses and format helpers for the voice-mirror tools.
 *
 * Imported by `voice-distil-profile` (count + sample walks),
 * `voice-retrieve-conditioning` (exemplar walk), `voice-tag-content` (tag
 * writes), and `voice-ingest-session-text` (on-demand session-text ingest). The single
 * load-bearing filter — when the corpus rules change, this is the only place
 * to edit.
 *
 * Three predicates in VOICE_CORPUS_WHERE:
 *
 *   1. `authorshipMode IN ['human-only', 'human-led-agent-assisted']`.
 *      `human-only` is the operator's own writing verbatim;
 *      `human-led-agent-assisted` is operator-authored with light agent
 *      polish, which still carries voice signal (the operator chose the
 *      claims and the structure). Including this expands the available
 *      corpus to match how most modern writing actually happens.
 *
 *   2. Label is one of the four primary content labels OR is a
 *      conversation-document `:Section` chunk (unguarded chat voice from
 *      WhatsApp / Telegram / Signal / Granola / Otter / Circleback etc.
 *      archives). After the Task 324 collapse, conversation transcripts
 *      land as `:KnowledgeDocument` parents carrying `conversationIdentity`
 *      with plain `:Section` children — no `:Conversation` secondary label.
 *      Conversation-document sections are identified by their parent's
 *      `conversationIdentity` property via an EXISTS sub-pattern. The
 *      conversation parent must itself be live — a trashed parent excludes
 *      its child chunks.
 *      Chat captures voice in a way email rarely does — this is the
 *      single highest-leverage corpus addition for voice fidelity.
 *
 *   3. The node is not trashed — `notTrashed("n")` filters both the
 *      `:Trashed` label and the `deletedAt` property (Task 472). This is
 *      the read-side equivalent of `graph-trash`'s soft-delete model: a
 *      node marked by either signal is excluded from every voice-mirror
 *      walk that goes through VOICE_CORPUS_WHERE.
 *
 * The clause expects `$accountId` to be bound in the calling Cypher
 * parameters. It does not bind any other parameters.
 */
export const VOICE_CORPUS_WHERE = `n.accountId = $accountId
  AND n.authorshipMode IN ['human-only', 'human-led-agent-assisted']
  AND ${notTrashed("n")}
  AND (
    any(lbl IN labels(n) WHERE lbl IN ['KnowledgeDocument', 'Message', 'SocialPost'])
    OR ('Section' IN labels(n) AND EXISTS {
      MATCH (parent:KnowledgeDocument)-[:HAS_SECTION]->(n)
      WHERE parent.conversationIdentity IS NOT NULL
        AND ${notTrashed("parent")}
    })
  )`;
/**
 * The label set the tag tool accepts when stamping `authorshipMode`.
 * Mirrors the label predicate inside VOICE_CORPUS_WHERE so the tag tool
 * and the corpus walk stay in lockstep. The tag tool does not filter
 * by authorshipMode (that's the property it's setting).
 *
 * `:Email` retired with Task 321 — email threads now land as
 * `:KnowledgeDocument {source:'email'}` and are already covered.
 */
export const TAGGABLE_PRIMARY_LABELS = [
    "KnowledgeDocument",
    "Message",
    "SocialPost",
];
/**
 * Closed enum of writing-format values. One `:VoiceProfile` exists per
 * `(accountId, userId, format)`. Adding a new value is a separate task.
 *
 * Format is an editorial classification set by the operator at tag time.
 * The only auto-tagged path is `voice-ingest-session-text`, which hard-codes
 * `format='text'` on `:Message` because chat turns are unambiguously text and
 * the operator is not in the loop on session end.
 */
export const FORMAT_VALUES = [
    "text",
    "email",
    "social-post",
    "article",
    "marketing-copy",
    "note",
];
/**
 * Returns VOICE_CORPUS_WHERE with an additional `n.format = $format`
 * predicate appended. Requires `$format` to be bound alongside `$accountId`
 * in the calling Cypher parameters.
 *
 * Format-discovery queries (which enumerate distinct formats from the
 * corpus) use the base `VOICE_CORPUS_WHERE` directly; per-format corpus
 * walks use this function.
 */
export function voiceCorpusWhereWithFormat(format) {
    return `${VOICE_CORPUS_WHERE}\n  AND n.format = $format`;
}
//# sourceMappingURL=voice-corpus.js.map