caelus 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/accuracy.json +15 -15
- package/dist/src/anchored.d.ts +49 -0
- package/dist/src/anchored.js +40 -0
- package/dist/src/astrocartography.js +6 -1
- package/dist/src/brief.d.ts +90 -0
- package/dist/src/brief.js +85 -0
- package/dist/src/chart.d.ts +43 -0
- package/dist/src/chart.js +83 -4
- package/dist/src/counterfactual.d.ts +82 -0
- package/dist/src/counterfactual.js +105 -0
- package/dist/src/eclipses.d.ts +103 -0
- package/dist/src/eclipses.js +260 -2
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +6 -0
- package/dist/src/interpret.d.ts +167 -0
- package/dist/src/interpret.js +192 -0
- package/dist/src/interpretation.d.ts +174 -0
- package/dist/src/interpretation.js +270 -0
- package/dist/src/node-loader.js +5 -2
- package/dist/src/provenance.d.ts +135 -0
- package/dist/src/provenance.js +159 -0
- package/package.json +1 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine interpretation matching + resolver -- the plug for a content layer.
|
|
3
|
+
*
|
|
4
|
+
* The {@link interpretationContext} projection turns a chart into ranked fact
|
|
5
|
+
* atoms; this layer lets a developer plug in *meaning*. A {@link Selector}
|
|
6
|
+
* matches atoms (and reports which ones, so a claim carries its provenance); a
|
|
7
|
+
* {@link Rule} pairs a selector with text; an {@link InterpretationSource}
|
|
8
|
+
* bundles rules (a tradition, a house style, a third-party corpus). The engine
|
|
9
|
+
* ships the contract and the resolver, never the content: {@link interpret}
|
|
10
|
+
* runs sources against a context and returns a ranked {@link Reading}, each
|
|
11
|
+
* entry tagged with the atom ids it rests on.
|
|
12
|
+
*
|
|
13
|
+
* Selectors read the projection directly, so they express the whole fact model
|
|
14
|
+
* -- house, dignity, pattern membership, signature dominance, aspect phase and
|
|
15
|
+
* strength -- which the geometric, time-only `query` predicates cannot.
|
|
16
|
+
*/
|
|
17
|
+
import type { FactAtom, InterpretationContext } from "./interpretation.js";
|
|
18
|
+
/** The result of a {@link Selector}: did it match, and on which atoms. */
|
|
19
|
+
export interface Match {
|
|
20
|
+
matched: boolean;
|
|
21
|
+
/** The atoms that satisfied the selector (the provenance). Empty for a
|
|
22
|
+
* satisfied absence test ({@link matchNone}). */
|
|
23
|
+
atoms: FactAtom[];
|
|
24
|
+
}
|
|
25
|
+
/** Tests a whole {@link InterpretationContext} and reports the matching atoms. */
|
|
26
|
+
export type Selector = (ctx: InterpretationContext) => Match;
|
|
27
|
+
/** Matches placement atoms by any subset of body / sign / house / retrograde /
|
|
28
|
+
* a held dignity. */
|
|
29
|
+
export declare function hasPlacement(filter?: {
|
|
30
|
+
body?: string;
|
|
31
|
+
sign?: string;
|
|
32
|
+
house?: number;
|
|
33
|
+
retrograde?: boolean;
|
|
34
|
+
dignity?: string;
|
|
35
|
+
}): Selector;
|
|
36
|
+
/** Matches aspect atoms. `between` is an unordered pair; `minStrength` filters
|
|
37
|
+
* loose aspects; `phase` filters applying/separating. */
|
|
38
|
+
export declare function hasAspect(filter?: {
|
|
39
|
+
a?: string;
|
|
40
|
+
b?: string;
|
|
41
|
+
between?: [string, string];
|
|
42
|
+
aspect?: string;
|
|
43
|
+
phase?: string;
|
|
44
|
+
minStrength?: number;
|
|
45
|
+
}): Selector;
|
|
46
|
+
/** Matches configuration atoms by kind and/or a participating body. */
|
|
47
|
+
export declare function hasPattern(filter?: {
|
|
48
|
+
kind?: string;
|
|
49
|
+
body?: string;
|
|
50
|
+
}): Selector;
|
|
51
|
+
/** Matches a structural-signature facet, e.g. `("element", "fire")`. */
|
|
52
|
+
export declare function hasSignature(facet: string, value?: string): Selector;
|
|
53
|
+
/** Matches an angle atom by which angle and/or its sign. */
|
|
54
|
+
export declare function hasAngle(angle: string, sign?: string): Selector;
|
|
55
|
+
/** Matches dispositor atoms by body, its dispositor, and/or the final flag
|
|
56
|
+
* (a body in its own domicile that terminates a dispositor chain). */
|
|
57
|
+
export declare function hasDispositor(filter?: {
|
|
58
|
+
body?: string;
|
|
59
|
+
dispositor?: string;
|
|
60
|
+
final?: boolean;
|
|
61
|
+
}): Selector;
|
|
62
|
+
/** Matches a mutual reception, optionally involving a given body. */
|
|
63
|
+
export declare function hasReception(filter?: {
|
|
64
|
+
body?: string;
|
|
65
|
+
}): Selector;
|
|
66
|
+
/** Matches a fixed-star conjunction by the catalog star and/or the body on it. */
|
|
67
|
+
export declare function hasStar(filter?: {
|
|
68
|
+
body?: string;
|
|
69
|
+
star?: string;
|
|
70
|
+
}): Selector;
|
|
71
|
+
/** Matches a Hermetic lot by name, and/or its sign or house. */
|
|
72
|
+
export declare function hasLot(filter?: {
|
|
73
|
+
lot?: string;
|
|
74
|
+
sign?: string;
|
|
75
|
+
house?: number;
|
|
76
|
+
}): Selector;
|
|
77
|
+
/** Matches only when every selector matches; returns the union of their atoms. */
|
|
78
|
+
export declare function matchAll(...sels: Selector[]): Selector;
|
|
79
|
+
/** Matches when any selector matches; returns the atoms from those that did. */
|
|
80
|
+
export declare function matchAny(...sels: Selector[]): Selector;
|
|
81
|
+
/** Matches when the selector does NOT match (an absence test); no atoms. */
|
|
82
|
+
export declare function matchNone(sel: Selector): Selector;
|
|
83
|
+
/** One interpretation: a condition and the text it licenses. */
|
|
84
|
+
export interface Rule {
|
|
85
|
+
/** Stable id, unique within its source. */
|
|
86
|
+
id: string;
|
|
87
|
+
/** The condition over the fact projection. */
|
|
88
|
+
when: Selector;
|
|
89
|
+
/** The interpretation text, or a function of the match for templating. */
|
|
90
|
+
text: string | ((match: Match, ctx: InterpretationContext) => string);
|
|
91
|
+
/** Multiplies the matched atoms' salience when ranking (default 1). */
|
|
92
|
+
weight?: number;
|
|
93
|
+
/** Free-form labels (theme, polarity, ...) carried through to the entry. */
|
|
94
|
+
tags?: string[];
|
|
95
|
+
}
|
|
96
|
+
/** A pluggable corpus of rules: a tradition, a house style, a third party. */
|
|
97
|
+
export interface InterpretationSource {
|
|
98
|
+
id: string;
|
|
99
|
+
version: string;
|
|
100
|
+
rules: Rule[];
|
|
101
|
+
}
|
|
102
|
+
/** One licensed statement in a {@link Reading}, with its provenance. */
|
|
103
|
+
export interface ReadingEntry {
|
|
104
|
+
/** `"<source>/<rule>"`. */
|
|
105
|
+
id: string;
|
|
106
|
+
source: string;
|
|
107
|
+
rule: string;
|
|
108
|
+
text: string;
|
|
109
|
+
/** Ids of the fact atoms this entry rests on -- the audit trail. */
|
|
110
|
+
atomIds: string[];
|
|
111
|
+
/** Sum of the matched atoms' salience times the rule weight. */
|
|
112
|
+
salience: number;
|
|
113
|
+
tags?: string[];
|
|
114
|
+
}
|
|
115
|
+
/** A resolved interpretation: ranked entries, each citing its facts. */
|
|
116
|
+
export interface Reading {
|
|
117
|
+
jdUt: number;
|
|
118
|
+
entries: ReadingEntry[];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Run interpretation sources against a fact projection and return a ranked
|
|
122
|
+
* {@link Reading}. Each rule whose selector matches emits an entry carrying the
|
|
123
|
+
* matched atom ids (provenance) and a salience = sum of those atoms' salience x
|
|
124
|
+
* the rule weight. The engine never ships the content: the sources are the
|
|
125
|
+
* caller's.
|
|
126
|
+
*
|
|
127
|
+
* @param ctx A projection from {@link interpretationContext}.
|
|
128
|
+
* @param sources One or more {@link InterpretationSource} corpora.
|
|
129
|
+
* @returns The {@link Reading}; entries are sorted by descending salience.
|
|
130
|
+
*/
|
|
131
|
+
export declare function interpret(ctx: InterpretationContext, sources: InterpretationSource[]): Reading;
|
|
132
|
+
/** Entries about the same facts, gathered. */
|
|
133
|
+
export interface ReadingGroup {
|
|
134
|
+
/** Union of the group's cited atom ids -- the facts it is about. */
|
|
135
|
+
atomIds: string[];
|
|
136
|
+
/** Member entries, highest salience first. */
|
|
137
|
+
entries: ReadingEntry[];
|
|
138
|
+
/** Distinct tags across the members. */
|
|
139
|
+
tags: string[];
|
|
140
|
+
/** True when a declared conflicting tag-pair both appear (the corpus made
|
|
141
|
+
* opposing claims about the same facts). */
|
|
142
|
+
contested: boolean;
|
|
143
|
+
/** The group's salience (its strongest entry). */
|
|
144
|
+
salience: number;
|
|
145
|
+
}
|
|
146
|
+
export interface ReconcileOptions {
|
|
147
|
+
/** Tag pairs that contradict, e.g. `[["affirming", "challenging"]]`. */
|
|
148
|
+
conflicts?: [string, string][];
|
|
149
|
+
/** Drop an entry whose `text` duplicates a higher-salience one. */
|
|
150
|
+
dedupe?: boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Group a {@link Reading}'s entries by the facts they share, so statements about
|
|
154
|
+
* the same atoms surface together rather than scattered through a flat list --
|
|
155
|
+
* the substrate for "everything said about this placement" and for spotting
|
|
156
|
+
* contention. Entries are connected when their cited atoms overlap; an entry
|
|
157
|
+
* citing nothing (an absence rule) stands alone. A group is `contested` when a
|
|
158
|
+
* declared conflicting tag-pair both appear in it.
|
|
159
|
+
*
|
|
160
|
+
* Semantic contradiction is the corpus author's to declare (via `tags` +
|
|
161
|
+
* `conflicts`); the resolver does the bookkeeping, not the judgement.
|
|
162
|
+
*
|
|
163
|
+
* @param reading A reading from {@link interpret}.
|
|
164
|
+
* @param opts Conflicting tag pairs and optional text de-duplication.
|
|
165
|
+
* @returns Groups sorted by descending salience.
|
|
166
|
+
*/
|
|
167
|
+
export declare function reconcile(reading: Reading, opts?: ReconcileOptions): ReadingGroup[];
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const hit = (atoms) => ({ matched: atoms.length > 0, atoms });
|
|
2
|
+
// ------------------------------------------------------------- atom selectors
|
|
3
|
+
/** Matches placement atoms by any subset of body / sign / house / retrograde /
|
|
4
|
+
* a held dignity. */
|
|
5
|
+
export function hasPlacement(filter = {}) {
|
|
6
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "placement"
|
|
7
|
+
&& (filter.body === undefined || a.body === filter.body)
|
|
8
|
+
&& (filter.sign === undefined || a.sign === filter.sign)
|
|
9
|
+
&& (filter.house === undefined || a.house === filter.house)
|
|
10
|
+
&& (filter.retrograde === undefined || a.retrograde === filter.retrograde)
|
|
11
|
+
&& (filter.dignity === undefined || a.dignities.includes(filter.dignity))));
|
|
12
|
+
}
|
|
13
|
+
/** Matches aspect atoms. `between` is an unordered pair; `minStrength` filters
|
|
14
|
+
* loose aspects; `phase` filters applying/separating. */
|
|
15
|
+
export function hasAspect(filter = {}) {
|
|
16
|
+
const pair = filter.between ? [...filter.between].sort() : null;
|
|
17
|
+
return (ctx) => hit(ctx.atoms.filter((at) => {
|
|
18
|
+
if (at.kind !== "aspect")
|
|
19
|
+
return false;
|
|
20
|
+
if (filter.a !== undefined && at.a !== filter.a)
|
|
21
|
+
return false;
|
|
22
|
+
if (filter.b !== undefined && at.b !== filter.b)
|
|
23
|
+
return false;
|
|
24
|
+
if (pair && [at.a, at.b].sort().join() !== pair.join())
|
|
25
|
+
return false;
|
|
26
|
+
if (filter.aspect !== undefined && at.aspect !== filter.aspect)
|
|
27
|
+
return false;
|
|
28
|
+
if (filter.phase !== undefined && at.phase !== filter.phase)
|
|
29
|
+
return false;
|
|
30
|
+
if (filter.minStrength !== undefined && at.strength < filter.minStrength)
|
|
31
|
+
return false;
|
|
32
|
+
return true;
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/** Matches configuration atoms by kind and/or a participating body. */
|
|
36
|
+
export function hasPattern(filter = {}) {
|
|
37
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "pattern"
|
|
38
|
+
&& (filter.kind === undefined || a.pattern === filter.kind)
|
|
39
|
+
&& (filter.body === undefined || a.bodies.includes(filter.body))));
|
|
40
|
+
}
|
|
41
|
+
/** Matches a structural-signature facet, e.g. `("element", "fire")`. */
|
|
42
|
+
export function hasSignature(facet, value) {
|
|
43
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "signature" && a.facet === facet
|
|
44
|
+
&& (value === undefined || a.value === value)));
|
|
45
|
+
}
|
|
46
|
+
/** Matches an angle atom by which angle and/or its sign. */
|
|
47
|
+
export function hasAngle(angle, sign) {
|
|
48
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "angle" && a.angle === angle
|
|
49
|
+
&& (sign === undefined || a.sign === sign)));
|
|
50
|
+
}
|
|
51
|
+
/** Matches dispositor atoms by body, its dispositor, and/or the final flag
|
|
52
|
+
* (a body in its own domicile that terminates a dispositor chain). */
|
|
53
|
+
export function hasDispositor(filter = {}) {
|
|
54
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "dispositor"
|
|
55
|
+
&& (filter.body === undefined || a.body === filter.body)
|
|
56
|
+
&& (filter.dispositor === undefined || a.dispositor === filter.dispositor)
|
|
57
|
+
&& (filter.final === undefined || a.final === filter.final)));
|
|
58
|
+
}
|
|
59
|
+
/** Matches a mutual reception, optionally involving a given body. */
|
|
60
|
+
export function hasReception(filter = {}) {
|
|
61
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "reception"
|
|
62
|
+
&& (filter.body === undefined || a.bodies.includes(filter.body))));
|
|
63
|
+
}
|
|
64
|
+
/** Matches a fixed-star conjunction by the catalog star and/or the body on it. */
|
|
65
|
+
export function hasStar(filter = {}) {
|
|
66
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "star"
|
|
67
|
+
&& (filter.body === undefined || a.body === filter.body)
|
|
68
|
+
&& (filter.star === undefined || a.star === filter.star)));
|
|
69
|
+
}
|
|
70
|
+
/** Matches a Hermetic lot by name, and/or its sign or house. */
|
|
71
|
+
export function hasLot(filter = {}) {
|
|
72
|
+
return (ctx) => hit(ctx.atoms.filter((a) => a.kind === "lot"
|
|
73
|
+
&& (filter.lot === undefined || a.lot === filter.lot)
|
|
74
|
+
&& (filter.sign === undefined || a.sign === filter.sign)
|
|
75
|
+
&& (filter.house === undefined || a.house === filter.house)));
|
|
76
|
+
}
|
|
77
|
+
// ----------------------------------------------------------------- combinators
|
|
78
|
+
/** Matches only when every selector matches; returns the union of their atoms. */
|
|
79
|
+
export function matchAll(...sels) {
|
|
80
|
+
return (ctx) => {
|
|
81
|
+
const parts = sels.map((s) => s(ctx));
|
|
82
|
+
return parts.every((p) => p.matched)
|
|
83
|
+
? { matched: true, atoms: dedupe(parts.flatMap((p) => p.atoms)) }
|
|
84
|
+
: { matched: false, atoms: [] };
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Matches when any selector matches; returns the atoms from those that did. */
|
|
88
|
+
export function matchAny(...sels) {
|
|
89
|
+
return (ctx) => {
|
|
90
|
+
const matched = sels.map((s) => s(ctx)).filter((p) => p.matched);
|
|
91
|
+
return matched.length
|
|
92
|
+
? { matched: true, atoms: dedupe(matched.flatMap((p) => p.atoms)) }
|
|
93
|
+
: { matched: false, atoms: [] };
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Matches when the selector does NOT match (an absence test); no atoms. */
|
|
97
|
+
export function matchNone(sel) {
|
|
98
|
+
return (ctx) => ({ matched: !sel(ctx).matched, atoms: [] });
|
|
99
|
+
}
|
|
100
|
+
function dedupe(atoms) {
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
return atoms.filter((a) => (seen.has(a.id) ? false : seen.add(a.id)));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Run interpretation sources against a fact projection and return a ranked
|
|
106
|
+
* {@link Reading}. Each rule whose selector matches emits an entry carrying the
|
|
107
|
+
* matched atom ids (provenance) and a salience = sum of those atoms' salience x
|
|
108
|
+
* the rule weight. The engine never ships the content: the sources are the
|
|
109
|
+
* caller's.
|
|
110
|
+
*
|
|
111
|
+
* @param ctx A projection from {@link interpretationContext}.
|
|
112
|
+
* @param sources One or more {@link InterpretationSource} corpora.
|
|
113
|
+
* @returns The {@link Reading}; entries are sorted by descending salience.
|
|
114
|
+
*/
|
|
115
|
+
export function interpret(ctx, sources) {
|
|
116
|
+
const entries = [];
|
|
117
|
+
for (const src of sources) {
|
|
118
|
+
for (const rule of src.rules) {
|
|
119
|
+
const m = rule.when(ctx);
|
|
120
|
+
if (!m.matched)
|
|
121
|
+
continue;
|
|
122
|
+
const text = typeof rule.text === "function" ? rule.text(m, ctx) : rule.text;
|
|
123
|
+
const salience = m.atoms.reduce((s, a) => s + a.salience, 0) * (rule.weight ?? 1);
|
|
124
|
+
entries.push({
|
|
125
|
+
id: `${src.id}/${rule.id}`, source: src.id, rule: rule.id, text,
|
|
126
|
+
atomIds: m.atoms.map((a) => a.id), salience, tags: rule.tags,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
entries.sort((p, q) => q.salience - p.salience || (p.id < q.id ? -1 : 1));
|
|
131
|
+
return { jdUt: ctx.jdUt, entries };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Group a {@link Reading}'s entries by the facts they share, so statements about
|
|
135
|
+
* the same atoms surface together rather than scattered through a flat list --
|
|
136
|
+
* the substrate for "everything said about this placement" and for spotting
|
|
137
|
+
* contention. Entries are connected when their cited atoms overlap; an entry
|
|
138
|
+
* citing nothing (an absence rule) stands alone. A group is `contested` when a
|
|
139
|
+
* declared conflicting tag-pair both appear in it.
|
|
140
|
+
*
|
|
141
|
+
* Semantic contradiction is the corpus author's to declare (via `tags` +
|
|
142
|
+
* `conflicts`); the resolver does the bookkeeping, not the judgement.
|
|
143
|
+
*
|
|
144
|
+
* @param reading A reading from {@link interpret}.
|
|
145
|
+
* @param opts Conflicting tag pairs and optional text de-duplication.
|
|
146
|
+
* @returns Groups sorted by descending salience.
|
|
147
|
+
*/
|
|
148
|
+
export function reconcile(reading, opts = {}) {
|
|
149
|
+
let entries = reading.entries;
|
|
150
|
+
if (opts.dedupe) {
|
|
151
|
+
const seen = new Set(); // entries arrive salience-sorted: keep first
|
|
152
|
+
entries = entries.filter((e) => (seen.has(e.text) ? false : seen.add(e.text)));
|
|
153
|
+
}
|
|
154
|
+
// Union-find over entries that share an atom id.
|
|
155
|
+
const parent = entries.map((_, i) => i);
|
|
156
|
+
const find = (x) => {
|
|
157
|
+
while (parent[x] !== x) {
|
|
158
|
+
parent[x] = parent[parent[x]];
|
|
159
|
+
x = parent[x];
|
|
160
|
+
}
|
|
161
|
+
return x;
|
|
162
|
+
};
|
|
163
|
+
const firstByAtom = new Map();
|
|
164
|
+
entries.forEach((e, i) => {
|
|
165
|
+
for (const id of e.atomIds) {
|
|
166
|
+
const seen = firstByAtom.get(id);
|
|
167
|
+
if (seen === undefined)
|
|
168
|
+
firstByAtom.set(id, i);
|
|
169
|
+
else
|
|
170
|
+
parent[find(i)] = find(seen);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const buckets = new Map();
|
|
174
|
+
entries.forEach((e, i) => {
|
|
175
|
+
const r = find(i);
|
|
176
|
+
(buckets.get(r) ?? buckets.set(r, []).get(r)).push(e);
|
|
177
|
+
});
|
|
178
|
+
const conflicts = opts.conflicts ?? [];
|
|
179
|
+
const groups = [...buckets.values()].map((es) => {
|
|
180
|
+
es.sort((a, b) => b.salience - a.salience || (a.id < b.id ? -1 : 1));
|
|
181
|
+
const tags = [...new Set(es.flatMap((e) => e.tags ?? []))];
|
|
182
|
+
return {
|
|
183
|
+
atomIds: [...new Set(es.flatMap((e) => e.atomIds))],
|
|
184
|
+
entries: es, tags,
|
|
185
|
+
contested: conflicts.some(([x, y]) => tags.includes(x) && tags.includes(y)),
|
|
186
|
+
salience: Math.max(...es.map((e) => e.salience)),
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
groups.sort((a, b) => b.salience - a.salience
|
|
190
|
+
|| (a.atomIds.join() < b.atomIds.join() ? -1 : 1));
|
|
191
|
+
return groups;
|
|
192
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { Chart, Zodiac } from "./chart.js";
|
|
2
|
+
import type { AspectPhase } from "./electional.js";
|
|
3
|
+
import { ChartPattern } from "./patterns.js";
|
|
4
|
+
import { ChartSignature } from "./signature.js";
|
|
5
|
+
import type { Realm, Certainty } from "./provenance.js";
|
|
6
|
+
/** Atom kinds in an {@link InterpretationContext}. */
|
|
7
|
+
export type FactKind = "placement" | "aspect" | "pattern" | "signature" | "angle" | "dispositor" | "reception" | "star" | "lot";
|
|
8
|
+
interface FactAtomBase {
|
|
9
|
+
/** Stable, content-addressable id, e.g. `"placement:mars"` or
|
|
10
|
+
* `"aspect:mars~saturn:square"`. Interpretations cite this. */
|
|
11
|
+
id: string;
|
|
12
|
+
kind: FactKind;
|
|
13
|
+
/** Body ids this atom concerns (empty for body-less signature facets). */
|
|
14
|
+
bodies: string[];
|
|
15
|
+
/** Transparent salience (higher = more prominent); see {@link SalienceWeights}. */
|
|
16
|
+
salience: number;
|
|
17
|
+
/** Plain-language statement of the fact -- no interpretation. */
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
export interface PlacementAtom extends FactAtomBase {
|
|
21
|
+
kind: "placement";
|
|
22
|
+
body: string;
|
|
23
|
+
sign: string;
|
|
24
|
+
signDeg: number;
|
|
25
|
+
house: number;
|
|
26
|
+
retrograde: boolean;
|
|
27
|
+
dignities: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface AspectAtom extends FactAtomBase {
|
|
30
|
+
kind: "aspect";
|
|
31
|
+
a: string;
|
|
32
|
+
b: string;
|
|
33
|
+
aspect: string;
|
|
34
|
+
/** Orb from exact, degrees. */
|
|
35
|
+
orb: number;
|
|
36
|
+
/** Applying, separating, or exact -- from the two bodies' speeds. */
|
|
37
|
+
phase: AspectPhase;
|
|
38
|
+
/** Closeness in `[0, 1]`: `1` exact, `0` at the orb limit. */
|
|
39
|
+
strength: number;
|
|
40
|
+
}
|
|
41
|
+
export interface PatternAtom extends FactAtomBase {
|
|
42
|
+
kind: "pattern";
|
|
43
|
+
/** Configuration kind, e.g. `"t_square"`, `"grand_trine"`. */
|
|
44
|
+
pattern: string;
|
|
45
|
+
/** Focal body for a T-square or yod. */
|
|
46
|
+
apex?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface SignatureAtom extends FactAtomBase {
|
|
49
|
+
kind: "signature";
|
|
50
|
+
/** Which facet of the structural signature this states. */
|
|
51
|
+
facet: "element" | "modality" | "sign" | "ruler";
|
|
52
|
+
value: string;
|
|
53
|
+
}
|
|
54
|
+
export interface AngleAtom extends FactAtomBase {
|
|
55
|
+
kind: "angle";
|
|
56
|
+
angle: "asc" | "mc" | "vertex" | "eastPoint";
|
|
57
|
+
sign: string;
|
|
58
|
+
signDeg: number;
|
|
59
|
+
}
|
|
60
|
+
export interface DispositorAtom extends FactAtomBase {
|
|
61
|
+
kind: "dispositor";
|
|
62
|
+
body: string;
|
|
63
|
+
/** The classical ruler of the body's sign (equals `body` when in domicile). */
|
|
64
|
+
dispositor: string;
|
|
65
|
+
/** The body occupies its own domicile -- a chain terminus / final dispositor. */
|
|
66
|
+
final: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface ReceptionAtom extends FactAtomBase {
|
|
69
|
+
kind: "reception";
|
|
70
|
+
/** The dignities the reception runs through: a single dignity when both
|
|
71
|
+
* bodies receive by the same (`"domicile"`, `"exaltation"`, `"triplicity"`),
|
|
72
|
+
* else a sorted pair for a mixed reception (e.g. `"domicile-exaltation"`). */
|
|
73
|
+
by: string;
|
|
74
|
+
}
|
|
75
|
+
export interface StarAtom extends FactAtomBase {
|
|
76
|
+
kind: "star";
|
|
77
|
+
/** The body conjunct the fixed star. */
|
|
78
|
+
body: string;
|
|
79
|
+
/** Catalog star name (see {@link Engine.starNames}). */
|
|
80
|
+
star: string;
|
|
81
|
+
/** Orb from exact conjunction, degrees. */
|
|
82
|
+
orb: number;
|
|
83
|
+
}
|
|
84
|
+
export interface LotAtom extends FactAtomBase {
|
|
85
|
+
kind: "lot";
|
|
86
|
+
/** Hermetic lot name, e.g. `"fortune"` (see {@link HERMETIC_LOTS}). */
|
|
87
|
+
lot: string;
|
|
88
|
+
sign: string;
|
|
89
|
+
signDeg: number;
|
|
90
|
+
house: number;
|
|
91
|
+
}
|
|
92
|
+
export type FactAtom = PlacementAtom | AspectAtom | PatternAtom | SignatureAtom | AngleAtom | DispositorAtom | ReceptionAtom | StarAtom | LotAtom;
|
|
93
|
+
/** A chart as a flat, ranked list of {@link FactAtom}s. */
|
|
94
|
+
export interface InterpretationContext {
|
|
95
|
+
jdUt: number;
|
|
96
|
+
zodiac: Zodiac;
|
|
97
|
+
/** Atoms sorted by descending {@link FactAtomBase.salience}, then `id`. */
|
|
98
|
+
atoms: FactAtom[];
|
|
99
|
+
/** What the chart is, when supplied via {@link ContextOptions.provenance} --
|
|
100
|
+
* framing for an interpreter (a forecast is provisional, a mythic chart is a
|
|
101
|
+
* symbol, not a biography). */
|
|
102
|
+
realm?: Realm;
|
|
103
|
+
/** How firmly the instant is known. When not `"exact"`, time-sensitive atoms
|
|
104
|
+
* (the Moon, the angles) are damped, since their positions are less certain. */
|
|
105
|
+
certainty?: Certainty;
|
|
106
|
+
}
|
|
107
|
+
/** Additive salience weights. Each contribution is documented at its use site;
|
|
108
|
+
* override any subset through {@link ContextOptions.salience}. */
|
|
109
|
+
export interface SalienceWeights {
|
|
110
|
+
/** Every atom starts here. */
|
|
111
|
+
base: number;
|
|
112
|
+
/** Added when the Sun or Moon is involved. */
|
|
113
|
+
luminary: number;
|
|
114
|
+
/** Added for an angular house (1/4/7/10) or an angle atom. */
|
|
115
|
+
angular: number;
|
|
116
|
+
/** Added to the placement of the Ascendant ruler. */
|
|
117
|
+
chartRuler: number;
|
|
118
|
+
/** Added per essential dignity a body holds. */
|
|
119
|
+
dignity: number;
|
|
120
|
+
/** Added to a hard aspect (conjunction/square/opposition). */
|
|
121
|
+
hardAspect: number;
|
|
122
|
+
/** Base salience of a whole configuration (T-square, grand trine, ...). */
|
|
123
|
+
pattern: number;
|
|
124
|
+
/** Added to a dispositor link (and again when it is a final dispositor). */
|
|
125
|
+
dispositor: number;
|
|
126
|
+
/** Added to a mutual reception. */
|
|
127
|
+
reception: number;
|
|
128
|
+
/** Added to a body's conjunction with a fixed star. */
|
|
129
|
+
star: number;
|
|
130
|
+
/** Added to a Hermetic lot (the Part of Fortune and its companions). */
|
|
131
|
+
lot: number;
|
|
132
|
+
}
|
|
133
|
+
export declare const DEFAULT_SALIENCE: SalienceWeights;
|
|
134
|
+
export interface ContextOptions {
|
|
135
|
+
/** Salience weights to override (merged over {@link DEFAULT_SALIENCE}). */
|
|
136
|
+
salience?: Partial<SalienceWeights>;
|
|
137
|
+
/** Precomputed patterns/signature, to avoid recomputing them. */
|
|
138
|
+
patterns?: ChartPattern[];
|
|
139
|
+
signature?: ChartSignature;
|
|
140
|
+
/** The chart's grounding. Carried onto the context; an inexact `certainty`
|
|
141
|
+
* damps time-sensitive atoms. Wire from {@link realize}'s result. */
|
|
142
|
+
provenance?: {
|
|
143
|
+
realm?: Realm;
|
|
144
|
+
certainty?: Certainty;
|
|
145
|
+
};
|
|
146
|
+
/** Fixed-star conjunctions to project as `star` atoms. The engine does not
|
|
147
|
+
* compute these from a bare {@link Chart} (the star catalog lives in the
|
|
148
|
+
* data pack), so a caller supplies them, e.g. from
|
|
149
|
+
* {@link Engine.starConjunctions}. */
|
|
150
|
+
stars?: {
|
|
151
|
+
body: string;
|
|
152
|
+
star: string;
|
|
153
|
+
orb: number;
|
|
154
|
+
}[];
|
|
155
|
+
/** Hermetic lots to project as `lot` atoms, e.g. from {@link Engine.lots}. */
|
|
156
|
+
lots?: {
|
|
157
|
+
lot: string;
|
|
158
|
+
sign: string;
|
|
159
|
+
signDeg: number;
|
|
160
|
+
house: number;
|
|
161
|
+
}[];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Project a {@link Chart} into a ranked list of {@link FactAtom}s -- the
|
|
165
|
+
* substrate an interpretation layer consumes. Pure and deterministic; computes
|
|
166
|
+
* applying/separating and a normalized strength for each aspect that the bare
|
|
167
|
+
* {@link Chart.aspects} list omits.
|
|
168
|
+
*
|
|
169
|
+
* @param chart A chart from {@link Engine.chart} / {@link Engine.chartAt}.
|
|
170
|
+
* @param opts Salience overrides, orb policy, and precomputed reductions.
|
|
171
|
+
* @returns The {@link InterpretationContext}; `atoms` are sorted by salience.
|
|
172
|
+
*/
|
|
173
|
+
export declare function interpretationContext(chart: Chart, opts?: ContextOptions): InterpretationContext;
|
|
174
|
+
export {};
|