Backend-calculated, audit-ready scoring

How every feedback score is calculated

AI reads the student text and selects labels. The backend then recalculates every numeric score with fixed formulas, attaches a score audit, and sends transparent values to the dashboard.

1.1 outputFromAI
AIlabels
Codescores
Auditformulas
Nullunknowns
01

Pipeline

One record moves through four deterministic checkpoints before it reaches juries or dashboards.

inputToSystem v1.2.0 Raw text, rating, course, teacher, student, and feedback context.
AI categorization Language, sentiment label, emotion, topics, keywords, severity, routing, and summary.
Validation guardrails Enums are normalized. Risk is removed when raw text has no explicit risk evidence.
Formula engine Python overwrites all numeric scores and creates score_audit.formulas.
02

Core Formula Inputs

These values are computed for every feedback before scoring starts.

rating_score

rating_score = (rating - 1) / 4

If no rating exists, the neutral default is 0.5.

label_score

positive = 0.80 · neutral = 0.50 · negative = 0.20

The AI chooses the label; the backend maps it to this fixed numeric value.

specificity

clip(0.15 + 0.55*min(word_count/20,1) + 0.30*specific_marker_present)

Specific markers include academic, dimension, or explicit risk terms found in the raw text.

alignment

alignment = 1 - abs(label_score - rating_score)

Contradictory rating/text pairs reduce confidence and credibility.

context_modifier

+0.02 / -0.03 / 0

+0.02 for specific senior high-attendance/high-GPA feedback. -0.03 for vague low-attendance feedback. Context is only a weak modifier.

rating_weight

0.25 if vague · 0.15 if specific · 0 if no rating

If rating and text strongly conflict, rating weight is capped at 0.10. For explicit risk allegations with random-positive ratings, rating_weight becomes 0.

03

Feedback-Level Scores

These are the numbers juries see on each analyzed record.

Sentiment score

clip((1-rating_weight)*label_score + rating_weight*rating_score + context_modifier)

Text label is primary. Rating becomes secondary, especially when the text is vague.

Credibility

clip(0.10 + 0.35*specificity + 0.25*alignment + 0.15*attendance_signal + 0.15*domain_evidence)

Vague feedback is capped at 0.45. Spam-like or irrelevant text is capped at 0.25.

Confidence

clip(0.20 + 0.35*specificity + 0.20*alignment + 0.25*domain_evidence)

Vague feedback is capped at 0.50 because the system should not overclaim certainty.

Emotion intensity

clip(0.55*emotion_base + 0.25*abs(sentiment_score-0.5)*2 + 0.10*rating_extremity + 0.10*specificity)

Emotion labels come from AI, but intensity is calculated from fixed base values and evidence strength.

04

Satisfaction Dimensions

Dimensions are scored only when raw text directly mentions the dimension. Otherwise they stay null.

No direct evidence = null The system does not convert silence into 0%, 50%, or guessed satisfaction.
teaching_quality clarity engagement course_content_relevance assessment_fairness grading_transparency materials_quality support_availability admin_responsiveness workload_balance overall_satisfaction

Dimension polarity

negative markers = 0.20 · positive markers = 0.85 · mixed markers = 0.50 · otherwise sentiment_score

For assessment fairness and grading transparency, neutral grading markers with negative sentiment use 0.30.

Dimension score

null if no direct evidence; otherwise clip(0.80*polarity + 0.15*sentiment_score + 0.05*effective_rating_score + context_modifier)

Only dimensions with direct raw-text evidence contribute to their dashboard average.

Overall satisfaction

clip(0.70*sentiment_score + 0.20*effective_rating_score + 0.10*mean(non_null_dimensions or sentiment_score))

Overall always exists. If explicit risk evidence appears, a positive/random rating is replaced by the text-derived sentiment score.

05

Risk and Impact

Risk fields remain empty unless explicit risk evidence appears in raw_text.

No explicit risk evidence

risk.types = [] risk.probability = 0.0 risk.impact_scopes = []

Ordinary complaints may still have recommended_action, but they are not treated as legal/safety risks.

Explicit risk probability

clip(base_by_evidence_level + 0.10*specificity + 0.03*min(type_count,3))

Evidence bases: weak 0.35, explicit 0.55, serious 0.75. Teacher money-request wording is treated as corruption_allegation and routed to teacher_instructor + department for investigation.

Risk impact score

clip(0.55*risk_probability + 0.30*max_scope_weight + 0.15*severity_weight)

Used for dashboard ranking and institutional risk summaries.

Severity weights

none 0.00 · low 0.20 · medium 0.45 · high 0.75 · critical 1.00

Scope weights

individual_student 0.20 · group_of_students 0.35 · course_section 0.45 · teacher_instructor 0.50 · staff_admin 0.55 · department 0.65 · faculty 0.75 · institute 0.85 · education_system 1.00 · external_community 0.65 · digital_platform 0.55

06

Dashboard Aggregates

University, course, teacher, trend, and dimension dashboards use weighted calculations.

Record weight max(0.05, credibility * confidence)
Average sentiment sum(sentiment_score * record_weight) / sum(record_weight)
University satisfaction weighted average of overall_satisfaction
Dimension average weighted average of non-null dimension_score[key]
Average risk impact weighted average of risk_impact_score
Audit trail output.score_audit.formulas + components + scores
07

Two Example Outcomes

The examples below show why the system does not guess hidden dimensions.

negative label

“chummadim”

Direct evidence exists for clarity only. Risk is empty. Other dimensions stay null.

sentiment_score
0.2125
clarity
0.2044
overall_satisfaction
0.2192
positive label

“xullasi bitta abed ekande 5”

Text is vague and non-academic, so credibility is low and non-overall dimensions stay null.

credibility
0.25
risk
empty
overall_satisfaction
0.756