@essrt/physics 4.8.0 → 5.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.
Files changed (62) hide show
  1. package/README.md +4 -0
  2. package/package.json +42 -39
  3. package/src/climate/l1-orbital.cjs +76 -5
  4. package/src/constants/coefficients.d.ts +678 -0
  5. package/src/constants/coefficients.js +4 -4
  6. package/src/constants/generated.d.ts +42 -41
  7. package/src/constants/generated.js +6 -5
  8. package/src/deltat/deep-time.cjs +69 -2
  9. package/src/earth/deep-orbital-history.cjs +6 -5
  10. package/src/earth/precession-composed.cjs +120 -0
  11. package/src/earth/year-lengths.cjs +12 -1
  12. package/src/index.js +6 -2
  13. package/src/layer0/derive-params.js +21 -4
  14. package/src/layer0/index.js +35 -4
  15. package/src/model.js +176 -33
  16. package/src/planets/chain-artifact.js +2 -2
  17. package/types/cardinal/index.d.cts +80 -0
  18. package/types/cardinal/one-source-structure.d.cts +35 -0
  19. package/types/chain-cycles/index.d.cts +33 -0
  20. package/types/climate/l1-orbital.d.cts +103 -0
  21. package/types/constants/coefficients.d.ts +678 -0
  22. package/types/constants/generated.d.ts +754 -0
  23. package/types/constants/index.d.ts +2 -0
  24. package/types/deltat/cycles.d.cts +72 -0
  25. package/types/deltat/deep-time.d.cts +135 -0
  26. package/types/deltat/historical.d.cts +8 -0
  27. package/types/deltat/recession-history.d.cts +80 -0
  28. package/types/earth/deep-orbital-history.d.cts +77 -0
  29. package/types/earth/precession-composed.d.cts +59 -0
  30. package/types/earth/sidereal-channel-artifact.d.cts +12 -0
  31. package/types/earth/sidereal-year-channel.d.cts +38 -0
  32. package/types/earth/year-lengths.d.cts +67 -0
  33. package/types/eclipse/besselian.d.cts +101 -0
  34. package/types/eclipse/finders.d.cts +116 -0
  35. package/types/eclipse/sun-planetary-completion.d.cts +39 -0
  36. package/types/index.d.ts +78 -0
  37. package/types/layer0/derive-params.d.ts +46 -0
  38. package/types/layer0/index.d.ts +64 -0
  39. package/types/layer1/index.d.ts +10 -0
  40. package/types/model.d.ts +184 -0
  41. package/types/moon/apparent.d.cts +78 -0
  42. package/types/moon/arguments.d.cts +138 -0
  43. package/types/moon/deep-ecc-channel.d.cts +25 -0
  44. package/types/moon/deep-modes-artifact.d.cts +140 -0
  45. package/types/moon/ecc-channel.d.cts +30 -0
  46. package/types/moon/month-chain.d.cts +79 -0
  47. package/types/moon/series-extension.d.cts +11 -0
  48. package/types/moon/series.d.cts +91 -0
  49. package/types/phase/index.d.cts +38 -0
  50. package/types/planets/asc-node-integrator.d.cts +30 -0
  51. package/types/planets/chain-artifact.d.ts +15 -0
  52. package/types/planets/ecc-channel.d.cts +20 -0
  53. package/types/planets/fibonacci-laws.d.cts +90 -0
  54. package/types/planets/geometry.d.cts +60 -0
  55. package/types/planets/inv-plane-frame.d.cts +36 -0
  56. package/types/planets/keplerian-chain.d.cts +173 -0
  57. package/types/planets/model.d.cts +116 -0
  58. package/types/planets/orbit-chain.d.cts +12 -0
  59. package/types/planets/orientation.d.cts +67 -0
  60. package/types/planets/predict.d.cts +88 -0
  61. package/types/planets/secular-series.d.cts +73 -0
  62. package/types/sun/longitude-correction.d.cts +41 -0
@@ -36,6 +36,8 @@
36
36
 
37
37
  'use strict';
38
38
 
