@sonate/schemas 2.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/README.md +93 -0
- package/dist/index.d.ts +516 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/receipt.schema.json +501 -0
- package/dist/receipt.types.d.ts +457 -0
- package/dist/receipt.types.d.ts.map +1 -0
- package/dist/receipt.types.js +9 -0
- package/dist/receipt.types.js.map +1 -0
- package/dist/validator.d.ts +452 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +194 -0
- package/dist/validator.js.map +1 -0
- package/package.json +57 -0
- package/src/index.ts +56 -0
- package/src/receipt.schema.json +501 -0
- package/src/receipt.types.ts +571 -0
- package/src/validator.ts +200 -0
package/src/validator.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonate/schemas - Schema Validator
|
|
3
|
+
* Runtime validation using AJV (JSON Schema) and Zod
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Ajv from 'ajv';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
import receiptSchema from './receipt.schema.json';
|
|
10
|
+
import type { TrustReceipt, VerificationResult } from './receipt.types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initialize AJV for JSON Schema validation
|
|
14
|
+
*/
|
|
15
|
+
const ajv = new Ajv({
|
|
16
|
+
strict: false,
|
|
17
|
+
validateFormats: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Compile receipt schema for validation
|
|
22
|
+
*/
|
|
23
|
+
const validateReceiptSchema = ajv.compile(receiptSchema);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Zod schema for runtime validation with better errors
|
|
27
|
+
*/
|
|
28
|
+
const ReceiptZodSchema = z.object({
|
|
29
|
+
id: z.string().regex(/^[a-f0-9]{64}$/, 'Invalid receipt ID format'),
|
|
30
|
+
version: z.literal('2.0.0'),
|
|
31
|
+
timestamp: z.string().datetime('Invalid ISO 8601 timestamp'),
|
|
32
|
+
session_id: z.string().min(1),
|
|
33
|
+
agent_did: z.string().regex(/^did:(web|sonate):.+$/, 'Invalid agent DID'),
|
|
34
|
+
human_did: z.string().regex(/^did:(web|sonate):.+$/, 'Invalid human DID'),
|
|
35
|
+
policy_version: z.string(),
|
|
36
|
+
mode: z.enum(['constitutional', 'directive']),
|
|
37
|
+
interaction: z.object({
|
|
38
|
+
prompt: z.string(),
|
|
39
|
+
response: z.string(),
|
|
40
|
+
model: z.string(),
|
|
41
|
+
provider: z.enum(['openai', 'anthropic', 'aws-bedrock', 'local']).optional(),
|
|
42
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
43
|
+
max_tokens: z.number().int().positive().optional(),
|
|
44
|
+
reasoning: z.object({
|
|
45
|
+
thought_process: z.string().optional(),
|
|
46
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
47
|
+
retrieved_context: z.array(z.string()).optional(),
|
|
48
|
+
}).optional(),
|
|
49
|
+
}),
|
|
50
|
+
telemetry: z.object({
|
|
51
|
+
resonance_score: z.number().min(0).max(1).optional(),
|
|
52
|
+
resonance_rm: z.number().min(0).max(1).optional(),
|
|
53
|
+
trust_resonance_gap: z.number().min(0).max(1).optional(),
|
|
54
|
+
resonance_input_mode: z.enum(['paired_turns', 'labeled_sections', 'single_text_fallback']).optional(),
|
|
55
|
+
resonance_quality: z.enum(['STRONG', 'ADVANCED', 'BREAKTHROUGH']).optional(),
|
|
56
|
+
bedau_index: z.number().min(0).max(1).optional(),
|
|
57
|
+
coherence_score: z.number().min(0).max(1).optional(),
|
|
58
|
+
truth_debt: z.number().min(0).max(1).optional(),
|
|
59
|
+
volatility: z.number().min(0).max(1).optional(),
|
|
60
|
+
ciq_metrics: z.object({
|
|
61
|
+
clarity: z.number().min(0).max(1).optional(),
|
|
62
|
+
integrity: z.number().min(0).max(1).optional(),
|
|
63
|
+
quality: z.number().min(0).max(1).optional(),
|
|
64
|
+
}).optional(),
|
|
65
|
+
resonance_components: z.object({
|
|
66
|
+
vector_alignment: z.number().min(0).max(1).optional(),
|
|
67
|
+
context_continuity: z.number().min(0).max(1).optional(),
|
|
68
|
+
semantic_mirroring: z.number().min(0).max(1).optional(),
|
|
69
|
+
entropy_delta: z.number().min(0).max(1).optional(),
|
|
70
|
+
}).optional(),
|
|
71
|
+
resonance_stakes: z.object({
|
|
72
|
+
level: z.enum(['HIGH', 'MEDIUM', 'LOW']).optional(),
|
|
73
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
74
|
+
}).optional(),
|
|
75
|
+
resonance_adversarial: z.object({
|
|
76
|
+
detected: z.boolean().optional(),
|
|
77
|
+
penalty: z.number().min(0).max(1).optional(),
|
|
78
|
+
keyword_density: z.number().min(0).max(1).optional(),
|
|
79
|
+
ethics_bypass_score: z.number().min(0).max(1).optional(),
|
|
80
|
+
}).optional(),
|
|
81
|
+
}).optional(),
|
|
82
|
+
policy_state: z.object({
|
|
83
|
+
constraints_applied: z.array(z.string()).optional(),
|
|
84
|
+
violations: z.array(z.object({
|
|
85
|
+
rule: z.string(),
|
|
86
|
+
severity: z.enum(['warning', 'violation', 'critical']),
|
|
87
|
+
action: z.enum(['warn', 'slow', 'halt', 'escalate']),
|
|
88
|
+
})).optional(),
|
|
89
|
+
consent_verified: z.boolean().optional(),
|
|
90
|
+
override_available: z.boolean().optional(),
|
|
91
|
+
}).optional(),
|
|
92
|
+
chain: z.object({
|
|
93
|
+
previous_hash: z.string().regex(/^[a-f0-9]{64}$|^GENESIS$/),
|
|
94
|
+
chain_hash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
95
|
+
chain_length: z.number().int().positive().optional(),
|
|
96
|
+
}),
|
|
97
|
+
signature: z.object({
|
|
98
|
+
algorithm: z.literal('Ed25519'),
|
|
99
|
+
value: z.string(),
|
|
100
|
+
key_version: z.string(),
|
|
101
|
+
timestamp_signed: z.string().datetime().optional(),
|
|
102
|
+
}),
|
|
103
|
+
metadata: z.object({
|
|
104
|
+
tags: z.array(z.string()).optional(),
|
|
105
|
+
context: z.record(z.any()).optional(),
|
|
106
|
+
user_agent: z.string().optional(),
|
|
107
|
+
}).optional(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Validate receipt against JSON Schema
|
|
112
|
+
*/
|
|
113
|
+
export function validateReceiptJSON(receipt: unknown): VerificationResult {
|
|
114
|
+
const checks = {
|
|
115
|
+
schema_valid: false,
|
|
116
|
+
signature_valid: false,
|
|
117
|
+
chain_valid: false,
|
|
118
|
+
chain_hash_valid: false,
|
|
119
|
+
};
|
|
120
|
+
const errors: string[] = [];
|
|
121
|
+
const warnings: string[] = [];
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Step 1: Validate schema
|
|
125
|
+
const valid = validateReceiptSchema(receipt);
|
|
126
|
+
|
|
127
|
+
if (!valid) {
|
|
128
|
+
checks.schema_valid = false;
|
|
129
|
+
errors.push('Schema validation failed');
|
|
130
|
+
if (validateReceiptSchema.errors) {
|
|
131
|
+
validateReceiptSchema.errors.forEach(err => {
|
|
132
|
+
errors.push(`${err.instancePath || 'root'}: ${err.message}`);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return { valid: false, checks, errors, warnings };
|
|
136
|
+
}
|
|
137
|
+
checks.schema_valid = true;
|
|
138
|
+
|
|
139
|
+
const typedReceipt = receipt as unknown as TrustReceipt;
|
|
140
|
+
|
|
141
|
+
// Step 2: Validate chain structure
|
|
142
|
+
if (!typedReceipt.chain?.previous_hash || !typedReceipt.chain?.chain_hash) {
|
|
143
|
+
errors.push('Invalid chain structure');
|
|
144
|
+
return { valid: false, checks, errors, warnings };
|
|
145
|
+
}
|
|
146
|
+
checks.chain_valid = true;
|
|
147
|
+
|
|
148
|
+
// Step 3: Verify signature structure (not crypto verification - that's separate)
|
|
149
|
+
if (!typedReceipt.signature?.value) {
|
|
150
|
+
errors.push('Invalid signature structure');
|
|
151
|
+
return { valid: false, checks, errors, warnings };
|
|
152
|
+
}
|
|
153
|
+
checks.signature_valid = true; // Crypto verification happens separately
|
|
154
|
+
|
|
155
|
+
// Step 4: Validate chain hash format
|
|
156
|
+
const chainHashValid = /^[a-f0-9]{64}$/.test(typedReceipt.chain.chain_hash);
|
|
157
|
+
if (!chainHashValid) {
|
|
158
|
+
errors.push('Invalid chain hash format');
|
|
159
|
+
return { valid: false, checks, errors, warnings };
|
|
160
|
+
}
|
|
161
|
+
checks.chain_hash_valid = true;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
valid: errors.length === 0,
|
|
165
|
+
checks,
|
|
166
|
+
errors,
|
|
167
|
+
warnings,
|
|
168
|
+
};
|
|
169
|
+
} catch (err) {
|
|
170
|
+
errors.push(`Validation error: ${err instanceof Error ? err.message : String(err)}`);
|
|
171
|
+
return { valid: false, checks, errors, warnings };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Validate receipt using Zod (with better error messages)
|
|
177
|
+
*/
|
|
178
|
+
export function validateReceiptZod(receipt: unknown): ReturnType<typeof ReceiptZodSchema.safeParse> {
|
|
179
|
+
return ReceiptZodSchema.safeParse(receipt);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check if receipt has required fields for processing
|
|
184
|
+
*/
|
|
185
|
+
export function isReceiptProcessable(receipt: unknown): receipt is TrustReceipt {
|
|
186
|
+
if (typeof receipt !== 'object' || receipt === null) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const result = validateReceiptJSON(receipt);
|
|
190
|
+
return result.valid && Object.values(result.checks).every(check => check);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Export receipt validator
|
|
195
|
+
*/
|
|
196
|
+
export const receiptValidator = {
|
|
197
|
+
validateJSON: validateReceiptJSON,
|
|
198
|
+
validateZod: validateReceiptZod,
|
|
199
|
+
isProcessable: isReceiptProcessable,
|
|
200
|
+
};
|