/** * Brief-type baseline — per-cell SHA-256 hashes for three-way merge * across the type's metadata and its `fields[]` array. * * Cell-path scheme (flat namespace, mirrors brand-kit's * `BrandBaselinePayload.cells`): * * - `name` — top-level codename * - `label` — localized human label * - `description` — human description * - `icon` — mdi icon codepoint * - `iconColor` — hex/named color * - `fields.` — whole field-definition object, keyed by * `BriefField.name` * * Hashing the whole field-definition object per codename keeps the * cell count proportional to the field count without dragging in * per-property classifications — a localized-label edit on a single * field surfaces as a `fields.` cms-edit, not five separate * intra-field cells. That mirrors how the API converges a brief type: * the only write path is a whole-record PUT, so per-property cells * would not give the operator finer control anyway. * * `fields[]` is array-ordered on the wire; the API preserves display * order. Adds/removes/reorders show up as `first-push` (new codename), * cms-side delete (codename absent from desired, present in baseline + * current), or a position-only edit. Position changes alone don't * register because the cell hash is over the field object content, * not its index — that's intentional: registry-author intent is the * field-definition graph, position drift is noise. */ import { type FieldClassification } from "../../sync/index.js"; import type { Baseline } from "../../sync/index.js"; import type { BriefTypeRecipe } from "./schema.js"; export interface BriefTypeBaselinePayload { schemaVersion: "1"; /** Flat path → SHA-256 hash. See module doc for the path vocabulary. */ cells: Record; /** * Server UUID of the brief-type row this baseline was captured * against. Optional for back-compat with baselines written before * this field landed. When present, the kind's apply path prefers * id-match (via `getBriefType(id)`) before falling back to the * codename-based `findTypeByName` — survives a codename refactor * without orphaning the existing tenant row. */ tenantId?: string; } export type BriefTypeBaseline = Baseline; /** The five top-level scalars that participate in three-way merge. */ declare const SCALAR_CELLS: readonly ["name", "label", "description", "icon", "iconColor"]; type ScalarCell = (typeof SCALAR_CELLS)[number]; declare const fieldCellPath: (codename: string) => string; /** * Walk a brief-type recipe and emit per-cell hashes. Each scalar is its * own cell; each field-definition is one cell keyed by its codename. */ export declare const hashBriefTypeCells: (recipe: BriefTypeRecipe) => Record; /** * Construct a baseline payload from a successfully applied recipe. * Pass the tenant `id` returned by `createBriefType` / read from * `findTypeByName` after `updateBriefType` so the next push can * resolve the row by id rather than relying on a codename match. */ export declare const captureBriefTypeBaselinePayload: (recipe: BriefTypeRecipe, tenantId?: string) => BriefTypeBaselinePayload; /** * Three-way classify every cell across desired / current / baseline. * Cells present in only one side classify against `hashJsonValue(undefined)` * on the other. */ export declare const classifyBriefTypeCells: (desired: BriefTypeRecipe, current: BriefTypeRecipe, baselinePayload: BriefTypeBaselinePayload | undefined) => Record; /** * Merge desired vs current per the policy and return a brief-type * recipe whose scalars + `fields[]` carry policy-resolved values. * * Tenant-only fields (codename absent from desired) are NOT pulled * into the merged recipe even under `cms-wins` — the recipe author * owns the field graph, mirroring brand-kit's section-graph ownership. * A cms-side delete on a recipe-declared field IS preserved under * `cms-wins` only by skipping the recipe value, which doesn't model * well on a whole-record PUT — see the inline comment in the field * loop for the chosen behaviour. */ export declare const mergeBriefTypeByPolicy: (desired: BriefTypeRecipe, current: BriefTypeRecipe, classifications: Record, policy: "error" | "recipe-wins" | "cms-wins") => { merged: BriefTypeRecipe; policyErrors: Array<{ path: string; classification: FieldClassification; }>; }; export { SCALAR_CELLS, fieldCellPath }; export type { ScalarCell };