39
+ const { createComposedPrecession } = require('../earth/precession-composed.cjs');
40
+
39
41
  /**
40
42
  * @typedef {Object} DeepTimeLodConstants
41
43
  * @property {number} lTotalEmKgm2S - Earth–Moon total angular momentum
@@ -53,6 +55,8 @@
53
55
  * @property {number} meanSiderealYearJ2000Seconds
54
56
  * @property {number} solarMassLossFracPerYear
55
57
  * @property {number} siderealYearDaysKinematicJ2000 - Actual-LOD numerator
58
+ * @property {number} precessionSolarShareJ2000 - f_S, the solar fraction of the J2000
59
+ * precession torque (derive-params) — the unit H(t) = 13·T_p,composed needs it
56
60
  */
57
61
 
58
62
  /**
@@ -100,14 +104,51 @@ function createDeepTimeLod(deps) {
100
104
  return (s === null) ? null : s / 3600;
101
105
  }
102
106
 
103
- /** H(t) via the H/13 identity: H(t) = H_J2000 · LOD(t)/LOD_J2000.
107
+ /** The FROZEN ERA CLOCK's phase convention: H_era(t) = H_J2000 · LOD(t)/LOD_J2000
108
+ * (pure spin scaling — the pre-Phase-3 "H/13 identity"). The frozen devices
109
+ * (the cardinal era clock, the year-length comb family, the ∫dt/H phase
110
+ * table) were fitted against THIS counter; it ships with their coefficients
111
+ * as a named device constant (plan 06 D8: two named counters). It is NOT
112
+ * the unit H(t) below.
104
113
  * @param {number} t_Ma @returns {number|null} */
