ether-to-astro 1.2.0 → 1.3.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 +15 -5
- package/dist/astro-service/chart-output-service.d.ts +44 -0
- package/dist/astro-service/chart-output-service.js +110 -0
- package/dist/astro-service/date-input.d.ts +14 -0
- package/dist/astro-service/date-input.js +30 -0
- package/dist/astro-service/electional-service.d.ts +45 -0
- package/dist/astro-service/electional-service.js +305 -0
- package/dist/astro-service/natal-service.d.ts +41 -0
- package/dist/astro-service/natal-service.js +179 -0
- package/dist/astro-service/rising-sign-service.d.ts +37 -0
- package/dist/astro-service/rising-sign-service.js +137 -0
- package/dist/astro-service/service-types.d.ts +82 -0
- package/dist/astro-service/service-types.js +1 -0
- package/dist/astro-service/shared.d.ts +65 -0
- package/dist/astro-service/shared.js +98 -0
- package/dist/astro-service/sky-service.d.ts +48 -0
- package/dist/astro-service/sky-service.js +144 -0
- package/dist/astro-service/transit-service.d.ts +82 -0
- package/dist/astro-service/transit-service.js +353 -0
- package/dist/astro-service.d.ts +101 -89
- package/dist/astro-service.js +162 -1042
- package/dist/tool-registry.js +1 -1
- package/docs/product/architecture-boundaries.md +8 -0
- package/docs/releases/1.3.0.md +51 -0
- package/docs/releases/README.md +17 -0
- package/package.json +4 -1
- package/src/astro-service/chart-output-service.ts +155 -0
- package/src/astro-service/date-input.ts +40 -0
- package/src/astro-service/electional-service.ts +395 -0
- package/src/astro-service/natal-service.ts +235 -0
- package/src/astro-service/rising-sign-service.ts +181 -0
- package/src/astro-service/service-types.ts +90 -0
- package/src/astro-service/shared.ts +128 -0
- package/src/astro-service/sky-service.ts +191 -0
- package/src/astro-service/transit-service.ts +507 -0
- package/src/astro-service.ts +177 -1386
- package/src/tool-registry.ts +1 -1
- package/tests/README.md +15 -0
- package/tests/property/electional-service.property.test.ts +67 -0
- package/tests/property/helpers/arbitraries.ts +126 -0
- package/tests/property/helpers/config.ts +52 -0
- package/tests/property/helpers/runtime.ts +12 -0
- package/tests/property/houses.property.test.ts +74 -0
- package/tests/property/rising-sign-service.property.test.ts +255 -0
- package/tests/property/service-transits.property.test.ts +154 -0
- package/tests/property/time-utils.property.test.ts +91 -0
- package/tests/property/transits.property.test.ts +113 -0
- package/tests/unit/astro-service/chart-output-service.test.ts +102 -0
- package/tests/unit/astro-service/electional-service.test.ts +182 -0
- package/tests/unit/astro-service/natal-service.test.ts +126 -0
- package/tests/unit/astro-service/rising-sign-service.test.ts +145 -0
- package/tests/unit/astro-service/sky-service.test.ts +130 -0
- package/tests/unit/astro-service/transit-service.test.ts +312 -0
- package/tests/unit/astro-service.test.ts +136 -781
- package/tests/unit/rising-sign-windows.test.ts +93 -0
- package/tests/unit/tool-registry.test.ts +11 -0
- package/tests/validation/README.md +14 -0
- package/tests/validation/adapters/internal.ts +234 -4
- package/tests/validation/compare/electional.ts +151 -0
- package/tests/validation/compare/rising-sign-windows.ts +347 -0
- package/tests/validation/compare/service-transits.ts +205 -0
- package/tests/validation/fixtures/electional/core.ts +88 -0
- package/tests/validation/fixtures/rising-sign-windows/core.ts +57 -0
- package/tests/validation/fixtures/service-transits/core.ts +89 -0
- package/tests/validation/utils/fixtureTypes.ts +139 -1
- package/tests/validation/validation.spec.ts +82 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PLANETS } from '../../../../src/types.js';
|
|
2
|
+
import type { ServiceTransitFixture } from '../../utils/fixtureTypes.js';
|
|
3
|
+
|
|
4
|
+
export const serviceTransitFixtures: ServiceTransitFixture[] = [
|
|
5
|
+
{
|
|
6
|
+
name: 'tokyo-local-noon-sign-carry-snapshot',
|
|
7
|
+
natalChart: {
|
|
8
|
+
name: 'Tokyo Boundary Chart',
|
|
9
|
+
latitude: 35.6762,
|
|
10
|
+
longitude: 139.6503,
|
|
11
|
+
timezone: 'Asia/Tokyo',
|
|
12
|
+
julianDayIsoUtc: '1990-06-12T03:00:00Z',
|
|
13
|
+
houseSystem: 'P',
|
|
14
|
+
planetOffsets: [
|
|
15
|
+
{
|
|
16
|
+
transitingPlanetId: PLANETS.SUN,
|
|
17
|
+
natalPlanetId: PLANETS.SUN,
|
|
18
|
+
natalOffsetDegrees: 0,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
input: {
|
|
23
|
+
date: '2024-03-20',
|
|
24
|
+
mode: 'snapshot',
|
|
25
|
+
categories: ['personal'],
|
|
26
|
+
},
|
|
27
|
+
startupDefaults: {
|
|
28
|
+
preferredTimezone: 'UTC',
|
|
29
|
+
},
|
|
30
|
+
expected: {
|
|
31
|
+
mode: 'snapshot',
|
|
32
|
+
timezone: 'UTC',
|
|
33
|
+
calculationTimezone: 'Asia/Tokyo',
|
|
34
|
+
reportingTimezone: 'UTC',
|
|
35
|
+
windowStart: '2024-03-20',
|
|
36
|
+
windowEnd: '2024-03-20',
|
|
37
|
+
expectTransit: {
|
|
38
|
+
transitingPlanet: 'Sun',
|
|
39
|
+
natalPlanet: 'Sun',
|
|
40
|
+
aspect: 'conjunction',
|
|
41
|
+
transitSign: 'Aries',
|
|
42
|
+
transitDegree: 0,
|
|
43
|
+
natalSign: 'Aries',
|
|
44
|
+
natalDegree: 0,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'los-angeles-to-tokyo-forecast-grouping',
|
|
50
|
+
natalChart: {
|
|
51
|
+
name: 'Pacific Forecast Chart',
|
|
52
|
+
latitude: 37.7749,
|
|
53
|
+
longitude: -122.4194,
|
|
54
|
+
timezone: 'America/Los_Angeles',
|
|
55
|
+
julianDayIsoUtc: '1990-06-12T21:35:00Z',
|
|
56
|
+
houseSystem: 'P',
|
|
57
|
+
planetOffsets: [
|
|
58
|
+
{
|
|
59
|
+
transitingPlanetId: PLANETS.SUN,
|
|
60
|
+
natalPlanetId: PLANETS.SUN,
|
|
61
|
+
natalOffsetDegrees: 0,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
input: {
|
|
66
|
+
date: '2024-03-26',
|
|
67
|
+
mode: 'forecast',
|
|
68
|
+
days_ahead: 1,
|
|
69
|
+
categories: ['personal'],
|
|
70
|
+
},
|
|
71
|
+
startupDefaults: {
|
|
72
|
+
preferredTimezone: 'Asia/Tokyo',
|
|
73
|
+
},
|
|
74
|
+
expected: {
|
|
75
|
+
mode: 'forecast',
|
|
76
|
+
timezone: 'Asia/Tokyo',
|
|
77
|
+
calculationTimezone: 'America/Los_Angeles',
|
|
78
|
+
reportingTimezone: 'Asia/Tokyo',
|
|
79
|
+
windowStart: '2024-03-27',
|
|
80
|
+
windowEnd: '2024-03-28',
|
|
81
|
+
forecastDays: 2,
|
|
82
|
+
expectTransit: {
|
|
83
|
+
transitingPlanet: 'Sun',
|
|
84
|
+
natalPlanet: 'Sun',
|
|
85
|
+
aspect: 'conjunction',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
];
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
GetElectionalContextInput,
|
|
3
|
+
GetRisingSignWindowsInput,
|
|
4
|
+
GetTransitsInput,
|
|
5
|
+
} from '../../../src/astro-service/service-types.js';
|
|
6
|
+
import type { McpStartupDefaults } from '../../../src/entrypoint.js';
|
|
7
|
+
import type { HouseSystem, PlanetName } from '../../../src/types.js';
|
|
2
8
|
|
|
3
9
|
export interface NormalizedBody {
|
|
4
10
|
body: PlanetName | string;
|
|
@@ -44,6 +50,70 @@ export interface NormalizedEclipse {
|
|
|
44
50
|
maxTime: string;
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
export interface NormalizedElectionalContext {
|
|
54
|
+
houseSystem: string;
|
|
55
|
+
classification: 'day' | 'night';
|
|
56
|
+
isDayChart: boolean;
|
|
57
|
+
sunAltitudeDegrees: number;
|
|
58
|
+
rawSunAltitudeDegrees: number;
|
|
59
|
+
sunAltitudeDisplaysZero: boolean;
|
|
60
|
+
warnings: string[];
|
|
61
|
+
hasApplyingAspects: boolean;
|
|
62
|
+
applyingAspectCount: number;
|
|
63
|
+
hasMoonApplyingAspects: boolean;
|
|
64
|
+
moonApplyingAspectCount: number;
|
|
65
|
+
hasRulerBasics: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface NormalizedRisingSignWindow {
|
|
69
|
+
sign: string;
|
|
70
|
+
start: string;
|
|
71
|
+
end: string;
|
|
72
|
+
durationMs: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface NormalizedRisingSignWindowResult {
|
|
76
|
+
date: string;
|
|
77
|
+
timezone: string;
|
|
78
|
+
mode: 'approximate' | 'exact';
|
|
79
|
+
windows: NormalizedRisingSignWindow[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface NormalizedServiceTransit {
|
|
83
|
+
transitingPlanet: string;
|
|
84
|
+
natalPlanet: string;
|
|
85
|
+
aspect: string;
|
|
86
|
+
orb: number;
|
|
87
|
+
exactTime?: string;
|
|
88
|
+
exactTimeStatus?: 'within_preview' | 'outside_preview' | 'not_found' | 'unsupported_body';
|
|
89
|
+
isApplying: boolean;
|
|
90
|
+
transitSign?: string;
|
|
91
|
+
transitDegree?: number;
|
|
92
|
+
transitHouse?: number;
|
|
93
|
+
natalSign?: string;
|
|
94
|
+
natalDegree?: number;
|
|
95
|
+
natalHouse?: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface NormalizedServiceTransitForecastDay {
|
|
99
|
+
date: string;
|
|
100
|
+
transits: NormalizedServiceTransit[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface NormalizedServiceTransitResult {
|
|
104
|
+
mode?: 'snapshot' | 'best_hit' | 'forecast';
|
|
105
|
+
modeSource?: 'legacy_default' | 'explicit';
|
|
106
|
+
date?: string;
|
|
107
|
+
timezone: string;
|
|
108
|
+
calculationTimezone?: string;
|
|
109
|
+
reportingTimezone?: string;
|
|
110
|
+
daysAhead?: number;
|
|
111
|
+
windowStart?: string;
|
|
112
|
+
windowEnd?: string;
|
|
113
|
+
transits?: NormalizedServiceTransit[];
|
|
114
|
+
forecast?: NormalizedServiceTransitForecastDay[];
|
|
115
|
+
}
|
|
116
|
+
|
|
47
117
|
export interface PositionFixture {
|
|
48
118
|
name: string;
|
|
49
119
|
isoUtc: string;
|
|
@@ -144,3 +214,71 @@ export interface AstrologEdgeParityFixture {
|
|
|
144
214
|
timezone?: string;
|
|
145
215
|
disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject';
|
|
146
216
|
}
|
|
217
|
+
|
|
218
|
+
export interface ElectionalFixture {
|
|
219
|
+
name: string;
|
|
220
|
+
input: GetElectionalContextInput;
|
|
221
|
+
expected: {
|
|
222
|
+
classification: 'day' | 'night';
|
|
223
|
+
isDayChart: boolean;
|
|
224
|
+
houseSystem?: string;
|
|
225
|
+
rawSunAltitudeSign?: 'positive' | 'negative' | 'zero';
|
|
226
|
+
sunAltitudeDisplaysZero?: boolean;
|
|
227
|
+
warningsContain?: string[];
|
|
228
|
+
hasApplyingAspects?: boolean;
|
|
229
|
+
hasMoonApplyingAspects?: boolean;
|
|
230
|
+
hasRulerBasics?: boolean;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface RisingSignWindowsFixture {
|
|
235
|
+
name: string;
|
|
236
|
+
input: GetRisingSignWindowsInput;
|
|
237
|
+
expectedTotalDurationMinutes: number;
|
|
238
|
+
minWindows?: number;
|
|
239
|
+
expectOffsetChange?: boolean;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface RisingSignModeComparisonFixture {
|
|
243
|
+
name: string;
|
|
244
|
+
baseInput: Omit<GetRisingSignWindowsInput, 'mode'>;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface ServiceTransitNatalFixture {
|
|
248
|
+
name: string;
|
|
249
|
+
latitude: number;
|
|
250
|
+
longitude: number;
|
|
251
|
+
timezone: string;
|
|
252
|
+
julianDayIsoUtc: string;
|
|
253
|
+
houseSystem?: HouseSystem;
|
|
254
|
+
planetOffsets: Array<{
|
|
255
|
+
transitingPlanetId: number;
|
|
256
|
+
natalPlanetId: number;
|
|
257
|
+
natalOffsetDegrees: number;
|
|
258
|
+
}>;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface ServiceTransitFixture {
|
|
262
|
+
name: string;
|
|
263
|
+
natalChart: ServiceTransitNatalFixture;
|
|
264
|
+
input: GetTransitsInput;
|
|
265
|
+
startupDefaults?: McpStartupDefaults;
|
|
266
|
+
expected: {
|
|
267
|
+
mode: 'snapshot' | 'best_hit' | 'forecast';
|
|
268
|
+
timezone: string;
|
|
269
|
+
calculationTimezone: string;
|
|
270
|
+
reportingTimezone: string;
|
|
271
|
+
windowStart?: string;
|
|
272
|
+
windowEnd?: string;
|
|
273
|
+
forecastDays?: number;
|
|
274
|
+
expectTransit: {
|
|
275
|
+
transitingPlanet: string;
|
|
276
|
+
natalPlanet: string;
|
|
277
|
+
aspect: string;
|
|
278
|
+
transitSign?: string;
|
|
279
|
+
transitDegree?: number;
|
|
280
|
+
natalSign?: string;
|
|
281
|
+
natalDegree?: number;
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
}
|
|
@@ -4,9 +4,15 @@ import { localToUTC } from '../../src/time-utils.js';
|
|
|
4
4
|
import { PLANETS, type PlanetPosition } from '../../src/types.js';
|
|
5
5
|
import { getAstrologHouses, getAstrologPositions, probeAstrolog } from './adapters/astrolog.js';
|
|
6
6
|
import { InternalValidationAdapter } from './adapters/internal.js';
|
|
7
|
+
import { compareElectionalContext } from './compare/electional.js';
|
|
7
8
|
import { compareHouses } from './compare/houses.js';
|
|
8
9
|
import { comparePositions } from './compare/positions.js';
|
|
10
|
+
import {
|
|
11
|
+
compareRisingSignModePrecision,
|
|
12
|
+
compareRisingSignWindows,
|
|
13
|
+
} from './compare/rising-sign-windows.js';
|
|
9
14
|
import { compareRoots } from './compare/roots.js';
|
|
15
|
+
import { compareServiceTransitFixture } from './compare/service-transits.js';
|
|
10
16
|
import { assertTransitStatus, findTransit } from './compare/transits.js';
|
|
11
17
|
import {
|
|
12
18
|
astrologEdgeParityFixtures,
|
|
@@ -15,10 +21,16 @@ import {
|
|
|
15
21
|
astrologTransitSnapshotFixtures,
|
|
16
22
|
} from './fixtures/astrolog-parity/core.js';
|
|
17
23
|
import { eclipseFixtures } from './fixtures/eclipses/core.js';
|
|
24
|
+
import { electionalFixtures } from './fixtures/electional/core.js';
|
|
18
25
|
import { houseFixtures } from './fixtures/houses/core.js';
|
|
19
26
|
import { positionFixtures } from './fixtures/positions/core.js';
|
|
20
27
|
import { riseSetFixtures } from './fixtures/rise-set/core.js';
|
|
28
|
+
import {
|
|
29
|
+
risingSignModeComparisonFixtures,
|
|
30
|
+
risingSignWindowFixtures,
|
|
31
|
+
} from './fixtures/rising-sign-windows/core.js';
|
|
21
32
|
import { rootFixtures } from './fixtures/roots/core.js';
|
|
33
|
+
import { serviceTransitFixtures } from './fixtures/service-transits/core.js';
|
|
22
34
|
import { transitFixtures } from './fixtures/transits/core.js';
|
|
23
35
|
import { dstFixtures } from './fixtures/transits/dst.js';
|
|
24
36
|
import { denseScanRootOracleWithDebug } from './utils/denseRootOracle.js';
|
|
@@ -826,6 +838,76 @@ describe('Astro Validation Harness', () => {
|
|
|
826
838
|
});
|
|
827
839
|
});
|
|
828
840
|
|
|
841
|
+
describe('H. Electional context invariants', () => {
|
|
842
|
+
it('covers sect classification, near-horizon warnings, fallback semantics, and optional fields', () => {
|
|
843
|
+
const report = new ValidationReport();
|
|
844
|
+
|
|
845
|
+
for (const fixture of electionalFixtures) {
|
|
846
|
+
const actual = adapter.getElectionalContext(fixture.input);
|
|
847
|
+
compareElectionalContext(fixture, actual, report);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
aggregateReport.hardFailures.push(...report.hardFailures);
|
|
851
|
+
aggregateReport.warnings.push(...report.warnings);
|
|
852
|
+
assertNoHardFailures(report);
|
|
853
|
+
});
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
describe('I. Rising-sign window invariants', () => {
|
|
857
|
+
it('validates contiguous local-day coverage, DST offsets, and deterministic repeats', () => {
|
|
858
|
+
const report = new ValidationReport();
|
|
859
|
+
|
|
860
|
+
for (const fixture of risingSignWindowFixtures) {
|
|
861
|
+
const actual = adapter.getRisingSignWindows(fixture.input);
|
|
862
|
+
const repeated = adapter.getRisingSignWindows(fixture.input);
|
|
863
|
+
compareRisingSignWindows(fixture, actual, repeated, report);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
aggregateReport.hardFailures.push(...report.hardFailures);
|
|
867
|
+
aggregateReport.warnings.push(...report.warnings);
|
|
868
|
+
assertNoHardFailures(report);
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
it('checks that exact mode is at least as precise as approximate mode for the same day', () => {
|
|
872
|
+
const report = new ValidationReport();
|
|
873
|
+
|
|
874
|
+
for (const fixture of risingSignModeComparisonFixtures) {
|
|
875
|
+
const approximate = adapter.getRisingSignWindows({
|
|
876
|
+
...fixture.baseInput,
|
|
877
|
+
mode: 'approximate',
|
|
878
|
+
});
|
|
879
|
+
const exact = adapter.getRisingSignWindows({
|
|
880
|
+
...fixture.baseInput,
|
|
881
|
+
mode: 'exact',
|
|
882
|
+
});
|
|
883
|
+
compareRisingSignModePrecision(fixture, approximate, exact, adapter, report);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
aggregateReport.hardFailures.push(...report.hardFailures);
|
|
887
|
+
aggregateReport.warnings.push(...report.warnings);
|
|
888
|
+
assertNoHardFailures(report);
|
|
889
|
+
});
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
describe('J. Service-level transit serialization invariants', () => {
|
|
893
|
+
it('covers enriched placement fields, explicit timezones, forecast grouping, and sign carry', () => {
|
|
894
|
+
const report = new ValidationReport();
|
|
895
|
+
|
|
896
|
+
for (const fixture of serviceTransitFixtures) {
|
|
897
|
+
const actual = adapter.getServiceTransits({
|
|
898
|
+
natalChart: fixture.natalChart,
|
|
899
|
+
transitInput: fixture.input,
|
|
900
|
+
startupDefaults: fixture.startupDefaults,
|
|
901
|
+
});
|
|
902
|
+
compareServiceTransitFixture(fixture, actual, report);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
aggregateReport.hardFailures.push(...report.hardFailures);
|
|
906
|
+
aggregateReport.warnings.push(...report.warnings);
|
|
907
|
+
assertNoHardFailures(report);
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
|
|
829
911
|
describe('DST scenario fixtures', () => {
|
|
830
912
|
it('covers ambiguous and nonexistent local times under reject policy', () => {
|
|
831
913
|
for (const fixture of dstFixtures) {
|