const { parseBirthToUtc } = require('../src/birth/parseBirth'); const { computeActivations } = require('../src/calc/profile'); const { computeBodygraph } = require('../src/hd/bodygraph'); const { iching_map } = require('../src/calc/mandala'); // Five real bodygraphs captured from a production Human Design calculator // (Swiss Ephemeris based). Each row is the gate.line for a body, in the standard // order, for the Design and Personality streams. These independently validate // free-human-design's pure-JS ephemeris + historical timezone handling against a // third-party reference. const ORDER = [ 'sun', 'earth', 'moon', 'north_node', 'south_node', 'mercury', 'venus', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune', 'pluto', ]; const CHARTS = [ { name: '1992-12-09 00:35 Brussels', birth: { birthdate: '1992-12-09', birthtime: '00:35', timezone: 'Europe/Brussels' }, P: ['26.1', '45.1', '20.5', '26.5', '45.5', '14.3', '60.5', '56.1', '48.2', '13.1', '54.2', '54.3', '43.6'], D: ['47.3', '22.3', '63.4', '11.5', '12.5', '64.5', '48.5', '15.2', '6.2', '19.6', '38.5', '54.2', '43.2'], }, { name: '1969-03-11 03:00 Chicago', birth: { birthdate: '1969-03-11', birthtime: '03:00', timezone: 'America/Chicago' }, P: ['22.4', '47.4', '26.5', '25.3', '46.3', '30.4', '42.6', '9.1', '46.5', '42.4', '46.5', '14.5', '6.2'], D: ['26.6', '45.6', '48.2', '17.3', '18.3', '11.5', '41.4', '32.1', '18.1', '51.4', '46.6', '14.3', '6.3'], }, { name: '1960-09-12 07:35 San Diego', birth: { birthdate: '1960-09-12', birthtime: '07:35', timezone: 'America/Los_Angeles' }, P: ['47.3', '22.3', '35.6', '64.5', '63.5', '46.3', '48.3', '12.3', '11.3', '38.3', '4.5', '28.6', '40.1'], D: ['45.6', '26.6', '19.1', '47.3', '22.3', '53.1', '45.3', '42.4', '10.2', '54.2', '7.6', '28.5', '59.4'], }, { name: '1974-08-02 12:00 Boise', birth: { birthdate: '1974-08-02', birthtime: '12:00', timezone: 'America/Boise' }, P: ['33.3', '19.3', '41.4', '26.2', '45.2', '62.5', '53.1', '59.4', '63.6', '39.4', '32.4', '9.2', '18.1'], D: ['24.5', '44.5', '46.1', '26.4', '45.4', '24.3', '36.6', '52.4', '63.1', '15.4', '32.5', '9.4', '18.1'], }, { name: '1970-06-04 04:00 Poznan', birth: { birthdate: '1970-06-04', birthtime: '04:00', timezone: 'Europe/Warsaw' }, P: ['35.2', '5.2', '35.3', '37.1', '40.1', '23.1', '39.6', '15.4', '50.1', '2.4', '18.1', '14.5', '6.3'], D: ['63.4', '64.4', '49.4', '63.1', '64.1', '55.1', '36.3', '3.4', '28.4', '27.4', '18.5', '34.1', '6.4'], }, ]; // Cells where free-human-design diverges from the screenshot. Each is exactly one // "line" away on the mandala wheel (see wheelLineSteps below) — the expected // envelope for inter-calculator differences (sub-line ephemeris, true-node // algorithm, and — for Boise — a 1-hour timezone-policy difference). // // Boise: the reference calculator used UTC-7 (MST). free-human-design uses UTC-6 // (MDT) because August 1974 was under the US year-round Daylight Saving Time // (Emergency Daylight Saving Time Energy Conservation Act of 1973) — the // historically-correct offset per the IANA database. Fed the reference's exact // instant (UTC-7), the engine reproduces Venus 53.1 and design Moon 46.1 // (proven in the "historical DST" block below). Both divergences are the // 1-hour shift surfacing on bodies that happen to sit on a gate cusp. const DIVERGENCES = { '1992-12-09 00:35 Brussels|P|mercury': { reason: '1 line; Mercury sits ~9′ from the 14.2/14.3 edge' }, '1974-08-02 12:00 Boise|D|moon': { reason: '1 line; reference used UTC-7 (no 1974 DST), Moon at the 6/46 cusp' }, '1974-08-02 12:00 Boise|P|venus': { reason: '1 line; reference used UTC-7 (no 1974 DST), Venus 1.9′ from the 39/53 cusp' }, '1970-06-04 04:00 Poznan|P|north_node': { reason: '1 line; true-node algorithm variance ~11′' }, '1970-06-04 04:00 Poznan|P|south_node': { reason: '1 line; true-node algorithm variance ~11′' }, }; // Global line index on the wheel (0..383): mandala order × 6 + (line-1). function wheelIndex(gate, line) { const i = iching_map.indexOf(gate); return i * 6 + (line - 1); } function wheelLineSteps(a, b) { const [ga, la] = a.split('.').map(Number); const [gb, lb] = b.split('.').map(Number); const d = Math.abs(wheelIndex(ga, la) - wheelIndex(gb, lb)); return Math.min(d, 64 * 6 - d); } describe('reference charts (vs third-party Swiss-Ephemeris calculator)', () => { const computed = CHARTS.map((c) => { const act = computeActivations({ birthUtc: parseBirthToUtc(c.birth) }); return { chart: c, P: Object.fromEntries(act.personality.map((a) => [a.body, `${a.gate}.${a.line}`])), D: Object.fromEntries(act.design.map((a) => [a.body, `${a.gate}.${a.line}`])), }; }); for (const { chart, P, D } of computed) { describe(chart.name, () => { ORDER.forEach((body, i) => { for (const stream of ['P', 'D']) { const ref = (stream === 'P' ? chart.P : chart.D)[i]; const got = (stream === 'P' ? P : D)[body]; const key = `${chart.name}|${stream}|${body}`; const div = DIVERGENCES[key]; if (!div) { it(`${stream} ${body} = ${ref}`, () => { expect(got).toBe(ref); }); } else if (!div.misread) { it(`${stream} ${body} ≈ ${ref} (within 1 line: ${div.reason})`, () => { expect(wheelLineSteps(got, ref)).toBeLessThanOrEqual(1); }); } } }); }); } it('reproduces the reference exactly for ≥125 of the 130 body activations', () => { let exact = 0; for (const { chart, P, D } of computed) { ORDER.forEach((body, i) => { if (P[body] === chart.P[i]) exact += 1; if (D[body] === chart.D[i]) exact += 1; }); } expect(exact).toBeGreaterThanOrEqual(125); }); }); // Bodygraph cross-check. The defined-centers / Type / Authority / Profile below // follow deterministically from the (reference-validated) gate activations. // The center colorings for Brussels, Chicago and Poznan were independently // confirmed against the screenshots; San Diego and Boise are locked from the // engine (eyeballing the colors is error-prone — e.g. San Diego's Solar Plexus // is defined via 12-22, and Boise's G is open, both easy to misread). const EXPECTED_BODYGRAPH = { '1992-12-09 00:35 Brussels': { type: 'Manifestor', authority: 'Emotional (Solar Plexus)', profile: '1/3', definedCenters: ['head', 'ajna', 'throat', 'solarplexus'], }, '1969-03-11 03:00 Chicago': { type: 'Projector', authority: 'Emotional (Solar Plexus)', profile: '4/6', definedCenters: ['g', 'heart', 'solarplexus', 'root'], }, '1960-09-12 07:35 San Diego': { type: 'Manifesting Generator', authority: 'Emotional (Solar Plexus)', profile: '3/6', definedCenters: ['head', 'ajna', 'throat', 'sacral', 'solarplexus', 'spleen', 'root'], }, '1974-08-02 12:00 Boise': { type: 'Generator', authority: 'Emotional (Solar Plexus)', profile: '3/5', definedCenters: ['heart', 'sacral', 'solarplexus', 'spleen', 'root'], }, '1970-06-04 04:00 Poznan': { type: 'Manifesting Generator', authority: 'Emotional (Solar Plexus)', profile: '2/4', definedCenters: ['throat', 'g', 'heart', 'sacral', 'solarplexus', 'spleen', 'root'], }, }; describe('reference charts — derived bodygraph', () => { for (const chart of CHARTS) { const exp = EXPECTED_BODYGRAPH[chart.name]; it(`${chart.name}: ${exp.type}, ${exp.authority}, ${exp.profile}`, () => { const bg = computeBodygraph(computeActivations({ birthUtc: parseBirthToUtc(chart.birth) })); expect(bg.type).toBe(exp.type); expect(bg.authority).toBe(exp.authority); expect(bg.profile).toBe(exp.profile); expect(bg.definedCenters).toEqual(exp.definedCenters); }); } }); // The Boise 1974 chart isolates a real historical-timezone edge case: the US // observed year-round Daylight Saving Time in 1974, so 12:00 local Boise time // is MDT (UTC-6), not MST (UTC-7). free-human-design follows the IANA database and // gets this right; the reference calculator used UTC-7. describe('Boise 1974 — historical DST handling', () => { it('America/Boise applies year-round DST: 12:00 → 18:00Z (UTC-6, MDT)', () => { const utc = parseBirthToUtc({ birthdate: '1974-08-02', birthtime: '12:00', timezone: 'America/Boise' }); expect(utc.toISOString()).toBe('1974-08-02T18:00:00.000Z'); }); it("at the reference's UTC-7 instant the engine reproduces Venus 53.1 & design Moon 46.1", () => { // Etc/GMT+7 is UTC-7 (the Etc/GMT sign convention is inverted). const utc7 = parseBirthToUtc({ birthdate: '1974-08-02', birthtime: '12:00', timezone: 'Etc/GMT+7' }); expect(utc7.toISOString()).toBe('1974-08-02T19:00:00.000Z'); const act = computeActivations({ birthUtc: utc7 }); const venus = act.personality.find((a) => a.body === 'venus'); const moon = act.design.find((a) => a.body === 'moon'); expect(`${venus.gate}.${venus.line}`).toBe('53.1'); expect(`${moon.gate}.${moon.line}`).toBe('46.1'); // Venus is direct (not retrograde) — VSOP87 near max speed ~+1.2°/day. expect(venus.retrograde).toBe(false); }); });