Packages3 MIN READ104 / 116

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.