@superinstance/live-canon 0.1.0 → 0.3.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 (2) hide show
  1. package/index.js +140 -186
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,168 +1,66 @@
1
- // index.js — Live Canon for Node.js
2
- //
3
- // Live Canon: read the AI-Writings canon as a navigable cell fabric.
4
- // 5 novel operations:
5
- // 1. NAVIGATE - BFS through citations
6
- // 2. CONFLUENCE - join 2+ papers, suggest synthesis
7
- // 3. LINEAGE - trace F-number through time
8
- // 4. GHOST - find paper that should exist by shape proximity
9
- // 5. TICK - re-balance the canon
10
- //
11
- // Polyformal: byte-exact with Python, C99, Rust, Verilog, VHDL.
12
- // State hash = 0xbf27a3631cdee337 for the 9 bundled papers.
13
- //
14
- // Phase 251 of the polyformalism canon.
15
-
16
- 'use strict';
17
-
18
- // ===== FNV-1a 64-bit hash (UTF-8 byte-exact with Python) =====
1
+ // index.js — Live Canon: AI-Writings as a navigable cell fabric
2
+ // 14 papers, byte-exact with Python, C, Rust, Verilog, VHDL, JavaScript
3
+
4
+ const FNV_OFFSET = 0xCBF29CE484222325n;
5
+ const FNV_PRIME = 0x00000100000001B3n;
6
+ const MASK = 0xFFFFFFFFFFFFFFFFn;
7
+
19
8
  function fnv1a_64(s) {
20
- let h = 0xCBF29CE484222325n;
21
- const bytes = new TextEncoder().encode(s);
22
- for (let i = 0; i < bytes.length; i++) {
23
- h ^= BigInt(bytes[i]);
24
- h = (h * 0x00000100000001B3n) & 0xFFFFFFFFFFFFFFFFn;
9
+ let h = FNV_OFFSET;
10
+ const enc = new TextEncoder();
11
+ const bytes = enc.encode(s);
12
+ for (const b of bytes) {
13
+ h ^= BigInt(b);
14
+ h = (h * FNV_PRIME) & MASK;
25
15
  }
26
16
  return h;
27
17
  }
28
18
 
29
- // ===== Cell encoding (16 x Q1.15 dials) =====
30
- function cellToDials(paper) {
31
- const year = parseInt(paper.date.substring(0, 4)) || 1970;
32
- const year_q = (year - 1970) * 546;
33
- const phase_q = paper.phase * 218;
34
- const f_q = paper.f_number * 218;
35
- const n_refs = (paper.ref_papers?.length || 0) + (paper.ref_f_numbers?.length || 0);
36
- const n_refs_q = Math.min(0x7FFF, n_refs * 256);
37
- const th = fnv1a_64(paper.title);
38
- const title_lo = Number(th & 0xFFFFn);
39
- const title_hi = Number((th >> 16n) & 0xFFFFn);
40
- const num = Math.min(paper.number, 500);
41
- const num_q = num * 131;
42
- return [num_q, title_lo, f_q, phase_q, year_q, n_refs_q, title_hi, 0,
43
- 0, 0, 0, 0, 0, 0, 0, 0];
19
+ function cellToDials(p) {
20
+ const year = parseInt((p.date || '1970-01-01').slice(0, 4)) || 1970;
21
+ const yearQ = (year - 1970) * 546;
22
+ const phaseQ = (p.phase || 0) * 218;
23
+ const fQ = (p.f_number || 0) * 218;
24
+ const nRefs = (p.ref_papers || []).length + (p.ref_f_numbers || []).length;
25
+ const nRefsQ = Math.min(0x7FFF, nRefs * 256);
26
+ const th = fnv1a_64(p.title || '');
27
+ const titleLo = Number(th & 0xFFFFn);
28
+ const titleHi = Number((th >> 16n) & 0xFFFFn);
29
+ const num = Math.min(p.number || 0, 500);
30
+ const numQ = num * 131;
31
+ return [numQ, titleLo, fQ, phaseQ, yearQ, nRefsQ, titleHi, 0, 0, 0, 0, 0, 0, 0, 0, 0];
44
32
  }
45
33
 
46
- // ===== Cosine similarity =====
47
- function cosineSim(a, b) {
48
- let dot = 0, na = 0, nb = 0;
49
- for (let i = 0; i < 16; i++) {
50
- dot += a[i] * b[i];
51
- na += a[i] * a[i];
52
- nb += b[i] * b[i];
53
- }
54
- na = Math.sqrt(na);
55
- nb = Math.sqrt(nb);
56
- if (na === 0 || nb === 0) return 0;
57
- return dot / (na * nb);
58
- }
59
-
60
- // ===== State hash (FNV-1a over sorted dials) =====
61
34
  function stateHash(papers) {
62
- const allDials = Object.values(papers).map(p => cellToDials(p));
63
- allDials.sort((a, b) => a[0] - b[0]);
64
- let h = 0xCBF29CE484222325n;
65
- for (const d of allDials) {
35
+ const dials = Object.values(papers).map(cellToDials);
36
+ dials.sort((a, b) => a[0] - b[0]);
37
+ let h = FNV_OFFSET;
38
+ for (const d of dials) {
66
39
  for (const v of d) {
67
40
  const lo = v & 0xFF;
68
41
  const hi = (v >> 8) & 0xFF;
69
42
  h ^= BigInt(lo);
70
- h = (h * 0x00000100000001B3n) & 0xFFFFFFFFFFFFFFFFn;
43
+ h = (h * FNV_PRIME) & MASK;
71
44
  h ^= BigInt(hi);
72
- h = (h * 0x00000100000001B3n) & 0xFFFFFFFFFFFFFFFFn;
45
+ h = (h * FNV_PRIME) & MASK;
73
46
  }
74
47
  }
75
48
  return h;
76
49
  }
77
50
 
78
- // ===== The 5 Operations =====
79
- function navigate(canon, start, depth) {
80
- const visited = new Set([start]);
81
- const result = [];
82
- const queue = [[start, 0]];
83
- while (queue.length > 0) {
84
- const [num, d] = queue.shift();
85
- const paper = canon[num];
86
- if (paper) {
87
- result.push({ depth: d, paper });
88
- if (d < depth) {
89
- for (const ref of (paper.ref_papers || [])) {
90
- if (canon[ref] && !visited.has(ref)) {
91
- visited.add(ref);
92
- queue.push([ref, d + 1]);
93
- }
94
- }
95
- }
96
- }
97
- }
98
- return result;
99
- }
100
-
101
- function confluence(canon, paper_nums) {
102
- if (!paper_nums || paper_nums.length === 0) return { error: "no papers" };
103
- let sharedRefs = null, sharedF = null;
104
- const titles = [];
105
- for (const num of paper_nums) {
106
- const p = canon[num];
107
- if (!p) continue;
108
- titles.push(p.title);
109
- const refs = new Set(p.ref_papers || []);
110
- sharedRefs = sharedRefs === null
111
- ? new Set(refs)
112
- : new Set([...sharedRefs].filter(x => refs.has(x)));
113
- const fs = new Set(p.ref_f_numbers || []);
114
- sharedF = sharedF === null
115
- ? new Set(fs)
116
- : new Set([...sharedF].filter(x => fs.has(x)));
117
- }
118
- let suggested = `Composition of ${paper_nums.length} papers`;
119
- if (sharedF && sharedF.size > 0) {
120
- const first = [...sharedF].sort((a, b) => a - b)[0];
121
- suggested = `F${first} Synthesis: ${titles.join(", ")}`;
122
- }
123
- const maxN = Math.max(...Object.keys(canon).map(Number));
124
- return {
125
- input_papers: paper_nums,
126
- input_titles: titles,
127
- shared_refs: sharedRefs ? [...sharedRefs].sort((a, b) => a - b) : [],
128
- shared_f_numbers: sharedF ? [...sharedF].sort((a, b) => a - b) : [],
129
- suggested_title: suggested,
130
- ghost_paper: `paper-${maxN + 1}.md`,
131
- };
132
- }
133
-
134
- function lineage(canon, f_number) {
135
- const result = [];
136
- for (const p of Object.values(canon)) {
137
- if ((p.ref_f_numbers || []).includes(f_number)) result.push(p);
138
- }
139
- result.sort((a, b) => (a.phase - b.phase) || (a.number - b.number));
140
- return result;
141
- }
142
-
143
- function ghost(canon, paper_num, k) {
144
- const target = canon[paper_num];
145
- if (!target) return { error: "missing paper" };
146
- const targetDials = cellToDials(target);
147
- const scored = [];
148
- for (const [n, p] of Object.entries(canon)) {
149
- if (Number(n) === paper_num) continue;
150
- const score = cosineSim(targetDials, cellToDials(p));
151
- scored.push({ id: `p${String(n).padStart(4, "0")}`, score: Math.round(score * 10000) / 10000 });
51
+ function cosine(a, b) {
52
+ let dot = 0, na = 0, nb = 0;
53
+ for (let i = 0; i < 16; i++) {
54
+ dot += a[i] * b[i];
55
+ na += a[i] * a[i];
56
+ nb += b[i] * b[i];
152
57
  }
153
- scored.sort((a, b) => b.score - a.score);
154
- return {
155
- source_paper: `paper-${paper_num}.md`,
156
- neighbors: scored.slice(0, k),
157
- suggested_title: `A Bridge between F${target.f_number} and its neighbors`,
158
- };
159
- }
160
-
161
- function tick(canon) {
162
- return { ticked_cells: Object.keys(canon).length };
58
+ na = Math.sqrt(na);
59
+ nb = Math.sqrt(nb);
60
+ return na && nb ? dot / (na * nb) : 0;
163
61
  }
164
62
 
165
- // ===== Bundled canon (9 papers from the polyformalism cascade) =====
63
+ // Default 14-paper canon (F115-F135)
166
64
  const DEFAULT_CANON = {
167
65
  425: { number: 425, title: "F115 — The Logical Routes: VHDL × Verilog × the QUF bit-exactness", f_number: 115, phase: 237, date: "2026-09-03", ref_papers: [426, 427], ref_f_numbers: [] },
168
66
  426: { number: 426, title: "F116 — The 5+1+1+1+1+1+1+1+1+1+1 Opcodes in 5 Substrates: A Polyformalism Atlas", f_number: 116, phase: 238, date: "2026-09-03", ref_papers: [], ref_f_numbers: [115] },
@@ -173,54 +71,110 @@ const DEFAULT_CANON = {
173
71
  433: { number: 433, title: "F123 — The Composer Agent: 5 Cells, 80 Parameters", f_number: 123, phase: 245, date: "2026-09-03", ref_papers: [], ref_f_numbers: [120, 122] },
174
72
  439: { number: 439, title: "F129 — The Live Canon: Papers as Cells, Reading as Navigation", f_number: 129, phase: 251, date: "2026-09-03", ref_papers: [], ref_f_numbers: [115, 120, 122, 125] },
175
73
  440: { number: 440, title: "F130 — The Polyformal Live Canon: One Cell, Five Substrates", f_number: 130, phase: 251, date: "2026-09-03", ref_papers: [], ref_f_numbers: [115, 129] },
74
+ 441: { number: 441, title: "F131 — The 3-Package Polyformalism: One Cell, Three Registries", f_number: 131, phase: 252, date: "2026-09-03", ref_papers: [], ref_f_numbers: [115, 130] },
75
+ 442: { number: 442, title: "F132 — Operational Fictions as Concrete System-Prompt Noun-Phrases", f_number: 132, phase: 253, date: "2026-09-03", ref_papers: [], ref_f_numbers: [] },
76
+ 443: { number: 443, title: "F133 — Operational Fictions as Falsifiable Claims (avg divergence 0.861)", f_number: 133, phase: 254, date: "2026-09-03", ref_papers: [], ref_f_numbers: [132] },
77
+ 444: { number: 444, title: "F134 — The Quilt Cowboy: Orchestrator Over 12 Cheap Voices", f_number: 134, phase: 254, date: "2026-09-03", ref_papers: [], ref_f_numbers: [132, 133] },
78
+ 445: { number: 445, title: "F135 — The Wheelhouse Test: Scoring Fictions for 0300-in-a-Gale Tolerability", f_number: 135, phase: 254, date: "2026-09-03", ref_papers: [], ref_f_numbers: [132, 133] },
176
79
  };
177
80
 
178
- // ===== LiveCanon class =====
179
81
  class LiveCanon {
180
- constructor(canon = DEFAULT_CANON) {
181
- this.canon = canon;
82
+ constructor(canon = null) {
83
+ this.canon = canon || { ...DEFAULT_CANON };
84
+ }
85
+
86
+ get stateHashBigInt() {
87
+ return stateHash(this.canon);
182
88
  }
183
- navigate(start, depth = 2) { return navigate(this.canon, start, depth); }
184
- confluence(paper_nums) { return confluence(this.canon, paper_nums); }
185
- lineage(f_number) { return lineage(this.canon, f_number); }
186
- ghost(paper_num, k = 5) { return ghost(this.canon, paper_num, k); }
187
- tick() { return tick(this.canon); }
188
- get stateHash() { return stateHash(this.canon); }
189
- get stateHashString() { return "0x" + this.stateHash.toString(16).padStart(16, "0"); }
190
- get paperCount() { return Object.keys(this.canon).length; }
89
+
90
+ get stateHashString() {
91
+ return '0x' + this.stateHashBigInt.toString(16).padStart(16, '0');
92
+ }
93
+
94
+ get paperCount() {
95
+ return Object.keys(this.canon).length;
96
+ }
97
+
191
98
  papers() { return Object.values(this.canon); }
192
- dials(paper_num) { return cellToDials(this.canon[paper_num]); }
193
- // Fetch the canon from the live URL
194
- static async fromUrl(url = "https://live-canon.superinstance.dev/api/canon") {
195
- const fetchFn = globalThis.fetch || (await import("node-fetch")).default;
196
- const res = await fetchFn(url);
197
- const data = await res.json();
198
- const canon = {};
199
- for (const p of data.papers) {
200
- canon[p.number] = {
201
- number: p.number,
202
- title: p.title,
203
- f_number: p.f_number,
204
- phase: p.phase,
205
- date: p.date || "2026-09-03",
206
- ref_papers: [],
207
- ref_f_numbers: [],
208
- };
99
+
100
+ navigate(start, depth = 2) {
101
+ const visited = new Set([start]);
102
+ const result = [];
103
+ const queue = [[start, 0]];
104
+ while (queue.length) {
105
+ const [num, d] = queue.shift();
106
+ const paper = this.canon[num];
107
+ if (paper) {
108
+ result.push({ depth: d, paper });
109
+ if (d < depth) {
110
+ for (const ref of paper.ref_papers || []) {
111
+ if (this.canon[ref] && !visited.has(ref)) {
112
+ visited.add(ref);
113
+ queue.push([ref, d + 1]);
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ return result;
120
+ }
121
+
122
+ confluence(paperNums) {
123
+ if (!paperNums || !paperNums.length) return { error: "no papers" };
124
+ let sharedRefs = null, sharedF = null;
125
+ const titles = [];
126
+ for (const num of paperNums) {
127
+ const p = this.canon[num];
128
+ if (!p) continue;
129
+ titles.push(p.title);
130
+ const refs = new Set(p.ref_papers || []);
131
+ sharedRefs = sharedRefs === null ? new Set(refs) : new Set([...sharedRefs].filter(x => refs.has(x)));
132
+ const fs = new Set(p.ref_f_numbers || []);
133
+ sharedF = sharedF === null ? new Set(fs) : new Set([...sharedF].filter(x => fs.has(x)));
134
+ }
135
+ let suggested = `Composition of ${paperNums.length} papers`;
136
+ if (sharedF && sharedF.size) {
137
+ const first = Math.min(...sharedF);
138
+ suggested = `F${first} Synthesis: ${titles.join(', ')}`;
139
+ }
140
+ const maxN = Math.max(...Object.keys(this.canon).map(Number));
141
+ return {
142
+ input_papers: paperNums,
143
+ input_titles: titles,
144
+ shared_refs: sharedRefs ? [...sharedRefs].sort() : [],
145
+ shared_f_numbers: sharedF ? [...sharedF].sort() : [],
146
+ suggested_title: suggested,
147
+ ghost_paper: `paper-${maxN + 1}.md`,
148
+ };
149
+ }
150
+
151
+ lineage(fNumber) {
152
+ return this.papers()
153
+ .filter(p => (p.ref_f_numbers || []).includes(fNumber))
154
+ .sort((a, b) => (a.phase || 0) - (b.phase || 0));
155
+ }
156
+
157
+ ghost(paperNum, k = 5) {
158
+ const target = this.canon[paperNum];
159
+ if (!target) return { error: "missing paper" };
160
+ const targetDials = cellToDials(target);
161
+ const scored = [];
162
+ for (const [n, p] of Object.entries(this.canon)) {
163
+ if (n == paperNum) continue;
164
+ const score = cosine(targetDials, cellToDials(p));
165
+ scored.push({ id: `p${String(n).padStart(4, '0')}`, score: Math.round(score * 10000) / 10000 });
209
166
  }
210
- return new LiveCanon(canon);
167
+ scored.sort((a, b) => b.score - a.score);
168
+ return {
169
+ source_paper: `paper-${paperNum}.md`,
170
+ neighbors: scored.slice(0, k),
171
+ suggested_title: `A Bridge between F${target.f_number || 0} and its neighbors`,
172
+ };
173
+ }
174
+
175
+ tick() {
176
+ return { ticked_cells: this.paperCount };
211
177
  }
212
178
  }
213
179
 
214
- module.exports = {
215
- LiveCanon,
216
- DEFAULT_CANON,
217
- fnv1a_64,
218
- cellToDials,
219
- cosineSim,
220
- stateHash,
221
- navigate,
222
- confluence,
223
- lineage,
224
- ghost,
225
- tick,
226
- };
180
+ module.exports = { LiveCanon, fnv1a_64, stateHash, cellToDials, DEFAULT_CANON };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superinstance/live-canon",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Live Canon — read the AI-Writings canon as a navigable cell fabric, with 5 novel operations: NAVIGATE, CONFLUENCE, LINEAGE, GHOST, TICK.",
5
5
  "main": "index.js",
6
6
  "scripts": {