hummbl-bibliography 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cascade/rules/hummbl-base120.md +107 -0
- package/.github/CODEOWNERS +17 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +10 -0
- package/.github/ISSUE_TEMPLATE/new-entry.md +79 -0
- package/.github/ISSUE_TEMPLATE/quality-improvement.md +71 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- package/.github/dependabot.yml +17 -0
- package/.github/workflows/ci.yml +98 -0
- package/.github/workflows/doi-enrichment.yml +77 -0
- package/.github/workflows/security-audit.yml +92 -0
- package/.github/workflows/stats-report.yml +59 -0
- package/.github/workflows/validate-models.yml +194 -0
- package/.github/workflows/validate.yml +152 -0
- package/.husky/pre-commit +15 -0
- package/.husky/validation-rules.json +11 -0
- package/CHANGELOG.md +228 -0
- package/CONTRIBUTING.md +110 -0
- package/CONTRIBUTORS.md +257 -0
- package/DEVELOPMENT.md +110 -0
- package/Day_1_Audit_Worksheet.md +64 -0
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/SECURITY.md +16 -0
- package/SITREP.md +141 -0
- package/bibliography/T10_collaboration.bib +281 -0
- package/bibliography/T11_security.bib +311 -0
- package/bibliography/T12_complexity.bib +272 -0
- package/bibliography/T13_reasoning.bib +231 -0
- package/bibliography/T1_canonical.bib +236 -0
- package/bibliography/T2_empirical.bib +258 -0
- package/bibliography/T3_applied.bib +219 -0
- package/bibliography/T4_agentic.bib +281 -0
- package/bibliography/T5_engineering.bib +243 -0
- package/bibliography/T6_governance.bib +277 -0
- package/bibliography/T7_emerging.bib +228 -0
- package/bibliography/T8_cognition.bib +260 -0
- package/bibliography/T9_economics.bib +275 -0
- package/bibliography/hummbl-transformations.json +84 -0
- package/dist/unified-bibliography.json +5699 -0
- package/docs/CONTRIBUTING.md +240 -0
- package/docs/GAP_ANALYSIS.md +142 -0
- package/docs/MULTI_AGENT_COORDINATION_PROTOCOL.md +700 -0
- package/docs/QUALITY_AUDIT_REPORT.md +576 -0
- package/docs/QUALITY_STANDARDS.md +350 -0
- package/docs/TRANSFORMATION_GUIDE.md +337 -0
- package/docs/metrics/model-accuracy.md +150 -0
- package/governance/CAES_CANONICAL.sha256 +1 -0
- package/governance/CAES_SPEC.md +107 -0
- package/governance/CAES_VERSION +1 -0
- package/governance/lexicon/ALLOWLIST_POLICY.md +63 -0
- package/governance/lexicon/CANONICALIZATION.md +63 -0
- package/governance/lexicon/acronym.schema.json +153 -0
- package/governance/lexicon/acronym_allowlist.txt +237 -0
- package/governance/lexicon/acronyms.v0.2.json +2555 -0
- package/llms.txt +1105 -0
- package/mappings/arcana_citations.json +219 -0
- package/mappings/bki_evidence.json +384 -0
- package/package.json +25 -0
- package/reports/.gitkeep +0 -0
- package/reports/citation_graph.json +119335 -0
- package/scripts/add_nist_tags.py +437 -0
- package/scripts/annotate_dois.py +204 -0
- package/scripts/check_palace_aliases.py +200 -0
- package/scripts/ingest_to_open_brain.py +307 -0
- package/scripts/monthly-review.sh +166 -0
- package/scripts/setup-hooks.sh +107 -0
- package/scripts/test_check_palace_aliases.py +194 -0
- package/sources/bki.bib +57 -0
- package/sources/theoretical-foundations.bib +589 -0
- package/toolkit/README.md +360 -0
- package/toolkit/docs/generated/quick-reference.md +179 -0
- package/toolkit/package-lock.json +1140 -0
- package/toolkit/package.json +66 -0
- package/toolkit/scripts/check-memory-palace-aliases.js +230 -0
- package/toolkit/scripts/check-memory-palace-aliases.test.js +297 -0
- package/toolkit/scripts/generate-docs.js +223 -0
- package/toolkit/src/check-duplicates.js +225 -0
- package/toolkit/src/check-required-fields.js +138 -0
- package/toolkit/src/citation-graph.js +425 -0
- package/toolkit/src/extensions/beyondBase120Audit.ts +250 -0
- package/toolkit/src/extensions/memoryPalace.ts +438 -0
- package/toolkit/src/extract-keywords.js +190 -0
- package/toolkit/src/find-missing-dois.js +178 -0
- package/toolkit/src/fix-duplicates.js +140 -0
- package/toolkit/src/merge-entries.js +29 -0
- package/toolkit/src/query.js +281 -0
- package/toolkit/src/stats.js +244 -0
- package/toolkit/src/test-validation.js +117 -0
- package/toolkit/src/utils/modelRegistry.ts +193 -0
- package/toolkit/src/utils/monitorModels.ts +150 -0
- package/toolkit/src/utils/validateModelCode.ts +196 -0
- package/toolkit/src/validate.js +251 -0
- package/toolkit/src/watch.js +100 -0
- package/toolkit/tsconfig.json +25 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Palace — Governed Extension Registry for Beyond-Base120 Mental Models
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Base120 is a closed, versioned canon: 6 transformations × 20 models = 120.
|
|
6
|
+
* It is validated by validateModelCode.ts. No model enters Base120 without a
|
|
7
|
+
* formal extension process and SemVer bump.
|
|
8
|
+
*
|
|
9
|
+
* - The Memory Palace is an open, governed extension library: philosophical lenses,
|
|
10
|
+
* enacted governance archetypes, domain frameworks, and cross-disciplinary models
|
|
11
|
+
* that are VALID and GOVERNED but do not (yet) have a Base120 code.
|
|
12
|
+
*
|
|
13
|
+
* Every entry in the Memory Palace must be registered here with:
|
|
14
|
+
* - A unique slug (kebab-case, e.g. "antifragility")
|
|
15
|
+
* - A source room (category / origin cluster)
|
|
16
|
+
* - A canonical name (how it appears in text)
|
|
17
|
+
* - Aliases (variant names that should resolve to the same entry)
|
|
18
|
+
* - A source reference (where the model originates)
|
|
19
|
+
* - Optional Base120 candidate code (if it's being nominated for promotion)
|
|
20
|
+
*
|
|
21
|
+
* Drift detection: if a model appears in content with a name that does NOT match
|
|
22
|
+
* any canonical name or alias in this registry, it is flagged as UNREGISTERED.
|
|
23
|
+
*
|
|
24
|
+
* Duplicate detection: if two entries share a canonical name or alias, the registry
|
|
25
|
+
* fails to load (hard error).
|
|
26
|
+
*
|
|
27
|
+
* Promotion path: an entry with a candidate_code may be promoted to Base120 via
|
|
28
|
+
* the standard extension process. At promotion, it is removed from Memory Palace
|
|
29
|
+
* and added to BASE120_MODELS in validateModelCode.ts.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Types
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
export type MemoryPalaceRoom =
|
|
37
|
+
| 'ARCANA' // Philosophical lenses from the ARCANA 28-agent platform
|
|
38
|
+
| 'PRAXIS' // Enacted governance archetypes (Aurelius, Cincinnatus, etc.)
|
|
39
|
+
| 'BKI' // Belonging as Knowledge Infrastructure cluster
|
|
40
|
+
| 'TALEB' // Nassim Taleb framework (Antifragility, Black Swan, etc.)
|
|
41
|
+
| 'SYSTEMS' // Systems thinking beyond Base120 SY models
|
|
42
|
+
| 'EPISTEMICS' // Epistemology and reasoning models
|
|
43
|
+
| 'DOMAIN' // Domain-specific models (healthcare, finance, etc.)
|
|
44
|
+
| 'PENDING'; // Nominated but not yet assigned to a room
|
|
45
|
+
|
|
46
|
+
export type SourceType =
|
|
47
|
+
| 'historical-person'
|
|
48
|
+
| 'living-person'
|
|
49
|
+
| 'mythologized-historical'
|
|
50
|
+
| 'fictional-authored'
|
|
51
|
+
| 'mythological'
|
|
52
|
+
| 'collective-pattern';
|
|
53
|
+
|
|
54
|
+
export interface MemoryPalaceEntry {
|
|
55
|
+
slug: string; // Unique kebab-case identifier
|
|
56
|
+
room: MemoryPalaceRoom; // Organisational category
|
|
57
|
+
canonical_name: string; // How this model appears in governed text
|
|
58
|
+
aliases: readonly string[]; // Variant names that resolve to this entry
|
|
59
|
+
source: string; // Origin (author, work, platform)
|
|
60
|
+
source_type?: SourceType; // Machine-readable epistemic authority type
|
|
61
|
+
description: string; // One-line description
|
|
62
|
+
candidate_code?: string; // Base120 nomination code, if any (e.g. "SY21")
|
|
63
|
+
tags: readonly string[]; // Search / filter tags
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Memory Palace Registry
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
export const MEMORY_PALACE: readonly MemoryPalaceEntry[] = [
|
|
71
|
+
|
|
72
|
+
// ── TALEB cluster ─────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
slug: 'antifragility',
|
|
76
|
+
room: 'TALEB',
|
|
77
|
+
canonical_name: 'Antifragility',
|
|
78
|
+
aliases: ['Anti-fragility', 'antifragile'],
|
|
79
|
+
source: 'Nassim Nicholas Taleb, Antifragile (2012)',
|
|
80
|
+
source_type: 'living-person',
|
|
81
|
+
description: 'Systems that gain from disorder, uncertainty, and volatility',
|
|
82
|
+
tags: ['risk', 'resilience', 'uncertainty', 'taleb'],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
slug: 'black-swan',
|
|
86
|
+
room: 'TALEB',
|
|
87
|
+
canonical_name: 'Black Swan',
|
|
88
|
+
aliases: ['Black Swan Event', 'black swan theory'],
|
|
89
|
+
source: 'Nassim Nicholas Taleb, The Black Swan (2007)',
|
|
90
|
+
source_type: 'living-person',
|
|
91
|
+
description: 'High-impact unpredictable events rationalized in hindsight',
|
|
92
|
+
tags: ['risk', 'uncertainty', 'prediction', 'taleb'],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
slug: 'skin-in-the-game',
|
|
96
|
+
room: 'TALEB',
|
|
97
|
+
canonical_name: 'Skin in the Game',
|
|
98
|
+
aliases: ['skin-in-the-game', 'risk-bearing alignment'],
|
|
99
|
+
source: 'Nassim Nicholas Taleb, Skin in the Game (2018)',
|
|
100
|
+
source_type: 'living-person',
|
|
101
|
+
description: 'Alignment of decision-making with risk-bearing as governance mechanism',
|
|
102
|
+
tags: ['governance', 'incentives', 'accountability', 'taleb'],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
slug: 'via-negativa',
|
|
106
|
+
room: 'TALEB',
|
|
107
|
+
canonical_name: 'Via Negativa',
|
|
108
|
+
aliases: ['subtraction principle'],
|
|
109
|
+
source: 'Nassim Nicholas Taleb; apophatic theology tradition',
|
|
110
|
+
source_type: 'living-person',
|
|
111
|
+
description: 'Improvement through subtraction rather than addition',
|
|
112
|
+
tags: ['design', 'simplicity', 'taleb'],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
slug: 'lindy-effect',
|
|
116
|
+
room: 'TALEB',
|
|
117
|
+
canonical_name: 'Lindy Effect',
|
|
118
|
+
aliases: ['Lindy', 'lindy filter'],
|
|
119
|
+
source: 'Nassim Nicholas Taleb (formalised), Benoit Mandelbrot',
|
|
120
|
+
source_type: 'living-person',
|
|
121
|
+
description: 'Expected lifespan of non-perishable things scales with current age',
|
|
122
|
+
tags: ['longevity', 'time', 'durability', 'taleb'],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
slug: 'survivorship-bias',
|
|
126
|
+
room: 'TALEB',
|
|
127
|
+
canonical_name: 'Survivorship Bias',
|
|
128
|
+
aliases: ['survival bias'],
|
|
129
|
+
source: 'Abraham Wald (WWII), popularised by Taleb',
|
|
130
|
+
source_type: 'historical-person',
|
|
131
|
+
description: 'Focusing on survivors while ignoring those that failed',
|
|
132
|
+
tags: ['bias', 'statistics', 'reasoning'],
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
slug: 'fat-tails',
|
|
136
|
+
room: 'TALEB',
|
|
137
|
+
canonical_name: 'Fat Tails',
|
|
138
|
+
aliases: ['fat-tail', 'heavy tails', 'power law tails'],
|
|
139
|
+
source: 'Nassim Nicholas Taleb, The Statistical Consequences of Fat Tails (2020)',
|
|
140
|
+
source_type: 'living-person',
|
|
141
|
+
description: 'Extreme events underweighted by standard statistical models',
|
|
142
|
+
tags: ['statistics', 'risk', 'distribution', 'taleb'],
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// ── EPISTEMICS ─────────────────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
{
|
|
148
|
+
slug: 'ooda-loop',
|
|
149
|
+
room: 'EPISTEMICS',
|
|
150
|
+
canonical_name: 'OODA Loop',
|
|
151
|
+
aliases: ['OODA', 'observe-orient-decide-act'],
|
|
152
|
+
source: 'Colonel John Boyd, USAF (1970s)',
|
|
153
|
+
source_type: 'historical-person',
|
|
154
|
+
description: 'Observe-Orient-Decide-Act decision cycle for dynamic environments',
|
|
155
|
+
tags: ['decision-making', 'military', 'strategy', 'cycles'],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
slug: 'circle-of-competence',
|
|
159
|
+
room: 'EPISTEMICS',
|
|
160
|
+
canonical_name: 'Circle of Competence',
|
|
161
|
+
aliases: ['competence boundary'],
|
|
162
|
+
source: 'Warren Buffett and Charlie Munger, Berkshire Hathaway letters',
|
|
163
|
+
source_type: 'living-person',
|
|
164
|
+
description: 'Knowing the boundaries of one\'s reliable knowledge domain',
|
|
165
|
+
tags: ['epistemics', 'decision-making', 'humility'],
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
slug: 'map-vs-territory',
|
|
169
|
+
room: 'EPISTEMICS',
|
|
170
|
+
canonical_name: 'Map vs Territory',
|
|
171
|
+
aliases: ['Map is not the Territory', 'map-territory distinction'],
|
|
172
|
+
source: 'Alfred Korzybski, Science and Sanity (1933)',
|
|
173
|
+
source_type: 'historical-person',
|
|
174
|
+
description: 'Models of reality are not reality itself; confusing them is a category error',
|
|
175
|
+
tags: ['epistemics', 'representation', 'abstraction'],
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
slug: 'occams-razor',
|
|
179
|
+
room: 'EPISTEMICS',
|
|
180
|
+
canonical_name: "Occam's Razor",
|
|
181
|
+
aliases: ["Ockham's razor", 'parsimony principle'],
|
|
182
|
+
source: 'William of Ockham (~1320)',
|
|
183
|
+
source_type: 'historical-person',
|
|
184
|
+
description: 'Prefer the simplest explanation that fits the evidence',
|
|
185
|
+
tags: ['epistemics', 'simplicity', 'reasoning'],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
slug: 'hanlons-razor',
|
|
189
|
+
room: 'EPISTEMICS',
|
|
190
|
+
canonical_name: "Hanlon's Razor",
|
|
191
|
+
aliases: ['razor of charitable interpretation'],
|
|
192
|
+
source: 'Robert J. Hanlon (attributed)',
|
|
193
|
+
source_type: 'mythologized-historical',
|
|
194
|
+
description: 'Never attribute to malice what can be explained by incompetence',
|
|
195
|
+
tags: ['epistemics', 'attribution', 'reasoning'],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
slug: 'regression-to-mean',
|
|
199
|
+
room: 'EPISTEMICS',
|
|
200
|
+
canonical_name: 'Regression to the Mean',
|
|
201
|
+
aliases: ['regression toward the mean', 'mean reversion'],
|
|
202
|
+
source: 'Francis Galton (1886)',
|
|
203
|
+
source_type: 'historical-person',
|
|
204
|
+
description: 'Extreme measurements tend toward the average on re-measurement',
|
|
205
|
+
tags: ['statistics', 'bias', 'prediction'],
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// ── ARCANA lenses ─────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
{
|
|
211
|
+
slug: 'mimetic-desire',
|
|
212
|
+
room: 'ARCANA',
|
|
213
|
+
canonical_name: 'Mimetic Desire',
|
|
214
|
+
aliases: ['mimetic theory', 'triangular desire'],
|
|
215
|
+
source: 'René Girard, Deceit, Desire and the Novel (1961)',
|
|
216
|
+
source_type: 'historical-person',
|
|
217
|
+
description: 'Desire is borrowed from models/rivals, not intrinsic to objects',
|
|
218
|
+
tags: ['girard', 'desire', 'social', 'arcana'],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
slug: 'scapegoat-mechanism',
|
|
222
|
+
room: 'ARCANA',
|
|
223
|
+
canonical_name: 'Scapegoat Mechanism',
|
|
224
|
+
aliases: ['scapegoating', 'sacrificial mechanism'],
|
|
225
|
+
source: 'René Girard, The Scapegoat (1982)',
|
|
226
|
+
source_type: 'historical-person',
|
|
227
|
+
description: 'Communities resolve mimetic crises through unanimous violence against an arbitrary victim',
|
|
228
|
+
tags: ['girard', 'violence', 'social', 'arcana'],
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// ── PRAXIS lenses ─────────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
{
|
|
234
|
+
slug: 'aurelius',
|
|
235
|
+
room: 'PRAXIS',
|
|
236
|
+
canonical_name: 'Aurelius Lens',
|
|
237
|
+
aliases: ['Marcus Aurelius', 'Reluctant Sovereign'],
|
|
238
|
+
source: 'Marcus Aurelius, Meditations (167–180 CE); PRAXIS module v0.1',
|
|
239
|
+
source_type: 'historical-person',
|
|
240
|
+
description: 'Power exercised with continuous self-audit; governance as private practice made institutional',
|
|
241
|
+
tags: ['praxis', 'stoicism', 'governance', 'accountability'],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
slug: 'cincinnatus',
|
|
245
|
+
room: 'PRAXIS',
|
|
246
|
+
canonical_name: 'Cincinnatus Lens',
|
|
247
|
+
aliases: ['Cincinnatus', 'Temporary Sovereign'],
|
|
248
|
+
source: 'Lucius Quinctius Cincinnatus (458 BCE); PRAXIS module v0.1',
|
|
249
|
+
source_type: 'mythologized-historical',
|
|
250
|
+
description: 'Legitimacy through voluntary relinquishment of authority',
|
|
251
|
+
tags: ['praxis', 'governance', 'accountability', 'kill-switch'],
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
slug: 'demerzel',
|
|
255
|
+
room: 'PRAXIS',
|
|
256
|
+
canonical_name: 'Demerzel Lens',
|
|
257
|
+
aliases: ['Demerzel', 'R. Daneel Olivaw', 'Governor in Plain Sight'],
|
|
258
|
+
source: 'Isaac Asimov, Foundation series; PRAXIS module v0.1',
|
|
259
|
+
source_type: 'fictional-authored',
|
|
260
|
+
description: 'Governance through architecture, defaults, and incentives — not command',
|
|
261
|
+
tags: ['praxis', 'governance', 'architecture', 'psychohistory'],
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
slug: 'prospero',
|
|
265
|
+
room: 'PRAXIS',
|
|
266
|
+
canonical_name: 'Prospero Lens',
|
|
267
|
+
aliases: ['Prospero', 'Knowledge Architect'],
|
|
268
|
+
source: 'Shakespeare, The Tempest (1611); PRAXIS module v0.1',
|
|
269
|
+
source_type: 'fictional-authored',
|
|
270
|
+
description: 'Governance through information asymmetry and model opacity',
|
|
271
|
+
tags: ['praxis', 'governance', 'information', 'transparency'],
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
slug: 'janus',
|
|
275
|
+
room: 'PRAXIS',
|
|
276
|
+
canonical_name: 'Janus Lens',
|
|
277
|
+
aliases: ['Janus', 'Threshold Guardian'],
|
|
278
|
+
source: 'Roman mythology; PRAXIS module v0.1',
|
|
279
|
+
source_type: 'mythological',
|
|
280
|
+
description: 'State management at transitions — onboarding, handoffs, version changes',
|
|
281
|
+
tags: ['praxis', 'governance', 'transitions', 'handoff'],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
slug: 'mond',
|
|
285
|
+
room: 'PRAXIS',
|
|
286
|
+
canonical_name: 'Mond Lens',
|
|
287
|
+
aliases: ['Mustapha Mond', 'Architect of Consent'],
|
|
288
|
+
source: 'Aldous Huxley, Brave New World (1932); PRAXIS module v0.1',
|
|
289
|
+
source_type: 'fictional-authored',
|
|
290
|
+
description: 'Governance by shaping what is thinkable, not by direct force',
|
|
291
|
+
tags: ['praxis', 'governance', 'consent', 'power'],
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
// ── BKI cluster ───────────────────────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
{
|
|
297
|
+
slug: 'belonging-infrastructure',
|
|
298
|
+
room: 'BKI',
|
|
299
|
+
canonical_name: 'Belonging Infrastructure',
|
|
300
|
+
aliases: ['BKI', 'Belonging as Knowledge Infrastructure'],
|
|
301
|
+
source: 'HUMMBL BKI framework; Walton & Cohen 2011; Edmondson 1999',
|
|
302
|
+
source_type: 'collective-pattern',
|
|
303
|
+
description: 'Belonging as structural precondition for knowledge creation and transmission',
|
|
304
|
+
tags: ['bki', 'belonging', 'knowledge', 'governance'],
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
slug: 'biocognitive-os',
|
|
308
|
+
room: 'BKI',
|
|
309
|
+
canonical_name: 'Biocognitive OS',
|
|
310
|
+
aliases: ['Biocognitive Operating System', 'BKI OS'],
|
|
311
|
+
source: 'HUMMBL BKI framework',
|
|
312
|
+
source_type: 'collective-pattern',
|
|
313
|
+
description: 'Six cognitive modes humans shift through depending on belonging conditions',
|
|
314
|
+
tags: ['bki', 'cognition', 'belonging', 'modes'],
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
// ---------------------------------------------------------------------------
|
|
320
|
+
// Registry utilities
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Build a lookup map from canonical name + all aliases → entry.
|
|
325
|
+
* Throws on duplicate names (registry integrity check).
|
|
326
|
+
*/
|
|
327
|
+
function buildLookupMap(): Map<string, MemoryPalaceEntry> {
|
|
328
|
+
const map = new Map<string, MemoryPalaceEntry>();
|
|
329
|
+
|
|
330
|
+
for (const entry of MEMORY_PALACE) {
|
|
331
|
+
const keys = [entry.canonical_name, ...entry.aliases];
|
|
332
|
+
for (const key of keys) {
|
|
333
|
+
const lower = key.toLowerCase();
|
|
334
|
+
if (map.has(lower)) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`Memory Palace duplicate: "${key}" appears in both "${map.get(lower)!.slug}" and "${entry.slug}"`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
map.set(lower, entry);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return map;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const _lookupMap = buildLookupMap();
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Look up a Memory Palace entry by canonical name or alias (case-insensitive).
|
|
350
|
+
* Returns null if not found.
|
|
351
|
+
*/
|
|
352
|
+
export function lookupMemoryPalace(name: string): MemoryPalaceEntry | null {
|
|
353
|
+
return _lookupMap.get(name.toLowerCase()) ?? null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Check if a term is a registered Memory Palace model (canonical or alias).
|
|
358
|
+
*/
|
|
359
|
+
export function isMemoryPalaceModel(name: string): boolean {
|
|
360
|
+
return _lookupMap.has(name.toLowerCase());
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Get all entries for a given room.
|
|
365
|
+
*/
|
|
366
|
+
export function getRoom(room: MemoryPalaceRoom): MemoryPalaceEntry[] {
|
|
367
|
+
return MEMORY_PALACE.filter(e => e.room === room);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get all canonical names (for drift detection scanning).
|
|
372
|
+
*/
|
|
373
|
+
export function getAllCanonicalNames(): string[] {
|
|
374
|
+
return MEMORY_PALACE.map(e => e.canonical_name);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get all aliases across all entries (for alias scanning).
|
|
379
|
+
*/
|
|
380
|
+
export function getAllAliases(): string[] {
|
|
381
|
+
return MEMORY_PALACE.flatMap(e => [...e.aliases]);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get all slugs (for uniqueness checks).
|
|
386
|
+
*/
|
|
387
|
+
export function getAllSlugs(): string[] {
|
|
388
|
+
return MEMORY_PALACE.map(e => e.slug);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Registry health check: returns duplicate slugs, duplicate names, and
|
|
393
|
+
* any entries with missing required fields.
|
|
394
|
+
*/
|
|
395
|
+
export function auditRegistry(): {
|
|
396
|
+
duplicateSlugs: string[];
|
|
397
|
+
duplicateNames: string[];
|
|
398
|
+
missingFields: Array<{ slug: string; fields: string[] }>;
|
|
399
|
+
missingSourceTypes: string[];
|
|
400
|
+
totalEntries: number;
|
|
401
|
+
byRoom: Record<string, number>;
|
|
402
|
+
} {
|
|
403
|
+
const slugs = getAllSlugs();
|
|
404
|
+
const duplicateSlugs = slugs.filter((s, i) => slugs.indexOf(s) !== i);
|
|
405
|
+
|
|
406
|
+
const allNames = MEMORY_PALACE.flatMap(e => [e.canonical_name, ...e.aliases]);
|
|
407
|
+
const lowerNames = allNames.map(n => n.toLowerCase());
|
|
408
|
+
const duplicateNames = allNames.filter((_, i) => lowerNames.indexOf(lowerNames[i]) !== i);
|
|
409
|
+
|
|
410
|
+
const missingFields = MEMORY_PALACE
|
|
411
|
+
.map(e => {
|
|
412
|
+
const missing: string[] = [];
|
|
413
|
+
if (!e.slug) missing.push('slug');
|
|
414
|
+
if (!e.canonical_name) missing.push('canonical_name');
|
|
415
|
+
if (!e.source) missing.push('source');
|
|
416
|
+
if (!e.description) missing.push('description');
|
|
417
|
+
return { slug: e.slug || '(unknown)', fields: missing };
|
|
418
|
+
})
|
|
419
|
+
.filter(r => r.fields.length > 0);
|
|
420
|
+
|
|
421
|
+
const missingSourceTypes = MEMORY_PALACE
|
|
422
|
+
.filter(e => !e.source_type)
|
|
423
|
+
.map(e => e.slug);
|
|
424
|
+
|
|
425
|
+
const byRoom = {} as Record<string, number>;
|
|
426
|
+
for (const e of MEMORY_PALACE) {
|
|
427
|
+
byRoom[e.room] = (byRoom[e.room] ?? 0) + 1;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
duplicateSlugs,
|
|
432
|
+
duplicateNames,
|
|
433
|
+
missingFields,
|
|
434
|
+
missingSourceTypes,
|
|
435
|
+
totalEntries: MEMORY_PALACE.length,
|
|
436
|
+
byRoom,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { Cite } from '@citation-js/core';
|
|
7
|
+
import '@citation-js/plugin-bibtex';
|
|
8
|
+
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const bibDir = args[0] || '../bibliography';
|
|
11
|
+
|
|
12
|
+
class KeywordExtractor {
|
|
13
|
+
constructor(bibDir) {
|
|
14
|
+
this.bibDir = path.resolve(bibDir);
|
|
15
|
+
this.transformationMap = new Map();
|
|
16
|
+
this.entryMap = new Map();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
parseBibTeXRaw(content) {
|
|
20
|
+
const rawEntries = {};
|
|
21
|
+
const entryRegex = /@\w+\{([^,]+),([^@]+?)(?=\n\})/gs;
|
|
22
|
+
let match;
|
|
23
|
+
|
|
24
|
+
while ((match = entryRegex.exec(content)) !== null) {
|
|
25
|
+
const key = match[1].trim();
|
|
26
|
+
const entryText = match[2];
|
|
27
|
+
const fields = {};
|
|
28
|
+
|
|
29
|
+
const lines = entryText.split('\n');
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
const fieldMatch = line.match(/^\s*(\w+)\s*=\s*\{(.+)\}\s*,?\s*$/);
|
|
32
|
+
if (fieldMatch) {
|
|
33
|
+
const [, fieldKey, value] = fieldMatch;
|
|
34
|
+
fields[fieldKey.toLowerCase()] = value.trim();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
rawEntries[key] = fields;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return rawEntries;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
extractTransformations(keywords) {
|
|
45
|
+
const transformations = [];
|
|
46
|
+
if (!keywords) return transformations;
|
|
47
|
+
|
|
48
|
+
const keywordStr = Array.isArray(keywords) ? keywords.join(', ') : keywords;
|
|
49
|
+
const matches = keywordStr.match(/HUMMBL:(P|IN|CO|DE|RE|SY)/g);
|
|
50
|
+
|
|
51
|
+
if (matches) {
|
|
52
|
+
matches.forEach(match => {
|
|
53
|
+
transformations.push(match.replace('HUMMBL:', ''));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return [...new Set(transformations)];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
processEntry(entry, filename, rawEntry = {}) {
|
|
61
|
+
const keywords = rawEntry.keywords || '';
|
|
62
|
+
const transformations = this.extractTransformations(keywords);
|
|
63
|
+
|
|
64
|
+
if (transformations.length > 0) {
|
|
65
|
+
this.entryMap.set(entry.id, {
|
|
66
|
+
title: entry.title,
|
|
67
|
+
file: filename,
|
|
68
|
+
transformations: transformations
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
transformations.forEach(trans => {
|
|
72
|
+
if (!this.transformationMap.has(trans)) {
|
|
73
|
+
this.transformationMap.set(trans, []);
|
|
74
|
+
}
|
|
75
|
+
this.transformationMap.get(trans).push({
|
|
76
|
+
key: entry.id,
|
|
77
|
+
title: entry.title,
|
|
78
|
+
file: filename
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async loadFile(filepath) {
|
|
85
|
+
const filename = path.basename(filepath);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const content = fs.readFileSync(filepath, 'utf8');
|
|
89
|
+
const citation = new Cite(content, { forceType: '@bibtex/text' });
|
|
90
|
+
const entries = citation.data;
|
|
91
|
+
|
|
92
|
+
// Parse raw BibTeX for keywords
|
|
93
|
+
const rawEntries = this.parseBibTeXRaw(content);
|
|
94
|
+
|
|
95
|
+
entries.forEach(entry => {
|
|
96
|
+
const rawEntry = rawEntries[entry.id] || {};
|
|
97
|
+
this.processEntry(entry, filename, rawEntry);
|
|
98
|
+
});
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(chalk.red(`Error loading ${filename}: ${err.message}`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
printReport() {
|
|
105
|
+
console.log('\n' + '='.repeat(60));
|
|
106
|
+
console.log(chalk.cyan.bold(' HUMMBL TRANSFORMATION KEYWORDS'));
|
|
107
|
+
console.log('='.repeat(60));
|
|
108
|
+
|
|
109
|
+
const transNames = {
|
|
110
|
+
P: 'Perspective',
|
|
111
|
+
IN: 'Inversion',
|
|
112
|
+
CO: 'Composition',
|
|
113
|
+
DE: 'Decomposition',
|
|
114
|
+
RE: 'Recursion',
|
|
115
|
+
SY: 'Synthesis'
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const transOrder = ['P', 'IN', 'CO', 'DE', 'RE', 'SY'];
|
|
119
|
+
|
|
120
|
+
transOrder.forEach(trans => {
|
|
121
|
+
const entries = this.transformationMap.get(trans) || [];
|
|
122
|
+
const name = transNames[trans];
|
|
123
|
+
|
|
124
|
+
console.log(chalk.cyan(`\n${trans}: ${name} (${entries.length} entries)`));
|
|
125
|
+
|
|
126
|
+
if (entries.length > 0) {
|
|
127
|
+
entries.forEach((entry, idx) => {
|
|
128
|
+
console.log(chalk.white(` ${idx + 1}. [${entry.key}] ${entry.title.substring(0, 70)}...`));
|
|
129
|
+
console.log(chalk.gray(` ${entry.file}`));
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
console.log(chalk.yellow(' No entries found'));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Entries by transformation count
|
|
137
|
+
console.log(chalk.cyan('\n📊 ENTRIES BY TRANSFORMATION COUNT'));
|
|
138
|
+
|
|
139
|
+
const countMap = new Map();
|
|
140
|
+
this.entryMap.forEach((entry, key) => {
|
|
141
|
+
const count = entry.transformations.length;
|
|
142
|
+
if (!countMap.has(count)) {
|
|
143
|
+
countMap.set(count, []);
|
|
144
|
+
}
|
|
145
|
+
countMap.get(count).push({ key, ...entry });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
Array.from(countMap.keys())
|
|
149
|
+
.sort((a, b) => b - a)
|
|
150
|
+
.forEach(count => {
|
|
151
|
+
const entries = countMap.get(count);
|
|
152
|
+
console.log(chalk.white(`\n ${count} transformation(s): ${entries.length} entries`));
|
|
153
|
+
entries.slice(0, 5).forEach(entry => {
|
|
154
|
+
console.log(chalk.gray(` - [${entry.key}] ${entry.transformations.join(', ')}`));
|
|
155
|
+
});
|
|
156
|
+
if (entries.length > 5) {
|
|
157
|
+
console.log(chalk.gray(` ... and ${entries.length - 5} more`));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
console.log('\n' + '='.repeat(60) + '\n');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async run() {
|
|
165
|
+
// Find all .bib files
|
|
166
|
+
const bibFiles = fs.readdirSync(this.bibDir)
|
|
167
|
+
.filter(f => f.endsWith('.bib'))
|
|
168
|
+
.map(f => path.join(this.bibDir, f));
|
|
169
|
+
|
|
170
|
+
if (bibFiles.length === 0) {
|
|
171
|
+
console.log(chalk.red('\n❌ No .bib files found in ' + this.bibDir));
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Load all files
|
|
176
|
+
for (const filepath of bibFiles) {
|
|
177
|
+
await this.loadFile(filepath);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Print report
|
|
181
|
+
this.printReport();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Run extractor
|
|
186
|
+
const extractor = new KeywordExtractor(bibDir);
|
|
187
|
+
extractor.run().catch(err => {
|
|
188
|
+
console.error(chalk.red('Fatal error:'), err);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
});
|