cleanup: remove dead code, stale shipped scaffolding, internal docs
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:
@@ -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.
|
||||
Reference in New Issue
Block a user