tribunal-kit 9.2.6 → 9.2.7
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/.agent/ARCHITECTURE.md +2 -2
- package/.agent/history/architecture-intelligence.html +1487 -401
- package/.agent/history/architecture-model.json +9365 -5697
- package/.agent/history/architecture-verification.json +37 -9
- package/.agent/routing_index.json +2069 -3340
- package/.agent/rules/GEMINI.md +1 -1
- package/.agent/scripts/adaptive_execution.js +511 -0
- package/.agent/scripts/architecture_diff.js +303 -260
- package/.agent/scripts/architecture_extractor.js +792 -753
- package/.agent/scripts/architecture_health.js +293 -256
- package/.agent/scripts/architecture_intelligence.js +3100 -0
- package/.agent/scripts/architecture_verifier.js +303 -270
- package/.agent/scripts/architecture_visualizer.js +880 -873
- package/.agent/scripts/blast_radius_engine.js +274 -234
- package/.agent/scripts/capability_evolution.js +453 -0
- package/.agent/scripts/concept_extractor.js +240 -0
- package/.agent/scripts/consideration_engine.js +284 -0
- package/.agent/scripts/coverage_engine.js +102 -0
- package/.agent/scripts/cross_domain_engine.js +1883 -0
- package/.agent/scripts/engineering_memory.js +1313 -0
- package/.agent/scripts/integrity_manifest.js +1 -5
- package/.agent/scripts/judgment_engine.js +790 -0
- package/.agent/scripts/materiality_engine.js +251 -0
- package/.agent/scripts/outcome_engine.js +624 -0
- package/.agent/scripts/outcome_optimization_engine.js +1632 -0
- package/.agent/scripts/simulation_engine.js +1478 -0
- package/.agent/scripts/skill_intelligence.js +1371 -0
- package/.agent/scripts/validation_engine.js +236 -236
- package/.agent/scripts/verification_auditor.js +266 -0
- package/.agent/skill-intelligence/taxonomy/engineering-concepts.json +555 -0
- package/.agent/skill_topic_map.json +301 -341
- package/.agent/skills_inventory.json +4272 -6922
- package/.agent/workflows/arch.md +96 -80
- package/.agent/workflows/skill-intelligence.md +216 -0
- package/CONTRIBUTING.md +2 -2
- package/README.md +24 -24
- package/bin/adapter-install.js +1 -1
- package/package.json +8 -9
- package/plugins/core-plugin.json +1 -1
- package/plugins/gemini/extension.json +1 -1
- package/src/browser/index.js +2 -1
- package/src/browser/launcher.js +41 -1
- package/src/cli.js +3 -1
- package/src/commands/arch.js +261 -172
- package/src/commands/context.js +27 -8
- package/src/commands/learn.js +21 -6
- package/src/commands/memory.js +10 -1
- package/src/commands/native.js +12 -3
- package/src/commands/skill-intelligence.js +1165 -0
- package/src/commands/system1.js +105 -4
- package/src/context/ranker.js +337 -339
- package/src/evolution/engine.js +296 -295
- package/src/synthesis/claim_check_separator.js +294 -271
- package/src/system1/browser_intelligence.js +300 -0
- package/src/system1/constants.js +49 -0
- package/src/system1/decision_engine.js +498 -0
- package/src/system1/evidence_engine.js +602 -0
- package/src/system1/evolution_pipeline.js +581 -0
- package/src/system1/index.d.ts +114 -0
- package/src/system1/index.js +102 -0
- package/src/system1/reviewer_orchestrator.js +477 -0
- package/src/tui/banner.js +1 -1
- package/src/utils/fs.js +27 -0
|
@@ -0,0 +1,3100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* architecture_intelligence.js — Tribunal Kit Phase 7: Architecture & Trade-Off Intelligence
|
|
4
|
+
* ===========================================================================================
|
|
5
|
+
* Core Invariant:
|
|
6
|
+
* AN ARCHITECTURE MUST BE JUSTIFIED BY REQUIREMENTS, CONSTRAINTS, AND EVIDENCE.
|
|
7
|
+
* NO ARCHITECTURAL CHOICE SHOULD BE MADE SOLELY BECAUSE IT IS FAMILIAR, POPULAR,
|
|
8
|
+
* MODERN, OR EASY FOR THE MODEL TO GENERATE.
|
|
9
|
+
*
|
|
10
|
+
* Pipeline:
|
|
11
|
+
* TASK → REQUIREMENTS → CONSTRAINTS → CONSIDERATIONS → ARCHITECTURE DISCOVERY
|
|
12
|
+
* → CANDIDATE GENERATION → VALIDATION → TRADE-OFF ANALYSIS → FAILURE ANALYSIS
|
|
13
|
+
* → COST/PERF/SECURITY/OPS ANALYSIS → DECISION RECORD → VERIFICATION
|
|
14
|
+
*
|
|
15
|
+
* Implements Phase 7 Sections 4–46.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const crypto = require('crypto');
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// 1. REQUIREMENT INTELLIGENCE (SECTIONS 4–5)
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
const REQUIREMENT_TYPES = {
|
|
27
|
+
FUNCTIONAL: 'functional',
|
|
28
|
+
NON_FUNCTIONAL: 'non_functional',
|
|
29
|
+
CONSTRAINT: 'constraint',
|
|
30
|
+
PREFERENCE: 'preference',
|
|
31
|
+
ASSUMPTION: 'assumption',
|
|
32
|
+
UNKNOWN: 'unknown',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const CONFIDENCE_LEVELS = {
|
|
36
|
+
EXPLICIT: 'explicit',
|
|
37
|
+
INFERRED: 'inferred',
|
|
38
|
+
ASSUMED: 'assumed',
|
|
39
|
+
UNKNOWN: 'unknown',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Functional requirement detection patterns.
|
|
44
|
+
* Each pattern maps a keyword domain to a functional requirement.
|
|
45
|
+
*/
|
|
46
|
+
const FUNCTIONAL_PATTERNS = [
|
|
47
|
+
{
|
|
48
|
+
match: /(?:messag|chat|inbox|conversation|dm|direct message)/i,
|
|
49
|
+
req: 'messaging',
|
|
50
|
+
domain: 'communication',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
match: /(?:presence|online|offline|status|active user)/i,
|
|
54
|
+
req: 'presence',
|
|
55
|
+
domain: 'communication',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
match: /(?:history|archive|log|conversation record)/i,
|
|
59
|
+
req: 'conversation history',
|
|
60
|
+
domain: 'data',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
match: /(?:payment|checkout|charge|billing|invoice|subscription)/i,
|
|
64
|
+
req: 'payment processing',
|
|
65
|
+
domain: 'financial',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
match: /(?:auth|login|signup|register|sso|oauth|credential)/i,
|
|
69
|
+
req: 'authentication',
|
|
70
|
+
domain: 'security',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
match: /(?:permission|role|rbac|acl|access control|authorization)/i,
|
|
74
|
+
req: 'authorization',
|
|
75
|
+
domain: 'security',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
match: /(?:upload|file|attachment|media|image|video)/i,
|
|
79
|
+
req: 'file management',
|
|
80
|
+
domain: 'storage',
|
|
81
|
+
},
|
|
82
|
+
{ match: /(?:search|filter|query|lookup|find|full.text)/i, req: 'search', domain: 'data' },
|
|
83
|
+
{
|
|
84
|
+
match: /(?:notification|alert|push|email|sms|webhook)/i,
|
|
85
|
+
req: 'notifications',
|
|
86
|
+
domain: 'communication',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
match: /(?:dashboard|report|analytic|metric|chart|graph)/i,
|
|
90
|
+
req: 'analytics & reporting',
|
|
91
|
+
domain: 'data',
|
|
92
|
+
},
|
|
93
|
+
{ match: /(?:feed|timeline|stream|wall|activity)/i, req: 'activity feed', domain: 'social' },
|
|
94
|
+
{ match: /(?:recommend|suggest|personalize|ml|ai model)/i, req: 'recommendations', domain: 'ai' },
|
|
95
|
+
{
|
|
96
|
+
match: /(?:collaboration|realtime|collab|edit.*together|shared.*doc)/i,
|
|
97
|
+
req: 'real-time collaboration',
|
|
98
|
+
domain: 'collaboration',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
match: /(?:crud|create|read|update|delete|manage.*record)/i,
|
|
102
|
+
req: 'CRUD operations',
|
|
103
|
+
domain: 'data',
|
|
104
|
+
},
|
|
105
|
+
{ match: /(?:import|export|csv|excel|bulk)/i, req: 'data import/export', domain: 'data' },
|
|
106
|
+
{
|
|
107
|
+
match: /(?:schedule|cron|timer|queue|background|worker|job)/i,
|
|
108
|
+
req: 'background processing',
|
|
109
|
+
domain: 'compute',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
match: /(?:tenant|multi.?tenant|workspace|organization)/i,
|
|
113
|
+
req: 'multi-tenancy',
|
|
114
|
+
domain: 'isolation',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
match: /(?:agent|tool|llm|prompt|chain|rag|vector)/i,
|
|
118
|
+
req: 'AI agent integration',
|
|
119
|
+
domain: 'ai',
|
|
120
|
+
},
|
|
121
|
+
{ match: /(?:api|endpoint|rest|graphql|grpc|gateway)/i, req: 'API layer', domain: 'integration' },
|
|
122
|
+
{ match: /(?:cache|redis|memcache|cdn)/i, req: 'caching layer', domain: 'performance' },
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Non-functional requirement detection patterns.
|
|
127
|
+
*/
|
|
128
|
+
const NON_FUNCTIONAL_PATTERNS = [
|
|
129
|
+
{
|
|
130
|
+
match: /(?:low.?latency|fast|responsive|sub.?\d+ms|p99|p95|latency)/i,
|
|
131
|
+
req: 'low latency',
|
|
132
|
+
category: 'performance',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
match: /(?:high.?availability|uptime|99\.9|five.?nine|four.?nine|ha\b)/i,
|
|
136
|
+
req: 'high availability',
|
|
137
|
+
category: 'reliability',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
match: /(?:scal|horizontal|vertical|elastic|auto.?scale)/i,
|
|
141
|
+
req: 'scalability',
|
|
142
|
+
category: 'scalability',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
match: /(?:secure|encrypt|tls|ssl|zero.?trust|penetration)/i,
|
|
146
|
+
req: 'security',
|
|
147
|
+
category: 'security',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
match: /(?:reliable|fault.?tolerant|resilient|durable|crash.?safe)/i,
|
|
151
|
+
req: 'reliability',
|
|
152
|
+
category: 'reliability',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
match: /(?:consistent|acid|lineariz|serial|strong.?consisten)/i,
|
|
156
|
+
req: 'strong consistency',
|
|
157
|
+
category: 'consistency',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
match: /(?:eventual|async|lazy|background.?sync)/i,
|
|
161
|
+
req: 'eventual consistency',
|
|
162
|
+
category: 'consistency',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
match: /(?:observab|monitor|trace|log|metric|opentelemetry)/i,
|
|
166
|
+
req: 'observability',
|
|
167
|
+
category: 'operations',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
match: /(?:test|ci|cd|pipeline|deploy|rollback)/i,
|
|
171
|
+
req: 'CI/CD & deployability',
|
|
172
|
+
category: 'operations',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
match: /(?:maintain|clean|modular|readable|document)/i,
|
|
176
|
+
req: 'maintainability',
|
|
177
|
+
category: 'quality',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
match: /(?:audit|compliance|gdpr|hipaa|sox|pci|regulatory)/i,
|
|
181
|
+
req: 'compliance & auditability',
|
|
182
|
+
category: 'governance',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
match: /(?:cost|budget|cheap|expensive|billing.?optim)/i,
|
|
186
|
+
req: 'cost efficiency',
|
|
187
|
+
category: 'cost',
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Constraint extraction patterns.
|
|
193
|
+
*/
|
|
194
|
+
const CONSTRAINT_PATTERNS = [
|
|
195
|
+
{
|
|
196
|
+
match: /(\d[\d,.]*)\s*(?:user|customer|account|subscriber)/i,
|
|
197
|
+
req: 'user count',
|
|
198
|
+
extractor: m => m[1],
|
|
199
|
+
category: 'scale',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
match: /(\d[\d,.]*)\s*(?:req|request|rps|qps|tps)(?:\/s|\/sec|\/second)?/i,
|
|
203
|
+
req: 'request throughput',
|
|
204
|
+
extractor: m => m[1],
|
|
205
|
+
category: 'performance',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
match: /(\d[\d,.]*)\s*(?:gb|tb|pb|mb)\s*(?:data|storage|size)/i,
|
|
209
|
+
req: 'data volume',
|
|
210
|
+
extractor: m => m[1],
|
|
211
|
+
category: 'storage',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
match: /(?:aws|gcp|azure|vercel|cloudflare|heroku|digital.?ocean|fly\.io)/i,
|
|
215
|
+
req: 'cloud provider',
|
|
216
|
+
category: 'infrastructure',
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
match: /(?:postgres|mysql|mongo|dynamo|redis|sqlite|cockroach|supabase|planetscale|neon)/i,
|
|
220
|
+
req: 'database technology',
|
|
221
|
+
category: 'technology',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
match: /(?:react|vue|angular|svelte|next|nuxt|remix|astro)/i,
|
|
225
|
+
req: 'frontend framework',
|
|
226
|
+
category: 'technology',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
match: /(?:node|python|go|rust|java|c#|\.net|ruby|elixir|php)/i,
|
|
230
|
+
req: 'backend language',
|
|
231
|
+
category: 'technology',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
match: /(?:docker|kubernetes|k8s|serverless|lambda|container)/i,
|
|
235
|
+
req: 'deployment platform',
|
|
236
|
+
category: 'infrastructure',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
match: /(?:team of (\d+)|(\d+)\s*dev|solo|one.?person|small team|large team)/i,
|
|
240
|
+
req: 'team size',
|
|
241
|
+
category: 'team',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
match: /(?:deadline|timeline|sprint|week|month|quarter|mvp|prototype|poc)/i,
|
|
245
|
+
req: 'timeline',
|
|
246
|
+
category: 'schedule',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
match: /(?:gdpr|hipaa|sox|pci|ccpa|iso.?27001|fedramp)/i,
|
|
250
|
+
req: 'compliance requirement',
|
|
251
|
+
category: 'governance',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
match: /(?:data.?residen|sovereign|eu.?only|us.?only|region.?restrict)/i,
|
|
255
|
+
req: 'data residency',
|
|
256
|
+
category: 'governance',
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
match: /(?:existing|legacy|migrate|current system|brownfield)/i,
|
|
260
|
+
req: 'existing system',
|
|
261
|
+
category: 'migration',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
match: /(?:budget|cost.?limit|\$\d+|free.?tier|startup)/i,
|
|
265
|
+
req: 'budget constraint',
|
|
266
|
+
category: 'cost',
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
match: /(?:real.?time|sub.?second|instant|live|streaming)/i,
|
|
270
|
+
req: 'real-time requirement',
|
|
271
|
+
category: 'performance',
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
match: /(?:offline|pwa|local.?first|sync)/i,
|
|
275
|
+
req: 'offline capability',
|
|
276
|
+
category: 'availability',
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Extract structured requirements from a natural-language task description.
|
|
282
|
+
*
|
|
283
|
+
* @param {string} taskQuery
|
|
284
|
+
* @returns {Object} Structured requirements
|
|
285
|
+
*/
|
|
286
|
+
function extractRequirements(taskQuery) {
|
|
287
|
+
const q = (taskQuery || '').trim();
|
|
288
|
+
if (!q)
|
|
289
|
+
return {
|
|
290
|
+
functional: [],
|
|
291
|
+
non_functional: [],
|
|
292
|
+
constraints: [],
|
|
293
|
+
preferences: [],
|
|
294
|
+
assumptions: [],
|
|
295
|
+
unknowns: [],
|
|
296
|
+
raw_task: q,
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const functional = [];
|
|
300
|
+
const nonFunctional = [];
|
|
301
|
+
const constraints = [];
|
|
302
|
+
const preferences = [];
|
|
303
|
+
const assumptions = [];
|
|
304
|
+
const unknowns = [];
|
|
305
|
+
const seen = new Set();
|
|
306
|
+
|
|
307
|
+
// Extract functional requirements
|
|
308
|
+
for (const p of FUNCTIONAL_PATTERNS) {
|
|
309
|
+
if (p.match.test(q) && !seen.has(p.req)) {
|
|
310
|
+
seen.add(p.req);
|
|
311
|
+
functional.push({
|
|
312
|
+
requirement: p.req,
|
|
313
|
+
source: 'task_description',
|
|
314
|
+
type: REQUIREMENT_TYPES.FUNCTIONAL,
|
|
315
|
+
confidence: CONFIDENCE_LEVELS.EXPLICIT,
|
|
316
|
+
domain: p.domain,
|
|
317
|
+
evidence: [{ type: 'keyword_match', detail: `Detected "${p.req}" from task description` }],
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Extract non-functional requirements
|
|
323
|
+
for (const p of NON_FUNCTIONAL_PATTERNS) {
|
|
324
|
+
if (p.match.test(q) && !seen.has(p.req)) {
|
|
325
|
+
seen.add(p.req);
|
|
326
|
+
nonFunctional.push({
|
|
327
|
+
requirement: p.req,
|
|
328
|
+
source: 'task_description',
|
|
329
|
+
type: REQUIREMENT_TYPES.NON_FUNCTIONAL,
|
|
330
|
+
confidence: CONFIDENCE_LEVELS.EXPLICIT,
|
|
331
|
+
category: p.category,
|
|
332
|
+
evidence: [{ type: 'keyword_match', detail: `Detected "${p.req}" from task description` }],
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Extract constraints
|
|
338
|
+
for (const p of CONSTRAINT_PATTERNS) {
|
|
339
|
+
const m = q.match(p.match);
|
|
340
|
+
if (m && !seen.has(p.req)) {
|
|
341
|
+
seen.add(p.req);
|
|
342
|
+
constraints.push({
|
|
343
|
+
requirement: p.req,
|
|
344
|
+
source: 'task_description',
|
|
345
|
+
type: REQUIREMENT_TYPES.CONSTRAINT,
|
|
346
|
+
confidence: CONFIDENCE_LEVELS.EXPLICIT,
|
|
347
|
+
category: p.category,
|
|
348
|
+
value: p.extractor ? p.extractor(m) : m[0],
|
|
349
|
+
evidence: [{ type: 'keyword_match', detail: `Detected "${p.req}" constraint: ${m[0]}` }],
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Infer implicit requirements based on functional requirements
|
|
355
|
+
if (functional.some(f => f.domain === 'financial') && !seen.has('idempotency')) {
|
|
356
|
+
seen.add('idempotency');
|
|
357
|
+
nonFunctional.push({
|
|
358
|
+
requirement: 'idempotency',
|
|
359
|
+
source: 'inferred_from_financial_domain',
|
|
360
|
+
type: REQUIREMENT_TYPES.NON_FUNCTIONAL,
|
|
361
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
362
|
+
category: 'reliability',
|
|
363
|
+
evidence: [
|
|
364
|
+
{
|
|
365
|
+
type: 'domain_inference',
|
|
366
|
+
detail: 'Financial transactions require idempotency to prevent duplicate charges',
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (functional.some(f => f.domain === 'financial') && !seen.has('auditability')) {
|
|
373
|
+
seen.add('auditability');
|
|
374
|
+
nonFunctional.push({
|
|
375
|
+
requirement: 'auditability',
|
|
376
|
+
source: 'inferred_from_financial_domain',
|
|
377
|
+
type: REQUIREMENT_TYPES.NON_FUNCTIONAL,
|
|
378
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
379
|
+
category: 'governance',
|
|
380
|
+
evidence: [
|
|
381
|
+
{
|
|
382
|
+
type: 'domain_inference',
|
|
383
|
+
detail: 'Financial systems require audit trails for regulatory compliance',
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (functional.some(f => f.domain === 'communication') && !seen.has('low latency')) {
|
|
390
|
+
seen.add('low latency');
|
|
391
|
+
nonFunctional.push({
|
|
392
|
+
requirement: 'low latency',
|
|
393
|
+
source: 'inferred_from_communication_domain',
|
|
394
|
+
type: REQUIREMENT_TYPES.NON_FUNCTIONAL,
|
|
395
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
396
|
+
category: 'performance',
|
|
397
|
+
evidence: [
|
|
398
|
+
{
|
|
399
|
+
type: 'domain_inference',
|
|
400
|
+
detail: 'Communication systems require low latency for user experience',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Identify unknowns based on what's NOT specified
|
|
407
|
+
const unknownChecks = [
|
|
408
|
+
{ condition: !constraints.some(c => c.category === 'scale'), unknown: 'peak concurrent users' },
|
|
409
|
+
{
|
|
410
|
+
condition: !constraints.some(c => c.req === 'request throughput'),
|
|
411
|
+
unknown: 'request rate / throughput',
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
condition: !constraints.some(c => c.category === 'storage'),
|
|
415
|
+
unknown: 'data retention period',
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
condition: !constraints.some(c => c.req === 'data residency'),
|
|
419
|
+
unknown: 'geographic distribution',
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
condition: !constraints.some(c => c.category === 'team'),
|
|
423
|
+
unknown: 'team size and expertise',
|
|
424
|
+
},
|
|
425
|
+
{ condition: !constraints.some(c => c.category === 'cost'), unknown: 'budget' },
|
|
426
|
+
{ condition: !constraints.some(c => c.category === 'schedule'), unknown: 'timeline' },
|
|
427
|
+
];
|
|
428
|
+
|
|
429
|
+
for (const check of unknownChecks) {
|
|
430
|
+
if (check.condition) {
|
|
431
|
+
unknowns.push({
|
|
432
|
+
requirement: check.unknown,
|
|
433
|
+
type: REQUIREMENT_TYPES.UNKNOWN,
|
|
434
|
+
confidence: CONFIDENCE_LEVELS.UNKNOWN,
|
|
435
|
+
evidence: [],
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
functional,
|
|
442
|
+
non_functional: nonFunctional,
|
|
443
|
+
constraints,
|
|
444
|
+
preferences,
|
|
445
|
+
assumptions,
|
|
446
|
+
unknowns,
|
|
447
|
+
raw_task: q,
|
|
448
|
+
total: functional.length + nonFunctional.length + constraints.length,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ============================================================================
|
|
453
|
+
// 2. CONSTRAINT EXTRACTION (SECTION 6)
|
|
454
|
+
// ============================================================================
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Extract and categorize all constraints from task + requirements.
|
|
458
|
+
*
|
|
459
|
+
* @param {string} taskQuery
|
|
460
|
+
* @param {Object} requirements
|
|
461
|
+
* @returns {Object} Structured constraints
|
|
462
|
+
*/
|
|
463
|
+
function extractConstraints(taskQuery, requirements) {
|
|
464
|
+
const q = (taskQuery || '').toLowerCase();
|
|
465
|
+
const existingConstraints = (requirements && requirements.constraints) || [];
|
|
466
|
+
|
|
467
|
+
const allConstraints = [...existingConstraints];
|
|
468
|
+
const categories = new Set(existingConstraints.map(c => c.category));
|
|
469
|
+
|
|
470
|
+
// Budget constraint inference
|
|
471
|
+
if (
|
|
472
|
+
!categories.has('cost') &&
|
|
473
|
+
/(?:startup|bootstrap|mvp|poc|prototype|free.?tier|hobby)/i.test(q)
|
|
474
|
+
) {
|
|
475
|
+
allConstraints.push({
|
|
476
|
+
requirement: 'limited budget',
|
|
477
|
+
type: REQUIREMENT_TYPES.CONSTRAINT,
|
|
478
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
479
|
+
category: 'cost',
|
|
480
|
+
value: 'low',
|
|
481
|
+
evidence: [
|
|
482
|
+
{
|
|
483
|
+
type: 'context_inference',
|
|
484
|
+
detail: 'Startup/MVP/prototype context suggests limited budget',
|
|
485
|
+
},
|
|
486
|
+
],
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Team expertise inference
|
|
491
|
+
if (
|
|
492
|
+
!categories.has('team') &&
|
|
493
|
+
/(?:solo|one.?person|small team|junior|learning|first time)/i.test(q)
|
|
494
|
+
) {
|
|
495
|
+
allConstraints.push({
|
|
496
|
+
requirement: 'limited team capacity',
|
|
497
|
+
type: REQUIREMENT_TYPES.CONSTRAINT,
|
|
498
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
499
|
+
category: 'team',
|
|
500
|
+
value: 'small',
|
|
501
|
+
evidence: [
|
|
502
|
+
{
|
|
503
|
+
type: 'context_inference',
|
|
504
|
+
detail: 'Small team or solo developer context constrains operational complexity',
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Operational maturity inference
|
|
511
|
+
if (
|
|
512
|
+
!categories.has('operations') &&
|
|
513
|
+
/(?:no.?devops|no.?infra|managed|serverless|simple.?deploy)/i.test(q)
|
|
514
|
+
) {
|
|
515
|
+
allConstraints.push({
|
|
516
|
+
requirement: 'limited operational maturity',
|
|
517
|
+
type: REQUIREMENT_TYPES.CONSTRAINT,
|
|
518
|
+
confidence: CONFIDENCE_LEVELS.INFERRED,
|
|
519
|
+
category: 'operations',
|
|
520
|
+
value: 'low',
|
|
521
|
+
evidence: [
|
|
522
|
+
{
|
|
523
|
+
type: 'context_inference',
|
|
524
|
+
detail: 'No DevOps expertise mentioned; prefer simpler operational models',
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
constraints: allConstraints,
|
|
532
|
+
categories: [...new Set(allConstraints.map(c => c.category))],
|
|
533
|
+
total: allConstraints.length,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// ============================================================================
|
|
538
|
+
// 3. ARCHITECTURE PATTERN REGISTRY (SECTION 8)
|
|
539
|
+
// ============================================================================
|
|
540
|
+
|
|
541
|
+
const ARCHITECTURE_PATTERNS = {
|
|
542
|
+
monolith: {
|
|
543
|
+
pattern: 'Monolith',
|
|
544
|
+
use_cases: ['small-to-medium applications', 'early-stage products', 'simple domain'],
|
|
545
|
+
strengths: [
|
|
546
|
+
'simple deployment',
|
|
547
|
+
'simple debugging',
|
|
548
|
+
'low operational cost',
|
|
549
|
+
'strong consistency',
|
|
550
|
+
'fast development',
|
|
551
|
+
'easy testing',
|
|
552
|
+
],
|
|
553
|
+
weaknesses: [
|
|
554
|
+
'scaling limitations',
|
|
555
|
+
'deployment coupling',
|
|
556
|
+
'technology lock-in',
|
|
557
|
+
'team coupling',
|
|
558
|
+
],
|
|
559
|
+
failure_modes: ['single point of failure', 'memory exhaustion', 'deployment blocks'],
|
|
560
|
+
operational_cost: 'low',
|
|
561
|
+
scaling_characteristics: {
|
|
562
|
+
horizontal: 'limited',
|
|
563
|
+
vertical: 'primary',
|
|
564
|
+
data_partitioning: 'difficult',
|
|
565
|
+
},
|
|
566
|
+
security_considerations: ['single trust boundary', 'shared memory space'],
|
|
567
|
+
related_patterns: ['modular_monolith', 'layered'],
|
|
568
|
+
anti_patterns: ['god_service'],
|
|
569
|
+
required_capabilities: ['single deployment pipeline'],
|
|
570
|
+
},
|
|
571
|
+
modular_monolith: {
|
|
572
|
+
pattern: 'Modular Monolith',
|
|
573
|
+
use_cases: [
|
|
574
|
+
'medium applications',
|
|
575
|
+
'clear domain boundaries',
|
|
576
|
+
'team growth path',
|
|
577
|
+
'payment systems',
|
|
578
|
+
'SaaS platforms',
|
|
579
|
+
],
|
|
580
|
+
strengths: [
|
|
581
|
+
'domain isolation within single deployment',
|
|
582
|
+
'simple operations',
|
|
583
|
+
'strong consistency',
|
|
584
|
+
'easy refactoring to services later',
|
|
585
|
+
'independent module development',
|
|
586
|
+
],
|
|
587
|
+
weaknesses: [
|
|
588
|
+
'requires discipline to maintain module boundaries',
|
|
589
|
+
'shared database',
|
|
590
|
+
'single deployment unit',
|
|
591
|
+
],
|
|
592
|
+
failure_modes: ['boundary erosion', 'shared state leakage', 'deployment coupling persists'],
|
|
593
|
+
operational_cost: 'low',
|
|
594
|
+
scaling_characteristics: {
|
|
595
|
+
horizontal: 'moderate',
|
|
596
|
+
vertical: 'primary',
|
|
597
|
+
data_partitioning: 'module-scoped',
|
|
598
|
+
},
|
|
599
|
+
security_considerations: ['module-level access control', 'shared process space'],
|
|
600
|
+
related_patterns: ['monolith', 'hexagonal', 'microservices'],
|
|
601
|
+
anti_patterns: ['distributed_monolith'],
|
|
602
|
+
required_capabilities: ['module boundary enforcement', 'internal API contracts'],
|
|
603
|
+
},
|
|
604
|
+
microservices: {
|
|
605
|
+
pattern: 'Microservices',
|
|
606
|
+
use_cases: [
|
|
607
|
+
'large-scale systems',
|
|
608
|
+
'multiple teams',
|
|
609
|
+
'independent deployment',
|
|
610
|
+
'polyglot technology',
|
|
611
|
+
],
|
|
612
|
+
strengths: [
|
|
613
|
+
'independent deployment',
|
|
614
|
+
'technology flexibility',
|
|
615
|
+
'team autonomy',
|
|
616
|
+
'independent scaling',
|
|
617
|
+
'fault isolation',
|
|
618
|
+
],
|
|
619
|
+
weaknesses: [
|
|
620
|
+
'distributed system complexity',
|
|
621
|
+
'network latency',
|
|
622
|
+
'data consistency challenges',
|
|
623
|
+
'operational overhead',
|
|
624
|
+
'debugging difficulty',
|
|
625
|
+
],
|
|
626
|
+
failure_modes: [
|
|
627
|
+
'cascading failures',
|
|
628
|
+
'network partitions',
|
|
629
|
+
'distributed deadlocks',
|
|
630
|
+
'service discovery failures',
|
|
631
|
+
'data inconsistency',
|
|
632
|
+
],
|
|
633
|
+
operational_cost: 'high',
|
|
634
|
+
scaling_characteristics: {
|
|
635
|
+
horizontal: 'excellent',
|
|
636
|
+
vertical: 'per-service',
|
|
637
|
+
data_partitioning: 'per-service',
|
|
638
|
+
},
|
|
639
|
+
security_considerations: [
|
|
640
|
+
'service-to-service auth',
|
|
641
|
+
'network segmentation',
|
|
642
|
+
'secret distribution',
|
|
643
|
+
'multiple trust boundaries',
|
|
644
|
+
],
|
|
645
|
+
related_patterns: ['soa', 'api_gateway', 'service_mesh', 'saga'],
|
|
646
|
+
anti_patterns: ['premature_microservices', 'distributed_monolith', 'chatty_services'],
|
|
647
|
+
required_capabilities: [
|
|
648
|
+
'service discovery',
|
|
649
|
+
'distributed tracing',
|
|
650
|
+
'circuit breakers',
|
|
651
|
+
'container orchestration',
|
|
652
|
+
'CI/CD per service',
|
|
653
|
+
],
|
|
654
|
+
},
|
|
655
|
+
serverless: {
|
|
656
|
+
pattern: 'Serverless',
|
|
657
|
+
use_cases: [
|
|
658
|
+
'event-driven workloads',
|
|
659
|
+
'variable traffic',
|
|
660
|
+
'rapid prototyping',
|
|
661
|
+
'webhook handlers',
|
|
662
|
+
'scheduled jobs',
|
|
663
|
+
],
|
|
664
|
+
strengths: [
|
|
665
|
+
'zero server management',
|
|
666
|
+
'auto-scaling',
|
|
667
|
+
'pay-per-use',
|
|
668
|
+
'fast deployment',
|
|
669
|
+
'no idle cost',
|
|
670
|
+
],
|
|
671
|
+
weaknesses: [
|
|
672
|
+
'cold starts',
|
|
673
|
+
'execution time limits',
|
|
674
|
+
'vendor lock-in',
|
|
675
|
+
'debugging difficulty',
|
|
676
|
+
'limited local testing',
|
|
677
|
+
'stateless constraint',
|
|
678
|
+
],
|
|
679
|
+
failure_modes: [
|
|
680
|
+
'cold start latency',
|
|
681
|
+
'timeout errors',
|
|
682
|
+
'concurrent execution limits',
|
|
683
|
+
'vendor outages',
|
|
684
|
+
],
|
|
685
|
+
operational_cost: 'very_low_to_variable',
|
|
686
|
+
scaling_characteristics: {
|
|
687
|
+
horizontal: 'automatic',
|
|
688
|
+
vertical: 'limited_by_runtime',
|
|
689
|
+
data_partitioning: 'external',
|
|
690
|
+
},
|
|
691
|
+
security_considerations: [
|
|
692
|
+
'IAM roles',
|
|
693
|
+
'environment variable secrets',
|
|
694
|
+
'function-level permissions',
|
|
695
|
+
],
|
|
696
|
+
related_patterns: ['event_driven', 'api_gateway'],
|
|
697
|
+
anti_patterns: ['over_engineering'],
|
|
698
|
+
required_capabilities: ['managed database', 'event source integration'],
|
|
699
|
+
},
|
|
700
|
+
event_driven: {
|
|
701
|
+
pattern: 'Event-Driven',
|
|
702
|
+
use_cases: [
|
|
703
|
+
'async workflows',
|
|
704
|
+
'decoupled systems',
|
|
705
|
+
'audit trails',
|
|
706
|
+
'real-time processing',
|
|
707
|
+
'CQRS',
|
|
708
|
+
],
|
|
709
|
+
strengths: [
|
|
710
|
+
'loose coupling',
|
|
711
|
+
'async processing',
|
|
712
|
+
'audit trail',
|
|
713
|
+
'replay capability',
|
|
714
|
+
'temporal decoupling',
|
|
715
|
+
],
|
|
716
|
+
weaknesses: [
|
|
717
|
+
'eventual consistency',
|
|
718
|
+
'debugging complexity',
|
|
719
|
+
'event ordering',
|
|
720
|
+
'schema evolution',
|
|
721
|
+
'idempotency requirement',
|
|
722
|
+
],
|
|
723
|
+
failure_modes: [
|
|
724
|
+
'event loss',
|
|
725
|
+
'duplicate events',
|
|
726
|
+
'out-of-order processing',
|
|
727
|
+
'poison pills',
|
|
728
|
+
'consumer lag',
|
|
729
|
+
],
|
|
730
|
+
operational_cost: 'medium_to_high',
|
|
731
|
+
scaling_characteristics: {
|
|
732
|
+
horizontal: 'excellent',
|
|
733
|
+
vertical: 'per-consumer',
|
|
734
|
+
data_partitioning: 'partition-based',
|
|
735
|
+
},
|
|
736
|
+
security_considerations: [
|
|
737
|
+
'event payload encryption',
|
|
738
|
+
'consumer authorization',
|
|
739
|
+
'event source verification',
|
|
740
|
+
],
|
|
741
|
+
related_patterns: ['cqrs', 'event_sourcing', 'saga', 'transactional_outbox'],
|
|
742
|
+
anti_patterns: ['dual_write'],
|
|
743
|
+
required_capabilities: [
|
|
744
|
+
'message broker',
|
|
745
|
+
'dead-letter queue',
|
|
746
|
+
'idempotent consumers',
|
|
747
|
+
'schema registry',
|
|
748
|
+
],
|
|
749
|
+
},
|
|
750
|
+
cqrs: {
|
|
751
|
+
pattern: 'CQRS',
|
|
752
|
+
use_cases: [
|
|
753
|
+
'read-heavy systems',
|
|
754
|
+
'complex queries',
|
|
755
|
+
'separate read/write scaling',
|
|
756
|
+
'event sourcing complement',
|
|
757
|
+
],
|
|
758
|
+
strengths: ['optimized read/write models', 'independent scaling', 'query flexibility'],
|
|
759
|
+
weaknesses: [
|
|
760
|
+
'increased complexity',
|
|
761
|
+
'eventual consistency between read/write',
|
|
762
|
+
'synchronization logic',
|
|
763
|
+
],
|
|
764
|
+
failure_modes: ['read model staleness', 'sync failures', 'write model corruption'],
|
|
765
|
+
operational_cost: 'medium',
|
|
766
|
+
scaling_characteristics: {
|
|
767
|
+
horizontal: 'per-model',
|
|
768
|
+
vertical: 'per-model',
|
|
769
|
+
data_partitioning: 'read/write split',
|
|
770
|
+
},
|
|
771
|
+
security_considerations: ['separate read/write authorization'],
|
|
772
|
+
related_patterns: ['event_driven', 'event_sourcing'],
|
|
773
|
+
anti_patterns: ['over_engineering'],
|
|
774
|
+
required_capabilities: ['separate data stores or views', 'sync mechanism'],
|
|
775
|
+
},
|
|
776
|
+
event_sourcing: {
|
|
777
|
+
pattern: 'Event Sourcing',
|
|
778
|
+
use_cases: [
|
|
779
|
+
'audit-critical systems',
|
|
780
|
+
'financial ledgers',
|
|
781
|
+
'temporal queries',
|
|
782
|
+
'regulatory compliance',
|
|
783
|
+
],
|
|
784
|
+
strengths: [
|
|
785
|
+
'complete audit trail',
|
|
786
|
+
'temporal queries',
|
|
787
|
+
'replay capability',
|
|
788
|
+
'debugging via event replay',
|
|
789
|
+
],
|
|
790
|
+
weaknesses: ['storage growth', 'complexity', 'snapshot management', 'schema evolution'],
|
|
791
|
+
failure_modes: ['event store corruption', 'projection failures', 'snapshot inconsistency'],
|
|
792
|
+
operational_cost: 'high',
|
|
793
|
+
scaling_characteristics: {
|
|
794
|
+
horizontal: 'partition-based',
|
|
795
|
+
vertical: 'moderate',
|
|
796
|
+
data_partitioning: 'aggregate-based',
|
|
797
|
+
},
|
|
798
|
+
security_considerations: ['immutable event store access control', 'PII in events'],
|
|
799
|
+
related_patterns: ['cqrs', 'event_driven'],
|
|
800
|
+
anti_patterns: [],
|
|
801
|
+
required_capabilities: ['event store', 'projection engine', 'snapshot mechanism'],
|
|
802
|
+
},
|
|
803
|
+
hexagonal: {
|
|
804
|
+
pattern: 'Hexagonal (Ports & Adapters)',
|
|
805
|
+
use_cases: [
|
|
806
|
+
'domain-driven applications',
|
|
807
|
+
'testable business logic',
|
|
808
|
+
'infrastructure-agnostic core',
|
|
809
|
+
],
|
|
810
|
+
strengths: ['infrastructure independence', 'highly testable', 'clear domain boundaries'],
|
|
811
|
+
weaknesses: ['more boilerplate', 'learning curve', 'over-abstraction risk'],
|
|
812
|
+
failure_modes: ['port/adapter mismatch', 'leaky abstractions'],
|
|
813
|
+
operational_cost: 'low',
|
|
814
|
+
scaling_characteristics: {
|
|
815
|
+
horizontal: 'inherited',
|
|
816
|
+
vertical: 'inherited',
|
|
817
|
+
data_partitioning: 'inherited',
|
|
818
|
+
},
|
|
819
|
+
security_considerations: ['adapter-level validation'],
|
|
820
|
+
related_patterns: ['clean_architecture', 'modular_monolith'],
|
|
821
|
+
anti_patterns: ['over_engineering'],
|
|
822
|
+
required_capabilities: ['dependency injection'],
|
|
823
|
+
},
|
|
824
|
+
api_gateway: {
|
|
825
|
+
pattern: 'API Gateway',
|
|
826
|
+
use_cases: [
|
|
827
|
+
'microservices entry point',
|
|
828
|
+
'rate limiting',
|
|
829
|
+
'auth consolidation',
|
|
830
|
+
'request routing',
|
|
831
|
+
],
|
|
832
|
+
strengths: [
|
|
833
|
+
'centralized cross-cutting concerns',
|
|
834
|
+
'client simplification',
|
|
835
|
+
'protocol translation',
|
|
836
|
+
],
|
|
837
|
+
weaknesses: ['single point of failure', 'added latency', 'deployment bottleneck'],
|
|
838
|
+
failure_modes: ['gateway overload', 'routing errors', 'configuration drift'],
|
|
839
|
+
operational_cost: 'medium',
|
|
840
|
+
scaling_characteristics: {
|
|
841
|
+
horizontal: 'excellent',
|
|
842
|
+
vertical: 'moderate',
|
|
843
|
+
data_partitioning: 'not_applicable',
|
|
844
|
+
},
|
|
845
|
+
security_considerations: ['auth termination point', 'rate limiting', 'DDoS protection'],
|
|
846
|
+
related_patterns: ['microservices', 'bff'],
|
|
847
|
+
anti_patterns: ['god_service'],
|
|
848
|
+
required_capabilities: ['load balancer', 'health checks'],
|
|
849
|
+
},
|
|
850
|
+
saga: {
|
|
851
|
+
pattern: 'Saga (Distributed Transactions)',
|
|
852
|
+
use_cases: [
|
|
853
|
+
'cross-service transactions',
|
|
854
|
+
'long-running workflows',
|
|
855
|
+
'compensating transactions',
|
|
856
|
+
],
|
|
857
|
+
strengths: ['distributed consistency without 2PC', 'fault tolerance', 'eventual consistency'],
|
|
858
|
+
weaknesses: ['compensation complexity', 'debugging difficulty', 'partial failure handling'],
|
|
859
|
+
failure_modes: ['compensation failures', 'orphaned sagas', 'timeout deadlocks'],
|
|
860
|
+
operational_cost: 'medium_to_high',
|
|
861
|
+
scaling_characteristics: {
|
|
862
|
+
horizontal: 'per-step',
|
|
863
|
+
vertical: 'per-step',
|
|
864
|
+
data_partitioning: 'per-service',
|
|
865
|
+
},
|
|
866
|
+
security_considerations: ['step authorization', 'compensation authorization'],
|
|
867
|
+
related_patterns: ['event_driven', 'transactional_outbox', 'microservices'],
|
|
868
|
+
anti_patterns: ['distributed_transaction_without_need'],
|
|
869
|
+
required_capabilities: [
|
|
870
|
+
'saga orchestrator or choreography',
|
|
871
|
+
'compensating actions',
|
|
872
|
+
'idempotent steps',
|
|
873
|
+
],
|
|
874
|
+
},
|
|
875
|
+
transactional_outbox: {
|
|
876
|
+
pattern: 'Transactional Outbox',
|
|
877
|
+
use_cases: ['reliable event publishing', 'dual write prevention', 'at-least-once delivery'],
|
|
878
|
+
strengths: ['atomicity between DB write and event publish', 'reliable delivery'],
|
|
879
|
+
weaknesses: [
|
|
880
|
+
'polling overhead',
|
|
881
|
+
'outbox table growth',
|
|
882
|
+
'at-least-once semantics require idempotent consumers',
|
|
883
|
+
],
|
|
884
|
+
failure_modes: ['outbox reader lag', 'duplicate delivery'],
|
|
885
|
+
operational_cost: 'low_to_medium',
|
|
886
|
+
scaling_characteristics: {
|
|
887
|
+
horizontal: 'moderate',
|
|
888
|
+
vertical: 'moderate',
|
|
889
|
+
data_partitioning: 'per-service',
|
|
890
|
+
},
|
|
891
|
+
security_considerations: ['outbox table access control'],
|
|
892
|
+
related_patterns: ['event_driven', 'saga'],
|
|
893
|
+
anti_patterns: ['dual_write'],
|
|
894
|
+
required_capabilities: ['database with transactional support', 'outbox reader/poller'],
|
|
895
|
+
},
|
|
896
|
+
streaming: {
|
|
897
|
+
pattern: 'Streaming Architecture',
|
|
898
|
+
use_cases: [
|
|
899
|
+
'real-time analytics',
|
|
900
|
+
'IoT data processing',
|
|
901
|
+
'event processing',
|
|
902
|
+
'log aggregation',
|
|
903
|
+
],
|
|
904
|
+
strengths: ['real-time processing', 'high throughput', 'temporal windowing'],
|
|
905
|
+
weaknesses: [
|
|
906
|
+
'complexity',
|
|
907
|
+
'ordering challenges',
|
|
908
|
+
'exactly-once difficulty',
|
|
909
|
+
'operational cost',
|
|
910
|
+
],
|
|
911
|
+
failure_modes: ['backpressure', 'out-of-order events', 'late data'],
|
|
912
|
+
operational_cost: 'high',
|
|
913
|
+
scaling_characteristics: {
|
|
914
|
+
horizontal: 'partition-based',
|
|
915
|
+
vertical: 'per-consumer',
|
|
916
|
+
data_partitioning: 'topic/partition',
|
|
917
|
+
},
|
|
918
|
+
security_considerations: ['stream encryption', 'consumer group authorization'],
|
|
919
|
+
related_patterns: ['event_driven', 'lambda_architecture', 'kappa_architecture'],
|
|
920
|
+
anti_patterns: ['over_engineering'],
|
|
921
|
+
required_capabilities: ['stream processing framework', 'message broker with partitioning'],
|
|
922
|
+
},
|
|
923
|
+
bff: {
|
|
924
|
+
pattern: 'Backend for Frontend',
|
|
925
|
+
use_cases: ['multiple client types', 'mobile + web + API', 'client-specific aggregation'],
|
|
926
|
+
strengths: ['client-optimized API', 'reduced over-fetching', 'client-specific caching'],
|
|
927
|
+
weaknesses: ['code duplication across BFFs', 'added services', 'sync overhead'],
|
|
928
|
+
failure_modes: ['BFF-backend desync', 'BFF proliferation'],
|
|
929
|
+
operational_cost: 'medium',
|
|
930
|
+
scaling_characteristics: {
|
|
931
|
+
horizontal: 'per-BFF',
|
|
932
|
+
vertical: 'per-BFF',
|
|
933
|
+
data_partitioning: 'not_applicable',
|
|
934
|
+
},
|
|
935
|
+
security_considerations: ['per-client auth', 'data filtering per client type'],
|
|
936
|
+
related_patterns: ['api_gateway', 'microservices'],
|
|
937
|
+
anti_patterns: ['god_service'],
|
|
938
|
+
required_capabilities: ['per-client deployment pipelines'],
|
|
939
|
+
},
|
|
940
|
+
distributed_workers: {
|
|
941
|
+
pattern: 'Distributed Workers',
|
|
942
|
+
use_cases: [
|
|
943
|
+
'background processing',
|
|
944
|
+
'task queues',
|
|
945
|
+
'parallel computation',
|
|
946
|
+
'email/notification pipelines',
|
|
947
|
+
],
|
|
948
|
+
strengths: ['horizontal scaling', 'fault isolation', 'async processing'],
|
|
949
|
+
weaknesses: ['monitoring complexity', 'dead-letter handling', 'worker coordination'],
|
|
950
|
+
failure_modes: ['worker crash', 'poison pills', 'starvation', 'thundering herd'],
|
|
951
|
+
operational_cost: 'medium',
|
|
952
|
+
scaling_characteristics: {
|
|
953
|
+
horizontal: 'excellent',
|
|
954
|
+
vertical: 'per-worker',
|
|
955
|
+
data_partitioning: 'queue-based',
|
|
956
|
+
},
|
|
957
|
+
security_considerations: ['worker credential management', 'job payload validation'],
|
|
958
|
+
related_patterns: ['event_driven', 'serverless'],
|
|
959
|
+
anti_patterns: ['unbounded_retry'],
|
|
960
|
+
required_capabilities: ['message queue', 'dead-letter queue', 'health monitoring'],
|
|
961
|
+
},
|
|
962
|
+
batch: {
|
|
963
|
+
pattern: 'Batch Architecture',
|
|
964
|
+
use_cases: ['ETL pipelines', 'data warehousing', 'report generation', 'nightly processing'],
|
|
965
|
+
strengths: ['high throughput', 'simple error handling', 'resource scheduling'],
|
|
966
|
+
weaknesses: ['high latency', 'resource spikes', 'stale data'],
|
|
967
|
+
failure_modes: ['timeout', 'partial failure', 'data corruption on restart'],
|
|
968
|
+
operational_cost: 'low_to_medium',
|
|
969
|
+
scaling_characteristics: {
|
|
970
|
+
horizontal: 'partition-based',
|
|
971
|
+
vertical: 'moderate',
|
|
972
|
+
data_partitioning: 'time/partition-based',
|
|
973
|
+
},
|
|
974
|
+
security_considerations: ['data access scoping', 'temporary credential lifecycle'],
|
|
975
|
+
related_patterns: ['streaming', 'distributed_workers'],
|
|
976
|
+
anti_patterns: [],
|
|
977
|
+
required_capabilities: ['scheduler', 'data pipeline framework'],
|
|
978
|
+
},
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Retrieve all architecture patterns or a specific one.
|
|
983
|
+
*
|
|
984
|
+
* @param {string} [patternName]
|
|
985
|
+
* @returns {Object|Object[]}
|
|
986
|
+
*/
|
|
987
|
+
function getArchitecturePatterns(patternName) {
|
|
988
|
+
if (patternName) {
|
|
989
|
+
const key = patternName.toLowerCase().replace(/[\s-]+/g, '_');
|
|
990
|
+
return ARCHITECTURE_PATTERNS[key] || null;
|
|
991
|
+
}
|
|
992
|
+
return { ...ARCHITECTURE_PATTERNS };
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// ============================================================================
|
|
996
|
+
// 4. ANTI-PATTERN REGISTRY (SECTION 9)
|
|
997
|
+
// ============================================================================
|
|
998
|
+
|
|
999
|
+
const ANTI_PATTERNS = {
|
|
1000
|
+
premature_microservices: {
|
|
1001
|
+
name: 'Premature Microservices',
|
|
1002
|
+
description:
|
|
1003
|
+
'Adopting microservices before the domain is understood or the team can operate them.',
|
|
1004
|
+
detection: /(?:microservice|micro.service)/i,
|
|
1005
|
+
contraindications: ['small team', 'mvp', 'prototype', 'solo', 'startup', 'simple', 'crud'],
|
|
1006
|
+
severity: 'HIGH',
|
|
1007
|
+
rationale:
|
|
1008
|
+
'Microservices introduce distributed system complexity (network failures, data consistency, deployment coordination) that is unjustified when a modular monolith suffices.',
|
|
1009
|
+
alternative: 'modular_monolith',
|
|
1010
|
+
},
|
|
1011
|
+
distributed_monolith: {
|
|
1012
|
+
name: 'Distributed Monolith',
|
|
1013
|
+
description: 'Multiple services that must be deployed together and share a database.',
|
|
1014
|
+
detection:
|
|
1015
|
+
/(?:distributed.monolith|shared.database.*microservice|microservice.*shared.database)/i,
|
|
1016
|
+
contraindications: [],
|
|
1017
|
+
severity: 'CRITICAL',
|
|
1018
|
+
rationale:
|
|
1019
|
+
'Combines the complexity of distributed systems with none of the benefits (independent deployment, fault isolation).',
|
|
1020
|
+
alternative: 'modular_monolith',
|
|
1021
|
+
},
|
|
1022
|
+
shared_database_coupling: {
|
|
1023
|
+
name: 'Shared Database Coupling',
|
|
1024
|
+
description: 'Multiple services directly accessing the same database tables.',
|
|
1025
|
+
detection: /(?:shared.database|common.db|same.database)/i,
|
|
1026
|
+
contraindications: [],
|
|
1027
|
+
severity: 'HIGH',
|
|
1028
|
+
rationale:
|
|
1029
|
+
'Creates implicit coupling: schema changes in one service break others. Prevents independent scaling and deployment.',
|
|
1030
|
+
alternative: 'transactional_outbox',
|
|
1031
|
+
},
|
|
1032
|
+
synchronous_chain: {
|
|
1033
|
+
name: 'Synchronous Chain',
|
|
1034
|
+
description: 'Long chains of synchronous service-to-service calls.',
|
|
1035
|
+
detection: /(?:synchronous.chain|sync.call.*chain|chain.*sync)/i,
|
|
1036
|
+
contraindications: [],
|
|
1037
|
+
severity: 'HIGH',
|
|
1038
|
+
rationale:
|
|
1039
|
+
'Latency compounds multiplicatively; any service failure cascades through the entire chain.',
|
|
1040
|
+
alternative: 'event_driven',
|
|
1041
|
+
},
|
|
1042
|
+
cache_as_source_of_truth: {
|
|
1043
|
+
name: 'Cache as Source of Truth',
|
|
1044
|
+
description: 'Using cache as the primary data store instead of a durable database.',
|
|
1045
|
+
detection: /(?:cache.as.source|cache.only|redis.only.store)/i,
|
|
1046
|
+
contraindications: [],
|
|
1047
|
+
severity: 'CRITICAL',
|
|
1048
|
+
rationale:
|
|
1049
|
+
'Caches are ephemeral by design; eviction, restart, or memory pressure causes data loss.',
|
|
1050
|
+
alternative: 'modular_monolith',
|
|
1051
|
+
},
|
|
1052
|
+
dual_write: {
|
|
1053
|
+
name: 'Dual Write',
|
|
1054
|
+
description: 'Writing to two systems (DB + message broker) without atomicity.',
|
|
1055
|
+
detection: /(?:dual.write|write.*both|db.*and.*queue.*write)/i,
|
|
1056
|
+
contraindications: [],
|
|
1057
|
+
severity: 'HIGH',
|
|
1058
|
+
rationale:
|
|
1059
|
+
'If either write fails, the systems become permanently inconsistent. Use transactional outbox instead.',
|
|
1060
|
+
alternative: 'transactional_outbox',
|
|
1061
|
+
},
|
|
1062
|
+
unbounded_retry: {
|
|
1063
|
+
name: 'Unbounded Retry',
|
|
1064
|
+
description: 'Retrying failed operations without backoff, jitter, or circuit breaking.',
|
|
1065
|
+
detection: /(?:retry.*forever|unlimited.retry|no.backoff)/i,
|
|
1066
|
+
contraindications: [],
|
|
1067
|
+
severity: 'HIGH',
|
|
1068
|
+
rationale: 'Creates retry storms that overwhelm recovering services and amplify failures.',
|
|
1069
|
+
alternative: null,
|
|
1070
|
+
},
|
|
1071
|
+
over_engineering: {
|
|
1072
|
+
name: 'Over-Engineering',
|
|
1073
|
+
description: 'Using complex patterns (Kafka, K8s, event sourcing) for simple problems.',
|
|
1074
|
+
detection: /(?:kafka|kubernetes|k8s|event.sourc|cqrs)/i,
|
|
1075
|
+
contraindications: [
|
|
1076
|
+
'high throughput',
|
|
1077
|
+
'million',
|
|
1078
|
+
'distributed',
|
|
1079
|
+
'multi-region',
|
|
1080
|
+
'audit trail',
|
|
1081
|
+
'regulatory',
|
|
1082
|
+
'compliance',
|
|
1083
|
+
'large team',
|
|
1084
|
+
'real-time analytics',
|
|
1085
|
+
],
|
|
1086
|
+
severity: 'MEDIUM',
|
|
1087
|
+
rationale:
|
|
1088
|
+
'Complexity without corresponding requirements creates operational burden, slows development, and introduces unnecessary failure modes.',
|
|
1089
|
+
alternative: 'modular_monolith',
|
|
1090
|
+
},
|
|
1091
|
+
under_engineering: {
|
|
1092
|
+
name: 'Under-Engineering',
|
|
1093
|
+
description:
|
|
1094
|
+
'Missing critical engineering for the requirements (no transactions for payments, no auth for sensitive data).',
|
|
1095
|
+
detection: null, // Detected by absence, not by keyword
|
|
1096
|
+
contraindications: [],
|
|
1097
|
+
severity: 'CRITICAL',
|
|
1098
|
+
rationale:
|
|
1099
|
+
'Missing engineering fundamentals causes data corruption, security breaches, and financial loss.',
|
|
1100
|
+
alternative: null,
|
|
1101
|
+
},
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* Detect architecture anti-patterns in a task description.
|
|
1106
|
+
*
|
|
1107
|
+
* @param {string} taskQuery
|
|
1108
|
+
* @param {Object} [requirements]
|
|
1109
|
+
* @returns {Array<Object>} Detected anti-patterns with context
|
|
1110
|
+
*/
|
|
1111
|
+
function detectAntiPatterns(taskQuery, requirements) {
|
|
1112
|
+
const q = (taskQuery || '').toLowerCase();
|
|
1113
|
+
const detected = [];
|
|
1114
|
+
const detectedKeys = new Set();
|
|
1115
|
+
|
|
1116
|
+
for (const [key, ap] of Object.entries(ANTI_PATTERNS)) {
|
|
1117
|
+
if (!ap.detection) continue;
|
|
1118
|
+
if (!ap.detection.test(q)) continue;
|
|
1119
|
+
|
|
1120
|
+
// Check contraindications — if task mentions a valid use case, this isn't an anti-pattern
|
|
1121
|
+
const hasValidContext = ap.contraindications.some(ci => q.includes(ci));
|
|
1122
|
+
if (hasValidContext && key === 'over_engineering') continue; // Don't flag overengineering when context justifies it
|
|
1123
|
+
|
|
1124
|
+
// For premature_microservices, flag only if contraindications match (e.g. "microservices" + "startup")
|
|
1125
|
+
if (key === 'premature_microservices' && !hasValidContext) continue;
|
|
1126
|
+
|
|
1127
|
+
if (key === 'premature_microservices') {
|
|
1128
|
+
detected.push({
|
|
1129
|
+
anti_pattern: ap.name,
|
|
1130
|
+
severity: ap.severity,
|
|
1131
|
+
rationale: ap.rationale,
|
|
1132
|
+
context_aware: true,
|
|
1133
|
+
contraindication_match: ap.contraindications.filter(ci => q.includes(ci)),
|
|
1134
|
+
alternative: ap.alternative ? ARCHITECTURE_PATTERNS[ap.alternative]?.pattern : null,
|
|
1135
|
+
});
|
|
1136
|
+
} else {
|
|
1137
|
+
detected.push({
|
|
1138
|
+
anti_pattern: ap.name,
|
|
1139
|
+
severity: ap.severity,
|
|
1140
|
+
rationale: ap.rationale,
|
|
1141
|
+
context_aware: key === 'over_engineering',
|
|
1142
|
+
alternative: ap.alternative ? ARCHITECTURE_PATTERNS[ap.alternative]?.pattern : null,
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
detectedKeys.add(key);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// Check for over-engineering specifically (only if not already detected in loop)
|
|
1149
|
+
if (!detectedKeys.has('over_engineering')) {
|
|
1150
|
+
const overEng = ANTI_PATTERNS.over_engineering;
|
|
1151
|
+
if (overEng.detection.test(q)) {
|
|
1152
|
+
const hasJustification = overEng.contraindications.some(ci => q.includes(ci));
|
|
1153
|
+
if (!hasJustification) {
|
|
1154
|
+
detected.push({
|
|
1155
|
+
anti_pattern: overEng.name,
|
|
1156
|
+
severity: overEng.severity,
|
|
1157
|
+
rationale: overEng.rationale,
|
|
1158
|
+
context_aware: true,
|
|
1159
|
+
missing_justification:
|
|
1160
|
+
'No high-scale, regulatory, or multi-team requirement detected to justify this complexity.',
|
|
1161
|
+
alternative: ARCHITECTURE_PATTERNS[overEng.alternative]?.pattern || null,
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
return detected;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// ============================================================================
|
|
1171
|
+
// 5. CANDIDATE GENERATION (SECTION 7)
|
|
1172
|
+
// ============================================================================
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* Score how well a pattern matches requirements and constraints.
|
|
1176
|
+
*/
|
|
1177
|
+
function scoreCandidate(patternKey, pattern, requirements, constraints) {
|
|
1178
|
+
let score = 0;
|
|
1179
|
+
const reasons = [];
|
|
1180
|
+
const risks = [];
|
|
1181
|
+
const q = (requirements.raw_task || '').toLowerCase();
|
|
1182
|
+
const allConstraints = (constraints && constraints.constraints) || [];
|
|
1183
|
+
|
|
1184
|
+
// Scale matching
|
|
1185
|
+
const scaleConstraint = allConstraints.find(c => c.category === 'scale');
|
|
1186
|
+
const scaleValue = scaleConstraint
|
|
1187
|
+
? parseInt(String(scaleConstraint.value).replace(/[,.\s]/g, ''), 10)
|
|
1188
|
+
: 0;
|
|
1189
|
+
|
|
1190
|
+
if (scaleValue > 1000000) {
|
|
1191
|
+
if (['microservices', 'event_driven', 'streaming'].includes(patternKey)) {
|
|
1192
|
+
score += 3;
|
|
1193
|
+
reasons.push('Architecture supports high-scale workloads');
|
|
1194
|
+
} else if (['monolith'].includes(patternKey)) {
|
|
1195
|
+
score -= 2;
|
|
1196
|
+
risks.push(
|
|
1197
|
+
'Single-process architecture may not handle millions of users without decomposition',
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
} else if (scaleValue > 0 && scaleValue <= 100000) {
|
|
1201
|
+
if (['monolith', 'modular_monolith'].includes(patternKey)) {
|
|
1202
|
+
score += 2;
|
|
1203
|
+
reasons.push('Simpler architecture sufficient for moderate scale');
|
|
1204
|
+
}
|
|
1205
|
+
if (['microservices'].includes(patternKey)) {
|
|
1206
|
+
score -= 1;
|
|
1207
|
+
risks.push('Microservices complexity may not be justified at this scale');
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// Team constraint
|
|
1212
|
+
const teamConstraint = allConstraints.find(c => c.category === 'team');
|
|
1213
|
+
if (teamConstraint && /(?:small|solo|1|2|3)/.test(String(teamConstraint.value))) {
|
|
1214
|
+
if (['monolith', 'modular_monolith', 'serverless'].includes(patternKey)) {
|
|
1215
|
+
score += 2;
|
|
1216
|
+
reasons.push('Low operational overhead matches small team capacity');
|
|
1217
|
+
}
|
|
1218
|
+
if (['microservices', 'streaming'].includes(patternKey)) {
|
|
1219
|
+
score -= 2;
|
|
1220
|
+
risks.push('Small team cannot sustain operational overhead of distributed architecture');
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// Financial domain
|
|
1225
|
+
if (requirements.functional && requirements.functional.some(f => f.domain === 'financial')) {
|
|
1226
|
+
if (['modular_monolith', 'hexagonal'].includes(patternKey)) {
|
|
1227
|
+
score += 2;
|
|
1228
|
+
reasons.push('Strong consistency and transaction support for financial operations');
|
|
1229
|
+
}
|
|
1230
|
+
if (['serverless'].includes(patternKey)) {
|
|
1231
|
+
score -= 1;
|
|
1232
|
+
risks.push(
|
|
1233
|
+
'Serverless cold starts and execution limits may conflict with payment processing SLAs',
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// Real-time / communication domain
|
|
1239
|
+
if (
|
|
1240
|
+
requirements.functional &&
|
|
1241
|
+
requirements.functional.some(f => f.domain === 'communication' || f.domain === 'collaboration')
|
|
1242
|
+
) {
|
|
1243
|
+
if (['event_driven', 'streaming'].includes(patternKey)) {
|
|
1244
|
+
score += 2;
|
|
1245
|
+
reasons.push('Event-driven architecture supports real-time communication patterns');
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// Multi-tenancy
|
|
1250
|
+
if (requirements.functional && requirements.functional.some(f => f.domain === 'isolation')) {
|
|
1251
|
+
if (['modular_monolith', 'microservices'].includes(patternKey)) {
|
|
1252
|
+
score += 1;
|
|
1253
|
+
reasons.push('Architecture supports tenant isolation boundaries');
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// Cost constraint
|
|
1258
|
+
const costConstraint = allConstraints.find(c => c.category === 'cost');
|
|
1259
|
+
if (costConstraint && /(?:low|limited|budget|startup|free)/i.test(String(costConstraint.value))) {
|
|
1260
|
+
if (['monolith', 'modular_monolith', 'serverless'].includes(patternKey)) {
|
|
1261
|
+
score += 1;
|
|
1262
|
+
reasons.push('Lower infrastructure cost');
|
|
1263
|
+
}
|
|
1264
|
+
if (['microservices', 'streaming', 'event_sourcing'].includes(patternKey)) {
|
|
1265
|
+
score -= 1;
|
|
1266
|
+
risks.push('Higher infrastructure cost may exceed budget constraints');
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// Timeline constraint
|
|
1271
|
+
const timeConstraint = allConstraints.find(c => c.category === 'schedule');
|
|
1272
|
+
if (
|
|
1273
|
+
timeConstraint &&
|
|
1274
|
+
/(?:mvp|prototype|poc|fast|quick|week)/i.test(String(timeConstraint.value || ''))
|
|
1275
|
+
) {
|
|
1276
|
+
if (['monolith', 'modular_monolith', 'serverless'].includes(patternKey)) {
|
|
1277
|
+
score += 2;
|
|
1278
|
+
reasons.push('Faster time to first deployment');
|
|
1279
|
+
}
|
|
1280
|
+
if (['microservices', 'event_sourcing'].includes(patternKey)) {
|
|
1281
|
+
score -= 1;
|
|
1282
|
+
risks.push('Higher upfront investment delays time to market');
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
return { pattern: patternKey, name: pattern.pattern, score, reasons, risks };
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* Generate architecture candidates based on requirements and constraints.
|
|
1291
|
+
*
|
|
1292
|
+
* @param {Object} requirements
|
|
1293
|
+
* @param {Object} constraints
|
|
1294
|
+
* @param {Array} [considerations]
|
|
1295
|
+
* @returns {Object} Architecture candidates with scores
|
|
1296
|
+
*/
|
|
1297
|
+
function generateCandidates(requirements, constraints, considerations) {
|
|
1298
|
+
const scored = [];
|
|
1299
|
+
|
|
1300
|
+
for (const [key, pattern] of Object.entries(ARCHITECTURE_PATTERNS)) {
|
|
1301
|
+
// Skip highly specific patterns that are sub-components rather than top-level architectures
|
|
1302
|
+
if (['api_gateway', 'bff', 'saga', 'transactional_outbox'].includes(key)) continue;
|
|
1303
|
+
|
|
1304
|
+
const result = scoreCandidate(key, pattern, requirements, constraints);
|
|
1305
|
+
scored.push(result);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Sort by score descending
|
|
1309
|
+
scored.sort((a, b) => b.score - a.score);
|
|
1310
|
+
|
|
1311
|
+
// Take top 2-4 candidates with meaningful differentiation
|
|
1312
|
+
const topScore = scored[0]?.score || 0;
|
|
1313
|
+
const candidates = scored.filter(s => s.score >= topScore - 3 && s.score >= -1).slice(0, 4);
|
|
1314
|
+
|
|
1315
|
+
return {
|
|
1316
|
+
candidates: candidates.map((c, idx) => ({
|
|
1317
|
+
rank: idx + 1,
|
|
1318
|
+
pattern: c.pattern,
|
|
1319
|
+
name: c.name,
|
|
1320
|
+
score: c.score,
|
|
1321
|
+
reasons: c.reasons,
|
|
1322
|
+
risks: c.risks,
|
|
1323
|
+
details: ARCHITECTURE_PATTERNS[c.pattern] || {},
|
|
1324
|
+
})),
|
|
1325
|
+
total_evaluated: scored.length,
|
|
1326
|
+
recommendation: candidates[0] ? candidates[0].name : 'Unknown',
|
|
1327
|
+
recommendation_rationale: candidates[0]
|
|
1328
|
+
? candidates[0].reasons.join('; ')
|
|
1329
|
+
: 'No matching pattern found',
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// ============================================================================
|
|
1334
|
+
// 6. TRADE-OFF ENGINE (SECTIONS 10–11)
|
|
1335
|
+
// ============================================================================
|
|
1336
|
+
|
|
1337
|
+
const TRADEOFF_CRITERIA = [
|
|
1338
|
+
'complexity',
|
|
1339
|
+
'scalability',
|
|
1340
|
+
'performance',
|
|
1341
|
+
'reliability',
|
|
1342
|
+
'availability',
|
|
1343
|
+
'consistency',
|
|
1344
|
+
'security',
|
|
1345
|
+
'cost',
|
|
1346
|
+
'development_speed',
|
|
1347
|
+
'operational_burden',
|
|
1348
|
+
'observability',
|
|
1349
|
+
'testing_difficulty',
|
|
1350
|
+
'deployment_complexity',
|
|
1351
|
+
'recovery_complexity',
|
|
1352
|
+
'team_complexity',
|
|
1353
|
+
'data_management',
|
|
1354
|
+
'vendor_lock_in',
|
|
1355
|
+
'future_evolution',
|
|
1356
|
+
];
|
|
1357
|
+
|
|
1358
|
+
/**
|
|
1359
|
+
* Rate a candidate on a single criterion (LOW / MODERATE / HIGH / VERY_HIGH).
|
|
1360
|
+
*/
|
|
1361
|
+
function rateCriterion(patternKey, criterion) {
|
|
1362
|
+
const ratings = {
|
|
1363
|
+
monolith: {
|
|
1364
|
+
complexity: 'LOW',
|
|
1365
|
+
scalability: 'LOW',
|
|
1366
|
+
performance: 'HIGH',
|
|
1367
|
+
reliability: 'MODERATE',
|
|
1368
|
+
availability: 'MODERATE',
|
|
1369
|
+
consistency: 'HIGH',
|
|
1370
|
+
security: 'MODERATE',
|
|
1371
|
+
cost: 'LOW',
|
|
1372
|
+
development_speed: 'HIGH',
|
|
1373
|
+
operational_burden: 'LOW',
|
|
1374
|
+
observability: 'MODERATE',
|
|
1375
|
+
testing_difficulty: 'LOW',
|
|
1376
|
+
deployment_complexity: 'LOW',
|
|
1377
|
+
recovery_complexity: 'LOW',
|
|
1378
|
+
team_complexity: 'LOW',
|
|
1379
|
+
data_management: 'LOW',
|
|
1380
|
+
vendor_lock_in: 'LOW',
|
|
1381
|
+
future_evolution: 'LOW',
|
|
1382
|
+
},
|
|
1383
|
+
modular_monolith: {
|
|
1384
|
+
complexity: 'MODERATE',
|
|
1385
|
+
scalability: 'MODERATE',
|
|
1386
|
+
performance: 'HIGH',
|
|
1387
|
+
reliability: 'MODERATE',
|
|
1388
|
+
availability: 'MODERATE',
|
|
1389
|
+
consistency: 'HIGH',
|
|
1390
|
+
security: 'MODERATE',
|
|
1391
|
+
cost: 'LOW',
|
|
1392
|
+
development_speed: 'HIGH',
|
|
1393
|
+
operational_burden: 'LOW',
|
|
1394
|
+
observability: 'MODERATE',
|
|
1395
|
+
testing_difficulty: 'LOW',
|
|
1396
|
+
deployment_complexity: 'LOW',
|
|
1397
|
+
recovery_complexity: 'LOW',
|
|
1398
|
+
team_complexity: 'LOW',
|
|
1399
|
+
data_management: 'MODERATE',
|
|
1400
|
+
vendor_lock_in: 'LOW',
|
|
1401
|
+
future_evolution: 'MODERATE',
|
|
1402
|
+
},
|
|
1403
|
+
microservices: {
|
|
1404
|
+
complexity: 'VERY_HIGH',
|
|
1405
|
+
scalability: 'VERY_HIGH',
|
|
1406
|
+
performance: 'MODERATE',
|
|
1407
|
+
reliability: 'HIGH',
|
|
1408
|
+
availability: 'HIGH',
|
|
1409
|
+
consistency: 'LOW',
|
|
1410
|
+
security: 'HIGH',
|
|
1411
|
+
cost: 'HIGH',
|
|
1412
|
+
development_speed: 'LOW',
|
|
1413
|
+
operational_burden: 'VERY_HIGH',
|
|
1414
|
+
observability: 'HIGH',
|
|
1415
|
+
testing_difficulty: 'HIGH',
|
|
1416
|
+
deployment_complexity: 'HIGH',
|
|
1417
|
+
recovery_complexity: 'MODERATE',
|
|
1418
|
+
team_complexity: 'HIGH',
|
|
1419
|
+
data_management: 'HIGH',
|
|
1420
|
+
vendor_lock_in: 'MODERATE',
|
|
1421
|
+
future_evolution: 'HIGH',
|
|
1422
|
+
},
|
|
1423
|
+
serverless: {
|
|
1424
|
+
complexity: 'MODERATE',
|
|
1425
|
+
scalability: 'HIGH',
|
|
1426
|
+
performance: 'MODERATE',
|
|
1427
|
+
reliability: 'HIGH',
|
|
1428
|
+
availability: 'HIGH',
|
|
1429
|
+
consistency: 'MODERATE',
|
|
1430
|
+
security: 'MODERATE',
|
|
1431
|
+
cost: 'LOW',
|
|
1432
|
+
development_speed: 'HIGH',
|
|
1433
|
+
operational_burden: 'LOW',
|
|
1434
|
+
observability: 'MODERATE',
|
|
1435
|
+
testing_difficulty: 'MODERATE',
|
|
1436
|
+
deployment_complexity: 'LOW',
|
|
1437
|
+
recovery_complexity: 'LOW',
|
|
1438
|
+
team_complexity: 'LOW',
|
|
1439
|
+
data_management: 'MODERATE',
|
|
1440
|
+
vendor_lock_in: 'HIGH',
|
|
1441
|
+
future_evolution: 'MODERATE',
|
|
1442
|
+
},
|
|
1443
|
+
event_driven: {
|
|
1444
|
+
complexity: 'HIGH',
|
|
1445
|
+
scalability: 'HIGH',
|
|
1446
|
+
performance: 'MODERATE',
|
|
1447
|
+
reliability: 'HIGH',
|
|
1448
|
+
availability: 'HIGH',
|
|
1449
|
+
consistency: 'LOW',
|
|
1450
|
+
security: 'MODERATE',
|
|
1451
|
+
cost: 'MODERATE',
|
|
1452
|
+
development_speed: 'MODERATE',
|
|
1453
|
+
operational_burden: 'MODERATE',
|
|
1454
|
+
observability: 'MODERATE',
|
|
1455
|
+
testing_difficulty: 'HIGH',
|
|
1456
|
+
deployment_complexity: 'MODERATE',
|
|
1457
|
+
recovery_complexity: 'MODERATE',
|
|
1458
|
+
team_complexity: 'MODERATE',
|
|
1459
|
+
data_management: 'MODERATE',
|
|
1460
|
+
vendor_lock_in: 'MODERATE',
|
|
1461
|
+
future_evolution: 'HIGH',
|
|
1462
|
+
},
|
|
1463
|
+
cqrs: {
|
|
1464
|
+
complexity: 'HIGH',
|
|
1465
|
+
scalability: 'HIGH',
|
|
1466
|
+
performance: 'HIGH',
|
|
1467
|
+
reliability: 'MODERATE',
|
|
1468
|
+
availability: 'MODERATE',
|
|
1469
|
+
consistency: 'LOW',
|
|
1470
|
+
security: 'MODERATE',
|
|
1471
|
+
cost: 'MODERATE',
|
|
1472
|
+
development_speed: 'LOW',
|
|
1473
|
+
operational_burden: 'MODERATE',
|
|
1474
|
+
observability: 'MODERATE',
|
|
1475
|
+
testing_difficulty: 'HIGH',
|
|
1476
|
+
deployment_complexity: 'MODERATE',
|
|
1477
|
+
recovery_complexity: 'MODERATE',
|
|
1478
|
+
team_complexity: 'MODERATE',
|
|
1479
|
+
data_management: 'HIGH',
|
|
1480
|
+
vendor_lock_in: 'LOW',
|
|
1481
|
+
future_evolution: 'HIGH',
|
|
1482
|
+
},
|
|
1483
|
+
streaming: {
|
|
1484
|
+
complexity: 'VERY_HIGH',
|
|
1485
|
+
scalability: 'VERY_HIGH',
|
|
1486
|
+
performance: 'HIGH',
|
|
1487
|
+
reliability: 'HIGH',
|
|
1488
|
+
availability: 'HIGH',
|
|
1489
|
+
consistency: 'LOW',
|
|
1490
|
+
security: 'MODERATE',
|
|
1491
|
+
cost: 'HIGH',
|
|
1492
|
+
development_speed: 'LOW',
|
|
1493
|
+
operational_burden: 'HIGH',
|
|
1494
|
+
observability: 'MODERATE',
|
|
1495
|
+
testing_difficulty: 'HIGH',
|
|
1496
|
+
deployment_complexity: 'HIGH',
|
|
1497
|
+
recovery_complexity: 'MODERATE',
|
|
1498
|
+
team_complexity: 'HIGH',
|
|
1499
|
+
data_management: 'HIGH',
|
|
1500
|
+
vendor_lock_in: 'MODERATE',
|
|
1501
|
+
future_evolution: 'HIGH',
|
|
1502
|
+
},
|
|
1503
|
+
hexagonal: {
|
|
1504
|
+
complexity: 'MODERATE',
|
|
1505
|
+
scalability: 'MODERATE',
|
|
1506
|
+
performance: 'HIGH',
|
|
1507
|
+
reliability: 'MODERATE',
|
|
1508
|
+
availability: 'MODERATE',
|
|
1509
|
+
consistency: 'HIGH',
|
|
1510
|
+
security: 'MODERATE',
|
|
1511
|
+
cost: 'LOW',
|
|
1512
|
+
development_speed: 'MODERATE',
|
|
1513
|
+
operational_burden: 'LOW',
|
|
1514
|
+
observability: 'MODERATE',
|
|
1515
|
+
testing_difficulty: 'LOW',
|
|
1516
|
+
deployment_complexity: 'LOW',
|
|
1517
|
+
recovery_complexity: 'LOW',
|
|
1518
|
+
team_complexity: 'MODERATE',
|
|
1519
|
+
data_management: 'LOW',
|
|
1520
|
+
vendor_lock_in: 'LOW',
|
|
1521
|
+
future_evolution: 'HIGH',
|
|
1522
|
+
},
|
|
1523
|
+
batch: {
|
|
1524
|
+
complexity: 'LOW',
|
|
1525
|
+
scalability: 'MODERATE',
|
|
1526
|
+
performance: 'LOW',
|
|
1527
|
+
reliability: 'MODERATE',
|
|
1528
|
+
availability: 'LOW',
|
|
1529
|
+
consistency: 'HIGH',
|
|
1530
|
+
security: 'MODERATE',
|
|
1531
|
+
cost: 'LOW',
|
|
1532
|
+
development_speed: 'HIGH',
|
|
1533
|
+
operational_burden: 'LOW',
|
|
1534
|
+
observability: 'LOW',
|
|
1535
|
+
testing_difficulty: 'LOW',
|
|
1536
|
+
deployment_complexity: 'LOW',
|
|
1537
|
+
recovery_complexity: 'LOW',
|
|
1538
|
+
team_complexity: 'LOW',
|
|
1539
|
+
data_management: 'MODERATE',
|
|
1540
|
+
vendor_lock_in: 'LOW',
|
|
1541
|
+
future_evolution: 'LOW',
|
|
1542
|
+
},
|
|
1543
|
+
distributed_workers: {
|
|
1544
|
+
complexity: 'MODERATE',
|
|
1545
|
+
scalability: 'HIGH',
|
|
1546
|
+
performance: 'MODERATE',
|
|
1547
|
+
reliability: 'HIGH',
|
|
1548
|
+
availability: 'MODERATE',
|
|
1549
|
+
consistency: 'MODERATE',
|
|
1550
|
+
security: 'MODERATE',
|
|
1551
|
+
cost: 'MODERATE',
|
|
1552
|
+
development_speed: 'MODERATE',
|
|
1553
|
+
operational_burden: 'MODERATE',
|
|
1554
|
+
observability: 'MODERATE',
|
|
1555
|
+
testing_difficulty: 'MODERATE',
|
|
1556
|
+
deployment_complexity: 'MODERATE',
|
|
1557
|
+
recovery_complexity: 'MODERATE',
|
|
1558
|
+
team_complexity: 'MODERATE',
|
|
1559
|
+
data_management: 'MODERATE',
|
|
1560
|
+
vendor_lock_in: 'LOW',
|
|
1561
|
+
future_evolution: 'MODERATE',
|
|
1562
|
+
},
|
|
1563
|
+
event_sourcing: {
|
|
1564
|
+
complexity: 'VERY_HIGH',
|
|
1565
|
+
scalability: 'HIGH',
|
|
1566
|
+
performance: 'MODERATE',
|
|
1567
|
+
reliability: 'HIGH',
|
|
1568
|
+
availability: 'MODERATE',
|
|
1569
|
+
consistency: 'HIGH',
|
|
1570
|
+
security: 'MODERATE',
|
|
1571
|
+
cost: 'HIGH',
|
|
1572
|
+
development_speed: 'LOW',
|
|
1573
|
+
operational_burden: 'HIGH',
|
|
1574
|
+
observability: 'HIGH',
|
|
1575
|
+
testing_difficulty: 'HIGH',
|
|
1576
|
+
deployment_complexity: 'MODERATE',
|
|
1577
|
+
recovery_complexity: 'MODERATE',
|
|
1578
|
+
team_complexity: 'HIGH',
|
|
1579
|
+
data_management: 'VERY_HIGH',
|
|
1580
|
+
vendor_lock_in: 'LOW',
|
|
1581
|
+
future_evolution: 'HIGH',
|
|
1582
|
+
},
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
const patternRatings = ratings[patternKey];
|
|
1586
|
+
if (!patternRatings) return 'UNKNOWN';
|
|
1587
|
+
return patternRatings[criterion] || 'UNKNOWN';
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Build a full trade-off matrix comparing candidates.
|
|
1592
|
+
*
|
|
1593
|
+
* @param {Array} candidates
|
|
1594
|
+
* @param {Object} requirements
|
|
1595
|
+
* @param {Object} constraints
|
|
1596
|
+
* @returns {Object} Trade-off matrix
|
|
1597
|
+
*/
|
|
1598
|
+
function analyzeTradeoffs(candidates, requirements, constraints) {
|
|
1599
|
+
if (!candidates || candidates.length < 2) {
|
|
1600
|
+
return {
|
|
1601
|
+
matrix: [],
|
|
1602
|
+
summary: 'Single candidate — no trade-off comparison needed.',
|
|
1603
|
+
meaningful_differences: [],
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
const matrix = [];
|
|
1608
|
+
const meaningfulDifferences = [];
|
|
1609
|
+
|
|
1610
|
+
for (const criterion of TRADEOFF_CRITERIA) {
|
|
1611
|
+
const row = {
|
|
1612
|
+
criterion,
|
|
1613
|
+
importance: determineCriterionImportance(criterion, requirements, constraints),
|
|
1614
|
+
candidate_values: {},
|
|
1615
|
+
evidence: [],
|
|
1616
|
+
uncertainty: 'MODERATE',
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
const values = {};
|
|
1620
|
+
for (const cand of candidates) {
|
|
1621
|
+
const rating = rateCriterion(cand.pattern, criterion);
|
|
1622
|
+
row.candidate_values[cand.name] = rating;
|
|
1623
|
+
values[cand.name] = rating;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
// Detect meaningful differences
|
|
1627
|
+
const uniqueValues = new Set(Object.values(values));
|
|
1628
|
+
if (uniqueValues.size > 1 && row.importance !== 'LOW') {
|
|
1629
|
+
meaningfulDifferences.push({
|
|
1630
|
+
criterion,
|
|
1631
|
+
importance: row.importance,
|
|
1632
|
+
values,
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
matrix.push(row);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
return {
|
|
1640
|
+
matrix,
|
|
1641
|
+
summary: `Compared ${candidates.length} candidates across ${TRADEOFF_CRITERIA.length} criteria. ${meaningfulDifferences.length} meaningful differences found.`,
|
|
1642
|
+
meaningful_differences: meaningfulDifferences,
|
|
1643
|
+
candidates_compared: candidates.map(c => c.name),
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/**
|
|
1648
|
+
* Determine how important a criterion is given the requirements.
|
|
1649
|
+
*/
|
|
1650
|
+
function determineCriterionImportance(criterion, requirements, constraints) {
|
|
1651
|
+
const nfrs = (requirements && requirements.non_functional) || [];
|
|
1652
|
+
const frs = (requirements && requirements.functional) || [];
|
|
1653
|
+
|
|
1654
|
+
const highImportance = {
|
|
1655
|
+
scalability: nfrs.some(n => n.category === 'scalability'),
|
|
1656
|
+
performance: nfrs.some(n => n.category === 'performance'),
|
|
1657
|
+
reliability: nfrs.some(n => n.category === 'reliability'),
|
|
1658
|
+
security:
|
|
1659
|
+
nfrs.some(n => n.category === 'security') ||
|
|
1660
|
+
frs.some(f => f.domain === 'financial' || f.domain === 'security'),
|
|
1661
|
+
consistency: frs.some(f => f.domain === 'financial'),
|
|
1662
|
+
cost: ((constraints && constraints.constraints) || []).some(c => c.category === 'cost'),
|
|
1663
|
+
operational_burden: ((constraints && constraints.constraints) || []).some(
|
|
1664
|
+
c => c.category === 'team' || c.category === 'operations',
|
|
1665
|
+
),
|
|
1666
|
+
availability: nfrs.some(n => n.category === 'reliability'),
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
if (highImportance[criterion]) return 'HIGH';
|
|
1670
|
+
if (['complexity', 'development_speed', 'testing_difficulty'].includes(criterion))
|
|
1671
|
+
return 'MEDIUM';
|
|
1672
|
+
return 'LOW';
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// ============================================================================
|
|
1676
|
+
// 7. DECISION SENSITIVITY & BREAKPOINTS (SECTIONS 12–13)
|
|
1677
|
+
// ============================================================================
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Identify which assumptions could change the architecture decision.
|
|
1681
|
+
*
|
|
1682
|
+
* @param {Array} candidates
|
|
1683
|
+
* @param {Object} tradeoffs
|
|
1684
|
+
* @param {Object} requirements
|
|
1685
|
+
* @returns {Array<Object>} Decision-sensitive assumptions
|
|
1686
|
+
*/
|
|
1687
|
+
function analyzeDecisionSensitivity(candidates, tradeoffs, requirements) {
|
|
1688
|
+
const sensitivities = [];
|
|
1689
|
+
const unknowns = (requirements && requirements.unknowns) || [];
|
|
1690
|
+
|
|
1691
|
+
// Traffic assumption sensitivity
|
|
1692
|
+
if (
|
|
1693
|
+
unknowns.some(
|
|
1694
|
+
u =>
|
|
1695
|
+
u.requirement === 'request rate / throughput' || u.requirement === 'peak concurrent users',
|
|
1696
|
+
)
|
|
1697
|
+
) {
|
|
1698
|
+
sensitivities.push({
|
|
1699
|
+
assumption: 'Current traffic estimate',
|
|
1700
|
+
current_value: 'UNKNOWN',
|
|
1701
|
+
threshold: 'If traffic exceeds 100K requests/day, consider service decomposition.',
|
|
1702
|
+
impact: 'Architecture decision may shift from monolith to service-based.',
|
|
1703
|
+
type: 'DECISION_SENSITIVE',
|
|
1704
|
+
evidence_quality: 'UNKNOWN',
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// Team growth sensitivity
|
|
1709
|
+
if (unknowns.some(u => u.requirement === 'team size and expertise')) {
|
|
1710
|
+
sensitivities.push({
|
|
1711
|
+
assumption: 'Team size remains stable',
|
|
1712
|
+
current_value: 'UNKNOWN',
|
|
1713
|
+
threshold:
|
|
1714
|
+
'If team grows beyond 8-10 engineers, modular monolith may need service decomposition.',
|
|
1715
|
+
impact: 'Architecture decision may shift to support independent team ownership.',
|
|
1716
|
+
type: 'DECISION_SENSITIVE',
|
|
1717
|
+
evidence_quality: 'UNKNOWN',
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// Data volume sensitivity
|
|
1722
|
+
if (unknowns.some(u => u.requirement === 'data retention period')) {
|
|
1723
|
+
sensitivities.push({
|
|
1724
|
+
assumption: 'Data volume remains manageable',
|
|
1725
|
+
current_value: 'UNKNOWN',
|
|
1726
|
+
threshold: 'If data exceeds single-node DB capacity, partitioning/sharding strategy needed.',
|
|
1727
|
+
impact: 'Database architecture may need fundamental change.',
|
|
1728
|
+
type: 'DECISION_SENSITIVE',
|
|
1729
|
+
evidence_quality: 'UNKNOWN',
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// Cost sensitivity
|
|
1734
|
+
if (unknowns.some(u => u.requirement === 'budget')) {
|
|
1735
|
+
sensitivities.push({
|
|
1736
|
+
assumption: 'Budget is sufficient for chosen architecture',
|
|
1737
|
+
current_value: 'UNKNOWN',
|
|
1738
|
+
threshold:
|
|
1739
|
+
'If budget is severely constrained, prefer monolith/serverless over microservices.',
|
|
1740
|
+
impact: 'Cost model may invalidate complex architecture choices.',
|
|
1741
|
+
type: 'DECISION_SENSITIVE',
|
|
1742
|
+
evidence_quality: 'UNKNOWN',
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
return sensitivities;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Identify architectural breakpoints — thresholds where architecture should change.
|
|
1751
|
+
*
|
|
1752
|
+
* @param {Object} candidate
|
|
1753
|
+
* @param {Object} requirements
|
|
1754
|
+
* @returns {Array<Object>} Breakpoints
|
|
1755
|
+
*/
|
|
1756
|
+
function identifyBreakpoints(candidate, requirements) {
|
|
1757
|
+
const breakpoints = [];
|
|
1758
|
+
const patternKey = candidate.pattern || '';
|
|
1759
|
+
|
|
1760
|
+
if (['monolith', 'modular_monolith'].includes(patternKey)) {
|
|
1761
|
+
breakpoints.push({
|
|
1762
|
+
dimension: 'traffic',
|
|
1763
|
+
current_range: '0–100K requests/day',
|
|
1764
|
+
breakpoint: '100K–1M requests/day',
|
|
1765
|
+
action: 'Scale application horizontally + database read replicas',
|
|
1766
|
+
evidence_quality: 'ESTIMATED',
|
|
1767
|
+
next_architecture: 'Consider service decomposition at >1M requests/day',
|
|
1768
|
+
});
|
|
1769
|
+
breakpoints.push({
|
|
1770
|
+
dimension: 'team_size',
|
|
1771
|
+
current_range: '1–8 engineers',
|
|
1772
|
+
breakpoint: '8–15 engineers',
|
|
1773
|
+
action: 'Enforce module ownership boundaries, consider domain service extraction',
|
|
1774
|
+
evidence_quality: 'ESTIMATED',
|
|
1775
|
+
next_architecture: 'Module → Service transition for >15 engineers',
|
|
1776
|
+
});
|
|
1777
|
+
breakpoints.push({
|
|
1778
|
+
dimension: 'data_volume',
|
|
1779
|
+
current_range: 'Single-node database',
|
|
1780
|
+
breakpoint: 'Database exceeds single-node capacity',
|
|
1781
|
+
action: 'Implement read replicas, then partitioning/sharding',
|
|
1782
|
+
evidence_quality: 'ESTIMATED',
|
|
1783
|
+
next_architecture: 'Per-domain database ownership',
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
if (['microservices'].includes(patternKey)) {
|
|
1788
|
+
breakpoints.push({
|
|
1789
|
+
dimension: 'team_size',
|
|
1790
|
+
current_range: '>8 engineers',
|
|
1791
|
+
breakpoint: '<4 engineers',
|
|
1792
|
+
action:
|
|
1793
|
+
'Consolidate services into modular monolith — team cannot sustain operational overhead',
|
|
1794
|
+
evidence_quality: 'ESTIMATED',
|
|
1795
|
+
next_architecture: 'Modular Monolith',
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
if (['serverless'].includes(patternKey)) {
|
|
1800
|
+
breakpoints.push({
|
|
1801
|
+
dimension: 'execution_duration',
|
|
1802
|
+
current_range: 'Sub-15-minute tasks',
|
|
1803
|
+
breakpoint: 'Tasks exceeding runtime limits',
|
|
1804
|
+
action: 'Move long-running workflows to container-based workers',
|
|
1805
|
+
evidence_quality: 'DOCUMENTED',
|
|
1806
|
+
next_architecture: 'Distributed Workers or container-based services',
|
|
1807
|
+
});
|
|
1808
|
+
breakpoints.push({
|
|
1809
|
+
dimension: 'cold_start_tolerance',
|
|
1810
|
+
current_range: 'Acceptable cold start latency',
|
|
1811
|
+
breakpoint: 'p99 latency exceeds SLA due to cold starts',
|
|
1812
|
+
action: 'Provisioned concurrency or move to always-on containers',
|
|
1813
|
+
evidence_quality: 'MEASURED',
|
|
1814
|
+
next_architecture: 'Container-based deployment',
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
return breakpoints;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// ============================================================================
|
|
1822
|
+
// 8. DOMAIN-SPECIFIC ANALYZERS (SECTIONS 14–27)
|
|
1823
|
+
// ============================================================================
|
|
1824
|
+
|
|
1825
|
+
/**
|
|
1826
|
+
* Analyze build vs buy decisions for common components.
|
|
1827
|
+
*/
|
|
1828
|
+
function analyzeBuildVsBuy(taskQuery, requirements) {
|
|
1829
|
+
const q = (taskQuery || '').toLowerCase();
|
|
1830
|
+
const decisions = [];
|
|
1831
|
+
|
|
1832
|
+
const components = [
|
|
1833
|
+
{
|
|
1834
|
+
match: /(?:auth|login|sso|oauth)/i,
|
|
1835
|
+
component: 'Authentication',
|
|
1836
|
+
buy: 'Auth0, Clerk, Supabase Auth, Firebase Auth',
|
|
1837
|
+
build_reason: 'Custom auth flows, data sovereignty, no vendor dependency',
|
|
1838
|
+
buy_reason: 'Faster implementation, proven security, compliance certifications',
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
match: /(?:payment|billing|subscription|charge)/i,
|
|
1842
|
+
component: 'Payment Processing',
|
|
1843
|
+
buy: 'Stripe, Paddle, LemonSqueezy',
|
|
1844
|
+
build_reason: 'Rarely justified — regulatory and PCI compliance burden',
|
|
1845
|
+
buy_reason: 'PCI compliance handled, fraud detection, global payment methods',
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
match: /(?:search|full.text|elastic)/i,
|
|
1849
|
+
component: 'Search',
|
|
1850
|
+
buy: 'Algolia, Meilisearch, Typesense, ElasticSearch (managed)',
|
|
1851
|
+
build_reason: 'Custom ranking algorithms, data privacy',
|
|
1852
|
+
buy_reason: 'Performance, relevance tuning, faceted search out-of-box',
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
match: /(?:email|smtp|transactional.mail)/i,
|
|
1856
|
+
component: 'Email',
|
|
1857
|
+
buy: 'Resend, SendGrid, Postmark, AWS SES',
|
|
1858
|
+
build_reason: 'Almost never justified',
|
|
1859
|
+
buy_reason: 'Deliverability, reputation management, compliance',
|
|
1860
|
+
},
|
|
1861
|
+
{
|
|
1862
|
+
match: /(?:observab|monitor|trace|log|metric)/i,
|
|
1863
|
+
component: 'Observability',
|
|
1864
|
+
buy: 'Datadog, Grafana Cloud, New Relic',
|
|
1865
|
+
build_reason: 'Cost at scale, data privacy',
|
|
1866
|
+
buy_reason: 'Immediate visibility, alerting, dashboards',
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
match: /(?:vector|embedding|rag|semantic.search)/i,
|
|
1870
|
+
component: 'Vector Database',
|
|
1871
|
+
buy: 'Pinecone, Weaviate Cloud, Qdrant Cloud',
|
|
1872
|
+
build_reason: 'pgvector for simple cases, data sovereignty',
|
|
1873
|
+
buy_reason: 'Optimized ANN search, managed scaling',
|
|
1874
|
+
},
|
|
1875
|
+
{
|
|
1876
|
+
match: /(?:feature.flag|toggle|experiment)/i,
|
|
1877
|
+
component: 'Feature Flags',
|
|
1878
|
+
buy: 'LaunchDarkly, Flagsmith, Unleash',
|
|
1879
|
+
build_reason: 'Simple boolean flags can be DIY',
|
|
1880
|
+
buy_reason: 'Percentage rollouts, A/B testing, audit trail',
|
|
1881
|
+
},
|
|
1882
|
+
];
|
|
1883
|
+
|
|
1884
|
+
for (const c of components) {
|
|
1885
|
+
if (c.match.test(q)) {
|
|
1886
|
+
decisions.push({
|
|
1887
|
+
component: c.component,
|
|
1888
|
+
recommendation:
|
|
1889
|
+
c.component === 'Payment Processing' || c.component === 'Email' ? 'BUY' : 'EVALUATE',
|
|
1890
|
+
buy_options: c.buy,
|
|
1891
|
+
build_rationale: c.build_reason,
|
|
1892
|
+
buy_rationale: c.buy_reason,
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
return decisions;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
/**
|
|
1901
|
+
* Analyze data architecture requirements.
|
|
1902
|
+
*/
|
|
1903
|
+
function analyzeDataArchitecture(taskQuery, requirements) {
|
|
1904
|
+
const q = (taskQuery || '').toLowerCase();
|
|
1905
|
+
const analysis = {
|
|
1906
|
+
consistency_model: 'UNKNOWN',
|
|
1907
|
+
transaction_boundaries: [],
|
|
1908
|
+
read_write_pattern: 'UNKNOWN',
|
|
1909
|
+
recommendations: [],
|
|
1910
|
+
considerations: [],
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1913
|
+
// Consistency model
|
|
1914
|
+
if (/(?:payment|financial|ledger|order|inventory|booking)/i.test(q)) {
|
|
1915
|
+
analysis.consistency_model = 'STRONG';
|
|
1916
|
+
analysis.considerations.push(
|
|
1917
|
+
'Financial data requires strong consistency — use ACID transactions.',
|
|
1918
|
+
);
|
|
1919
|
+
analysis.transaction_boundaries.push(
|
|
1920
|
+
'payment execution',
|
|
1921
|
+
'inventory reservation',
|
|
1922
|
+
'order creation',
|
|
1923
|
+
);
|
|
1924
|
+
} else if (/(?:feed|timeline|analytics|recommendation|cache)/i.test(q)) {
|
|
1925
|
+
analysis.consistency_model = 'EVENTUAL';
|
|
1926
|
+
analysis.considerations.push(
|
|
1927
|
+
'Feed/analytics data can tolerate eventual consistency for better performance.',
|
|
1928
|
+
);
|
|
1929
|
+
} else if (/(?:collaboration|editor|realtime)/i.test(q)) {
|
|
1930
|
+
analysis.consistency_model = 'CAUSAL';
|
|
1931
|
+
analysis.considerations.push(
|
|
1932
|
+
'Collaborative editing requires causal consistency with conflict resolution (CRDT/OT).',
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
// Read/write pattern
|
|
1937
|
+
if (/(?:feed|timeline|dashboard|report|analytics)/i.test(q)) {
|
|
1938
|
+
analysis.read_write_pattern = 'READ_HEAVY';
|
|
1939
|
+
analysis.recommendations.push('Consider read replicas, caching, and materialized views.');
|
|
1940
|
+
} else if (/(?:log|audit|event|ingest|import)/i.test(q)) {
|
|
1941
|
+
analysis.read_write_pattern = 'WRITE_HEAVY';
|
|
1942
|
+
analysis.recommendations.push(
|
|
1943
|
+
'Consider write-optimized storage, append-only logs, and batch inserts.',
|
|
1944
|
+
);
|
|
1945
|
+
} else {
|
|
1946
|
+
analysis.read_write_pattern = 'BALANCED';
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// Database recommendations
|
|
1950
|
+
if (
|
|
1951
|
+
/(?:relational|sql|postgres|mysql|transaction|acid|join|foreign.key)/i.test(q) ||
|
|
1952
|
+
analysis.consistency_model === 'STRONG'
|
|
1953
|
+
) {
|
|
1954
|
+
analysis.recommendations.push(
|
|
1955
|
+
'PostgreSQL: Strong ACID, extensible (pgvector, PostGIS), mature ecosystem.',
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
if (/(?:document|json|flexible.schema|mongo|nosql)/i.test(q)) {
|
|
1959
|
+
analysis.recommendations.push(
|
|
1960
|
+
'Document store (MongoDB, DynamoDB): Flexible schema, horizontal scaling. Evaluate if relational model is truly insufficient.',
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
if (/(?:time.series|iot|sensor|metric|tsdb)/i.test(q)) {
|
|
1964
|
+
analysis.recommendations.push(
|
|
1965
|
+
'Time-series DB (TimescaleDB, InfluxDB): Optimized for temporal queries and retention.',
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
if (/(?:graph|relation|connection|social|network|knowledge)/i.test(q)) {
|
|
1969
|
+
analysis.recommendations.push(
|
|
1970
|
+
'Graph DB (Neo4j, Neptune): Consider if relationships are the primary query target.',
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
return analysis;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Analyze communication patterns.
|
|
1979
|
+
*/
|
|
1980
|
+
function analyzeCommunicationPatterns(taskQuery) {
|
|
1981
|
+
const q = (taskQuery || '').toLowerCase();
|
|
1982
|
+
const patterns = [];
|
|
1983
|
+
|
|
1984
|
+
if (/(?:api|endpoint|crud|rest)/i.test(q)) {
|
|
1985
|
+
patterns.push({
|
|
1986
|
+
pattern: 'REST',
|
|
1987
|
+
rationale: 'Standard HTTP API for CRUD operations',
|
|
1988
|
+
fit: 'HIGH',
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
if (/(?:realtime|websocket|presence|chat|collaboration)/i.test(q)) {
|
|
1992
|
+
patterns.push({
|
|
1993
|
+
pattern: 'WebSocket',
|
|
1994
|
+
rationale: 'Bidirectional real-time communication',
|
|
1995
|
+
fit: 'HIGH',
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
if (/(?:notification|webhook|event.trigger)/i.test(q)) {
|
|
1999
|
+
patterns.push({ pattern: 'Webhook', rationale: 'Push-based event notification', fit: 'HIGH' });
|
|
2000
|
+
}
|
|
2001
|
+
if (/(?:stream|sse|server.sent)/i.test(q)) {
|
|
2002
|
+
patterns.push({ pattern: 'SSE', rationale: 'Server-to-client streaming', fit: 'MODERATE' });
|
|
2003
|
+
}
|
|
2004
|
+
if (/(?:grpc|protobuf|internal.service|high.throughput.rpc)/i.test(q)) {
|
|
2005
|
+
patterns.push({
|
|
2006
|
+
pattern: 'gRPC',
|
|
2007
|
+
rationale: 'High-performance service-to-service communication',
|
|
2008
|
+
fit: 'MODERATE',
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
if (/(?:graphql|flexible.query|client.driven)/i.test(q)) {
|
|
2012
|
+
patterns.push({
|
|
2013
|
+
pattern: 'GraphQL',
|
|
2014
|
+
rationale: 'Client-driven flexible queries',
|
|
2015
|
+
fit: 'MODERATE',
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
if (/(?:queue|async|background|worker|job)/i.test(q)) {
|
|
2019
|
+
patterns.push({
|
|
2020
|
+
pattern: 'Message Queue',
|
|
2021
|
+
rationale: 'Asynchronous decoupled processing',
|
|
2022
|
+
fit: 'HIGH',
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
if (patterns.length === 0) {
|
|
2027
|
+
patterns.push({
|
|
2028
|
+
pattern: 'REST',
|
|
2029
|
+
rationale: 'Default API pattern for HTTP services',
|
|
2030
|
+
fit: 'MODERATE',
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
return patterns;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Analyze security architecture.
|
|
2039
|
+
*/
|
|
2040
|
+
function analyzeSecurityArchitecture(taskQuery, requirements) {
|
|
2041
|
+
const q = (taskQuery || '').toLowerCase();
|
|
2042
|
+
const analysis = {
|
|
2043
|
+
trust_boundaries: [],
|
|
2044
|
+
authentication_model: 'UNKNOWN',
|
|
2045
|
+
authorization_model: 'UNKNOWN',
|
|
2046
|
+
considerations: [],
|
|
2047
|
+
trust_boundary_graph: [],
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
// Trust boundary graph
|
|
2051
|
+
analysis.trust_boundary_graph = [
|
|
2052
|
+
{ from: 'Internet', to: 'CDN/WAF', trust_transition: true },
|
|
2053
|
+
{ from: 'CDN/WAF', to: 'Load Balancer', trust_transition: false },
|
|
2054
|
+
{ from: 'Load Balancer', to: 'Application', trust_transition: true },
|
|
2055
|
+
{ from: 'Application', to: 'Database', trust_transition: true },
|
|
2056
|
+
];
|
|
2057
|
+
|
|
2058
|
+
if (/(?:auth|login|jwt|session|oauth|sso)/i.test(q)) {
|
|
2059
|
+
analysis.authentication_model = /(?:jwt|token)/i.test(q) ? 'JWT/Token-based' : 'Session-based';
|
|
2060
|
+
analysis.considerations.push('Enforce cryptographic signature verification on all tokens.');
|
|
2061
|
+
analysis.considerations.push('Implement token expiration and refresh rotation.');
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
if (/(?:rbac|role|permission|acl|authorization)/i.test(q)) {
|
|
2065
|
+
analysis.authorization_model = 'RBAC';
|
|
2066
|
+
analysis.considerations.push('Define authorization matrix: User × Role × Resource × Action.');
|
|
2067
|
+
analysis.considerations.push('Enforce authorization before business logic, never after.');
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
if (/(?:multi.tenant|tenant|workspace)/i.test(q)) {
|
|
2071
|
+
analysis.considerations.push('CRITICAL: Tenant isolation at every data access boundary.');
|
|
2072
|
+
analysis.considerations.push(
|
|
2073
|
+
'Verify cross-tenant access is impossible at database query level.',
|
|
2074
|
+
);
|
|
2075
|
+
analysis.trust_boundary_graph.push({
|
|
2076
|
+
from: 'Application',
|
|
2077
|
+
to: 'Tenant Boundary',
|
|
2078
|
+
trust_transition: true,
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
if (/(?:agent|llm|prompt|ai|tool)/i.test(q)) {
|
|
2083
|
+
analysis.considerations.push(
|
|
2084
|
+
'Agent sandboxing: restrict subprocess execution and tool permissions.',
|
|
2085
|
+
);
|
|
2086
|
+
analysis.considerations.push(
|
|
2087
|
+
'Prompt injection defense: isolate user input from system instructions.',
|
|
2088
|
+
);
|
|
2089
|
+
analysis.trust_boundary_graph.push({
|
|
2090
|
+
from: 'Application',
|
|
2091
|
+
to: 'AI Agent Sandbox',
|
|
2092
|
+
trust_transition: true,
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
return analysis;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Analyze cost architecture for a candidate.
|
|
2101
|
+
*/
|
|
2102
|
+
function analyzeCostArchitecture(candidate, constraints) {
|
|
2103
|
+
const patternKey = candidate.pattern || '';
|
|
2104
|
+
const costDrivers = {
|
|
2105
|
+
compute: 'UNKNOWN',
|
|
2106
|
+
database: 'UNKNOWN',
|
|
2107
|
+
storage: 'UNKNOWN',
|
|
2108
|
+
network: 'UNKNOWN',
|
|
2109
|
+
managed_services: 'UNKNOWN',
|
|
2110
|
+
observability: 'UNKNOWN',
|
|
2111
|
+
operations: 'UNKNOWN',
|
|
2112
|
+
};
|
|
2113
|
+
|
|
2114
|
+
const costProfiles = {
|
|
2115
|
+
monolith: {
|
|
2116
|
+
compute: 'LOW',
|
|
2117
|
+
database: 'LOW',
|
|
2118
|
+
storage: 'LOW',
|
|
2119
|
+
network: 'LOW',
|
|
2120
|
+
managed_services: 'LOW',
|
|
2121
|
+
observability: 'LOW',
|
|
2122
|
+
operations: 'LOW',
|
|
2123
|
+
},
|
|
2124
|
+
modular_monolith: {
|
|
2125
|
+
compute: 'LOW',
|
|
2126
|
+
database: 'LOW',
|
|
2127
|
+
storage: 'LOW',
|
|
2128
|
+
network: 'LOW',
|
|
2129
|
+
managed_services: 'LOW',
|
|
2130
|
+
observability: 'LOW',
|
|
2131
|
+
operations: 'LOW',
|
|
2132
|
+
},
|
|
2133
|
+
microservices: {
|
|
2134
|
+
compute: 'HIGH',
|
|
2135
|
+
database: 'HIGH',
|
|
2136
|
+
storage: 'MODERATE',
|
|
2137
|
+
network: 'HIGH',
|
|
2138
|
+
managed_services: 'HIGH',
|
|
2139
|
+
observability: 'HIGH',
|
|
2140
|
+
operations: 'HIGH',
|
|
2141
|
+
},
|
|
2142
|
+
serverless: {
|
|
2143
|
+
compute: 'VARIABLE',
|
|
2144
|
+
database: 'MODERATE',
|
|
2145
|
+
storage: 'LOW',
|
|
2146
|
+
network: 'LOW',
|
|
2147
|
+
managed_services: 'MODERATE',
|
|
2148
|
+
observability: 'MODERATE',
|
|
2149
|
+
operations: 'LOW',
|
|
2150
|
+
},
|
|
2151
|
+
event_driven: {
|
|
2152
|
+
compute: 'MODERATE',
|
|
2153
|
+
database: 'MODERATE',
|
|
2154
|
+
storage: 'MODERATE',
|
|
2155
|
+
network: 'MODERATE',
|
|
2156
|
+
managed_services: 'MODERATE',
|
|
2157
|
+
observability: 'MODERATE',
|
|
2158
|
+
operations: 'MODERATE',
|
|
2159
|
+
},
|
|
2160
|
+
streaming: {
|
|
2161
|
+
compute: 'HIGH',
|
|
2162
|
+
database: 'HIGH',
|
|
2163
|
+
storage: 'HIGH',
|
|
2164
|
+
network: 'HIGH',
|
|
2165
|
+
managed_services: 'HIGH',
|
|
2166
|
+
observability: 'HIGH',
|
|
2167
|
+
operations: 'HIGH',
|
|
2168
|
+
},
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2171
|
+
const profile = costProfiles[patternKey] || {};
|
|
2172
|
+
Object.assign(costDrivers, profile);
|
|
2173
|
+
|
|
2174
|
+
return {
|
|
2175
|
+
pattern: candidate.name || patternKey,
|
|
2176
|
+
cost_drivers: costDrivers,
|
|
2177
|
+
cost_category: ['monolith', 'modular_monolith'].includes(patternKey)
|
|
2178
|
+
? 'LOW'
|
|
2179
|
+
: ['microservices', 'streaming'].includes(patternKey)
|
|
2180
|
+
? 'HIGH'
|
|
2181
|
+
: 'MODERATE',
|
|
2182
|
+
scaling_cost_model: ['serverless'].includes(patternKey) ? 'PAY_PER_USE' : 'FIXED_PLUS_VARIABLE',
|
|
2183
|
+
notes: [],
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
/**
|
|
2188
|
+
* Analyze operational complexity for a candidate.
|
|
2189
|
+
*/
|
|
2190
|
+
function analyzeOperationalComplexity(candidate) {
|
|
2191
|
+
const patternKey = candidate.pattern || '';
|
|
2192
|
+
const profiles = {
|
|
2193
|
+
monolith: {
|
|
2194
|
+
deployment_units: 1,
|
|
2195
|
+
services: 1,
|
|
2196
|
+
databases: 1,
|
|
2197
|
+
queues: 0,
|
|
2198
|
+
secrets: 'FEW',
|
|
2199
|
+
monitoring: 'BASIC',
|
|
2200
|
+
on_call: 'LOW',
|
|
2201
|
+
},
|
|
2202
|
+
modular_monolith: {
|
|
2203
|
+
deployment_units: 1,
|
|
2204
|
+
services: 1,
|
|
2205
|
+
databases: 1,
|
|
2206
|
+
queues: 0,
|
|
2207
|
+
secrets: 'FEW',
|
|
2208
|
+
monitoring: 'BASIC',
|
|
2209
|
+
on_call: 'LOW',
|
|
2210
|
+
},
|
|
2211
|
+
microservices: {
|
|
2212
|
+
deployment_units: 'MANY',
|
|
2213
|
+
services: 'MANY',
|
|
2214
|
+
databases: 'MANY',
|
|
2215
|
+
queues: 'SEVERAL',
|
|
2216
|
+
secrets: 'MANY',
|
|
2217
|
+
monitoring: 'COMPLEX',
|
|
2218
|
+
on_call: 'HIGH',
|
|
2219
|
+
},
|
|
2220
|
+
serverless: {
|
|
2221
|
+
deployment_units: 'MANY_FUNCTIONS',
|
|
2222
|
+
services: 'MANY_FUNCTIONS',
|
|
2223
|
+
databases: 1,
|
|
2224
|
+
queues: 'FEW',
|
|
2225
|
+
secrets: 'MODERATE',
|
|
2226
|
+
monitoring: 'MODERATE',
|
|
2227
|
+
on_call: 'LOW',
|
|
2228
|
+
},
|
|
2229
|
+
event_driven: {
|
|
2230
|
+
deployment_units: 'SEVERAL',
|
|
2231
|
+
services: 'SEVERAL',
|
|
2232
|
+
databases: 'FEW',
|
|
2233
|
+
queues: 'SEVERAL',
|
|
2234
|
+
secrets: 'MODERATE',
|
|
2235
|
+
monitoring: 'MODERATE',
|
|
2236
|
+
on_call: 'MODERATE',
|
|
2237
|
+
},
|
|
2238
|
+
streaming: {
|
|
2239
|
+
deployment_units: 'MANY',
|
|
2240
|
+
services: 'MANY',
|
|
2241
|
+
databases: 'SEVERAL',
|
|
2242
|
+
queues: 'MANY',
|
|
2243
|
+
secrets: 'MANY',
|
|
2244
|
+
monitoring: 'COMPLEX',
|
|
2245
|
+
on_call: 'HIGH',
|
|
2246
|
+
},
|
|
2247
|
+
};
|
|
2248
|
+
|
|
2249
|
+
return (
|
|
2250
|
+
profiles[patternKey] || {
|
|
2251
|
+
deployment_units: 'UNKNOWN',
|
|
2252
|
+
services: 'UNKNOWN',
|
|
2253
|
+
databases: 'UNKNOWN',
|
|
2254
|
+
queues: 'UNKNOWN',
|
|
2255
|
+
secrets: 'UNKNOWN',
|
|
2256
|
+
monitoring: 'UNKNOWN',
|
|
2257
|
+
on_call: 'UNKNOWN',
|
|
2258
|
+
}
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// ============================================================================
|
|
2263
|
+
// 9. MIGRATION & EVOLUTION INTELLIGENCE (SECTIONS 28–29)
|
|
2264
|
+
// ============================================================================
|
|
2265
|
+
|
|
2266
|
+
/**
|
|
2267
|
+
* Analyze migration path between architectures.
|
|
2268
|
+
*/
|
|
2269
|
+
function analyzeMigration(currentArch, targetArch) {
|
|
2270
|
+
const migration = {
|
|
2271
|
+
current: currentArch,
|
|
2272
|
+
target: targetArch,
|
|
2273
|
+
strategy: 'INCREMENTAL',
|
|
2274
|
+
risk_level: 'MODERATE',
|
|
2275
|
+
steps: [],
|
|
2276
|
+
rollback_plan: 'Maintain dual deployment during migration; route traffic via feature flags.',
|
|
2277
|
+
considerations: [],
|
|
2278
|
+
};
|
|
2279
|
+
|
|
2280
|
+
if (currentArch === 'monolith' && targetArch === 'modular_monolith') {
|
|
2281
|
+
migration.risk_level = 'LOW';
|
|
2282
|
+
migration.steps = [
|
|
2283
|
+
'Identify domain boundaries in existing code',
|
|
2284
|
+
'Extract shared code into internal library modules',
|
|
2285
|
+
'Define module interfaces (internal API contracts)',
|
|
2286
|
+
'Enforce module boundaries via import restrictions',
|
|
2287
|
+
'Add module-level integration tests',
|
|
2288
|
+
];
|
|
2289
|
+
} else if (currentArch === 'modular_monolith' && targetArch === 'microservices') {
|
|
2290
|
+
migration.risk_level = 'HIGH';
|
|
2291
|
+
migration.strategy = 'STRANGLER_FIG';
|
|
2292
|
+
migration.steps = [
|
|
2293
|
+
'Identify highest-value module for extraction (highest deployment friction)',
|
|
2294
|
+
'Set up service infrastructure (discovery, auth, observability)',
|
|
2295
|
+
'Extract module to independent service behind API gateway',
|
|
2296
|
+
'Implement dual-write/read with consistency verification',
|
|
2297
|
+
'Migrate traffic incrementally via feature flags',
|
|
2298
|
+
'Decommission monolith module after verification period',
|
|
2299
|
+
];
|
|
2300
|
+
migration.considerations.push(
|
|
2301
|
+
'CRITICAL: Big-bang migration has high failure risk. Use Strangler Fig pattern.',
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
return migration;
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
/**
|
|
2309
|
+
* Analyze evolution paths for an architecture.
|
|
2310
|
+
*/
|
|
2311
|
+
function analyzeEvolution(candidate) {
|
|
2312
|
+
const patternKey = candidate.pattern || '';
|
|
2313
|
+
const evolution = {
|
|
2314
|
+
pattern: candidate.name || patternKey,
|
|
2315
|
+
evolution_paths: [],
|
|
2316
|
+
growth_directions: [],
|
|
2317
|
+
};
|
|
2318
|
+
|
|
2319
|
+
if (['monolith', 'modular_monolith'].includes(patternKey)) {
|
|
2320
|
+
evolution.evolution_paths = [
|
|
2321
|
+
{
|
|
2322
|
+
trigger: 'Traffic growth beyond single-node',
|
|
2323
|
+
target: 'Horizontal scaling + read replicas',
|
|
2324
|
+
},
|
|
2325
|
+
{ trigger: 'Team growth beyond 8–10', target: 'Service decomposition via Strangler Fig' },
|
|
2326
|
+
{
|
|
2327
|
+
trigger: 'New compliance requirements',
|
|
2328
|
+
target: 'Add audit logging module, encryption at rest',
|
|
2329
|
+
},
|
|
2330
|
+
{ trigger: 'Geographic expansion', target: 'Multi-region deployment with read replicas' },
|
|
2331
|
+
];
|
|
2332
|
+
evolution.growth_directions = ['vertical_first', 'then_horizontal', 'then_decomposition'];
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
if (['microservices'].includes(patternKey)) {
|
|
2336
|
+
evolution.evolution_paths = [
|
|
2337
|
+
{ trigger: 'Team shrinkage', target: 'Consolidate services into fewer, larger services' },
|
|
2338
|
+
{
|
|
2339
|
+
trigger: 'Service mesh complexity',
|
|
2340
|
+
target: 'Evaluate managed service mesh or simplification',
|
|
2341
|
+
},
|
|
2342
|
+
{
|
|
2343
|
+
trigger: 'Data consistency challenges',
|
|
2344
|
+
target: 'Introduce saga orchestrator or event sourcing',
|
|
2345
|
+
},
|
|
2346
|
+
];
|
|
2347
|
+
evolution.growth_directions = ['service_per_team', 'independent_scaling'];
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
if (['serverless'].includes(patternKey)) {
|
|
2351
|
+
evolution.evolution_paths = [
|
|
2352
|
+
{
|
|
2353
|
+
trigger: 'Cold start exceeds SLA',
|
|
2354
|
+
target: 'Provisioned concurrency or container migration',
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
trigger: 'Vendor lock-in concern',
|
|
2358
|
+
target: 'Abstract via ports & adapters for portability',
|
|
2359
|
+
},
|
|
2360
|
+
{
|
|
2361
|
+
trigger: 'Long-running workflows',
|
|
2362
|
+
target: 'Step Functions / Durable Functions or container workers',
|
|
2363
|
+
},
|
|
2364
|
+
];
|
|
2365
|
+
evolution.growth_directions = ['function_per_feature', 'managed_services'];
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
return evolution;
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
// ============================================================================
|
|
2372
|
+
// 10. ADR GENERATION (SECTION 30)
|
|
2373
|
+
// ============================================================================
|
|
2374
|
+
|
|
2375
|
+
/**
|
|
2376
|
+
* Generate an Architecture Decision Record.
|
|
2377
|
+
*
|
|
2378
|
+
* @param {Object} params
|
|
2379
|
+
* @returns {Object} ADR
|
|
2380
|
+
*/
|
|
2381
|
+
function generateADR(params) {
|
|
2382
|
+
const {
|
|
2383
|
+
task,
|
|
2384
|
+
requirements,
|
|
2385
|
+
constraints,
|
|
2386
|
+
candidates,
|
|
2387
|
+
tradeoffs,
|
|
2388
|
+
decision,
|
|
2389
|
+
antiPatterns,
|
|
2390
|
+
sensitivity,
|
|
2391
|
+
breakpoints,
|
|
2392
|
+
securityAnalysis,
|
|
2393
|
+
} = params;
|
|
2394
|
+
|
|
2395
|
+
const selectedCandidate = decision || (candidates && candidates[0]) || {};
|
|
2396
|
+
const rejectedCandidates = (candidates || []).filter(c => c.name !== selectedCandidate.name);
|
|
2397
|
+
|
|
2398
|
+
return {
|
|
2399
|
+
id: `ADR-${crypto.randomUUID ? crypto.randomUUID().slice(0, 8) : Date.now().toString(36)}`,
|
|
2400
|
+
title: `Architecture Decision: ${selectedCandidate.name || 'Unknown'}`,
|
|
2401
|
+
status: 'PROPOSED',
|
|
2402
|
+
date: new Date().toISOString(),
|
|
2403
|
+
context: {
|
|
2404
|
+
task: task || '',
|
|
2405
|
+
functional_requirements: (requirements && requirements.functional) || [],
|
|
2406
|
+
non_functional_requirements: (requirements && requirements.non_functional) || [],
|
|
2407
|
+
constraints: (constraints && constraints.constraints) || [],
|
|
2408
|
+
unknowns: (requirements && requirements.unknowns) || [],
|
|
2409
|
+
},
|
|
2410
|
+
decision: {
|
|
2411
|
+
architecture: selectedCandidate.name || 'Unknown',
|
|
2412
|
+
pattern: selectedCandidate.pattern || '',
|
|
2413
|
+
rationale: selectedCandidate.reasons || [],
|
|
2414
|
+
score: selectedCandidate.score || 0,
|
|
2415
|
+
},
|
|
2416
|
+
tradeoffs: tradeoffs || {},
|
|
2417
|
+
rejected_alternatives: rejectedCandidates.map(c => ({
|
|
2418
|
+
architecture: c.name,
|
|
2419
|
+
pattern: c.pattern,
|
|
2420
|
+
rejection_reason: c.risks || [],
|
|
2421
|
+
score: c.score || 0,
|
|
2422
|
+
})),
|
|
2423
|
+
anti_patterns_detected: antiPatterns || [],
|
|
2424
|
+
assumptions: (requirements && requirements.assumptions) || [],
|
|
2425
|
+
evidence: [],
|
|
2426
|
+
risks: selectedCandidate.risks || [],
|
|
2427
|
+
decision_sensitivity: sensitivity || [],
|
|
2428
|
+
breakpoints: breakpoints || [],
|
|
2429
|
+
security_considerations: (securityAnalysis && securityAnalysis.considerations) || [],
|
|
2430
|
+
verification_plan: [
|
|
2431
|
+
'Verify architecture handles expected load via load test',
|
|
2432
|
+
'Verify failure behavior via Phase 6 pre-mortem simulation',
|
|
2433
|
+
'Verify security boundaries via Phase 8 validation',
|
|
2434
|
+
'Review decision sensitivity assumptions quarterly',
|
|
2435
|
+
],
|
|
2436
|
+
revisit_conditions: [
|
|
2437
|
+
'Traffic exceeds estimated breakpoint thresholds',
|
|
2438
|
+
'Team size changes significantly',
|
|
2439
|
+
'New compliance requirements imposed',
|
|
2440
|
+
'Cost exceeds projected budget by >50%',
|
|
2441
|
+
'Critical failure mode materializes in production',
|
|
2442
|
+
],
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
// ============================================================================
|
|
2447
|
+
// 11. ARCHITECTURE GRAPH (SECTION 39)
|
|
2448
|
+
// ============================================================================
|
|
2449
|
+
|
|
2450
|
+
/**
|
|
2451
|
+
* Generate a machine-readable architecture graph.
|
|
2452
|
+
*/
|
|
2453
|
+
function generateArchitectureGraph(candidate, requirements, securityAnalysis) {
|
|
2454
|
+
const patternKey = candidate.pattern || '';
|
|
2455
|
+
const nodes = [];
|
|
2456
|
+
const edges = [];
|
|
2457
|
+
|
|
2458
|
+
// Always have a client
|
|
2459
|
+
nodes.push({
|
|
2460
|
+
id: 'client',
|
|
2461
|
+
type: 'external',
|
|
2462
|
+
technology: 'Browser/Mobile',
|
|
2463
|
+
responsibility: 'User interaction',
|
|
2464
|
+
scaling_model: 'N/A',
|
|
2465
|
+
});
|
|
2466
|
+
|
|
2467
|
+
// API layer
|
|
2468
|
+
nodes.push({
|
|
2469
|
+
id: 'api',
|
|
2470
|
+
type: 'service',
|
|
2471
|
+
technology: 'API Server',
|
|
2472
|
+
responsibility: 'Request handling, routing, validation',
|
|
2473
|
+
scaling_model: 'horizontal',
|
|
2474
|
+
security_boundary: true,
|
|
2475
|
+
});
|
|
2476
|
+
edges.push({ from: 'client', to: 'api', protocol: 'HTTPS' });
|
|
2477
|
+
|
|
2478
|
+
// Database
|
|
2479
|
+
nodes.push({
|
|
2480
|
+
id: 'database',
|
|
2481
|
+
type: 'datastore',
|
|
2482
|
+
technology: 'PostgreSQL',
|
|
2483
|
+
responsibility: 'Primary data persistence',
|
|
2484
|
+
scaling_model: 'vertical + read replicas',
|
|
2485
|
+
security_boundary: true,
|
|
2486
|
+
});
|
|
2487
|
+
edges.push({ from: 'api', to: 'database', protocol: 'TCP' });
|
|
2488
|
+
|
|
2489
|
+
// Pattern-specific nodes
|
|
2490
|
+
if (['event_driven', 'microservices', 'distributed_workers'].includes(patternKey)) {
|
|
2491
|
+
nodes.push({
|
|
2492
|
+
id: 'queue',
|
|
2493
|
+
type: 'infrastructure',
|
|
2494
|
+
technology: 'Message Queue',
|
|
2495
|
+
responsibility: 'Async task routing',
|
|
2496
|
+
scaling_model: 'partition-based',
|
|
2497
|
+
});
|
|
2498
|
+
nodes.push({
|
|
2499
|
+
id: 'worker',
|
|
2500
|
+
type: 'service',
|
|
2501
|
+
technology: 'Background Worker',
|
|
2502
|
+
responsibility: 'Async processing',
|
|
2503
|
+
scaling_model: 'horizontal',
|
|
2504
|
+
});
|
|
2505
|
+
edges.push({ from: 'api', to: 'queue', protocol: 'AMQP/SQS' });
|
|
2506
|
+
edges.push({ from: 'queue', to: 'worker', protocol: 'AMQP/SQS' });
|
|
2507
|
+
edges.push({ from: 'worker', to: 'database', protocol: 'TCP' });
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
// Cache
|
|
2511
|
+
if (
|
|
2512
|
+
requirements &&
|
|
2513
|
+
requirements.functional &&
|
|
2514
|
+
requirements.functional.some(f => f.domain === 'performance' || f.req === 'caching layer')
|
|
2515
|
+
) {
|
|
2516
|
+
nodes.push({
|
|
2517
|
+
id: 'cache',
|
|
2518
|
+
type: 'infrastructure',
|
|
2519
|
+
technology: 'Redis',
|
|
2520
|
+
responsibility: 'Query caching, session storage',
|
|
2521
|
+
scaling_model: 'horizontal',
|
|
2522
|
+
});
|
|
2523
|
+
edges.push({ from: 'api', to: 'cache', protocol: 'TCP' });
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
// External services
|
|
2527
|
+
if (
|
|
2528
|
+
requirements &&
|
|
2529
|
+
requirements.functional &&
|
|
2530
|
+
requirements.functional.some(f => f.domain === 'financial')
|
|
2531
|
+
) {
|
|
2532
|
+
nodes.push({
|
|
2533
|
+
id: 'payment_gateway',
|
|
2534
|
+
type: 'external',
|
|
2535
|
+
technology: 'Stripe/Payment Provider',
|
|
2536
|
+
responsibility: 'Payment processing',
|
|
2537
|
+
scaling_model: 'managed',
|
|
2538
|
+
});
|
|
2539
|
+
edges.push({ from: 'api', to: 'payment_gateway', protocol: 'HTTPS' });
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
return { nodes, edges, pattern: candidate.name || patternKey };
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// ============================================================================
|
|
2546
|
+
// 12. ARCHITECTURE DIFFERENCE ENGINE (SECTION 40)
|
|
2547
|
+
// ============================================================================
|
|
2548
|
+
|
|
2549
|
+
/**
|
|
2550
|
+
* Compare two architectures and identify material differences.
|
|
2551
|
+
*/
|
|
2552
|
+
function diffArchitectures(archA, archB) {
|
|
2553
|
+
const diff = {
|
|
2554
|
+
architectures: { a: archA.name || 'A', b: archB.name || 'B' },
|
|
2555
|
+
components_added: [],
|
|
2556
|
+
components_removed: [],
|
|
2557
|
+
dependencies_changed: [],
|
|
2558
|
+
failure_modes_changed: [],
|
|
2559
|
+
consistency_changed: false,
|
|
2560
|
+
cost_changed: false,
|
|
2561
|
+
operational_burden_changed: false,
|
|
2562
|
+
security_boundaries_changed: false,
|
|
2563
|
+
scaling_behavior_changed: false,
|
|
2564
|
+
summary: '',
|
|
2565
|
+
};
|
|
2566
|
+
|
|
2567
|
+
const patternA = ARCHITECTURE_PATTERNS[archA.pattern] || {};
|
|
2568
|
+
const patternB = ARCHITECTURE_PATTERNS[archB.pattern] || {};
|
|
2569
|
+
|
|
2570
|
+
// Compare required capabilities
|
|
2571
|
+
const capsA = new Set(patternA.required_capabilities || []);
|
|
2572
|
+
const capsB = new Set(patternB.required_capabilities || []);
|
|
2573
|
+
diff.components_added = [...capsB].filter(c => !capsA.has(c));
|
|
2574
|
+
diff.components_removed = [...capsA].filter(c => !capsB.has(c));
|
|
2575
|
+
|
|
2576
|
+
// Compare failure modes
|
|
2577
|
+
const fmA = new Set(patternA.failure_modes || []);
|
|
2578
|
+
const fmB = new Set(patternB.failure_modes || []);
|
|
2579
|
+
diff.failure_modes_changed = [...fmB].filter(f => !fmA.has(f));
|
|
2580
|
+
|
|
2581
|
+
// Compare operational cost
|
|
2582
|
+
diff.cost_changed = patternA.operational_cost !== patternB.operational_cost;
|
|
2583
|
+
diff.operational_burden_changed = patternA.operational_cost !== patternB.operational_cost;
|
|
2584
|
+
|
|
2585
|
+
// Compare scaling
|
|
2586
|
+
const scaleA = JSON.stringify(patternA.scaling_characteristics || {});
|
|
2587
|
+
const scaleB = JSON.stringify(patternB.scaling_characteristics || {});
|
|
2588
|
+
diff.scaling_behavior_changed = scaleA !== scaleB;
|
|
2589
|
+
|
|
2590
|
+
// Compare security
|
|
2591
|
+
const secA = (patternA.security_considerations || []).length;
|
|
2592
|
+
const secB = (patternB.security_considerations || []).length;
|
|
2593
|
+
diff.security_boundaries_changed = secA !== secB;
|
|
2594
|
+
|
|
2595
|
+
diff.summary =
|
|
2596
|
+
`Moving from ${diff.architectures.a} to ${diff.architectures.b}: ` +
|
|
2597
|
+
`+${diff.components_added.length} components, -${diff.components_removed.length} components, ` +
|
|
2598
|
+
`${diff.failure_modes_changed.length} new failure modes.`;
|
|
2599
|
+
|
|
2600
|
+
return diff;
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
// ============================================================================
|
|
2604
|
+
// 13. DECISION REVERSIBILITY & CONFIDENCE (SECTIONS 31–32)
|
|
2605
|
+
// ============================================================================
|
|
2606
|
+
|
|
2607
|
+
/**
|
|
2608
|
+
* Classify architecture decision reversibility.
|
|
2609
|
+
*/
|
|
2610
|
+
function classifyArchitectureReversibility(decisionType) {
|
|
2611
|
+
const classifications = {
|
|
2612
|
+
ui_library: 'EASILY_REVERSIBLE',
|
|
2613
|
+
css_framework: 'EASILY_REVERSIBLE',
|
|
2614
|
+
api_framework: 'MODERATELY_REVERSIBLE',
|
|
2615
|
+
database_choice: 'HARD_TO_REVERSE',
|
|
2616
|
+
data_model: 'HARD_TO_REVERSE',
|
|
2617
|
+
consistency_model: 'HARD_TO_REVERSE',
|
|
2618
|
+
api_contract: 'MODERATELY_REVERSIBLE',
|
|
2619
|
+
deployment_platform: 'MODERATELY_REVERSIBLE',
|
|
2620
|
+
architecture_pattern: 'HARD_TO_REVERSE',
|
|
2621
|
+
message_broker: 'MODERATELY_REVERSIBLE',
|
|
2622
|
+
auth_provider: 'MODERATELY_REVERSIBLE',
|
|
2623
|
+
cloud_provider: 'HARD_TO_REVERSE',
|
|
2624
|
+
};
|
|
2625
|
+
return classifications[decisionType] || 'UNKNOWN';
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
/**
|
|
2629
|
+
* Assess architecture confidence across dimensions.
|
|
2630
|
+
*/
|
|
2631
|
+
function assessArchitectureConfidence(requirements) {
|
|
2632
|
+
const confidence = {};
|
|
2633
|
+
const constraints = (requirements && requirements.constraints) || [];
|
|
2634
|
+
const unknowns = (requirements && requirements.unknowns) || [];
|
|
2635
|
+
|
|
2636
|
+
confidence.database = constraints.some(c => c.category === 'technology') ? 'KNOWN' : 'ESTIMATED';
|
|
2637
|
+
confidence.traffic = constraints.some(c => c.category === 'scale' || c.category === 'performance')
|
|
2638
|
+
? 'SUPPORTED'
|
|
2639
|
+
: 'UNKNOWN';
|
|
2640
|
+
confidence.team = constraints.some(c => c.category === 'team') ? 'KNOWN' : 'UNKNOWN';
|
|
2641
|
+
confidence.budget = constraints.some(c => c.category === 'cost') ? 'KNOWN' : 'UNKNOWN';
|
|
2642
|
+
confidence.compliance = constraints.some(c => c.category === 'governance') ? 'KNOWN' : 'UNKNOWN';
|
|
2643
|
+
confidence.geographic = constraints.some(c => c.req === 'data residency') ? 'KNOWN' : 'UNKNOWN';
|
|
2644
|
+
|
|
2645
|
+
return confidence;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
// ============================================================================
|
|
2649
|
+
// 14. FITNESS TEST GENERATOR (SECTION 42)
|
|
2650
|
+
// ============================================================================
|
|
2651
|
+
|
|
2652
|
+
/**
|
|
2653
|
+
* Generate architecture fitness tests for a candidate + ADR.
|
|
2654
|
+
*/
|
|
2655
|
+
function generateFitnessTests(candidate, adr) {
|
|
2656
|
+
const tests = [];
|
|
2657
|
+
const patternKey = candidate.pattern || '';
|
|
2658
|
+
|
|
2659
|
+
// Universal tests
|
|
2660
|
+
tests.push({
|
|
2661
|
+
name: 'no_circular_dependencies',
|
|
2662
|
+
description: 'No circular dependency chains between modules/services',
|
|
2663
|
+
type: 'structural',
|
|
2664
|
+
automated: true,
|
|
2665
|
+
});
|
|
2666
|
+
tests.push({
|
|
2667
|
+
name: 'no_forbidden_dependencies',
|
|
2668
|
+
description: 'No module imports from forbidden layers (e.g., infrastructure importing domain)',
|
|
2669
|
+
type: 'structural',
|
|
2670
|
+
automated: true,
|
|
2671
|
+
});
|
|
2672
|
+
tests.push({
|
|
2673
|
+
name: 'no_missing_timeouts',
|
|
2674
|
+
description: 'All external HTTP/RPC calls have explicit timeout configuration',
|
|
2675
|
+
type: 'resilience',
|
|
2676
|
+
automated: true,
|
|
2677
|
+
});
|
|
2678
|
+
tests.push({
|
|
2679
|
+
name: 'no_unbounded_retries',
|
|
2680
|
+
description: 'All retry logic has maximum attempt limits and backoff',
|
|
2681
|
+
type: 'resilience',
|
|
2682
|
+
automated: true,
|
|
2683
|
+
});
|
|
2684
|
+
|
|
2685
|
+
// Pattern-specific tests
|
|
2686
|
+
if (['modular_monolith', 'hexagonal'].includes(patternKey)) {
|
|
2687
|
+
tests.push({
|
|
2688
|
+
name: 'module_boundary_enforcement',
|
|
2689
|
+
description: 'Modules access each other only through defined interfaces, not direct imports',
|
|
2690
|
+
type: 'structural',
|
|
2691
|
+
automated: true,
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
if (['microservices', 'event_driven'].includes(patternKey)) {
|
|
2696
|
+
tests.push({
|
|
2697
|
+
name: 'no_shared_database',
|
|
2698
|
+
description: 'Each service owns its database; no direct cross-service DB access',
|
|
2699
|
+
type: 'data_ownership',
|
|
2700
|
+
automated: true,
|
|
2701
|
+
});
|
|
2702
|
+
tests.push({
|
|
2703
|
+
name: 'no_synchronous_chain',
|
|
2704
|
+
description: 'No synchronous call chain exceeding 3 services deep',
|
|
2705
|
+
type: 'resilience',
|
|
2706
|
+
automated: true,
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
if (adr && adr.security_considerations && adr.security_considerations.length > 0) {
|
|
2711
|
+
tests.push({
|
|
2712
|
+
name: 'auth_before_business_logic',
|
|
2713
|
+
description:
|
|
2714
|
+
'All API endpoints enforce authentication and authorization before executing business logic',
|
|
2715
|
+
type: 'security',
|
|
2716
|
+
automated: true,
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
return tests;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
// ============================================================================
|
|
2724
|
+
// 15. DRIFT DETECTION (SECTION 41)
|
|
2725
|
+
// ============================================================================
|
|
2726
|
+
|
|
2727
|
+
/**
|
|
2728
|
+
* Detect architectural drift between implementation and ADR.
|
|
2729
|
+
*/
|
|
2730
|
+
function detectArchitecturalDrift(implementation, adr) {
|
|
2731
|
+
const drifts = [];
|
|
2732
|
+
|
|
2733
|
+
if (!implementation || !adr) return drifts;
|
|
2734
|
+
|
|
2735
|
+
// Check for unauthorized dependencies
|
|
2736
|
+
const implDeps = implementation.dependencies || [];
|
|
2737
|
+
const adrDeps = (adr.decision && adr.decision.rationale) || [];
|
|
2738
|
+
|
|
2739
|
+
// Check for new direct database access bypassing intended boundaries
|
|
2740
|
+
if (implementation.direct_db_access_from_unauthorized_layer) {
|
|
2741
|
+
drifts.push({
|
|
2742
|
+
type: 'BOUNDARY_VIOLATION',
|
|
2743
|
+
severity: 'HIGH',
|
|
2744
|
+
description:
|
|
2745
|
+
'Direct database access detected from unauthorized layer, bypassing repository boundary.',
|
|
2746
|
+
adr_reference: adr.id || 'N/A',
|
|
2747
|
+
});
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
// Check for new service dependencies creating synchronous cycles
|
|
2751
|
+
if (implementation.synchronous_cycle_detected) {
|
|
2752
|
+
drifts.push({
|
|
2753
|
+
type: 'DEPENDENCY_CYCLE',
|
|
2754
|
+
severity: 'CRITICAL',
|
|
2755
|
+
description:
|
|
2756
|
+
'New synchronous service dependency creates a cycle, contradicting ADR architecture.',
|
|
2757
|
+
adr_reference: adr.id || 'N/A',
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
// Check for new cache creating second source of truth
|
|
2762
|
+
if (implementation.new_cache_without_invalidation) {
|
|
2763
|
+
drifts.push({
|
|
2764
|
+
type: 'DATA_INTEGRITY',
|
|
2765
|
+
severity: 'HIGH',
|
|
2766
|
+
description:
|
|
2767
|
+
'New cache introduced without invalidation strategy creates second source of truth.',
|
|
2768
|
+
adr_reference: adr.id || 'N/A',
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
// Check for new API bypassing auth middleware
|
|
2773
|
+
if (implementation.api_bypasses_auth) {
|
|
2774
|
+
drifts.push({
|
|
2775
|
+
type: 'SECURITY_VIOLATION',
|
|
2776
|
+
severity: 'CRITICAL',
|
|
2777
|
+
description: 'New API endpoint bypasses authentication/authorization middleware.',
|
|
2778
|
+
adr_reference: adr.id || 'N/A',
|
|
2779
|
+
});
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
return drifts;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// ============================================================================
|
|
2786
|
+
// 16. PHASE 7 METRICS TRACKER (SECTION 45)
|
|
2787
|
+
// ============================================================================
|
|
2788
|
+
|
|
2789
|
+
class Phase7MetricsTracker {
|
|
2790
|
+
constructor() {
|
|
2791
|
+
this.metrics = {
|
|
2792
|
+
requirement_extraction_accuracy: { correct: 0, total: 0 },
|
|
2793
|
+
constraint_discovery_rate: { discovered: 0, total: 0 },
|
|
2794
|
+
candidate_relevance: { relevant: 0, total: 0 },
|
|
2795
|
+
tradeoff_coverage: { covered: 0, total: 0 },
|
|
2796
|
+
unsupported_assumption_detection: { detected: 0, total: 0 },
|
|
2797
|
+
architecture_failure_discovery: { discovered: 0, total: 0 },
|
|
2798
|
+
adr_completeness: { complete_fields: 0, total_fields: 0 },
|
|
2799
|
+
drift_detection: { detected: 0, total: 0 },
|
|
2800
|
+
decision_reversal_detection: { detected: 0, total: 0 },
|
|
2801
|
+
simulation_decision_coverage: { covered: 0, total: 0 },
|
|
2802
|
+
historical_reuse_accuracy: { accurate: 0, total: 0 },
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
record(metric, success) {
|
|
2807
|
+
if (this.metrics[metric]) {
|
|
2808
|
+
this.metrics[metric].total++;
|
|
2809
|
+
if (success) {
|
|
2810
|
+
const key = Object.keys(this.metrics[metric]).find(k => k !== 'total');
|
|
2811
|
+
if (key) this.metrics[metric][key]++;
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
getMetrics() {
|
|
2817
|
+
const result = {};
|
|
2818
|
+
for (const [key, val] of Object.entries(this.metrics)) {
|
|
2819
|
+
result[key] = {
|
|
2820
|
+
...val,
|
|
2821
|
+
rate: val.total > 0 ? val[Object.keys(val).find(k => k !== 'total')] / val.total : 0,
|
|
2822
|
+
};
|
|
2823
|
+
}
|
|
2824
|
+
return result;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
let _phase7MetricsTracker = null;
|
|
2829
|
+
|
|
2830
|
+
function getPhase7MetricsTracker() {
|
|
2831
|
+
if (!_phase7MetricsTracker) {
|
|
2832
|
+
_phase7MetricsTracker = new Phase7MetricsTracker();
|
|
2833
|
+
}
|
|
2834
|
+
return _phase7MetricsTracker;
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
// ============================================================================
|
|
2838
|
+
// 17. PROGRESSIVE ANALYSIS (SECTION 46)
|
|
2839
|
+
// ============================================================================
|
|
2840
|
+
|
|
2841
|
+
/**
|
|
2842
|
+
* Determine how deep the architecture analysis should go.
|
|
2843
|
+
*
|
|
2844
|
+
* @param {string} taskQuery
|
|
2845
|
+
* @returns {string} 'NONE' | 'MINIMAL' | 'STANDARD' | 'FULL'
|
|
2846
|
+
*/
|
|
2847
|
+
function determineAnalysisDepth(taskQuery) {
|
|
2848
|
+
const q = (taskQuery || '').toLowerCase();
|
|
2849
|
+
|
|
2850
|
+
// Tier 0: No architecture analysis needed
|
|
2851
|
+
if (/(?:^fix|^typo|^css|^format|^rename|^lint|^style|^readme|^comment|^doc)/i.test(q.trim())) {
|
|
2852
|
+
return 'NONE';
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
// Tier 1: Minimal — single file change, simple logic
|
|
2856
|
+
if (/(?:^add.*button|^change.*color|^update.*text|^modify.*config|^add.*field)/i.test(q.trim())) {
|
|
2857
|
+
return 'MINIMAL';
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
// Tier 3: Full — architectural keywords present
|
|
2861
|
+
if (
|
|
2862
|
+
/(?:architect|design.*system|multi.?tenant|distributed|microservice|platform|saas|scale|million|enterprise|migrate)/i.test(
|
|
2863
|
+
q,
|
|
2864
|
+
)
|
|
2865
|
+
) {
|
|
2866
|
+
return 'FULL';
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
// Tier 2: Standard — multi-component work
|
|
2870
|
+
if (/(?:build|create|implement|api|backend|frontend|database|service|application|app)/i.test(q)) {
|
|
2871
|
+
return 'STANDARD';
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
return 'MINIMAL';
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
// ============================================================================
|
|
2878
|
+
// 18. MAIN ORCHESTRATOR — runArchitectureAnalysis
|
|
2879
|
+
// ============================================================================
|
|
2880
|
+
|
|
2881
|
+
/**
|
|
2882
|
+
* Run the full Phase 7 architecture intelligence pipeline.
|
|
2883
|
+
*
|
|
2884
|
+
* @param {string} taskQuery
|
|
2885
|
+
* @param {Object} [options]
|
|
2886
|
+
* @returns {Object} Full architecture analysis
|
|
2887
|
+
*/
|
|
2888
|
+
function runArchitectureAnalysis(taskQuery, options = {}) {
|
|
2889
|
+
const depth = options.depth || determineAnalysisDepth(taskQuery);
|
|
2890
|
+
|
|
2891
|
+
if (depth === 'NONE') {
|
|
2892
|
+
return {
|
|
2893
|
+
task: taskQuery,
|
|
2894
|
+
depth: 'NONE',
|
|
2895
|
+
skipped: true,
|
|
2896
|
+
reason: 'Task does not require architecture analysis (Tier 0).',
|
|
2897
|
+
requirements: null,
|
|
2898
|
+
candidates: null,
|
|
2899
|
+
tradeoffs: null,
|
|
2900
|
+
adr: null,
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
// Step 1: Extract requirements
|
|
2905
|
+
const requirements = extractRequirements(taskQuery);
|
|
2906
|
+
|
|
2907
|
+
// Step 2: Extract constraints
|
|
2908
|
+
const constraintResult = extractConstraints(taskQuery, requirements);
|
|
2909
|
+
|
|
2910
|
+
if (depth === 'MINIMAL') {
|
|
2911
|
+
return {
|
|
2912
|
+
task: taskQuery,
|
|
2913
|
+
depth: 'MINIMAL',
|
|
2914
|
+
requirements,
|
|
2915
|
+
constraints: constraintResult,
|
|
2916
|
+
candidates: null,
|
|
2917
|
+
tradeoffs: null,
|
|
2918
|
+
adr: null,
|
|
2919
|
+
anti_patterns: [],
|
|
2920
|
+
reason: 'Task requires minimal architecture analysis (Tier 1).',
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
// Step 3: Detect anti-patterns
|
|
2925
|
+
const antiPatterns = detectAntiPatterns(taskQuery, requirements);
|
|
2926
|
+
|
|
2927
|
+
// Step 4: Generate candidates
|
|
2928
|
+
const candidateResult = generateCandidates(requirements, constraintResult);
|
|
2929
|
+
|
|
2930
|
+
// Step 5: Build trade-offs
|
|
2931
|
+
let tradeoffResult = null;
|
|
2932
|
+
if (candidateResult.candidates.length >= 2) {
|
|
2933
|
+
tradeoffResult = analyzeTradeoffs(candidateResult.candidates, requirements, constraintResult);
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
// Step 6: Decision sensitivity
|
|
2937
|
+
const sensitivity = analyzeDecisionSensitivity(
|
|
2938
|
+
candidateResult.candidates,
|
|
2939
|
+
tradeoffResult,
|
|
2940
|
+
requirements,
|
|
2941
|
+
);
|
|
2942
|
+
|
|
2943
|
+
// Step 7: Breakpoints for top candidate
|
|
2944
|
+
const breakpoints = candidateResult.candidates[0]
|
|
2945
|
+
? identifyBreakpoints(candidateResult.candidates[0], requirements)
|
|
2946
|
+
: [];
|
|
2947
|
+
|
|
2948
|
+
// Step 8: Domain-specific analysis
|
|
2949
|
+
const buildVsBuy = analyzeBuildVsBuy(taskQuery, requirements);
|
|
2950
|
+
const dataArchitecture = analyzeDataArchitecture(taskQuery, requirements);
|
|
2951
|
+
const communicationPatterns = analyzeCommunicationPatterns(taskQuery);
|
|
2952
|
+
const securityArchitecture = analyzeSecurityArchitecture(taskQuery, requirements);
|
|
2953
|
+
|
|
2954
|
+
// Step 9: Cost & operational analysis for top candidate
|
|
2955
|
+
let costAnalysis = null;
|
|
2956
|
+
let operationalAnalysis = null;
|
|
2957
|
+
if (candidateResult.candidates[0]) {
|
|
2958
|
+
costAnalysis = analyzeCostArchitecture(candidateResult.candidates[0], constraintResult);
|
|
2959
|
+
operationalAnalysis = analyzeOperationalComplexity(candidateResult.candidates[0]);
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
// Step 10: Evolution analysis
|
|
2963
|
+
const evolutionAnalysis = candidateResult.candidates[0]
|
|
2964
|
+
? analyzeEvolution(candidateResult.candidates[0])
|
|
2965
|
+
: null;
|
|
2966
|
+
|
|
2967
|
+
// Step 11: Architecture graph
|
|
2968
|
+
const architectureGraph = candidateResult.candidates[0]
|
|
2969
|
+
? generateArchitectureGraph(candidateResult.candidates[0], requirements, securityArchitecture)
|
|
2970
|
+
: null;
|
|
2971
|
+
|
|
2972
|
+
// Step 12: Confidence assessment
|
|
2973
|
+
const confidence = assessArchitectureConfidence(requirements);
|
|
2974
|
+
|
|
2975
|
+
// Step 13: Fitness tests
|
|
2976
|
+
let fitnessTests = [];
|
|
2977
|
+
let adr = null;
|
|
2978
|
+
|
|
2979
|
+
if (depth === 'FULL' || candidateResult.candidates.length > 0) {
|
|
2980
|
+
// Step 14: Generate ADR
|
|
2981
|
+
adr = generateADR({
|
|
2982
|
+
task: taskQuery,
|
|
2983
|
+
requirements,
|
|
2984
|
+
constraints: constraintResult,
|
|
2985
|
+
candidates: candidateResult.candidates,
|
|
2986
|
+
tradeoffs: tradeoffResult,
|
|
2987
|
+
decision: candidateResult.candidates[0],
|
|
2988
|
+
antiPatterns,
|
|
2989
|
+
sensitivity,
|
|
2990
|
+
breakpoints,
|
|
2991
|
+
securityAnalysis: securityArchitecture,
|
|
2992
|
+
});
|
|
2993
|
+
|
|
2994
|
+
fitnessTests = candidateResult.candidates[0]
|
|
2995
|
+
? generateFitnessTests(candidateResult.candidates[0], adr)
|
|
2996
|
+
: [];
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
return {
|
|
3000
|
+
task: taskQuery,
|
|
3001
|
+
depth,
|
|
3002
|
+
requirements,
|
|
3003
|
+
constraints: constraintResult,
|
|
3004
|
+
anti_patterns: antiPatterns,
|
|
3005
|
+
candidates: candidateResult,
|
|
3006
|
+
tradeoffs: tradeoffResult,
|
|
3007
|
+
decision_sensitivity: sensitivity,
|
|
3008
|
+
breakpoints,
|
|
3009
|
+
build_vs_buy: buildVsBuy,
|
|
3010
|
+
data_architecture: dataArchitecture,
|
|
3011
|
+
communication_patterns: communicationPatterns,
|
|
3012
|
+
security_architecture: securityArchitecture,
|
|
3013
|
+
cost_analysis: costAnalysis,
|
|
3014
|
+
operational_analysis: operationalAnalysis,
|
|
3015
|
+
evolution: evolutionAnalysis,
|
|
3016
|
+
architecture_graph: architectureGraph,
|
|
3017
|
+
confidence,
|
|
3018
|
+
fitness_tests: fitnessTests,
|
|
3019
|
+
adr,
|
|
3020
|
+
memory_updates: [],
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
// ============================================================================
|
|
3025
|
+
// EXPORTS
|
|
3026
|
+
// ============================================================================
|
|
3027
|
+
|
|
3028
|
+
module.exports = {
|
|
3029
|
+
// Constants
|
|
3030
|
+
REQUIREMENT_TYPES,
|
|
3031
|
+
CONFIDENCE_LEVELS,
|
|
3032
|
+
ARCHITECTURE_PATTERNS,
|
|
3033
|
+
ANTI_PATTERNS,
|
|
3034
|
+
TRADEOFF_CRITERIA,
|
|
3035
|
+
|
|
3036
|
+
// Requirement Intelligence (§4–§5)
|
|
3037
|
+
extractRequirements,
|
|
3038
|
+
|
|
3039
|
+
// Constraint Extraction (§6)
|
|
3040
|
+
extractConstraints,
|
|
3041
|
+
|
|
3042
|
+
// Pattern Registry (§8)
|
|
3043
|
+
getArchitecturePatterns,
|
|
3044
|
+
|
|
3045
|
+
// Anti-Pattern Detection (§9)
|
|
3046
|
+
detectAntiPatterns,
|
|
3047
|
+
|
|
3048
|
+
// Candidate Generation (§7)
|
|
3049
|
+
generateCandidates,
|
|
3050
|
+
|
|
3051
|
+
// Trade-Off Engine (§10–§11)
|
|
3052
|
+
analyzeTradeoffs,
|
|
3053
|
+
rateCriterion,
|
|
3054
|
+
determineCriterionImportance,
|
|
3055
|
+
|
|
3056
|
+
// Decision Sensitivity & Breakpoints (§12–§13)
|
|
3057
|
+
analyzeDecisionSensitivity,
|
|
3058
|
+
identifyBreakpoints,
|
|
3059
|
+
|
|
3060
|
+
// Domain-Specific Analyzers (§14–§27)
|
|
3061
|
+
analyzeBuildVsBuy,
|
|
3062
|
+
analyzeDataArchitecture,
|
|
3063
|
+
analyzeCommunicationPatterns,
|
|
3064
|
+
analyzeSecurityArchitecture,
|
|
3065
|
+
analyzeCostArchitecture,
|
|
3066
|
+
analyzeOperationalComplexity,
|
|
3067
|
+
|
|
3068
|
+
// Migration & Evolution (§28–§29)
|
|
3069
|
+
analyzeMigration,
|
|
3070
|
+
analyzeEvolution,
|
|
3071
|
+
|
|
3072
|
+
// ADR Generation (§30)
|
|
3073
|
+
generateADR,
|
|
3074
|
+
|
|
3075
|
+
// Architecture Graph (§39)
|
|
3076
|
+
generateArchitectureGraph,
|
|
3077
|
+
|
|
3078
|
+
// Difference Engine (§40)
|
|
3079
|
+
diffArchitectures,
|
|
3080
|
+
|
|
3081
|
+
// Reversibility & Confidence (§31–§32)
|
|
3082
|
+
classifyArchitectureReversibility,
|
|
3083
|
+
assessArchitectureConfidence,
|
|
3084
|
+
|
|
3085
|
+
// Fitness Tests (§42)
|
|
3086
|
+
generateFitnessTests,
|
|
3087
|
+
|
|
3088
|
+
// Drift Detection (§41)
|
|
3089
|
+
detectArchitecturalDrift,
|
|
3090
|
+
|
|
3091
|
+
// Metrics (§45)
|
|
3092
|
+
Phase7MetricsTracker,
|
|
3093
|
+
getPhase7MetricsTracker,
|
|
3094
|
+
|
|
3095
|
+
// Progressive Analysis (§46)
|
|
3096
|
+
determineAnalysisDepth,
|
|
3097
|
+
|
|
3098
|
+
// Main Orchestrator
|
|
3099
|
+
runArchitectureAnalysis,
|
|
3100
|
+
};
|