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,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant Registry - Defines system rules that must never be violated
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class InvariantRegistry {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.invariants = new Map();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register a new invariant
|
|
12
|
+
*/
|
|
13
|
+
register(invariant) {
|
|
14
|
+
if (!invariant || typeof invariant !== 'object') {
|
|
15
|
+
console.warn('Warning: Cannot register invalid invariant (not an object)');
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!invariant.id) {
|
|
20
|
+
console.warn('Warning: Cannot register invariant without ID');
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate invariant structure
|
|
25
|
+
if (!this.validateInvariant(invariant)) {
|
|
26
|
+
console.warn(`Warning: Invariant ${invariant.id} does not meet required structure`);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Add timestamp if not provided
|
|
31
|
+
if (!invariant.createdAt) {
|
|
32
|
+
invariant.createdAt = new Date().toISOString();
|
|
33
|
+
} else {
|
|
34
|
+
// Ensure createdAt is a valid ISO string
|
|
35
|
+
try {
|
|
36
|
+
new Date(invariant.createdAt);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
invariant.createdAt = new Date().toISOString();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.invariants.set(invariant.id, invariant);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate invariant structure
|
|
48
|
+
*/
|
|
49
|
+
validateInvariant(invariant) {
|
|
50
|
+
if (!invariant.id || typeof invariant.id !== 'string') return false;
|
|
51
|
+
if (!invariant.system || typeof invariant.system !== 'string') return false;
|
|
52
|
+
if (!invariant.description || typeof invariant.description !== 'string') return false;
|
|
53
|
+
if (!invariant.severity || typeof invariant.severity !== 'string' || !['block', 'risk'].includes(invariant.severity)) return false;
|
|
54
|
+
if (!invariant.scope || typeof invariant.scope !== 'object') return false;
|
|
55
|
+
if (!invariant.rule || typeof invariant.rule !== 'object') return false;
|
|
56
|
+
if (!invariant.rule.type || typeof invariant.rule.type !== 'string') return false;
|
|
57
|
+
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get all invariants
|
|
63
|
+
*/
|
|
64
|
+
getAll() {
|
|
65
|
+
return Array.from(this.invariants.values());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get invariants by system
|
|
70
|
+
*/
|
|
71
|
+
getBySystem(system) {
|
|
72
|
+
if (typeof system !== 'string') {
|
|
73
|
+
console.warn('Warning: Invalid system parameter for getBySystem');
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return this.getAll().filter(inv => inv.system === system);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get invariants that match scope
|
|
82
|
+
*/
|
|
83
|
+
getMatchingInvariants(files) {
|
|
84
|
+
if (!Array.isArray(files)) {
|
|
85
|
+
console.warn('Warning: Invalid files parameter for getMatchingInvariants');
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return this.getAll().filter(invariant =>
|
|
90
|
+
this.matchesScope(files, invariant.scope)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if files match invariant scope
|
|
96
|
+
*/
|
|
97
|
+
matchesScope(files, scope) {
|
|
98
|
+
if (!Array.isArray(files)) return false;
|
|
99
|
+
if (!scope || typeof scope !== 'object') return false;
|
|
100
|
+
|
|
101
|
+
// If no scope restrictions, always matches
|
|
102
|
+
if (!scope.files && !scope.components && !scope.flows) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check file patterns using robust pattern matcher
|
|
107
|
+
if (scope.files && Array.isArray(scope.files) && scope.files.length > 0) {
|
|
108
|
+
try {
|
|
109
|
+
const { patternMatcher } = require('./pattern-matcher');
|
|
110
|
+
return files.some(file => {
|
|
111
|
+
if (typeof file !== 'string') return false;
|
|
112
|
+
return scope.files.some(pattern => {
|
|
113
|
+
if (typeof pattern !== 'string') return false;
|
|
114
|
+
try {
|
|
115
|
+
return patternMatcher.match(file, pattern, { matchBase: true });
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn(`Warning: Invalid pattern "${pattern}" in scope:`, error.message);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.warn('Warning: Could not process pattern matching for scope matching:', error.message);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// For now, just check files - we can expand to components/flows later
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Remove invariant by ID
|
|
134
|
+
*/
|
|
135
|
+
remove(id) {
|
|
136
|
+
if (typeof id !== 'string') {
|
|
137
|
+
console.warn('Warning: Invalid ID parameter for remove');
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const existed = this.invariants.has(id);
|
|
142
|
+
this.invariants.delete(id);
|
|
143
|
+
return existed;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Update existing invariant
|
|
148
|
+
*/
|
|
149
|
+
update(id, invariantUpdates) {
|
|
150
|
+
if (typeof id !== 'string') {
|
|
151
|
+
console.warn('Warning: Invalid ID parameter for update');
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!invariantUpdates || typeof invariantUpdates !== 'object') {
|
|
156
|
+
console.warn('Warning: Invalid updates parameter for update');
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const existing = this.invariants.get(id);
|
|
161
|
+
if (existing) {
|
|
162
|
+
const updated = {
|
|
163
|
+
...existing,
|
|
164
|
+
...invariantUpdates,
|
|
165
|
+
id, // Ensure ID stays the same
|
|
166
|
+
lastModified: new Date().toISOString()
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Validate the updated invariant
|
|
170
|
+
if (this.validateInvariant(updated)) {
|
|
171
|
+
this.invariants.set(id, updated);
|
|
172
|
+
return true;
|
|
173
|
+
} else {
|
|
174
|
+
console.warn(`Warning: Updated invariant ${id} does not meet required structure`);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Load invariants from file
|
|
184
|
+
*/
|
|
185
|
+
loadFromFile(filePath) {
|
|
186
|
+
if (typeof filePath !== 'string') {
|
|
187
|
+
console.warn('Warning: Invalid file path for loadFromFile');
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const fs = require('fs');
|
|
193
|
+
if (!fs.existsSync(filePath)) {
|
|
194
|
+
console.warn(`Warning: Invariants file does not exist: ${filePath}`);
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
199
|
+
const data = JSON.parse(content);
|
|
200
|
+
|
|
201
|
+
// Handle different possible structures
|
|
202
|
+
let invariantsToLoad = [];
|
|
203
|
+
|
|
204
|
+
if (Array.isArray(data)) {
|
|
205
|
+
// Direct array of invariants
|
|
206
|
+
invariantsToLoad = data;
|
|
207
|
+
} else if (data.project_specific_invariants) {
|
|
208
|
+
// Standard ArcVision format
|
|
209
|
+
invariantsToLoad = data.project_specific_invariants;
|
|
210
|
+
} else if (data.invariants) {
|
|
211
|
+
// Alternative format
|
|
212
|
+
invariantsToLoad = data.invariants;
|
|
213
|
+
} else {
|
|
214
|
+
// Try to find invariants in any property
|
|
215
|
+
const keys = Object.keys(data);
|
|
216
|
+
for (const key of keys) {
|
|
217
|
+
if (Array.isArray(data[key]) && data[key].length > 0 && data[key][0].id) {
|
|
218
|
+
invariantsToLoad = data[key];
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!Array.isArray(invariantsToLoad)) {
|
|
225
|
+
console.warn(`Warning: Could not find valid invariants array in ${filePath}`);
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Validate each invariant before loading
|
|
230
|
+
const validInvariants = invariantsToLoad.filter(invariant => {
|
|
231
|
+
if (!this.validateInvariant(invariant)) {
|
|
232
|
+
console.warn(`Warning: Skipping invalid invariant with ID: ${invariant.id || 'unknown'}`);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Clear existing invariants and load new ones
|
|
239
|
+
this.invariants.clear();
|
|
240
|
+
let loadedCount = 0;
|
|
241
|
+
validInvariants.forEach(inv => {
|
|
242
|
+
if (this.register(inv)) {
|
|
243
|
+
loadedCount++;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
console.log(`Loaded ${loadedCount} valid invariants from ${filePath}`);
|
|
248
|
+
return true;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.warn(`Could not load invariants from ${filePath}:`, error.message);
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Save invariants to file
|
|
257
|
+
*/
|
|
258
|
+
saveToFile(filePath) {
|
|
259
|
+
if (typeof filePath !== 'string') {
|
|
260
|
+
console.warn('Warning: Invalid file path for saveToFile');
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const fs = require('fs');
|
|
266
|
+
const invariants = this.getAll();
|
|
267
|
+
const data = {
|
|
268
|
+
version: '1.0',
|
|
269
|
+
project_specific_invariants: invariants,
|
|
270
|
+
generated_at: new Date().toISOString()
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
274
|
+
return true;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error(`Could not save invariants to ${filePath}:`, error.message);
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Get count of registered invariants
|
|
283
|
+
*/
|
|
284
|
+
getCount() {
|
|
285
|
+
return this.invariants.size;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Clear all invariants
|
|
290
|
+
*/
|
|
291
|
+
clear() {
|
|
292
|
+
this.invariants.clear();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Export singleton instance
|
|
297
|
+
const invariantRegistry = new InvariantRegistry();
|
|
298
|
+
module.exports = { InvariantRegistry, invariantRegistry };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant Registry - Defines system rules that must never be violated
|
|
3
|
+
*/
|
|
4
|
+
export type Invariant = {
|
|
5
|
+
id: string
|
|
6
|
+
system: string // e.g. "payments", "auth", "database"
|
|
7
|
+
description: string
|
|
8
|
+
severity: "block" | "risk" | "warning"
|
|
9
|
+
scope: {
|
|
10
|
+
files?: string[] // glob paths like "**/payment/**/*.js"
|
|
11
|
+
components?: string[] // component names like ["PaymentService", "AuthService"]
|
|
12
|
+
flows?: string[] // flow names like ["payment-processing", "auth-flow"]
|
|
13
|
+
}
|
|
14
|
+
rule: {
|
|
15
|
+
type: "dependency" | "flow" | "ownership" | "access_control" | "data_flow"
|
|
16
|
+
condition: any // abstract, interpreted by evaluator
|
|
17
|
+
}
|
|
18
|
+
owner?: string // team/person responsible for this invariant
|
|
19
|
+
createdAt: string // ISO date string
|
|
20
|
+
lastModified?: string // ISO date string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Invariant Registry Manager
|
|
25
|
+
*/
|
|
26
|
+
export class InvariantRegistry {
|
|
27
|
+
private invariants: Map<string, Invariant> = new Map()
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Register a new invariant
|
|
31
|
+
*/
|
|
32
|
+
register(invariant: Invariant): void {
|
|
33
|
+
this.invariants.set(invariant.id, invariant)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get all invariants
|
|
38
|
+
*/
|
|
39
|
+
getAll(): Invariant[] {
|
|
40
|
+
return Array.from(this.invariants.values())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get invariants by system
|
|
45
|
+
*/
|
|
46
|
+
getBySystem(system: string): Invariant[] {
|
|
47
|
+
return this.getAll().filter(inv => inv.system === system)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get invariants that match scope
|
|
52
|
+
*/
|
|
53
|
+
getMatchingInvariants(files: string[]): Invariant[] {
|
|
54
|
+
return this.getAll().filter(invariant =>
|
|
55
|
+
this.matchesScope(files, invariant.scope)
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Check if files match invariant scope
|
|
61
|
+
*/
|
|
62
|
+
private matchesScope(files: string[], scope: Invariant['scope']): boolean {
|
|
63
|
+
if (!scope.files && !scope.components && !scope.flows) {
|
|
64
|
+
return true // no scope restriction = matches all
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check file patterns
|
|
68
|
+
if (scope.files && scope.files.length > 0) {
|
|
69
|
+
const minimatch = require('minimatch')
|
|
70
|
+
return files.some(file =>
|
|
71
|
+
scope.files!.some(pattern =>
|
|
72
|
+
minimatch(file, pattern, { matchBase: true })
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// For now, just check files - we can expand to components/flows later
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Remove invariant by ID
|
|
83
|
+
*/
|
|
84
|
+
remove(id: string): void {
|
|
85
|
+
this.invariants.delete(id)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Update existing invariant
|
|
90
|
+
*/
|
|
91
|
+
update(id: string, invariant: Partial<Invariant>): void {
|
|
92
|
+
const existing = this.invariants.get(id)
|
|
93
|
+
if (existing) {
|
|
94
|
+
this.invariants.set(id, { ...existing, ...invariant, lastModified: new Date().toISOString() })
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Export singleton instance
|
|
100
|
+
export const invariantRegistry = new InvariantRegistry()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for Invariant System
|
|
3
|
+
* Defines the contract and structure for architectural invariants
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} Invariant
|
|
8
|
+
* @property {string} id - Unique identifier for the invariant
|
|
9
|
+
* @property {string} description - Human-readable description of what the invariant ensures
|
|
10
|
+
* @property {'module'|'boundary'|'system'} scope - Scope at which the invariant applies
|
|
11
|
+
* @property {boolean} critical_path - Whether violation causes existential system failure
|
|
12
|
+
* @property {Function} assertion - Function that evaluates to boolean given context
|
|
13
|
+
* @property {Function} [on_violation] - Optional handler for when invariant is violated
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} ViolationEvent
|
|
18
|
+
* @property {string} timestamp - ISO string timestamp of violation
|
|
19
|
+
* @property {string} invariantId - ID of the violated invariant
|
|
20
|
+
* @property {string} invariantDescription - Description of the violated invariant
|
|
21
|
+
* @property {'module'|'boundary'|'system'} scope - Scope of the invariant
|
|
22
|
+
* @property {boolean} criticalPath - Whether this is a critical path violation
|
|
23
|
+
* @property {any} context - Context where violation occurred
|
|
24
|
+
* @property {string|null} error - Error message if applicable
|
|
25
|
+
* @property {string|null} stack - Stack trace if applicable
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {Object} InvariantResult
|
|
30
|
+
* @property {boolean} passed - Whether the invariant held
|
|
31
|
+
* @property {ViolationEvent|null} violation - Violation event if invariant failed
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Interface for invariant-aware modules
|
|
36
|
+
*/
|
|
37
|
+
class InvariantAwareInterface {
|
|
38
|
+
/**
|
|
39
|
+
* Register invariants for this module/component
|
|
40
|
+
* @param {Invariant[]} invariants - Array of invariants to register
|
|
41
|
+
*/
|
|
42
|
+
registerInvariants(invariants) {
|
|
43
|
+
throw new Error('Must be implemented by subclass');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate that all registered invariants hold for given context
|
|
48
|
+
* @param {any} context - Context to validate against
|
|
49
|
+
* @returns {Object} - Validation results
|
|
50
|
+
*/
|
|
51
|
+
validateInvariants(context) {
|
|
52
|
+
throw new Error('Must be implemented by subclass');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get registered invariants
|
|
57
|
+
* @returns {Invariant[]} - Array of registered invariants
|
|
58
|
+
*/
|
|
59
|
+
getInvariants() {
|
|
60
|
+
throw new Error('Must be implemented by subclass');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
InvariantAwareInterface
|
|
66
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant System Index - Main entry point for the invariant system
|
|
3
|
+
* Provides unified access to all invariant functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { InvariantRegistry, invariantRegistry } = require('./invariant-registry');
|
|
7
|
+
const { InvariantAwareInterface } = require('./invariant-types');
|
|
8
|
+
const {
|
|
9
|
+
CONTEXT_SCHEMA_INVARIANT,
|
|
10
|
+
FILE_PATH_BOUNDARY_INVARIANT,
|
|
11
|
+
DEPENDENCY_CONSISTENCY_INVARIANT,
|
|
12
|
+
PARSER_STATE_INTEGRITY_INVARIANT,
|
|
13
|
+
registerExampleInvariants
|
|
14
|
+
} = require('./example-invariants');
|
|
15
|
+
const {
|
|
16
|
+
InvariantHooks,
|
|
17
|
+
invariantHooks,
|
|
18
|
+
CRITICAL_HOOKS,
|
|
19
|
+
initializeCriticalHooks
|
|
20
|
+
} = require('./invariant-hooks');
|
|
21
|
+
const {
|
|
22
|
+
InvariantEnforcer,
|
|
23
|
+
invariantEnforcer,
|
|
24
|
+
initializeEnforcementMechanisms
|
|
25
|
+
} = require('./invariant-enforcer');
|
|
26
|
+
const {
|
|
27
|
+
ArcVisionParser,
|
|
28
|
+
InvariantAwareParser,
|
|
29
|
+
createInvariantProtectedOperations,
|
|
30
|
+
demonstrateInvariantProtection
|
|
31
|
+
} = require('./invariant-integration-example');
|
|
32
|
+
|
|
33
|
+
// Initialize the complete invariant system
|
|
34
|
+
function initializeInvariantSystem() {
|
|
35
|
+
console.log('Initializing ArcVision Invariant System...');
|
|
36
|
+
|
|
37
|
+
// Register all example invariants
|
|
38
|
+
registerExampleInvariants();
|
|
39
|
+
|
|
40
|
+
// Initialize critical path hooks
|
|
41
|
+
initializeCriticalHooks();
|
|
42
|
+
|
|
43
|
+
// Initialize enforcement mechanisms
|
|
44
|
+
initializeEnforcementMechanisms();
|
|
45
|
+
|
|
46
|
+
console.log('ArcVision Invariant System initialized successfully');
|
|
47
|
+
console.log(`- ${invariantRegistry.getAll().length} invariants registered`);
|
|
48
|
+
console.log(`- ${invariantHooks.hooks.size} critical hooks configured`);
|
|
49
|
+
console.log('- Enforcement mechanisms active');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
// Core classes
|
|
54
|
+
InvariantRegistry,
|
|
55
|
+
InvariantAwareInterface,
|
|
56
|
+
InvariantHooks,
|
|
57
|
+
InvariantEnforcer,
|
|
58
|
+
|
|
59
|
+
// Singleton instances
|
|
60
|
+
invariantRegistry,
|
|
61
|
+
invariantHooks,
|
|
62
|
+
invariantEnforcer,
|
|
63
|
+
|
|
64
|
+
// Example invariants
|
|
65
|
+
CONTEXT_SCHEMA_INVARIANT,
|
|
66
|
+
FILE_PATH_BOUNDARY_INVARIANT,
|
|
67
|
+
DEPENDENCY_CONSISTENCY_INVARIANT,
|
|
68
|
+
PARSER_STATE_INTEGRITY_INVARIANT,
|
|
69
|
+
|
|
70
|
+
// Registration functions
|
|
71
|
+
registerExampleInvariants,
|
|
72
|
+
|
|
73
|
+
// Critical hooks
|
|
74
|
+
CRITICAL_HOOKS,
|
|
75
|
+
initializeCriticalHooks,
|
|
76
|
+
|
|
77
|
+
// Enforcement
|
|
78
|
+
initializeEnforcementMechanisms,
|
|
79
|
+
|
|
80
|
+
// Integration examples
|
|
81
|
+
ArcVisionParser,
|
|
82
|
+
InvariantAwareParser,
|
|
83
|
+
createInvariantProtectedOperations,
|
|
84
|
+
demonstrateInvariantProtection,
|
|
85
|
+
|
|
86
|
+
// System initialization
|
|
87
|
+
initializeInvariantSystem
|
|
88
|
+
};
|