arcvision 0.2.14 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCVISION_DIRECTORY_STRUCTURE.md +104 -0
- package/CLI_STRUCTURE.md +110 -0
- package/CONFIGURATION.md +119 -0
- package/IMPLEMENTATION_SUMMARY.md +99 -0
- package/README.md +149 -89
- package/architecture.authority.ledger.json +46 -0
- package/arcvision-0.2.3.tgz +0 -0
- package/arcvision-0.2.4.tgz +0 -0
- package/arcvision-0.2.5.tgz +0 -0
- package/arcvision.context.diff.json +2181 -0
- package/arcvision.context.json +1021 -0
- package/arcvision.context.v1.json +2163 -0
- package/arcvision.context.v2.json +2173 -0
- package/arcvision_context/README.md +93 -0
- package/arcvision_context/architecture.authority.ledger.json +83 -0
- package/arcvision_context/arcvision.context.json +6884 -0
- package/debug-cycle-detection.js +56 -0
- package/dist/index.js +1626 -25
- package/docs/ENHANCED_ACCURACY_SAFETY_PROTOCOL.md +172 -0
- package/docs/accuracy-enhancement-artifacts/enhanced-validation-config.json +98 -0
- package/docs/acig-robustness-guide.md +164 -0
- package/docs/authoritative-gate-implementation.md +168 -0
- package/docs/cli-strengthening-summary.md +232 -0
- package/docs/invariant-system-summary.md +100 -0
- package/docs/invariant-system.md +112 -0
- package/generate_large_test.js +42 -0
- package/large_test_repo.json +1 -0
- package/output1.json +2163 -0
- package/output2.json +2163 -0
- package/package.json +46 -36
- package/scan_calcom_report.txt +0 -0
- package/scan_leafmint_report.txt +0 -0
- package/scan_output.txt +0 -0
- package/scan_trigger_report.txt +0 -0
- package/schema/arcvision_context_schema_v1.json +136 -1
- package/src/arcvision-guard.js +433 -0
- package/src/core/authority-core-detector.js +382 -0
- package/src/core/authority-ledger.js +300 -0
- package/src/core/blastRadius.js +299 -0
- package/src/core/call-resolver.js +196 -0
- package/src/core/change-evaluator.js +509 -0
- package/src/core/change-evaluator.js.backup +424 -0
- package/src/core/change-evaluator.ts +285 -0
- package/src/core/chunked-uploader.js +180 -0
- package/src/core/circular-dependency-detector.js +404 -0
- package/src/core/cli-error-handler.js +458 -0
- package/src/core/cli-validator.js +458 -0
- package/src/core/compression.js +64 -0
- package/src/core/context_builder.js +741 -0
- package/src/core/dependency-manager.js +134 -0
- package/src/core/di-detector.js +202 -0
- package/src/core/diff-analyzer.js +76 -0
- package/src/core/example-invariants.js +135 -0
- package/src/core/failure-mode-synthesizer.js +341 -0
- package/src/core/invariant-analyzer.js +294 -0
- package/src/core/invariant-detector.js +548 -0
- package/src/core/invariant-enforcer.js +171 -0
- package/src/core/invariant-evaluation-utils.js +172 -0
- package/src/core/invariant-hooks.js +152 -0
- package/src/core/invariant-integration-example.js +186 -0
- package/src/core/invariant-registry.js +298 -0
- package/src/core/invariant-registry.ts +100 -0
- package/src/core/invariant-types.js +66 -0
- package/src/core/invariants-index.js +88 -0
- package/src/core/method-tracker.js +170 -0
- package/src/core/override-handler.js +304 -0
- package/src/core/ownership-resolver.js +227 -0
- package/src/core/parser-enhanced.js +80 -0
- package/src/core/parser.js +610 -0
- package/src/core/path-resolver.js +240 -0
- package/src/core/pattern-matcher.js +246 -0
- package/src/core/progress-tracker.js +71 -0
- package/src/core/react-nextjs-detector.js +245 -0
- package/src/core/readme-generator.js +167 -0
- package/src/core/retry-handler.js +57 -0
- package/src/core/scanner.js +289 -0
- package/src/core/semantic-analyzer.js +204 -0
- package/src/core/structural-context-owner.js +442 -0
- package/src/core/symbol-indexer.js +164 -0
- package/src/core/tsconfig-utils.js +73 -0
- package/src/core/type-analyzer.js +272 -0
- package/src/core/watcher.js +18 -0
- package/src/core/workspace-scanner.js +88 -0
- package/src/engine/context_builder.js +280 -0
- package/src/engine/context_sorter.js +59 -0
- package/src/engine/context_validator.js +200 -0
- package/src/engine/id-generator.js +16 -0
- package/src/engine/pass1_facts.js +260 -0
- package/src/engine/pass2_semantics.js +333 -0
- package/src/engine/pass3_lifter.js +99 -0
- package/src/engine/pass4_signals.js +201 -0
- package/src/index.js +830 -0
- package/src/plugins/express-plugin.js +48 -0
- package/src/plugins/plugin-manager.js +58 -0
- package/src/plugins/react-plugin.js +54 -0
- package/temp_original.js +0 -0
- package/test/determinism-test.js +83 -0
- package/test-authoritative-context.js +53 -0
- package/test-real-authoritative-context.js +118 -0
- package/test-upload-enhancements.js +111 -0
- package/test_repos/allowed-clean-architecture/.arcvision/invariants.json +57 -0
- package/test_repos/allowed-clean-architecture/adapters/controllers/UserController.js +95 -0
- package/test_repos/allowed-clean-architecture/adapters/http/HttpServer.js +78 -0
- package/test_repos/allowed-clean-architecture/application/dtos/CreateUserRequest.js +37 -0
- package/test_repos/allowed-clean-architecture/application/services/UserService.js +61 -0
- package/test_repos/allowed-clean-architecture/arcvision_context/README.md +93 -0
- package/test_repos/allowed-clean-architecture/arcvision_context/arcvision.context.json +2796 -0
- package/test_repos/allowed-clean-architecture/domain/interfaces/UserRepository.js +25 -0
- package/test_repos/allowed-clean-architecture/domain/models/User.js +39 -0
- package/test_repos/allowed-clean-architecture/index.js +45 -0
- package/test_repos/allowed-clean-architecture/infrastructure/database/DatabaseConnection.js +56 -0
- package/test_repos/allowed-clean-architecture/infrastructure/repositories/InMemoryUserRepository.js +61 -0
- package/test_repos/allowed-clean-architecture/package.json +15 -0
- package/test_repos/blocked-legacy-monolith/.arcvision/invariants.json +78 -0
- package/test_repos/blocked-legacy-monolith/arcvision_context/README.md +93 -0
- package/test_repos/blocked-legacy-monolith/arcvision_context/arcvision.context.json +2882 -0
- package/test_repos/blocked-legacy-monolith/database/dbConnection.js +35 -0
- package/test_repos/blocked-legacy-monolith/index.js +38 -0
- package/test_repos/blocked-legacy-monolith/modules/emailService.js +31 -0
- package/test_repos/blocked-legacy-monolith/modules/paymentProcessor.js +37 -0
- package/test_repos/blocked-legacy-monolith/package.json +15 -0
- package/test_repos/blocked-legacy-monolith/shared/utils.js +19 -0
- package/test_repos/blocked-legacy-monolith/utils/helpers.js +23 -0
- package/test_repos/risky-microservices-concerns/.arcvision/invariants.json +69 -0
- package/test_repos/risky-microservices-concerns/arcvision_context/README.md +93 -0
- package/test_repos/risky-microservices-concerns/arcvision_context/arcvision.context.json +3070 -0
- package/test_repos/risky-microservices-concerns/common/utils.js +77 -0
- package/test_repos/risky-microservices-concerns/gateways/apiGateway.js +84 -0
- package/test_repos/risky-microservices-concerns/index.js +20 -0
- package/test_repos/risky-microservices-concerns/libs/deprecatedHelper.js +36 -0
- package/test_repos/risky-microservices-concerns/package.json +15 -0
- package/test_repos/risky-microservices-concerns/services/orderService.js +42 -0
- package/test_repos/risky-microservices-concerns/services/userService.js +48 -0
- package/verify_engine.js +116 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant Enforcer - Non-bypassable enforcement layer
|
|
3
|
+
* Ensures developers cannot accidentally bypass invariants
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { invariantRegistry } = require('./invariant-registry');
|
|
7
|
+
const { invariantHooks } = require('./invariant-hooks');
|
|
8
|
+
|
|
9
|
+
class InvariantEnforcer {
|
|
10
|
+
constructor() {
|
|
11
|
+
// Sealed wrappers for critical operations
|
|
12
|
+
this.wrappers = new Map();
|
|
13
|
+
this.enforcedInterfaces = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a sealed wrapper that enforces invariants
|
|
18
|
+
* @param {string} name - Name of the wrapper
|
|
19
|
+
* @param {Function} implementation - The actual implementation
|
|
20
|
+
* @param {string} hookName - The hook to execute before the implementation
|
|
21
|
+
*/
|
|
22
|
+
createSealedWrapper(name, implementation, hookName) {
|
|
23
|
+
if (this.wrappers.has(name)) {
|
|
24
|
+
throw new Error(`Wrapper with name ${name} already exists`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const wrappedFunction = async (...args) => {
|
|
28
|
+
// Execute the hook with invariant checking before the actual implementation
|
|
29
|
+
return await invariantHooks.executeHook(hookName, { args }, (data) => {
|
|
30
|
+
return implementation(...data.args);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
this.wrappers.set(name, wrappedFunction);
|
|
35
|
+
return wrappedFunction;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a synchronous sealed wrapper
|
|
40
|
+
*/
|
|
41
|
+
createSealedWrapperSync(name, implementation, hookName) {
|
|
42
|
+
if (this.wrappers.has(name)) {
|
|
43
|
+
throw new Error(`Wrapper with name ${name} already exists`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const wrappedFunction = (...args) => {
|
|
47
|
+
// Execute the hook with invariant checking before the actual implementation
|
|
48
|
+
return invariantHooks.executeHookSync(hookName, { args }, (data) => {
|
|
49
|
+
return implementation(...data.args);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.wrappers.set(name, wrappedFunction);
|
|
54
|
+
return wrappedFunction;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get a sealed wrapper by name
|
|
59
|
+
*/
|
|
60
|
+
getWrapper(name) {
|
|
61
|
+
return this.wrappers.get(name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Seal an interface to enforce invariants
|
|
66
|
+
* @param {Object} targetInterface - The interface/object to seal
|
|
67
|
+
* @param {Object} invariantSpecs - Specifications for invariant enforcement
|
|
68
|
+
*/
|
|
69
|
+
sealInterface(targetInterface, invariantSpecs) {
|
|
70
|
+
const sealedInterface = {};
|
|
71
|
+
|
|
72
|
+
for (const [methodName, spec] of Object.entries(invariantSpecs)) {
|
|
73
|
+
if (typeof targetInterface[methodName] === 'function') {
|
|
74
|
+
sealedInterface[methodName] = async (...args) => {
|
|
75
|
+
// Execute the appropriate hook before the method
|
|
76
|
+
return await invariantHooks.executeHook(spec.hookName, { args }, (data) => {
|
|
77
|
+
return targetInterface[methodName](...data.args);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Also create a synchronous version
|
|
82
|
+
sealedInterface[`${methodName}Sync`] = (...args) => {
|
|
83
|
+
return invariantHooks.executeHookSync(spec.hookName, { args }, (data) => {
|
|
84
|
+
return targetInterface[methodName](...data.args);
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Prevent further modifications to enforce the contract
|
|
91
|
+
Object.freeze(sealedInterface);
|
|
92
|
+
this.enforcedInterfaces.set(targetInterface.constructor?.name || 'anonymous', sealedInterface);
|
|
93
|
+
|
|
94
|
+
return sealedInterface;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Decorator-style enforcement for class methods
|
|
99
|
+
*/
|
|
100
|
+
enforceMethod(target, methodName, hookName) {
|
|
101
|
+
const originalMethod = target[methodName];
|
|
102
|
+
|
|
103
|
+
if (typeof originalMethod !== 'function') {
|
|
104
|
+
throw new Error(`Method ${methodName} does not exist on target`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Replace the method with an invariant-enforced version
|
|
108
|
+
target[methodName] = async function(...args) {
|
|
109
|
+
return await invariantHooks.executeHook(hookName, { args, context: this }, (data) => {
|
|
110
|
+
return originalMethod.apply(data.context, data.args);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Also add a sync version
|
|
115
|
+
target[`${methodName}Sync`] = function(...args) {
|
|
116
|
+
return invariantHooks.executeHookSync(hookName, { args, context: this }, (data) => {
|
|
117
|
+
return originalMethod.apply(data.context, data.args);
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Framework-level hook integration
|
|
124
|
+
* This would be used to integrate with the existing ArcVision architecture
|
|
125
|
+
*/
|
|
126
|
+
integrateWithFramework(frameworkHooks) {
|
|
127
|
+
// Example: Integrate with existing ArcVision hooks
|
|
128
|
+
if (frameworkHooks && typeof frameworkHooks.addPreHook === 'function') {
|
|
129
|
+
frameworkHooks.addPreHook('parse-file', async (context) => {
|
|
130
|
+
// This runs before file parsing and enforces invariants
|
|
131
|
+
await invariantHooks.executeHook('pre-parse', context, () => {});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
frameworkHooks.addPostHook('analyze-file', async (context) => {
|
|
135
|
+
// This runs after analysis and enforces invariants
|
|
136
|
+
await invariantHooks.executeHook('post-analyze', context, () => {});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get all active enforcement mechanisms
|
|
143
|
+
*/
|
|
144
|
+
getStatus() {
|
|
145
|
+
return {
|
|
146
|
+
wrapperCount: this.wrappers.size,
|
|
147
|
+
interfaceCount: this.enforcedInterfaces.size,
|
|
148
|
+
registeredHooks: invariantHooks.hooks.size,
|
|
149
|
+
registeredInvariants: invariantRegistry.getAll().length
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Singleton enforcer instance
|
|
155
|
+
const invariantEnforcer = new InvariantEnforcer();
|
|
156
|
+
|
|
157
|
+
// Initialize common sealed wrappers for ArcVision operations
|
|
158
|
+
function initializeEnforcementMechanisms() {
|
|
159
|
+
console.log('Initializing invariant enforcement mechanisms...');
|
|
160
|
+
|
|
161
|
+
// Example: Seal critical ArcVision operations
|
|
162
|
+
// These would wrap the actual parsing, analysis, and persistence functions
|
|
163
|
+
|
|
164
|
+
console.log('Invariant enforcement mechanisms initialized');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
InvariantEnforcer,
|
|
169
|
+
invariantEnforcer,
|
|
170
|
+
initializeEnforcementMechanisms
|
|
171
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Invariant Evaluation Utilities
|
|
3
|
+
* Provides strengthened logic for invariant validation and evaluation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validates that an invariant object has required properties
|
|
8
|
+
*/
|
|
9
|
+
function isValidInvariant(invariant) {
|
|
10
|
+
if (!invariant || typeof invariant !== 'object') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Check for required fields
|
|
15
|
+
if (!invariant.id || typeof invariant.id !== 'string' || invariant.id.trim().length === 0) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!invariant.system || typeof invariant.system !== 'string' || invariant.system.trim().length === 0) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!invariant.description || typeof invariant.description !== 'string' || invariant.description.trim().length === 0) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!invariant.severity || typeof invariant.severity !== 'string' || !['block', 'risk', 'BLOCK', 'RISK'].includes(invariant.severity)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!invariant.scope || typeof invariant.scope !== 'object') {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!invariant.rule || typeof invariant.rule !== 'object') {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sanitize and normalize changed files array
|
|
44
|
+
*/
|
|
45
|
+
function sanitizeChangedFiles(changedFiles) {
|
|
46
|
+
if (!Array.isArray(changedFiles)) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return changedFiles
|
|
51
|
+
.filter(file => file && typeof file === 'string' && file.trim().length > 0)
|
|
52
|
+
.map(file => file.trim());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sanitize and normalize invariants array
|
|
57
|
+
*/
|
|
58
|
+
function sanitizeInvariants(invariants) {
|
|
59
|
+
if (!Array.isArray(invariants)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return invariants
|
|
64
|
+
.filter(inv => inv && typeof inv === 'object' && isValidInvariant(inv));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Enhanced evaluation result formatter
|
|
69
|
+
*/
|
|
70
|
+
function formatEnhancedResult(decision, violations, input) {
|
|
71
|
+
const blockingViolations = violations.filter(v =>
|
|
72
|
+
v.severity === 'block' || v.severity === 'BLOCK'
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const riskyViolations = violations.filter(v =>
|
|
76
|
+
v.severity === 'risk' || v.severity === 'RISK'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const baseResult = {
|
|
80
|
+
decision,
|
|
81
|
+
violations,
|
|
82
|
+
blockingViolations: blockingViolations.length,
|
|
83
|
+
riskyViolations: riskyViolations.length,
|
|
84
|
+
details: calculateImpactDetails(input, violations)
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
switch (decision) {
|
|
88
|
+
case 'BLOCKED':
|
|
89
|
+
return {
|
|
90
|
+
...baseResult,
|
|
91
|
+
reasons: violations.map(v => v.description || `Critical violation in invariant: ${v.id}`)
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
case 'RISKY':
|
|
95
|
+
return {
|
|
96
|
+
...baseResult,
|
|
97
|
+
reasons: violations.map(v => v.description || `Potential violation in invariant: ${v.id}`)
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
case 'ALLOWED':
|
|
101
|
+
default:
|
|
102
|
+
return {
|
|
103
|
+
...baseResult,
|
|
104
|
+
violations: [],
|
|
105
|
+
reasons: ['No invariant violations detected']
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Calculate impact details for the evaluation result
|
|
112
|
+
*/
|
|
113
|
+
function calculateImpactDetails(input, violations) {
|
|
114
|
+
const { changedFiles, dependencyGraph, context } = input || {};
|
|
115
|
+
|
|
116
|
+
// Calculate affected nodes from dependency graph
|
|
117
|
+
let affectedNodes = 0;
|
|
118
|
+
if (dependencyGraph && dependencyGraph.nodes && Array.isArray(dependencyGraph.nodes)) {
|
|
119
|
+
affectedNodes = dependencyGraph.nodes.filter((node) =>
|
|
120
|
+
changedFiles && Array.isArray(changedFiles) &&
|
|
121
|
+
changedFiles.includes(node.id || node.path)
|
|
122
|
+
).length;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Calculate blast radius impact if available in context
|
|
126
|
+
let blastRadiusImpact = 0;
|
|
127
|
+
if (context && context.blastRadiusAnalysis) {
|
|
128
|
+
blastRadiusImpact = context.blastRadiusAnalysis.totalAffected || 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check for authority core changes
|
|
132
|
+
let authorityCoreChanges = false;
|
|
133
|
+
if (context && Array.isArray(context.authorityCores)) {
|
|
134
|
+
authorityCoreChanges = changedFiles && Array.isArray(changedFiles) &&
|
|
135
|
+
changedFiles.some(file =>
|
|
136
|
+
context.authorityCores.some((core) => core.path === file)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
affectedNodes,
|
|
142
|
+
blastRadiusImpact,
|
|
143
|
+
authorityCoreChanges
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Enhanced error result creator
|
|
149
|
+
*/
|
|
150
|
+
function createEnhancedErrorResult(errorMessage) {
|
|
151
|
+
return {
|
|
152
|
+
decision: 'ERROR',
|
|
153
|
+
violations: [],
|
|
154
|
+
blockingViolations: 0,
|
|
155
|
+
riskyViolations: 0,
|
|
156
|
+
reasons: [errorMessage],
|
|
157
|
+
details: {
|
|
158
|
+
affectedNodes: 0,
|
|
159
|
+
blastRadiusImpact: 0,
|
|
160
|
+
authorityCoreChanges: false
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = {
|
|
166
|
+
isValidInvariant,
|
|
167
|
+
sanitizeChangedFiles,
|
|
168
|
+
sanitizeInvariants,
|
|
169
|
+
formatEnhancedResult,
|
|
170
|
+
calculateImpactDetails,
|
|
171
|
+
createEnhancedErrorResult
|
|
172
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant Hooks - Critical path enforcement points
|
|
3
|
+
* Implements mandatory invariant checks at high-leverage choke points
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { invariantRegistry } = require('./invariant-registry');
|
|
7
|
+
|
|
8
|
+
class InvariantHooks {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.hooks = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Register a hook at a critical execution point
|
|
15
|
+
* @param {string} hookName - Name of the hook (e.g., 'pre-parse', 'post-analyze')
|
|
16
|
+
* @param {string[]} invariantIds - Array of invariant IDs to check at this hook
|
|
17
|
+
* @param {Function} contextProvider - Function that provides context for invariant evaluation
|
|
18
|
+
*/
|
|
19
|
+
registerHook(hookName, invariantIds, contextProvider) {
|
|
20
|
+
this.hooks.set(hookName, {
|
|
21
|
+
invariantIds,
|
|
22
|
+
contextProvider
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Execute a hook with invariant checking
|
|
28
|
+
* @param {string} hookName - Name of the hook to execute
|
|
29
|
+
* @param {any} data - Input data for the hook
|
|
30
|
+
* @param {Function} next - The actual function to execute after invariant checks
|
|
31
|
+
*/
|
|
32
|
+
async executeHook(hookName, data, next) {
|
|
33
|
+
const hook = this.hooks.get(hookName);
|
|
34
|
+
if (!hook) {
|
|
35
|
+
// If no hook is registered, just execute the function
|
|
36
|
+
return await next(data);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Get context for invariant evaluation
|
|
40
|
+
const context = hook.contextProvider ? hook.contextProvider(data) : data;
|
|
41
|
+
|
|
42
|
+
// Check all registered invariants for this hook
|
|
43
|
+
const results = invariantRegistry.checkMultiple(hook.invariantIds, context);
|
|
44
|
+
|
|
45
|
+
// If all invariants passed, proceed with the actual function
|
|
46
|
+
if (Object.values(results).every(result => result === true)) {
|
|
47
|
+
return await next(data);
|
|
48
|
+
} else {
|
|
49
|
+
// Some invariants failed, the registry already handled the violation
|
|
50
|
+
// according to each invariant's critical_path setting
|
|
51
|
+
throw new Error(`Invariant violation prevented execution of hook: ${hookName}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Execute a hook synchronously
|
|
57
|
+
*/
|
|
58
|
+
executeHookSync(hookName, data, next) {
|
|
59
|
+
const hook = this.hooks.get(hookName);
|
|
60
|
+
if (!hook) {
|
|
61
|
+
return next(data);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get context for invariant evaluation
|
|
65
|
+
const context = hook.contextProvider ? hook.contextProvider(data) : data;
|
|
66
|
+
|
|
67
|
+
// Check all registered invariants for this hook
|
|
68
|
+
const results = invariantRegistry.checkMultiple(hook.invariantIds, context);
|
|
69
|
+
|
|
70
|
+
// If all invariants passed, proceed with the actual function
|
|
71
|
+
if (Object.values(results).every(result => result === true)) {
|
|
72
|
+
return next(data);
|
|
73
|
+
} else {
|
|
74
|
+
// Some invariants failed, the registry already handled the violation
|
|
75
|
+
throw new Error(`Invariant violation prevented execution of hook: ${hookName}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Create singleton instance
|
|
81
|
+
const invariantHooks = new InvariantHooks();
|
|
82
|
+
|
|
83
|
+
// Predefined critical path hooks for ArcVision system
|
|
84
|
+
const CRITICAL_HOOKS = {
|
|
85
|
+
// Hook for when a file is about to be parsed
|
|
86
|
+
PRE_PARSE: 'pre-parse',
|
|
87
|
+
|
|
88
|
+
// Hook for when AST analysis is complete
|
|
89
|
+
POST_ANALYZE: 'post-analyze',
|
|
90
|
+
|
|
91
|
+
// Hook for when context is about to be persisted
|
|
92
|
+
PRE_PERSIST: 'pre-persist',
|
|
93
|
+
|
|
94
|
+
// Hook for when external data is received (e.g., from dashboard API)
|
|
95
|
+
PRE_EXTERNAL_INPUT: 'pre-external-input',
|
|
96
|
+
|
|
97
|
+
// Hook for when module dependencies are being resolved
|
|
98
|
+
PRE_DEPENDENCY_RESOLUTION: 'pre-dependency-resolution'
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Register critical path hooks with appropriate invariants
|
|
102
|
+
function initializeCriticalHooks() {
|
|
103
|
+
// Hook before file parsing - check parser state integrity and file path boundaries
|
|
104
|
+
invariantHooks.registerHook(
|
|
105
|
+
CRITICAL_HOOKS.PRE_PARSE,
|
|
106
|
+
['parser-state-integrity', 'file-path-boundary'],
|
|
107
|
+
(data) => ({
|
|
108
|
+
parserState: data.parserState,
|
|
109
|
+
filePath: data.filePath
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Hook after analysis - check context schema conformance
|
|
114
|
+
invariantHooks.registerHook(
|
|
115
|
+
CRITICAL_HOOKS.POST_ANALYZE,
|
|
116
|
+
['context-schema-conformance'],
|
|
117
|
+
(data) => data.context
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// Hook before persisting context - check schema conformance
|
|
121
|
+
invariantHooks.registerHook(
|
|
122
|
+
CRITICAL_HOOKS.PRE_PERSIST,
|
|
123
|
+
['context-schema-conformance'],
|
|
124
|
+
(data) => data.context
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Hook for external input - check schema and boundaries
|
|
128
|
+
invariantHooks.registerHook(
|
|
129
|
+
CRITICAL_HOOKS.PRE_EXTERNAL_INPUT,
|
|
130
|
+
['context-schema-conformance', 'file-path-boundary'],
|
|
131
|
+
(data) => data
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Hook for dependency resolution - check dependency consistency
|
|
135
|
+
invariantHooks.registerHook(
|
|
136
|
+
CRITICAL_HOOKS.PRE_DEPENDENCY_RESOLUTION,
|
|
137
|
+
['dependency-consistency'],
|
|
138
|
+
(data) => ({
|
|
139
|
+
dependencies: data.dependencies,
|
|
140
|
+
availableModules: data.availableModules
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
console.log(`${invariantHooks.hooks.size} critical path hooks initialized`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
InvariantHooks,
|
|
149
|
+
invariantHooks,
|
|
150
|
+
CRITICAL_HOOKS,
|
|
151
|
+
initializeCriticalHooks
|
|
152
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant Integration Example
|
|
3
|
+
* Shows how the invariant system integrates with existing ArcVision components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { invariantRegistry } = require('./invariant-registry');
|
|
7
|
+
const { invariantHooks, CRITICAL_HOOKS } = require('./invariant-hooks');
|
|
8
|
+
const { invariantEnforcer } = require('./invariant-enforcer');
|
|
9
|
+
const { registerExampleInvariants } = require('./example-invariants');
|
|
10
|
+
|
|
11
|
+
// Example ArcVision Parser class (representing existing functionality)
|
|
12
|
+
class ArcVisionParser {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.currentState = {
|
|
15
|
+
currentFile: null,
|
|
16
|
+
dependencies: [],
|
|
17
|
+
ast: null
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Method to parse a file - this would be wrapped with invariant enforcement
|
|
22
|
+
async parseFile(filePath) {
|
|
23
|
+
console.log(`Parsing file: ${filePath}`);
|
|
24
|
+
|
|
25
|
+
// Simulate parsing logic
|
|
26
|
+
this.currentState.currentFile = filePath;
|
|
27
|
+
this.currentState.dependencies = ['example-dependency'];
|
|
28
|
+
this.currentState.ast = { type: 'Program', body: [] };
|
|
29
|
+
|
|
30
|
+
return this.currentState.ast;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Method to analyze dependencies - this would also be wrapped
|
|
34
|
+
async analyzeDependencies(dependencies) {
|
|
35
|
+
console.log(`Analyzing ${dependencies.length} dependencies`);
|
|
36
|
+
|
|
37
|
+
// Simulate analysis logic
|
|
38
|
+
const analysisResults = dependencies.map(dep => ({
|
|
39
|
+
name: dep,
|
|
40
|
+
status: 'valid',
|
|
41
|
+
references: []
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
return analysisResults;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Method to persist context - this would be wrapped too
|
|
48
|
+
async persistContext(context) {
|
|
49
|
+
console.log(`Persisting context with ${context.nodes?.length || 0} nodes`);
|
|
50
|
+
|
|
51
|
+
// Simulate persistence logic
|
|
52
|
+
return { success: true, id: 'context-id' };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Example of how to integrate invariants with the existing parser
|
|
57
|
+
class InvariantAwareParser {
|
|
58
|
+
constructor() {
|
|
59
|
+
this.parser = new ArcVisionParser();
|
|
60
|
+
|
|
61
|
+
// Initialize the invariant system
|
|
62
|
+
registerExampleInvariants();
|
|
63
|
+
require('./invariant-hooks').initializeCriticalHooks();
|
|
64
|
+
require('./invariant-enforcer').initializeEnforcementMechanisms();
|
|
65
|
+
|
|
66
|
+
// Seal the parser interface with invariant enforcement
|
|
67
|
+
this.sealedParser = invariantEnforcer.sealInterface(this.parser, {
|
|
68
|
+
parseFile: { hookName: CRITICAL_HOOKS.PRE_PARSE },
|
|
69
|
+
analyzeDependencies: { hookName: CRITICAL_HOOKS.PRE_DEPENDENCY_RESOLUTION },
|
|
70
|
+
persistContext: { hookName: CRITICAL_HOOKS.PRE_PERSIST }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Public methods that enforce invariants
|
|
75
|
+
async parseFile(filePath) {
|
|
76
|
+
// This calls the sealed interface which enforces invariants
|
|
77
|
+
return await this.sealedParser.parseFile(filePath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async analyzeDependencies(dependencies) {
|
|
81
|
+
// This calls the sealed interface which enforces invariants
|
|
82
|
+
return await this.sealedParser.analyzeDependencies(dependencies);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async persistContext(context) {
|
|
86
|
+
// This calls the sealed interface which enforces invariants
|
|
87
|
+
return await this.sealedParser.persistContext(context);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Alternative: Use method decoration on existing instances
|
|
91
|
+
static enhanceExistingParser(parserInstance) {
|
|
92
|
+
// Decorate individual methods with invariant enforcement
|
|
93
|
+
invariantEnforcer.enforceMethod(parserInstance, 'parseFile', CRITICAL_HOOKS.PRE_PARSE);
|
|
94
|
+
invariantEnforcer.enforceMethod(parserInstance, 'analyzeDependencies', CRITICAL_HOOKS.PRE_DEPENDENCY_RESOLUTION);
|
|
95
|
+
invariantEnforcer.enforceMethod(parserInstance, 'persistContext', CRITICAL_HOOKS.PRE_PERSIST);
|
|
96
|
+
|
|
97
|
+
return parserInstance;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Example of using sealed wrappers for specific operations
|
|
102
|
+
function createInvariantProtectedOperations() {
|
|
103
|
+
// Create a protected file parsing operation
|
|
104
|
+
const protectedParseFile = invariantEnforcer.createSealedWrapper(
|
|
105
|
+
'protected-parse-file',
|
|
106
|
+
async (filePath) => {
|
|
107
|
+
console.log(`Actually parsing file: ${filePath}`);
|
|
108
|
+
// Actual parsing logic here
|
|
109
|
+
return { ast: { type: 'Program' }, filePath };
|
|
110
|
+
},
|
|
111
|
+
CRITICAL_HOOKS.PRE_PARSE
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Create a protected persistence operation
|
|
115
|
+
const protectedPersistContext = invariantEnforcer.createSealedWrapper(
|
|
116
|
+
'protected-persist-context',
|
|
117
|
+
async (context) => {
|
|
118
|
+
console.log(`Actually persisting context: ${context.id}`);
|
|
119
|
+
// Actual persistence logic here
|
|
120
|
+
return { success: true, persistedId: context.id };
|
|
121
|
+
},
|
|
122
|
+
CRITICAL_HOOKS.PRE_PERSIST
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
protectedParseFile,
|
|
127
|
+
protectedPersistContext
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Demonstration function showing how invariants prevent systemic issues
|
|
132
|
+
async function demonstrateInvariantProtection() {
|
|
133
|
+
console.log('\n=== Demonstrating Invariant Protection ===\n');
|
|
134
|
+
|
|
135
|
+
const parser = new InvariantAwareParser();
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// This should work fine - valid inputs that satisfy invariants
|
|
139
|
+
console.log('1. Valid operation:');
|
|
140
|
+
await parser.parseFile('./valid-file.js');
|
|
141
|
+
console.log(' ✓ Parse successful\n');
|
|
142
|
+
|
|
143
|
+
// This should trigger dependency consistency warning (non-critical)
|
|
144
|
+
console.log('2. Testing dependency consistency:');
|
|
145
|
+
await parser.analyzeDependencies([{ name: 'missing-dep' }]);
|
|
146
|
+
console.log(' ^ Warning logged but operation continues\n');
|
|
147
|
+
|
|
148
|
+
// This should fail critically if parser state is invalid
|
|
149
|
+
console.log('3. Testing parser state integrity:');
|
|
150
|
+
try {
|
|
151
|
+
// Simulate invalid parser state
|
|
152
|
+
await invariantHooks.executeHook(
|
|
153
|
+
CRITICAL_HOOKS.PRE_PARSE,
|
|
154
|
+
{ parserState: { currentFile: '', dependencies: 'invalid-type' } },
|
|
155
|
+
() => {}
|
|
156
|
+
);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.log(` ✓ Critical violation properly blocked: ${error.message}\n`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Show system status
|
|
162
|
+
console.log('4. System Status:');
|
|
163
|
+
const status = invariantEnforcer.getStatus();
|
|
164
|
+
console.log(` - Registered invariants: ${status.registeredInvariants}`);
|
|
165
|
+
console.log(` - Active hooks: ${status.registeredHooks}`);
|
|
166
|
+
console.log(` - Protected wrappers: ${status.wrapperCount}`);
|
|
167
|
+
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error('Error during demonstration:', error);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Export for use in other parts of the system
|
|
174
|
+
module.exports = {
|
|
175
|
+
ArcVisionParser,
|
|
176
|
+
InvariantAwareParser,
|
|
177
|
+
createInvariantProtectedOperations,
|
|
178
|
+
demonstrateInvariantProtection
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// If run directly, demonstrate the system
|
|
182
|
+
if (require.main === module) {
|
|
183
|
+
demonstrateInvariantProtection()
|
|
184
|
+
.then(() => console.log('\nDemonstration complete'))
|
|
185
|
+
.catch(console.error);
|
|
186
|
+
}
|