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,498 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * decision_engine.js — System-1 Capability 2: Cross-Capability Decision Engine
5
+ * ============================================================================
6
+ * Unified System-1 decision layer that combines:
7
+ * - Impact (Laya ONNX + change volume heuristic)
8
+ * - Risk (diff patterns, sensitive file types, credential leaks)
9
+ * - Evidence Intelligence (relevance, coverage, confidence L1-L4)
10
+ * - Browser / Interaction Intelligence (UI risk, route impact, CDP availability)
11
+ * - Adaptive Reviewer Orchestration (minimal covering reviewer set)
12
+ *
13
+ * Core Directives:
14
+ * 1. Monotonic Safety: Uncertainty maintains or increases scrutiny; never silently reduces scrutiny.
15
+ * 2. Precedence: High-risk signals can never be downgraded by low-confidence capabilities.
16
+ * 3. Explainability: Every decision contains an explicit audit trail of why the tier was chosen,
17
+ * which signals fired, which capabilities were consulted or unavailable, and whether fallback was used.
18
+ */
19
+
20
+ const crypto = require('crypto');
21
+ const {
22
+ HIGH_RISK_PATTERNS,
23
+ HIGH_RISK_EXTENSIONS,
24
+ TIER_NAMES,
25
+ ROUTING_NAMES,
26
+ } = require('./constants');
27
+ const { collectAndRankEvidence } = require('./evidence_engine');
28
+ const { evaluateBrowserRequirement } = require('./browser_intelligence');
29
+ const { orchestrateReviewers } = require('./reviewer_orchestrator');
30
+
31
+ function resolveMonotonicImpactTier(options = {}) {
32
+ const opts = options && typeof options === 'object' ? options : {};
33
+ const rawFiles = opts.files;
34
+ const files = (
35
+ Array.isArray(rawFiles) ? rawFiles : typeof rawFiles === 'string' ? rawFiles.split(',') : []
36
+ )
37
+ .map(f =>
38
+ typeof f === 'string'
39
+ ? f
40
+ .replace(/[\u200B-\u200D\uFEFF]/g, '')
41
+ .trim()
42
+ .replace(/\\/g, '/')
43
+ : '',
44
+ )
45
+ .filter(Boolean);
46
+ const rawLines =
47
+ typeof opts.lines === 'number' && !isNaN(opts.lines)
48
+ ? opts.lines
49
+ : parseInt(opts.lines, 10) || 0;
50
+ const lines = Math.max(0, rawLines);
51
+ const task = typeof opts.task === 'string' ? opts.task.replace(/[\u200B-\u200D\uFEFF]/g, '') : '';
52
+ const diff = typeof opts.diff === 'string' ? opts.diff.replace(/[\u200B-\u200D\uFEFF]/g, '') : '';
53
+ const layaTier = opts.layaTier;
54
+
55
+ const fileCount = files.length;
56
+
57
+ // 1. Base tier from change volume
58
+ const isFastPass =
59
+ fileCount <= 2 &&
60
+ lines <= 10 &&
61
+ files.length > 0 &&
62
+ files.every(f => /\.(css|scss|less|md|txt|svg|png|jpg)$/i.test(f));
63
+
64
+ let baseTier = 0;
65
+ if (isFastPass || (fileCount === 0 && lines <= 5)) baseTier = 0;
66
+ else if (fileCount <= 1 && lines <= 50) baseTier = 1;
67
+ else if (fileCount <= 5 && lines <= 200) baseTier = 2;
68
+ else baseTier = 3;
69
+
70
+ // 2. Concrete risk evidence analysis
71
+ const isPureDocFiles =
72
+ fileCount > 0 &&
73
+ files.every(f => /\.(md|txt|markdown|rst|adoc)$/i.test(f) || f.includes('docs/'));
74
+
75
+ // Concrete secret or code patterns that make even documentation dangerous
76
+ const secretOrExecPatterns =
77
+ /(?:-----BEGIN [A-Z ]+KEY-----|eyJ[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+|AKIA[0-9A-Z]{16}|(?:aws[_-]?)?(?:api[_-]?key|secret(?:[_-]?key)?|password|bearer|auth[_-]?token|access[_-]?key(?:[_-]?id)?)\s*[:=]\s*['"]?[^'"\s\n]{6,}['"]?)/i;
78
+
79
+ const diffHasCode =
80
+ /^\+[ \t]*(?:const|let|var|function|def|import|require|class|export|db\.|SELECT|UPDATE|DELETE|INSERT|jwt\.|auth\.)/im.test(
81
+ diff,
82
+ );
83
+ const diffMatchesHighRiskCode = diffHasCode && HIGH_RISK_PATTERNS.test(diff);
84
+
85
+ const diffHasHighRisk =
86
+ HIGH_RISK_EXTENSIONS.test(diff) ||
87
+ diffMatchesHighRiskCode ||
88
+ (!isPureDocFiles && HIGH_RISK_PATTERNS.test(diff)) ||
89
+ secretOrExecPatterns.test(diff);
90
+
91
+ const fileHasHighRisk = files.some(
92
+ f =>
93
+ HIGH_RISK_EXTENSIONS.test(f) ||
94
+ (!isPureDocFiles && HIGH_RISK_PATTERNS.test(f)) ||
95
+ f.includes('docker') ||
96
+ f.includes('.github/'),
97
+ );
98
+
99
+ let riskEvidenceTier = 0;
100
+ if (diffHasHighRisk || fileHasHighRisk) {
101
+ riskEvidenceTier = 3;
102
+ } else if (!isPureDocFiles && HIGH_RISK_PATTERNS.test(task + ' ' + files.join(' '))) {
103
+ riskEvidenceTier = 3;
104
+ }
105
+
106
+ // 3. Negative controls (Documentation changes)
107
+ // A doc change remains low risk (Tier 0) UNLESS concrete high-risk implementation evidence exists in files or diff
108
+ if (isPureDocFiles && !diffHasHighRisk && !fileHasHighRisk) {
109
+ return 0;
110
+ }
111
+
112
+ // 4. Ambiguity tier: short vague tasks (<= 2 words) touching non-doc code files
113
+ let ambiguityTier = 0;
114
+ const wordCount = task.trim().length > 0 ? task.trim().split(/\s+/).length : 0;
115
+ if (wordCount > 0 && wordCount <= 2 && fileCount > 0 && !isPureDocFiles) {
116
+ ambiguityTier = 2;
117
+ }
118
+
119
+ // 5. Monotonic aggregation: finalTier = max(baseTier, layaTier, riskEvidenceTier, ambiguityTier)
120
+ const candidateTiers = [baseTier, riskEvidenceTier, ambiguityTier];
121
+ if (typeof layaTier === 'number' && !isNaN(layaTier) && layaTier >= 0 && layaTier <= 3) {
122
+ candidateTiers.push(layaTier);
123
+ }
124
+
125
+ return Math.max(...candidateTiers);
126
+ }
127
+
128
+ /**
129
+ * Evaluate cross-capability System-1 decision
130
+ * @param {Object} options
131
+ * @param {string} [options.task]
132
+ * @param {string} [options.diff]
133
+ * @param {string[]|string} [options.files]
134
+ * @param {number} [options.lines]
135
+ * @param {Object} [options.evidence] - Optional pre-computed evidence
136
+ * @param {Object} [options.browserSignal] - Optional pre-computed browser signal
137
+ * @param {number|null} [options.layaTier] - Optional Laya inference output
138
+ * @param {string} [options.repoRoot] - Optional repository root
139
+ * @param {Array} [options.memory] - Optional memory items
140
+ * @param {Array} [options.previousFindings] - Optional previous findings
141
+ * @param {Object} [options.environment] - Optional environment overrides (e.g. browserFound)
142
+ * @returns {Object} Comprehensive Decision Payload
143
+ */
144
+ function evaluateDecision(options = {}) {
145
+ const rawTask = typeof options.task === 'string' ? options.task : '';
146
+ const task = rawTask.replace(/[\u200B-\u200D\uFEFF]/g, '');
147
+ const rawDiff = typeof options.diff === 'string' ? options.diff : '';
148
+ const diff = rawDiff.replace(/[\u200B-\u200D\uFEFF]/g, '');
149
+ const rawFiles = options.files;
150
+ const files = (
151
+ Array.isArray(rawFiles) ? rawFiles : typeof rawFiles === 'string' ? rawFiles.split(',') : []
152
+ )
153
+ .map(f =>
154
+ typeof f === 'string'
155
+ ? f
156
+ .replace(/[\u200B-\u200D\uFEFF]/g, '')
157
+ .trim()
158
+ .replace(/\\/g, '/')
159
+ : '',
160
+ )
161
+ .filter(Boolean);
162
+ const rawLines =
163
+ typeof options.lines === 'number' && !isNaN(options.lines)
164
+ ? options.lines
165
+ : parseInt(options.lines, 10) || (diff ? diff.split('\n').length : 0);
166
+ const lines = Math.max(0, rawLines);
167
+ const repoRoot = options.repoRoot || process.cwd();
168
+ const layaTier = options.layaTier ?? null;
169
+
170
+ const capabilitiesConsulted = [];
171
+ const capabilitiesUnavailable = [];
172
+ const firedRiskSignals = [];
173
+ const monotonicSafeguards = [];
174
+ let fallbackUsed = false;
175
+
176
+ // 1. Evidence Intelligence Consultation
177
+ let evidenceResult = options.evidence;
178
+ if (!evidenceResult) {
179
+ try {
180
+ evidenceResult = collectAndRankEvidence({
181
+ task,
182
+ diff,
183
+ files,
184
+ repoRoot,
185
+ memory: options.memory,
186
+ previousFindings: options.previousFindings,
187
+ });
188
+ capabilitiesConsulted.push('evidence_engine');
189
+ } catch (_) {
190
+ capabilitiesUnavailable.push('evidence_engine');
191
+ evidenceResult = {
192
+ evidence: [],
193
+ summary: { confidence: 'L4', critical_evidence_count: 0, has_security_boundary: false },
194
+ };
195
+ }
196
+ } else {
197
+ capabilitiesConsulted.push('evidence_engine (provided)');
198
+ }
199
+
200
+ // 2. Browser Intelligence Consultation
201
+ let browserSignal = options.browserSignal;
202
+ if (!browserSignal) {
203
+ try {
204
+ browserSignal = evaluateBrowserRequirement({
205
+ files,
206
+ diff,
207
+ task,
208
+ environment: options.environment,
209
+ });
210
+ capabilitiesConsulted.push('browser_intelligence');
211
+ if (browserSignal.browser_available === 'UNAVAILABLE') {
212
+ capabilitiesUnavailable.push('browser_cdp');
213
+ }
214
+ } catch (_) {
215
+ capabilitiesUnavailable.push('browser_intelligence');
216
+ browserSignal = {
217
+ requires_browser_verification: false,
218
+ validation_level: 'NONE',
219
+ browser_available: 'UNAVAILABLE',
220
+ escalate: false,
221
+ };
222
+ }
223
+ } else {
224
+ capabilitiesConsulted.push('browser_intelligence (provided)');
225
+ }
226
+
227
+ // 3. Impact & Risk Analysis
228
+ if (layaTier !== null && typeof layaTier === 'number') {
229
+ capabilitiesConsulted.push('laya_onnx');
230
+ } else {
231
+ capabilitiesConsulted.push('deterministic_heuristic');
232
+ capabilitiesUnavailable.push('laya_onnx');
233
+ fallbackUsed = true;
234
+ }
235
+
236
+ // Scan concrete risk signals
237
+ const combinedContext = `${task}\n${diff}\n${files.join('\n')}`;
238
+ if (HIGH_RISK_PATTERNS.test(combinedContext)) {
239
+ firedRiskSignals.push('HIGH_RISK_PATTERNS (auth/crypto/secrets/tokens/database)');
240
+ }
241
+ if (files.some(f => HIGH_RISK_EXTENSIONS.test(f)) || HIGH_RISK_EXTENSIONS.test(diff)) {
242
+ firedRiskSignals.push('HIGH_RISK_EXTENSIONS (.sql, .prisma, .tf)');
243
+ }
244
+ if (
245
+ /(?:-----BEGIN [A-Z ]+KEY-----|eyJ[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+|(?:api[_-]?key|secret|password)\s*[:=])/i.test(
246
+ diff,
247
+ )
248
+ ) {
249
+ firedRiskSignals.push('SECRET_OR_KEY_PATTERN (possible exposed credentials)');
250
+ }
251
+ if (evidenceResult.summary?.has_security_boundary) {
252
+ firedRiskSignals.push(
253
+ 'SECURITY_BOUNDARY_EVIDENCE (direct touch of security policy / boundary)',
254
+ );
255
+ }
256
+
257
+ // Calculate baseline monotonic tier with fail-closed production safeguard
258
+ let calculatedTier = 3;
259
+ try {
260
+ const resolver =
261
+ typeof options.tierResolver === 'function'
262
+ ? options.tierResolver
263
+ : resolveMonotonicImpactTier;
264
+ calculatedTier = resolver({
265
+ files,
266
+ lines,
267
+ task,
268
+ diff,
269
+ layaTier,
270
+ });
271
+ } catch (err) {
272
+ calculatedTier = 3;
273
+ monotonicSafeguards.push(
274
+ `Tier calculation fallback to Tier 3 due to exception: ${err.message}`,
275
+ );
276
+ }
277
+
278
+ if (
279
+ typeof calculatedTier !== 'number' ||
280
+ isNaN(calculatedTier) ||
281
+ calculatedTier < 0 ||
282
+ calculatedTier > 3
283
+ ) {
284
+ calculatedTier = 3;
285
+ monotonicSafeguards.push(
286
+ `Tier calculation fallback to Tier 3 due to invalid output from resolver`,
287
+ );
288
+ }
289
+
290
+ let finalTier = calculatedTier;
291
+ let escalated = false;
292
+ let escalationReason = null;
293
+
294
+ // 4. Cross-Capability Monotonic Rules & Conflict Resolution
295
+ // Base tier strictly from change volume (ignoring risk for safeguard comparison)
296
+ const isFastPassVol =
297
+ files.length <= 2 &&
298
+ lines <= 10 &&
299
+ files.every(f => /\.(css|scss|less|md|txt|svg|png|jpg)$/i.test(f));
300
+ const baseVolumeTier =
301
+ isFastPassVol || (files.length === 0 && lines <= 5)
302
+ ? 0
303
+ : files.length <= 1 && lines <= 50
304
+ ? 1
305
+ : files.length <= 5 && lines <= 200
306
+ ? 2
307
+ : 3;
308
+
309
+ // Rule A: High Risk + Low Base Tier -> Enforce Tier 3
310
+ if (firedRiskSignals.length > 0) {
311
+ const isPureDoc = files.length > 0 && files.every(f => /\.(md|txt)$/i.test(f));
312
+ const hasDiffRisk = firedRiskSignals.some(
313
+ s =>
314
+ s.includes('SECRET') ||
315
+ s.includes('HIGH_RISK_EXTENSIONS') ||
316
+ s.includes('SECURITY_BOUNDARY') ||
317
+ diff.includes('jwt') ||
318
+ diff.includes('auth'),
319
+ );
320
+ if (!isPureDoc || hasDiffRisk) {
321
+ if (finalTier < 3) {
322
+ finalTier = 3;
323
+ }
324
+ if (baseVolumeTier < 3) {
325
+ monotonicSafeguards.push(
326
+ 'Enforced Tier 3: Concrete risk signals detected despite low change volume',
327
+ );
328
+ }
329
+ }
330
+ }
331
+
332
+ // Rule B: Low Evidence Confidence (L4 / unavailable) forbids Fast-Pass (Tier 0)
333
+ const evidenceConfidence = evidenceResult.summary?.confidence || 'L4';
334
+ if ((evidenceConfidence === 'L4' || evidenceResult.evidence.length === 0) && finalTier === 0) {
335
+ const isTrivialDoc = files.length > 0 && files.every(f => /\.(md|txt)$/i.test(f)) && lines <= 5;
336
+ if (!isTrivialDoc) {
337
+ finalTier = 1; // Cannot fast-pass when evidence is unavailable/unverified
338
+ monotonicSafeguards.push(
339
+ 'Elevated from Tier 0 to Tier 1: Low evidence confidence forbids Fast-Pass assumption',
340
+ );
341
+ }
342
+ }
343
+
344
+ // Rule C: Laya Downgrade Prevention
345
+ if (layaTier !== null && layaTier < finalTier) {
346
+ monotonicSafeguards.push(
347
+ `Prevented Laya downgrade: Laya suggested Tier ${layaTier}, but deterministic evidence mandated Tier ${finalTier}`,
348
+ );
349
+ }
350
+
351
+ // Rule D: Browser Intelligence Escalation
352
+ // If browser validation is required (SMOKE/FUNCTIONAL/HIGH_RISK) but browser is UNAVAILABLE, escalate
353
+ if (browserSignal.requires_browser_verification && browserSignal.escalate) {
354
+ escalated = true;
355
+ escalationReason =
356
+ browserSignal.safety_notice ||
357
+ 'Browser verification is required but browser runtime is unavailable.';
358
+ monotonicSafeguards.push(
359
+ 'Escalation triggered: Missing browser execution capability for UI change',
360
+ );
361
+ }
362
+
363
+ // If browser risk is HIGH_RISK, elevate tier to at least Tier 2
364
+ if (browserSignal.validation_level === 'HIGH_RISK' && finalTier < 2) {
365
+ finalTier = 2;
366
+ monotonicSafeguards.push(
367
+ 'Elevated to Tier 2: High-risk browser verification (payment/auth UI)',
368
+ );
369
+ }
370
+
371
+ // If Tier 2 and Browser risk is HIGH_RISK + browser unavailable -> Escalate to human gate
372
+ if (
373
+ finalTier >= 2 &&
374
+ browserSignal.validation_level === 'HIGH_RISK' &&
375
+ browserSignal.browser_available === 'UNAVAILABLE'
376
+ ) {
377
+ escalated = true;
378
+ escalationReason =
379
+ 'High-risk payment/auth browser verification required but browser environment is unavailable.';
380
+ }
381
+
382
+ // 5. Adaptive Reviewer Orchestration
383
+ let reviewerResult;
384
+ try {
385
+ reviewerResult = orchestrateReviewers({
386
+ tier: finalTier,
387
+ files,
388
+ diff,
389
+ task,
390
+ evidence: evidenceResult.evidence,
391
+ previousFindings: options.previousFindings,
392
+ });
393
+ capabilitiesConsulted.push('reviewer_orchestrator');
394
+ } catch (_) {
395
+ capabilitiesUnavailable.push('reviewer_orchestrator');
396
+ reviewerResult = {
397
+ selected: [],
398
+ rejected: [],
399
+ total_selected: 0,
400
+ coverage: { all_risks_covered: false },
401
+ };
402
+ }
403
+
404
+ // 6. Routing Decision & Socratic Gate
405
+ const routing = escalated ? 'ESCALATE' : ROUTING_NAMES[finalTier] || 'TARGETED_REVIEW';
406
+
407
+ const socraticGate = escalated
408
+ ? 'required'
409
+ : finalTier >= 3
410
+ ? 'required'
411
+ : finalTier >= 2
412
+ ? 'conditional'
413
+ : 'bypass';
414
+
415
+ // 7. Explanations & Provenance
416
+ const influencingEvidence = evidenceResult.evidence
417
+ .filter(e => e.score >= 0.8 || e.is_mandatory)
418
+ .map(e => `${e.id} (score: ${e.score})`);
419
+
420
+ let whyTierSelected = `Classified as ${TIER_NAMES[finalTier]} (Tier ${finalTier}). `;
421
+ if (firedRiskSignals.length > 0) {
422
+ whyTierSelected += `Risk signals fired: [${firedRiskSignals.join(', ')}]. `;
423
+ } else if (finalTier === 0) {
424
+ whyTierSelected +=
425
+ 'Change is low-volume styling/documentation with zero risk signals (Fast-Pass eligible). ';
426
+ } else if (finalTier === 1) {
427
+ whyTierSelected +=
428
+ 'Single-file or bounded component edit with isolated impact (Express Pass). ';
429
+ } else if (finalTier === 2) {
430
+ whyTierSelected += 'Multi-file feature edit requiring targeted domain verification. ';
431
+ } else {
432
+ whyTierSelected +=
433
+ 'High-impact architectural or security change requiring full gauntlet review. ';
434
+ }
435
+
436
+ if (escalated) {
437
+ whyTierSelected += `ESCALATED: ${escalationReason}`;
438
+ }
439
+
440
+ // Overall Decision Confidence
441
+ let decisionConfidence = 'L1';
442
+ if (fallbackUsed && evidenceConfidence !== 'L1') {
443
+ decisionConfidence = 'L2';
444
+ } else if (evidenceConfidence === 'L3' || evidenceConfidence === 'L4') {
445
+ decisionConfidence = evidenceConfidence;
446
+ }
447
+
448
+ return {
449
+ decision_id: `DEC-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`,
450
+ timestamp: new Date().toISOString(),
451
+ tier: finalTier,
452
+ tier_name: TIER_NAMES[finalTier],
453
+ routing,
454
+ socratic_gate: socraticGate,
455
+ escalated,
456
+ escalation_reason: escalationReason,
457
+ confidence: decisionConfidence,
458
+ explanation: {
459
+ why_tier_selected: whyTierSelected.trim(),
460
+ influencing_evidence: influencingEvidence,
461
+ fired_risk_signals: firedRiskSignals,
462
+ capabilities_consulted: capabilitiesConsulted,
463
+ capabilities_unavailable: capabilitiesUnavailable,
464
+ fallback_used: fallbackUsed,
465
+ monotonic_safeguards_applied: monotonicSafeguards,
466
+ },
467
+ signals: {
468
+ change_lines: lines,
469
+ change_files_count: files.length,
470
+ impact_tier_raw: calculatedTier,
471
+ laya_tier: layaTier,
472
+ evidence_confidence: evidenceConfidence,
473
+ browser_validation_level: browserSignal.validation_level,
474
+ browser_available: browserSignal.browser_available,
475
+ },
476
+ evidence_summary: {
477
+ total_evaluated: evidenceResult.summary?.total_items_evaluated || 0,
478
+ total_selected: evidenceResult.summary?.total_items_selected || 0,
479
+ critical_count: evidenceResult.summary?.critical_evidence_count || 0,
480
+ confidence: evidenceConfidence,
481
+ },
482
+ reviewers: {
483
+ selected: reviewerResult.selected,
484
+ rejected: reviewerResult.rejected,
485
+ total_selected: reviewerResult.total_selected,
486
+ all_risks_covered: reviewerResult.coverage?.all_risks_covered ?? true,
487
+ },
488
+ };
489
+ }
490
+
491
+ module.exports = {
492
+ evaluateDecision,
493
+ resolveMonotonicImpactTier,
494
+ HIGH_RISK_PATTERNS,
495
+ HIGH_RISK_EXTENSIONS,
496
+ TIER_NAMES,
497
+ ROUTING_NAMES,
498
+ };