This commit implements critical fixes to stabilize the MongoDB persistence layer
and adds inst_016-018 content validation to BoundaryEnforcer as specified in
instruction history.
## Context
- First session using Anthropic's new API Memory system
- Fixed 3 MongoDB persistence test failures
- Implemented BoundaryEnforcer inst_016-018 trigger logic per user request
- All unit tests now passing (61/61 BoundaryEnforcer, 25/25 BlogCuration)
## Fixes
### 1. CrossReferenceValidator: Port Regex Enhancement
- **File**: src/services/CrossReferenceValidator.service.js:203
- **Issue**: Regex couldn't extract port from "port 27017" (space-delimited format)
- **Fix**: Changed `/port[:=]\s*(\d{4,5})/i` to `/port[:\s=]\s*(\d{4,5})/i`
- **Result**: Now matches "port: X", "port = X", and "port X" formats
- **Tests**: 28/28 CrossReferenceValidator tests passing
### 2. BlogCuration: MongoDB Method Correction
- **File**: src/services/BlogCuration.service.js:187
- **Issue**: Called non-existent `Document.findAll()` method
- **Fix**: Changed to `Document.list({ limit: 20, skip: 0 })`
- **Result**: BlogCuration can now fetch existing documents for topic generation
- **Tests**: 25/25 BlogCuration tests passing
### 3. MemoryProxy: Optional Anthropic API Integration
- **File**: src/services/MemoryProxy.service.js
- **Issue**: Treated Anthropic Memory Tool API as mandatory, causing errors without API key
- **Fix**: Made Anthropic client optional with graceful degradation
- **Architecture**: MongoDB (required) + Anthropic API (optional enhancement)
- **Result**: System functions fully without CLAUDE_API_KEY environment variable
### 4. AuditLog Model: Duplicate Index Fix
- **File**: src/models/AuditLog.model.js:132
- **Issue**: Mongoose warning about duplicate timestamp index
- **Fix**: Removed inline `index: true`, kept TTL index definition at line 149
- **Result**: No more Mongoose duplicate index warnings
### 5. BlogCuration Tests: Mock API Correction
- **File**: tests/unit/BlogCuration.service.test.js
- **Issue**: Tests mocked non-existent `generateBlogTopics()` function
- **Fix**: Updated mocks to use actual `sendMessage()` and `extractJSON()` methods
- **Result**: All 25 BlogCuration tests passing
## New Features
### 6. BoundaryEnforcer: inst_016-018 Content Validation (MAJOR)
- **File**: src/services/BoundaryEnforcer.service.js:508-580
- **Purpose**: Prevent fabricated statistics, absolute guarantees, and unverified claims
- **Implementation**: Added `_checkContentViolations()` private method
- **Enforcement Rules**:
- **inst_017**: Blocks absolute assurance terms (guarantee, 100% secure, never fails)
- **inst_016**: Blocks statistics/ROI/$ amounts without sources
- **inst_018**: Blocks production claims (production-ready, battle-tested) without evidence
- **Mechanism**: All violations classified as VALUES boundary violations (honesty/transparency)
- **Tests**: 22 new comprehensive tests in tests/unit/BoundaryEnforcer.test.js
- **Result**: 61/61 BoundaryEnforcer tests passing
### Regex Pattern for inst_016 (Statistics Detection):
```regex
/\d+(\.\d+)?%|\$[\d,]+|\d+x\s*roi|payback\s*(period)?\s*of\s*\d+|\d+[\s-]*(month|year)s?\s*payback|\d+(\.\d+)?m\s*(saved|savings)/i
```
### Detection Examples:
- ✅ BLOCKS: "This system guarantees 100% security"
- ✅ BLOCKS: "Delivers 1315% ROI without sources"
- ✅ BLOCKS: "Production-ready framework" (without testing_evidence)
- ✅ ALLOWS: "Research shows 85% improvement [source: example.com]"
- ✅ ALLOWS: "Validated framework with testing_evidence provided"
## MongoDB Models (New Files)
- src/models/AuditLog.model.js - Audit log persistence with TTL
- src/models/GovernanceRule.model.js - Governance rules storage
- src/models/SessionState.model.js - Session state tracking
- src/models/VerificationLog.model.js - Verification logs
- src/services/AnthropicMemoryClient.service.js - Optional API integration
## Test Results
- BoundaryEnforcer: 61/61 tests passing (22 new inst_016-018 tests)
- BlogCuration: 25/25 tests passing
- CrossReferenceValidator: 28/28 tests passing
## Framework Compliance
- ✅ Implements inst_016, inst_017, inst_018 enforcement
- ✅ Addresses 2025-10-09 framework failure (fabricated statistics on leader.html)
- ✅ All content generation now subject to honesty/transparency validation
- ✅ Human approval required for statistical claims without sources
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
300 lines
6.8 KiB
JavaScript
300 lines
6.8 KiB
JavaScript
/**
|
|
* GovernanceRule Model
|
|
*
|
|
* Stores Tractatus governance instructions (inst_001, inst_016, etc.)
|
|
* Replaces filesystem-based .claude/instruction-history.json
|
|
*
|
|
* Benefits over filesystem:
|
|
* - Fast indexed queries by ID, quadrant, persistence
|
|
* - Atomic updates (no race conditions)
|
|
* - Aggregation for analytics
|
|
* - Built-in replication/backup
|
|
* - Transaction support
|
|
*/
|
|
|
|
const mongoose = require('mongoose');
|
|
|
|
const governanceRuleSchema = new mongoose.Schema({
|
|
// Rule identification
|
|
id: {
|
|
type: String,
|
|
required: true,
|
|
unique: true,
|
|
index: true,
|
|
description: 'Unique rule identifier (e.g., inst_016, inst_017)'
|
|
},
|
|
|
|
// Rule content
|
|
text: {
|
|
type: String,
|
|
required: true,
|
|
description: 'The governance instruction text'
|
|
},
|
|
|
|
// Classification
|
|
quadrant: {
|
|
type: String,
|
|
required: true,
|
|
enum: ['STRATEGIC', 'OPERATIONAL', 'TACTICAL', 'SYSTEM', 'STORAGE'],
|
|
index: true,
|
|
description: 'Tractatus quadrant classification'
|
|
},
|
|
|
|
persistence: {
|
|
type: String,
|
|
required: true,
|
|
enum: ['HIGH', 'MEDIUM', 'LOW'],
|
|
index: true,
|
|
description: 'Persistence level - how long this rule remains active'
|
|
},
|
|
|
|
// Metadata
|
|
category: {
|
|
type: String,
|
|
enum: ['content', 'security', 'privacy', 'technical', 'process', 'values', 'other'],
|
|
default: 'other',
|
|
index: true,
|
|
description: 'Category for filtering and organization'
|
|
},
|
|
|
|
priority: {
|
|
type: Number,
|
|
default: 50,
|
|
min: 0,
|
|
max: 100,
|
|
description: 'Priority level (100 = highest, 0 = lowest)'
|
|
},
|
|
|
|
// Temporal scope
|
|
temporalScope: {
|
|
type: String,
|
|
enum: ['IMMEDIATE', 'SESSION', 'PROJECT', 'PERMANENT'],
|
|
default: 'PERMANENT',
|
|
description: 'How long this rule applies (IMMEDIATE = one-time, SESSION = this conversation, PROJECT = this project, PERMANENT = always)'
|
|
},
|
|
|
|
expiresAt: {
|
|
type: Date,
|
|
default: null,
|
|
description: 'When this rule expires (null = never)'
|
|
},
|
|
|
|
// Status
|
|
active: {
|
|
type: Boolean,
|
|
default: true,
|
|
index: true,
|
|
description: 'Whether this rule is currently enforced'
|
|
},
|
|
|
|
// Source tracking
|
|
source: {
|
|
type: String,
|
|
enum: ['user_instruction', 'framework_default', 'automated', 'migration', 'test'],
|
|
default: 'framework_default',
|
|
description: 'How this rule was created'
|
|
},
|
|
|
|
createdBy: {
|
|
type: String,
|
|
default: 'system',
|
|
description: 'Who created this rule'
|
|
},
|
|
|
|
// Enforcement statistics
|
|
stats: {
|
|
timesChecked: {
|
|
type: Number,
|
|
default: 0,
|
|
description: 'How many times this rule has been evaluated'
|
|
},
|
|
timesViolated: {
|
|
type: Number,
|
|
default: 0,
|
|
description: 'How many times this rule was violated'
|
|
},
|
|
lastChecked: {
|
|
type: Date,
|
|
default: null,
|
|
description: 'When this rule was last evaluated'
|
|
},
|
|
lastViolated: {
|
|
type: Date,
|
|
default: null,
|
|
description: 'When this rule was last violated'
|
|
}
|
|
},
|
|
|
|
// Additional context
|
|
examples: {
|
|
type: [String],
|
|
default: [],
|
|
description: 'Example scenarios where this rule applies'
|
|
},
|
|
|
|
relatedRules: {
|
|
type: [String],
|
|
default: [],
|
|
description: 'IDs of related rules (e.g., inst_016 relates to inst_017)'
|
|
},
|
|
|
|
notes: {
|
|
type: String,
|
|
default: '',
|
|
description: 'Additional notes or clarifications'
|
|
}
|
|
|
|
}, {
|
|
timestamps: true, // Adds createdAt and updatedAt automatically
|
|
collection: 'governanceRules'
|
|
});
|
|
|
|
// Indexes for common queries
|
|
governanceRuleSchema.index({ quadrant: 1, persistence: 1 });
|
|
governanceRuleSchema.index({ active: 1, priority: -1 });
|
|
governanceRuleSchema.index({ category: 1, active: 1 });
|
|
governanceRuleSchema.index({ expiresAt: 1 }, { sparse: true }); // Sparse index for expiry queries
|
|
|
|
// Virtual for checking if rule is expired
|
|
governanceRuleSchema.virtual('isExpired').get(function() {
|
|
if (!this.expiresAt) return false;
|
|
return new Date() > this.expiresAt;
|
|
});
|
|
|
|
// Static methods
|
|
|
|
/**
|
|
* Find all active rules
|
|
*/
|
|
governanceRuleSchema.statics.findActive = function(options = {}) {
|
|
const query = { active: true };
|
|
|
|
// Filter out expired rules
|
|
query.$or = [
|
|
{ expiresAt: null },
|
|
{ expiresAt: { $gt: new Date() } }
|
|
];
|
|
|
|
return this.find(query)
|
|
.sort({ priority: -1, id: 1 })
|
|
.limit(options.limit || 0);
|
|
};
|
|
|
|
/**
|
|
* Find rules by quadrant
|
|
*/
|
|
governanceRuleSchema.statics.findByQuadrant = function(quadrant, activeOnly = true) {
|
|
const query = { quadrant };
|
|
|
|
if (activeOnly) {
|
|
query.active = true;
|
|
query.$or = [
|
|
{ expiresAt: null },
|
|
{ expiresAt: { $gt: new Date() } }
|
|
];
|
|
}
|
|
|
|
return this.find(query).sort({ priority: -1, id: 1 });
|
|
};
|
|
|
|
/**
|
|
* Find rules by persistence level
|
|
*/
|
|
governanceRuleSchema.statics.findByPersistence = function(persistence, activeOnly = true) {
|
|
const query = { persistence };
|
|
|
|
if (activeOnly) {
|
|
query.active = true;
|
|
query.$or = [
|
|
{ expiresAt: null },
|
|
{ expiresAt: { $gt: new Date() } }
|
|
];
|
|
}
|
|
|
|
return this.find(query).sort({ priority: -1, id: 1 });
|
|
};
|
|
|
|
/**
|
|
* Find rule by ID
|
|
*/
|
|
governanceRuleSchema.statics.findByRuleId = function(ruleId) {
|
|
return this.findOne({ id: ruleId, active: true });
|
|
};
|
|
|
|
/**
|
|
* Get rule statistics summary
|
|
*/
|
|
governanceRuleSchema.statics.getStatistics = async function() {
|
|
const stats = await this.aggregate([
|
|
{ $match: { active: true } },
|
|
{
|
|
$group: {
|
|
_id: null,
|
|
totalRules: { $sum: 1 },
|
|
byQuadrant: {
|
|
$push: {
|
|
quadrant: '$quadrant',
|
|
count: 1
|
|
}
|
|
},
|
|
byPersistence: {
|
|
$push: {
|
|
persistence: '$persistence',
|
|
count: 1
|
|
}
|
|
},
|
|
totalChecks: { $sum: '$stats.timesChecked' },
|
|
totalViolations: { $sum: '$stats.timesViolated' }
|
|
}
|
|
}
|
|
]);
|
|
|
|
return stats[0] || null;
|
|
};
|
|
|
|
/**
|
|
* Increment check counter
|
|
*/
|
|
governanceRuleSchema.methods.incrementChecked = async function() {
|
|
this.stats.timesChecked += 1;
|
|
this.stats.lastChecked = new Date();
|
|
return this.save();
|
|
};
|
|
|
|
/**
|
|
* Increment violation counter
|
|
*/
|
|
governanceRuleSchema.methods.incrementViolated = async function() {
|
|
this.stats.timesViolated += 1;
|
|
this.stats.lastViolated = new Date();
|
|
return this.save();
|
|
};
|
|
|
|
/**
|
|
* Deactivate rule (soft delete)
|
|
*/
|
|
governanceRuleSchema.methods.deactivate = async function() {
|
|
this.active = false;
|
|
return this.save();
|
|
};
|
|
|
|
/**
|
|
* Activate rule
|
|
*/
|
|
governanceRuleSchema.methods.activate = async function() {
|
|
this.active = true;
|
|
return this.save();
|
|
};
|
|
|
|
// Pre-save hook to validate expiration
|
|
governanceRuleSchema.pre('save', function(next) {
|
|
// If expiresAt is in the past, deactivate the rule
|
|
if (this.expiresAt && this.expiresAt < new Date()) {
|
|
this.active = false;
|
|
}
|
|
next();
|
|
});
|
|
|
|
const GovernanceRule = mongoose.model('GovernanceRule', governanceRuleSchema);
|
|
|
|
module.exports = GovernanceRule;
|