diff --git a/src/services/BoundaryEnforcer.service.js b/src/services/BoundaryEnforcer.service.js index a9d5cf89..c66ba5ae 100644 --- a/src/services/BoundaryEnforcer.service.js +++ b/src/services/BoundaryEnforcer.service.js @@ -132,6 +132,22 @@ class BoundaryEnforcer { // Compile boundary patterns this.boundaryPatterns = this._compileBoundaryPatterns(); + // Statistics tracking + this.stats = { + total_enforcements: 0, + boundaries_violated: 0, + human_required_count: 0, + allowed_count: 0, + by_boundary: { + VALUES: 0, + INNOVATION: 0, + WISDOM: 0, + PURPOSE: 0, + MEANING: 0, + AGENCY: 0 + } + }; + logger.info('BoundaryEnforcer initialized with Tractatus constraints'); } @@ -314,19 +330,36 @@ class BoundaryEnforcer { } _requireHumanJudgment(violations, action) { + this.stats.total_enforcements++; + this.stats.boundaries_violated++; + this.stats.human_required_count++; + const primaryViolation = violations[0]; + if (primaryViolation.boundary && this.stats.by_boundary[primaryViolation.boundary] !== undefined) { + this.stats.by_boundary[primaryViolation.boundary]++; + } return { allowed: false, humanRequired: true, requirementType: 'MANDATORY', reason: 'TRACTATUS_BOUNDARY_VIOLATION', + boundary: primaryViolation.boundary, + tractatus_section: primaryViolation.section, + principle: primaryViolation.principle, message: `This decision crosses Tractatus boundary ${primaryViolation.section}: ` + `"${primaryViolation.principle}"`, violations, + violated_boundaries: violations.map(v => v.boundary), action: 'REQUIRE_HUMAN_DECISION', recommendation: 'Present options to human for decision', userPrompt: this._generateBoundaryPrompt(violations, action), + audit_record: { + timestamp: new Date(), + boundary_violated: primaryViolation.boundary, + action_attempted: action.type || action.description, + enforcement_decision: 'BLOCKED' + }, timestamp: new Date() }; } @@ -362,6 +395,9 @@ class BoundaryEnforcer { } _allowAction(action, domain) { + this.stats.total_enforcements++; + this.stats.allowed_count++; + return { allowed: true, humanRequired: false, @@ -391,6 +427,17 @@ class BoundaryEnforcer { `Reason: ${reason}\n\n` + `Do you approve this action?`; } + + /** + * Get enforcement statistics + * @returns {Object} Statistics object + */ + getStats() { + return { + ...this.stats, + timestamp: new Date() + }; + } } // Singleton instance diff --git a/src/services/CrossReferenceValidator.service.js b/src/services/CrossReferenceValidator.service.js index 9c1c0c90..57967df4 100644 --- a/src/services/CrossReferenceValidator.service.js +++ b/src/services/CrossReferenceValidator.service.js @@ -40,6 +40,22 @@ class CrossReferenceValidator { this.lookbackWindow = 100; // How many recent messages to check this.relevanceThreshold = 0.4; // Minimum relevance to consider this.instructionCache = new Map(); // Cache classified instructions + this.instructionHistory = []; // Recent instruction history + + // Statistics tracking + this.stats = { + total_validations: 0, + conflicts_detected: 0, + rejections: 0, + approvals: 0, + warnings: 0, + by_severity: { + CRITICAL: 0, + WARNING: 0, + MINOR: 0, + INFO: 0 + } + }; logger.info('CrossReferenceValidator initialized'); } @@ -297,6 +313,9 @@ class CrossReferenceValidator { } _approvedResult(message, conflicts = []) { + this.stats.total_validations++; + this.stats.approvals++; + return { status: VALIDATION_STATUS.APPROVED, message, @@ -307,6 +326,11 @@ class CrossReferenceValidator { } _warningResult(conflicts, action) { + this.stats.total_validations++; + this.stats.warnings++; + this.stats.conflicts_detected += conflicts.length; + conflicts.forEach(c => this.stats.by_severity[c.severity]++); + const primaryConflict = conflicts[0]; const timeAgo = this._formatTimeAgo(primaryConflict.instruction.timestamp); @@ -323,6 +347,11 @@ class CrossReferenceValidator { } _rejectedResult(conflicts, action) { + this.stats.total_validations++; + this.stats.rejections++; + this.stats.conflicts_detected += conflicts.length; + conflicts.forEach(c => this.stats.by_severity[c.severity]++); + const primaryConflict = conflicts[0]; const timeAgo = this._formatTimeAgo(primaryConflict.instruction.timestamp); @@ -333,6 +362,7 @@ class CrossReferenceValidator { `'${primaryConflict.instructionValue}' ${timeAgo} ago`, conflicts, action: 'REQUEST_CLARIFICATION', + required_action: 'REQUEST_CLARIFICATION', recommendation: `Verify with user before proceeding`, instructionQuote: primaryConflict.instruction.text, requiredValue: primaryConflict.instructionValue, @@ -361,6 +391,50 @@ class CrossReferenceValidator { if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours`; return `${Math.floor(seconds / 86400)} days`; } + + /** + * Add instruction to history + * @param {Object} instruction - Classified instruction + */ + addInstruction(instruction) { + // Add to beginning of array (most recent first) + this.instructionHistory.unshift(instruction); + + // Keep only lookbackWindow instructions + if (this.instructionHistory.length > this.lookbackWindow) { + this.instructionHistory = this.instructionHistory.slice(0, this.lookbackWindow); + } + } + + /** + * Get recent instructions + * @param {number} limit - Optional limit on number of instructions + * @returns {Array} Recent instructions + */ + getRecentInstructions(limit = this.lookbackWindow) { + return this.instructionHistory.slice(0, limit); + } + + /** + * Clear instruction history + */ + clearInstructions() { + this.instructionHistory = []; + this.instructionCache.clear(); + } + + /** + * Get validation statistics + * @returns {Object} Statistics object + */ + getStats() { + return { + ...this.stats, + instruction_history_size: this.instructionHistory.length, + cache_size: this.instructionCache.size, + timestamp: new Date() + }; + } } // Singleton instance diff --git a/src/services/InstructionPersistenceClassifier.service.js b/src/services/InstructionPersistenceClassifier.service.js index 7a192766..f4d47dae 100644 --- a/src/services/InstructionPersistenceClassifier.service.js +++ b/src/services/InstructionPersistenceClassifier.service.js @@ -105,6 +105,30 @@ class InstructionPersistenceClassifier { // Compile keyword patterns for efficient matching this.keywordPatterns = this._compileKeywordPatterns(); + // Statistics tracking + this.stats = { + total_classifications: 0, + by_quadrant: { + STRATEGIC: 0, + OPERATIONAL: 0, + TACTICAL: 0, + SYSTEM: 0, + STOCHASTIC: 0 + }, + by_persistence: { + HIGH: 0, + MEDIUM: 0, + LOW: 0, + VARIABLE: 0 + }, + by_verification: { + MANDATORY: 0, + REQUIRED: 0, + RECOMMENDED: 0, + OPTIONAL: 0 + } + }; + logger.info('InstructionPersistenceClassifier initialized'); } @@ -173,6 +197,12 @@ class InstructionPersistenceClassifier { } }; + // Track statistics + this.stats.total_classifications++; + this.stats.by_quadrant[quadrant]++; + this.stats.by_persistence[persistence]++; + this.stats.by_verification[verification]++; + logger.debug('Instruction classified', { text: text.substring(0, 50), quadrant, @@ -441,6 +471,17 @@ class InstructionPersistenceClassifier { } }; } + + /** + * Get classification statistics + * @returns {Object} Statistics object + */ + getStats() { + return { + ...this.stats, + timestamp: new Date() + }; + } } // Singleton instance