livrare lot 2

This commit is contained in:
EVOTECH IT SRL 2026-07-10 03:39:53 -07:00
commit 8ecc78e729
763 changed files with 164593 additions and 0 deletions

View file

@ -0,0 +1,489 @@
# VERDICT BUGS AUDIT — Verified with Redis + PostgreSQL Data
**Data**: 2026-02-26
**Status**: Auditat si confirmat cu date reale din Redis si PostgreSQL
**Fisiere afectate**:
- `src/components/pipeline/verdict-calculator.ts` — buguri #1, #2, #6, #7
- `src/components/techniques/executor.ts` — bug #3
- `src/components/claims/executor.ts` — bug #4
- `src/config/analysisLimits.ts` — context pentru bug #4 (MIN_CLAIMS_TEXT_LENGTH = 100)
---
## Sesiuni de referinta (din PostgreSQL bos_analysis)
### Sesiunea 7cc2cca8 — DOVADA BUG #1
```
risk_score = 90 | risk_category = RELIABLE | risk_level = CRITICAL | severity = CRITICAL
score_manipulation = 87 | score_claims = 75 | score_ai = 0 | score_source = NULL
override_applied = true | override_type = SYNERGY | override_adjustment = 20
override_reason = "2 components with high risk (+10%); 2 severe techniques (+10%)"
input_text = "UK and France plan to send nuclear weapons to Ukraine to fight Russian..."
components_run = {ai_tampered, techniques, claims}
```
### Sesiunea d07266ca — DOVADA BUG #3
```
risk_score = 68 | risk_category = QUESTIONABLE | risk_level = HIGH
manipulation_score = 100 | techniques_count = 1 | total_severity = 60 | dimensions_affected = {D8}
credibility_score = 50 | total_claims = 2 | verified_false = 0
input_text = "In februarie 2026 in bucuresti a nins masiv si la 4 dimineata autoritatile au tr..."
```
### Sesiunea 2adf7ace — DOVADA BUG #4 si #5
```
risk_score = 0 | risk_category = RELIABLE | risk_level = VERY_LOW
score_manipulation = 0 | score_claims = NULL | score_ai = 0 | score_source = NULL
manipulation_score = 0 | techniques_count = 0 | dimensions_affected = {D7, D8}
credibility_score = NULL | interpretation = "Text too short for claims analysis (54 chars)"
input_text = "Uk and France plan to send nuclear weapons to ukraine." (54 chars)
```
### Sesiunea 4fa38b53 — Context BUG #3 si LLM false positives
```
risk_score = 58 | risk_category = QUESTIONABLE | risk_level = HIGH | severity = MEDIUM
manipulation_score = 100 | techniques_count = 3 | total_severity = 240 | dimensions_affected = {D1}
credibility_score = 92 | total_claims = 10 | verified_true = 9 | verified_false = 0
override_applied = true | override_adjustment = 10 (CRITICAL: severe techniques)
input_type = url | input_text = "Title: Nancy Guthrie's family offers $1m reward..."
score_source = 30 (domain trusted)
```
### Sesiunea ee58753d — DOVADA BUG #2
```
risk_score = 80 | risk_category = UNRELIABLE | risk_level = VERY_HIGH | severity = MEDIUM
manipulation_score = 100 | techniques_count = 13 | total_severity = 820 | dimensions_affected = {D1,D3,D7,D8}
credibility_score = 45 | total_claims = 7 | verified_false = 1
override_applied = true | override_adjustment = 10
input_text = "Un studiu secret al Universitatii Harvard arata ca 80% dintre romani vor ramane..."
```
**Severity=MEDIUM la risk_score=80 e gresit.** Conform severity_assessment: 80 e in range CRITICAL (80-100). Floatul a fost probabil ~79.5 care a cazut in gap intre HIGH (60-79) si CRITICAL (80-100).
---
## Date framework din Redis SI PostgreSQL (identice in ambele)
### Verdict Categories (bos_parammgmt.verdict_category)
```
RELIABLE start=0 end=15 color=green
MOSTLY_RELIABLE start=16 end=30 color=lightgreen
MIXED start=31 end=55 color=yellow
QUESTIONABLE start=56 end=75 color=orange
UNRELIABLE start=76 end=90 color=red
DISINFORMATION start=91 end=100 color=darkred
```
GAP-URI FLOAT: 15.x, 30.x, 55.x, 75.x, 90.x — niciun range nu acopera aceste valori.
### Risk Mappings (bos_parammgmt.risk_mapping) — 6 nivele, NU 4 ca in cod defaults
```
VERY_LOW start=0 end=10 level=1 color=green
LOW start=11 end=25 level=2 color=lightgreen
MEDIUM start=26 end=50 level=3 color=yellow
HIGH start=51 end=75 level=4 color=orange
VERY_HIGH start=76 end=90 level=5 color=red
CRITICAL start=91 end=100 level=6 color=darkred
```
GAP-URI FLOAT: 10.x, 25.x, 50.x, 75.x, 90.x
Cod defaults au 4 nivele (LOW/MODERATE/HIGH/CRITICAL), Redis are 6 (VERY_LOW/LOW/MEDIUM/HIGH/VERY_HIGH/CRITICAL).
Fallback in cod: `risk_mappings[length - 1]` = ultimul element = CRITICAL (cel mai sever).
### Severity Assessments (bos_parammgmt.severity_assessment)
```
LOW start=0 end=29
MEDIUM start=30 end=59
HIGH start=60 end=79
CRITICAL start=80 end=100
```
GAP-URI FLOAT: 29.x, 59.x, 79.x
Fallback in cod: `severity_assessments[length - 1]` = ultimul element.
NOTA: Redis are trailing whitespace pe valori (`"CRITICAL "`), codul face `.trim()` la linia 318.
### Component Weights (bos_parammgmt.component_weight)
```
manipulation = 35 (cod default: 0.35)
claims = 25 (cod default: 0.25)
source = 20 (cod default: 0.20)
ai = 10 (cod default: 0.10)
context = 10 (cod default: 0.10)
```
Unitati diferite (35 vs 0.35) dar FARA impact — `calculateWeightedRisk` imparte la totalWeight, deci se normalizeaza.
### Multipliers (doar in Redis, cod defaults = array gol)
```
Topic (type 1):
elections = 150 (intentie: 1.5x)
security = 140 (intentie: 1.4x)
public_health = 130
dimension_d4 = 130
dimension_d8 = 130
dimension_d5 = 120
dimension_d7 = 110
dimension_d6 = 90
Temporal (type 2):
election_window = 140
crisis_window = 130
Reach (type 3):
high_reach = 125
medium_reach = 110
low_reach = 100
```
### Verdict Config (Redis didi:config:pipeline:v1:verdict_config)
```
synergy: enabled=true, threshold=70, bonus_per_component=5, max_bonus=15
false_claims: enabled=true, threshold=3, bonus_per_claim=5, max_bonus=20
severe_techniques: enabled=true, threshold=2, bonus=10
undisclosed_ai: enabled=true, bonus=15
untrusted_domain: enabled=true, untrusted_bonus=20, suspicious_bonus=10, blacklisted_bonus=25
domain_red_flags: enabled=true, threshold=2, bonus_per_flag=5, max_bonus=15
confidence: base_per_component=12.5, domain_strong=15, domain_weak=8, techniques_max=12
ai_high=12, ai_medium=8, ai_low=4, claims_max=11
confidence_levels: HIGH=75, MEDIUM=50, LOW=0
```
### Scenarii redistribuire (doar Redis, ignorate de cod)
```
Full Analysis: manipulation=35, claims=25, source=20, ai=10, context=10
No Source: manipulation=44, claims=31, source=0, ai=12, context=13
No Claims: manipulation=44, claims=0, source=25, ai=12, context=19
Text Only: manipulation=47, claims=33, source=0, ai=0, context=20
Minimal: manipulation=70, claims=0, source=0, ai=0, context=30
```
### Techniques Scoring Config (Redis didi:config:techniques:v3:scoring_config)
```
manipulation_levels: LOW=0-0.25, MEDIUM=0.25-0.5, HIGH=0.5-0.75, CRITICAL=0.75-1.0
bonuses:
count_bonus: threshold_3=+5%, threshold_5=+10%
dimension_bonus: per_dimension=2%, max_bonus=15%
intensity_bonus: formula = (avgIntensity - 1) * 0.05
```
---
## BUGURI CONFIRMATE — DETALII TEHNICE
### BUG #1 — CRITIC: Float gap in mapToVerdictCategory
**Fisier**: `src/components/pipeline/verdict-calculator.ts`
**Linii**: 292 (mapare), 313 (rotunjire), 568-573 (functia)
**Problema**: Scorul e un float (ex: 90.4). Categoriile au ranguri integer (UNRELIABLE: 76-90, DISINFORMATION: 91-100). Valoarea 90.4 nu se potriveste nicaieri. Fallback = `categories[0]` = RELIABLE.
**Cod buguit**:
```typescript
// Linia 292 — mapare pe float NEROTUNJIT
const riskCategory = this.mapToVerdictCategory(riskScore);
const riskLevel = this.mapToRiskLevel(riskScore);
const severity = this.mapToSeverity(riskScore);
// Linia 313 — rotunjire DUPA mapare
risk_score: Math.round(riskScore),
// Linia 568-573 — functia cu fallback RELIABLE
private mapToVerdictCategory(score: number): VerdictCategory {
for (const cat of this.verdicts.categories) {
if (score >= cat.start_range && score <= cat.end_range) return cat;
}
return this.verdicts.categories[0]; // RELIABLE — cel mai bun!
}
```
**Fallback-uri contradictorii**:
- mapToVerdictCategory: `categories[0]` = RELIABLE (cel mai bun)
- mapToRiskLevel: `risk_mappings[last]` = CRITICAL (cel mai rau)
- mapToSeverity: `severity_assessments[last]` = CRITICAL (cel mai rau)
Rezultat posibil: risk_category=RELIABLE + risk_level=CRITICAL simultan.
**Fix**:
```typescript
// INAINTE de liniile 292-294, adauga:
const roundedScore = Math.round(riskScore);
// Apoi foloseste roundedScore in loc de riskScore:
const riskCategory = this.mapToVerdictCategory(roundedScore);
const riskLevel = this.mapToRiskLevel(roundedScore);
const severity = this.mapToSeverity(roundedScore);
// La linia 313 foloseste roundedScore:
risk_score: roundedScore,
```
**Dovada din PG**: Sesiunea 7cc2cca8: risk_score=90, risk_category=RELIABLE, risk_level=CRITICAL.
---
### BUG #2 — CRITIC: Severity float gap (aceeasi cauza ca #1)
**Fisier**: `src/components/pipeline/verdict-calculator.ts`
**Linii**: 582-587
**Dovada din PG**: Sesiunea ee58753d: risk_score=80, severity=MEDIUM. Ar trebui CRITICAL (80-100).
**Fix**: Acelasi ca #1 — rotunjire inainte de mapare.
**Nota**: Ordinea elementelor in array-ul severity_assessments din Redis poate afecta fallback-ul. Trebuie verificat ordinea exacta daca se vrea un fallback inteligent.
---
### BUG #3 — MARE: manipulation_score=100 pe 1 tehnica
**Fisier**: `src/components/techniques/executor.ts`
**Linii**: 575-612
**Problema**: Formula `baseScore = sum(severity * confidence/100) / sum(severity)` se simplifica la `confidence/100` cand e o singura tehnica (severity se anuleaza). Cu confidence=95% si bonusuri: 0.95 + 0.02 + 0.10 = 1.07 → clamped la 1.0 → manipulation_score=100.
**Cod buguit**:
```typescript
private calculateManipulationScore(techniques: DetectedTechnique[], config: any): number {
if (techniques.length === 0) return 0;
let severitySum = 0;
let weightedSum = 0;
for (const t of techniques) {
severitySum += t.severity;
weightedSum += t.severity * (t.confidence / 100);
}
let baseScore = severitySum > 0 ? weightedSum / severitySum : 0;
// Cu 1 tehnica: baseScore = (S * C/100) / S = C/100
// ...bonusuri...
const finalScore = baseScore + dimensionBonus + countBonus + intensityBonus;
return Math.round(Math.max(0, Math.min(1, finalScore)) * 100);
}
```
**Fix propus** — Scalare bazata pe numar tehnici (cap maxim per count):
```typescript
// Dupa calculul baseScore, inainte de bonusuri:
// Penalizare count mic: o singura tehnica nu poate justifica scor maxim
const countScaler = Math.min(1.0, techniques.length / 3);
// 1 tehnica -> max 33%, 2 tehnici -> max 67%, 3+ -> 100%
baseScore = baseScore * countScaler;
```
Alternativ, un cap per count: 1 tehnica → max 50, 2 tehnici → max 70, 3+ → max 100.
**Dovada din PG**: Sesiunea d07266ca: techniques_count=1, total_severity=60, manipulation_score=100.
---
### BUG #4 — MARE: Claims credibility_score=NULL pierde ponderea
**Fisiere**:
- `src/components/claims/executor.ts` linii 695-716 (buildSkippedResult)
- `src/components/pipeline/verdict-calculator.ts` linii 358-360 (extractComponentScores)
- `src/config/analysisLimits.ts` linia 21 (MIN_CLAIMS_TEXT_LENGTH = 100)
**Problema**: Text intre 50-99 chars trece validarea hard (MIN_TEXT_LENGTH=50) dar claims e skip-uit (MIN_CLAIMS_TEXT_LENGTH=100). buildSkippedResult returneaza `credibility_score: null`. VerdictCalculator: null → -1 → component indisponibil → weight redistribuit.
Diferenta comportament:
- Text < 100 chars: claims skip credibility=NULL weight redistribuit (claims ignorat)
- Text >= 100 chars, 0 claims: buildEmptyResult → credibility=50 → participa la scor
- Text >= 100 chars, claims gasite: credibility calculat 0-100
**Cod relevant**:
```typescript
// claims/executor.ts linia 695
private buildSkippedResult(startTime: number, textLength: number): ClaimsResult {
return {
credibility_score: null, // <-- NULL
interpretation: `Text too short for claims analysis (${textLength} chars)`,
// ...
};
}
// claims/executor.ts linia 672
private buildEmptyResult(...): ClaimsResult {
return {
credibility_score: 50, // <-- DEFAULT 50
interpretation: 'No claims to verify',
// ...
};
}
// verdict-calculator.ts linia 358
const claimsRisk = claims && claims.credibility_score != null && claims.credibility_score >= 0
? Math.round(100 - claims.credibility_score)
: -1; // -1 = indisponibil, weight redistribuit
```
**Fix propus**: In buildSkippedResult, returneaza `credibility_score: 50` in loc de `null` (neutral, ca si 0 claims). Sau: in verdict-calculator, trateaza null ca 50 in loc de -1.
**Dovada din PG**: Sesiunea 2adf7ace: credibility_score=NULL, interpretation="Text too short for claims analysis (54 chars)".
---
### BUG #5 — MARE: Text scurt vs lung inconsistenta dramatica
**Cauza**: Combinatie buguri #3 + #4 + dampening din verdict-calculator.
**Mecanism**:
1. Text scurt (54 chars) → screening LLM nu detecteaza tehnici → manipulation=0
2. 54 < 100 claims skip credibility=NULL weight redistribuit
3. dampenBenignContent (verdict-calculator.ts:455-469): techniques=0, ai=0 → maxStrongSignal=0 < 15 cap = 0 + 15 = 15
4. Rezultat: risk_score capeat la max 15 → in practica 0
**Cod dampening**:
```typescript
// verdict-calculator.ts linia 455
private dampenBenignContent(rawScore: number, scores: ComponentScores): number {
const BENIGN_THRESHOLD = 15;
const strongSignals = [scores.manipulation, scores.ai].filter(s => s >= 0);
if (strongSignals.length === 0) return rawScore;
const maxStrongSignal = Math.max(...strongSignals);
if (maxStrongSignal >= BENIGN_THRESHOLD) return rawScore;
const cap = maxStrongSignal + BENIGN_THRESHOLD;
return Math.min(rawScore, cap);
}
```
**Dovada din PG**:
- 2adf7ace (54 chars): risk_score=0, RELIABLE
- 7cc2cca8 (aceeasi info, ~200+ chars): risk_score=90, RELIABLE (bug #1, ar trebui UNRELIABLE)
---
### BUG #6 — MARE (LATENT): Multiplicatori ×150 in loc de ×1.5
**Fisier**: `src/components/pipeline/verdict-calculator.ts`
**Linii**: 279-289
**Problema**: Redis stocheaza multiplicatori ca procente (elections=150 = 1.5x). Codul aplica direct: `riskScore * 150` in loc de `riskScore * 1.5`.
**Cod buguit**:
```typescript
// Linia 284
if (options?.topic) {
const topicMultiplier = this.getMultiplier('topic', options.topic);
if (topicMultiplier) {
riskScore = Math.min(100, riskScore * topicMultiplier.multiplier);
// riskScore * 150 = scor × 150, nu × 1.5
// Math.min(100, ...) salveaza de catastrofa dar orice scor > 0.67 devine 100
}
}
```
**Date Redis**:
```
elections=150, security=140, public_health=130, dimension_d4=130, dimension_d8=130
election_window=140, crisis_window=130, high_reach=125, medium_reach=110, low_reach=100
```
**Fix**:
```typescript
riskScore = Math.min(100, riskScore * (topicMultiplier.multiplier / 100));
```
**Status**: Bug latent — multiplicatorii se aplica doar daca `options.topic` e setat, ceea ce pare sa nu fie folosit activ momentan. Dar cand se va activa, va fi catastrofal.
---
### BUG #7 — MIC: Scenarii Redis ignorate
**Fisier**: `src/components/pipeline/verdict-calculator.ts`
**Linia**: 385
**Problema**: Parametrul `_scenario` (cu underscore = nefolosit) in `calculateWeights`. Codul face redistribuire proportionala proprie in loc sa foloseasca scenariile pre-definite din Redis.
**Redis contine 5 scenarii**:
```
Full Analysis: manipulation=35, claims=25, source=20, ai=10, context=10
No Source: manipulation=44, claims=31, source=0, ai=12, context=13
No Claims: manipulation=44, claims=0, source=25, ai=12, context=19
Text Only: manipulation=47, claims=33, source=0, ai=0, context=20
Minimal: manipulation=70, claims=0, source=0, ai=0, context=30
```
**Impact**: Redistribuirea proportionala din cod poate diferi de scenariile gandite de admin. Nu e un bug functional, dar e un feature ignorat.
---
### BUG #8 — MIC: coupling_context flags din screening, nu deep analysis
**Fisier**: `src/components/techniques/executor.ts`
**Linii**: 664-666
**Problema**: `dimensionsAffected` vine din screening (linia 544), nu din tehnicile confirmate in deep analysis. Daca screening detecteaza D7/D8 dar deep analysis nu gaseste tehnici → coupling_context flags raman true cu 0 tehnici.
**Cod buguit**:
```typescript
// Linia 664-666 in buildCouplingContext
for_context_analysis: {
narrative_manipulation_detected: dimensionsAffected.includes('D7'), // din SCREENING
context_manipulation_detected: dimensionsAffected.includes('D8'), // din SCREENING
amplification_detected: dimensionsAffected.includes('D6'),
suspicious_patterns: warningFlags,
},
```
**Fix**: Foloseste dimensiunile din tehnicile efectiv detectate (deep analysis) in loc de cele din screening:
```typescript
const confirmedDimensions = new Set(techniques.map(t => t.dimension));
// apoi: confirmedDimensions.has('D7') in loc de dimensionsAffected.includes('D7')
```
**Dovada din PG**: Sesiunea 2adf7ace: dimensions_affected={D7,D8}, techniques_count=0.
---
## PRIORITIZARE FIX-URI
| Prioritate | Bug | Efort | Impact |
|-----------|-----|-------|--------|
| 1 | #1 + #2: Rotunjire inainte de mapare | 1 linie | Elimina bug CRITIC (RELIABLE la risk 90) |
| 2 | #3: Formula manipulation_score | ~10 linii | Elimina scor 100% pe 1 tehnica |
| 3 | #6: Multiplicatori /100 | 1 linie | Previne bug catastrofal cand se activeaza topics |
| 4 | #4: Claims null → 50 | 1 linie | Elimina pierdere ponderi pe text scurt |
| 5 | #8: coupling_context flags | ~5 linii | Corecteaza metadata inconsistenta |
| 6 | #7: Scenarii Redis | ~20 linii | Feature, nu bug critic |
---
## REFERINTE FISIERE
```
verdict-calculator.ts — src/components/pipeline/verdict-calculator.ts
Linia 292-294: mapare categorii (BUG #1, #2)
Linia 279-289: multiplicatori (BUG #6)
Linia 313: Math.round output
Linia 358-360: claims null handling (BUG #4)
Linia 385: _scenario ignorat (BUG #7)
Linia 455-469: dampenBenignContent (context BUG #5)
Linia 568-573: mapToVerdictCategory cu fallback RELIABLE
Linia 575-579: mapToRiskLevel cu fallback CRITICAL (ultimul)
Linia 582-587: mapToSeverity cu fallback ultimul
techniques/executor.ts — src/components/techniques/executor.ts
Linia 575-612: calculateManipulationScore (BUG #3)
Linia 664-666: coupling_context flags (BUG #8)
claims/executor.ts — src/components/claims/executor.ts
Linia 695-716: buildSkippedResult credibility=null (BUG #4)
Linia 672-693: buildEmptyResult credibility=50
analysisLimits.ts — src/config/analysisLimits.ts
Linia 14: MIN_TEXT_LENGTH = 50
Linia 21: MIN_CLAIMS_TEXT_LENGTH = 100
```