/**
 * Schema validator — validates memory-write inputs against two sources of
 * truth:
 *
 *   1. `LiveSchemaSource` — recognised-label set = `db.labels()` snapshot
 *      ∪ `schema.cypher` constraint/index declarations. This is the gate.
 *      A label is recognised iff it appears in either set.
 *   2. `LoadedSchema` (markdown sidecar) — required-property and naming-rule
 *      metadata for documented labels. Markdown is no longer a label-existence
 *      gate; required-property checks are skipped (with a log line) when the
 *      label is recognised by the live source but absent from markdown.
 *
 * Checks run in order; first failure throws with a descriptive message.
 *
 *   1. accountId            — non-empty trimmed string
 *   2. label existence      — at least one input label is in live ∪ declared.
 *                             Rejection cites both sources and the nearest
 *                             documented match (Levenshtein) when there is one
 *   3. property synonym     — no property key is a known wrong-name alias.
 *                             Runs before required-props so a `firstName`
 *                             typo is reported as "rename firstName →
 *                             givenName" rather than "missing givenName"
 *   3b. forbidden property. Per-label deny-list parsed from the
 *                             "Forbidden Properties" table in schema markdown.
 *                             Fires AFTER the synonym pass so `firstName`
 *                             still rewrites to `givenName` rather than
 *                             rejecting on the wrong rule. First row:
 *                             `Person | name`, eliminating the divergence
 *                             trap where `name` truncated to `givenName`
 *                             ("Dan") while the canonical pair held the full
 *                             identity ("Dan Brett")
 *   4. required properties  — for the primary label, fires only when the
 *                             label is documented in markdown. Skipped (with
 *                             a structured log line) when the label is
 *                             recognised but undocumented — that's a
 *                             stale-doc signal, not a write error
 *
 * The `[schema-validator]` log lines are the single observability surface.
 * Operators reading server.log can distinguish "validation didn't run" from
 * "validation passed" from "validation rejected" without source access.
 *
 * "Present" semantics for required-property values: defined, not null, and
 * not a whitespace-only string. Numeric `0`, boolean `false`, and empty
 * arrays count as present — the agent may legitimately persist those.
 */
import type { LoadedSchema } from "./schema-loader.js";
import type { LiveSchemaSource } from "./live-schema-source.js";
import type { VerticalContext } from "./resolve-active-vertical.js";
export interface ValidateWriteInput {
    labels: string[];
    properties: Record<string, unknown>;
    accountId?: string;
}
export interface ValidatorEnv {
    /** Markdown sidecar — required-property + synonym metadata. */
    schema: LoadedSchema;
    /** Live ∪ declared label source — gates label existence. */
    liveSource: LiveSchemaSource;
    /** Test-injectable log emitter. Default: process.stderr. */
    emit?: (line: string) => void;
}
export interface ValidateWriteOptions {
    /**
     * `"create"` (default) — full validation: synonym pass, forbidden-property
     * pass, required-property pass.
     * `"update"` — partial-update mode. Skips the required-property
     * loop only; synonym + forbidden checks still fire. Use when SETting
     * additional properties on a node that already passed required-props at
     * create time (the canonical case is `profile-update.personFields`
     * adding identity fields to a personal-profile Person whose
     * givenName/familyName were written at PIN setup). The accept path emits
     * `[schema-validator] check label=<X> mode=update …` so partial writes
     * are forensically distinguishable from full writes.
     */
    mode?: "create" | "update";
    /**
     * Active-vertical context resolved by the caller (memory-write /
     * profile-update). When omitted, the validator behaves as if no brand
     * vertical were declared and no LocalBusiness override applied — only
     * base rules fire. Callers in production paths always pass this; tests
     * may omit it to assert the base-only contract.
     */
    verticalContext?: VerticalContext;
}
/**
 * Validate a write. Throws on the first violation. Caller is responsible
 * for logging the thrown error in addition to the structured outcome lines
 * this function emits — this stays a (mostly) pure unit so test fixtures
 * can capture both the throw path and the emit stream.
 */
export declare function validateWrite(input: ValidateWriteInput, env: ValidatorEnv, options?: ValidateWriteOptions): void;
//# sourceMappingURL=schema-validator.d.ts.map