/**
 * topicProfileIngress — the §10.1 SERVER-SIDE conversational ingress for
 * Topic Profile writes (TOPIC-PROFILE-SPEC §10.1, §8 'switch now', §10.4
 * cooldown confirm).
 *
 * Two pieces, both pure logic (no I/O — the write surface owns side effects):
 *
 *  1. The deterministic TRIGGER GRAMMAR (`parseProfileTrigger`). The parse
 *     runs in the message-ingress pipeline where the authenticated sender uid
 *     is first-party — the uid reaches the store through code, never through
 *     a body the agent composed. The grammar is a CLOSED set (Tier 0, §14):
 *     no fuzzy matcher ever holds write authority. Out-of-grammar phrasings
 *     ride the propose-then-confirm lane instead.
 *
 *  2. The ARMED-CONFIRM slot manager (`ProfileConfirmSlots`). ALL THREE
 *     confirm surfaces — §10.1 propose-confirm, §8 switch-now, §10.4
 *     re-apply-cooldown — share ONE armed slot per topic (round-7: a bare
 *     "yes" must never be ambiguous about which confirm it fires). The slot
 *     enforces:
 *      - TTL (`switchNowConfirmTtlMs`),
 *      - event-based ordering on PLATFORM MESSAGE IDS (the confirm's id must
 *        be > the latest echo's platform-returned id; ties refused toward
 *        re-echo — never a cross-clock timestamp compare, round-7),
 *      - supersession (a re-proposal invalidates any in-flight confirm; the
 *        confirm must answer the LATEST echo),
 *      - a re-proposal rate bound per topic (churn is a suspicion signal —
 *        past the bound the slot refuses re-proposals for a cooldown and
 *        tears down, round-7),
 *      - forwarded-content rejection (a message carrying platform forward
 *        metadata never matches ANY ingress recognition, round-5).
 */
import type { ProfilePatchInput } from './topicProfileValidation.js';
export type ProfileTrigger = {
    kind: 'write';
    patch: ProfilePatchInput;
} | {
    kind: 'readout';
} | {
    kind: 'undo';
} | {
    kind: 'clear';
} | {
    kind: 'reapply';
} | {
    kind: 'switch-now';
} | {
    kind: 'confirm';
};
/**
 * Parse a first-party operator turn against the closed trigger set.
 * Returns null for anything outside the grammar — the message then routes
 * to the session normally (the agent may propose via the §10.1
 * propose-confirm lane). Deterministic and anchored: a trigger is the WHOLE
 * message (trailing punctuation tolerated), never a substring match inside
 * prose — quoting someone else's "use codex here" mid-paragraph must not
 * fire a write.
 */
export declare function parseProfileTrigger(text: string): ProfileTrigger | null;
export type ArmedConfirmKind = 'propose-confirm' | 'switch-now' | 'reapply-cooldown';
export interface ArmedConfirm {
    kind: ArmedConfirmKind;
    topicKey: string;
    /** The registered structured delta (what a confirm will actually write). */
    patch: ProfilePatchInput;
    /** The SERVER-rendered echo (what the operator saw — §10.1(b)). */
    echoText: string;
    /** Platform-returned message id of the latest echo (ordering anchor). */
    echoPlatformMessageId: number | null;
    armedAt: number;
    /** Audit provenance: agent-composed (propose lane) vs ingress-derived. */
    origin: 'agent-composed' | 'ingress';
}
export type ConfirmMatch = {
    ok: true;
    armed: ArmedConfirm;
} | {
    ok: false;
    reason: 'none-armed' | 'expired' | 'stale-order' | 'no-echo-id' | 'forwarded';
};
export interface ProfileConfirmSlotsOptions {
    /** §12.5 switchNowConfirmTtlMs (default 300000). */
    ttlMs?: () => number;
    /** Re-proposal rate bound per topic (hardcoded v1 default: 5 per 10min). */
    maxProposalsPerWindow?: number;
    proposalWindowMs?: number;
    now?: () => number;
    audit?: (event: Record<string, unknown>) => void;
}
export declare class ProfileConfirmSlots {
    private slots;
    /** Re-proposal timestamps per topic (rate bound, round-7). */
    private proposalTimes;
    /** Topics cooling down after a proposal-churn trip. */
    private churnCooldownUntil;
    private readonly opts;
    private readonly now;
    constructor(opts?: ProfileConfirmSlotsOptions);
    private ttl;
    /**
     * Arm (or supersede) the topic's ONE confirm slot. Returns ok:false when
     * the topic is rate-bounded on re-proposals (the armed proposal is torn
     * down and the operator re-states fresh — round-7).
     */
    arm(topicKey: string, kind: ArmedConfirmKind, patch: ProfilePatchInput, echoText: string, origin: ArmedConfirm['origin']): {
        ok: true;
        superseded: boolean;
    } | {
        ok: false;
        reason: 'proposal-churn-cooldown';
    };
    /** Record the platform-returned id of the echo we just sent (ordering anchor). */
    recordEchoMessageId(topicKey: string, platformMessageId: number): void;
    /** The armed slot, if any (readout / switch-now no-op reply). */
    peek(topicKey: string): ArmedConfirm | null;
    disarm(topicKey: string): void;
    /**
     * Match an inbound affirmative against the armed slot. On ok:true the slot
     * is CONSUMED (one confirm per echo). Refusals leave the slot armed except
     * 'expired' (torn down).
     */
    matchConfirm(topicKey: string, ctx: {
        platformMessageId: number | null;
        forwarded: boolean;
    }): ConfirmMatch;
}
/** Parse the numeric platform message id from a Message.id like `tg-12345`. */
export declare function platformMessageIdFrom(messageId: string | undefined): number | null;
//# sourceMappingURL=topicProfileIngress.d.ts.map