105
- function hAtAge(t_Ma) {
114
+ function eraClockHAtAge(t_Ma) {
106
115
  const LOD_s = lodSecondsAtAge(t_Ma);
107
116
  if (LOD_s === null) return null;
108
117
  return K.holisticYearJ2000 * LOD_s / K.lodNowH13Seconds;
109
118
  }
110
119
 
120
+ // The unit H(t) ≡ 13 × the composed lunisolar precession period (plan 06
121
+ // D6 → Phase 3): ψ̇(t) = [ω(t)/ω₀]·p₀·[f_S + (1 − f_S)(a₀/a_M(t))³], p₀ =
122
+ // 1,296,000/(H₀/13). ONE formula home: earth/precession-composed, built
123
+ // here on this factory's own LOD and recession history.
124
+ const composed = createComposedPrecession({
125
+ p0ArcsecPerYr: 1296000 / (K.holisticYearJ2000 / 13),
126
+ solarShare: K.precessionSolarShareJ2000,
127
+ lodSecondsAtAge,
128
+ lodJ2000Seconds: K.lodNowH13Seconds,
129
+ moonDistanceMetresAtAge: deps.moonDistanceMetresAtAge,
130
+ moonDistanceJ2000Metres: K.aMoonNowMetres,
131
+ yearToTMa: /** @param {number} year */ (year) => (2000 - year) / 1e6,
132
+ });
133
+
134
+ /** The unit H(t) = 13·T_p,composed(t) — H is 13 lunisolar precession periods
135
+ * at every epoch (plan 06: H is a UNIT). Written as H_era / [f_S + (1 − f_S)
136
+ * (a₀/a_M)³] — algebraically 13·1,296,000/ψ̇_composed, spelled in the SAME
137
+ * operations as layer0's holisticHCore so the layer0 gate holds the twins
138
+ * bit-identical (13·T_p differs by one ULP). ≡ H_era wherever (a₀/a_M)³ ≈ 1.
139
+ * @param {number} t_Ma @returns {number|null} */
140
+ function hAtAge(t_Ma) {
141
+ const hEra = eraClockHAtAge(t_Ma);
142
+ const term = composed.torqueTermAtAge(t_Ma);
143
+ return hEra === null || term === null ? null : hEra / term;
144
+ }
145
+
146
+ /** The composed lunisolar precession rate, ″/yr (= 1,296,000·13/H(t)).
147
+ * @param {number} t_Ma @returns {number|null} */
148
+ function lunisolarPrecessionRateArcsecPerYrAtAge(t_Ma) {
149
+ return composed.composedRateArcsecPerYrAtAge(t_Ma);
150
+ }
151
+
111
152
  /** Sidereal year seconds (Kepler under linear mass loss, dT/T = −2 dM/M).
112
153
  * @param {number} t_Ma @returns {number} */
113
154
  function siderealYearSecondsAtAge(t_Ma) {
@@ -145,6 +186,26 @@ function createDeepTimeLod(deps) {
145
186
  return tropicalYearSecondsAtAge(t_Ma) / LOD_s;
146
187
  }
147
188
 
189
+ // ── The frozen era clock's twins (device tier) ──────────────────────────
190
+ // The same forms on H_era — the bases the frozen cardinal clock (its drift
191
+ // integrand and real-LOD convention) and the year-length comb family were
192
+ // fitted against. Bit-identical to the pre-Phase-3 tropicalYearSecondsAtAge /
193
+ // yearInDaysAtAge; the physical (unit) forms above are what the model
194
+ // publishes.
195
+ /** @param {number} t_Ma @returns {number} */
196
+ function eraClockTropicalYearSecondsAtAge(t_Ma) {
197
+ const sidSec = siderealYearSecondsAtAge(t_Ma);
198
+ const Ht = eraClockHAtAge(t_Ma);
199
+ if (Ht === null) return sidSec * (1 - 13 / K.holisticYearJ2000);
200
+ return sidSec * (1 - 13 / Ht);
201
+ }
202
+ /** @param {number} t_Ma @returns {number|null} */
203
+ function eraClockYearInDaysAtAge(t_Ma) {
204
+ const LOD_s = lodSecondsAtAge(t_Ma);
205
+ if (LOD_s === null) return null;
206
+ return eraClockTropicalYearSecondsAtAge(t_Ma) / LOD_s;
207
+ }
208
+
148
209
  /**
149
210
  * RAW ΔT integral relative to J2000 (0 at t=0 by convention) — Simpson
150
211
  * over the H/5-raw kinematic LOD, WITHOUT the cycle corrections and
@@ -270,9 +331,15 @@ function createDeepTimeLod(deps) {
270
331
 
271
332
  return {
272
333
  lodSecondsAtAge, lodSecondsAtAgeWithAlpha, lodHoursAtAge, hAtAge,
334
+ lunisolarPrecessionRateArcsecPerYrAtAge,
335
+ // the composition's terms (plan 06 Phase 3 S3, the lunisolar surface): (a₀/a_M)³ and f_S + (1 − f_S)(a₀/a_M)³
336
+ lunarTorqueFactorAtAge: composed.lunarTorqueFactorAtAge,
337
+ precessionTorqueTermAtAge: composed.torqueTermAtAge,
273
338
  siderealYearSecondsAtAge, tropicalYearSecondsAtAge, tropicalYearDaysAtAge,
274
339
  yearInDaysAtAge, deltaTRawSecondsAtAge, lodSecondsWithCorrectionsAtAge,
275
340
  lodSecondsActualAtAge, dLodDtDecompositionAtAge,
341
+ // the frozen era clock's named counter and bases (device tier, plan 06 D8)
342
+ eraClockHAtAge, eraClockTropicalYearSecondsAtAge, eraClockYearInDaysAtAge,
276
343
  };
277
344
  }
278
345
 
@@ -191,11 +191,12 @@ function createDeepOrbitalHistory({
191
191
  const ALPHA = psiDot / Math.cos(EPS0);
192
192
  // D1-revised (plan 02, owner 2026-09-13): when the injecting engine
193
193
  // supplies its epoch-aware axial-precession evaluator, α follows the
194
- // model's own H(t) recession history — α(t) = ψ̇(t)/cos ε₀ — and the
195
- // integrated deep-time obliquity IS the sharpened falsification-leg-1
196
- // form (the beat 2π/(ψ̇(t) − |s₃|), p H-scaled, s₃ dynamical). No new
197
- // constants: ψ̇(t) comes from the same certified year-length machinery
198
- // as the J2000 anchor. Absent the option, α stays constant (the
194
+ // model's own deep-time rate — α(t) = ψ̇(t)/cos ε₀ — and the integrated
195
+ // deep-time obliquity IS the sharpened falsification-leg-1 form (the
196
+ // beat 2π/(ψ̇(t) − |s₃|), ψ̇ the COMPOSED lunisolar rate the injecting
197
+ // engines build from earth/precession-composed (plan 06 D6), s₃
198
+ // dynamical). No new constants: ψ̇(t)'s J2000 anchor is the same
199
+ // certified year-length machinery; only its deep-time scaling is injected. Absent the option, α stays constant (the
199
200
  // pre-D1 ±Myr-class behavior, bit-identical).
200
201
  const alphaAtGeneral = axialPrecessionYearsAtYearFn
201
202
  ? (/** @type {number} */ t) =>
@@ -0,0 +1,120 @@
1
+ /**
2
+ * The composed lunisolar precession rate — ONE home (holisticuniverse plan 06,
3
+ * D6: the physical ψ̇(t) of falsification leg 1).
4
+ *
5
+ * Earth's axial precession rate is the two tiers composed: the spin ω(t) from
6
+ * the tidal chain (LOD history) carries BOTH torques, and the lunar torque
7
+ * additionally grows with the recession history as (a₀/a_M(t))³:
8
+ *
9
+ * ψ̇(t) = [ω(t)/ω₀] · p₀ · [ f_S + (1 − f_S) · (a₀/a_M(t))³ ]
10
+ *
11
+ * with p₀ the J2000 rate and f_S the solar fraction of the J2000 torque,
12
+ * derived from the shared constants (two-body point-mass torques with the
13
+ * (1 − e²)^(−3/2) eccentricity factors and the lunar-inclination factor
14
+ * 1 − 3/2·sin² i_M; ≈ 0.316, the textbook value). At J2000 every factor is 1.
15
+ * Plan 06 Phase 3: the unit H(t) IS 13 of these periods at every epoch
16
+ * (deltat/deep-time.cjs hAtAge builds on this factory), so H(t)/13 and the
17
+ * composed period are one quantity. The pre-Phase-3 structural clock
18
+ * 13·1,296,000/H_era(t) (pure ω-scaling, H_era = H₀·LOD/LOD₀) survives only
19
+ * as the FROZEN ERA CLOCK's named phase convention (eraClockHAtAge) and in
20
+ * docs/retired-record.md, with its record: it read 70.9 ″/yr against
21
+ * Lantink et al. 2022's 108.6 ± 8.5 at 2.46 Ga and 65.2 against Meyers &
22
+ * Malinverno 2018's 85.79 ± 2.72 at 1.4 Ga, where the composed rate reads
23
+ * 104.5 and 86.5.
24
+ *
25
+ * Pure factory: the tidal chain is injected (each runtime's own LOD and
26
+ * moon-distance evaluators), no artifact reads, no globals.
27
+ */
28
+
29
+ 'use strict';
30
+
31
+ const D2R = Math.PI / 180;
32
+
33
+ /**
34
+ * Solar fraction of the J2000 precession torque from the shared constants.
35
+ * @param {{
36
+ * gmSunKm3S2: number, auKm: number, earthEccentricity: number,
37
+ * gmMoonKm3S2: number, moonDistanceKm: number, moonEccentricity: number, moonInclinationDeg: number,
38
+ * }} c
39
+ * @returns {number} f_S in [0, 1]
40
+ */
41
+ function computeSolarTorqueShare(c) {
42
+ const sol = (c.gmSunKm3S2 / c.auKm ** 3) * Math.pow(1 - c.earthEccentricity * c.earthEccentricity, -1.5);
43
+ const lun = (c.gmMoonKm3S2 / c.moonDistanceKm ** 3) * Math.pow(1 - c.moonEccentricity * c.moonEccentricity, -1.5)
44
+ * (1 - 1.5 * Math.sin(c.moonInclinationDeg * D2R) ** 2);
45
+ return sol / (sol + lun);
46
+ }
47
+
48
+ /**
49
+ * @param {{
50
+ * p0ArcsecPerYr: number,
51
+ * solarShare: number,
52
+ * lodSecondsAtAge: (tMa: number) => (number | null),
53
+ * lodJ2000Seconds: number,
54
+ * moonDistanceMetresAtAge: (tMa: number) => (number | null),
55
+ * moonDistanceJ2000Metres: number,
56
+ * yearToTMa: (year: number) => number,
57
+ * }} deps - p0 = 1,296,000/(H/13) (the model's J2000 rate); lodJ2000Seconds
58
+ * the SAME day basis lodSecondsAtAge(0) returns.
59
+ * @returns {{
60
+ * composedRateArcsecPerYrAtAge: (tMa: number) => (number | null),
61
+ * composedPeriodYearsAtAge: (tMa: number) => (number | null),
62
+ * composedRateArcsecPerYrAtYear: (year: number) => (number | null),
63
+ * composedPeriodYearsAtYear: (year: number) => (number | null),
64
+ * composedRateRatioAtAge: (tMa: number) => (number | null),
65
+ * torqueTermAtAge: (tMa: number) => (number | null),
66
+ * lunarTorqueFactorAtAge: (tMa: number) => (number | null),
67
+ * solarShare: number,
68
+ * p0ArcsecPerYr: number,
69
+ * }}
70
+ */
71
+ function createComposedPrecession(deps) {
72
+ const { p0ArcsecPerYr: p0, solarShare: fS } = deps;
73
+ /** @param {number} tMa */
74
+ const lunarTorqueFactorAtAge = (tMa) => {
75
+ const a = deps.moonDistanceMetresAtAge(tMa);
76
+ return a === null || !(a > 0) ? null : Math.pow(deps.moonDistanceJ2000Metres / a, 3);
77
+ };
78
+ /** The torque term f_S + (1 − f_S)·(a₀/a_M)³ — the factor the unit H(t)
79
+ * divides the spin-scaled H_era by (deltat/deep-time.cjs; layer0 spells the
80
+ * SAME operations, the layer0 gate holds them bit-identical).
81
+ * @param {number} tMa */
82
+ const torqueTermAtAge = (tMa) => {
83
+ const lf = lunarTorqueFactorAtAge(tMa);
84
+ return lf === null ? null : fS + (1 - fS) * lf;
85
+ };
86
+ /** @param {number} tMa */
87
+ const composedRateArcsecPerYrAtAge = (tMa) => {
88
+ const lod = deps.lodSecondsAtAge(tMa);
89
+ const term = torqueTermAtAge(tMa);
90
+ if (lod === null || !(lod > 0) || term === null) return null;
91
+ return (deps.lodJ2000Seconds / lod) * p0 * term;
92
+ };
93
+ /** @param {number} tMa */
94
+ const composedPeriodYearsAtAge = (tMa) => {
95
+ const r = composedRateArcsecPerYrAtAge(tMa);
96
+ return r === null ? null : 1296000 / r;
97
+ };
98
+ /** ψ̇(t)/ψ̇₀ — the factor a consumer scales ITS OWN certified J2000
99
+ * anchor by (the hybrids anchor on the of-date beat 25,771.4 yr, not on
100
+ * p₀'s 25,793; the ratio is what D6 changes, the anchor stays theirs).
101
+ * ≡ 1 at J2000; null out of the tidal chain's domain.
102
+ * @param {number} tMa */
103
+ const composedRateRatioAtAge = (tMa) => {
104
+ const r = composedRateArcsecPerYrAtAge(tMa);
105
+ return r === null ? null : r / p0;
106
+ };
107
+ return {
108
+ composedRateArcsecPerYrAtAge,
109
+ composedPeriodYearsAtAge,
110
+ composedRateArcsecPerYrAtYear: (year) => composedRateArcsecPerYrAtAge(deps.yearToTMa(year)),
111
+ composedPeriodYearsAtYear: (year) => composedPeriodYearsAtAge(deps.yearToTMa(year)),
112
+ composedRateRatioAtAge,
113
+ torqueTermAtAge,
114
+ lunarTorqueFactorAtAge,
115
+ solarShare: fS,
116
+ p0ArcsecPerYr: p0,
117
+ };
118
+ }
119
+
120
+ module.exports = { computeSolarTorqueShare, createComposedPrecession };
@@ -113,4 +113,15 @@ function createYearLengths({ sampleAt, massLossSiderealSecondsAtYearFn, apsidalS
113
113
  });
114
114
  }
