@essrt/physics 4.0.0 → 4.1.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@essrt/physics",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "ESSRT (Expanding Solar System Resonance Theory) physics core \u2014 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
6
  "modelVersion": "v13.0",
@@ -32,6 +32,9 @@
32
32
  "./phase": "./src/phase/index.cjs",
33
33
  "./cardinal": "./src/cardinal/index.cjs",
34
34
  "./moon/ecc-channel": "./src/moon/ecc-channel.cjs",
35
+ "./moon/deep-ecc-channel": "./src/moon/deep-ecc-channel.cjs",
36
+ "./moon/deep-modes-artifact": "./src/moon/deep-modes-artifact.cjs",
37
+ "./earth/deep-orbital-history": "./src/earth/deep-orbital-history.cjs",
35
38
  "./moon/month-chain": "./src/moon/month-chain.cjs",
36
39
  "./chain-cycles": "./src/chain-cycles/index.cjs",
37
40
  "./moon/arguments": "./src/moon/arguments.cjs",
@@ -741,4 +741,13 @@ export declare const REFERENCE_DATA: {
741
741
  "max": number;
742
742
  };
743
743
  };
744
+ readonly planetSpinObserved: {
745
+ "marsSpinPrecessionArcsecPerYr": number;
746
+ "jupiterSpinPrecessionApproxArcsecPerYr": number;
747
+ "saturnSpinPrecessionPresentArcsecPerYr": number;
748
+ "saturnPresentToLongTermFraction": number;
749
+ "marsObliquityJ2000Deg": number;
750
+ "jupiterObliquityJ2000Deg": number;
751
+ "saturnObliquityJ2000Deg": number;
752
+ };
744
753
  };
@@ -14,6 +14,7 @@
14
14
  * moonGrailWilliams2014 target
15
15
  * giaCoxChaoPeltier target
16
16
  * obliquityChapront2002 target
17
+ * planetSpinObserved target
17
18
  * ascendingNodesSouamiSouchay target
18
19
  * laplaceLagrangeBounds target
19
20
  * jplEclipticInclinationTrends target
@@ -913,4 +914,13 @@ export const REFERENCE_DATA = Object.freeze({
913
914
  "max": 200
914
915
  }
915
916
  },
917
+ planetSpinObserved: {
918
+ "marsSpinPrecessionArcsecPerYr": -7.606,
919
+ "jupiterSpinPrecessionApproxArcsecPerYr": -2.8,
920
+ "saturnSpinPrecessionPresentArcsecPerYr": -0.45,
921
+ "saturnPresentToLongTermFraction": 0.68,
922
+ "marsObliquityJ2000Deg": 25.19,
923
+ "jupiterObliquityJ2000Deg": 3.13,
924
+ "saturnObliquityJ2000Deg": 26.73
925
+ },
916
926
  });
