Internal module guide. This module is now part of
@astrology/western; use the public package README for application setup.
natal module
Pure Western natal judgments over admitted chart facts: element/modality distribution, house emphasis, rulership, essential dignity and aspect/sign patterns. Public imports use the package root. See the package specification and task W-02.
Run pnpm --filter @astrology/western build, check, and test. The package acquires no
astronomy, resolves no profile and recomputes no aspect geometry.
Inputs and outputs
evaluateWesternNatal(snapshot, contacts, rules) takes a Composer ChartSnapshot, the contacts
Composer already evaluated for it, and validated rule tables. evaluateNatal(facts, aspects, rules)
takes the adapted shapes when a consumer already holds them. createNatalFeature(admitted) takes
AdmittedRules<WesternNatalRules> and returns the WesternFeature<void, WesternNatalResult> the
engine invokes; the feature reads the engine’s snapshot and contacts from its context.
The result names the chart, the counted bodies, every group count with its contributing bodies, the
rulers of occupied signs, dignity claims, matched patterns, contributing rule identities and named
gaps. The feature additionally returns the deciding RuleMatch[]. Inputs are never mutated.
Adaptation boundary
src/adapters/facts.ts is the dependency seam. toNatalFacts copies position, resolved sign, degree
in sign, house placement, motion and cusps from the snapshot; toNatalAspects copies the aspect id,
both point ids, separation, orb (allowed distance from exact) and phase (applying or separating) from the supplied contacts. Natal rules therefore read only
Western-owned shapes, and a change of snapshot shape or reader implementation is absorbed here.
Nothing is inferred: a null house or null speed stays unknown, and geometry is never re-derived. Point ids remain strings so angle points can participate without being treated as bodies.
Rules
validateNatalRules admits a table set once, at registration, and fails with INVALID_RULES. It
requires a full twelve-sign classification table, a non-empty explicit counted body set, unique
rulership ids, no sign claimed by two rulers, no duplicate dignity claim, and an exact aspect count per
pattern point pair. Every rulership and dignity rule must carry the section’s scheme identity, so
modern and traditional tables cannot be blended in one response.
The technique identity, version and variant live on the admitted bundle, not in the payload, so a
table cannot claim a revision it was not admitted as. createNatalFeature refuses rules admitted for
another technique.
Degradation
Missing houses remove only house emphasis and add a missing-houses gap; the other factors still run.
A counted body absent from the chart is named in a missing-body gap. An occupied sign the selected
scheme does not rule appears in unruledSigns. Absent shared geometry omits aspect patterns and adds a
missing-aspects gap instead of inventing contacts. A chart whose resolved sign the classification
table does not cover fails with INVALID_REQUEST instead of silently dropping the body.
Consumer example
import { createNatalFeature } from './calculations/natal/index.js';
const feature = createNatalFeature(admitted);
const capability = feature.inspect(profile, upstreamStatus);
if (capability.supported) {
const output = await feature.evaluate(undefined, { profile, rulebook, snapshot, aspects, dependencies: {}, upstream: {} });
output.value.patterns;
output.rules;
}
Not implemented here
Chart acquisition, contact evaluation (Compose geometry), profile resolution, rulebook loading and hashing, response envelopes, and non-natal techniques.