Version: 1.0
Purpose: Human-readable query explanations for approval
HQL (Human Query Language) translates NQL queries into plain language explanations that non-technical users can understand and approve before execution. This approval gate prevents unintended database operations.
HQL uses deterministic templates to ensure accuracy. AI-generated explanations could:
- Downplay dangerous operations
- Hallucinate non-existent safeguards
- Inconsistently describe the same query
Templates guarantee reliable, trustworthy explanations.
Risk is calculated through static analysis (no database queries):
Analyze query structure
↓
Check filter specificity
↓
Assess operation danger
↓
Calculate risk score
↓
Display appropriate warning
Benefits:
- Zero database load
- Instant feedback
- No race conditions
- Consistent results
Operations are classified by risk level:
SAFE (read with filters)
LOW (create, read all)
MEDIUM (update single, delete single)
HIGH (bulk update, bulk delete)
CRITICAL (delete/update all records)
{WARNING_BLOCK}
You're about to {OPERATION} {RESOURCE} {PLURALITY}
{CONDITIONS_BLOCK}
{CHANGES_BLOCK}
Risk: {RISK_LEVEL}
Scope: {SCOPE}
{SAFETY_MESSAGE}
{ACTIONS}
function assessRisk(nqlQuery, schema) {
const analysis = {
operation: nqlQuery.operation,
hasFilter: hasFilter(nqlQuery),
filterType: analyzeFilter(nqlQuery, schema),
riskLevel: 'unknown'
};
// Determine scope
if (!analysis.hasFilter) {
analysis.scope = 'ALL_RECORDS';
analysis.riskLevel = calculateRisk('all', analysis.operation);
} else if (hasPrimaryKeyFilter(nqlQuery, schema)) {
analysis.scope = 'SINGLE_RECORD';
analysis.riskLevel = calculateRisk('single', analysis.operation);
} else if (hasUniqueFieldFilter(nqlQuery, schema)) {
analysis.scope = 'SINGLE_RECORD';
analysis.riskLevel = calculateRisk('single', analysis.operation);
} else {
analysis.scope = 'MULTIPLE_RECORDS';
analysis.riskLevel = calculateRisk('multiple', analysis.operation);
}
return analysis;
}
function calculateRisk(scope, operation) {
const riskMatrix = {
'read': {
'single': 'safe',
'multiple': 'safe',
'all': 'low'
},
'create': {
'single': 'low',
'multiple': 'low',
'all': 'low'
},
'update': {
'single': 'medium',
'multiple': 'high',
'all': 'critical'
},
'delete': {
'single': 'medium',
'multiple': 'high',
'all': 'critical'
}
};
return riskMatrix[operation][scope];
}function hasPrimaryKeyFilter(nqlQuery, schema) {
const filter = nqlQuery.params.filter;
const resource = schema.resources[nqlQuery.resource];
const primaryKey = resource.fields.find(f => f.primary);
if (!primaryKey) return false;
// Check if filter is: { id: { $eq: "value" } }
return filter[primaryKey.name]?.$eq !== undefined;
}
function hasUniqueFieldFilter(nqlQuery, schema) {
const filter = nqlQuery.params.filter;
const resource = schema.resources[nqlQuery.resource];
for (const [fieldName, condition] of Object.entries(filter)) {
const field = resource.fields[fieldName];
if (field?.unique && condition.$eq !== undefined) {
return true;
}
}
return false;
}You're about to READ {RESOURCE} records
Conditions:
- {CONDITION_1}
- {CONDITION_2}
Fields: {FIELD_LIST}
Risk: SAFE
Scope: {SCOPE}
[Preview first 10] [Cancel] [Approve]
You're about to CREATE a new {RESOURCE} record
Data:
- {FIELD_1}: "{VALUE_1}"
- {FIELD_2}: "{VALUE_2}"
Risk: LOW
[Cancel] [Create]
Update Confirmation
You're about to UPDATE 1 {RESOURCE} record
Conditions:
- {ID_FIELD} equals "{ID_VALUE}"
Changes:
- Set {FIELD} to "{VALUE}"
Risk: MEDIUM
Scope: SINGLE RECORD
[Preview record] [Cancel] [Update]
WARNING: BULK UPDATE
You're about to UPDATE {RESOURCE} records
Conditions:
- {CONDITION_1}
Changes:
- Set {FIELD} to "{VALUE}"
Risk: HIGH
Scope: MULTIPLE RECORDS
[Preview affected records] [Cancel] [Continue]
⚠️ CRITICAL: BULK UPDATE
You're about to UPDATE ALL {RESOURCE} records
NO CONDITIONS SPECIFIED - AFFECTS ENTIRE TABLE
Changes:
- Set {FIELD} to "{VALUE}"
Risk: CRITICAL
Scope: ALL RECORDS
This action requires admin approval.
[Cancel]
Delete Confirmation
You're about to DELETE 1 {RESOURCE} record PERMANENTLY
Conditions:
- {ID_FIELD} equals "{ID_VALUE}"
THIS CANNOT BE UNDONE
Risk: MEDIUM
Scope: SINGLE RECORD
[Preview record] [Cancel] [Delete]
WARNING: DELETION OPERATION
You're about to DELETE {RESOURCE} records PERMANENTLY
Conditions:
- {CONDITION_1}
THIS CANNOT BE UNDONE
Risk: HIGH
Scope: MULTIPLE RECORDS
[Preview affected records] [Cancel] [Continue]
⚠️ CRITICAL: BULK DELETION
You're about to DELETE ALL {RESOURCE} records PERMANENTLY
NO CONDITIONS SPECIFIED - DELETES ENTIRE TABLE
THIS CANNOT BE UNDONE
Risk: CRITICAL
Scope: ALL RECORDS
This action is blocked. Contact administrator.
[Cancel]
read → "READ" or "fetch"
create → "CREATE" or "add"
update → "UPDATE" or "modify"
delete → "DELETE" or "remove"
SINGLE RECORD → One record (has unique filter)
MULTIPLE RECORDS → Several records (has non-unique filter)
ALL RECORDS → Entire table (no filter)
Operators translated to natural language:
$eq → "equals"
$ne → "does not equal"
$gt → "greater than"
$gte → "at least"
$lt → "less than"
$lte → "at most"
$in → "is one of"
$nin → "is not one of"
$contains → "contains"
$startsWith → "starts with"
$endsWith → "ends with"
Multiple conditions:
{
"age": { "$gte": 18 },
"status": { "$eq": "active" }
}Displays as:
Conditions:
- age at least 18
- status equals "active"
Logical operators:
{
"$or": [
{ "role": { "$eq": "admin" } },
{ "role": { "$eq": "moderator" } }
]
}Displays as:
Conditions:
- role equals "admin" OR role equals "moderator"
Regular fields: id, name, created_at
Sensitive fields: email (PII), ssn (PII), salary (confidential)
Hidden fields: password_hash (never shown)
Preview is user-initiated (not automatic):
async function generatePreview(nqlQuery) {
// Convert to safe READ operation
const previewQuery = {
...nqlQuery,
operation: 'read',
params: {
...nqlQuery.params,
limit: 10
}
};
// Execute safely
const result = await execute(previewQuery);
return {
records: result.data,
count: result.data.length,
hasMore: result.data.length === 10
};
}Preview dialog:
Preview: Records to be {OPERATION}
Showing first 10 matching records:
┌─────┬──────────────┬──────────┬────────────┐
│ ID │ Email │ Status │ Created │
├─────┼──────────────┼──────────┼────────────┤
│ 123 │ user1@... │ banned │ 2024-01-15 │
│ 456 │ user2@... │ banned │ 2024-02-03 │
│ ... │ ... │ ... │ ... │
└─────┴──────────────┴──────────┴────────────┘
{10+ more records match}
[Cancel] [Proceed]
class HQLGenerator {
generate(nqlQuery, schema, userContext) {
// Static risk analysis (no DB query)
const risk = assessRisk(nqlQuery, schema);
// Select template
const template = this.selectTemplate(
nqlQuery.operation,
risk.riskLevel,
risk.scope
);
// Build context
const context = {
operation: this.formatOperation(nqlQuery.operation),
resource: this.formatResource(nqlQuery.resource),
plurality: this.getPlurality(risk.scope),
conditions: this.formatConditions(nqlQuery.params.filter),
changes: this.formatChanges(nqlQuery.params.data),
fields: this.formatFields(nqlQuery.params.fields, schema),
riskLevel: risk.riskLevel.toUpperCase(),
scope: risk.scope.replace('_', ' '),
warningBlock: this.getWarningBlock(risk.riskLevel)
};
return template.render(context);
}
getWarningBlock(riskLevel) {
if (riskLevel === 'critical') {
return '⚠️ CRITICAL WARNING ⚠️';
}
if (riskLevel === 'high') {
return 'WARNING';
}
return '';
}
getPlurality(scope) {
return scope === 'SINGLE_RECORD' ? 'record' : 'records';
}
}class TemplateEngine {
render(templateString, context) {
return templateString.replace(
/{(\w+)}/g,
(match, key) => context[key] || match
);
}
}┌─────────────────────────────────────────────┐
│ Query Review │
├─────────────────────────────────────────────┤
│ {WARNING_BLOCK} │
│ │
│ {HQL_EXPLANATION} │
│ │
├─────────────────────────────────────────────┤
│ {ACTION_BUTTONS} │
└─────────────────────────────────────────────┘
.approval-dialog.safe {
border-color: green;
}
.approval-dialog.low {
border-color: blue;
}
.approval-dialog.medium {
border-color: orange;
}
.approval-dialog.high {
border-color: red;
}
.approval-dialog.critical {
border-color: darkred;
background: #fff5f5;
}Templates support multiple languages:
templates:
read:
en: "You're about to READ {count} {resource} {plurality}"
es: "Vas a LEER {count} {resource}"
ko: "{count}개의 {resource} 레코드를 읽으려고 합니다"
fr: "Vous allez LIRE {count} {resource}"All approval decisions logged:
{
"timestamp": "2024-11-27T14:32:15Z",
"user_id": "uuid-123",
"operation": "delete",
"resource": "users",
"risk_level": "high",
"scope": "multiple_records",
"decision": "approved",
"execution_time_ms": 125
}- Always use static risk analysis (never query database for count)
- Show scope clearly (SINGLE, MULTIPLE, ALL)
- Highlight sensitive fields (PII, confidential)
- Require explicit confirmation for high-risk operations
- Provide preview on demand (not automatically)
- Log all approval decisions for audit
- Use templates (never AI) for safety-critical explanations
Version: 1.0
Status: Draft
License: MIT
Author: nagibaba