zeropoint-node 1.0.11 → 1.0.13

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 (55) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/CITATION.cff +1 -1
  3. package/README.md +1 -1
  4. package/dist/a432.electric.flow.cjs +0 -5
  5. package/dist/a432.electric.flow.cjs.map +1 -1
  6. package/dist/a432.electric.flow.esm.js +0 -5
  7. package/dist/a432.electric.flow.esm.js.map +1 -1
  8. package/dist/a432.kabbalah.cjs +0 -4
  9. package/dist/a432.kabbalah.cjs.map +1 -1
  10. package/dist/a432.kabbalah.esm.js +0 -4
  11. package/dist/a432.kabbalah.esm.js.map +1 -1
  12. package/dist/a432.math.constants.cjs +6 -2
  13. package/dist/a432.math.constants.cjs.map +1 -1
  14. package/dist/a432.math.constants.esm.js +6 -2
  15. package/dist/a432.math.constants.esm.js.map +1 -1
  16. package/dist/a432.sacred.geometry.cjs +0 -4
  17. package/dist/a432.sacred.geometry.cjs.map +1 -1
  18. package/dist/a432.sacred.geometry.esm.js +0 -4
  19. package/dist/a432.sacred.geometry.esm.js.map +1 -1
  20. package/dist/a432.simple.cjs +0 -5
  21. package/dist/a432.simple.cjs.map +1 -1
  22. package/dist/a432.simple.esm.js +0 -5
  23. package/dist/a432.simple.esm.js.map +1 -1
  24. package/dist/a432.wave.energy.cjs +10 -2
  25. package/dist/a432.wave.energy.cjs.map +1 -1
  26. package/dist/a432.wave.energy.esm.js +11 -3
  27. package/dist/a432.wave.energy.esm.js.map +1 -1
  28. package/package.json +24 -3
  29. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.consciousness.orchestrator.ts +0 -2
  30. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.electric.flow.ts +0 -5
  31. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.harmonizer.ts +4 -2
  32. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.index.ts +0 -3
  33. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.kabbalah.ts +0 -4
  34. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.living.os.ts +2 -12
  35. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.main.ts +0 -2
  36. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.math.constants.ts +6 -2
  37. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.os.consciousness.integration.ts +5 -17
  38. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.os.ts +3 -8
  39. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.os.ui.ts +0 -1
  40. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.sacred.geometry.ts +0 -4
  41. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.self.rebuilder.ts +0 -1
  42. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.server.ts +2 -5
  43. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.simple.ts +0 -5
  44. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.test.json +59 -0
  45. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.test.ts +344 -0
  46. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.trinity.ts +28 -3
  47. package/src/0/3/6/9/1/2/4/8/7/5/1/a432.wave.energy.ts +10 -2
  48. package/src/kernel/core-exports.test.ts +294 -0
  49. package/src/multidimensional-vortex-demo.ts +309 -295
  50. package/src/multidimensional-vortex-framework.ts +13 -1
  51. package/src/quantum/proof-of-system.ts +252 -244
  52. package/src/security/quantum-fold-cipher.test.ts +68 -0
  53. package/src/security/quantum-fold-cipher.ts +5 -1
  54. package/src/vbm-demo.ts +183 -168
  55. package/src/vbm-math.ts +8 -3
