@essrt/physics 13.0.0 → 15.0.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/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@essrt/physics",
3
- "version": "13.0.0",
3
+ "version": "15.0.0",
4
4
  "description": "ESSRT (Expanding Solar System Resonance Theory) physics core — pure, injectable-constants, no I/O, no globals, no DOM. The complete model incl. fitted coefficients; every published version immutably ships one recorded model identity.",
5
5
  "essrt": {
6
- "modelVersion": "v17.0",
6
+ "modelVersion": "v19.0",
7
7
  "_note": "The model identity this package version ships (IP-unified-architecture §10: package semver tracks the API axis; the model version + CONSTANTS_HASH/COEFFICIENTS_HASH in src/constants/ carry the scientific identity). The version-pinning gate enforces this pairing against public/input/model-version.json."
8
8
  },
9
9
  "type": "module",
@@ -50,10 +50,7 @@
50
50
  "./moon/series-extension": { "types": "./types/moon/series-extension.d.cts", "default": "./src/moon/series-extension.cjs" },
51
51
  "./moon/apparent": { "types": "./types/moon/apparent.d.cts", "default": "./src/moon/apparent.cjs" },
52
52
  "./planets/geometry": { "types": "./types/planets/geometry.d.cts", "default": "./src/planets/geometry.cjs" },
53
- "./planets/fibonacci-laws": { "types": "./types/planets/fibonacci-laws.d.cts", "default": "./src/planets/fibonacci-laws.cjs" },
54
53
  "./planets/ecc-channel": { "types": "./types/planets/ecc-channel.d.cts", "default": "./src/planets/ecc-channel.cjs" },
55
- "./planets/orientation": { "types": "./types/planets/orientation.d.cts", "default": "./src/planets/orientation.cjs" },
56
- "./planets/asc-node-integrator": { "types": "./types/planets/asc-node-integrator.d.cts", "default": "./src/planets/asc-node-integrator.cjs" },
57
54
  "./planets/orbit-chain": { "types": "./types/planets/orbit-chain.d.cts", "default": "./src/planets/orbit-chain.cjs" },
58
55
  "./planets/keplerian-chain": { "types": "./types/planets/keplerian-chain.d.cts", "default": "./src/planets/keplerian-chain.cjs" },
59
56
  "./planets/spin-channel": { "types": "./types/planets/spin-channel.d.cts", "default": "./src/planets/spin-channel.cjs" },
@@ -2,14 +2,14 @@
2
2
  // Gives the TypeScript website full type safety at the boundary (§2g) while
3
3
  // packages/physics stays JavaScript.
4
4
 
5
- export declare const CONSTANTS_HASH: "726b10e23d8ace09";
5
+ export declare const CONSTANTS_HASH: "5ce921f2efa2e845";
6
6
 
7
7
  export declare const MODEL_VERSION: string;
8
8
 
9
9
  export declare const PREPRINT_DOI: string;
10
10
 