@@ -0,0 +1,190 @@
1
+ /**
2
+ * THE DEEP ORBITAL HISTORY FACTORY — the ONE home for the Stage-C hybrid
3
+ * mathematics (plan 02 §8, C-3): Earth's deep-time orbital quantities from
4
+ * the engine's own governed mode tables, and the obliquity hybrid
5
+ *
6
+ * ds/dt = α (ŝ·n̂)(ŝ×n̂), α = ψ̇_J2000 / cos ε₀
7
+ *
8
+ * with the orbit normal n̂(t) from an anchored ζ mode-sum and ψ̇_J2000 the
9
+ * injected engine-K anchor (the equinox-precession rate measured from the
10
+ * engine's own year lengths). ZERO fitted constants; the J2000 celestial
11
+ * pole sits at ecliptic longitude +90° (s₀ = (0, +sin ε₀, cos ε₀) — the
12
+ * −90° choice anti-correlates perfectly, the recorded convention catch).
13
+ *
14
+ * Consumers (each injecting its own certified surfaces, cross-engine
15
+ * matched): the Stage-C lab / verdict generator (both ζ tiers), the Node
16
+ * shim tools/lib/deep-orbital-history.js (the deep insolation extractor),
17
+ * and the browser's published ε surfaces (VFP chart, Earth-panel row) via
18
+ * the generated deep-modes embed. The ERA machinery (frame conversions,
19
+ * lunar D5, besselian, the scene's A-solve and Step 6b) stays on the
20
+ * certified fitted law — measured: the hybrid differs from it by 5″ rms in
21
+ * 1900–2100 / 19.5″ in 1600–2400, mostly hybrid-side there — the same
22
+ * certification split as e and ϖ.
23
+ *
24
+ * The climatic precession is the PHYSICAL of-date angle from the moving
25
+ * equinox γ = unit(ŝ×n̂) to the perihelion direction, measured in the orbit
26
+ * plane about n̂ — no linear-precession approximation at any epoch
27
+ * (validated: reproduces the J2000 ecliptic longitude and La2004's
28
+ * e·sin ϖ̃ exactly at t = 0).
29
+ */
30
+
31
+ 'use strict';
32
+
33
+ /**
34
+ * @param {{
35
+ * zModes: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
36
+ * zetaModes: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
37
+ * anchorE: number,
38
+ * anchorPeriEclipticDeg: number,
39
+ * anchorInclEclipticDeg: number,
40
+ * anchorAscNodeEclipticDeg: number,
41
+ * axialPrecessionYearsJ2000: number,
42
+ * obliquityJ2000Deg: number,
43
+ * }} deps — mode tables from the governed deep artifact (choose the ζ tier
44
+ * per consumer: era = its own 8-term extraction, deep = the 16-term
45
+ * table; NEVER a slice); anchors from the chain artifact's one home; the
46
+ * axial-precession years and ε₀ from the injecting engine's certified
47
+ * surfaces.
48
+ */
49
+ function createDeepOrbitalHistory({
50
+ zModes, zetaModes,
51
+ anchorE, anchorPeriEclipticDeg, anchorInclEclipticDeg, anchorAscNodeEclipticDeg,
52
+ axialPrecessionYearsJ2000, obliquityJ2000Deg,
53
+ }) {
54
+ const D2R = Math.PI / 180, R2D = 180 / Math.PI;
55
+
56
+ const mkAnchored = (
57
+ /** @type {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} */ modes,
58
+ /** @type {[number, number]} */ anchor,
59
+ ) => {
60
+ const sum = (/** @type {number} */ t) => {
61
+ let re = 0, im = 0;
62
+ for (const m of modes) {
63
+ const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
64
+ re += m.re * c - m.im * s;
65
+ im += m.re * s + m.im * c;
66
+ }
67
+ return [re, im];
68
+ };
69
+ const s0 = sum(0), R = [anchor[0] - s0[0], anchor[1] - s0[1]];
70
+ return (/** @type {number} */ t) => { const [x, y] = sum(t); return [x + R[0], y + R[1]]; };
71
+ };
72
+ const s2h = Math.sin(anchorInclEclipticDeg / 2 * D2R);
73
+ const zetaAt = mkAnchored(zetaModes,
74
+ [s2h * Math.cos(anchorAscNodeEclipticDeg * D2R), s2h * Math.sin(anchorAscNodeEclipticDeg * D2R)]);
75
+ const zAt = mkAnchored(zModes,
76
+ [anchorE * Math.cos(anchorPeriEclipticDeg * D2R), anchorE * Math.sin(anchorPeriEclipticDeg * D2R)]);
77
+
78
+ /** @param {number} t */
79
+ const inclNode = (t) => {
80
+ const [q, p] = zetaAt(t);
81
+ return { i: 2 * Math.asin(Math.min(1, Math.hypot(q, p))), Om: Math.atan2(p, q) };
82
+ };
83
+ /** @param {number} t */
84
+ const orbitNormal = (t) => {
85
+ const { i, Om } = inclNode(t);
86
+ return [Math.sin(i) * Math.sin(Om), -Math.sin(i) * Math.cos(Om), Math.cos(i)];
87
+ };
88
+
89
+ const psiDot = (2 * Math.PI) / axialPrecessionYearsJ2000;
90
+ const EPS0 = obliquityJ2000Deg * D2R;
91
+ const ALPHA = psiDot / Math.cos(EPS0);
92
+
93
+ const cross = (/** @type {number[]} */ a, /** @type {number[]} */ b) =>
94
+ [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
95
+ const dot = (/** @type {number[]} */ a, /** @type {number[]} */ b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
96
+ const deriv = (/** @type {number[]} */ s, /** @type {number} */ t) => {
97
+ const n = orbitNormal(t);
98
+ const k = ALPHA * dot(s, n);
99
+ const c = cross(s, n);
100
+ return [k * c[0], k * c[1], k * c[2]];
101
+ };
102
+ const rk4 = (/** @type {number[]} */ s, /** @type {number} */ t, /** @type {number} */ h) => {
103
+ const k1 = deriv(s, t);
104
+ const k2 = deriv([s[0] + h / 2 * k1[0], s[1] + h / 2 * k1[1], s[2] + h / 2 * k1[2]], t + h / 2);
105
+ const k3 = deriv([s[0] + h / 2 * k2[0], s[1] + h / 2 * k2[1], s[2] + h / 2 * k2[2]], t + h / 2);
106
+ const k4 = deriv([s[0] + h * k3[0], s[1] + h * k3[1], s[2] + h * k3[2]], t + h);
107
+ const o = [0, 1, 2].map((i) => s[i] + h / 6 * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
108
+ const r = Math.hypot(o[0], o[1], o[2]);
109
+ return [o[0] / r, o[1] / r, o[2] / r];
110
+ };
111
+
112
+ /** One quantity bundle at time t (years from J2000) from spin axis s. */
113
+ function sampleAt(/** @type {number[]} */ s, /** @type {number} */ t) {
114
+ const n = orbitNormal(t);
115
+ const { i, Om } = inclNode(t);
116
+ const [zx, zy] = zAt(t);
117
+ const e = Math.hypot(zx, zy);
118
+ const w = Math.atan2(zy, zx) - Om;
119
+ const ph = [
120
+ Math.cos(Om) * Math.cos(w) - Math.sin(Om) * Math.sin(w) * Math.cos(i),
121
+ Math.sin(Om) * Math.cos(w) + Math.cos(Om) * Math.sin(w) * Math.cos(i),
122
+ Math.sin(w) * Math.sin(i),
123
+ ];
124
+ const g = cross(s, n);
125
+ const gn = Math.hypot(g[0], g[1], g[2]);
126
+ const gu = [g[0] / gn, g[1] / gn, g[2] / gn];
127
+ const cosA = dot(gu, ph);
128
+ const sinA = dot(n, cross(gu, ph));
129
+ const periOfDateDeg = ((Math.atan2(sinA, cosA) * R2D) % 360 + 360) % 360;
130
+ return {
131
+ epsDeg: Math.acos(Math.max(-1, Math.min(1, dot(s, n)))) * R2D,
132
+ e,
133
+ periOfDateDeg,
134
+ eSinPeri: e * Math.sin(periOfDateDeg * D2R),
135
+ eCosPeri: e * Math.cos(periOfDateDeg * D2R),
136
+ inclEclDeg: i * R2D,
137
+ };
138
+ }
139
+
140
+ /**
141
+ * Integrate once over [min(t0,t1,0), max(t0,t1,0)] and return a sampler
142
+ * on a stepYr grid (linear interpolation; angles interpolated on the
143
+ * wrapped difference). t in years from J2000, negative = past.
144
+ * @param {number} t0Yr @param {number} t1Yr @param {number} stepYr
145
+ */
146
+ function build(t0Yr, t1Yr, stepYr) {
147
+ const tMin = Math.min(t0Yr, t1Yr, 0), tMax = Math.max(t0Yr, t1Yr, 0);
148
+ const grid = new Map();
149
+ const S0 = [0, Math.sin(EPS0), Math.cos(EPS0)];
150
+ const H_STEP = 5;
151
+ for (const dir of [-1, +1]) {
152
+ let s = S0, t = 0;
153
+ grid.set(0, sampleAt(s, 0));
154
+ const end = dir < 0 ? tMin : tMax;
155
+ while (dir < 0 ? t > end : t < end) {
156
+ s = rk4(s, t, dir * H_STEP);
157
+ t += dir * H_STEP;
158
+ // Store ONLY at true step multiples: an end-of-range sample under a
159
+ // ROUNDED key collides with a real grid node (measured during C-3:
160
+ // build(+200, …, 1000) stored ε(+200) under key 0, clobbering the
161
+ // t = 0 sample by 94″ — the verdict generator's rms caught it).
162
+ // Partial edge segments are covered by at()'s a-side fallback.
163
+ if (Math.abs(t % stepYr) < H_STEP / 2) grid.set(Math.round(t / stepYr) * stepYr, sampleAt(s, t));
164
+ }
165
+ }
166
+ return {
167
+ /** @param {number} tYr */
168
+ at(tYr) {
169
+ const k0 = Math.floor(tYr / stepYr) * stepYr, k1 = k0 + stepYr;
170
+ const a = grid.get(k0), b = grid.get(k1) ?? a;
171
+ if (!a) throw new Error(`deep-orbital-history: ${tYr} outside the built range`);
172
+ const f = (tYr - k0) / stepYr;
173
+ const lerp = (/** @type {number} */ x, /** @type {number} */ y) => x + (y - x) * f;
174
+ const dAng = (/** @type {number} */ x, /** @type {number} */ y) => x + (((y - x + 540) % 360) - 180) * f;
175
+ return {
176
+ epsDeg: lerp(a.epsDeg, b.epsDeg),
177
+ e: lerp(a.e, b.e),
178
+ periOfDateDeg: ((dAng(a.periOfDateDeg, b.periOfDateDeg) % 360) + 360) % 360,
179
+ eSinPeri: lerp(a.eSinPeri, b.eSinPeri),
180
+ eCosPeri: lerp(a.eCosPeri, b.eCosPeri),
181
+ inclEclDeg: lerp(a.inclEclDeg, b.inclEclDeg),
182
+ };
183
+ },
184
+ };
185
+ }
186
+
187
+ return { build, alphaArcsecPerYr: ALPHA * R2D * 3600 };
188
+ }
189
+
190
+ module.exports = { createDeepOrbitalHistory };
package/src/index.js CHANGED
@@ -121,6 +121,13 @@ export * as planetOrbitChain from './planets/orbit-chain.cjs';
121
121
  // governed artifact; the browser flag path consumes exactly these).
122
122
  export { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear, computeHeliocentricEclipticFromElements, computePoissonArgRad, computeOsculatingElements, solveKeplerRad, ANCHOR_EPOCH_YEAR, ANCHOR_EPOCH_JD } from './planets/keplerian-chain.cjs';
123
123
  export { CHAIN_ARTIFACT, CHAIN_ARTIFACT_HASH } from './planets/chain-artifact.js';
124
+ // Engine-switch Stage B, T5d-(d): the deep-time Earth-z channel (the deep
125
+ // lunar-chain modulation rides it; era consumers stay on the H/3 channel).
126
+ export { createDeepEccChannel } from './moon/deep-ecc-channel.cjs';
127
+ export { DEEP_MODES_ARTIFACT, DEEP_MODES_ARTIFACT_HASH } from './moon/deep-modes-artifact.cjs';
128
+ // Stage C-3: the ONE home of the obliquity-hybrid / deep-orbital-history
129
+ // mathematics (published-ε surfaces + the deep insolation features).
130
+ export { createDeepOrbitalHistory } from './earth/deep-orbital-history.cjs';
124
131
  export { createPredictivePrecession, calcPlanetPerihelionLongDeg } from './planets/predict.cjs';
125
132
  // L10 — the composition front door: one law set, N body records. Thin by
126
133
  // design; engines keep their direct call sites (see planets/model.cjs).
package/src/model.js CHANGED
@@ -27,6 +27,8 @@ import { createDeepTimeLod } from './deltat/deep-time.cjs';
27
27
  import { createMoonRecessionHistory, createSolarChannelBudget } from './deltat/recession-history.cjs';
28
28
  import { evalClimateL1OrbitalPermil } from './climate/l1-orbital.cjs';
29
29
  import { createMoonEccChannel } from './moon/ecc-channel.cjs';
30
+ import { createDeepEccChannel } from './moon/deep-ecc-channel.cjs';
31
+ import { DEEP_MODES_ARTIFACT } from './moon/deep-modes-artifact.cjs';
30
32
  import { createMoonMonthChain } from './moon/month-chain.cjs';
31
33
  import { createChainCycleIntegrator } from './chain-cycles/index.cjs';
32
34
  import { createMoonArguments, jdToDecimalYear } from './moon/arguments.cjs';
@@ -333,9 +335,13 @@ export function assembleModel(C, F, laws = {}) {
333
335
  // measured, the H/16 law's present ė (−0.84e-5/cy) is 5× below the
334
336
  // observed −4.20e-5 while this law reads −4.31e-5 (Phase-0 record:
335
337
  // tools/explore/fq7s-h3-law-candidate.mjs; JPL Sun 1.49″, registry 0.80″,
336
- // syzygy 3.72″). Consumers: the eclipse Sun (equation of centre), the
337
- // besselian Sun distance, the Moon channel (E-factor, perigee/node ),
338
- // and the cardinal-point braid — one eccentricity everywhere.
338
+ // syzygy 3.72″). Consumers (engine-switch decision (ii) restatement,
339
+ // plan 02 §8): the eclipse Sun (equation of centre), the besselian Sun
340
+ // distance and the cardinal-point braid — the CLOCK-side machinery. The
341
+ // LUNAR chain (E-factor, perigee/node modulation/T², argument Δe² and
342
+ // of-date rates) rides the ONE deep e (deep-ecc-channel.cjs — the
343
+ // engine's own ±10-Myr z-vector); this H/3 line is its epoch-local
344
+ // tangent (E18), agreeing within 4.2e-5 across the historical era.
339
345
  // ONE implementation for all three runtimes: moon/ecc-channel.cjs (the
340
346
  // Node engine's deep-time.js and the browser's script.js instantiate the
341
347
  // same channel with the same inputs). Its phase counter runs from J2000
@@ -349,6 +355,14 @@ export function assembleModel(C, F, laws = {}) {
349
355
  inclinationCycleAnchorDeg: C.earthOrbital.earthInclinationCycleAnchor,
350
356
  eccentricityJ2000: C.earthOrbital.earthEccentricityJ2000,
351
357
  });
358
+ // Engine-switch decision (ii) (plan 02 §8): the ONE deep e — the engine's
359
+ // own ±10-Myr mode table, anchored form — feeds the ENTIRE lunar chain
360
+ // (modulation, cycle counts, arguments eccAt/channelIntegral, E-factor).
361
+ // The Sun/clock machinery (eclipse Sun EoC, besselian Sun distance,
362
+ // cardinal braid) stays on the H/3 channel above — a certification
363
+ // split, not a physics one (the two agree within 4.2e-5 in-era). The
364
+ // laws hook deliberately does NOT reach this channel.
365
+ const deepEcc = createDeepEccChannel(DEEP_MODES_ARTIFACT);
352
366
  /** @param {number} year @returns {number} */
353
367
  const eccentricityAt = laws.eccentricityAt ?? ((year) => moonEcc.eccAt(year - 2000));
354
368
  /** de/dyear of the one law — the cardinal braid's equation-of-centre
@@ -682,7 +696,13 @@ export function assembleModel(C, F, laws = {}) {
682
696
  meanLodSecondsAtAge: /** @param {number} tMa */ (tMa) => deepLod.lodSecondsAtAge(tMa),
683
697
  meanSiderealYearSecondsAtAge: /** @param {number} tMa */ (tMa) => deepLod.siderealYearSecondsAtAge(tMa),
684
698
  meanHAtAge: /** @param {number} tMa */ (tMa) => deepLod.hAtAge(tMa),
685
- modulation: /** @param {number} tMa @param {number} s */ (tMa, s) => moonEcc.modulation(tMa, s),
699
+ // Decision (ii) (owner-approved MODEL CHANGE, plan 02 §8): the whole
700
+ // lunar chain — this modulation, the integrated cycle counts it
701
+ // drives, the arguments' eccAt/channelIntegral and the E-factor —
702
+ // reads the ONE deep e. The era shift in the ancient eclipse stack is
703
+ // accepted and rebaselined with its explanation (deep e is
704
+ // La2004-corroborated in-era).
705
+ modulation: /** @param {number} tMa @param {number} s */ (tMa, s) => deepEcc.modulation(tMa, s),
686
706
  distanceMetresAtAge: moonDistanceMetresAtAge,
687
707
  },
688
708
  });
