/**
* Declared row identity (T12341): which syncing tables carry a uid and how it
* is made. Data only, with type-only imports, so the Gate B scripts
* (`scripts/fingerprint-store.mjs`) load it straight from source, like the
* Gate A registry. The uid recipes and the fill live in `row-identity.ts`.
* Spec: `cleo docs fetch t12341-uid-scheme`.
*
* @module
* @task T12341
* @task T12897
* @epic T12323
*/
import type { RowIdentitySpec, TableScope } from '@cleocode/contracts';
/** Physical name of every uid column. */
export declare const UID_COLUMN = "uid";
/**
* The rows of a declared table that should carry a uid but lack one (a SQL
* predicate over `main.
`): not kept local by a NULL key column
* (`localWhenNull`), nor by an earlier row holding the same natural key
* (`localUnlessFirst`, T13777).
*
* @param spec - A declared table's spec.
* @returns The predicate, for a `WHERE` over `main.`.
*/
export declare function uidMissingWhere(spec: RowIdentitySpec): string;
/**
* The rows of a declared table that sync (T13777): every row with a uid, and
* the rows still waiting for one. A row local by spec ({@link uidMissingWhere})
* is not one of them. `null` for a table with no local rule (all rows sync).
*
* @param spec - A declared table's spec.
* @returns The predicate, for a `WHERE` over `main.`, or `null`.
*/
export declare function syncedRowsWhere(spec: RowIdentitySpec): string | null;
/** Physical name of the birth fingerprint column of every minted table. */
export declare const BIRTH_FP_COLUMN = "birth_fp";
/**
* Declared row identity, per scope. Every syncing table is either declared
* here or exempt with a reason in {@link ROW_IDENTITY_EXEMPT} (T12897); the
* row-identity coverage gate fails on a table in neither.
*
* Tables whose bare twin is still the live write target (attachments, ADRs,
* token usage, …) are declared when their twin collapse lands (spec §10).
*
* `content` and `birthFacts` lists are FROZEN for recipe v1: changing one is a
* new recipe version, never an edit here.
*/
export declare const ROW_IDENTITY: Readonly>;
/**
* Tables that exist only to support row identity (added by the uid migration
* itself). A replay of a store from before that migration leaves them out,
* with the identity columns (`fingerprint-store.mjs --omit-row-identity`).
* Includes the local-only AC uid graveyard (spec §6.5).
*/
export declare const ROW_IDENTITY_TABLES: Readonly>;
/**
* Why a syncing table syncs without declared row identity (T12897).
*
* - `planned` — a filed task gives the table its uid; it syncs without one
* until then.
* - `twin-collapse` — one of a live exodus twin pair that both sync, or a
* table the collapse must change first; the uid goes on the survivor once
* T12535 collapses the pair (spec §10).
* - `not-row-replicated` — the table does not travel as rows at all.
*
* @task T12897
*/
export type RowIdentityExemptionCategory = 'planned' | 'twin-collapse' | 'not-row-replicated';
/**
* A syncing table's declared reason for having no {@link ROW_IDENTITY} entry.
*
* @task T12897
*/
export interface RowIdentityExemption {
/** Kind of reason. */
readonly category: RowIdentityExemptionCategory;
/** Why the table syncs without row identity, and what ends the exemption. */
readonly reason: string;
/** The task that ends the exemption; it must exist and be open. */
readonly task: string;
}
/**
* Bare tables the twin collapse DRAINS into their prefixed twin (T13115,
* T13777), bare name → twin name. Kept here, a module every open already loads, so
* the bare-twin strand check (`sync/flags.ts`) adds nothing to the CLI's
* startup graph (gate 39).
*
* A drained bare table is the inbox of rows an older build writes: every open
* moves them into the twin losslessly, and a row the drain must leave behind
* is reported by `cleo doctor twin-collapse`. So its rows are never a legacy
* strand that should refuse capture or sealing: the next open carries them.
*
* @task T13777
*/
export declare const DRAINED_TWINS: Readonly>;
/**
* Every syncing table WITHOUT a {@link ROW_IDENTITY} entry, with the reason it
* syncs without one. A syncing table in neither place fails the row-identity
* coverage gate (`scripts/lint-row-identity-coverage.mjs` against the
* classification registry, `__tests__/row-identity-gate.test.ts` against
* fresh stores), and so does an exemption whose table is declared, no longer
* exists or no longer syncs. Declaring a table drops its exemption in the
* same change.
*
* @task T12897
*/
export declare const ROW_IDENTITY_EXEMPT: Readonly>>>;
/**
* The exemption count per scope. Only ever lowered: a change that declares
* tables lowers it in the same change, so the allowance cannot be spent again,
* and a new syncing table is declared rather than exempted unless the change
* raises this on purpose.
*
* Since T12894 declared the brain text-keyed tables (11 project, 12 global),
* T12895 the brain natural-key tables (3 project, 3 global) and T12896 the
* brain integer-keyed tables (6 project, 6 global), T12915 declared the
* agent registry (1 global; 6 more reclassified derived or local-only),
* T13354 declared the re-keyed conduit doc family (5 project, dropping 4
* exemptions — contributors became derived and not syncing), T13467 the
* credential tables (4 global), and T12919 the doc registry and its refs
* (2 project; docs_wikilinks became derived and not syncing), and T13729
* reclassified brain_embeddings derived in both scopes (owner decision
* 2026-10-14: vectors are a local cache), closing the T12918 blob exemption,
* and T12914 the lifecycle, release, PR and commit tables (16 project),
* and T13777 declared the command logs (3 project: the audit log, token
* usage, handoff entries; 1 global: the Nexus audit log),
* and T12535 the project sticky tables and the playbook tables (2 + 4
* project: the bare playbook twins became frozen-legacy and not syncing)
* ({@link rowIdentityExemptionSummary} prints the live numbers):
*
* | category | task | project | global |
* |----------------------|--------|---------|--------|
* | planned | T12894 | 0 | 0 |
* | planned | T12895 | 0 | 0 |
* | planned | T12896 | 2 | 1 |
* | planned (conduit) | T12913 | 8 | 0 |
* | planned (lifecycle…) | T12914 | 0 | 0 |
* | planned (nexus) | T12916 | 0 | 7 |
* | planned (skills) | T12917 | 0 | 4 |
* | planned (misc) | T12920 | 11 | 0 |
* | twin-collapse | T12535 | 22 | 0 |
* | total | | 41 | 11 |
*
* @task T12897
*/
export declare const ROW_IDENTITY_EXEMPT_PINNED: Readonly>;
/**
* sha256 of each scope's sorted exempt table names
* ({@link rowIdentityExemptDigest}), pinned with the count so swapping one
* exempt table for another fails too (#1764 review L4). Update it in the same
* change that drops an exemption; the gate prints the new value.
*
* @task T12897
*/
export declare const ROW_IDENTITY_EXEMPT_NAMES_SHA256: Readonly>;
/**
* sha256 (hex) of a set of table names, sorted and newline-joined.
*
* @param names - Table names.
* @returns The hex digest.
* @task T12897
*/
export declare function rowIdentityExemptDigest(names: Iterable): string;
/**
* Exemption counts of one scope, by category and by `category task`.
*
* @param scope - Store scope.
* @returns `total`, `byCategory` and `byTask` (key ` `),
* keys sorted.
* @task T12897
*/
export declare function rowIdentityExemptionSummary(scope: TableScope): {
total: number;
byCategory: Record;
byTask: Record;
};
/**
* One problem the row-identity coverage gate reports.
*
* - `missing` — a syncing table with neither a declared uid nor an exemption.
* - `stale` — an exemption whose table is not a syncing table (gone, or
* reclassified to a class that does not sync).
* - `declared` — an exemption whose table is also declared.
* - `invalid` — an exemption without a reason or a `T` task.
* - `pinned` — the exemption count or the digest of the exempt names differs
* from its pin.
*
* @task T12897
*/
export interface RowIdentityCoverageProblem {
readonly kind: 'missing' | 'stale' | 'declared' | 'invalid' | 'pinned';
readonly table?: string;
readonly message: string;
}
/**
* Check that every syncing table is declared or exempt, and that every
* exemption still names an undeclared syncing table. Pure: the caller supplies
* the syncing set (from the classification registry or a physical store).
*
* @param input - `syncing`: the scope's syncing tables; `declared`: tables
* with a {@link ROW_IDENTITY} entry; `exempt`: the scope's exemptions;
* `pinned`: the expected exemption count (omit to skip); `pinnedDigest`:
* the expected {@link rowIdentityExemptDigest} of the exempt names (omit to
* skip); `mayBeAbsent`:
* exempt tables allowed to be missing from `syncing` (a fresh store leaves
* out optional-transient tables).
* @returns The problems; empty when every syncing table is covered.
* @task T12897
*/
export declare function checkRowIdentityCoverage(input: {
readonly syncing: Iterable;
readonly declared: Iterable;
readonly exempt: Readonly>;
readonly pinned?: number;
readonly pinnedDigest?: string;
readonly mayBeAbsent?: Iterable;
}): RowIdentityCoverageProblem[];
/**
* The declared identity of a table, or `undefined` when it has none (yet).
*
* @param scope - Store scope.
* @param table - Physical table name.
* @returns The spec, or `undefined`.
*/
export declare function rowIdentitySpec(scope: TableScope, table: string): RowIdentitySpec | undefined;
/**
* The identity columns of a table: `uid`, `birth_fp` (minted tables) and its
* stored reference facts. Replay comparisons of a store before and after the
* uid migration leave these out (`fingerprint-store.mjs --omit-row-identity`).
*
* @param scope - Store scope.
* @param table - Physical table name.
* @returns Column names; empty for an undeclared table.
*/
export declare function rowIdentityColumns(scope: TableScope, table: string): string[];
//# sourceMappingURL=row-identity-registry.d.ts.map