/**
 * Module-level normalization helpers shared by StrandDescriptorStore.
 *
 * The strand descriptor parser (`parseStrandBlob`) validates identity
 * and coordinate fields but leaves `intentQueue` and `evolution`
 * trailing fields as raw JSON bags. This module is the boundary decoder
 * that converts those trailing bags into the typed strand model
 * (StrandIntentQueue, StrandEvolution, etc.).
 *
 * @module domain/services/strand/descriptorNormalization
 */
import type { StrandDescriptor } from '../../utils/parseStrandBlob.ts';
import type Patch from '../../types/Patch.ts';
/**
 * Recursive hashable shape produced by JSON-decoded blob fields. The
 * strand descriptor blob was already JSON-parsed; the trailing
 * `intentQueue`/`evolution` fields carry values of this shape after
 * descriptor parsing leaves them as raw trailing data.
 */
export type RawValue = string | number | boolean | null | readonly RawValue[] | RawBag | undefined;
/**
 * A plain-object bag produced by JSON decode. Used as the post-
 * narrowing structural type for the trailing descriptor fields.
 */
export type RawBag = {
    readonly [key: string]: RawValue;
};
/**
 * Type-guard predicate: narrows a blob field to RawBag.
 */
export declare function isRawBag(value: unknown): value is RawBag;
export type StrandReadOverlayDescriptor = {
    strandId: string;
    overlayId: string;
    kind: string;
    headPatchSha: string | null;
    patchCount: number;
};
/**
 * Typed normalizer: narrows a RawValue to a positive integer, else
 * returns the fallback. Public surface kept for backward
 * compatibility with the prior helper name.
 */
export declare function normalizePositiveInteger(value: RawValue, fallback: number): number;
/**
 * Typed normalizer: narrows a RawValue to a non-negative integer,
 * else returns the fallback.
 */
export declare function normalizeNonNegativeInteger(value: RawValue, fallback: number): number;
/**
 * Normalize a required string field out of a raw bag. Rejects with
 * a StrandError when the value is present but not a string.
 * Preserves the defensive boundary contract that existed before
 * cycle 0025B3 tightened the TS types.
 */
export declare function normalizeRequiredString(record: RawBag, key: string, field: string): string;
/**
 * Coerce a raw value into a sorted array of read-overlay descriptors.
 */
export declare function normalizeReadOverlays(value: RawValue): StrandReadOverlayDescriptor[];
/**
 * Check whether two read-overlay arrays are structurally identical.
 */
export declare function readOverlaysEqual(left: StrandReadOverlayDescriptor[], right: StrandReadOverlayDescriptor[]): boolean;
/**
 * Check whether two read-overlay descriptors are structurally identical.
 */
export declare function readOverlayEqual(overlay: StrandReadOverlayDescriptor, candidate: StrandReadOverlayDescriptor | undefined): boolean;
/**
 * Return true if descriptor overlay metadata matches the expected values.
 */
export declare function overlayMetadataMatches(descriptor: StrandDescriptor & {
    overlay: {
        writable: boolean;
    };
}, expected: {
    headPatchSha: string | null;
    patchCount: number;
    writable: boolean;
}): boolean;
export type StrandRejectedCounterfactual = {
    intentId: string;
    reason: string;
    conflictsWith: string[];
    reads: string[];
    writes: string[];
};
export type StrandTickRecord = {
    tickId: string;
    strandId: string;
    tickIndex: number;
    createdAt: string;
    drainedIntentCount: number;
    admittedIntentIds: string[];
    rejected: StrandRejectedCounterfactual[];
    baseOverlayHeadPatchSha: string | null;
    overlayHeadPatchSha: string | null;
    overlayPatchShas: string[];
};
export type StrandQueuedIntent = {
    intentId: string;
    enqueuedAt: string;
    patch: Patch;
    reads: string[];
    writes: string[];
    contentBlobOids: string[];
};
export type StrandIntentQueue = {
    nextIntentSeq: number;
    intents: StrandQueuedIntent[];
};
export type StrandEvolution = {
    tickCount: number;
    lastTick: StrandTickRecord | null;
};
/**
 * Coerce a raw value into a validated intent queue with sequence counter.
 */
export declare function normalizeIntentQueue(value: RawValue, normalizeQueuedIntentsFn: (value: RawValue) => StrandQueuedIntent[]): StrandIntentQueue;
/**
 * Coerce a raw value into a validated evolution record with tick count.
 */
export declare function normalizeEvolution(value: RawValue, normalizeLastTickFn: (lastTick: RawBag | null) => StrandTickRecord | null): StrandEvolution;
/**
 * Parse a raw array into validated rejected-counterfactual records.
 */
export declare function normalizeRejectedCounterfactuals(value: RawValue): StrandRejectedCounterfactual[];
/**
 * Validate and normalize a raw last-tick record into a typed tick record.
 */
export declare function normalizeLastTick(lastTick: RawBag | null): StrandTickRecord | null;
/**
 * Parse one queued-intent entry, dropping malformed records.
 */
export declare function normalizeQueuedIntentEntry(rawEntry: RawValue): StrandQueuedIntent[];
/**
 * Parse and validate a raw array into typed queued intents, discarding malformed entries.
 */
export declare function normalizeQueuedIntents(value: RawValue): StrandQueuedIntent[];
/**
 * Resolve the required identity fields for one queued-intent record.
 * Returns null when required identity fields are missing.
 *
 * The `patch` field carries a Patch instance reconstructed from the
 * JSON-decoded intent bag. `rawBagToPatch` walks the structural
 * shape the boundary parser left behind; the cast lives there,
 * colocated with the structural decoder rather than sprayed through
 * the normalizer.
 */
export declare function resolveQueuedIntentIdentity(candidate: RawBag): {
    patch: Patch;
    intentId: string;
    enqueuedAt: string;
} | null;
