aisp-validator 0.1.0 → 0.2.1
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/bin/cli.js +62 -13
- package/package.json +1 -1
- package/src/index.js +164 -7
package/bin/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import { readFile } from 'fs/promises';
|
|
|
9
9
|
import { existsSync } from 'fs';
|
|
10
10
|
|
|
11
11
|
const HELP = `
|
|
12
|
-
AISP Validator - Validate AISP 5.1 documents
|
|
12
|
+
AISP Validator v0.2.1 - Validate AISP 5.1 documents
|
|
13
13
|
|
|
14
14
|
Usage:
|
|
15
15
|
aisp-validator <command> [file]
|
|
@@ -19,6 +19,7 @@ Commands:
|
|
|
19
19
|
validate <file> Validate an AISP document
|
|
20
20
|
tier <file> Get quality tier (⊘ to ◊⁺⁺)
|
|
21
21
|
density <file> Get density score (δ)
|
|
22
|
+
debug <file> Show detailed density breakdown
|
|
22
23
|
help Show this help message
|
|
23
24
|
|
|
24
25
|
Quality Tiers:
|
|
@@ -28,10 +29,18 @@ Quality Tiers:
|
|
|
28
29
|
◊⁻ Bronze δ ≥ 0.20
|
|
29
30
|
⊘ Reject δ < 0.20
|
|
30
31
|
|
|
32
|
+
Density Formulas:
|
|
33
|
+
δ (semantic) = (blockScore × 0.4) + (bindingScore × 0.6)
|
|
34
|
+
ρ (pure) = |AISP_symbols| ÷ |non_ws_tokens|
|
|
35
|
+
|
|
36
|
+
blockScore: Required blocks present (⟦Ω⟧, ⟦Σ⟧, ⟦Γ⟧, ⟦Λ⟧, ⟦Ε⟧)
|
|
37
|
+
bindingScore: Semantic operators (≜, ≔, ∀, ∃, λ, ⇒, ∈, etc.)
|
|
38
|
+
pureDensity: Ratio of AISP symbols to total tokens
|
|
39
|
+
|
|
31
40
|
Examples:
|
|
32
41
|
npx aisp-validator validate spec.aisp
|
|
33
42
|
npx aisp-validator tier spec.aisp
|
|
34
|
-
npx aisp-validator spec.aisp
|
|
43
|
+
npx aisp-validator debug spec.aisp
|
|
35
44
|
`;
|
|
36
45
|
|
|
37
46
|
async function main() {
|
|
@@ -42,11 +51,16 @@ async function main() {
|
|
|
42
51
|
process.exit(0);
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
if (args[0] === '--version' || args[0] === '-v') {
|
|
55
|
+
console.log('aisp-validator v0.2.1');
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
45
59
|
let command = args[0];
|
|
46
60
|
let file = args[1];
|
|
47
61
|
|
|
48
62
|
// If first arg is a file (no command), default to validate
|
|
49
|
-
if (command && !['validate', 'tier', 'density'].includes(command)) {
|
|
63
|
+
if (command && !['validate', 'tier', 'density', 'debug'].includes(command)) {
|
|
50
64
|
file = command;
|
|
51
65
|
command = 'validate';
|
|
52
66
|
}
|
|
@@ -65,34 +79,69 @@ async function main() {
|
|
|
65
79
|
try {
|
|
66
80
|
await AISP.init();
|
|
67
81
|
const content = await readFile(file, 'utf-8');
|
|
68
|
-
const result = AISP.validate(content);
|
|
69
82
|
|
|
70
83
|
switch (command) {
|
|
71
|
-
case 'validate':
|
|
84
|
+
case 'validate': {
|
|
85
|
+
const result = AISP.validate(content);
|
|
72
86
|
if (result.valid) {
|
|
73
87
|
console.log(`✓ VALID`);
|
|
74
|
-
console.log(` Tier: ${result.tier}`);
|
|
75
|
-
console.log(`
|
|
76
|
-
console.log(`
|
|
88
|
+
console.log(` Tier: ${result.tier} ${result.tierName}`);
|
|
89
|
+
console.log(` Semantic (δ): ${result.delta.toFixed(3)}`);
|
|
90
|
+
console.log(` Pure (ρ): ${result.pureDensity.toFixed(3)}`);
|
|
91
|
+
console.log(` Ambiguity: ${result.ambiguity.toFixed(3)}`);
|
|
77
92
|
process.exit(0);
|
|
78
93
|
} else {
|
|
79
94
|
console.log(`✗ INVALID`);
|
|
80
95
|
console.log(` Error: ${result.error || `Error code ${result.errorCode}`}`);
|
|
81
96
|
if (result.tier) {
|
|
82
|
-
console.log(` Tier: ${result.tier}`);
|
|
83
|
-
console.log(`
|
|
97
|
+
console.log(` Tier: ${result.tier} ${result.tierName}`);
|
|
98
|
+
console.log(` Semantic (δ): ${result.delta.toFixed(3)}`);
|
|
99
|
+
console.log(` Pure (ρ): ${result.pureDensity.toFixed(3)}`);
|
|
84
100
|
}
|
|
85
101
|
process.exit(1);
|
|
86
102
|
}
|
|
87
103
|
break;
|
|
104
|
+
}
|
|
88
105
|
|
|
89
|
-
case 'tier':
|
|
90
|
-
|
|
106
|
+
case 'tier': {
|
|
107
|
+
const result = AISP.validate(content);
|
|
108
|
+
console.log(`${result.tier} ${result.tierName}`);
|
|
91
109
|
break;
|
|
110
|
+
}
|
|
92
111
|
|
|
93
|
-
case 'density':
|
|
112
|
+
case 'density': {
|
|
113
|
+
const result = AISP.validate(content);
|
|
94
114
|
console.log(result.delta.toFixed(4));
|
|
95
115
|
break;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
case 'debug': {
|
|
119
|
+
const debug = AISP.debug(content);
|
|
120
|
+
console.log(`\nAISP Density Debug`);
|
|
121
|
+
console.log(`==================`);
|
|
122
|
+
console.log(`\nTier: ${debug.tier} ${debug.tierName}`);
|
|
123
|
+
console.log(`Semantic (δ): ${debug.delta.toFixed(3)}`);
|
|
124
|
+
console.log(`Pure (ρ): ${debug.pureDensity.toFixed(3)}`);
|
|
125
|
+
console.log(`\nSemantic Score Breakdown:`);
|
|
126
|
+
console.log(` Block Score: ${(debug.blockScore * 100).toFixed(1)}% (weight: 40%)`);
|
|
127
|
+
console.log(` Binding Score: ${(debug.bindingScore * 100).toFixed(1)}% (weight: 60%)`);
|
|
128
|
+
console.log(`\nBlocks Found: ${debug.breakdown.blocksFound}/${debug.breakdown.blocksRequired}`);
|
|
129
|
+
console.log(` Required: ⟦Ω⟧, ⟦Σ⟧, ⟦Γ⟧, ⟦Λ⟧, ⟦Ε⟧`);
|
|
130
|
+
console.log(`\nSemantic Operators: ${debug.breakdown.totalBindings}`);
|
|
131
|
+
console.log(` ≜ definitions: ${debug.breakdown.definitions}`);
|
|
132
|
+
console.log(` ≔ assignments: ${debug.breakdown.assignments}`);
|
|
133
|
+
console.log(` ∀∃ quantifiers: ${debug.breakdown.quantifiers}`);
|
|
134
|
+
console.log(` λ lambdas: ${debug.breakdown.lambdas}`);
|
|
135
|
+
console.log(` ⇒⇔ implications: ${debug.breakdown.implications}`);
|
|
136
|
+
console.log(` ∈⊆∩∪ set ops: ${debug.breakdown.setOps}`);
|
|
137
|
+
console.log(`\nPure Density Breakdown:`);
|
|
138
|
+
console.log(` AISP Symbols: ${debug.breakdown.symbolCount}`);
|
|
139
|
+
console.log(` Total Tokens: ${debug.breakdown.tokenCount}`);
|
|
140
|
+
console.log(`\nFormulas:`);
|
|
141
|
+
console.log(` δ = (${debug.blockScore.toFixed(2)} × 0.4) + (${debug.bindingScore.toFixed(2)} × 0.6) = ${debug.delta.toFixed(3)}`);
|
|
142
|
+
console.log(` ρ = ${debug.breakdown.symbolCount} ÷ ${debug.breakdown.tokenCount} = ${debug.pureDensity.toFixed(3)}`);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
96
145
|
}
|
|
97
146
|
} catch (err) {
|
|
98
147
|
console.error(`Error: ${err.message}`);
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -10,6 +10,127 @@ import { dirname, join } from 'path';
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
const __dirname = dirname(__filename);
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* AISP Symbol Set (Σ_512 subset for density calculation)
|
|
15
|
+
* Formal symbols that define AISP semantic content
|
|
16
|
+
*/
|
|
17
|
+
const AISP_SYMBOLS = [
|
|
18
|
+
// Block delimiters
|
|
19
|
+
'⟦', '⟧',
|
|
20
|
+
// Operators
|
|
21
|
+
'≜', '≔', '≡', '≢',
|
|
22
|
+
// Quantifiers
|
|
23
|
+
'∀', '∃',
|
|
24
|
+
// Lambda
|
|
25
|
+
'λ',
|
|
26
|
+
// Logic
|
|
27
|
+
'⇒', '⇔', '→', '↔', '∧', '∨', '¬', '⊕',
|
|
28
|
+
// Sets
|
|
29
|
+
'∈', '∉', '⊆', '⊇', '∩', '∪', '∅', '𝒫',
|
|
30
|
+
// Relations
|
|
31
|
+
'≤', '≥', '<', '>',
|
|
32
|
+
// Types
|
|
33
|
+
'ℕ', 'ℤ', 'ℝ', '𝔹', '𝕊',
|
|
34
|
+
// Document
|
|
35
|
+
'𝔸',
|
|
36
|
+
// Tier symbols
|
|
37
|
+
'◊', '⊘',
|
|
38
|
+
// Angle brackets (tuples)
|
|
39
|
+
'⟨', '⟩',
|
|
40
|
+
// Greek letters (commonly used)
|
|
41
|
+
'α', 'β', 'γ', 'δ', 'ε', 'φ', 'τ', 'ρ', 'Ω', 'Σ', 'Γ', 'Λ', 'Ε', 'Θ', 'Χ', 'Δ', 'Π'
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Calculate pure density: |AISP_symbols| ÷ |non_ws_tokens|
|
|
46
|
+
* @param {string} text - AISP source
|
|
47
|
+
* @returns {object} { pureDensity, symbolCount, tokenCount }
|
|
48
|
+
*/
|
|
49
|
+
function calculatePureDensity(text) {
|
|
50
|
+
// Count AISP symbols
|
|
51
|
+
let symbolCount = 0;
|
|
52
|
+
for (const symbol of AISP_SYMBOLS) {
|
|
53
|
+
const matches = text.split(symbol).length - 1;
|
|
54
|
+
symbolCount += matches;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Count non-whitespace tokens (split on whitespace, filter empty)
|
|
58
|
+
const tokens = text.split(/\s+/).filter(t => t.length > 0);
|
|
59
|
+
const tokenCount = tokens.length;
|
|
60
|
+
|
|
61
|
+
// Pure density: ratio of AISP symbols to tokens
|
|
62
|
+
const pureDensity = tokenCount > 0 ? symbolCount / tokenCount : 0;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
pureDensity,
|
|
66
|
+
symbolCount,
|
|
67
|
+
tokenCount
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Calculate semantic density using Block Coverage + Binding Density
|
|
73
|
+
* δ = (blockScore × 0.4) + (bindingScore × 0.6)
|
|
74
|
+
* @param {string} text - AISP source
|
|
75
|
+
* @returns {object} { delta, blockScore, bindingScore, breakdown, pureDensity }
|
|
76
|
+
*/
|
|
77
|
+
function calculateSemanticDensity(text) {
|
|
78
|
+
// Required blocks present?
|
|
79
|
+
const blocks = ['⟦Ω', '⟦Σ', '⟦Γ', '⟦Λ', '⟦Ε'];
|
|
80
|
+
const blocksFound = blocks.filter(b => text.includes(b));
|
|
81
|
+
const blockScore = blocksFound.length / blocks.length;
|
|
82
|
+
|
|
83
|
+
// Binding density (semantic operators)
|
|
84
|
+
const definitions = (text.match(/≜/g) || []).length;
|
|
85
|
+
const assignments = (text.match(/≔/g) || []).length;
|
|
86
|
+
const quantifiers = (text.match(/[∀∃]/g) || []).length;
|
|
87
|
+
const lambdas = (text.match(/λ/g) || []).length;
|
|
88
|
+
const implications = (text.match(/[⇒⇔→↔]/g) || []).length;
|
|
89
|
+
const setOps = (text.match(/[∈⊆∩∪∅]/g) || []).length;
|
|
90
|
+
|
|
91
|
+
const totalBindings = definitions + assignments + quantifiers + lambdas + implications + setOps;
|
|
92
|
+
const bindingScore = Math.min(1, totalBindings / 20);
|
|
93
|
+
|
|
94
|
+
// Combined score (semantic delta)
|
|
95
|
+
const delta = (blockScore * 0.4) + (bindingScore * 0.6);
|
|
96
|
+
|
|
97
|
+
// Pure density (symbol/token ratio)
|
|
98
|
+
const pureResult = calculatePureDensity(text);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
delta,
|
|
102
|
+
blockScore,
|
|
103
|
+
bindingScore,
|
|
104
|
+
pureDensity: pureResult.pureDensity,
|
|
105
|
+
breakdown: {
|
|
106
|
+
blocksFound: blocksFound.length,
|
|
107
|
+
blocksRequired: blocks.length,
|
|
108
|
+
definitions,
|
|
109
|
+
assignments,
|
|
110
|
+
quantifiers,
|
|
111
|
+
lambdas,
|
|
112
|
+
implications,
|
|
113
|
+
setOps,
|
|
114
|
+
totalBindings,
|
|
115
|
+
symbolCount: pureResult.symbolCount,
|
|
116
|
+
tokenCount: pureResult.tokenCount
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get tier from delta value
|
|
123
|
+
* @param {number} delta
|
|
124
|
+
* @returns {object} { tier, tierValue, tierName }
|
|
125
|
+
*/
|
|
126
|
+
function getTierFromDelta(delta) {
|
|
127
|
+
if (delta >= 0.75) return { tier: '◊⁺⁺', tierValue: 4, tierName: 'Platinum' };
|
|
128
|
+
if (delta >= 0.60) return { tier: '◊⁺', tierValue: 3, tierName: 'Gold' };
|
|
129
|
+
if (delta >= 0.40) return { tier: '◊', tierValue: 2, tierName: 'Silver' };
|
|
130
|
+
if (delta >= 0.20) return { tier: '◊⁻', tierValue: 1, tierName: 'Bronze' };
|
|
131
|
+
return { tier: '⊘', tierValue: 0, tierName: 'Reject' };
|
|
132
|
+
}
|
|
133
|
+
|
|
13
134
|
const AISP = {
|
|
14
135
|
_instance: null,
|
|
15
136
|
_memory: null,
|
|
@@ -74,15 +195,40 @@ const AISP = {
|
|
|
74
195
|
};
|
|
75
196
|
}
|
|
76
197
|
|
|
77
|
-
const
|
|
198
|
+
const parseResult = this._instance.aisp_validate(docId);
|
|
199
|
+
|
|
200
|
+
// Use semantic density calculation instead of WASM density
|
|
201
|
+
const densityResult = calculateSemanticDensity(source);
|
|
202
|
+
const tierResult = getTierFromDelta(densityResult.delta);
|
|
78
203
|
|
|
79
204
|
return {
|
|
80
|
-
valid:
|
|
81
|
-
tier:
|
|
82
|
-
tierValue:
|
|
83
|
-
|
|
205
|
+
valid: parseResult === 0,
|
|
206
|
+
tier: tierResult.tier,
|
|
207
|
+
tierValue: tierResult.tierValue,
|
|
208
|
+
tierName: tierResult.tierName,
|
|
209
|
+
delta: densityResult.delta,
|
|
210
|
+
pureDensity: densityResult.pureDensity,
|
|
84
211
|
ambiguity: this._instance.aisp_ambig(docId),
|
|
85
|
-
errorCode:
|
|
212
|
+
errorCode: parseResult
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get detailed density breakdown for debugging
|
|
218
|
+
* @param {string} source - AISP source
|
|
219
|
+
* @returns {object} Detailed breakdown
|
|
220
|
+
*/
|
|
221
|
+
debug(source) {
|
|
222
|
+
const densityResult = calculateSemanticDensity(source);
|
|
223
|
+
const tierResult = getTierFromDelta(densityResult.delta);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
...tierResult,
|
|
227
|
+
delta: densityResult.delta,
|
|
228
|
+
pureDensity: densityResult.pureDensity,
|
|
229
|
+
blockScore: densityResult.blockScore,
|
|
230
|
+
bindingScore: densityResult.bindingScore,
|
|
231
|
+
breakdown: densityResult.breakdown
|
|
86
232
|
};
|
|
87
233
|
},
|
|
88
234
|
|
|
@@ -130,8 +276,19 @@ const AISP = {
|
|
|
130
276
|
async validateFile(filePath) {
|
|
131
277
|
const content = await readFile(filePath, 'utf-8');
|
|
132
278
|
return this.validate(content);
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Debug file - show density breakdown
|
|
283
|
+
* @param {string} filePath - Path to AISP file
|
|
284
|
+
* @returns {Promise<object>} Debug breakdown
|
|
285
|
+
*/
|
|
286
|
+
async debugFile(filePath) {
|
|
287
|
+
const content = await readFile(filePath, 'utf-8');
|
|
288
|
+
return this.debug(content);
|
|
133
289
|
}
|
|
134
290
|
};
|
|
135
291
|
|
|
136
292
|
export default AISP;
|
|
137
|
-
export const { init, validate, isValid, getDensity, getTier, validateFile } = AISP;
|
|
293
|
+
export const { init, validate, isValid, getDensity, getTier, validateFile, debug, debugFile } = AISP;
|
|
294
|
+
export { calculateSemanticDensity, calculatePureDensity, getTierFromDelta, AISP_SYMBOLS };
|