/**
 * time/periodForm — a tool's period FORMS as DECLARED (time design § 7.1):
 * the shapes, the sugar, each form's own rules, a declared value's spelling,
 * and the tool's facts against a range.
 *
 * Pattern: the declaration half of `convert.ts`, split from the conversions so
 *          the SYNCHRONOUS doors — `defineTool({ period })`
 *          (`tools/declare.ts`), a time answer's check at the resume
 *          door (`ask.ts` · `checkTimeAnswer`) and the checkpoint door's
 *          refusal codes (`rows.ts`) — reach it without the conversion
 *          engine, which only an armed agent loads (`bind.ts`, `drift.ts`,
 *          reached through `import()`: the optional-family law of docs-next's
 *          site budget). `convert.ts` re-exports everything public here.
 * Role:    L0 leaf (the time layer). Imports `instant.ts`, `duration.ts`
 *          and `zone.ts` only.
 * Emits:   N/A.
 *
 * @example
 * ```ts
 * const [form] = sugarForms({ argument: 'window', spelling: 'iso-range' });
 * formIssue(form); // undefined — a well-formed form
 * parsesUnderForm('2026-10-09T08:00:00-07:00..2026-10-09T08:40:59-07:00', form, 'window'); // true
 * ```
 */
import { type DurationText } from './duration.js';
import { type InstantText } from './instant.js';
import { type Edge, type TimeRange } from './range.js';
import { type WallTime } from './zone.js';
/** The single-argument spellings — today's three, and `wall-range` (wall times plus a zone argument). */
export type PeriodSpelling = 'lookback' | 'signed-lookback' | 'iso-range' | 'wall-range';
/** The spellings, in the order the docs list them. */
export declare const PERIOD_SPELLINGS: readonly PeriodSpelling[];
/** How one bound is written: an instant with its offset, epoch milliseconds or seconds, a calendar date, a wall time. */
export type BoundAs = 'iso' | 'epoch-ms' | 'epoch-s' | 'date' | 'wall';
export declare const BOUND_AS: readonly BoundAs[];
/**
 * One bound of a two-argument period. A `from` bound is inclusive (its `edge`,
 * when written, can only say so); a `to` bound MUST say its edge
 * ({@link ToBound}) — TQ18: the library never guesses a tool's edge, only the
 * sugar defaults (`inclusive`).
 */
export interface Bound {
    readonly argument: string;
    readonly as: BoundAs;
    readonly edge?: Edge;
}
/** The end bound of a `bounds` form — its edge is declared, never defaulted (TQ18). */
export interface ToBound extends Bound {
    readonly edge: Edge;
}
/** The argument a wall or date form reads its zone from. */
export interface ZoneArgument {
    readonly argument: string;
}
/**
 * Every shape a tool's period can take — one `TimeRange` onto one or more
 * arguments. Any form may carry its own `maxRange` — the widest window THAT
 * form reads at once — when the tool's forms differ (bounds capped at a day,
 * a look-back with no cap): it overrides the period's `maxRange` for that
 * form only ({@link formMaxRange}, the one owner).
 */
export type PeriodForm = {
    readonly kind: 'bounds';
    readonly from: Bound;
    readonly to: ToBound;
    readonly zone?: ZoneArgument;
    readonly maxRange?: DurationText;
} | {
    readonly kind: 'joined';
    readonly argument: string;
    readonly as: BoundAs;
    readonly joiner: '..' | '/';
    readonly edge?: Edge;
    readonly zone?: ZoneArgument;
    readonly maxRange?: DurationText;
} | {
    readonly kind: 'object';
    readonly argument: string;
    readonly keys: {
        readonly from: string;
        readonly to: string;
    };
    readonly as: BoundAs;
    /** Declared, never defaulted (TQ18). */
    readonly edge: Edge;
    readonly zone?: ZoneArgument;
    readonly maxRange?: DurationText;
} | {
    readonly kind: 'day';
    readonly argument: string;
    readonly zone?: ZoneArgument;
    readonly maxRange?: DurationText;
} | {
    readonly kind: 'lookback';
    readonly argument: string;
    readonly signed: boolean;
    /** A unit set ⊆ `smhdw`; absent → today's `mhdw`. */
    readonly units?: string;
    readonly maxRange?: DurationText;
};
export declare const FORM_KINDS: readonly PeriodForm['kind'][];
/** Which side of now a source can hold. */
export type PeriodDirection = 'past' | 'future' | 'any';
/** Facts about the source — never policy (§ 7.1). Durations are in `smhdw`. */
export interface PeriodFacts {
    readonly direction?: PeriodDirection;
    readonly retention?: DurationText;
    readonly maxRange?: DurationText;
    readonly granularity?: DurationText;
    readonly filtersToAsked?: boolean;
}
/** The unit set of a fact's duration (`retention`, `maxRange`, `granularity`). */
export declare const FACT_UNITS = "smhdw";
/** The step a look-back ending "at now" may miss by when no `granularity` is declared (§ 7.4). */
export declare const DEFAULT_GRANULARITY_MS = 60000;
/** The form one single-argument spelling means (the module table). */
export declare function sugarForm(argument: string, spelling: PeriodSpelling, zoneArgument?: string): PeriodForm;
/** The sugar and general halves of a period declaration, as `sugarForms` reads them. */
export interface PeriodShapes {
    readonly argument?: string;
    readonly spelling?: PeriodSpelling;
    readonly accepts?: readonly PeriodSpelling[];
    readonly zoneArgument?: string;
    readonly forms?: readonly PeriodForm[];
}
/**
 * Every form a declaration names, in preference order: `forms` as written,
 * else the sugar (`accepts`, else `spelling`). A declaration that names an
 * argument and no spelling has no form — today's "which argument", nothing
 * the library can convert into.
 */