115
115
 
116
- module.exports = { createYearLengths };
116
+ /**
117
+ * The published of-date window (plan 06 Phase 3 S2): inside |year − 2000| ≤
118
+ * this span the one-family route is THE published year-length / precession
119
+ * family (the banked tiers — 100-yr and 1000-yr grids, no unbounded sampler
120
+ * growth); beyond it the published surfaces return the unit's SECULAR mean
121
+ * (H(t)/13 for the precession period, the tidal-chain mean year), because the
122
+ * of-date wobble is unresolved there and the deep sampler grows ~0.1 s per Myr
123
+ * of span. A displayed rate must name its window — this is the window.
124
+ */
125
+ const ONE_FAMILY_WINDOW_YEARS = 2000000;
126
+
127
+ module.exports = { createYearLengths, ONE_FAMILY_WINDOW_YEARS };
package/src/index.js CHANGED
@@ -138,7 +138,11 @@ export { createDeepOrbitalHistory } from './earth/deep-orbital-history.cjs';
138
138
  // D6: the sidereal-year-of-date channel (banked λ̇ ratio × the caller's mass-loss law)
139
139
  export { createSiderealYearChannel } from './earth/sidereal-year-channel.cjs';
140
140
  // S2: THE ONE of-date year-length family (years + precession beats, SI seconds)
