/** * 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; 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= 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