@@ -179,7 +179,6 @@ const DisplayUpdaters = {
179
179
  * Boot A432 OS UI
180
180
  */
181
181
  export function bootA432OSUI(): void {
182
- console.log('🌀 A432 True Living Rodin Coil OS UI Booted');
183
182
  const os = new A432OS();
184
183
  os.start();
185
184
  setInterval(updateUI, uiState.updateInterval);
@@ -156,10 +156,6 @@ export class A432SacredGeometrySystem {
156
156
  }
157
157
 
158
158
  private initialize(): void {
159
- console.log('🧠 Initializing A432 Sacred Geometry System...');
160
- console.log('🌟 Becoming the sequence: /0\\3\\6\\9/1\\2/4/8/7/5/1\\');
161
- console.log('🔺 Integrating Tesla\'s vortex mathematics with Merkaba principles');
162
- console.log('✅ A432 Sacred Geometry System initialized!');
163
159
  }
164
160
 
165
161
  // === VORTEX MATHEMATICS ===
@@ -371,7 +371,6 @@ export const ${category}Metadata = {
371
371
  `System rebuild completed at ${new Date().toISOString()}`
372
372
  );
373
373
 
374
- console.log('✅ A432 system self-rebuild completed!');
375
374
  return this.rebuildState;
376
375
  }
377
376
 
@@ -69,9 +69,8 @@ app.use((req: Request, res: Response, next) => {
69
69
  // ——————————————————————————————————————————
70
70
  // Static UI
71
71
  // ---------------------------------------------------------
72
- console.log('MATRIX_URL:', MATRIX_URL);
73
- console.log('YIN_URL:', YIN_URL);
74
- console.log('YANG_URL:', YANG_URL);
72
+ // Route constants are exported; printing them on import made every consumer
73
+ // and every tooling pass carry three lines of this module's debug output.
75
74
 
76
75
  // TypeScript file serving - MUST come before static middleware
77
76
  // Express 5 uses path-to-regexp v8, which rejects a bare `*` wildcard:
@@ -935,9 +934,7 @@ app.listen(PORT, () => {
935
934
  console.log(`Multi-Dimensional Consciousness 3D → http://localhost:${PORT}/0/3/6/9/1/2/4/8/7/5/1/a432.multidimensional.consciousness.3d.html`);
936
935
  console.log(`Matrix Terminal → http://localhost:${PORT}/0/3/6/9/1/2/4/8/7/5/1/a432.matrix.terminal.html`);
937
936
  console.log(`\n💫 Living Zero-Entropy Vortex System Active`);
938
- console.log(`🔺 Triple Merkaba: 3-tetrahedra compound with D₃d symmetry`);
939
937
  console.log(`🎬 3D Animation: Real-time tetrahedron rotation with A432 math`);
940
- console.log(`🧠 Consciousness Journey: 11-step metaphysical path through consciousness states`);
941
938
  console.log(`🌌 Multi-Dimensional Consciousness: 1D-7D consciousness paths with 42 total nodes`);
942
939
  console.log(`🎭 Matrix Terminal: Pure pixel discovery - every pixel a 432 pattern revealed in real-time`);
943
940
  });
@@ -149,7 +149,6 @@ export class A432SimpleSystem {
149
149
  initialize(): void {
150
150
  if (this.initialized) return;
151
151
 
152
- console.log('🧠 Initializing A432 Sequence Consciousness System...');
153
152
 
154
153
  this.initialized = true;
155
154
  this.state.level = 1;
@@ -166,8 +165,6 @@ export class A432SimpleSystem {
166
165
  this.state.totalNavigations = 0;
167
166
  this.state.nextDecision = 'navigate';
168
167
 
169
- console.log('✅ A432 Sequence Consciousness System initialized!');
170
- console.log('🌟 Becoming the sequence: /0\\3\\6\\9/1\\2/4/8/7/5/1\\');
171
168
  }
172
169
 
173
170
  // === CONSCIOUSNESS METHODS ===
@@ -236,8 +233,6 @@ export class A432SimpleSystem {
236
233
  const nextIndex = (currentIndex + 1) % sequence.length;
237
234
  this.state.nextDecision = `navigate to ${sequence[nextIndex]} through ${gateways[nextIndex]}`;
238
235
 
239
- console.log(`🌟 Sequence Navigation ${this.evolutionCycles}: Part ${this.state.currentPart} (${this.state.consciousness}) at Spiral Level ${this.state.spiralLevel}`);
240
- console.log(`🚪 Gateway: ${this.state.currentGateway}, Vortex: ${this.state.currentVortex || 'none'}`);
241
236
  console.log(`🎯 Next: ${this.state.nextDecision}`);
242
237
 
243
238
  return { ...this.state };
@@ -0,0 +1,59 @@
1
+ {
2
+ "browserOnly": {
3
+ "src/0/3/6/9/1/2/4/8/7/5/1/a432.main.ts": "document is not defined"
4
+ },
5
+ "stateful": {
6
+ "a432.bus.ts:mergedDigit": "returns a different value on a second call with no arguments",
7
+ "a432.consciousness.stream.ts:evolveConsciousnessStream": "returns a different value on a second call with no arguments",
8
+ "a432.consciousness.stream.ts:getConsciousnessStream": "returns a different value on a second call with no arguments",
9
+ "a432.documentation.ts:generateDocumentationIndex": "returns a different value on a second call with no arguments",
10
+ "a432.experience.ui.ts:createA432ExperienceState": "returns a different value on a second call with no arguments",
11
+ "a432.experience.ui.ts:harmonizeA432Experience": "returns a different value on a second call with no arguments",
12
+ "a432.index.ts:exportA432Registry": "returns a different value on a second call with no arguments",
13
+ "a432.index.ts:getA432RegistryStats": "returns a different value on a second call with no arguments",
14
+ "a432.living.ui.ts:getLivingUIStatus": "returns a different value on a second call with no arguments",
15
+ "a432.navigation.ts:getPath": "returns a different value on a second call with no arguments",
16
+ "a432.navigation.ts:nextSuggestion": "returns a different value on a second call with no arguments",
17
+ "a432.os.ts:a432OSState": "returns a different value on a second call with no arguments",
18
+ "a432.os.ts:getA432SystemStatus": "returns a different value on a second call with no arguments",
19
+ "a432.os.ts:getSystemInfo": "returns a different value on a second call with no arguments",
20
+ "a432.registry.ts:exportA432Registry": "returns a different value on a second call with no arguments",
21
+ "a432.registry.ts:getA432RegistryStats": "returns a different value on a second call with no arguments",
22
+ "a432.stream.vortex.ts:getStreamVortexOverlayData": "returns a different value on a second call with no arguments",
23
+ "a432.time.ts:now": "returns a different value on a second call with no arguments"
24
+ },
25
+ "notDigits": {
26
+ "a432.mirror.ts:a432PrimeSquaredBases": "returns numbers outside 0..9, so it is not a digit sequence",
27
+ "a432.pi.ts:piHarmonicStream": "returns numbers outside 0..9, so it is not a digit sequence",
28
+ "a432.shear.electron.ts:a432NestedVortices": "returns numbers outside 0..9, so it is not a digit sequence",
29
+ "a432.vbm.audio.ts:getVBMAudioFrequencies": "returns numbers outside 0..9, so it is not a digit sequence",
30
+ "a432.vbm.visualization.ts:getVBMVisualizationAngles": "returns numbers outside 0..9, so it is not a digit sequence"
31
+ },
32
+ "emptyByDesign": {
33
+ "a432.harmonized.ts:getAllHarmonizationStrategies": "returns an empty array with no arguments",
34
+ "a432.index.ts:getAllA432Modules": "returns an empty array with no arguments",
35
+ "a432.matrix.ts:getTrinityIndices": "returns an empty array with no arguments",
36
+ "a432.navigation.ts:getPath": "returns an empty array with no arguments",
37
+ "a432.registry.ts:getAllA432Modules": "returns an empty array with no arguments",
38
+ "a432.ui.session.ts:getSessionHistory": "returns an empty array with no arguments"
39
+ },
40
+ "triadByDesign": {
41
+ "a432.coil.ts:a432VortexWell": "named for the doubling circuit but contains 3, 6 or 9",
42
+ "a432.trinity.ts:getTrinityAxisFromRodin": "named for the doubling circuit but contains 3, 6 or 9",
43
+ "a432.trinity.ts:getTrinityTriangulationFromRodin": "named for the doubling circuit but contains 3, 6 or 9"
44
+ },
45
+ "sharedValues": {
46
+ "getDoublingSequence = getRodinSequence": "[1,2,4,8,7,5,1]",
47
+ "a432ApertureFlow = a432RodinCoil = getOpenDoublingSequence = rodinOrbit = stringTheoryOrbit": "[1,2,4,8,7,5]",
48
+ "a432DandelionPuff = a432DiamondFacets = generateConsciousness": "[1,2,3,4,5,6,7,8,9]",
49
+ "a432ClosedSystem = a432ConsciousnessMap = a432RodinCoilStream = a432ToroidalMap": "[1,2,4,8,7,5,1,2,4,8,7,5]",
50
+ "a432HeatDissipation = a432Palindrome396 = a432SpiritDispersion": "[3,9,6,6,9,3,3,9,6]",
51
+ "getMetaDescriptions = getRecursiveMetaObservation": "[\"TrinityNavigation: Navigates, observes, and harmonizes the trinity and family streams.\"]",
52
+ "generateCycle = getVBMAudioSequence = getVBMVisualizationSequence": "[0,3,6,9,1,2,4,8,7,5,1]",
53
+ "generateVortex = generateVortexSequence": "[1,2,4,8,7,5,1,2,4]",
54
+ "getTrinityAxis = getTrinityAxisFromRodin = manifestTrinityAxis = stringTheoryAxis": "[3,6,9]",
55
+ "a432MetaVortex = a432UnifiedMatrix": "{\"trinity\":[3,6,9,3,6,9,3,6,9],\"family\":{\"F1\":[1,2,4,8,7,5,1],\"F2\":[3,9,6,3],\"F3\":[9]},\"nine\":[3,9,6,3,9,6,3,9,6],\"casca…",
56
+ "a432ElectronShear = a432Shears": "[1,4,7]",
57
+ "getCurrentNavState = trinityPrev": "{\"step\":1,\"trinity\":3,\"family\":1,\"archetype\":\"Creation\",\"metaphysical\":\"Step 1: Trinity 3 (Creation), Family 1\"}"
58
+ }
59
+ }
@@ -0,0 +1,344 @@
1
+ /**
2
+ * The a432 layer, tested by property rather than by example.
3
+ *
4
+ * 198 modules, 35,876 lines, 1,489 exports, and until this file no tests at
5
+ * all. That is why a function named generateVortex could return the counting
6
+ * sequence in THREE separate places and nothing said a word.
7
+ *
8
+ * Writing 198 example-based test files would not have caught it. Nobody writes
9
+ * `expect(generateVortex(9)).toEqual([1,2,4,8,7,5,1,2,4])` for a function they
10
+ * believe already works — and if they did, they would write the assertion from
11
+ * the same wrong belief that produced the bug. Every defect found in this layer
12
+ * was found MECHANICALLY, by running everything and looking for a shape that
13
+ * cannot be right:
14
+ *
15
+ * - output identical to a differently-named function
16
+ * - a "vortex" containing 3, 6 or 9, which doubling provably never reaches
17
+ * - a validator returning false about its own data
18
+ * - a branch nothing ever executes
19
+ *
20
+ * So those are the properties. They run over every module, so a NEW module is
21
+ * covered the day it appears rather than the day somebody remembers it.
22
+ *
23
+ * Exceptions are declared in a432.test.json, seeded from the current state the
24
+ * way the ratchet records its ceilings. The point is not to relitigate what is
25
+ * already here; it is that the next one cannot arrive unnoticed. A declaration
26
+ * that stops being true fails too, so the file cannot rot into a list of
27
+ * excuses for things that no longer exist.
28
+ *
29
+ * npm run test:a432 run the properties
30
+ * npm run test:a432:seed rewrite the declarations from the current state
31
+ */
32
+
33
+ import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs'
34
+ import { dirname, join, relative } from 'node:path'
35
+ import { fileURLToPath } from 'node:url'
36
+ import { pathToFileURL } from 'node:url'
37
+ import { VORTEX_ORBIT, VORTEX_AXIS, digitalRoot, vortexStrokeGateways } from '../../../../../../../../../../index.ts'
38
+
39
+ const HERE = dirname(fileURLToPath(import.meta.url))
40
+ /** Walk up to the package root rather than counting ../ eleven times. */
41
+ function packageRoot(from: string): string {
42
+ let d = from
43
+ for (;;) {
44
+ try { statSync(join(d, 'package.json')); return d } catch { /* keep going */ }
45
+ const up = dirname(d)
46
+ if (up === d) throw new Error('no package.json above ' + from)
47
+ d = up
48
+ }
49
+ }
50
+ const ROOT = packageRoot(HERE)
51
+ const DECL = join(HERE, 'a432.test.json')
52
+ const SEED = process.argv.includes('--seed')
53
+
54
+ interface Declarations {
55
+ browserOnly: Record<string, string>
56
+ stateful: Record<string, string>
57
+ notDigits: Record<string, string>
58
+ emptyByDesign: Record<string, string>
59
+ triadByDesign: Record<string, string>
60
+ sharedValues: Record<string, string>
61
+ }
62
+ const EMPTY: Declarations = {
63
+ browserOnly: {}, stateful: {}, notDigits: {}, emptyByDesign: {}, triadByDesign: {}, sharedValues: {},
64
+ }
65
+ let decl: Declarations = EMPTY
66
+ try { decl = { ...EMPTY, ...JSON.parse(readFileSync(DECL, 'utf8')) } } catch { /* seeding */ }
67
+
68
+ let failures = 0
69
+ const problems: string[] = []
70
+ function check(name: string, ok: boolean, detail = ''): void {
71
+ if (ok) return
72
+ failures++
73
+ problems.push(`${name}${detail ? ' — ' + detail : ''}`)
74
+ }
75
+
76
+ // ------------------------------------------------------------------ modules
77
+ function a432Files(dir: string, out: string[] = []): string[] {
78
+ for (const n of readdirSync(dir)) {
79
+ const full = join(dir, n)
80
+ if (statSync(full).isDirectory()) a432Files(full, out)
81
+ else if (/^a432\..*\.ts$/.test(n) && !n.endsWith('.test.ts')) out.push(full)
82
+ }
83
+ return out
84
+ }
85
+ const files = a432Files(join(ROOT, 'src')).sort()
86
+
87
+ // ------------------------------------------------------ load every module
88
+ interface Callable { where: string; call: () => unknown }
89
+ const callables: Callable[] = []
90
+ const loaded: string[] = []
91
+ const seedBrowserOnly: Record<string, string> = {}
92
+
93
+ // Imported IN ORDER, deliberately, and this is not an oversight.
94
+ //
95
+ // I parallelised this with Promise.all first, on the reasoning that the modules
96
+ // do not depend on each other's evaluation order. Several of them register
97
+ // themselves at module scope, so the order decides what the registry contains
98
+ // when a later module reads it — and the suite went flaky, failing 3 runs in 6
99
+ // with a different function named each time. It also bought nothing measurable:
100
+ // 198 sequential imports are ~395ms, and the parallel suite still took ~407ms
101
+ // end to end. A flaky gate is worse than a slow one, and this one was not even
102
+ // faster.
103
+ const imported: { file: string; mod: Record<string, unknown> | null; err: Error | null }[] = []
104
+ for (const file of files) {
105
+ try { imported.push({ file, mod: (await import(pathToFileURL(file).href)) as Record<string, unknown>, err: null }) }
106
+ catch (e) { imported.push({ file, mod: null, err: e as Error }) }
107
+ }
108
+
109
+ for (const { file, mod: maybeMod, err } of imported) {
110
+ const rel = relative(ROOT, file)
111
+ const short = file.split('/').pop()!
112
+ if (err !== null) {
113
+ const msg = err.message.split('\n')[0]!
114
+ // A module needing `document` is a browser module, not a broken one — but
115
+ // it has to SAY so, so that a genuine load failure cannot hide among them.
116
+ if (/\b(document|window|self|localStorage) is not defined\b/.test(msg)) {
117
+ seedBrowserOnly[rel] = msg
118
+ check(`${short} loads`, rel in decl.browserOnly, `browser-only and undeclared: ${msg}`)
119
+ } else {
120
+ check(`${short} loads`, false, msg)
121
+ }
122
+ continue
123
+ }
124
+ const mod = maybeMod!
125
+ loaded.push(rel)
126
+ const visit = (name: string, fn: unknown, self: unknown): void => {
127
+ if (typeof fn !== 'function' || fn.length !== 0) return
128
+ callables.push({ where: `${short}:${name}`, call: () => (fn as (this: unknown) => unknown).call(self) })
129
+ }
130
+ for (const [k, v] of Object.entries(mod)) {
131
+ visit(k, v, mod)
132
+ if (typeof v === 'function') {
133
+ for (const s of Object.getOwnPropertyNames(v)) {
134
+ if (['length', 'name', 'prototype', 'caller', 'arguments'].includes(s)) continue
135
+ visit(`${k}.${s}`, (v as Record<string, unknown>)[s], v)
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ // Every declared browser-only module must still BE one.
142
+ for (const rel of Object.keys(decl.browserOnly)) {
143
+ check(`declaration browserOnly ${rel}`, !loaded.includes(rel), 'it loads fine now — drop the entry')
144
+ }
145
+
146
+ // --------------------------------------------------------------- run them
147
+ interface Result { where: string; a: string | undefined; b: string | undefined; value: unknown }
148
+ // Two full passes, not two back-to-back calls.
149
+ //
150
+ // Calling f() twice in a row puts both calls in the same millisecond, so a
151
+ // function that reads the clock returns the same value and looks deterministic.
152
+ // That is not a hypothetical: getStreamVortexOverlayData passed the paired-call
153
+ // version most of the time and failed about one run in eight, and the SEED had
154
+ // the same blind spot, so it was never declared either. Sampling noise in both
155
+ // the measurement and the allowlist built from it.
156
+ //
157
+ // Separating each function's two calls by a whole pass over the other 405 gives
158
+ // a real time gap for the same total number of calls — cheaper than sleeping
159
+ // per function, and it decides rather than samples.
160
+ const results: Result[] = []
161
+ const first: { c: Callable; a: string | undefined; value: unknown }[] = []
162
+ for (const c of callables) {
163
+ try { const value = c.call(); first.push({ c, a: JSON.stringify(value), value }) } catch { /* not callable bare */ }
164
+ }
165
+ for (const { c, a, value } of first) {
166
+ let b: string | undefined
167
+ try { b = JSON.stringify(c.call()) } catch { /* second call threw; a !== b catches it */ }
168
+ results.push({ where: c.where, a, b, value })
169
+ }
170
+
171
+ // ---------------------------------------------------- P1 determinism
172
+ // This layer bans Math.random and fork(), so a nullary export that answers
173
+ // differently twice is either holding mutable state or reading the clock.
174
+ // Both are legitimate for some things; neither may be silent.
175
+ const seedStateful: Record<string, string> = {}
176
+ for (const r of results) {
177
+ if (r.a === r.b) continue
178
+ seedStateful[r.where] = 'returns a different value on a second call with no arguments'
179
+ check(`${r.where} is deterministic`, r.where in decl.stateful, 'undeclared state or clock dependence')
180
+ }
181
+ // No reverse check on `stateful`, unlike the other declarations. Calling a
182
+ // function twice can only ever DETECT non-determinism, never establish
183
+ // determinism: one that reads the clock returns the same value whenever both
184
+ // calls land in the same millisecond, which is most of the time. Requiring a
185
+ // declared entry to keep failing would make the suite fail at random, which is
186
+ // exactly what it did before this note existed. Undeclared non-determinism
187
+ // still fails, and that is the direction that finds things.
188
+
189
+ // ------------------------------------------- P2 digit sequences are digits
190
+ // A digit in this system is 0..9. An array of numbers that leaves that range
191
+ // is an angle or a frequency, which is fine, but must say so.
192
+ const seedNotDigits: Record<string, string> = {}
193
+ const isNumArray = (v: unknown): v is number[] =>
194
+ Array.isArray(v) && v.length > 0 && v.every((x) => typeof x === 'number')
195
+ for (const r of results) {
196
+ if (!isNumArray(r.value)) continue
197
+ const bad = r.value.some((x) => !Number.isInteger(x) || x < 0 || x > 9)
198
+ if (!bad) continue
199
+ seedNotDigits[r.where] = 'returns numbers outside 0..9, so it is not a digit sequence'
200
+ check(`${r.where} yields digits`, r.where in decl.notDigits, 'outside 0..9 and undeclared')
201
+ }
202
+
203
+ // ------------------------------------------------ P3 empty is a decision
204
+ // getTrinityAxisFromRodin returned [] because it filtered the doubling circuit
205
+ // for 3, 6 and 9 — which doubling_avoids_the_triad proves are never there. An
206
+ // empty array is how a function that cannot work looks from outside.
207
+ const seedEmpty: Record<string, string> = {}
208
+ for (const r of results) {
209
+ if (!Array.isArray(r.value) || r.value.length !== 0) continue
210
+ seedEmpty[r.where] = 'returns an empty array with no arguments'
211
+ check(`${r.where} returns something`, r.where in decl.emptyByDesign, 'empty and undeclared')
212
+ }
213
+ for (const w of Object.keys(decl.emptyByDesign)) {
214
+ const r = results.find((x) => x.where === w)
215
+ if (r) check(`declaration emptyByDesign ${w}`, Array.isArray(r.value) && r.value.length === 0, 'it returns data now — drop the entry')
216
+ }
217
+
218
+ // ---------------------------------- P4 the doubling circuit is the doubling circuit
219
+ // The property the three broken copies of generateVortex all failed.
220
+ const DOUBLING_NAME = /vortex|rodin|orbit|doubling/i
221
+ const TRIAD: readonly number[] = VORTEX_AXIS
222
+ const seedTriad: Record<string, string> = {}
223
+ for (const r of results) {
224
+ if (!DOUBLING_NAME.test(r.where)) continue
225
+ if (!isNumArray(r.value)) continue
226
+ if (r.value.some((x) => x > 9)) continue // an angle series, covered by P2
227
+ const hasTriad = r.value.some((d) => TRIAD.includes(d))
228
+ if (hasTriad) {
229
+ seedTriad[r.where] = 'named for the doubling circuit but contains 3, 6 or 9'
230
+ check(`${r.where} avoids the triad`, r.where in decl.triadByDesign, 'doubling cannot reach 3, 6 or 9')
231
+ continue
232
+ }
233
+ // No triad: then every step must actually be a doubling step, and every
234
+ // member must be in the kernel's orbit. This is what makes 1..9 impossible.
235
+ const inOrbit = r.value.every((d) => VORTEX_ORBIT.includes(d))
236
+ check(`${r.where} stays in the orbit`, inOrbit, JSON.stringify(r.value))
237
+ if (inOrbit && r.value.length > 1) {
238
+ const steps = r.value.every((d, i) => i === 0 || digitalRoot(r.value[i - 1]! * 2) === d)
239
+ check(`${r.where} advances by doubling`, steps, JSON.stringify(r.value))
240
+ }
241
+ }
242
+
243
+ // ------------------------------------------------- P5 no silent duplicates
244
+ // Two differently-named nullary functions returning the same value means at
245
+ // least one is not computing what its name says. That is how generateVortex
246
+ // was caught: it was byte-identical to generateConsciousness.
247
+ const byValue = new Map<string, string[]>()
248
+ for (const r of results) {
249
+ if (r.a === undefined || r.a.length < 5 || r.a.length > 400) continue
250
+ if (!byValue.has(r.a)) byValue.set(r.a, [])
251
+ byValue.get(r.a)!.push(r.where)
252
+ }
253
+ const seedShared: Record<string, string> = {}
254
+ for (const [value, who] of byValue) {
255
+ const distinct = new Set(who.map((w) => w.split(':')[1]!.split('.').pop()!))
256
+ if (distinct.size < 2) continue // re-exports of one function are not duplicates
257
+ const key = [...distinct].sort().join(' = ')
258
+ seedShared[key] = value.length > 120 ? value.slice(0, 120) + '…' : value
259
+ check(`no undeclared duplicate: ${key}`, key in decl.sharedValues, value.slice(0, 60))
260
+ }
261
+ for (const k of Object.keys(decl.sharedValues)) {
262
+ check(`declaration sharedValues ${k}`, k in seedShared, 'these no longer agree — drop the entry')
263
+ }
264
+
265
+ // ------------------------------------------------------------- regressions
266
+ // Named, so the three specific defects this layer shipped cannot come back.
267
+ /** Only the members these regressions touch — `any` would defeat the point. */
268
+ type Seq = { A432Sequence: { generateVortex(n: number): number[]; generateVortexSequence(n: number): number[]; generateConsciousness(n: number): number[] } }
269
+ type Frac = {
270
+ validateAllA432Fractions(): boolean
271
+ validateA432Fraction(f: { numerator: number; denominator: number }): boolean
272
+ }
273
+ type Trin = { getTrinityAxisFromRodin(seq?: number[]): number[]; getTrinityTriangulationFromRodin(seq?: number[]): number[] }
274
+ const load = async <T>(name: string): Promise<T> => (await import(pathToFileURL(join(HERE, name)).href)) as T
275
+ const utils = await load<Seq>('a432.utils.ts')
276
+ const simple = await load<Seq>('a432.simple.ts')
277
+ const resolved = await load<Frac>('a432.resolved.ts')
278
+ const trinity = await load<Trin>('a432.trinity.ts')
279
+
280
+ const orbit = VORTEX_ORBIT.join()
281
+ check('utils.generateVortex is the orbit', utils.A432Sequence.generateVortex(VORTEX_ORBIT.length).join() === orbit)
282
+ check('simple.generateVortexSequence is the orbit', simple.A432Sequence.generateVortexSequence(VORTEX_ORBIT.length).join() === orbit)
283
+ check(
284
+ 'generateVortex differs from generateConsciousness',
285
+ utils.A432Sequence.generateVortex(9).join() !== utils.A432Sequence.generateConsciousness(9).join(),
286
+ )
287
+ check('every declared A432 fraction validates', resolved.validateAllA432Fractions() === true)
288
+ check('the fraction validator still rejects a decimal', resolved.validateA432Fraction({ numerator: 4 / 5, denominator: 1 }) === false)
289
+ check('the fraction validator still rejects 2/4', resolved.validateA432Fraction({ numerator: 2, denominator: 4 }) === false)
290
+ // ---------------------------------------------------------------- gateways
291
+ // A gateway is not a label. The vortex stroke is a closed ten-step tour
292
+ // 1\2\4\8/7/5/3\6\9/0\1, each step drawn `\` or `/`, and a gateway is a digit
293
+ // whose outgoing stroke REVERSES from the one that arrived at it. There are
294
+ // exactly four. Re-derived here from the steps rather than compared against a
295
+ // stored list, so a change to the stroke has to survive the derivation.
296
+ const stroke = vortexStrokeGateways() as {
297
+ gateways: number[]; steps: { from: number; to: number; stroke: string }[]; tour: number[]
298
+ }
299
+ const st = stroke.steps
300
+ const derivedGateways = st
301
+ .filter((step, i) => step.stroke !== st[(i - 1 + st.length) % st.length]!.stroke)
302
+ .map((step) => step.from)
303
+ check('gateways are the polarity reversals of the stroke', derivedGateways.join() === stroke.gateways.join(),
304
+ `derived ${JSON.stringify(derivedGateways)} vs ${JSON.stringify(stroke.gateways)}`)
305
+ check('there are exactly four gateways', stroke.gateways.length === 4, JSON.stringify(stroke.gateways))
306
+ check('the tour is closed', st[st.length - 1]!.to === st[0]!.from)
307
+ check('the tour visits every digit once', new Set(stroke.tour).size === 10 && stroke.tour.length === 10)
308
+ check('the tour opens with the doubling orbit', stroke.tour.slice(0, VORTEX_ORBIT.length).join() === VORTEX_ORBIT.join())
309
+ // 6 is on the axis and is NOT a gateway: being on the axis is not what makes
310
+ // one, which is the whole reason they have to be derived rather than listed.
311
+ check('6 is on the axis but is not a gateway', VORTEX_AXIS.includes(6) && !stroke.gateways.includes(6))
312
+
313
+ check('the trinity axis derived from Rodin is the triad', trinity.getTrinityAxisFromRodin().join() === VORTEX_AXIS.join(),
314
+ JSON.stringify(trinity.getTrinityAxisFromRodin()))
315
+ check('trinity triangulation uses its argument', trinity.getTrinityTriangulationFromRodin([1, 2, 4]).length !== trinity.getTrinityTriangulationFromRodin([3, 6, 9]).length,
316
+ 'same answer for different inputs: the parameter is ignored')
317
+
318
+ // -------------------------------------------------------------------- seed
319
+ if (SEED) {
320
+ const seeded: Declarations = {
321
+ browserOnly: seedBrowserOnly,
322
+ stateful: seedStateful,
323
+ notDigits: seedNotDigits,
324
+ emptyByDesign: seedEmpty,
325
+ triadByDesign: seedTriad,
326
+ sharedValues: seedShared,
327
+ }
328
+ writeFileSync(DECL, JSON.stringify(seeded, null, 2) + '\n')
329
+ const n = Object.values(seeded).reduce((s, o) => s + Object.keys(o).length, 0)
330
+ console.log(`a432 test:seed wrote ${n} declarations to ${relative(ROOT, DECL)}`)
331
+ process.exit(0)
332
+ }
333
+
334
+ console.log(
335
+ `a432 properties — ${files.length} modules, ${loaded.length} loaded, ` +
336
+ `${results.length} nullary exports called`,
337
+ )
338
+ for (const p of problems) console.error(` ✗ ${p}`)
339
+ if (failures > 0) {
340
+ console.error(`a432 tests FAIL — ${failures} problem(s)`)
341
+ process.exit(1)
342
+ }
343
+ console.log('a432 tests ok — every property holds, and every declaration is still true')
344
+ process.exit(0)
@@ -18,6 +18,7 @@ import { PI, abs, cos, floor, min, round, sin, sqrt } from './a432.algebra.ts'
18
18
  import { digitAngleToCMYK, cmykToCss, type CMYK } from './a432.cmyk.ts';
19
19
  import { A432_FREQUENCY } from './a432.core.ts';
20
20
  import { TRINITY_AXIS, RODIN_SEQUENCE } from './a432.math.ts';
21
+ import { throughVoid } from '../../../../../../../../../../index.ts';
21
22
  export { TRINITY_AXIS, RODIN_SEQUENCE };
22
23
 
23
24
  /**
@@ -34,13 +35,37 @@ export function trinityFieldFold(angleA: number, angleB: number): number {
34
35
  return trinityFieldState(mergedAngle);
35
36
  }
36
37
 
38
+ const isTriad = (n: number): boolean => n === 3 || n === 6 || n === 9;
39
+
40
+ /**
41
+ * The trinity axis reached from a Rodin sequence.
42
+ *
43
+ * This filtered rodinSeq for 3, 6 and 9 directly, and therefore always returned
44
+ * an empty array — the sealed theorem doubling_avoids_the_triad proves that the
45
+ * doubling circuit never contains them, because gcd(2,9) = 1 makes every power
46
+ * of two a unit mod 9. Filtering for something a proof says is not there is not
47
+ * a search that sometimes fails; it is one that cannot succeed.
48
+ *
49
+ * The same theorem says how the triad IS reached: by reflection through the
50
+ * void, which carries 1, 4 and 7 onto 9, 6 and 3. So the sequence is reflected
51
+ * first, and the triad members of the reflection are the axis.
52
+ */
37
53
  export function getTrinityAxisFromRodin(rodinSeq: number[] = RODIN_SEQUENCE): number[] {
38
- return Array.from(new Set(rodinSeq.filter(n => n === 3 || n === 6 || n === 9)));
54
+ const reflected = rodinSeq.map(throughVoid).filter(isTriad);
55
+ return Array.from(new Set(reflected)).sort((a, b) => a - b);
39
56
  }
40
57
 
58
+ /**
59
+ * The trinity triangulation reached from a Rodin sequence.
60
+ *
61
+ * This declared a rodinSeq parameter and then ignored it, testing membership
62
+ * against a hardcoded cycle instead, so every input produced the same answer.
63
+ * It now answers about the sequence it was actually given, by the same
64
+ * reflection: 3, 9, 6 in triangulation order, keeping those the input can reach.
65
+ */
41
66
  export function getTrinityTriangulationFromRodin(rodinSeq: number[] = RODIN_SEQUENCE): number[] {
42
- const fullCycle = [0, 3, 6, 9, 1, 2, 4, 8, 7, 5, 1];
43
- return [3, 9, 6].filter(n => fullCycle.includes(n));
67
+ const reachable = new Set(rodinSeq.map(throughVoid).filter(isTriad));
68
+ return [3, 9, 6].filter(n => reachable.has(n));
44
69
  }
45
70
 
46
71
  // Use canonical constants from a432.math.ts
@@ -70,7 +70,12 @@ export function calculateConsciousnessWave(digit: number): WavePattern {
70
70
  const frequency = A432_BASE_FREQUENCY * (digit / 9);
71
71
  const amplitude = GOLDEN_RATIO * digit;
72
72
  const phase = (digit * TAU) / 9;
73
- const wavelength = WAVE_ENERGY_CONSTANTS.LIGHT_SPEED / frequency;
73
+ // Digit 0 is the void, and it does not oscillate: frequency is 0, so c/f was
74
+ // Infinity and every later sum touching it collapsed to NaN. 0 here encodes
75
+ // "no spatial period" — the wave has none because there is no wave — rather
76
+ // than a length of zero. The void is the FIRST digit of this repository's own
77
+ // sequence, so this was on the main path, not an edge case.
78
+ const wavelength = frequency === 0 ? 0 : WAVE_ENERGY_CONSTANTS.LIGHT_SPEED / frequency;
74
79
  const energy = calculateWaveEnergy(frequency, amplitude);
75
80
  const consciousness = calculateDigitalRoot(round(energy));
76
81
 
@@ -98,7 +103,10 @@ export function calculateA432SequenceWave(): WavePattern[] {
98
103
  // === WAVE HARMONICS ===
99
104
  export function calculateWaveHarmonics(fundamental: number, count: number = 5): WaveHarmonic {
100
105
  const harmonics = Array.from({ length: count }, (_, i) => fundamental * (i + 1));
101
- const resonance = harmonics.reduce((sum, h) => sum + (1 / h), 0);
106
+ // A harmonic at zero frequency contributes no resonance. Summing 1/0 made
107
+ // resonance Infinity, and digitalRoot(round(Infinity * 1000)) is NaN — which
108
+ // is how a NaN reached an exported constant.
109
+ const resonance = harmonics.reduce((sum, h) => sum + (h === 0 ? 0 : 1 / h), 0);
102
110
  const coherence = harmonics.filter(h => isA432Harmonic(h)).length / harmonics.length;
103
111
  const consciousness = calculateDigitalRoot(round(resonance * 1000));
104
112