@@ -757,11 +777,12 @@ export function assembleModel(C, F, laws = {}) {
757
777
  eccentricityDotDotJ2000: C.earthOrbital.earthEccentricityDotDotJ2000,
758
778
  elpEarthFigureJ2ArcsecPerCy2: C.moonMeeus.elpW1T2Decomposition_arcsecPerCy2.earthFigureJ2,
759
779
  elpGeneralPrecessionPA_T2ArcsecPerCy2: C.moonMeeus.elpW1T2Decomposition_arcsecPerCy2.generalPrecessionPA_T2_Lieske1976,
760
- eccE0: moonEcc.e0,
780
+ // Decision (ii): the lunar chain reads ONE deep e end to end
781
+ eccE0: deepEcc.e0,
761
782
  },
762
783
  fns: {
763
- eccAt: /** @param {number} tYr */ (tYr) => moonEcc.eccAt(tYr),
764
- channelIntegral: /** @param {number} T @param {number} s */ (T, s) => moonEcc.channelIntegral(T, s),
784
+ eccAt: /** @param {number} tYr */ (tYr) => deepEcc.eccAt(tYr),
785
+ channelIntegral: /** @param {number} T @param {number} s */ (T, s) => deepEcc.channelIntegral(T, s),
765
786
  computeObliquityEarth: obliquitySnapshotDeg,
766
787
  jdToSIyear: yearFromJD,
767
788
  tropicalOrbitsBetween: mcTropical,
@@ -809,10 +830,10 @@ export function assembleModel(C, F, laws = {}) {
809
830
  return Number.isFinite(dT) ? dT : 0;
810
831
  };
811
832
 
812
- // Bounded Meeus E-factor from the H/3 line (framework-native branch only;
813
- // the pure-Meeus polynomial A/B branch stays engine-local)
833
+ // Bounded Meeus E-factor from the ONE deep e (decision (ii); the
834
+ // pure-Meeus polynomial A/B branch stays engine-local)
814
835
  /** @param {number} dDays @returns {number} */
815
- const fwEFactor = (dDays) => moonEcc.eFactorAt(dDays / C.foundational.inputmeanlengthsolaryearindays);
836
+ const fwEFactor = (dDays) => deepEcc.eFactorAt(dDays / C.foundational.inputmeanlengthsolaryearindays);
816
837
 
817
838
  // D2 derived additional-argument rates (deg/cy, J2000 8H-lattice months;
818
839
  // record: tools/explore/derive-a1a2a3.js)
@@ -0,0 +1,132 @@
1
+ /**
2
+ * The DEEP Earth-eccentricity channel — engine-switch Stage B, the T5d-(d)
3
+ * decision (ii) (plan 02 §8, owner-approved MODEL CHANGE, pre-registered
4
+ * acceptance in the same record).
5
+ *
6
+ * Evaluates Earth's e(t) from the engine's own ±10-Myr NAFF mode table
7
+ * (data/nbody-deep-secular-modes.json, embedded verbatim by generate.mjs as
8
+ * deep-modes-artifact.cjs) in the ANCHORED form the era chain also uses:
9
+ *
10
+ * z(t) = Σ (re + i·im)·e^{iωt} + (z_J2000 − Σ(0)), e = |z|
11
+ *
12
+ * — the constant remainder pins the unresolved short/ultra-long content at
13
+ * the JPL J2000 seed anchor, so e(J2000) is exact by construction.
14
+ *
15
+ * DOMAIN (decision (ii), proper physics — no mixed device): the ENTIRE
16
+ * lunar chain reads THIS channel — eccAt (the Δe² argument terms),
17
+ * channelIntegral (perigee/node of-date rates), modulation (the
18
+ * month/precession chain and its integrated cycle counts), eFactorAt (the
19
+ * Meeus E-factor). The Sun/clock machinery (eclipse Sun equation of
20
+ * centre, besselian Sun distance, cardinal braid) stays on the H/3 law
21
+ * (moon/ecc-channel.cjs) — a CERTIFICATION split, not a physics one: the
22
+ * two e's agree within 4.2e-5 wherever the domains overlap, and the H/3
23
+ * line keeps its E18 role as the epoch-local tangent inside the fitted
24
+ * clock stack.
25
+ *
26
+ * MEASURED at adoption (banked in the plan record): vs the H/3 law the
27
+ * attractor-mean modulation shifts are +2,526 ppm (perigee channel,
28
+ * s = 2.407) and +1,067 ppm (node, s = 1.018) — month/LOD shifts of
29
+ * ~10–25 ppm class, all 41 paleo anchors in bands; the ancient eclipse
30
+ * stack's cycle counts shift (χ² IMPROVES — recorded with its
31
+ * explanation: this e is La2004-corroborated in-era, 3× closer than the
32
+ * H/3 line; theory-corroborated, never tuned). Beyond ~5 Myr the table is
33
+ * spectrum-class (phases decohere) — the quasi-periodic ATTRACTOR (mean e
34
+ * and the 405-kyr-class beat structure) is the claim, never a pointwise
35
+ * ephemeris.
36
+ *
37
+ * LOAD-BEARING conventions (carried VERBATIM from the era channel —
38
+ * moon/ecc-channel.cjs — so the certified numerics match):
39
+ * - channelIntegral uses composite Simpson with step ≤ ~4,000 yr
40
+ * (N ≥ 2, even);
41
+ * - modulation(tMa, s) takes age in Myr, positive = past, ≡ 1 at J2000;
42
+ * - eFactorAt(tYr) = eccAt(tYr) / e0, ≡ 1 at J2000.
43
+ */
44
+
45
+ 'use strict';
46
+
47
+ /**
48
+ * @param {{
49
+ * earthZ: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
50
+ * anchorE: number,
51
+ * anchorPeriEclipticDeg: number,
52
+ * }} artifact — the embedded deep-modes artifact (earth z-modes + the J2000
53
+ * anchor pair joined from the chain artifact's one home).
54
+ */
55
+ function createDeepEccChannel({ earthZ, anchorE, anchorPeriEclipticDeg }) {
56
+ const D2R = Math.PI / 180;
57
+ const zA = [anchorE * Math.cos(anchorPeriEclipticDeg * D2R), anchorE * Math.sin(anchorPeriEclipticDeg * D2R)];
58
+ /** @param {number} tYr @returns {[number, number]} */
59
+ const modeSum = (tYr) => {
60
+ let re = 0, im = 0;
61
+ for (const m of earthZ) {
62
+ const c = Math.cos(m.omegaRadPerYr * tYr), s = Math.sin(m.omegaRadPerYr * tYr);
63
+ re += m.re * c - m.im * s;
64
+ im += m.re * s + m.im * c;
65
+ }
66
+ return [re, im];
67
+ };
68
+ const s0 = modeSum(0);
69
+ const R = [zA[0] - s0[0], zA[1] - s0[1]]; // the constant remainder
70
+
71
+ /** Earth's e at tYr years from J2000 (negative = past).
72
+ * @param {number} tYr @returns {number} */
73
+ function eccAt(tYr) {
74
+ const [x, y] = modeSum(tYr);
75
+ return Math.hypot(x + R[0], y + R[1]);
76
+ }
77
+
78
+ /** de/dyear — analytic from the mode sum: d|z|/dt = (z·ż)/|z|.
79
+ * @param {number} tYr @returns {number} */
80
+ function eccRateAt(tYr) {
81
+ const [x0, y0] = modeSum(tYr);
82
+ const x = x0 + R[0], y = y0 + R[1];
83
+ let dx = 0, dy = 0;
84
+ for (const m of earthZ) {
85
+ const c = Math.cos(m.omegaRadPerYr * tYr), s = Math.sin(m.omegaRadPerYr * tYr);
86
+ dx += m.omegaRadPerYr * (-m.re * s - m.im * c);
87
+ dy += m.omegaRadPerYr * (m.re * c - m.im * s);
88
+ }
89
+ const r = Math.hypot(x, y);
90
+ return r === 0 ? 0 : (x * dx + y * dy) / r;
91
+ }
92
+
93
+ const e0 = eccAt(0); // ≡ anchorE by construction
94
+ const g0 = Math.pow(1 - e0 * e0, -1.5);
95
+
96
+ /** [g(e(t))/g₀]^s — the perigee/node rate modulation, ≡ 1 at J2000.
97
+ * tMa is age in Myr (positive = past, the deep-time chain convention).
98
+ * @param {number} tMa @param {number} s @returns {number} */
99
+ function modulation(tMa, s) {
100
+ if (tMa === 0) return 1;
101
+ const e = eccAt(-tMa * 1e6);
102
+ return Math.pow(Math.pow(1 - e * e, -1.5) / g0, s);
103
+ }
104
+
105
+ /** ∫₀ᵀ [(g(e(t′))/g₀)^s − 1] dt′ in Julian centuries — the phase-aware
106
+ * channel-rate integral. Composite Simpson, step ≤ ~4 kyr (the era
107
+ * channel's certified discretization, verbatim).
108
+ * @param {number} T @param {number} s @returns {number} */
109
+ function channelIntegral(T, s) {
110
+ if (T === 0) return 0;
111
+ /** @param {number} t */
112
+ const f = (t) => {
113
+ const e = eccAt(t * 100); // t in cy → years
114
+ return Math.pow(Math.pow(1 - e * e, -1.5) / g0, s) - 1;
115
+ };
116
+ const N = Math.max(2, 2 * Math.ceil(Math.abs(T) * 100 / 8000));
117
+ const h = T / N;
118
+ let sum = f(0) + f(T);
119
+ for (let i = 1; i < N; i++) sum += f(i * h) * (i % 2 ? 4 : 2);
120
+ return sum * h / 3;
121
+ }
122
+
123
+ /** Bounded Meeus E-factor: E ≡ e(t)/e(J2000), ≡ 1 at J2000.
124
+ * @param {number} tYr @returns {number} */
125
+ function eFactorAt(tYr) {
126
+ return eccAt(tYr) / e0;
127
+ }
128
+
129
+ return { eccAt, eccRateAt, modulation, channelIntegral, eFactorAt, e0, g0 };
130
+ }
131
+
132
+ module.exports = { createDeepEccChannel };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * GENERATED — do not edit. Regenerate:
3
+ * node tools/constants/generate.mjs --write
4
+ *
5
+ * Source: data/nbody-deep-secular-modes.json (the governed deep-time
6
+ * Earth-z mode table, engine-switch Stage B), earth z-modes + verdict
7
+ * emitted VERBATIM, plus the J2000 anchor pair (e, ϖ) joined from
8
+ * data/nbody-secular-frequencies.json j2000AnchorElements.earth — the
9
+ * anchor's ONE home. Two gates guard the chain: check:artifacts pins
10
+ * artifact ↔ engine; generate.mjs check mode pins this embed ↔ artifact.
11
+ * CJS because the lunar-chain consumers are CommonJS modules.
12
+ */
13
+ 'use strict';
14
+
15
+ const DEEP_MODES_ARTIFACT_HASH = "b74be2d9b00a3460";
16
+
17
+ const DEEP_MODES_ARTIFACT = Object.freeze({"meta":{"integrator":"wh","order":2,"dtDays":2,"spanYears":20000000,"sampleDays":20000,"gr":true,"seed":"JPL Horizons J2000 heliocentric state vectors (tools/explore/j2000-state.mjs, the one home)","masses":"DE440 mass ratios (astro-reference physicalConstants)","runCommand":"node tools/explore/lattice-long-window-test.mjs years=20000000 integrator=wh dt=2 order=2 gr=1 frame=both sample=20000","dumpFile":"tools/explore/lattice-long-window-ecliptic-20000000-gr.local.json (untracked, 337 MB)","dumpSha256":"c6f37b93f8f53c5b72d9e2935085145820d384ed61ecdf69f3831895d5f0a516","conservationMaxDE":1.3523274883097007e-8,"decimation":4,"naffTerms":18,"naffZetaTerms":16,"naffZetaTermsEra":8,"frame":"ecliptic-J2000 (z-modes for the lunar-chain e; ζ-modes for the Stage-C obliquity hybrid — the invariable-frame ζ table remains unbanked, no consumer)","laskarRef":"Laskar, J. et al. (2004), A&A 428, 261–285, Table 3 (theory reference labels)"},"verdict":{"strongestBeatPeriodKyr":409.398962153882,"strongestBeatArcsecPerYr":3.165616232101899,"la2004BeatPeriodKyr":405.6972922210049,"rockMetronomeKyr":405.6,"companion124Kyr":123.63439229002236,"companion95Kyr":94.95801992141148,"earthLeadingModesArcsecPerYr":[4.257339363798321,7.422955595900221,17.905475677851488,17.35600814229943],"topBeatLines":[{"periodKyr":409.398962153882,"productAmp":0.0003189871275662614},{"periodKyr":94.95801992141148,"productAmp":0.00023593726318903166},{"periodKyr":123.63439229002236,"productAmp":0.0002021269449318684},{"periodKyr":98.94135212634195,"productAmp":0.0001820123713850866},{"periodKyr":130.4734867701679,"productAmp":0.00015592960633097004},{"periodKyr":2358.6470831218417,"productAmp":0.00011533256795834209},{"periodKyr":974.251698194696,"productAmp":0.00007391281237249426},{"periodKyr":706.1267630803258,"productAmp":0.00006332094707822819}],"note":"g5 matches La2004 to 0.0002 ″/yr; the beat gap vs 405.6 is g2 (chaotic-diffusion window sensitivity + omitted separate-Moon/asteroid terms) — the anatomy is the plan’s Stage-B record."},"earthZ":[{"omegaRadPerYr":0.000020640163686955943,"re":0.01663782532735386,"im":0.009773828910268845},{"omegaRadPerYr":0.00003598750427161015,"re":-0.0155511555977695,"im":-0.005606883657279738},{"omegaRadPerYr":0.00008680819575396443,"re":-0.011017310146969267,"im":0.005302931248387234},{"omegaRadPerYr":0.00008414430196835267,"re":0.005902460235142885,"im":-0.0073575521441138925},{"omegaRadPerYr":0.000027089406032463197,"re":0.0003820712762735637,"im":0.00381132243985138},{"omegaRadPerYr":0.00008287265957255809,"re":0.0018740756883102302,"im":0.0007570047078217853},{"omegaRadPerYr":0.00008556055947193001,"re":0.00065046714460136,"im":0.001636722269192129},{"omegaRadPerYr":0.00003343872861356042,"re":-0.0015906877043739744,"im":0.0008131867314299489},{"omegaRadPerYr":0.00008733249835491452,"re":0.0019695845162428804,"im":0.0007638996859228755},{"omegaRadPerYr":0.00008624160326238742,"re":-0.0007912287558015328,"im":0.0008454083667608703},{"omegaRadPerYr":0.00013693637603446235,"re":-0.00091728504412424,"im":0.0011947455784994275},{"omegaRadPerYr":0.00008149221104720623,"re":-0.0002919323858022318,"im":0.0013378769276789224},{"omegaRadPerYr":0.000035340366616489944,"re":-0.0014017009332458236,"im":-0.0005418283702703829},{"omegaRadPerYr":0.00003411910644328693,"re":0.0009644062512081837,"im":-0.0009278208477004621},{"omegaRadPerYr":0.000026443547751027787,"re":-0.0003484265086069058,"im":-0.0019049634588757702},{"omegaRadPerYr":0.00008946536777652535,"re":-0.0010363626781434278,"im":-0.00021237189770655706},{"omegaRadPerYr":0.000027681653760243513,"re":0.00026309559235420505,"im":0.0013827244513428105},{"omegaRadPerYr":0.00003665339440166644,"re":0.001341581161662452,"im":0.00035305205249495507}],"earthZeta":[{"omegaRadPerYr":-2.96732779276946e-14,"re":-0.004153530797421736,"im":0.013136287139943213},{"omegaRadPerYr":-0.00009139185627510659,"re":-0.0039341668744113665,"im":-0.007077440344808186},{"omegaRadPerYr":-0.000027083329194200705,"re":0.0041703974742109,"im":0.0016342020564862083},{"omegaRadPerYr":-0.00008606223132085272,"re":0.0015441443378585364,"im":-0.0036871518361985415},{"omegaRadPerYr":-0.00003413935334637193,"re":-0.002956817542124509,"im":0.0024359440436811054},{"omegaRadPerYr":-0.00008872604497912732,"re":-0.00013216158559522037,"im":-0.002797304033559708},{"omegaRadPerYr":-0.00003326020694677573,"re":0.0008627085184454156,"im":-0.0008468691172706413},{"omegaRadPerYr":-0.00003470927143831441,"re":0.0013226438289662852,"im":-0.0011121945465339342},{"omegaRadPerYr":-0.00009406049953471362,"re":0.001297329508193755,"im":0.0008926331980509192},{"omegaRadPerYr":-0.00002648259433928881,"re":0.001695647505347929,"im":0.0006707872920285527},{"omegaRadPerYr":-0.00012773804995598164,"re":-0.0008156188441322624,"im":0.0010583300732716742},{"omegaRadPerYr":-0.00003267570575865712,"re":0.00028878599128559593,"im":-0.0004498471691632459},{"omegaRadPerYr":-0.000033725843136033775,"re":0.0012152922715564112,"im":-0.0007872735440399818},{"omegaRadPerYr":-0.000014507526525427572,"re":-0.00064166716018201,"im":0.0005786259131500737},{"omegaRadPerYr":-0.00009265988888533535,"re":-0.0005654435501795496,"im":0.00014913577755089046},{"omegaRadPerYr":-0.000003353112962211696,"re":0.0006060116994915085,"im":0.00025189133351366343}],"earthZetaEra":[{"omegaRadPerYr":-2.96732779276946e-14,"re":-0.0041400895842324354,"im":0.01314865914923023},{"omegaRadPerYr":-0.00009139185627510659,"re":-0.0038874970989988566,"im":-0.0070425256250290546},{"omegaRadPerYr":-0.000027083329194200705,"re":0.004075700185805294,"im":0.0016137774467260707},{"omegaRadPerYr":-0.00008606223132085272,"re":0.0015261120191598105,"im":-0.0036992031256430353},{"omegaRadPerYr":-0.00003413935334637193,"re":-0.0031492966403078486,"im":0.002570649693650614},{"omegaRadPerYr":-0.00008872604497912732,"re":-0.00014686941549255626,"im":-0.0027917154781614112},{"omegaRadPerYr":-0.00003326020694677573,"re":0.0005693304183459907,"im":-0.0006693278314130071},{"omegaRadPerYr":-0.00003470927143831441,"re":0.0012956912361530007,"im":-0.0010932966486614268}],"anchorE":0.016702435651957018,"anchorPeriEclipticDeg":462.9179213996577,"anchorInclEclipticDeg":0.00010345820355474172,"anchorAscNodeEclipticDeg":140.29217988414328});
18
+
19
+ module.exports = { DEEP_MODES_ARTIFACT, DEEP_MODES_ARTIFACT_HASH };
@@ -8,14 +8,17 @@
8
8
  * max. The observed J2000 e (−0.86%), ė (+1.7%) and the sign of ë are
9
9
  * PREDICTIONS of this line, not inputs.
10
10
  *
11
- * ONE law for the eclipse chain (FQ-7-Sun option C-small, doc 66 §5): the
12
- * eclipse Sun's equation of centre rides this same H/3 line (anchored at
13
- * its J2000 value, model.js sunEccentricityAt) eccentricity is
14
- * frame-invariant and may carry only fixed-frame lattice periods; the
15
- * H/16 perihelion cycle is the H/3 rotation seen from the H/13 equinox
16
- * (13 + 3 = 16) and belongs to ϖ, not e (doc 108). Only the
17
- * cardinal-point/deep-time path still keeps the H/16 law (`cardinal`'s
18
- * injected eccentricityAt) a recorded, not yet resolved, split.
11
+ * DOMAIN (engine-switch decision (ii) restatement, plan 02 §8): this H/3
12
+ * line is the CLOCK-side e — the eclipse Sun's equation of centre (FQ-7-Sun
13
+ * option C-small, doc 66 §5), the besselian Sun distance, the cardinal
14
+ * braid and the scene machinery ride it. The LUNAR chain (E-factor,
15
+ * modulation, channelIntegral, argument Δe²) rides the ONE deep e
16
+ * (deep-ecc-channel.cjs the engine's own ±10-Myr z-vector); the two
17
+ * agree within 4.2e-5 across the historical era, and this line keeps its
18
+ * E18 role as the epoch-local tangent. Eccentricity remains
19
+ * frame-invariant (fixed-frame periods only); the H/16 perihelion cycle
20
+ * (the H/3 rotation seen from the H/13 equinox, 13 + 3 = 16) belongs to
21
+ * ϖ, not e (doc 108).
19
22
  *
20
23
  * Extracted VERBATIM from src/script.js (_FW_ECC, _fwEarthEcc,
21
24
  * _eCompModulation, _fwChannelIntegral, the framework branch of _fwEFactor),