export declare function sugarForms(period: PeriodShapes): readonly PeriodForm[];
type Plain = Record<string, unknown>;
export declare const isPlain: (value: unknown) => value is Plain;
/**
 * Why one form's own shape is not a form, or `undefined` when it is one. The
 * schema half (does the argument exist, is it the right type, does it carry a
 * rule) is `tools/declare.ts`'s — this is the shape alone.
 */
export declare function formIssue(form: unknown): string | undefined;
/** Whether a form reads wall-clock values and so needs a zone (`wall`, `date`, a `day`). */
export declare function needsZone(form: PeriodForm): boolean;
/** One argument a form names, and what the schema must say of it. */
export interface FormArgument {
    readonly argument: string;
    /** `bound`: carries a value of the window; `zone`: carries the zone; `object`: an object of both bounds. */
    readonly role: 'bound' | 'zone' | 'object';
    /** The JSON Schema type the property must have: a number for an epoch, else a string. */
    readonly type: 'number' | 'string' | 'object';
    /** For a `bound` of a `bounds` form — the bound it carries. */
    readonly bound?: Bound;
}
/** Every argument a form names, the zone argument last. */
export declare function formArguments(form: PeriodForm): readonly FormArgument[];
/** The argument a form is known by — the results layer's join key (its first bound). */
export declare function primaryArgument(form: PeriodForm): string;
/** A wall time written with no offset, and the step its spelling is precise to. */
export declare function wallOf(text: unknown): {
    readonly wall: WallTime;
    readonly stepMs: number;
} | undefined;
/** A calendar date `YYYY-MM-DD`, day-checked. */
export declare function dateOf(text: unknown): {
    readonly year: number;
    readonly month: number;
    readonly day: number;
} | undefined;
/** Whether a single bound value is written the way `as` declares. */
export declare function isBoundValue(value: unknown, as: BoundAs): boolean;
export declare const epochFromText: (text: string) => number | undefined;
/**
 * Whether a declared value (an `assume` default, an `ask` choice) of
 * `argument` is written the way `form` spells that argument. A format check:
 * no clock, no conversion. `true` for an argument the form does not name.
 */
export declare function parsesUnderForm(value: unknown, form: PeriodForm, argument: string): boolean;
/** Why a range breaks one of the tool's facts — a code; the sentence is the catalog's. */
export type PeriodFactProblem = 'time-future' | 'time-past' | 'beyond-retention' | 'over-max-range';
/**
 * Which of the tool's declared facts a half-open range breaks, against the
 * turn's clock — or `undefined`. `past`: a range that starts after now;
 * `future`: one that ends before now; `retention`: only a range WHOLLY older
 * than `now − retention` (a partial overlap is the result's to judge);
 * `maxRange`: a range that REACHES further than it (`range.ts` · `reachMs`:
 * first instant to last, so a look-back exactly `maxRange` long fits — an
 * inclusive ceiling). A fact the tool does not declare is not checked.
 */
export declare function periodFactProblem(range: TimeRange, facts: PeriodFacts, now: InstantText): PeriodFactProblem | undefined;
/**
 * The widest window ONE form reads at once: its own `maxRange`, else the
 * period's — the one owner every door asks (the conversion, a sent window's
 * check, the answer to a period argument). `undefined`: no cap for that form.
 *
 * @example
 * ```ts
 * formMaxRange({ kind: 'bounds', from, to, maxRange: '24h' }, { maxRange: '7d' }); // '24h'
 * formMaxRange({ kind: 'lookback', argument: 'w', signed: false }, { maxRange: '7d' }); // '7d'
 * ```
 */
export declare function formMaxRange(form: PeriodForm, facts: PeriodFacts | undefined): DurationText | undefined;
/** The facts ONE form is judged against: the period's, with the form's own `maxRange` in place. */
export declare function formFacts(form: PeriodForm, facts: PeriodFacts): PeriodFacts;
/**
 * The facts the TOOL is judged against before any form is chosen (a window
 * of the person's to fill, a time ask's choices): `maxRange` is the widest
 * any form reads — none when one form reads with no cap — so a window is
 * refused `over-max-range` only when NO form can read it. The period's facts
 * as declared when no form declares its own `maxRange`.
 */
export declare function toolFacts(forms: readonly PeriodForm[], facts: PeriodFacts): PeriodFacts;
/**
 * Why a call is refused before dispatch (§ 7.2, step T5b): one of the tool's
 * facts ({@link PeriodFactProblem}), a range across days to a tool that reads
 * one day (`multi-day`), a wall time the zone skips (`dst-gap`), or a window
 * of the person's that no form the tool declares can read, exactly or by
 * reading a wider one (`no-form-holds` — a look-back ends at now, so a window
 * still running is out of its reach, and a covering look-back wider than
 * `maxRange` is one the tool will not read). The tool's own rule never stands
 * in for the person's window: its default would read a time nobody asked about.
 */
export type TimeRefusal = PeriodFactProblem | 'multi-day' | 'dst-gap' | 'no-form-holds';
export declare const TIME_REFUSALS: readonly TimeRefusal[];
export {};
//# sourceMappingURL=periodForm.d.ts.map