141
- export { createYearLengths } from './earth/year-lengths.cjs';
141
+ export { createYearLengths, ONE_FAMILY_WINDOW_YEARS } from './earth/year-lengths.cjs';
142
+ // Plan 06 D6: THE ONE home of the composed lunisolar precession rate ψ̇(t)
143
+ // (spin ω(t) × [solar torque + lunar torque on the recession history]) —
144
+ // leg-1's physical rate; the structural H(t)/13 clock is its named diagnostic.
145
+ export { computeSolarTorqueShare, createComposedPrecession } from './earth/precession-composed.cjs';
142
146
  export { createPredictivePrecession, calcPlanetPerihelionLongDeg } from './planets/predict.cjs';
143
147
  // L10 — the composition front door: one law set, N body records. Thin by
144
148
  // design; engines keep their direct call sites (see planets/model.cjs).
@@ -148,7 +152,7 @@ export { createDeltaTCycles } from './deltat/cycles.cjs';
148
152
  export { createDeepTimeLod } from './deltat/deep-time.cjs';
149
153
  export { createMoonRecessionHistory, createSolarChannelBudget } from './deltat/recession-history.cjs';
150
154
  export { deltaTEspenakMeeusCanonSeconds } from './deltat/historical.cjs';
151
- export { evalClimateL1OrbitalPermil } from './climate/l1-orbital.cjs';
155
+ export { evalClimateL1OrbitalPermil, laggedL1Terms, createAlphaGiaChannel } from './climate/l1-orbital.cjs';
152
156
  // Phase 8.5 — eclipse geometry (single-copy: the browser had no Node twin).
