cleanup: remove dead code, stale shipped scaffolding, internal docs
CI / test (push) Successful in 5m45s
CI / benchmark (push) Successful in 43s
CI / publish (push) Has been skipped

Dead code with zero callers (deprecation notes promised removal):
- RelationCSR index: always-off option (useRelationCsrIndex), never
  enabled in production, wired through RelationManager/RelationUpdates/
  RelationLookup. Removed the module and all wiring.
- getAggregatedBlurredValue (RelationManager) and aggregateBlurredValues
  (ValueManager): @deprecated shims, zero callers.
- QualitativeRelationalComparatorRule._aggregateBlurredValues:
  @deprecated shim, zero callers.

Kept compareRelationValues: non-deprecated public API, coherent and
clock-threaded, just currently callerless.

Stale scaffolding shipping in the published artifact (files: src/):
- src/ast/tests/* and src/ast/examples/*: orphaned duplicates of
  tests/ast/, zero references anywhere, 11 files in the tarball.
  Removed; the live copies live in tests/ast/.

Internal docs moved out of the shipped surface (1266 lines) to
docs/internal/: VALUE_OPTIMIZATION_SUMMARY, rules API_SPECIFICATION,
ast README, qualitative README — repo-kept, not packaged.

Tarball .md count: 11 -> 1. Rigor 251/251, full suite 853/791/0.
This commit is contained in:
John Dvorak
2026-08-02 21:03:37 -07:00
parent 33dd15bba5
commit f8f6c5cb1b
21 changed files with 0 additions and 3843 deletions
+273
View File
@@ -0,0 +1,273 @@
# Value Handling Optimization Summary
## Overview
This document outlines the comprehensive optimization of value handling in the RuleEvaluator system, which eliminates wasteful recalculations and dramatically improves performance for complex rule evaluations.
## Problems Identified
### 1. **Redundant Value Fetching**
- **Issue**: Multiple rules in the same evaluation tree were independently fetching the same values from relations
- **Example**: A union rule with 3 child RelationalComparatorRules would fetch `user.balance` 3 times
- **Impact**: O(n) redundant database/relation queries per evaluation
### 2. **Missing Value Propagation**
- **Issue**: LogicalOperators (union/intersection) weren't combining `collectedValues` from child rules
- **Impact**: Lost value information that could be reused by parent rules
### 3. **Wasteful Inference Triggering**
- **Issue**: Inference engine was called even when sufficient values existed but weren't being considered
- **Impact**: Expensive similarity calculations when values were already available
### 4. **No Context Sharing**
- **Issue**: Each rule evaluation was isolated with no mechanism to share computed values
- **Impact**: Repeated work across the evaluation tree
## Solution: ValueContext System
### Core Components
#### 1. **ValueContext Class** (`ValueContext.js`)
```javascript
export class ValueContext {
// Centralized value cache and aggregation
// - Value cache: entity:relation -> raw values
// - Aggregated cache: entity:relation:method -> aggregated result
// - Performance tracking: hits/misses/fetch counts
}
```
**Key Features:**
- **Caching**: Eliminate redundant fetches with `entity:relation` keyed cache
- **Aggregation**: Pre-compute and cache aggregated values (sum, max, min, etc.)
- **Smart Inference**: Check value sufficiency before triggering expensive inference
- **Performance Tracking**: Monitor cache hit rates and fetch reduction
#### 2. **Enhanced RuleEvaluator** (`RuleEvaluator.js`)
```javascript
evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options = {}) {
const { valueContext = null } = options;
const finalValueContext = valueContext || new ValueContext(this.arbiter);
// Pass valueContext to all child rule evaluations
// Add collected values to context
// Use context to make smarter inference decisions
}
```
**Key Improvements:**
- **Context Propagation**: Pass ValueContext through entire evaluation tree
- **Value Collection**: Automatically add `collectedValues` to context
- **Smart Inference**: Check `hasSufficientValues()` before expensive inference
- **Batch Optimization**: Shared ValueContext across batch evaluations
#### 3. **Optimized LogicalOperators** (`LogicalOperators_v2.js`)
```javascript
evaluateUnion(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options = {}) {
const allCollectedValues = []; // Track from all child rules
for (const child of childRules) {
const res = this.ruleEvaluator.evaluateRule(/* ... */, options);
// Merge collected values from child
if (res.collectedValues) {
allCollectedValues.push(...res.collectedValues);
if (valueContext) {
valueContext.addCollectedValues(res.collectedValues, child.type, child);
}
}
}
return { /* ... */, collectedValues: allCollectedValues };
}
```
**Key Improvements:**
- **Value Merging**: Combine `collectedValues` from all child rules
- **Context Integration**: Add child values to shared ValueContext
- **Preserved Information**: Ensure no value information is lost in logical operations
#### 4. **Optimized RelationalComparatorRule** (`RelationalComparatorRule_v2.js`)
```javascript
_evaluateOperand(/* ... */, options, side) {
const { valueContext = null } = options;
// 1. Check if rule already provided values (collectedValues)
if (ruleResult.collectedValues?.length > 0) {
return this._useCollectedValues(ruleResult.collectedValues);
}
// 2. Check ValueContext cache before extraction
if (valueContext?.hasValues(entityId, relationName)) {
return valueContext.getAggregatedValue(entityId, relationName, aggregator);
}
// 3. Fallback to original extraction (but cache results)
return this._extractValuesWithContext(/* ... */, valueContext);
}
```
**Key Improvements:**
- **Cached Value Reuse**: Check ValueContext before fetching from relations
- **Collected Value Utilization**: Prefer values from child rule `collectedValues`
- **Fallback Safety**: Maintain backward compatibility with original extraction logic
## Performance Benefits
### Quantitative Improvements
#### Value Fetch Reduction
- **Before**: O(n × m) fetches where n = rule count, m = unique values per rule
- **After**: O(k) fetches where k = unique entity:relation combinations
- **Typical Reduction**: 60-90% fewer database/relation queries
#### Cache Effectiveness
- **Hit Rate**: 70-95% in complex rule evaluations
- **Memory Usage**: Minimal overhead (values cached only for evaluation duration)
- **Invalidation**: Automatic cleanup after evaluation completion
#### Inference Optimization
- **Before**: Inference triggered on every zero-result rule
- **After**: Inference only when `hasSufficientValues()` returns false
- **Typical Reduction**: 40-70% fewer expensive inference operations
### Example Performance Case
**Scenario**: User purchasing premium feature
```
Rule Structure:
└── UNION
├── RELATIONAL_COMPARATOR (user.balance >= feature.price)
└── INTERSECTION
├── CHAIN (user -> subscriptions)
└── UNION
├── RELATIONAL_COMPARATOR (user.credit >= feature.price)
└── RELATIONAL_COMPARATOR (user.balance >= feature.price)
```
**Old System Value Fetches:**
- `user.balance`: 2 times (redundant!)
- `user.credit`: 1 time
- `feature.price`: 3 times (redundant!)
- **Total**: 6 fetches
**New System Value Fetches:**
- `user.balance`: 1 time (cached)
- `user.credit`: 1 time (cached)
- `feature.price`: 1 time (cached)
- **Total**: 3 fetches (50% reduction)
## Implementation Guidelines
### 1. **Using ValueContext**
```javascript
// Single evaluation with context
const valueContext = new ValueContext(arbiter);
const result = ruleEvaluator.evaluateRule(/* ... */, { valueContext });
// Batch evaluation (automatic shared context)
const results = ruleEvaluator.batchEvaluateRules(queries);
// Performance monitoring
const stats = valueContext.getStats();
console.log(`Cache hit rate: ${stats.hitRate * 100}%`);
```
### 2. **Adding Value Collection to Custom Rules**
```javascript
export class CustomRule extends BaseRule {
_evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options) {
const { valueContext } = options;
// Collect values during evaluation
const collectedValues = [];
// ... rule logic ...
// Add values you've collected
const collectedValue = this._createCollectedValue(
value, possibility, path, source, metadata
);
collectedValues.push(collectedValue);
return this._createStandardResult(authResult, collectedValues);
}
}
```
### 3. **Performance Monitoring**
```javascript
// Enable value context stats in production
const result = ruleEvaluator.evaluateRule(/* ... */, {
valueContext,
trackPerformance: true
});
const stats = ruleEvaluator.getValueContextStats({ valueContext });
logger.info('Rule evaluation performance', {
cacheHitRate: stats.hitRate,
fetchReduction: stats.fetchCount,
executionTime: result.executionTime
});
```
## Migration Strategy
### Phase 1: Backward Compatibility
-**Complete**: All optimizations work alongside existing code
-**Complete**: No breaking changes to existing rule configurations
-**Complete**: Automatic fallback to original logic when ValueContext unavailable
### Phase 2: Gradual Adoption
- **Recommended**: Use ValueContext in new rule evaluations
- **Recommended**: Enable for batch operations (automatic)
- **Optional**: Retrofit existing custom rules to use ValueContext
### Phase 3: Full Optimization
- **Future**: Require ValueContext for all evaluations
- **Future**: Remove fallback extraction logic
- **Future**: Add advanced caching strategies (LRU, TTL, etc.)
## Validation & Testing
### Correctness Validation
-**Complete**: All optimizations maintain identical results to original system
-**Complete**: Comprehensive test coverage with `ValueOptimizationDemo`
-**Complete**: Edge case handling (missing values, cache misses, etc.)
### Performance Testing
-**Available**: Demo shows 50%+ fetch reduction in typical scenarios
-**Available**: Cache hit rates consistently above 70%
-**Available**: Performance tracking and monitoring built-in
## Future Enhancements
### 1. **Advanced Caching**
- **LRU Eviction**: Limit memory usage in long-running processes
- **TTL Support**: Expire stale values automatically
- **Persistent Cache**: Cross-evaluation value persistence
### 2. **Smart Prefetching**
- **Dependency Analysis**: Pre-fetch values based on rule structure
- **Batch Loading**: Group value fetches by entity/relation patterns
- **Predictive Caching**: Learn from evaluation patterns
### 3. **Distributed Caching**
- **Redis Integration**: Share ValueContext across service instances
- **Cluster Coordination**: Synchronized cache invalidation
- **Partitioning**: Shard value cache by entity patterns
## Conclusion
The ValueContext optimization system provides:
1. **🚀 Performance**: 50-90% reduction in redundant value fetches
2. **💡 Intelligence**: Smart inference decisions based on available values
3. **🔄 Compatibility**: Zero breaking changes to existing code
4. **📊 Observability**: Built-in performance monitoring and stats
5. **🛡️ Reliability**: Maintained result consistency with comprehensive testing
This optimization eliminates the core inefficiencies in value handling while maintaining full backward compatibility and providing a foundation for future enhancements.
+340
View File
@@ -0,0 +1,340 @@
# AST Module - DSL Compiler for Zanzibar-Graph
This module provides a complete Abstract Syntax Tree (AST) system for parsing and compiling the Evidence DSL into rule configurations that interface with the zanzibar-graph authorization system.
## Overview
The AST module consists of three main components:
1. **Parser** - Converts DSL text into AST nodes
2. **Generator** - Converts AST nodes into rule configurations
3. **Compiler** - Orchestrates the parsing and generation process
## Architecture
```
DSL Text → Parser → AST Nodes → Generator → Rule Configs → setRelationConfig()
```
## Features
- **Complete DSL Support** - Supports all DSL constructs from the specification
- **Modular Design** - Clean separation of concerns with pluggable components
- **Error Handling** - Comprehensive error reporting and validation
- **Program Management** - Support for multiple compiled programs
- **Rule Generation** - Automatic conversion to existing rule system
- **Extensible** - Easy to add new node types and generators
## Quick Start
```javascript
import { DSLCompiler } from './src/ast/index.js';
// Create compiler with arbiter instance
const compiler = new DSLCompiler(arbiter);
// Compile DSL text
const result = compiler.compile(dslText, 'my-program');
if (result.success) {
console.log(`Generated ${result.generatedCount} rules`);
} else {
console.error('Compilation errors:', result.errors);
}
```
## Core Components
### 1. AST Nodes (`/nodes/`)
The AST nodes represent the parsed structure of the DSL:
- **BaseNode** - Base class for all AST nodes
- **ProgramNode** - Root node containing all definitions
- **DefinitionNode** - Type definitions with fields and behaviors
- **FactNode** - Fact definitions with parameters and properties
- **EvidenceNode** - Evidence definitions with bodies
- **MeasureNode** - Measure definitions for value collection
- **ExpressionNode** - Expressions, variables, and literals
- **And many more...**
### 2. Parser (`/parser/`)
The DSL parser converts text into AST nodes:
```javascript
import { DSLParser } from './parser/DSLParser.js';
const parser = new DSLParser();
const program = parser.parse(dslText);
```
### 3. Generator (`/generator/`)
The rule generator converts AST nodes into rule configurations:
```javascript
import { RuleGenerator } from './generator/RuleGenerator.js';
const generator = new RuleGenerator(arbiter);
const result = generator.generateRules(program);
```
### 4. Compiler (`DSLCompiler.js`)
The main compiler orchestrates the entire process:
```javascript
import { DSLCompiler } from './DSLCompiler.js';
const compiler = new DSLCompiler(arbiter);
const result = compiler.compile(dslText, 'program-name');
```
## Usage Examples
### Basic Compilation
```javascript
const dsl = `
definition User {
role: string
isActive: boolean
}
fact hasRole(user: User, role: string) CACHE eager
evidence canRead(user: User, doc: Document) {
hasRole(user, 'admin')
}
`;
const result = compiler.compile(dsl, 'auth');
```
### Complex DSL with Defeasible Logic
```javascript
const complexDSL = `
evidence canAccessCritical(user: User, resource: Resource) {
// Strict requirement
ALWAYS user.isActive
// Defeasible access
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
// Requirements
REQUIRES hasClearance(user, resource.level)
// Fusion evidence
fusion majority {
user.isTrusted
user.hasRecentActivity
}
}
`;
const result = compiler.compile(complexDSL, 'critical-access');
```
### Multiple Programs
```javascript
const programs = {
'auth': `
fact hasRole(user: User, role: string)
evidence canRead(user: User, doc: Document) {
hasRole(user, 'admin')
}
`,
'finance': `
fact hasBalance(user: User, amount: number)
evidence canWithdraw(user: User, amount: number) {
hasBalance(user, amount)
}
`
};
const result = compiler.compileMultiple(programs);
```
## API Reference
### DSLCompiler
#### Methods
- `compile(dslText, programName)` - Compile DSL text into rules
- `compileMultiple(programs)` - Compile multiple programs
- `validate(dslText)` - Validate DSL without compilation
- `getCompiledProgram(name)` - Get compiled program by name
- `getAllCompiledPrograms()` - Get all compiled programs
- `removeCompiledProgram(name)` - Remove compiled program
- `clearCompiledPrograms()` - Clear all programs
- `getCompilationStats()` - Get compilation statistics
#### Properties
- `arbiter` - The arbiter instance
- `parser` - The DSL parser
- `generator` - The rule generator
### DSLParser
#### Methods
- `parse(dslText)` - Parse DSL text into AST
- `getErrors()` - Get parser errors
### RuleGenerator
#### Methods
- `generateRules(program)` - Generate rules from AST
- `getErrors()` - Get generator errors
- `getGeneratedRules()` - Get generated rules
## Supported DSL Constructs
### Type Definitions
```typescript
definition User {
role: string
isActive: boolean
lastActive: timestamp BEHAVES {
decaying down hourly
} CACHE lazy
}
```
### Facts
```typescript
fact hasRole(user: User, role: string) CACHE eager
fact isMember(user: User, group: Group) transitive CACHE lazy
```
### Evidence
```typescript
evidence canRead(user: User, doc: Document) {
// Direct evidence
owns(user, doc)
// Pattern matching
isMember(user, *group) {
canRead(group, doc)
} limit 5
// Defeasible logic
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
}
```
### Measures
```typescript
measure userBalance(user: User) {
user.balance
} PROVIDES number
measure userPermissions(user: User) {
fusion max {
user.role.permissions
user.group.permissions
}
} PROVIDES Permission[]
```
## Error Handling
The compiler provides comprehensive error handling:
```javascript
const result = compiler.compile(dslText);
if (!result.success) {
console.error('Compilation failed:');
result.errors.forEach(error => console.error(` - ${error}`));
}
if (result.warnings.length > 0) {
console.warn('Warnings:');
result.warnings.forEach(warning => console.warn(` - ${warning}`));
}
```
## Testing
Run the test suite:
```javascript
import { runDSLCompilerTests } from './tests/DSLCompiler.test.js';
const testResults = runDSLCompilerTests(arbiter);
console.log('Test Results:', testResults);
```
## Examples
See the examples directory for comprehensive usage examples:
- `examples/DSLExample.js` - Complete usage examples
- `tests/DSLCompiler.test.js` - Test suite
## Integration with Existing System
The AST module integrates seamlessly with the existing zanzibar-graph system:
1. **Parser** converts DSL text to AST nodes
2. **Generator** converts AST nodes to rule configurations
3. **Compiler** applies rules via `arbiter.setRelationConfig()`
The generated rules are compatible with all existing rule types:
- Direct rules
- Computed rules
- Parent rules
- Tuple-to-userset rules
- Similarity rules
- Multi-hop rules
- Logical operators
- Defeasible logic
## Extensibility
The AST system is designed to be extensible:
1. **Add new node types** by extending `BaseNode`
2. **Add new parsers** by extending `DSLParser`
3. **Add new generators** by extending `RuleGenerator`
4. **Add new compilers** by extending `DSLCompiler`
## Performance Considerations
- **Lazy evaluation** - AST nodes are created on demand
- **Efficient parsing** - Token-based parsing with minimal memory usage
- **Rule caching** - Generated rules are cached for reuse
- **Batch processing** - Support for compiling multiple programs at once
## Future Enhancements
- **Incremental compilation** - Only recompile changed parts
- **Parallel processing** - Compile multiple programs in parallel
- **Advanced optimizations** - Rule optimization and simplification
- **IDE support** - Language server protocol support
- **Visualization** - AST visualization tools
## Contributing
When contributing to the AST module:
1. Follow the existing code structure
2. Add comprehensive tests for new features
3. Update documentation
4. Ensure backward compatibility
5. Follow the established patterns
## License
This module is part of the zanzibar-graph project and follows the same license terms.
+256
View File
@@ -0,0 +1,256 @@
# Qualitative Capacity System
This module provides a complete implementation of qualitative capacities (q-capacities) as described in the research paper on qualitative capacities and their applications to evidential reasoning, decision making, and imprecise possibility.
## Overview
A qualitative capacity γ: 2^W → L is a monotonic set-function where:
- γ(∅) = 0, γ(W) = 1
- If A ⊆ B, then γ(A) ≤ γ(B)
- L is a finite totally ordered scale with order-reversing negation
The core design principle is to use the Qualitative Möbius Transform (QMT) γ# as the canonical internal representation for any q-capacity γ.
## Core Components
### 1. SetUtils
Utility functions for working with Sets as Map keys, providing canonical string representations for consistent and efficient Map operations.
```javascript
import { getSetKey, setFromKey, setsEqual } from './src/qualitative/index.js';
const set = new Set(['a', 'b', 'c']);
const key = getSetKey(set); // "a,b,c"
const reconstructed = setFromKey(key); // Set(['a', 'b', 'c'])
const areEqual = setsEqual(set, reconstructed); // true
```
### 2. QualitativeScale
Finite totally ordered scales with order-reversing negation.
```javascript
import { QualitativeScale } from './src/qualitative/index.js';
// Create a 5-point scale
const scale = QualitativeScale.fivePoint(); // [0, 0.25, 0.5, 0.75, 1]
// Test operations
console.log(scale.min(0.25, 0.75)); // 0.25
console.log(scale.max(0.25, 0.75)); // 0.75
console.log(scale.negate(0.25)); // 0.75 (order-reversing)
```
### 3. QualitativeCapacity
Q-capacities with QMT internal representation.
```javascript
import { QualitativeCapacity } from './src/qualitative/index.js';
const stateSpace = ['s1', 's2', 's3'];
const scale = QualitativeScale.ternary();
// Create a simple support capacity
const ssc = QualitativeCapacity.createSimpleSupport(
stateSpace,
['s1'],
0.5,
scale
);
// Get capacity values
console.log(ssc.getCapacity(['s1'])); // 0.5
console.log(ssc.getCapacity(['s1', 's2'])); // 1
// Check if it's a necessity measure
console.log(ssc.isNecessityMeasure()); // true
```
### 4. QualitativeFusion
Theoretically sound fusion rules for capacity combination.
```javascript
import { QualitativeFusion } from './src/qualitative/index.js';
// Create multiple capacities
const cap1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 0.5, scale);
const cap2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 0.5, scale);
// Normalized conjunctive fusion (theoretically sound)
const fused = QualitativeFusion.normalizedConjunctive([cap1, cap2]);
// Disjunctive fusion
const disjunctive = QualitativeFusion.disjunctive(cap1, cap2);
// Sugeno integral for decision making
const decisionFunction = { 's1': 0.5, 's2': 1, 's3': 0.5 };
const sugenoValue = QualitativeFusion.sugenoIntegral(fused, decisionFunction);
```
### 5. OWAQualitativeFusion
Bag algebras for sophisticated qualitative aggregation.
```javascript
import { OWAQualitativeFusion } from './src/qualitative/index.js';
const values = [0.25, 0.5, 0.75];
const metas = [{ source: 'rule1' }, { source: 'rule2' }, { source: 'rule3' }];
// Different aggregation modes
const maxResult = OWAQualitativeFusion.max(values, metas, scale);
const majorityResult = OWAQualitativeFusion.majority(values, metas, scale);
const optimisticResult = OWAQualitativeFusion.optimistic(values, metas, scale);
// Configurable activation threshold
const selectiveResult = OWAQualitativeFusion.max(values, metas, scale, 0.8);
// Proper Sugeno integral
const sugenoResult = OWAQualitativeFusion.sugenoIntegral(capacity, decisionFunction);
```
### 6. QMTOWAFusion
Theoretically sound OWA-like operators that work directly on QMTs.
```javascript
import { QMTOWAFusion } from './src/qualitative/index.js';
// These methods preserve monotonicity by working on QMTs directly
const optimistic = QMTOWAFusion.optimisticFusion([cap1, cap2]);
const pessimistic = QMTOWAFusion.pessimisticFusion([cap1, cap2]);
const majority = QMTOWAFusion.majorityFusion([cap1, cap2]);
const priority = QMTOWAFusion.priorityFusion([cap1, cap2], [10, 5]);
```
## Theoretical Considerations
### Pointwise OWA Fusion Warning
The `pointwiseOWAFusion` method (formerly `fuseCapacities`) performs pointwise OWA fusion on capacity values, which **does NOT guarantee** that the result is a valid qualitative capacity. The resulting set-function may violate the fundamental monotonicity property: A⊆B ⟹ γ(A)≤γ(B).
**Use this method only for experimental purposes or when monotonicity is not required.**
For theoretically sound capacity fusion, use:
- `QualitativeFusion.normalizedConjunctive()`
- `QualitativeFusion.disjunctive()`
- `QMTOWAFusion` methods
### Qualitative OWA Operator
The qualitative OWA operator implements a novel weighted maximum where weights act as "gates" that must pass a threshold to allow their corresponding values to be considered. This is distinct from the standard Sugeno integral but provides a practical way to introduce weight influence in purely ordinal contexts.
The activation threshold is configurable (default 0.5) to allow for more or less "selective" aggregations.
### Sugeno Integral
The Sugeno integral is the qualitative counterpart to the Choquet integral and provides a theoretically sound way to aggregate qualitative values with respect to a capacity:
S_γ(f) = max_{i=1}^n min(f_{(i)}, γ(A_{(i)}))
where f_{(i)} are the sorted values in descending order and A_{(i)} = {w_{(1)}, ..., w_{(i)}}.
## Applications
### 1. Evidential Reasoning
Combine testimonies from different sources using Simple Support Capacities and normalized conjunctive fusion.
```javascript
// Create testimonies as Simple Support Capacities
const testimony1 = QualitativeCapacity.createSimpleSupport(
stateSpace,
['s1'],
0.8,
scale
);
const testimony2 = QualitativeCapacity.createSimpleSupport(
stateSpace,
['s2'],
0.6,
scale
);
// Fuse testimonies
const combinedEvidence = QualitativeFusion.normalizedConjunctive([
testimony1,
testimony2
]);
```
### 2. Qualitative Decision Making
Use Sugeno integrals to evaluate decisions based on qualitative utility functions and uncertainty represented by q-capacities.
```javascript
// Define decision function (utility for each state)
const utility = {
's1': 0.8, // High utility
's2': 0.4, // Medium utility
's3': 0.2 // Low utility
};
// Evaluate decision using Sugeno integral
const decisionValue = QualitativeFusion.sugenoIntegral(capacity, utility);
```
### 3. Imprecise Possibility
Represent ill-known possibility measures bounded by lower (q-capacity) and upper (possibility) measures.
```javascript
// Get upper capacity (possibility measure)
const upperCapacity = capacity.getUpperCapacity();
// Get contour function
const contour = capacity.getContourFunction();
// Get conjugate capacity
const conjugate = capacity.getConjugate();
```
## Performance Considerations
The current implementation has O(2^|W|) complexity for operations that generate all subsets. This is suitable for small state spaces (|W| < 20) but may not scale to larger ones.
### Optimizations Implemented
1. **QualitativeScale Optimizations**:
- `contains()`: O(1) average time using Set-based lookup
- `indexOf()`: O(log n) time using binary search
- These optimizations significantly improve performance for scale operations
2. **Canonical QMT Optimization**:
- `_convertToCanonicalQMT()`: Only checks immediate proper subsets instead of all smaller subsets
- Uses the mathematical property: γ#(A) > 0 ⟺ γ(A) > max_{w∈A} γ(A{w})
- Provides substantial performance improvement for canonicalization
3. **String Key Robustness**:
- All Set objects are converted to canonical string keys for Map operations
- Eliminates JavaScript Set reference comparison issues
- Ensures consistent and efficient Map key operations
4. **Canonicalization Consistency**:
- All fusion methods return canonical QMTs by default
- Ensures minimal representation and consistent behavior
- Simplifies subsequent operations and saves memory
For large state spaces, consider:
1. Working with QMTs directly (already implemented)
2. Using sparse representations
3. Implementing approximation algorithms
## Future Research Directions
1. **QMT-based OWA**: Develop more sophisticated OWA-like operators that work directly on QMTs
2. **Complexity Optimization**: Implement efficient algorithms for large state spaces
3. **Approximation Methods**: Develop approximation algorithms for intractable operations
4. **Integration with DSL**: Extend the Evidence DSL to support qualitative capacities
## References
This implementation is based on the research paper "Qualitative capacities: basic notions and potential applications" and related work on qualitative uncertainty theory, possibility theory, and evidential reasoning.
+399
View File
@@ -0,0 +1,399 @@
# Authorization Rules API Specification
This document defines the standardized API that all authorization rules must implement to ensure consistency, performance, and maintainability across the zanzibar-graph system.
## Overview
All authorization rules must extend the `BaseRule` class and implement the required abstract methods. This ensures:
- **Consistent Interface**: All rules have the same public API
- **Performance Tracking**: Built-in performance monitoring
- **Error Handling**: Standardized error responses
- **Batch Processing**: Optional but encouraged for performance
- **Early Exit**: Threshold-based optimization support
- **Input Validation**: Automatic parameter validation
## Core Interface
### Constructor
```javascript
constructor(arbiter)
```
**Parameters:**
- `arbiter` (Arbiter): The main Arbiter instance
**Requirements:**
- Must call `super(arbiter)` first
- Should initialize any rule-specific state
- Must not throw exceptions
### Primary Evaluation Method
```javascript
evaluate(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options = {})
```
**Parameters:**
- `userId` (number): Internal user node ID
- `userKey` (string): User key (e.g., "user:alice")
- `objectId` (number): Internal object node ID
- `objectKey` (string): Object key (e.g., "doc:secret")
- `rule` (Object): Rule configuration object
- `visited` (Set): Set of visited nodes for cycle detection
- `currentRelation` (string): Current relation being evaluated
- `options` (Object): Evaluation options
**Returns:** `RuleEvaluationResult` object
**Standard Options:**
```javascript
{
// Performance options
fastPath: false, // Enable early termination
minAllowPossibility: null, // Threshold for allow early exit (0-1)
maxDenyPossibility: null, // Threshold for deny early exit (0-1)
// Inference options
noInfer: false, // Disable inference
allowInference: true, // Allow inference (opposite of noInfer)
// Binary mode
binary: false, // Return binary allow/deny decisions
// Evaluation tracking
trackEvaluation: true, // Include evaluation metadata
// Rule-specific options (passed through)
// ... additional options specific to rule type
}
```
### Batch Evaluation Method (Optional)
```javascript
batchEvaluate(queries, batchOptions = {})
```
**Parameters:**
- `queries` (Array): Array of query objects with same structure as `evaluate` parameters
- `batchOptions` (Object): Batch-specific options
**Returns:** Array of `RuleEvaluationResult` objects
**Query Object Structure:**
```javascript
{
userId: number,
userKey: string,
objectId: number,
objectKey: string,
rule: Object,
visited: Set,
currentRelation: string,
options: Object
}
```
### Batch Support Check
```javascript
canBatchProcess()
```
**Returns:** `boolean` - Whether this rule supports efficient batch processing
## Standard Result Structure
All evaluation methods must return a `RuleEvaluationResult` object:
```javascript
{
// Core evaluation results (required)
possibility_allow: number, // 0-1, possibility of allowing access
possibility_deny: number, // 0-1, possibility of denying access
reliability: number, // 0-1, reliability of the evaluation
// Metadata (required, can be null)
meta_allow: Object | null, // Metadata for allow decision
meta_deny: Object | null, // Metadata for deny decision
// Optional fields
reason: string, // Reason for the result
error: boolean, // Whether this is an error result
details: Object, // Additional details
evaluation: Object // Evaluation tracking data
}
```
### Standard Metadata Structure
```javascript
// meta_allow / meta_deny structure
{
ruleType: string, // Type of rule (e.g., 'direct', 'tuple_to_userset')
reason: string, // Reason for decision
rule: Object, // Original rule configuration
// Performance metadata
earlyExit: boolean, // Whether early exit was used
earlyExitReason: string, // Reason for early exit
// Rule-specific metadata
// ... additional fields specific to rule type
}
```
## Implementation Requirements
### Abstract Methods (Must Implement)
```javascript
// Core evaluation logic
_evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options)
// Batch evaluation logic (optional, only if canBatchProcess() returns true)
_batchEvaluateRule(queries, batchOptions)
```
### Performance Tracking
All rules automatically track:
- Individual evaluation count and timing
- Batch evaluation count and timing
- Average evaluation times
Access via:
```javascript
rule.getPerformanceStats()
rule.resetPerformanceStats()
```
### Error Handling
Rules should handle errors gracefully:
- Input validation is automatic
- Exceptions are caught and converted to error results
- Batch operations fall back to individual evaluations on error
## Rule-Specific Configurations
### Common Rule Properties
```javascript
{
type: string, // Rule type identifier
ruleType: string, // 'defeasible', 'defeater', 'strict'
priority: number, // Rule priority (higher = more important)
weight: number, // Rule weight for aggregation
// Performance options
no_infer: boolean, // Disable inference for this rule
allowInference: boolean, // Allow inference
// Aggregation options
owaWeights: Array<number>, // OWA aggregation weights
aggregator: string, // Aggregation method ('max', 'min', 'avg', etc.)
// Rule-specific properties
// ... varies by rule type
}
```
### DirectRule Configuration
```javascript
{
type: 'direct',
relation: string, // Relation to check (optional, uses currentRelation)
reverse: boolean // Check in reverse direction
}
```
### TupleToUsersetRule Configuration
```javascript
{
type: 'tuple_to_userset',
tuplesetRelation: string, // Relation from object to intermediate
computedRelation: string, // Relation from user to intermediate
reverse: boolean // Check in reverse direction
}
```
### ParentRule Configuration
```javascript
{
type: 'parent',
parentRelation: string, // Relation defining parent-child
relation: string, // Relation to check on parent
reverse: boolean // Check in reverse direction
}
```
### SimilarityRule Configuration
```javascript
{
type: 'similar_to',
relation: string, // Relation to find similarities for
k: number, // Number of similar entities to consider
similarityThreshold: number, // Minimum similarity threshold (0-1)
reverse: boolean, // Check in reverse direction
fallbackToBasicSimilarity: boolean // Use basic similarity when embeddings unavailable
}
```
### MultiHopRule Configuration
```javascript
{
type: 'multi_hop',
relation: string, // Relation to traverse
maxDepth: number, // Maximum path depth
minReliability: number, // Minimum path reliability
decayFactor: number, // Reliability decay per hop
pathAggregation: string, // How to aggregate multiple paths ('max', 'sum', 'owa')
reverse: boolean, // Search in reverse direction
allowInference: boolean, // Allow inference for missing edges
fallbackToBasicPaths: boolean // Use basic path finding as fallback
}
```
### ComputedRule Configuration
```javascript
{
type: 'computed',
relation: string // Relation to recursively evaluate
}
```
## Logical Operators
### Union (OR) Configuration
```javascript
{
union: Array<RuleConfig>, // Array of rules to OR together
aggregator: string, // Aggregation method
owaWeights: Array<number>, // OWA weights for fusion
reliabilityWeighting: boolean // Weight by reliability
}
```
### Intersection (AND) Configuration
```javascript
{
intersection: Array<RuleConfig>, // Array of rules to AND together
aggregator: string, // Aggregation method (defaults to 'min')
owaWeights: Array<number> // OWA weights for fusion
}
```
### Exclusion (A AND NOT B) Configuration
```javascript
{
exclusion: [RuleConfig, RuleConfig] // [base rule, exclusion rule]
}
```
## Performance Optimization Guidelines
### Early Exit Support
Rules should support early termination when:
- `options.fastPath` is true
- `options.minAllowPossibility` threshold is met
- `options.maxDenyPossibility` threshold is met
### Batch Processing
Rules that can benefit from batch processing should:
- Override `canBatchProcess()` to return `true`
- Implement `_batchEvaluateRule()` method
- Group similar operations for efficiency
- Use indexed lookups instead of linear scans
### Caching
Rules should leverage:
- Arbiter's built-in caching mechanisms
- Batch caches for intermediate results
- Embedding caches for similarity calculations
## Testing Requirements
All rules must include:
- Unit tests for individual evaluation
- Batch evaluation tests (if supported)
- Performance benchmarks
- Error handling tests
- Edge case coverage
## Migration Guide
To migrate existing rules to the new API:
1. **Extend BaseRule**: Change `export class MyRule` to `export class MyRule extends BaseRule`
2. **Rename evaluate**: Rename `evaluate()` to `_evaluateRule()`
3. **Update constructor**: Call `super(arbiter)` first
4. **Handle options**: Use normalized options parameter
5. **Update tests**: Test against new interface
## Example Implementation
```javascript
import { BaseRule } from './BaseRule.js';
export class ExampleRule extends BaseRule {
constructor(arbiter) {
super(arbiter);
// Rule-specific initialization
}
canBatchProcess() {
return true; // This rule supports batching
}
_evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options) {
// Implement rule-specific logic
const result = {
possibility_allow: 0.8,
possibility_deny: 0.1,
reliability: 0.9,
meta_allow: {
ruleType: 'example',
reason: 'example_evaluation',
rule
},
meta_deny: null,
reason: 'example_result'
};
return result;
}
_batchEvaluateRule(queries, batchOptions) {
// Implement efficient batch processing
return queries.map(query =>
this._evaluateRule(
query.userId,
query.userKey,
query.objectId,
query.objectKey,
query.rule,
query.visited,
query.currentRelation,
query.options
)
);
}
}
```
This standardized API ensures all rules work consistently while allowing for rule-specific optimizations and features.