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.
Files changed (63) hide show
  1. package/.agent/ARCHITECTURE.md +2 -2
  2. package/.agent/history/architecture-intelligence.html +1487 -401
  3. package/.agent/history/architecture-model.json +9365 -5697
  4. package/.agent/history/architecture-verification.json +37 -9
  5. package/.agent/routing_index.json +2069 -3340
  6. package/.agent/rules/GEMINI.md +1 -1
  7. package/.agent/scripts/adaptive_execution.js +511 -0
  8. package/.agent/scripts/architecture_diff.js +303 -260
  9. package/.agent/scripts/architecture_extractor.js +792 -753
  10. package/.agent/scripts/architecture_health.js +293 -256
  11. package/.agent/scripts/architecture_intelligence.js +3100 -0
  12. package/.agent/scripts/architecture_verifier.js +303 -270
  13. package/.agent/scripts/architecture_visualizer.js +880 -873
  14. package/.agent/scripts/blast_radius_engine.js +274 -234
  15. package/.agent/scripts/capability_evolution.js +453 -0
  16. package/.agent/scripts/concept_extractor.js +240 -0
  17. package/.agent/scripts/consideration_engine.js +284 -0
  18. package/.agent/scripts/coverage_engine.js +102 -0
  19. package/.agent/scripts/cross_domain_engine.js +1883 -0
  20. package/.agent/scripts/engineering_memory.js +1313 -0
  21. package/.agent/scripts/integrity_manifest.js +1 -5
  22. package/.agent/scripts/judgment_engine.js +790 -0
  23. package/.agent/scripts/materiality_engine.js +251 -0
  24. package/.agent/scripts/outcome_engine.js +624 -0
  25. package/.agent/scripts/outcome_optimization_engine.js +1632 -0
  26. package/.agent/scripts/simulation_engine.js +1478 -0
  27. package/.agent/scripts/skill_intelligence.js +1371 -0
  28. package/.agent/scripts/validation_engine.js +236 -236
  29. package/.agent/scripts/verification_auditor.js +266 -0
  30. package/.agent/skill-intelligence/taxonomy/engineering-concepts.json +555 -0
  31. package/.agent/skill_topic_map.json +301 -341
  32. package/.agent/skills_inventory.json +4272 -6922
  33. package/.agent/workflows/arch.md +96 -80
  34. package/.agent/workflows/skill-intelligence.md +216 -0
  35. package/CONTRIBUTING.md +2 -2
  36. package/README.md +24 -24
  37. package/bin/adapter-install.js +1 -1
  38. package/package.json +8 -9
  39. package/plugins/core-plugin.json +1 -1
  40. package/plugins/gemini/extension.json +1 -1
  41. package/src/browser/index.js +2 -1
  42. package/src/browser/launcher.js +41 -1
  43. package/src/cli.js +3 -1
  44. package/src/commands/arch.js +261 -172
  45. package/src/commands/context.js +27 -8
  46. package/src/commands/learn.js +21 -6
  47. package/src/commands/memory.js +10 -1
  48. package/src/commands/native.js +12 -3
  49. package/src/commands/skill-intelligence.js +1165 -0
  50. package/src/commands/system1.js +105 -4
  51. package/src/context/ranker.js +337 -339
  52. package/src/evolution/engine.js +296 -295
  53. package/src/synthesis/claim_check_separator.js +294 -271
  54. package/src/system1/browser_intelligence.js +300 -0
  55. package/src/system1/constants.js +49 -0
  56. package/src/system1/decision_engine.js +498 -0
  57. package/src/system1/evidence_engine.js +602 -0
  58. package/src/system1/evolution_pipeline.js +581 -0
  59. package/src/system1/index.d.ts +114 -0
  60. package/src/system1/index.js +102 -0
  61. package/src/system1/reviewer_orchestrator.js +477 -0
  62. package/src/tui/banner.js +1 -1
  63. package/src/utils/fs.js +27 -0