153
157
  export { createEclipseFinders } from './eclipse/finders.cjs';
154
158
  // Phase 8.6 — the published reference curves (external comparison formulas
@@ -9,12 +9,16 @@
9
9
  * If the two ever disagree, one of them changed and the other did not — which
10
10
  * is the exact drift mode that produced five diverging implementations.
11
11
  *
12
- * Pure function, imports nothing. Lives in physics so the browser and the Node
13
- * engine can both build Layer 0 from ONE derivation (deep-time.js keeps its
14
- * own inline copy only until Phase C rewrites it; until then the test is the
15
- * enforcement).
12
+ * Pure function; its only import is the torque-share derivation (plan 06
13
+ * Phase 3: the unit H(t) = 13·T_p,composed needs the solar fraction of the
14
+ * J2000 precession torque, derived ONCE here from the shared constants).
15
+ * Lives in physics so the browser and the Node engine can both build Layer 0
16
+ * from ONE derivation (deep-time.js keeps its own inline copy only until
17
+ * Phase C rewrites it; until then the test is the enforcement).
16
18
  */
17
19
 
20
+ import { computeSolarTorqueShare } from '../earth/precession-composed.cjs';
21
+
18
22
  /**
19
23
  * @typedef {Object} RawEpochConstants
20
24
  * @property {number} solarLuminosityW IAU 2015 nominal (W)
@@ -35,6 +39,10 @@
35
39
  * @property {number} moonDistanceKm
36
40
  * @property {number} moonOrbitalEccentricity
37
41
  * @property {number} gmEarthMoonSystemKm3S2
42
+ * @property {number} gmSunKm3S2 GM☉ (km³/s²) — the solar precession torque
43
+ * @property {number} astronomicalUnitKm 1 AU (km)
44
+ * @property {number} earthOrbitalEccentricityJ2000
45
+ * @property {number} moonEclipticInclinationJ2000Deg
38
46
  */
