import type { QuestionData } from "../tool/types.ts";
import type { WrappingSelectItem } from "../view/components/wrapping-select.ts";
/**
 * Row kind discriminator. Single source of truth — derived from the runtime
 * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new
 * variant there forces a `ROW_INTENT_META` entry here (compile-time
 * exhaustiveness via `Record<RowKind, …>`).
 */
export type RowKind = WrappingSelectItem["kind"];
/**
 * Sentinel kinds — the subset of `RowKind` representing protocol-driven rows
 * (vs author-defined `option` rows). The auto-append walker, the reserved-label
 * derivation, and `LABELS_BY_KIND` consumers iterate this list.
 */
export type SentinelKind = Exclude<RowKind, "option">;
export declare const SENTINEL_KINDS: readonly SentinelKind[];
/**
 * Per-kind static metadata. Pure data — no closures, no per-kind handler
 * functions. Behavior-bearing branches (answer construction in
 * `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,
 * and the inline-Input render branch in `wrapping-select.ts`) keep their
 * exhaustive switches and READ flags from this table.
 *
 * Adding a new sentinel:
 *   1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).
 *   2. Add an entry here. Compile fails until both edits are present.
 *   3. (If user-facing) author wherever the row is synthesized — typically
 *      `buildItemsForQuestion` for main-list residents, or the `chatList`
 *      construction site for non-main-list rows.
 *
 * Field semantics:
 * - `label` — user-facing string. For `option` it's an empty placeholder
 *   (per-instance labels come from `QuestionData.options[i].label`); every
 *   sentinel uses its META entry as the single source of truth.
 * - `reserved` — author-facing labels matching this string trigger
 *   `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.
 * - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Chat
 *   lives in its own `chatList` (`questionnaire-session.ts:95`) so its row
 *   never enters the main list.
 * - `numbered` — true iff the row contributes to the main-list numbering
 *   offset that `chatNumberingFor` reads. Multi-select Next is the only
 *   numberable=false row that lives in the list; chat is numbered=true but
 *   `livesInMainList=false` so the flag is moot for chat.
 * - `activatesInputMode` — true iff focusing the row should toggle
 *   `state.inputMode = true`. Read by `state-reducer.ts` `nav` /
 *   `focus_options` cases.
 * - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)
 *   on this row is suppressed. The Next sentinel is the only true.
 * - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits
 *   the question (emits `multi_confirm`). The Next sentinel is the only true.
 * - `autoAppendOnSingleSelectNoPreview` — `buildItemsForQuestion` appends
 *   this row when the question is single-select AND no option carries a
 *   `preview`. The "other" sentinel is the only true.
 * - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row
 *   when the question is multi-select. The Next sentinel is the only true.
 */
export interface RowIntentMeta {
    label: string;
    reserved: boolean;
    livesInMainList: boolean;
    numbered: boolean;
    activatesInputMode: boolean;
    blocksMultiToggle: boolean;
    autoSubmitsInMulti: boolean;
    autoAppendOnSingleSelectNoPreview: boolean;
    autoAppendOnMultiSelect: boolean;
}
export declare const ROW_INTENT_META: Record<RowKind, RowIntentMeta>;
/**
 * Kind-keyed label view. `option` is excluded — its label is per-instance,
 * not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.
 */
export declare const LABELS_BY_KIND: {
    readonly [K in SentinelKind]: string;
};
/**
 * Reserved-label set for runtime validation. Includes "Other" (a model-conditioned
 * label that has no runtime kind) plus every sentinel with `reserved: true`.
 */
export declare const RESERVED_LABEL_SET: ReadonlySet<string>;
/**
 * Walk the META table to synthesize sentinel rows for one question. The two
 * append predicates are mutually exclusive in practice (`multiSelect` vs
 * `!multiSelect && !hasAnyPreview`) but the walker doesn't enforce that —
 * adding a third bucket only requires a new META flag.
 *
 * Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The
 * caller wraps each with the `WrappingSelectItem` shape (kind + label).
 */
export declare function sentinelsToAppend(question: QuestionData, hasAnyPreview: boolean): SentinelKind[];
//# sourceMappingURL=row-intent.d.ts.map