11
11
  export declare const DEFAULT_CONSTANTS: {
12
- readonly hash: "726b10e23d8ace09";
12
+ readonly hash: "5ce921f2efa2e845";
13
13
  readonly additionalBodies: {
14
14
  "pluto": {
15
15
  "name": string;
@@ -17,9 +17,7 @@ export declare const DEFAULT_CONSTANTS: {
17
17
  "type": string;
18
18
  "angleCorrection": number;
19
19
  "startpos": number;
20
- "perihelionEclipticFraction": [number, number];
21
20
  "ascendingNodeInvPlane": number;
22
- "inclinationCycleAnchor": number;
23
21
  "invPlaneInclinationMean": number;
24
22
  "invPlaneInclinationAmplitude": number;
25
23
  };
@@ -29,9 +27,7 @@ export declare const DEFAULT_CONSTANTS: {
29
27
  "type": string;
30
28
  "angleCorrection": number;
31
29
  "startpos": number;
32
- "perihelionEclipticFraction": [number, number];
33
30
  "ascendingNodeInvPlane": number;
34
- "inclinationCycleAnchor": number;
35
31
  "invPlaneInclinationMean": number;
36
32
  "invPlaneInclinationAmplitude": number;
37
33
  };
@@ -41,9 +37,7 @@ export declare const DEFAULT_CONSTANTS: {
41
37
  "type": string;
42
38
  "angleCorrection": number;
43
39
  "startpos": number;
44
- "perihelionEclipticFraction": [number, number];
45
40
  "ascendingNodeInvPlane": number;
46
- "inclinationCycleAnchor": number;
47
41
  "invPlaneInclinationMean": number;
48
42
  "invPlaneInclinationAmplitude": number;
49
43
  };
@@ -53,9 +47,7 @@ export declare const DEFAULT_CONSTANTS: {
53
47
  "orbitDistanceOverride": number;
54
48
  "angleCorrection": number;
55
49
  "startpos": number;
56
- "perihelionEclipticFraction": [number, number];
57
50
  "ascendingNodeInvPlane": number;
58
- "inclinationCycleAnchor": number;
59
51
  "invPlaneInclinationMean": number;
60
52
  "invPlaneInclinationAmplitude": number;
61
53
  };
@@ -486,13 +478,9 @@ export declare const DEFAULT_CONSTANTS: {
486
478
  "eocFraction": number;
487
479
  "startpos": number;
488
480
  "angleCorrection": number;
489
- "perihelionEclipticFraction": [number, number];
490
481
  "type": string;
491
482
  "mirrorPair": string;
492
- "fibonacciD": number;
493
483
  "ascendingNodeInvPlane": number;
494
- "inclinationCycleAnchor": number;
495
- "antiPhase": boolean;
496
484
  "ascendingNodeCyclesIn8H": number;
497
485
  };
498
486
  "venus": {
@@ -500,13 +488,9 @@ export declare const DEFAULT_CONSTANTS: {
500
488
  "eocFraction": number;
501
489
  "startpos": number;
502
490
  "angleCorrection": number;
503
- "perihelionEclipticFraction": [number, number];
504
491
  "type": string;
505
492
  "mirrorPair": string;
506
- "fibonacciD": number;
507
493
  "ascendingNodeInvPlane": number;
508
- "inclinationCycleAnchor": number;
509
- "antiPhase": boolean;
510
494
  "ascendingNodeCyclesIn8H": number;
511
495
  };
512
496
  "mars": {
@@ -514,13 +498,9 @@ export declare const DEFAULT_CONSTANTS: {
514
498
  "eocFraction": number;
515
499
  "startpos": number;
516
500
  "angleCorrection": number;
517
- "perihelionEclipticFraction": [number, number];
518
501
  "type": string;
519
502
  "mirrorPair": string;
520
- "fibonacciD": number;
521
503
  "ascendingNodeInvPlane": number;
522
- "inclinationCycleAnchor": number;
523
- "antiPhase": boolean;
524
504
  "ascendingNodeCyclesIn8H": number;
525
505
  };
526
506
  "jupiter": {
@@ -528,13 +508,9 @@ export declare const DEFAULT_CONSTANTS: {
528
508
  "eocFraction": number;
529
509
  "startpos": number;
530
510
  "angleCorrection": number;
531
- "perihelionEclipticFraction": [number, number];
532
511
  "type": string;
533
512
  "mirrorPair": string;
534
- "fibonacciD": number;
535
513
  "ascendingNodeInvPlane": number;
536
- "inclinationCycleAnchor": number;
537
- "antiPhase": boolean;
538
514
  "ascendingNodeCyclesIn8H": number;
539
515
  };
540
516
  "saturn": {
@@ -542,13 +518,9 @@ export declare const DEFAULT_CONSTANTS: {
542
518
  "eocFraction": number;
543
519
  "startpos": number;
544
520
  "angleCorrection": number;
545
- "perihelionEclipticFraction": [number, number];
546
521
  "type": string;
547
522
  "mirrorPair": string;
548
- "fibonacciD": number;
549
523
  "ascendingNodeInvPlane": number;
550
- "inclinationCycleAnchor": number;
551
- "antiPhase": boolean;
552
524
  "ascendingNodeCyclesIn8H": number;
553
525
  };
554
526
  "uranus": {
@@ -556,13 +528,9 @@ export declare const DEFAULT_CONSTANTS: {
556
528
  "eocFraction": number;
557
529
  "startpos": number;
558
530
  "angleCorrection": number;
559
- "perihelionEclipticFraction": [number, number];
560
531
  "type": string;
561
532
  "mirrorPair": string;
562
- "fibonacciD": number;
563
533
  "ascendingNodeInvPlane": number;
564
- "inclinationCycleAnchor": number;
565
- "antiPhase": boolean;
566
534
  "ascendingNodeCyclesIn8H": number;
567
535
  };
568
536
  "neptune": {
@@ -570,13 +538,9 @@ export declare const DEFAULT_CONSTANTS: {
570
538
  "eocFraction": number;
571
539
  "startpos": number;
572
540
  "angleCorrection": number;
573
- "perihelionEclipticFraction": [number, number];
574
541
  "type": string;
575
542
  "mirrorPair": string;
576
- "fibonacciD": number;
577
543
  "ascendingNodeInvPlane": number;
578
- "inclinationCycleAnchor": number;
579
- "antiPhase": boolean;
580
544
  "ascendingNodeCyclesIn8H": number;
581
545
  };
582
546
  };
@@ -33,17 +33,17 @@
33
33
  * carry it so a counterfactual is reproducible (§2d).
34
34
  * @type {string}
35
35
  */
36
- export const CONSTANTS_HASH = "726b10e23d8ace09";
36
+ export const CONSTANTS_HASH = "5ce921f2efa2e845";
37
37
 
38
38
  /** Model version label — single source: public/input/model-version.json (§10 two-axis scheme). */
39
- export const MODEL_VERSION = "v17.0";
39
+ export const MODEL_VERSION = "v19.0";
40
40
 
41
41
  /** Canonical preprint DOI — single source: public/input/model-version.json. */
42
42
  export const PREPRINT_DOI = "10.21203/rs.3.rs-8758810/v4";
43
43
 
44
44
  /** @type {Readonly<Record<string, unknown>>} */
45
45
  export const DEFAULT_CONSTANTS = Object.freeze({
46
- hash: "726b10e23d8ace09",
46
+ hash: "5ce921f2efa2e845",
47
47
  additionalBodies: {
48
48
  "pluto": {
49
49
  "name": "Pluto",
@@ -51,12 +51,7 @@ export const DEFAULT_CONSTANTS = Object.freeze({
51
51
  "type": "I",
52
52
  "angleCorrection": 2.469281,
53
53
  "startpos": 71.555,
54
- "perihelionEclipticFraction": [
55
- 1,
56
- 1
57
- ],
58
54
  "ascendingNodeInvPlane": 101.06,
59
- "inclinationCycleAnchor": 203.32,
60
55
  "invPlaneInclinationMean": 15.7162,
61
56
  "invPlaneInclinationAmplitude": 0.717024
62
57
  },
@@ -66,12 +61,7 @@ export const DEFAULT_CONSTANTS = Object.freeze({
66
61
  "type": "III",
67
62
  "angleCorrection": -1.619816,
68
63
  "startpos": 80,
69
- "perihelionEclipticFraction": [
70
- 1,
71
- 1
72
- ],
73
64
  "ascendingNodeInvPlane": 59.56,
74
- "inclinationCycleAnchor": 23.3195,
75
65
  "invPlaneInclinationMean": 150,
76
66
  "invPlaneInclinationAmplitude": 0.1
77
67
  },
@@ -81,12 +71,7 @@ export const DEFAULT_CONSTANTS = Object.freeze({
81
71
  "type": "II",
82
72
  "angleCorrection": 0.047888,
83
73
  "startpos": 57.402,
84
- "perihelionEclipticFraction": [
85
- 1,
86
- 1
87
- ],
88
74
  "ascendingNodeInvPlane": 10.36,
89
- "inclinationCycleAnchor": 203.3195,
90
75
  "invPlaneInclinationMean": 9.25,
91
76
  "invPlaneInclinationAmplitude": 0.5
92
77
  },
@@ -96,12 +81,7 @@ export const DEFAULT_CONSTANTS = Object.freeze({
96
81
  "orbitDistanceOverride": 2.76596,
97
82
  "angleCorrection": 0,
98
83
  "startpos": 0,
99
- "perihelionEclipticFraction": [
100
- 1,
101
- 1
102
- ],
103
84
  "ascendingNodeInvPlane": 80.89,
104
- "inclinationCycleAnchor": 203.3195,
105
85
  "invPlaneInclinationMean": 0.43,
106
86
  "invPlaneInclinationAmplitude": 0.05
107
87
  }
@@ -647,16 +627,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
647
627
  "eocFraction": -0.527,
648
628
  "startpos": 83.64651142941864,
649
629
  "angleCorrection": 0.9727205912043573,
650
- "perihelionEclipticFraction": [
651
- 8,
652
- 11
653
- ],
654
630
  "type": "I",
655
631
  "mirrorPair": "uranus",
656
- "fibonacciD": 21,
657
632
  "ascendingNodeInvPlane": 32.83,
658
- "inclinationCycleAnchor": 234.52,
659
- "antiPhase": false,
660
633
  "ascendingNodeCyclesIn8H": 9
661
634
  },
662
635
  "venus": {
@@ -664,16 +637,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
664
637
  "eocFraction": 0.436,
665
638
  "startpos": 249.28769121856186,
666
639
  "angleCorrection": -2.789778861448692,
667
- "perihelionEclipticFraction": [
668
- -8,
669
- 6
670
- ],
671
640
  "type": "I",
672
641
  "mirrorPair": "neptune",
673
- "fibonacciD": 34,
674
642
  "ascendingNodeInvPlane": 54.7,
675
- "inclinationCycleAnchor": 218.64,
676
- "antiPhase": false,
677
643
  "ascendingNodeCyclesIn8H": 1
678
644
  },
679
645
  "mars": {
@@ -681,16 +647,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
681
647
  "eocFraction": -0.066224,
682
648
  "startpos": 121.4634461571797,
683
649
  "angleCorrection": -2.104652936098656,
684
- "perihelionEclipticFraction": [
685
- 8,
686
- 36
687
- ],
688
650
  "type": "II",
689
651
  "mirrorPair": "jupiter",
690
- "fibonacciD": 5,
691
652
  "ascendingNodeInvPlane": 354.87,
692
- "inclinationCycleAnchor": 236.07,
693
- "antiPhase": false,
694
653
  "ascendingNodeCyclesIn8H": 64
695
654
  },
696
655
  "jupiter": {
@@ -698,16 +657,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
698
657
  "eocFraction": 0.495,
699
658
  "startpos": 13.887946755371052,
700
659
  "angleCorrection": 0.9333205235053406,
701
- "perihelionEclipticFraction": [
702
- 8,
703
- 39
704
- ],
705
660
  "type": "III",
706
661
  "mirrorPair": "mars",
707
- "fibonacciD": 5,
708
662
  "ascendingNodeInvPlane": 312.89,
709
- "inclinationCycleAnchor": 287.06,
710
- "antiPhase": false,
711
663
  "ascendingNodeCyclesIn8H": 36
712
664
  },
713
665
  "saturn": {
@@ -715,16 +667,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
715
667
  "eocFraction": 0.54,
716
668
  "startpos": 11.279308392461772,
717
669
  "angleCorrection": -0.1784695052193328,
718
- "perihelionEclipticFraction": [
719
- -8,
720
- 65
721
- ],
722
670
  "type": "III",
723
671
  "mirrorPair": "earth",
724
- "fibonacciD": 3,
725
672
  "ascendingNodeInvPlane": 118.81,
726
- "inclinationCycleAnchor": 116.26,
727
- "antiPhase": true,
728
673
  "ascendingNodeCyclesIn8H": 36
729
674
  },
730
675
  "uranus": {
@@ -732,16 +677,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
732
677
  "eocFraction": 0.53,
733
678
  "startpos": 44.900388945775106,
734
679
  "angleCorrection": -0.7343433510960402,
735
- "perihelionEclipticFraction": [
736
- 1,
737
- 3
738
- ],
739
680
  "type": "III",
740
681
  "mirrorPair": "mercury",
741
- "fibonacciD": 21,
742
682
  "ascendingNodeInvPlane": 307.8,
743
- "inclinationCycleAnchor": 21.33,
744
- "antiPhase": false,
745
683
  "ascendingNodeCyclesIn8H": 11
746
684
  },
747
685
  "neptune": {
@@ -749,16 +687,9 @@ export const DEFAULT_CONSTANTS = Object.freeze({
749
687
  "eocFraction": 0.585,
750
688
  "startpos": 47.9552024382285,
751
689
  "angleCorrection": 2.3327665835675617,
752
- "perihelionEclipticFraction": [
753
- 2,
754
- 1
755
- ],
756
690
  "type": "III",
757
691
  "mirrorPair": "venus",
758
- "fibonacciD": 34,
759
692
  "ascendingNodeInvPlane": 192.04,
760
- "inclinationCycleAnchor": 174.04,
761
- "antiPhase": false,
762
693
  "ascendingNodeCyclesIn8H": 3
763
694
  }
764
695
  },
package/src/index.js CHANGED
@@ -122,12 +122,13 @@ export { createMoonApparent } from './moon/apparent.cjs';
122
122
  // sample) and the offset-circle wheel-angle solver: the scene twins' one placement.
123
123
  export { computeEarthFrameOfDate, solveWheelAngleForLongitude } from './earth/frame-of-date.cjs';
124
124
  // Phase 8.3 — the planet machinery, extracted by LAW over body records
125
- // (survey order: geometry → Fibonacci laws → channels → chains).
125
+ // (survey order: geometry → channels → chains). The ψ/K amplitude laws
126
+ // (planets/fibonacci-laws), the record-based orientation forms
127
+ // (planets/orientation) and the ascending-node integrator
128
+ // (planets/asc-node-integrator) are DELETED at plan 07 R5/R6: the planets'
129
+ // elements of date have one home, the N-body chain; docs/retired-record.md.
126
130
  export { derivePlanetGeometry } from './planets/geometry.cjs';
127
- export * as planetFibonacciLaws from './planets/fibonacci-laws.cjs';
128
131
  export { eccentricityFromCycles, computeEccentricityIntegrated } from './planets/ecc-channel.cjs';
129
- export * as planetOrientation from './planets/orientation.cjs';
130
- export { integrateAscendingNode } from './planets/asc-node-integrator.cjs';
131
132
  export * as planetOrbitChain from './planets/orbit-chain.cjs';
132
133
  // P5/K4.6c — the engine-D Keplerian chain (pure evaluator + the embedded
133
134
  // governed artifact; the browser flag path consumes exactly these).
package/src/model.js CHANGED
@@ -18,7 +18,6 @@
18
18
  * which itself mirrors tools/lib/constants.js §9.
19
19
  */
20
20
  import { deriveEpochParams } from './layer0/derive-params.js';
21
- import * as FL from './planets/fibonacci-laws.cjs';
22
21
  import { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear } from './planets/keplerian-chain.cjs';
23
22
  import { createSecularSeriesOverride } from './planets/secular-series.cjs';
24
23
  import { computeEquatorNodeOriginSFrameDeg, convertNodeSFrameToEquatorOriginDeg } from './planets/inv-plane-frame.cjs';
@@ -26,7 +25,6 @@ import { createPhaseMachinery } from './phase/index.cjs';
26
25
  import { createYearLengths, ONE_FAMILY_WINDOW_YEARS } from './earth/year-lengths.cjs';
27
26
  import { createDeepOrbitalHistory } from './earth/deep-orbital-history.cjs';
28
27
  import { CHAIN_ARTIFACT } from './planets/chain-artifact.js';
29
- import { computeSecularShape } from './planets/secular-shape.cjs';
30
28
  import { createPlanetSpinChannelFromArtifacts, computeObliquityJ2000Deg } from './planets/spin-channel.cjs';
31
29
  import { createDeltaTCycles } from './deltat/cycles.cjs';
32
30
  import { createDeepTimeLod } from './deltat/deep-time.cjs';
@@ -97,14 +95,12 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
97
95
  const meanAnomalisticYearDays = (meanSolarYearDays * (H / 16)) / (H / 16 - 1);
98
96
  const meanTropicalYearJ2000Seconds = meanSolarYearDays * meanLengthOfDay;
99
97
 
100
- const earthInclAmplitude = C.earth.earthInvPlaneInclinationAmplitude;
101
- // Plan 07 R6: `earthtiltMean` and `eccentricityAmplitude` were read here
102
- // ONLY to invert the K constant from Earth's calibration. With the K law
103
- // retired nothing in this module reads either — they remain on C.earth for
104
- // the Earth-side devices (R9) and the registry.
105
- const earthInclMean = C.earthOrbital.earthInclinationJ2000_deg
106
- - earthInclAmplitude * Math.cos(((C.earthOrbital.earthPerihelionLongitudeJ2000
107
- - C.earthOrbital.earthInclinationCycleAnchor) * Math.PI) / 180);
98
+ // Plan 07 R5/R6/R9: `earthtiltMean`, `earthInvPlaneInclinationAmplitude`
99
+ // and `eccentricityAmplitude` were read here only to invert the K and ψ
100
+ // constants from Earth's calibration and to build the H/3 inclination
101
+ // device. With both laws retired nothing in this module reads them — they
102
+ // remain on C.earth as the K device's J2000 pose inputs (the scene's wheel
103
+ // geometry at the chain anchor epoch) and for the registry's record keys.
108
104
  const solsticeObliquityMean = F.SOLSTICE_OBLIQUITY_MEAN_FITTED;
109
105
 
110
106
  const G_CONSTANT = C.physicalConstants.G_CONSTANT;
@@ -429,14 +425,9 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
429
425
  /** de/dyear of the Sun's e — the cardinal braid's equation-of-centre
430
426
  * derivative rides it (±0.5-yr central difference; the constant offset
431
427
  * cancels). @param {number} year @returns {number} */
432
- /** @param {number} year @returns {number} */
433
- const inclinationDeg = (year) => earthInclMean
434
- - earthInclAmplitude * Math.cos(phaseRadians(balancedYear, year, 3));
435
- /** @param {number} year @returns {number} */
436
- const ascendingNodeDeg = (year) => {
437
- const period = -H / 5;
438
- return (((C.earthOrbital.earthAscendingNodeInvPlane + (360.0 * (year - 2000)) / period) % 360) + 360) % 360;
439
- };
428
+ // (Plan 07 R5/R9: Earth's H/3 inclination cosine and −H/5 linear node — the
429
+ // K device — stood here; `inclinationDeg`/`ascendingNodeDeg` are now the
430
+ // one-source construction defined with the planets' chain evaluators below.)
440
431
 
441
432
  // ── Year/day lengths ──────────────────────────────────────────────────────
442
433
  /** @param {number} year @param {number} base @param {Array<[number, number, number]>} harmonics @returns {number} */
@@ -617,6 +608,8 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
617
608
  });
618
609
  return {
619
610
  yearLengths,
611
+ /** The one-source sample at a decimal year (the engine year) — ε, e, ϖ of date, the Earth-orbit normal (the fields the frame of date and the invariable-plane elements read). @param {number} year */
612
+ sampleAt,
620
613
  /** EXPERIMENT accessors: the series' e and equinox-referenced ϖ of date. @param {number} year @returns {number} */
621
614
  eAt: (year) => sampleAt(year).e,
622
615
  /** @param {number} year @returns {number} */
@@ -716,41 +709,27 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
716
709
  for (const k of PLANET_KEYS) massFraction[k] = 1 / C.physicalConstants.massRatioDE440[k];
717
710
  massFraction.earth = massEarthAlone / M_SUN;
718
711
 
719
- const PSI = FL.computePsiConstant({
720
- earthInvPlaneInclinationAmplitude: earthInclAmplitude,
721
- massEarthAlone,
722
- massSun: M_SUN,
723
- });
724
712
  // (plan 07 R6: eccentricityAmplitudeK — the K constant inverted from
725
713
  // Earth's calibration — and the t2000 phase offset it fed went with the
726
- // eccentricity law. systemResetN is kept where other consumers read it.)
727
-
728
- /** @param {[number, number]|null} frac @returns {number|null} */
729
- const fractionToYears = (frac) => (frac === null ? null : (H * frac[0]) / frac[1]);
714
+ // eccentricity law; plan 07 R5: PSI — ψ = 3·A_earth·√(m_E/m_☉) — and the
715
+ // inclination law it fed went the same way. systemResetN is kept where
716
+ // other consumers read it.)
730
717
 
731
- /** @type {Record<string, Record<string, any>>} */
732
- const PLANET_RECORDS = {}; // internal: the fitters read the device fields
718
+ // Plan 07 R1/R8: the internal PLANET_RECORDS — the device record the
719
+ // fitters once read (the H·num/den perihelion period from
720
+ // perihelionEclipticFraction, fibonacciD, antiPhase, inclinationCycleAnchor,
721
+ // the −8H/N node period) — had no reader left after R6/R5 and is gone with
722
+ // its JSON inputs. What remains is the PUBLISHED record below.
733
723
  /** @type {Record<string, Record<string, any>>} */
734
724
  const PUBLISHED_PLANET_RECORDS = {}; // what model.planets.record() serves (R8)
735
725
  for (const k of PLANET_KEYS) {
736
726
  const mp = C.planets[k];
737
727
  const ar = C.planetOrbitalElements[k];
738
- const ecl = /** @type {number} */ (fractionToYears(mp.perihelionEclipticFraction));
739
728
  // Plan 06 Phase 7 commit 2: the K device's integer axial and obliquity
740
- // fractions are retired. The eccentricity law's cycle period is the
741
- // chain's OWN g-mode beat (the dominant mode × largest companion of the
742
- // planet's eccentricity vector), its obliquity input the DERIVED J2000
743
- // obliquity of the spin channel (the IAU pole against the chain's J2000
744
- // plane, acute form) — both from the governed artifacts, no fractions.
745
- const wobble = computeSecularShape(/** @type {any} */ (CHAIN_ARTIFACT), k).beatYears;
746
- const il = FL.computeInclinationLaw({
747
- fibonacciD: mp.fibonacciD,
748
- massFrac: massFraction[k],
749
- invPlaneInclinationJ2000: ar.invPlaneInclinationJ2000,
750
- longitudePerihelion: ar.longitudePerihelion,
751
- inclinationCycleAnchor: mp.inclinationCycleAnchor,
752
- antiPhase: mp.antiPhase || false,
753
- }, PSI);
729
+ // fractions are retired; the obliquity is the DERIVED J2000 obliquity of
730
+ // the spin channel (the IAU pole against the chain's J2000 plane, acute
731
+ // form) — from the governed artifacts, no fractions. (The g-mode beat the
732
+ // K law's period rode left with the internal record at plan 07 R1/R8.)
754
733
  const obliquityDerived = computeObliquityJ2000Deg({
755
734
  spin: C.planetSpinPhysical[k],
756
735
  anchorInclEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].inclEclipticDeg,
@@ -758,31 +737,11 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
758
737
  obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
759
738
  });
760
739
  const obliquityMean = Math.min(obliquityDerived, 180 - obliquityDerived); // acute form of the derived J2000 obliquity
761
- PLANET_RECORDS[k] = Object.freeze({
762
- name: mp.name,
763
- perihelionEclipticYears: ecl,
764
- longitudePerihelion: ar.longitudePerihelion,
765
- ascendingNodeCyclesIn8H: mp.ascendingNodeCyclesIn8H,
766
- ascendingNodePeriod: -(8 * H) / mp.ascendingNodeCyclesIn8H,
767
- wobblePeriod: wobble,
768
- fibonacciD: mp.fibonacciD,
769
- antiPhase: mp.antiPhase || false,
770
- ascendingNodeInvPlane: mp.ascendingNodeInvPlane,
771
- inclinationCycleAnchor: mp.inclinationCycleAnchor,
772
- invPlaneInclinationJ2000: ar.invPlaneInclinationJ2000,
773
- invPlaneInclinationAmplitude: il.amplitude,
774
- invPlaneInclinationMean: il.mean,
775
- obliquityMean,
776
- orbitalEccentricityJ2000: ar.orbitalEccentricityJ2000,
777
- solarYearInput: ar.solarYearInput,
778
- axialTiltJ2000: ar.axialTiltJ2000,
779
- });
780
- // R8 (plan 07): what `model.planets.record()` PUBLISHES is not the record
781
- // above. The internal record kept the ψ/K law outputs for the fitting
782
- // pipeline; at R6 the K half and both fitter steps that read it are gone,
783
- // so what remains above is the ψ half (until R5) and the structural inputs.
784
- // The separation stands for the same reason it was made —
785
- // but nothing outside needs the device, and serving it made /v1/bodies
740
+ // R8 (plan 07): what `model.planets.record()` PUBLISHES is the structural
741
+ // record, not the device. The internal record that kept the ψ/K law
742
+ // outputs for the fitting pipeline went piecewise: the K half at R6, the ψ
743
+ // half at R5, the lattice inputs at R1/R8 (nothing read it by then).
744
+ // Nothing outside needs the device, and serving it made /v1/bodies
786
745
  // contradict the model's own chain on the SAME quantities: Mercury's node
787
746
  // cycle 298,060 yr against the chain's 232,001, Jupiter's perihelion period
788
747
  // 68,783 against 304,456, Neptune's 670,634 against 2,136,796. The two
@@ -878,13 +837,15 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
878
837
  };
879
838
  /** Ecliptic longitude of perihelion, J2000 ecliptic and equinox (the chain's ϖ). @param {string} k @param {number} year @returns {number} */
880
839
  const planetPerihelionDeg = (k, year) => planetChainElementsAt(k, year).lonPeriEclipticDeg;
881
- /** Ascending node on the model's invariable plane, from the plane's ascending node on the ICRF equator (the Souami & Souchay 2012 origin; derived conversion, inv-plane-frame). @param {string} k @param {number} year @returns {number} */
882
- const planetAscNodeDeg = (k, year) => {
840
+ /** The S&S longitude origin as an s-frame longitude (J2000-fixed, derived). @returns {number} */
841
+ const nodeOriginSSDeg = () => {
883
842
  if (planetNodeOriginSSDeg === null) {
884
843
  planetNodeOriginSSDeg = computeEquatorNodeOriginSFrameDeg(/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane, C.earthOrbital.obliquityJ2000_deg);
885
844
  }
886
- return convertNodeSFrameToEquatorOriginDeg(planetChainElementsAt(k, year).ascNodeInvPlaneDeg, planetNodeOriginSSDeg);
845
+ return planetNodeOriginSSDeg;
887
846
  };
847
+ /** Ascending node on the model's invariable plane, from the plane's ascending node on the ICRF equator (the Souami & Souchay 2012 origin; derived conversion, inv-plane-frame). @param {string} k @param {number} year @returns {number} */
848
+ const planetAscNodeDeg = (k, year) => convertNodeSFrameToEquatorOriginDeg(planetChainElementsAt(k, year).ascNodeInvPlaneDeg, nodeOriginSSDeg());
888
849
  /** Inclination to the model's invariable plane (exact orbit-normal rotation). @param {string} k @param {number} year @returns {number} */
889
850
  const planetInclinationDeg = (k, year) => planetChainElementsAt(k, year).inclInvPlaneDeg;
890
851
  /** Orbital eccentricity of date, from the same chain elements (R8): the
@@ -893,6 +854,52 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
893
854
  * e-vector does not have. @param {string} k @param {number} year @returns {number} */
894
855
  const planetEccentricity = (k, year) => planetChainElementsAt(k, year).e;
895
856
 
857
+ // ── Earth's invariable-plane elements of date (plan 07 R5/R9) ─────────────
858
+ // ONE published i_inv / Ω_inv everywhere — the mirror of the browser's
859
+ // inclInvPlaneModel / ascNodeInvPlaneModel (identical ops): the engine's
860
+ // own Earth-orbit normal of date (the one-source sampler — the banked
861
+ // secular series inside ±10 Myr, the mode tail beyond) against the
862
+ // artifact's invariable plane, the node expressed in the Souami & Souchay
863
+ // longitude origin through the same derived conversion the planets' node
864
+ // takes. The H/3 cosine on the fixed apsidal carrier and the −H/5 linear
865
+ // node that served here until R5 were the K device: 1.578677° against
866
+ // 1.578422° at J2000, 1.24° against 1.91° at −100 kyr, and 112° against
867
+ // 94° of node there. Doc 05 banks the one-source reading at rms 0.003°
868
+ // vs La2010 over −500 kyr. Argument: the engine year (dynamical time,
869
+ // Julian from J2000 TT — the sampler's own coordinate, as the chain's).
870
+ const invPlaneGeometry = (() => {
871
+ const ip = /** @type {{ inclEclipticDeg: number, ascNodeEclipticDeg: number }} */ (/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane);
872
+ const D2R = Math.PI / 180;
873
+ const si = Math.sin(ip.inclEclipticDeg * D2R), ci = Math.cos(ip.inclEclipticDeg * D2R);
874
+ const nInv = [si * Math.sin(ip.ascNodeEclipticDeg * D2R), -si * Math.cos(ip.ascNodeEclipticDeg * D2R), ci];
875
+ const xIp = [Math.cos(ip.ascNodeEclipticDeg * D2R), Math.sin(ip.ascNodeEclipticDeg * D2R), 0];
876
+ const yIp = [nInv[1] * xIp[2] - nInv[2] * xIp[1], nInv[2] * xIp[0] - nInv[0] * xIp[2], nInv[0] * xIp[1] - nInv[1] * xIp[0]];
877
+ return { ascNodeEclipticDeg: ip.ascNodeEclipticDeg, nInv, xIp, yIp };
878
+ })();
879
+ /** The engine Earth-orbit normal of date, J2000 ecliptic frame. @param {number} year @returns {number[]} */
880
+ const earthOrbitNormalJ2000At = (year) => {
881
+ const s = oneSourceM.sampleAt(year);
882
+ return [s.orbitNormalX, s.orbitNormalY, Math.sqrt(Math.max(0, 1 - s.orbitNormalX * s.orbitNormalX - s.orbitNormalY * s.orbitNormalY))];
883
+ };
884
+ /** Earth's inclination of date to the model's invariable plane, degrees. @param {number} year @returns {number} */
885
+ const inclinationDeg = (year) => {
886
+ const nE = earthOrbitNormalJ2000At(year), nInv = invPlaneGeometry.nInv;
887
+ const d = nE[0] * nInv[0] + nE[1] * nInv[1] + nE[2] * nInv[2];
888
+ return Math.acos(Math.min(1, Math.max(-1, d))) / (Math.PI / 180);
889
+ };
890
+ /** Earth's ascending node of date on the invariable plane, S&S origin, degrees in [0, 360). @param {number} year @returns {number} */
891
+ const ascendingNodeDeg = (year) => {
892
+ const D2R = Math.PI / 180;
893
+ const { ascNodeEclipticDeg, nInv, xIp, yIp } = invPlaneGeometry;
894
+ const nE = earthOrbitNormalJ2000At(year);
895
+ let N = [nInv[1] * nE[2] - nInv[2] * nE[1], nInv[2] * nE[0] - nInv[0] * nE[2], nInv[0] * nE[1] - nInv[1] * nE[0]];
896
+ const L = Math.hypot(N[0], N[1], N[2]);
897
+ N = [N[0] / L, N[1] / L, N[2] / L];
898
+ const sFrameDeg = ((Math.atan2(N[0] * yIp[0] + N[1] * yIp[1] + N[2] * yIp[2],
899
+ N[0] * xIp[0] + N[1] * xIp[1] + N[2] * xIp[2]) / D2R + ascNodeEclipticDeg) % 360 + 360) % 360;
900
+ return convertNodeSFrameToEquatorOriginDeg(sFrameDeg, nodeOriginSSDeg());
901
+ };
902
+
896
903
  // ── Time axis: exact JD ↔ model-year conversion ───────────────────────────
897
904
  // The model's `year` inputs live on the SI axis (the axis the fits were
898
905
  // anchored on — tools/lib `_jdToSIyear`): linear in SI 86400-s days from the