Astrology4 MIN READ49 / 116

Western dependency adapters

Status: Implemented seams · Updated: 2026-10-25

The Western packages are built ahead of a frozen Compose implementation by narrowing every upstream contact to a Western-owned shape. An adapter copies values into that shape; technique code never imports a Composer, Binder or provider implementation, and no upstream fact is recalculated while copying.

Two seam kinds exist, deliberately separate:

  • Port binder and shared conversions live in packages/western, because every technique needs the same gate inspection and the same snapshot-to-geometry conversion.
  • Technique result narrowing lives in the consuming package under src/adapters/, because only that technique knows which facts its rules read.

Implemented seams

Seam Location Upstream input Western output
Convention → chart request packages/western/src/profiles/context.ts Admitted WesternProfile plus per-request instant and observers Shared ChartContextInput for an injected ComposerPort
Capabilities → gate status packages/western/src/upstream/binder.ts ComposerPort.capabilities() and its ports WesternUpstreamStatus, require(gate) and connect(gates)
Snapshot → geometry chart packages/western/src/upstream/adapters.ts ChartSnapshot Shared GeometryChart with observed point origins, angles and cusps
Snapshot → natal facts packages/western/src/calculations/natal/adapters/facts.ts ChartSnapshot and Composer-evaluated ChartContact[] NatalChartFacts, NatalAspect[]
Technique resources → admitted rules packages/western/src/rulebooks/registry.ts Manifest plus supplied technique payloads Frozen AdmittedRules<T> with technique/version/variant, hash and rulebook identity

toChartContextInput is the outbound seam: it emits exactly the shared request shape, so swapping the Composer implementation changes nothing in Western code. It refuses observers that contradict the profile’s pinned position origin and never selects an ayanamsa, house system or frame at request time. With { houses: false } it composes positions only, so a technique that needs no cusps does not require a house observer.

bindWesternUpstream inspects Composer once per engine call. A capability the host has not connected stays closed and names its owning task, and connect hands a feature only the ports it declared; a technique therefore cannot fabricate an astronomy or geometry answer while an upstream task is pending. geometryChartFrom copies bodies, angles and cusps into the shared GeometryChart and keeps observed origins and evidence, so a derived point can never be mistaken for a provider position.

toNatalFacts is the inbound seam: position, resolved sign, degree in sign, house placement, motion, cusps and aspect annotations are copied, with null meaning unavailable. Because rules consume NatalChartFacts, a fixture snapshot, a real Composer snapshot and a future reader all feed the same rule code. evaluateNatal(facts, aspects, rules) exposes the adapted entry point directly.

getWesternTechniqueRules is the admission seam: the registry verifies the manifest and content hashes, then passes the stored payload through the owning technique’s validator. A resource is never cast to a schema it does not satisfy, and the returned AdmittedRules<T> carries the identity the engine compares with the registered feature.

Planned seams

Seam Consumer Intended narrowing
Cross-chart geometry synastry CrossChartContact/HouseOverlay → source/target contacts with directional overlays; the port is still injected, only its result shape is narrowed
Bounded probes transit, returns ProbeResult/ProbeBudget → technique-owned solver steps, retaining residuals and evaluation counts as evidence
Composer charts progressions, returns, composite ComposerPort.compose → technique-specific mapped contexts; derived charts are labelled separately from observed ones

Rules for a new adapter

  1. Put shared port inspection and chart-shape conversion in packages/western; put technique-specific result narrowing in that technique’s src/adapters/.
  2. Import Compose and Binder types only. A runtime import means the technique is no longer pure.
  3. Copy; never re-derive placement, sign resolution, aspect separation or rounding.
  4. Keep upstream nulls null and unknown motion unknown; do not substitute zero.
  5. Validate the copied shape and fail with a shared WesternError code rather than returning a partial object.
  6. Test the adapter against a synthetic fixture in the same shape the real upstream publishes, so the technique and engine tests stay runnable without a provider or ephemeris file.

Remaining external dependencies

  • S-01 workspace registration. packages/western/src/* is registered in pnpm-workspace.yaml with build:western, check:western and test:western root scripts. The integration agent owns these files; keep the entries when merging other family work.
  • Contract freeze on packages/chart-composer. Composer contracts now belong to the consolidated chart-composer package. The Western adapters pin their current shapes; a later contract change is absorbed in the seams listed above, not in technique or rule code.
  • S-02 integration. @astrology/western can already be constructed with any ComposerPort; its tests use a synthetic host. The remaining work is a host that wires the real Binder/Composer into both engines and exposes their results.