39
47
 
40
48
  /**
@@ -64,6 +72,14 @@ export const deriveEpochParams = (raw) => {
64
72
  + (moonMassKg * Math.sqrt(gmEarthMoonM3S2 * moonDistanceNowM) * moonEccentricityFactor);
65
73
  const moonLockDistanceM = (totalAngularMomentumKgM2S / (moonMassKg * Math.sqrt(gmEarthMoonM3S2) * moonEccentricityFactor)) ** 2;
66
74
 
75
+ // The solar fraction of the J2000 precession torque (plan 06 Phase 3): the
76
+ // unit H(t) ≡ 13·T_p,composed = H_era(t) / [f_S + (1 − f_S)(a₀/a_M(t))³].
77
+ const precessionSolarShareJ2000 = computeSolarTorqueShare({
78
+ gmSunKm3S2: raw.gmSunKm3S2, auKm: raw.astronomicalUnitKm, earthEccentricity: raw.earthOrbitalEccentricityJ2000,
79
+ gmMoonKm3S2: raw.gmMoonAloneKm3S2, moonDistanceKm: raw.moonDistanceKm, moonEccentricity: raw.moonOrbitalEccentricity,
80
+ moonInclinationDeg: raw.moonEclipticInclinationJ2000Deg,
81
+ });
82
+
67
83
  return Object.freeze({
68
84
  epochYear: 2000,
69
85
  alpha1PerMa: raw.alpha1PerMa,
@@ -81,5 +97,6 @@ export const deriveEpochParams = (raw) => {
81
97
  lodNowH13Seconds,
82
98
  siderealYearJ2000Seconds: raw.meanSiderealYearSeconds,
83
99
  solarMassLossFracPerYear,
100
+ precessionSolarShareJ2000,
84
101
  });
85
102
  };
@@ -47,6 +47,7 @@
47
47
  * @property {number} lodNowH13Seconds
48
48
  * @property {number} siderealYearJ2000Seconds
49
49
  * @property {number} solarMassLossFracPerYear
50
+ * @property {number} precessionSolarShareJ2000 f_S, the solar fraction of the J2000 precession torque
50
51
  */
51
52
 
52
53
  /**
@@ -54,10 +55,12 @@
54
55
  * @property {(year: number) => number} tMa
55
56
  * @property {(year: number) => number} moonDistanceMetres
56
57
  * @property {(year: number) => number|null} lodSeconds
57
- * @property {(year: number) => number|null} holisticH
58
+ * @property {(year: number) => number|null} holisticH the UNIT: 13 × the composed lunisolar precession period
58
59
  * @property {(year: number) => number} siderealYearSeconds
59
60
  * @property {(year: number) => number} tropicalYearSeconds
60
61
  * @property {(year: number) => number|null} anomalisticYearSeconds
62
+ * @property {(year: number) => number|null} eraClockH the frozen era clock's phase convention H₀·LOD/LOD₀ (device tier)
63
+ * @property {(year: number) => number} eraClockTropicalYearSeconds T_sid·(1 − 13/H_era) — the frozen comb family's base
61
64
  */
