/** * astroengine interpretation matching + resolver -- the plug for a content layer. * * The {@link interpretationContext} projection turns a chart into ranked fact * atoms; this layer lets a developer plug in *meaning*. A {@link Selector} * matches atoms (and reports which ones, so a claim carries its provenance); a * {@link Rule} pairs a selector with text; an {@link InterpretationSource} * bundles rules (a tradition, a house style, a third-party corpus). The engine * ships the contract and the resolver, never the content: {@link interpret} * runs sources against a context and returns a ranked {@link Reading}, each * entry tagged with the atom ids it rests on. * * Selectors read the projection directly, so they express the whole fact model * -- house, dignity, pattern membership, signature dominance, aspect phase and * strength -- which the geometric, time-only `query` predicates cannot. */ import type { FactAtom, InterpretationContext } from "./interpretation.js"; /** The result of a {@link Selector}: did it match, and on which atoms. */ export interface Match { matched: boolean; /** The atoms that satisfied the selector (the provenance). Empty for a * satisfied absence test ({@link matchNone}). */ atoms: FactAtom[]; } /** Tests a whole {@link InterpretationContext} and reports the matching atoms. */ export type Selector = (ctx: InterpretationContext) => Match; /** Matches placement atoms by any subset of body / sign / house / retrograde / * a held dignity. */ export declare function hasPlacement(filter?: { body?: string; sign?: string; house?: number; retrograde?: boolean; dignity?: string; }): Selector; /** Matches aspect atoms. `between` is an unordered pair; `minStrength` filters * loose aspects; `phase` filters applying/separating. */ export declare function hasAspect(filter?: { a?: string; b?: string; between?: [string, string]; aspect?: string; phase?: string; minStrength?: number; }): Selector; /** Matches configuration atoms by kind and/or a participating body. */ export declare function hasPattern(filter?: { kind?: string; body?: string; }): Selector; /** Matches a structural-signature facet, e.g. `("element", "fire")`. */ export declare function hasSignature(facet: string, value?: string): Selector; /** Matches an angle atom by which angle and/or its sign. */ export declare function hasAngle(angle: string, sign?: string): Selector; /** Matches dispositor atoms by body, its dispositor, and/or the final flag * (a body in its own domicile that terminates a dispositor chain). */ export declare function hasDispositor(filter?: { body?: string; dispositor?: string; final?: boolean; }): Selector; /** Matches a mutual reception, optionally involving a given body and/or the * dignity it runs through (`by`: `"domicile"`, `"exaltation"`, * `"triplicity"`, or a sorted mixed pair like `"domicile-exaltation"`). */ export declare function hasReception(filter?: { body?: string; by?: string; }): Selector; /** Matches a fixed-star conjunction by the catalog star and/or the body on it. */ export declare function hasStar(filter?: { body?: string; star?: string; }): Selector; /** Matches a Hermetic lot by name, and/or its sign or house. */ export declare function hasLot(filter?: { lot?: string; sign?: string; house?: number; }): Selector; /** Matches transit-to-natal aspect atoms. */ export declare function hasTransit(filter?: { transit?: string; natal?: string; aspect?: string; phase?: string; minStrength?: number; }): Selector; /** Matches synastry aspect or house-overlay atoms. */ export declare function hasSynastry(filter?: { mode?: "aspect" | "overlay"; a?: string; b?: string; aspect?: string; body?: string; partner?: "a" | "b"; house?: number; }): Selector; /** Matches a composite midpoint placement. */ export declare function hasComposite(filter?: { body?: string; sign?: string; }): Selector; /** Matches an active time-lord period, optionally by the period's sign * (profection sign, ZR sign) where the system carries one. */ export declare function hasTimelord(filter?: { system?: "profection" | "zr" | "firdaria" | "dasha"; level?: string; lord?: string; sign?: string; }): Selector; /** Matches finer essential-dignity facts (term, face, triplicity, almuten). */ export declare function hasDignityFine(filter?: { facet?: "term" | "face" | "triplicity" | "almuten"; body?: string; ruler?: string; }): Selector; /** Matches a nakshatra placement, optionally down to the pada (quarter). */ export declare function hasNakshatra(filter?: { body?: string; name?: string; lord?: string; pada?: number; }): Selector; /** Matches a varga (divisional chart) placement. */ export declare function hasVarga(filter?: { division?: number; body?: string; sign?: string; }): Selector; /** Matches a parallel or contraparallel of declination. `between` is an * unordered pair; `body` matches either member; `declination` narrows to * `"parallel"` or `"contraparallel"`. */ export declare function hasParallel(filter?: { body?: string; between?: [string, string]; declination?: "parallel" | "contraparallel"; maxOrb?: number; }): Selector; /** Matches an out-of-bounds body (declination beyond the obliquity). */ export declare function hasOutOfBounds(filter?: { body?: string; minMargin?: number; }): Selector; /** Matches a classical yoga. */ export declare function hasYoga(filter?: { yoga?: string; body?: string; }): Selector; /** Matches only when every selector matches; returns the union of their atoms. */ export declare function matchAll(...sels: Selector[]): Selector; /** Matches when any selector matches; returns the atoms from those that did. */ export declare function matchAny(...sels: Selector[]): Selector; /** Matches when the selector does NOT match (an absence test); no atoms. */ export declare function matchNone(sel: Selector): Selector; /** One interpretation: a condition and the text it licenses. */ export interface Rule { /** Stable id, unique within its source. */ id: string; /** The condition over the fact projection. */ when: Selector; /** The interpretation text, or a function of the match for templating. */ text: string | ((match: Match, ctx: InterpretationContext) => string); /** Multiplies the matched atoms' salience when ranking (default 1). */ weight?: number; /** Free-form labels (theme, polarity, ...) carried through to the entry. */ tags?: string[]; } /** A pluggable corpus of rules: a tradition, a house style, a third party. */ export interface InterpretationSource { id: string; version: string; rules: Rule[]; } /** One licensed statement in a {@link Reading}, with its provenance. */ export interface ReadingEntry { /** `"/"`. */ id: string; source: string; rule: string; text: string; /** Ids of the fact atoms this entry rests on -- the audit trail. */ atomIds: string[]; /** Sum of the matched atoms' salience times the rule weight. */ salience: number; tags?: string[]; } /** A resolved interpretation: ranked entries, each citing its facts. */ export interface Reading { jdUt: number; entries: ReadingEntry[]; } /** * Run interpretation sources against a fact projection and return a ranked * {@link Reading}. Each rule whose selector matches emits an entry carrying the * matched atom ids (provenance) and a salience = sum of those atoms' salience x * the rule weight. The engine never ships the content: the sources are the * caller's. * * @param ctx A projection from {@link interpretationContext}. * @param sources One or more {@link InterpretationSource} corpora. * @returns The {@link Reading}; entries are sorted by descending salience. */ export declare function interpret(ctx: InterpretationContext, sources: InterpretationSource[]): Reading; /** Entries about the same facts, gathered. */ export interface ReadingGroup { /** Union of the group's cited atom ids -- the facts it is about. */ atomIds: string[]; /** Member entries, highest salience first. */ entries: ReadingEntry[]; /** Distinct tags across the members. */ tags: string[]; /** True when a declared conflicting tag-pair both appear (the corpus made * opposing claims about the same facts). */ contested: boolean; /** The group's salience (its strongest entry). */ salience: number; } export interface ReconcileOptions { /** Tag pairs that contradict, e.g. `[["affirming", "challenging"]]`. */ conflicts?: [string, string][]; /** Drop an entry whose `text` duplicates a higher-salience one. */ dedupe?: boolean; } /** * Group a {@link Reading}'s entries by the facts they share, so statements about * the same atoms surface together rather than scattered through a flat list -- * the substrate for "everything said about this placement" and for spotting * contention. Entries are connected when their cited atoms overlap; an entry * citing nothing (an absence rule) stands alone. A group is `contested` when a * declared conflicting tag-pair both appear in it. * * Semantic contradiction is the corpus author's to declare (via `tags` + * `conflicts`); the resolver does the bookkeeping, not the judgement. * * @param reading A reading from {@link interpret}. * @param opts Conflicting tag pairs and optional text de-duplication. * @returns Groups sorted by descending salience. */ export declare function reconcile(reading: Reading, opts?: ReconcileOptions): ReadingGroup[];