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,244 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { Cite } from '@citation-js/core';
|
|
8
|
+
import '@citation-js/plugin-bibtex';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const bibDir = args[0] || '../bibliography';
|
|
15
|
+
const jsonOutput = args.includes('--json');
|
|
16
|
+
|
|
17
|
+
class BibStats {
|
|
18
|
+
constructor(bibDir) {
|
|
19
|
+
this.bibDir = path.resolve(bibDir);
|
|
20
|
+
this.stats = {
|
|
21
|
+
total: 0,
|
|
22
|
+
byTier: {},
|
|
23
|
+
byType: {},
|
|
24
|
+
transformations: { P: 0, IN: 0, CO: 0, DE: 0, RE: 0, SY: 0 },
|
|
25
|
+
quality: {
|
|
26
|
+
withDOI: 0,
|
|
27
|
+
withISBN: 0,
|
|
28
|
+
withAbstract: 0,
|
|
29
|
+
withKeywords: 0
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
parseBibTeXRaw(content) {
|
|
35
|
+
const rawEntries = {};
|
|
36
|
+
const entryRegex = /@\w+\{([^,]+),([^@]+?)(?=\n\})/gs;
|
|
37
|
+
let match;
|
|
38
|
+
|
|
39
|
+
while ((match = entryRegex.exec(content)) !== null) {
|
|
40
|
+
const key = match[1].trim();
|
|
41
|
+
const entryText = match[2];
|
|
42
|
+
const fields = {};
|
|
43
|
+
|
|
44
|
+
const lines = entryText.split('\n');
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
const fieldMatch = line.match(/^\s*(\w+)\s*=\s*\{(.+)\}\s*,?\s*$/);
|
|
47
|
+
if (fieldMatch) {
|
|
48
|
+
const [, fieldKey, value] = fieldMatch;
|
|
49
|
+
fields[fieldKey.toLowerCase()] = value.trim();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
rawEntries[key] = fields;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return rawEntries;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
extractTransformations(keywords) {
|
|
60
|
+
const transformations = new Set();
|
|
61
|
+
if (!keywords) return transformations;
|
|
62
|
+
|
|
63
|
+
const keywordStr = Array.isArray(keywords) ? keywords.join(', ') : keywords;
|
|
64
|
+
const matches = keywordStr.match(/HUMMBL:(P|IN|CO|DE|RE|SY)/g);
|
|
65
|
+
|
|
66
|
+
if (matches) {
|
|
67
|
+
matches.forEach(match => {
|
|
68
|
+
const trans = match.replace('HUMMBL:', '');
|
|
69
|
+
transformations.add(trans);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return transformations;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getTier(filename) {
|
|
77
|
+
const match = filename.match(/T(\d+)/);
|
|
78
|
+
if (match) return `T${match[1]}`;
|
|
79
|
+
return 'Unknown';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
processEntry(entry, filename, rawEntry = {}) {
|
|
83
|
+
this.stats.total++;
|
|
84
|
+
|
|
85
|
+
// Count by tier
|
|
86
|
+
const tier = this.getTier(filename);
|
|
87
|
+
this.stats.byTier[tier] = (this.stats.byTier[tier] || 0) + 1;
|
|
88
|
+
|
|
89
|
+
// Count by type
|
|
90
|
+
const type = entry.type || 'unknown';
|
|
91
|
+
this.stats.byType[type] = (this.stats.byType[type] || 0) + 1;
|
|
92
|
+
|
|
93
|
+
// Count transformations from raw keywords
|
|
94
|
+
const keywords = rawEntry.keywords || '';
|
|
95
|
+
const transformations = this.extractTransformations(keywords);
|
|
96
|
+
transformations.forEach(trans => {
|
|
97
|
+
this.stats.transformations[trans]++;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Quality metrics
|
|
101
|
+
if (entry.DOI) this.stats.quality.withDOI++;
|
|
102
|
+
if (entry.ISBN) this.stats.quality.withISBN++;
|
|
103
|
+
|
|
104
|
+
const abstract = rawEntry.abstract || '';
|
|
105
|
+
if (abstract && abstract.length >= 50) this.stats.quality.withAbstract++;
|
|
106
|
+
if (transformations.size > 0) this.stats.quality.withKeywords++;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async loadFile(filepath) {
|
|
110
|
+
const filename = path.basename(filepath);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const content = fs.readFileSync(filepath, 'utf8');
|
|
114
|
+
const citation = new Cite(content, { forceType: '@bibtex/text' });
|
|
115
|
+
const entries = citation.data;
|
|
116
|
+
|
|
117
|
+
// Parse raw BibTeX for additional fields
|
|
118
|
+
const rawEntries = this.parseBibTeXRaw(content);
|
|
119
|
+
|
|
120
|
+
entries.forEach(entry => {
|
|
121
|
+
const rawEntry = rawEntries[entry.id] || {};
|
|
122
|
+
this.processEntry(entry, filename, rawEntry);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return entries.length;
|
|
126
|
+
} catch (err) {
|
|
127
|
+
if (!jsonOutput) {
|
|
128
|
+
console.error(chalk.red(`Error loading ${filename}: ${err.message}`));
|
|
129
|
+
}
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
printReport() {
|
|
135
|
+
console.log('\n' + '='.repeat(60));
|
|
136
|
+
console.log(chalk.cyan.bold(' HUMMBL BIBLIOGRAPHY STATISTICS'));
|
|
137
|
+
console.log('='.repeat(60));
|
|
138
|
+
|
|
139
|
+
// Total entries
|
|
140
|
+
console.log(chalk.cyan('\n📊 OVERVIEW'));
|
|
141
|
+
console.log(chalk.white(`Total Entries: ${chalk.bold(this.stats.total)}`));
|
|
142
|
+
|
|
143
|
+
// By tier
|
|
144
|
+
console.log(chalk.cyan('\n📚 BY TIER'));
|
|
145
|
+
Object.entries(this.stats.byTier).forEach(([tier, count]) => {
|
|
146
|
+
const percentage = ((count / this.stats.total) * 100).toFixed(1);
|
|
147
|
+
const bar = '█'.repeat(Math.floor(count / 2));
|
|
148
|
+
console.log(chalk.white(` ${tier}: ${chalk.bold(count.toString().padStart(2))} (${percentage}%) ${chalk.blue(bar)}`));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// By type
|
|
152
|
+
console.log(chalk.cyan('\n📖 BY TYPE'));
|
|
153
|
+
Object.entries(this.stats.byType)
|
|
154
|
+
.sort((a, b) => b[1] - a[1])
|
|
155
|
+
.forEach(([type, count]) => {
|
|
156
|
+
const percentage = ((count / this.stats.total) * 100).toFixed(1);
|
|
157
|
+
console.log(chalk.white(` ${type.padEnd(15)}: ${chalk.bold(count.toString().padStart(2))} (${percentage}%)`));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Transformations
|
|
161
|
+
console.log(chalk.cyan('\n🔄 HUMMBL TRANSFORMATIONS'));
|
|
162
|
+
const transNames = {
|
|
163
|
+
P: 'Perspective',
|
|
164
|
+
IN: 'Inversion',
|
|
165
|
+
CO: 'Composition',
|
|
166
|
+
DE: 'Decomposition',
|
|
167
|
+
RE: 'Recursion',
|
|
168
|
+
SY: 'Synthesis'
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
Object.entries(this.stats.transformations)
|
|
172
|
+
.sort((a, b) => b[1] - a[1])
|
|
173
|
+
.forEach(([trans, count]) => {
|
|
174
|
+
const bar = '█'.repeat(Math.floor(count / 2));
|
|
175
|
+
console.log(chalk.white(` ${trans.padEnd(2)} (${transNames[trans].padEnd(13)}): ${chalk.bold(count.toString().padStart(2))} ${chalk.green(bar)}`));
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Quality metrics
|
|
179
|
+
console.log(chalk.cyan('\n✨ QUALITY METRICS'));
|
|
180
|
+
const qualityMetrics = [
|
|
181
|
+
{ label: 'Entries with DOI', count: this.stats.quality.withDOI },
|
|
182
|
+
{ label: 'Entries with ISBN', count: this.stats.quality.withISBN },
|
|
183
|
+
{ label: 'Entries with Abstract', count: this.stats.quality.withAbstract },
|
|
184
|
+
{ label: 'Entries with HUMMBL Keywords', count: this.stats.quality.withKeywords }
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
qualityMetrics.forEach(metric => {
|
|
188
|
+
const percentage = ((metric.count / this.stats.total) * 100).toFixed(1);
|
|
189
|
+
const color = percentage >= 80 ? 'green' : percentage >= 50 ? 'yellow' : 'red';
|
|
190
|
+
console.log(chalk.white(` ${metric.label.padEnd(30)}: ${chalk.bold(metric.count.toString().padStart(2))} (${chalk[color](percentage + '%')})`));
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Gap analysis
|
|
194
|
+
console.log(chalk.cyan('\n📈 GAP ANALYSIS'));
|
|
195
|
+
const avgTransformations = Object.values(this.stats.transformations).reduce((a, b) => a + b, 0) / 6;
|
|
196
|
+
const gaps = Object.entries(this.stats.transformations)
|
|
197
|
+
.filter(([, count]) => count < avgTransformations)
|
|
198
|
+
.sort((a, b) => a[1] - b[1]);
|
|
199
|
+
|
|
200
|
+
if (gaps.length > 0) {
|
|
201
|
+
console.log(chalk.yellow(` Average coverage: ${avgTransformations.toFixed(1)} entries per transformation`));
|
|
202
|
+
console.log(chalk.yellow(` Need more entries for: ${gaps.map(([t]) => t).join(', ')}`));
|
|
203
|
+
} else {
|
|
204
|
+
console.log(chalk.green(' ✓ Balanced transformation coverage'));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.log('\n' + '='.repeat(60) + '\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async run() {
|
|
211
|
+
// Find all .bib files
|
|
212
|
+
const bibFiles = fs.readdirSync(this.bibDir)
|
|
213
|
+
.filter(f => f.endsWith('.bib'))
|
|
214
|
+
.map(f => path.join(this.bibDir, f));
|
|
215
|
+
|
|
216
|
+
if (bibFiles.length === 0) {
|
|
217
|
+
if (!jsonOutput) {
|
|
218
|
+
console.log(chalk.red('\n❌ No .bib files found in ' + this.bibDir));
|
|
219
|
+
}
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Load all files
|
|
224
|
+
for (const filepath of bibFiles) {
|
|
225
|
+
await this.loadFile(filepath);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Output results
|
|
229
|
+
if (jsonOutput) {
|
|
230
|
+
console.log(JSON.stringify(this.stats, null, 2));
|
|
231
|
+
} else {
|
|
232
|
+
this.printReport();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Run stats
|
|
238
|
+
const stats = new BibStats(bibDir);
|
|
239
|
+
stats.run().catch(err => {
|
|
240
|
+
if (!jsonOutput) {
|
|
241
|
+
console.error(chalk.red('Fatal error:'), err);
|
|
242
|
+
}
|
|
243
|
+
process.exit(1);
|
|
244
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script for HUMMBL Base120 model validation and Memory Palace audit
|
|
5
|
+
* Run with: node src/test-validation.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { validateModelCode } from './utils/validateModelCode.js';
|
|
9
|
+
import { monitorModelReferences } from './utils/monitorModels.js';
|
|
10
|
+
import { isMemoryPalaceModel, lookupMemoryPalace, auditRegistry } from './extensions/memoryPalace.js';
|
|
11
|
+
import { auditBeyondBase120, scanForExtendedModels } from './extensions/beyondBase120Audit.js';
|
|
12
|
+
|
|
13
|
+
console.log('🧪 Testing HUMMBL Base120 Model Validation\n');
|
|
14
|
+
|
|
15
|
+
// Test valid models
|
|
16
|
+
console.log('✅ Testing valid model codes:');
|
|
17
|
+
const validTests = ['P1', 'IN15', 'CO7', 'DE3', 'RE20', 'SY5'];
|
|
18
|
+
|
|
19
|
+
validTests.forEach(code => {
|
|
20
|
+
const result = validateModelCode(code);
|
|
21
|
+
if (result.isValid) {
|
|
22
|
+
console.log(` ${code} → "${result.name}" (${result.transformation}) ✅`);
|
|
23
|
+
} else {
|
|
24
|
+
console.log(` ${code} → ERROR: ${result.error} ❌`);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
console.log('\n❌ Testing invalid model codes:');
|
|
29
|
+
const invalidTests = ['P21', 'XX1', 'P0', 'IN', 'CO99'];
|
|
30
|
+
|
|
31
|
+
invalidTests.forEach(code => {
|
|
32
|
+
const result = validateModelCode(code);
|
|
33
|
+
console.log(` ${code} → ${result.error} ✅ (correctly rejected)`);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log('\n📚 Testing Memory Palace registry:');
|
|
37
|
+
const memoryPalaceTests = [
|
|
38
|
+
{ term: 'Antifragility', expected: true },
|
|
39
|
+
{ term: 'Black Swan', expected: true },
|
|
40
|
+
{ term: 'OODA Loop', expected: true },
|
|
41
|
+
{ term: 'Skin in the Game', expected: true },
|
|
42
|
+
{ term: 'Aurelius Lens', expected: true },
|
|
43
|
+
{ term: 'Mimetic Desire', expected: true },
|
|
44
|
+
{ term: 'Belonging Infrastructure', expected: true },
|
|
45
|
+
{ term: 'RandomFakeModel', expected: false },
|
|
46
|
+
{ term: 'SomethingNotRegistered', expected: false },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
memoryPalaceTests.forEach(({ term, expected }) => {
|
|
50
|
+
const found = isMemoryPalaceModel(term);
|
|
51
|
+
const pass = found === expected;
|
|
52
|
+
const status = pass ? '✅' : '❌';
|
|
53
|
+
if (found) {
|
|
54
|
+
const entry = lookupMemoryPalace(term);
|
|
55
|
+
console.log(` "${term}" → registered (${entry.room}, ${entry.source_type ?? 'unset'}) ${status}`);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(` "${term}" → not registered ${status}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log('\n🏛️ Memory Palace registry health:');
|
|
62
|
+
const health = auditRegistry();
|
|
63
|
+
console.log(` Total entries: ${health.totalEntries}`);
|
|
64
|
+
Object.entries(health.byRoom).forEach(([room, count]) => {
|
|
65
|
+
console.log(` ${room}: ${count}`);
|
|
66
|
+
});
|
|
67
|
+
if (health.duplicateSlugs.length > 0) {
|
|
68
|
+
console.log(` ❌ Duplicate slugs: ${health.duplicateSlugs.join(', ')}`);
|
|
69
|
+
} else {
|
|
70
|
+
console.log(` ✅ No duplicate slugs`);
|
|
71
|
+
}
|
|
72
|
+
if (health.duplicateNames.length > 0) {
|
|
73
|
+
console.log(` ❌ Duplicate names: ${health.duplicateNames.join(', ')}`);
|
|
74
|
+
} else {
|
|
75
|
+
console.log(` ✅ No duplicate names`);
|
|
76
|
+
}
|
|
77
|
+
if (health.missingSourceTypes.length > 0) {
|
|
78
|
+
console.log(` ⚠️ Missing source_type: ${health.missingSourceTypes.join(', ')}`);
|
|
79
|
+
} else {
|
|
80
|
+
console.log(` ✅ All entries have source_type`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log('\n🔭 Testing Beyond-Base120 audit:');
|
|
84
|
+
const governedText = `
|
|
85
|
+
This framework applies Antifragility principles when designing for uncertainty.
|
|
86
|
+
The Scapegoat Mechanism reveals how communities handle mimetic crises.
|
|
87
|
+
The Aurelius Lens suggests governors should maintain continuous self-audit.
|
|
88
|
+
We use the OODA Loop for rapid decision cycles in dynamic environments.
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const audit = auditBeyondBase120(governedText);
|
|
92
|
+
console.log(` Terms scanned: ${audit.stats.total_terms_scanned}`);
|
|
93
|
+
console.log(` Registered: ${audit.stats.registered}`);
|
|
94
|
+
console.log(` Unregistered: ${audit.stats.unregistered}`);
|
|
95
|
+
if (audit.findings.length === 0) {
|
|
96
|
+
console.log(` ✅ All extended model references are registered`);
|
|
97
|
+
} else {
|
|
98
|
+
audit.findings.forEach(f => {
|
|
99
|
+
const icon = f.severity === 'ERROR' ? '❌' : '⚠️';
|
|
100
|
+
console.log(` ${icon} [${f.code}] ${f.term}: ${f.message}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log('\n📊 Testing runtime monitoring:');
|
|
105
|
+
const testOutput = `
|
|
106
|
+
Let's apply P1 (First Principles Framing) to break this down.
|
|
107
|
+
Using DE3 (Modularization) will help organize the code.
|
|
108
|
+
Don't forget IN2 (Premortem Analysis) before deployment.
|
|
109
|
+
Antifragility thinking applies here too.
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const monitoring = monitorModelReferences(testOutput);
|
|
113
|
+
console.log(`Valid references: ${monitoring.valid.join(', ')}`);
|
|
114
|
+
console.log(`Invalid references: ${monitoring.invalid.join(', ') || 'none'}`);
|
|
115
|
+
console.log(`Hallucinations: ${monitoring.hallucinations.join(', ') || 'none (governed extension audit handles this now)'}`);
|
|
116
|
+
|
|
117
|
+
console.log('\n🎉 Validation system ready for production use!');
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HUMMBL Base120 Model Registry Service
|
|
3
|
+
* Centralized validation and lookup service for mental models
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { validateModelCode, BASE120_MODELS, TransformationType, ModelCode } from './validateModelCode.js';
|
|
7
|
+
|
|
8
|
+
export interface ModelDefinition {
|
|
9
|
+
code: ModelCode;
|
|
10
|
+
name: string;
|
|
11
|
+
transformation: TransformationType;
|
|
12
|
+
description: string;
|
|
13
|
+
example?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Singleton Model Registry
|
|
17
|
+
export class ModelRegistry {
|
|
18
|
+
private static instance: ModelRegistry;
|
|
19
|
+
private models: Map<ModelCode, ModelDefinition>;
|
|
20
|
+
|
|
21
|
+
private constructor() {
|
|
22
|
+
this.models = this.loadBase120();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static getInstance(): ModelRegistry {
|
|
26
|
+
if (!ModelRegistry.instance) {
|
|
27
|
+
ModelRegistry.instance = new ModelRegistry();
|
|
28
|
+
}
|
|
29
|
+
return ModelRegistry.instance;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load all Base120 models into registry
|
|
34
|
+
*/
|
|
35
|
+
private loadBase120(): Map<ModelCode, ModelDefinition> {
|
|
36
|
+
const registry = new Map<ModelCode, ModelDefinition>();
|
|
37
|
+
|
|
38
|
+
Object.entries(BASE120_MODELS).forEach(([transformation, models]) => {
|
|
39
|
+
models.forEach((name, index) => {
|
|
40
|
+
const code = `${transformation}${index + 1}` as ModelCode;
|
|
41
|
+
registry.set(code, {
|
|
42
|
+
code,
|
|
43
|
+
name,
|
|
44
|
+
transformation: transformation as TransformationType,
|
|
45
|
+
description: this.getDefaultDescription(code),
|
|
46
|
+
example: this.getDefaultExample(code)
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return registry;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate a model code
|
|
56
|
+
*/
|
|
57
|
+
validate(code: string): ReturnType<typeof validateModelCode> {
|
|
58
|
+
return validateModelCode(code);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get model definition by code
|
|
63
|
+
*/
|
|
64
|
+
getModel(code: ModelCode): ModelDefinition | null {
|
|
65
|
+
return this.models.get(code) || null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Search models by name or description
|
|
70
|
+
*/
|
|
71
|
+
search(query: string): ModelCode[] {
|
|
72
|
+
const results: ModelCode[] = [];
|
|
73
|
+
const lowerQuery = query.toLowerCase();
|
|
74
|
+
|
|
75
|
+
this.models.forEach((def, code) => {
|
|
76
|
+
if (def.name.toLowerCase().includes(lowerQuery) ||
|
|
77
|
+
def.description.toLowerCase().includes(lowerQuery)) {
|
|
78
|
+
results.push(code);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return results;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get all models for a transformation
|
|
87
|
+
*/
|
|
88
|
+
getTransformationModels(transformation: TransformationType): ModelDefinition[] {
|
|
89
|
+
const models: ModelDefinition[] = [];
|
|
90
|
+
this.models.forEach(def => {
|
|
91
|
+
if (def.transformation === transformation) {
|
|
92
|
+
models.push(def);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return models;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get all models
|
|
100
|
+
*/
|
|
101
|
+
getAllModels(): ModelDefinition[] {
|
|
102
|
+
return Array.from(this.models.values());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Comprehensive audit of text
|
|
107
|
+
*/
|
|
108
|
+
auditText(text: string): {
|
|
109
|
+
references: Array<{code: string, definition?: ModelDefinition, isValid: boolean}>;
|
|
110
|
+
hallucinations: string[];
|
|
111
|
+
validationErrors: string[];
|
|
112
|
+
} {
|
|
113
|
+
const references = this.extractReferences(text);
|
|
114
|
+
const hallucinations = this.detectHallucinations(text);
|
|
115
|
+
const validationErrors = this.findValidationErrors(text);
|
|
116
|
+
|
|
117
|
+
return { references, hallucinations, validationErrors };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract model references from text
|
|
122
|
+
*/
|
|
123
|
+
private extractReferences(text: string): Array<{code: string, definition?: ModelDefinition, isValid: boolean}> {
|
|
124
|
+
const modelPattern = /(P|IN|CO|DE|RE|SY)(\d+)/g;
|
|
125
|
+
const matches = [...text.matchAll(modelPattern)];
|
|
126
|
+
|
|
127
|
+
return matches.map(([fullMatch, transformation, num]) => {
|
|
128
|
+
const code = `${transformation}${num}`;
|
|
129
|
+
const result = validateModelCode(code);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
code,
|
|
133
|
+
definition: result.isValid ? this.models.get(code as ModelCode) : undefined,
|
|
134
|
+
isValid: result.isValid
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Hallucination detection removed — use beyondBase120Audit.ts (Memory Palace)
|
|
141
|
+
* for extended model drift detection. No-op retained for interface compat.
|
|
142
|
+
*/
|
|
143
|
+
private detectHallucinations(_text: string): string[] {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Find validation errors
|
|
149
|
+
*/
|
|
150
|
+
private findValidationErrors(text: string): string[] {
|
|
151
|
+
const errors: string[] = [];
|
|
152
|
+
const references = this.extractReferences(text);
|
|
153
|
+
|
|
154
|
+
references.forEach(ref => {
|
|
155
|
+
if (!ref.isValid) {
|
|
156
|
+
errors.push(`Invalid model code: ${ref.code}`);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return errors;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get default description for a model (placeholder)
|
|
165
|
+
*/
|
|
166
|
+
private getDefaultDescription(code: ModelCode): string {
|
|
167
|
+
// In a full implementation, this would have detailed descriptions
|
|
168
|
+
// For now, return a basic description
|
|
169
|
+
const result = validateModelCode(code);
|
|
170
|
+
return result.name ? `HUMMBL Base120 model: ${result.name}` : 'Unknown model';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get default example for a model (placeholder)
|
|
175
|
+
*/
|
|
176
|
+
private getDefaultExample(code: ModelCode): string {
|
|
177
|
+
// In a full implementation, this would have usage examples
|
|
178
|
+
return `Example usage of ${code}`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Health check
|
|
183
|
+
*/
|
|
184
|
+
healthCheck(): { status: 'healthy' | 'unhealthy', modelCount: number } {
|
|
185
|
+
const modelCount = this.models.size;
|
|
186
|
+
const expectedCount = 120; // 6 transformations × 20 models each
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
status: modelCount === expectedCount ? 'healthy' : 'unhealthy',
|
|
190
|
+
modelCount
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime monitoring for HUMMBL Base120 model references
|
|
3
|
+
* Prevents hallucination by monitoring agent outputs in real-time
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { validateModelCode, ModelCode } from './validateModelCode.js';
|
|
7
|
+
|
|
8
|
+
export interface AuditReport {
|
|
9
|
+
references: ModelReference[];
|
|
10
|
+
hallucinations: string[];
|
|
11
|
+
validationErrors: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ModelReference {
|
|
15
|
+
code: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
isValid: boolean;
|
|
18
|
+
position: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Monitors agent output for mental model references and hallucinations
|
|
23
|
+
*/
|
|
24
|
+
export function monitorModelReferences(output: string): {
|
|
25
|
+
valid: ModelCode[];
|
|
26
|
+
invalid: string[];
|
|
27
|
+
hallucinations: string[];
|
|
28
|
+
} {
|
|
29
|
+
const modelPattern = /(P|IN|CO|DE|RE|SY)(\d+)/g;
|
|
30
|
+
const matches = [...output.matchAll(modelPattern)];
|
|
31
|
+
|
|
32
|
+
const valid: ModelCode[] = [];
|
|
33
|
+
const invalid: string[] = [];
|
|
34
|
+
|
|
35
|
+
matches.forEach(([fullMatch, transformation, num]) => {
|
|
36
|
+
const code = `${transformation}${num}`;
|
|
37
|
+
const result = validateModelCode(code);
|
|
38
|
+
|
|
39
|
+
if (result.isValid) {
|
|
40
|
+
valid.push(code as ModelCode);
|
|
41
|
+
} else {
|
|
42
|
+
invalid.push(code);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Check for hallucinated terms
|
|
47
|
+
const hallucinations = detectHallucinations(output);
|
|
48
|
+
|
|
49
|
+
return { valid, invalid, hallucinations };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Comprehensive audit of text for model compliance
|
|
54
|
+
*/
|
|
55
|
+
export function auditText(text: string): AuditReport {
|
|
56
|
+
const references = extractReferences(text);
|
|
57
|
+
const hallucinations = detectHallucinations(text);
|
|
58
|
+
const validationErrors = findValidationErrors(text);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
references,
|
|
62
|
+
hallucinations,
|
|
63
|
+
validationErrors
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Extract all model references from text
|
|
69
|
+
*/
|
|
70
|
+
function extractReferences(text: string): ModelReference[] {
|
|
71
|
+
const modelPattern = /(P|IN|CO|DE|RE|SY)(\d+)/g;
|
|
72
|
+
const matches = [...text.matchAll(modelPattern)];
|
|
73
|
+
|
|
74
|
+
return matches.map((match, index) => {
|
|
75
|
+
const code = `${match[1]}${match[2]}`;
|
|
76
|
+
const result = validateModelCode(code);
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
code,
|
|
80
|
+
name: result.name,
|
|
81
|
+
isValid: result.isValid,
|
|
82
|
+
position: match.index || 0
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Detect hallucinated mental model references.
|
|
89
|
+
* Governed ARCANA models and BaseN extensions are excluded from hallucination
|
|
90
|
+
* detection — they are first-class governed models, not noise.
|
|
91
|
+
*/
|
|
92
|
+
/**
|
|
93
|
+
* Hallucination detection removed — use beyondBase120Audit.ts (Memory Palace)
|
|
94
|
+
* for extended model drift detection. No-op retained for interface compat.
|
|
95
|
+
*/
|
|
96
|
+
function detectHallucinations(_text: string): string[] {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Find validation errors in model references
|
|
102
|
+
*/
|
|
103
|
+
function findValidationErrors(text: string): string[] {
|
|
104
|
+
const errors: string[] = [];
|
|
105
|
+
const references = extractReferences(text);
|
|
106
|
+
|
|
107
|
+
references.forEach(ref => {
|
|
108
|
+
if (!ref.isValid) {
|
|
109
|
+
errors.push(`Invalid model code: ${ref.code}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return errors;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if output passes model validation
|
|
118
|
+
*/
|
|
119
|
+
export function passesValidation(output: string): boolean {
|
|
120
|
+
const { invalid, hallucinations } = monitorModelReferences(output);
|
|
121
|
+
return invalid.length === 0 && hallucinations.length === 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Generate validation report for logging
|
|
126
|
+
*/
|
|
127
|
+
export function generateValidationReport(output: string): string {
|
|
128
|
+
const audit = auditText(output);
|
|
129
|
+
const { valid, invalid, hallucinations } = monitorModelReferences(output);
|
|
130
|
+
|
|
131
|
+
let report = 'MENTAL MODEL VALIDATION REPORT\n';
|
|
132
|
+
report += '='.repeat(40) + '\n\n';
|
|
133
|
+
|
|
134
|
+
report += `Valid references (${valid.length}): ${valid.join(', ') || 'None'}\n`;
|
|
135
|
+
report += `Invalid references (${invalid.length}): ${invalid.join(', ') || 'None'}\n`;
|
|
136
|
+
report += `Hallucinations detected (${hallucinations.length}): ${hallucinations.join(', ') || 'None'}\n\n`;
|
|
137
|
+
|
|
138
|
+
if (audit.validationErrors.length > 0) {
|
|
139
|
+
report += 'Validation Errors:\n';
|
|
140
|
+
audit.validationErrors.forEach(error => {
|
|
141
|
+
report += `- ${error}\n`;
|
|
142
|
+
});
|
|
143
|
+
report += '\n';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const overallStatus = passesValidation(output) ? '✅ PASS' : '❌ FAIL';
|
|
147
|
+
report += `Overall Status: ${overallStatus}\n`;
|
|
148
|
+
|
|
149
|
+
return report;
|
|
150
|
+
}
|