62
65
 
63
66
  /**
@@ -98,16 +101,35 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa }) => {
98
101
  };
99
102
 
100
103
  /**
101
- * The Earth Fundamental Cycle. H scales with LOD — the lattice is defined by
102
- * the rotation rate, so a longer day is a longer H.
104
+ * The frozen era clock's phase convention: H_era(t) = H₀·LOD(t)/LOD₀ —
105
+ * pure spin scaling. This is the counter the FROZEN devices (the cardinal
106
+ * era clock, the year-length comb family) were fitted against; it ships
107
+ * with their coefficients as a named device constant (plan 06 Phase 3,
108
+ * D8), never as "H(t)".
103
109
  * @param {number} t age in Ma
104
110
  * @returns {number|null} years
105
111
  */
106
- const holisticHCore = (t) => {
112
+ const eraClockHCore = (t) => {
107
113
  const lod = lodSecondsCore(t);
108
114
  return lod === null ? null : p.holisticYearJ2000 * lod / p.lodNowH13Seconds;
109
115
  };
110
116
 
117
+ /**
118
+ * The unit H(t) ≡ 13 × the composed lunisolar precession period:
119
+ * H_era(t) / [f_S + (1 − f_S)·(a₀/a_M(t))³] — the spin scaling AND the
120
+ * lunar torque growing on the recession history (plan 06 D6/Phase 3; the
121
+ * formula's home is earth/precession-composed, this is its Layer-0 twin,
122
+ * held bit-identical to deltat/deep-time.cjs by the layer0 gate).
123
+ * @param {number} t age in Ma
124
+ * @returns {number|null} years
125
+ */
126
+ const holisticHCore = (t) => {
127
+ const hEra = eraClockHCore(t);
128
+ if (hEra === null) return null;
129
+ const lf = Math.pow(p.moonDistanceNowM / moonDistanceMetresCore(t), 3);
130
+ return hEra / (p.precessionSolarShareJ2000 + (1 - p.precessionSolarShareJ2000) * lf);
131
+ };
132
+
111
133
  /**
112
134
  * Sidereal year. Driver 2 alone — solar mass loss via Kepler, `dT/T = -2 dM/M`
113
135
  * under the adiabatic `a*M = const` coupling. Carries NO alpha and NO LOD,
@@ -159,6 +181,13 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa }) => {
159
181
  return sid * (H - 13) / H * H / (H - 16);
160
182
  };
161
183
 
184
+ /** The frozen comb family's tropical base: T_sid·(1 − 13/H_era). @param {number} t */
185
+ const eraClockTropicalYearSecondsCore = (t) => {
186
+ const sid = siderealYearSecondsCore(t);
187
+ const H = eraClockHCore(t);
188
+ return H === null ? sid * (1 - 13 / p.holisticYearJ2000) : sid * (1 - 13 / H);
189
+ };
190
+
162
191
  return Object.freeze({
163
192
  tMa,
164
193
  moonDistanceMetres: (year) => moonDistanceMetresCore(tMa(year)),
@@ -167,5 +196,7 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa }) => {
167
196
  siderealYearSeconds: (year) => siderealYearSecondsCore(tMa(year)),
168
197
  tropicalYearSeconds: (year) => tropicalYearSecondsCore(tMa(year)),
169
198
  anomalisticYearSeconds: (year) => anomalisticYearSecondsCore(tMa(year)),
199
+ eraClockH: (year) => eraClockHCore(tMa(year)),
200
+ eraClockTropicalYearSeconds: (year) => eraClockTropicalYearSecondsCore(tMa(year)),
170
201
  });
171
202
  };