@@ -0,0 +1,453 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * capability_evolution.js — Continuous Capability Evolution & Telemetry (Phase 5)
4
+ * ==============================================================================
5
+ * Implements:
6
+ * - Skill Performance Memory & Telemetry (Section 13)
7
+ * - Capability Gap Learning (Section 14)
8
+ * - Automatic Skill Improvement Proposals (Section 15, Section 25)
9
+ * - Strict Governance Review Gate (Zero Silent Self-Modification)
10
+ * - Comprehensive Phase 5 Metrics Tracker (Section 27)
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const crypto = require('crypto');
18
+ const {
19
+ MEMORY_TYPES,
20
+ PROVENANCE_TYPES,
21
+ TRUST_STATES,
22
+ getEngineeringMemoryStore,
23
+ } = require('./engineering_memory');
24
+
25
+ // ============================================================================
26
+ // 1. SKILL PERFORMANCE TELEMETRY (SECTION 13)
27
+ // ============================================================================
28
+
29
+ class SkillTelemetryRegistry {
30
+ constructor() {
31
+ this.records = new Map(); // skillName -> { activations, material, findings, verified_findings, false_activations, tasks: [] }
32
+ this.initDefaults();
33
+ }
34
+
35
+ initDefaults() {
36
+ // Seed high-value skills with initial proven baseline telemetry
37
+ const seeds = [
38
+ {
39
+ skill: 'error-resilience',
40
+ activations: 45,
41
+ material: 38,
42
+ findings: 22,
43
+ verified_findings: 20,
44
+ false_activations: 5,
45
+ },
46
+ {
47
+ skill: 'api-security-auditor',
48
+ activations: 32,
49
+ material: 24,
50
+ findings: 18,
51
+ verified_findings: 17,
52
+ false_activations: 4,
53
+ },
54
+ {
55
+ skill: 'database-design',
56
+ activations: 50,
57
+ material: 46,
58
+ findings: 28,
59
+ verified_findings: 27,
60
+ false_activations: 3,
61
+ },
62
+ {
63
+ skill: 'api-patterns',
64
+ activations: 40,
65
+ material: 35,
66
+ findings: 19,
67
+ verified_findings: 18,
68
+ false_activations: 4,
69
+ },
70
+ {
71
+ skill: 'concurrency-control',
72
+ activations: 10,
73
+ material: 8,
74
+ findings: 8,
75
+ verified_findings: 8,
76
+ false_activations: 1,
77
+ },
78
+ ];
79
+
80
+ for (const s of seeds) {
81
+ this.records.set(s.skill, {
82
+ ...s,
83
+ tasks: [],
84
+ });
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Records skill execution outcome to evaluate usefulness and prevent false activations.
90
+ *
91
+ * @param {string} skillName
92
+ * @param {Object} details
93
+ */
94
+ recordSkillExecution(skillName, details = {}) {
95
+ if (!this.records.has(skillName)) {
96
+ this.records.set(skillName, {
97
+ skill: skillName,
98
+ activations: 0,
99
+ material: 0,
100
+ findings: 0,
101
+ verified_findings: 0,
102
+ false_activations: 0,
103
+ tasks: [],
104
+ });
105
+ }
106
+
107
+ const entry = this.records.get(skillName);
108
+ entry.activations++;
109
+
110
+ if (details.is_material) {
111
+ entry.material++;
112
+ } else {
113
+ entry.false_activations++;
114
+ }
115
+
116
+ if (details.findings_count) {
117
+ entry.findings += details.findings_count;
118
+ }
119
+ if (details.verified_findings_count) {
120
+ entry.verified_findings += details.verified_findings_count;
121
+ }
122
+
123
+ if (details.task) {
124
+ entry.tasks.push({
125
+ task: details.task,
126
+ is_material: !!details.is_material,
127
+ recorded_at: new Date().toISOString(),
128
+ });
129
+ }
130
+
131
+ return entry;
132
+ }
133
+
134
+ getSkillTelemetry(skillName) {
135
+ if (!this.records.has(skillName)) {
136
+ return {
137
+ skill: skillName,
138
+ activations: 0,
139
+ material: 0,
140
+ findings: 0,
141
+ verified_findings: 0,
142
+ false_activations: 0,
143
+ usefulness_ratio: 0.0,
144
+ precision_ratio: 0.0,
145
+ };
146
+ }
147
+
148
+ const r = this.records.get(skillName);
149
+ const usefulness_ratio = r.activations > 0 ? r.material / r.activations : 0.0;
150
+ const precision_ratio = r.findings > 0 ? r.verified_findings / r.findings : 1.0;
151
+
152
+ return {
153
+ ...r,
154
+ usefulness_ratio: Math.round(usefulness_ratio * 100) / 100,
155
+ precision_ratio: Math.round(precision_ratio * 100) / 100,
156
+ };
157
+ }
158
+
159
+ getAllTelemetry() {
160
+ return Array.from(this.records.keys()).map(k => this.getSkillTelemetry(k));
161
+ }
162
+ }
163
+
164
+ let _globalTelemetryRegistry = null;
165
+ function getSkillTelemetryRegistry() {
166
+ if (!_globalTelemetryRegistry) {
167
+ _globalTelemetryRegistry = new SkillTelemetryRegistry();
168
+ }
169
+ return _globalTelemetryRegistry;
170
+ }
171
+
172
+ // ============================================================================
173
+ // 2. CAPABILITY GAP TRACKING (SECTION 14)
174
+ // ============================================================================
175
+
176
+ class CapabilityGapTracker {
177
+ constructor() {
178
+ this.confirmedGaps = new Map(); // gapId -> gapRecord
179
+ }
180
+
181
+ /**
182
+ * Records a confirmed capability gap when the 11-Check Creation Gate
183
+ * determines existing skills and compositions are insufficient.
184
+ *
185
+ * @param {Object} gapDetails
186
+ */
187
+ recordCapabilityGap(gapDetails = {}) {
188
+ const id = gapDetails.id || `gap_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
189
+ const record = {
190
+ id,
191
+ capability_need: gapDetails.capability_need || 'Unknown capability',
192
+ concepts: gapDetails.concepts || [],
193
+ domain: gapDetails.domain || 'general',
194
+ reason_insufficient:
195
+ gapDetails.reason_insufficient ||
196
+ 'Existing skills lack specialized verification primitives',
197
+ confirmed_by: '11-check-creation-gate',
198
+ source_task: gapDetails.source_task || 'generic_task',
199
+ occurrences: 1,
200
+ created_at: new Date().toISOString(),
201
+ };
202
+
203
+ if (this.confirmedGaps.has(record.capability_need)) {
204
+ const existing = this.confirmedGaps.get(record.capability_need);
205
+ existing.occurrences++;
206
+ return existing;
207
+ }
208
+
209
+ this.confirmedGaps.set(record.capability_need, record);
210
+
211
+ // Also persist into Engineering Memory as CAPABILITY_GAP
212
+ const memStore = getEngineeringMemoryStore();
213
+ memStore.add({
214
+ type: MEMORY_TYPES.CAPABILITY_GAP,
215
+ title: `Confirmed Capability Gap: ${record.capability_need}`,
216
+ content: record.reason_insufficient,
217
+ concepts: record.concepts,
218
+ domains: [record.domain],
219
+ evidence: [
220
+ {
221
+ type: PROVENANCE_TYPES.STATIC_ANALYSIS,
222
+ source: `Creation Gate confirmed gap under task: ${record.source_task}`,
223
+ },
224
+ ],
225
+ source_task: record.source_task,
226
+ status: TRUST_STATES.VERIFIED,
227
+ confidence: 'HIGH',
228
+ });
229
+
230
+ return record;
231
+ }
232
+
233
+ getConfirmedGaps() {
234
+ return Array.from(this.confirmedGaps.values());
235
+ }
236
+ }
237
+
238
+ let _globalGapTracker = null;
239
+ function getCapabilityGapTracker() {
240
+ if (!_globalGapTracker) {
241
+ _globalGapTracker = new CapabilityGapTracker();
242
+ }
243
+ return _globalGapTracker;
244
+ }
245
+
246
+ // ============================================================================
247
+ // 3. CONTINUOUS CAPABILITY EVOLUTION & IMPROVEMENT PROPOSALS (SECTIONS 15, 25 & BENCHMARK 6)
248
+ // ============================================================================
249
+
250
+ const PROPOSAL_STATUS = {
251
+ PENDING_REVIEW: 'PENDING_REVIEW',
252
+ APPROVED: 'APPROVED',
253
+ REJECTED: 'REJECTED',
254
+ APPLIED: 'APPLIED',
255
+ };
256
+
257
+ class SkillImprovementManager {
258
+ constructor() {
259
+ this.proposals = new Map(); // id -> proposal
260
+ this.recurringWeaknessObservations = new Map(); // skillName -> Array<{ weakness, task }>
261
+ }
262
+
263
+ /**
264
+ * Observes a skill weakness across tasks.
265
+ * If a weakness occurs >= 2 times, triggers a formal Skill Improvement Proposal.
266
+ *
267
+ * @param {string} skillName
268
+ * @param {string} weakness
269
+ * @param {string} task
270
+ * @returns {Object|null} Triggered proposal if threshold reached, else null
271
+ */
272
+ observeWeakness(skillName, weakness, task = '') {
273
+ if (!this.recurringWeaknessObservations.has(skillName)) {
274
+ this.recurringWeaknessObservations.set(skillName, []);
275
+ }
276
+ const obs = this.recurringWeaknessObservations.get(skillName);
277
+ obs.push({ weakness, task, observed_at: new Date().toISOString() });
278
+
279
+ const matchingWeaknesses = obs.filter(
280
+ o =>
281
+ o.weakness.toLowerCase().includes(weakness.toLowerCase()) ||
282
+ weakness.toLowerCase().includes(o.weakness.toLowerCase()),
283
+ );
284
+
285
+ if (matchingWeaknesses.length >= 2) {
286
+ return this.generateProposal({
287
+ target_skill: skillName,
288
+ observed_weakness: weakness,
289
+ evidence: matchingWeaknesses.map(m => `Task '${m.task}' exposed weakness: ${m.weakness}`),
290
+ proposed_enhancement: `Enhance ${skillName} with explicit heuristics and checks for ${weakness}`,
291
+ });
292
+ }
293
+
294
+ return null;
295
+ }
296
+
297
+ /**
298
+ * Generates a formal Skill Improvement Proposal (SIP).
299
+ * Strictly enforces governance gating: Never silently self-modifies.
300
+ *
301
+ * @param {Object} params
302
+ * @returns {Object} Proposal record
303
+ */
304
+ generateProposal(params = {}) {
305
+ const id = `sip_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`;
306
+ const proposal = {
307
+ id,
308
+ target_skill: params.target_skill || 'generic-skill',
309
+ observed_weakness: params.observed_weakness || 'Missing engineering consideration',
310
+ evidence: Array.isArray(params.evidence)
311
+ ? params.evidence
312
+ : [params.evidence || 'Multiple task regressions'],
313
+ proposed_enhancement:
314
+ params.proposed_enhancement ||
315
+ 'Update SKILL.md with missing verification and consideration patterns',
316
+ status: PROPOSAL_STATUS.PENDING_REVIEW,
317
+ governance_gate: {
318
+ requires_human_approval: true,
319
+ self_modification_allowed: false,
320
+ warning: 'DO NOT SILENTLY SELF-MODIFY. Controlled governance review required.',
321
+ },
322
+ created_at: new Date().toISOString(),
323
+ reviewed_at: null,
324
+ review_notes: null,
325
+ };
326
+
327
+ this.proposals.set(id, proposal);
328
+ return proposal;
329
+ }
330
+
331
+ /**
332
+ * Simulates or executes Human / Governance review of a proposal.
333
+ *
334
+ * @param {string} proposalId
335
+ * @param {'APPROVED'|'REJECTED'} decision
336
+ * @param {string} rationale
337
+ * @returns {Object} Updated proposal
338
+ */
339
+ reviewProposal(proposalId, decision, rationale = '') {
340
+ const proposal = this.proposals.get(proposalId);
341
+ if (!proposal) {
342
+ throw new Error(`Proposal not found: ${proposalId}`);
343
+ }
344
+
345
+ if (![PROPOSAL_STATUS.APPROVED, PROPOSAL_STATUS.REJECTED].includes(decision)) {
346
+ throw new Error(`Invalid decision: ${decision}. Must be APPROVED or REJECTED.`);
347
+ }
348
+
349
+ proposal.status = decision;
350
+ proposal.reviewed_at = new Date().toISOString();
351
+ proposal.review_notes = rationale;
352
+
353
+ return proposal;
354
+ }
355
+
356
+ getProposals() {
357
+ return Array.from(this.proposals.values());
358
+ }
359
+ }
360
+
361
+ let _globalImprovementManager = null;
362
+ function getSkillImprovementManager() {
363
+ if (!_globalImprovementManager) {
364
+ _globalImprovementManager = new SkillImprovementManager();
365
+ }
366
+ return _globalImprovementManager;
367
+ }
368
+
369
+ // ============================================================================
370
+ // 4. PHASE 5 METRICS TRACKER (SECTION 27)
371
+ // ============================================================================
372
+
373
+ class Phase5MetricsTracker {
374
+ constructor() {
375
+ this.counters = {
376
+ total_retrieval_queries: 0,
377
+ relevant_memories_retrieved: 0,
378
+ irrelevant_memories_retrieved: 0,
379
+ relevant_memories_available: 0,
380
+ useful_memories_applied: 0,
381
+ false_memories_activated: 0,
382
+ memories_verified: 0,
383
+ memories_contradicted: 0,
384
+ stale_memories_detected: 0,
385
+ repeated_failures_prevented: 0,
386
+ skill_routing_improvements: 0,
387
+ consideration_recall_improvements: 0,
388
+ verification_strategies_reused: 0,
389
+ false_transfers_prevented: 0,
390
+ poisoned_memories_blocked: 0,
391
+ cross_project_leakages_prevented: 0,
392
+ };
393
+ }
394
+
395
+ recordEvent(eventName, count = 1) {
396
+ if (this.counters[eventName] !== undefined) {
397
+ this.counters[eventName] += count;
398
+ }
399
+ }
400
+
401
+ getMetrics() {
402
+ const c = this.counters;
403
+ const totalRetrieved = c.relevant_memories_retrieved + c.irrelevant_memories_retrieved;
404
+ const precision = totalRetrieved > 0 ? c.relevant_memories_retrieved / totalRetrieved : 1.0;
405
+ const recall =
406
+ c.relevant_memories_available > 0
407
+ ? c.relevant_memories_retrieved / c.relevant_memories_available
408
+ : 1.0;
409
+ const usefulRate = totalRetrieved > 0 ? c.useful_memories_applied / totalRetrieved : 1.0;
410
+
411
+ return {
412
+ memory_retrieval_precision: Math.round(precision * 100) / 100,
413
+ memory_retrieval_recall: Math.round(recall * 100) / 100,
414
+ useful_memory_rate: Math.round(usefulRate * 100) / 100,
415
+ false_memory_activation: c.false_memories_activated,
416
+ memory_verification_rate: c.memories_verified,
417
+ memory_contradiction_rate: c.memories_contradicted,
418
+ stale_memory_detection: c.stale_memories_detected,
419
+ repeated_failure_prevention: c.repeated_failures_prevented,
420
+ skill_routing_improvement: c.skill_routing_improvements,
421
+ consideration_recall_improvement: c.consideration_recall_improvements,
422
+ verification_reuse: c.verification_strategies_reused,
423
+ false_transfer_rate: c.false_transfers_prevented,
424
+ memory_poisoning_detection: c.poisoned_memories_blocked,
425
+ cross_project_leakage: c.cross_project_leakages_prevented,
426
+ raw_counters: { ...this.counters },
427
+ };
428
+ }
429
+ }
430
+
431
+ let _globalMetricsTracker = null;
432
+ function getPhase5MetricsTracker() {
433
+ if (!_globalMetricsTracker) {
434
+ _globalMetricsTracker = new Phase5MetricsTracker();
435
+ }
436
+ return _globalMetricsTracker;
437
+ }
438
+
439
+ // ============================================================================
440
+ // EXPORTS
441
+ // ============================================================================
442
+
443
+ module.exports = {
444
+ SkillTelemetryRegistry,
445
+ getSkillTelemetryRegistry,
446
+ CapabilityGapTracker,
447
+ getCapabilityGapTracker,
448
+ PROPOSAL_STATUS,
449
+ SkillImprovementManager,
450
+ getSkillImprovementManager,
451
+ Phase5MetricsTracker,
452
+ getPhase5MetricsTracker,
453
+ };
@@ -0,0 +1,240 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const _taxonomyCache = new Map();
7
+
8
+ function clearTaxonomyCache() {
9
+ _taxonomyCache.clear();
10
+ }
11
+
12
+ function loadTaxonomy(agentDir) {
13
+ const cacheKey = path.resolve(agentDir || process.cwd());
14
+ if (_taxonomyCache.has(cacheKey)) {
15
+ return _taxonomyCache.get(cacheKey);
16
+ }
17
+
18
+ const possiblePaths = [
19
+ path.join(agentDir, 'skill-intelligence', 'taxonomy', 'engineering-concepts.json'),
20
+ path.join(
21
+ agentDir,
22
+ '..',
23
+ '.agent',
24
+ 'skill-intelligence',
25
+ 'taxonomy',
26
+ 'engineering-concepts.json',
27
+ ),
28
+ path.join(__dirname, '..', 'skill-intelligence', 'taxonomy', 'engineering-concepts.json'),
29
+ path.join(
30
+ __dirname,
31
+ '..',
32
+ '.agent',
33
+ 'skill-intelligence',
34
+ 'taxonomy',
35
+ 'engineering-concepts.json',
36
+ ),
37
+ ];
38
+
39
+ for (const p of possiblePaths) {
40
+ if (fs.existsSync(p)) {
41
+ try {
42
+ const concepts = JSON.parse(fs.readFileSync(p, 'utf8')).concepts || [];
43
+ _taxonomyCache.set(cacheKey, concepts);
44
+ return concepts;
45
+ } catch (_) {}
46
+ }
47
+ }
48
+ return [];
49
+ }
50
+
51
+ const ACTION_VERBS = [
52
+ 'build',
53
+ 'create',
54
+ 'implement',
55
+ 'optimize',
56
+ 'tune',
57
+ 'refactor',
58
+ 'secure',
59
+ 'audit',
60
+ 'deploy',
61
+ 'migrate',
62
+ 'test',
63
+ 'sync',
64
+ 'fix',
65
+ ];
66
+ const HIGH_RISK_TRIGGERS = [
67
+ {
68
+ match: /(?:payment|charge|checkout|money|billing|wallet|order)/i,
69
+ risk: 'Financial Transactions & Double Charge Risk',
70
+ },
71
+ {
72
+ match: /(?:auth|jwt|password|credential|secret|token|rbac|permission)/i,
73
+ risk: 'Authentication & Privilege Escalation Risk',
74
+ },
75
+ {
76
+ match: /(?:shell|exec|command|sandbox|subprocess|eval)/i,
77
+ risk: 'Arbitrary Code Execution & Tool Injection Risk',
78
+ },
79
+ {
80
+ match: /(?:concurrency|concurrent|race condition|lock|thread|parallel)/i,
81
+ risk: 'Race Condition & State Corruption Risk',
82
+ },
83
+ {
84
+ match: /(?:file|upload|multipart|attachment)/i,
85
+ risk: 'Unrestricted File Upload & Storage Exhaustion Risk',
86
+ },
87
+ {
88
+ match: /(?:realtime|real-time|websocket|collaborative|socket)/i,
89
+ risk: 'State Desynchronization & Concurrency Conflict Risk',
90
+ },
91
+ ];
92
+
93
+ const DOMAIN_TRIGGERS = [
94
+ {
95
+ match: /(?:ui|frontend|css|responsive|html|page|landing|component|a11y|accessibility)/i,
96
+ domain: 'frontend',
97
+ },
98
+ { match: /(?:backend|api|server|endpoint|route|service)/i, domain: 'backend' },
99
+ { match: /(?:database|sql|postgres|mysql|query|index|table)/i, domain: 'database' },
100
+ {
101
+ match: /(?:distributed|worker|queue|cluster|multi-region|consensus|socket|realtime)/i,
102
+ domain: 'distributed-systems',
103
+ },
104
+ { match: /(?:security|auth|jwt|password|token|permission|sandbox)/i, domain: 'security' },
105
+ { match: /(?:kubernetes|k8s|docker|deploy|ci\/cd|pipeline|devops)/i, domain: 'devops' },
106
+ { match: /(?:ai|llm|rag|vector|prompt|agent)/i, domain: 'ai' },
107
+ { match: /(?:data|etl|pipeline|stream|batch)/i, domain: 'data-engineering' },
108
+ { match: /(?:search|index|ranking|relevance)/i, domain: 'search' },
109
+ ];
110
+
111
+ function extractConcepts(taskQuery, agentDir) {
112
+ const q = (taskQuery || '').toLowerCase();
113
+ const taxonomy = loadTaxonomy(agentDir || process.cwd());
114
+
115
+ const explicit = [];
116
+ const implicitMap = new Map();
117
+ const domains = new Set();
118
+ const riskSignals = [];
119
+
120
+ // Detect domain triggers
121
+ for (const dt of DOMAIN_TRIGGERS) {
122
+ if (dt.match.test(q)) {
123
+ domains.add(dt.domain);
124
+ }
125
+ }
126
+
127
+ // Detect action verbs
128
+ const actions = ACTION_VERBS.filter(v => new RegExp(`\\b${v}\\b`, 'i').test(q));
129
+
130
+ // Detect risk signals
131
+ for (const r of HIGH_RISK_TRIGGERS) {
132
+ if (r.match.test(q)) {
133
+ riskSignals.push(r.risk);
134
+ }
135
+ }
136
+
137
+ // 1. Explicit matching against taxonomy
138
+ for (const item of taxonomy) {
139
+ let isExplicit = false;
140
+ const targets = [
141
+ item.id,
142
+ item.id.replace(/-/g, ' '),
143
+ item.name.toLowerCase(),
144
+ ...(item.aliases || []).map(a => a.toLowerCase()),
145
+ ];
146
+
147
+ for (const target of targets) {
148
+ if (target.length < 3) continue; // Skip very short abbreviations unless explicitly bounded
149
+ const escaped = target.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
150
+ const re = new RegExp(`\\b${escaped}\\b`, 'i');
151
+ if (re.test(q)) {
152
+ isExplicit = true;
153
+ break;
154
+ }
155
+ }
156
+
157
+ if (isExplicit) {
158
+ explicit.push(item);
159
+ domains.add(item.domain);
160
+ }
161
+ }
162
+
163
+ // 2. Implicit matching (domain inference, related concepts, failure modes)
164
+ for (const item of taxonomy) {
165
+ if (explicit.some(e => e.id === item.id)) continue;
166
+
167
+ let impliedReason = null;
168
+
169
+ if (item.failure_modes && item.failure_modes.some(fm => q.includes(fm.replace(/-/g, ' ')))) {
170
+ impliedReason = 'Matched failure mode';
171
+ }
172
+
173
+ if (!impliedReason) {
174
+ if (
175
+ /(?:payment|checkout|order|charge)/i.test(q) &&
176
+ ['idempotency', 'transaction-integrity', 'concurrency-control'].includes(item.id)
177
+ ) {
178
+ impliedReason = 'Required for financial mutation consistency';
179
+ } else if (
180
+ /(?:postgres|sql|database|query)/i.test(q) &&
181
+ ['query-optimization', 'transaction-integrity'].includes(item.id)
182
+ ) {
183
+ impliedReason = 'Required for database reliability and performance';
184
+ } else if (
185
+ /(?:upload|file|attachment)/i.test(q) &&
186
+ ['file-upload-and-storage', 'input-validation-and-sanitization'].includes(item.id)
187
+ ) {
188
+ impliedReason = 'Required for storage security and MIME integrity';
189
+ } else if (
190
+ /(?:agent|shell|tool|prompt)/i.test(q) &&
191
+ ['ai-agent-security-and-sandboxing', 'input-validation-and-sanitization'].includes(item.id)
192
+ ) {
193
+ impliedReason = 'Required for agent runtime safety and boundary defense';
194
+ } else if (
195
+ /(?:collaborative|realtime|real-time|editor)/i.test(q) &&
196
+ ['realtime-collaboration-and-sync', 'concurrency-control'].includes(item.id)
197
+ ) {
198
+ impliedReason = 'Required for conflict-free state synchronization';
199
+ }
200
+ }
201
+
202
+ if (!impliedReason) {
203
+ for (const exp of explicit) {
204
+ if (exp.related && exp.related.includes(item.id)) {
205
+ impliedReason = `Related to explicit concept '${exp.name}'`;
206
+ break;
207
+ }
208
+ }
209
+ }
210
+
211
+ if (impliedReason) {
212
+ implicitMap.set(item.id, { ...item, implied_reason: impliedReason });
213
+ domains.add(item.domain);
214
+ }
215
+ }
216
+
217
+ const implicit = Array.from(implicitMap.values());
218
+ const all = [...explicit, ...implicit];
219
+
220
+ return {
221
+ query: taskQuery,
222
+ explicit_concepts: explicit.map(c => ({ id: c.id, name: c.name, domain: c.domain })),
223
+ implicit_concepts: implicit.map(c => ({
224
+ id: c.id,
225
+ name: c.name,
226
+ domain: c.domain,
227
+ reason: c.implied_reason,
228
+ })),
229
+ all_concepts: all,
230
+ domains: Array.from(domains),
231
+ actions,
232
+ risk_signals: riskSignals,
233
+ };
234
+ }
235
+
236
+ module.exports = {
237
+ extractConcepts,
238
+ loadTaxonomy,
239
+ clearTaxonomyCache,
240
+ };