This document describes how the skill matrix engine behaves in operations. It is aligned with the current *
skill-matrix-engine* codebase and the Flyway migrations V1__skill_matrix_schema.sql (tables + column defaults)
and V2__rubric_preset_seed.sql (system rubric anchors + sample formula/version rows). Features that are only policy
goals or live outside this repo are called out explicitly.
| Migration file | In plain language | Why you should care |
|---|---|---|
V1__skill_matrix_schema.sql |
Creates all skill-matrix tables and defines default numbers on each formula column (weights, bonuses, caps) whenever a new formula row is created without overriding a column. | Guarantees a consistent, auditable starting policy. Your live tenant may use different weights after admins publish updates—the app always reads the active formula for the logged-in tenant. |
V2__rubric_preset_seed.sql |
(1) Loads global rubric anchors (suggested 0–10 starting scores per evidence type and tier). (2) Optionally seeds sample skill_formula_config + skill_formula_version rows for one reference tenant UUID so a fresh environment can demo version history (version.v1 → version1). |
Rubrics help students and staff see fair starting points before quality/recency adjustments. The seeded version1 policy slightly raises work experience vs exam weight compared to version.v1—useful story for “we value demonstrated practice alongside formal assessment.” |
Seeded formula labels (reference data in V2 only)
version.v1 — earlier label; tied to config_id = 1 in the seed; marked inactive in skill_formula_version.version1 — currently published in the seed (config_id = 2, is_active = true on the version row).Important: Production tenants that are not that UUID have no rows from this insert until your team publishes
a formula in the UI/API. The worked examples below use the V2 seeded version1 weights so numbers match a
typical post-migrate demo database.
EvidenceType includes: CERTIFICATIONS, PROJECTS, PUBLICATIONS, COMPETITIONS, EXAMS, HACKATHONS,
TRAININGS, EXPERIENCE, AWARDS, CONFERENCES, PATENTS, SELF_ASSESSMENT.
Row-level behavior (student_skill_evidence):
BOTH, EMPLOYER, etc.): employer-visible scores use only rows visible to employers.scoring_excluded: excluded rows do not enter the score bundle (still counted on the profile where applicable).is_verified): affects anchor credibility and confidence; verification changes enqueue *
EVIDENCE_VERIFICATION* / EVIDENCE_VERIFICATION_BULK recomputes.dedupe_key, duplicate_of_evidence_id, marginal_duplicate support ingest hygiene (see API
warnings).version1)Weights are per evidence type. The twelve configured weights must sum to 1.00 within tolerance 0.0001.
Top 3 and bottom 2 types (used for completeness and low-type down-weighting) are always recalculated from
whatever weights your tenant’s active formula row has—not from this document.
skill_formula_config (schema template)These are the numbers baked into CREATE TABLE in V1__skill_matrix_schema.sql when a column is not specified on
insert.
| Type | DDL default weight |
|---|---|
| EXAMS | 0.22 |
| PROJECTS | 0.18 |
| EXPERIENCE | 0.14 |
| CERTIFICATIONS | 0.10 |
| TRAININGS | 0.09 |
| HACKATHONS | 0.07 |
| COMPETITIONS | 0.06 |
| PUBLICATIONS | 0.05 |
| PATENTS | 0.04 |
| AWARDS | 0.03 |
| CONFERENCES | 0.02 |
| SELF_ASSESSMENT | 0.00 |
Top 3 (V1 defaults only): EXAMS, PROJECTS, EXPERIENCE. Bottom 2 (low-weighted): SELF_ASSESSMENT (weight **0 **), CONFERENCES ( 0.02 ) — see Engine buckets below. AWARDS is mid-mass, not low-weighted.
version1 (skill_formula_config second insert row)This matches V2__rubric_preset_seed.sql: same non-weight columns as V1 defaults; only exam vs experience balance
changes vs version.v1 in the same file.
| Type | version1 weight |
Change vs version.v1 in V2 (first row) |
|---|---|---|
| EXAMS | 0.17 | −0.05 |
| PROJECTS | 0.18 | unchanged |
| EXPERIENCE | 0.19 | +0.05 |
| CERTIFICATIONS | 0.10 | unchanged |
| TRAININGS | 0.09 | unchanged |
| HACKATHONS | 0.07 | unchanged |
| COMPETITIONS | 0.06 | unchanged |
| PUBLICATIONS | 0.05 | unchanged |
| PATENTS | 0.04 | unchanged |
| AWARDS | 0.03 | unchanged |
| CONFERENCES | 0.02 | unchanged |
| SELF_ASSESSMENT | 0.00 | unchanged |
How to explain version1 to stakeholders: “We still reward exams and projects highly, but internships and jobs
move slightly ahead of exam marks in the default mix—reflecting that proven on-the-job use of a skill matters as
much as a test score.”
Top 3 (version1 weights): EXPERIENCE, PROJECTS, EXAMS. Bottom 2 (low-weighted): SELF_ASSESSMENT ( 0 ),
CONFERENCES ( 0.02 ) — same rule as V1; only ranking of the top three changed.
This mirrors SkillScoringService: labels come only from configured weights on skill_formula_config, never
from a student’s rubric or raw scores.
| Implementation | Value | Meaning |
|---|---|---|
TOP_WEIGHTED_COUNT |
3 | Types with the largest configured weights (deriveTopWeightedTypes). |
LOW_WEIGHTED_COUNT |
2 | Types with the smallest configured weights (deriveLowWeightedTypes). |
LOW_PRIORITY_DOWNWEIGHT |
0.4 | Applied to a present low-weighted type’s configured weight before splitting 100% across present types, only if the student has evidence in at least two top-weighted types. |
Algorithm (dynamic redistribution branch).
sourceScores per type (after anchor, multipliers, recency, top-k merge).sourceScore > 0.(EvidenceType, weight) pairs, sort by weight descending, keep 3 keys.effectiveWeight = configuredWeight. If topPresent >= 2 and the type is
in the low-weighted set, set effectiveWeight *= 0.4.effectiveWeight / Σ(effectiveWeight over present types) → present types’ dynamic
weights sum to 1.sourceScore > 0,
multiply by completeness_bonus_per_top_type, cap 0.20.Colloquial “high mass.” High configured mass = large weight in the published formula. “High mass present” in logic = at least two of the three top-weighted types have non-zero source scores — that unlocks ×0.4 on any present low-weighted type.
Mid-mass types. Types in neither the top-3 nor bottom-2 sets (with default V1 / V2 seeds, seven types:
e.g. certifications through awards between experience and conferences).
SELF_ASSESSMENT at weight 0. It is always one of the two smallest weights in default migrations, so it sits in
lowWeightedTypes. Down-weighting applies only if the student has self-assessment lines that produce
sourceScore > 0 and topPresent >= 2. If only self rows exist but weight is 0, effectiveWeight stays 0 — an
edge case to avoid relying on self-only profiles when the formula gives self zero global weight.
Ties. Equal configured weights: which type occupies a top-3 or bottom-2 slot depends on sort tie-breaking; avoid identical weights if you need stable labels in audits.
| Rank | Evidence type | Configured weight | Bucket |
|---|---|---|---|
| 1 | EXAMS | 0.22 | Top-weighted (high mass) |
| 2 | PROJECTS | 0.18 | Top-weighted |
| 3 | EXPERIENCE | 0.14 | Top-weighted |
| 4 | CERTIFICATIONS | 0.10 | Mid-mass |
| 5 | TRAININGS | 0.09 | Mid-mass |
| 6 | HACKATHONS | 0.07 | Mid-mass |
| 7 | COMPETITIONS | 0.06 | Mid-mass |
| 8 | PUBLICATIONS | 0.05 | Mid-mass |
| 9 | PATENTS | 0.04 | Mid-mass |
| 10 | AWARDS | 0.03 | Mid-mass |
| 11 | CONFERENCES | 0.02 | Low-weighted |
| 12 | SELF_ASSESSMENT | 0.00 | Low-weighted |
version1 weights| Rank | Evidence type | Configured weight | Bucket |
|---|---|---|---|
| 1 | EXPERIENCE | 0.19 | Top-weighted |
| 2 | PROJECTS | 0.18 | Top-weighted |
| 3 | EXAMS | 0.17 | Top-weighted |
| 4 | CERTIFICATIONS | 0.10 | Mid-mass |
| 5 | TRAININGS | 0.09 | Mid-mass |
| 6 | HACKATHONS | 0.07 | Mid-mass |
| 7 | COMPETITIONS | 0.06 | Mid-mass |
| 8 | PUBLICATIONS | 0.05 | Mid-mass |
| 9 | PATENTS | 0.04 | Mid-mass |
| 10 | AWARDS | 0.03 | Mid-mass |
| 11 | CONFERENCES | 0.02 | Low-weighted |
| 12 | SELF_ASSESSMENT | 0.00 | Low-weighted |
If your team publishes a new formula, re-rank the twelve types and replace top 3 / bottom 2; the UI should show
whatever the API returns in topWeightedTypes / lowWeightedTypes on the latest computation.
Java and java merge.For each skill, the engine can compute two bundles:
EMPLOYER or BOTH.The profile stores final institutional score (after optional decay and override) and, when the employer bundle is
non-empty, employer_visible_final_score and employer_visible_confidence. Job match evaluation can use either
via useEmployerVisibleScores.
When use_dynamic_weight_redistribution is true (default), the engine adapts to evidence the student actually
submitted. Top-weighted and low-weighted sets are only the three largest and two smallest configured
weights (see Engine buckets). With self_assessment_weight = 0 (V1/V2 defaults), low-weighted types are *
SELF_ASSESSMENT* and CONFERENCES, not AWARDS.
SkillScoringService.computeScoreBundle)If use_dynamic_weight_redistribution is false, steps 4–5 are skipped: there is no “present-types only”
normalization and no ×0.4 low-type step; contributions are configuredWeight × sourceScore per type (zero
where there is no score). Completeness still uses topWeightedTypes.
base_score_0_10) and self-assessment (
student_self_assessment_score_0_10) with inflation dampening when self-assessment exceeds rubric:dampenedSelf = rubric + gap / (1 + sensitivity × gap) for gap = max(0, self − rubric); if self ≤ rubric, no
dampening.anchor = rubric × credibility + dampenedSelf × (1 − credibility) where
credibility = rubricAnchorFloor + (verifiedRubricBoost if verified), capped at 1.0.anchor × min(1, quality) × min(1, confidence) × recency, then clamped to 0–10.top_k_per_source (k = 3 default) and decay_factor (
0.70 default): weighted average of the top scores with weights 1, decay, decay², ….topWeightedTypes is ≥ 2 and the type is in *
*lowWeightedTypes**, multiply its weight by 0.4 (LOW_PRIORITY_DOWNWEIGHT).dynamic_weight = effective_weight / Σ effective_weight so
present types sum to 1.0 (missing types get 0).dynamic_weight × source_score) + completeness bonus (see below). The
value persisted as weighted_core in skill_score_computation includes the completeness bonus.min(0.20, count(top types with evidence) × completeness_bonus_per_top_type) (defaults: *
0.05* per type, cap 0.20). Here “top types with evidence” means members of topWeightedTypes with
sourceScore > 0.min(diversity_bonus_cap, max(0, distinctTypesWithScore − 1) × bonus_per_source) (defaults:
cap 0.80, 0.20 per extra type).consistency_penalty_factor × sqrt(variance of non-zero source scores) across types (
default factor 0.08).weighted_core + diversity_bonus − consistency_penalty).CERTIFICATIONS,
PROJECTS, EXAMS, or EXPERIENCE, the final score is capped at profile_only_max_cap (default 5.5).skill_level_decay_enabled and no human override, institutional (and employer)
scores drift toward skill_level_decay_baseline_0_10 based on skill_level_decay_basis (default
EVIDENCE_DATE) and half-life skill_level_decay_half_life_days (default 365). When
skill_level_decay_apply_on_read is true, decay can be re-applied on read from stored intrinsic scores.confidence_score on the profile uses:
100 × (0.35 × coverage + 0.30 × verificationRatio + 0.20 × freshness + 0.15 × stability)
1 − min(1, consistencyPenalty).If evidence_date is null, recency defaults to 0.70. Otherwise exponential decay uses type-specific half-lives (
days), e.g. EXAMS / CERTIFICATIONS / TRAININGS 540; PROJECTS / COMPETITIONS / HACKATHONS / EXPERIENCE
365; PUBLICATIONS / PATENTS 720; AWARDS / CONFERENCES 270; SELF_ASSESSMENT 180.
| Parameter | Default | Description |
|---|---|---|
top_k_per_source |
3 | How many evidence lines per type participate in diminishing aggregation |
decay_factor |
0.70 | Decay weight for 2nd, 3rd, … best line within a type |
diversity_bonus_cap |
0.80 | Upper bound on diversity bonus |
bonus_per_source |
0.20 | Increment per extra evidence type beyond the first |
consistency_penalty_factor |
0.08 | Scales spread penalty across types |
profile_only_max_cap |
5.5 | Cap for “single weak-type-only” profiles (see step 11) |
use_dynamic_weight_redistribution |
true | Enable redistribution among present types |
completeness_bonus_per_top_type |
0.05 | Bonus per top-weighted type with evidence (max 0.20) |
self_inflation_sensitivity |
0.5 | Dampening strength when self-assessment exceeds rubric (DB allows 0–5) |
rubric_anchor_floor |
0.4 | Minimum rubric weight in anchor blend |
verified_rubric_boost |
0.3 | Extra rubric weight when verified; floor + boost ≤ 1.0 |
skill_level_decay_enabled |
false | Time decay toward baseline |
skill_level_decay_basis |
EVIDENCE_DATE |
What timestamps drive decay |
skill_level_decay_half_life_days |
365 | Half-life for decay curve |
skill_level_decay_baseline_0_10 |
5.0 | Baseline score toward which skill decays |
skill_level_decay_apply_on_read |
false | Re-apply decay on API read |
SkillScoringService only (not separate DB columns): TOP_WEIGHTED_COUNT = 3, LOW_WEIGHTED_COUNT = 2,
LOW_PRIORITY_DOWNWEIGHT = 0.4.
These non-weight defaults match V1__skill_matrix_schema.sql column definitions; the V2 seed inserts use
the same values for rubric-anchor and decay fields on both version.v1 and version1 rows (only the twelve
weights differ between those two configs).
FormulaPublishRequest today carries weights and skill-level decay fields; other parameters keep entity/DB
defaults on publish unless extended in code.
| Scenario | Evidence present | Behaviour |
|---|---|---|
| Single type | Only CERTIFICATIONS |
100% dynamic weight to that type; no penalty for missing other categories. |
| Two low-mass types | CERTIFICATIONS + PUBLICATIONS |
Redistribute by configured mass (e.g. 0.10 vs 0.05 → ~67% / ~33%). |
| Top types only | Any two of EXPERIENCE / PROJECTS / EXAMS (under V2 version1) |
Strong signal; completeness bonus can apply. |
| Mixed top + low | e.g. EXAMS + PROJECTS + CONFERENCES |
With ≥2 top-weighted types present, each present low-weighted type (default seeds: CONFERENCES, or SELF_ASSESSMENT if it has score) is ×0.4 before normalization. AWARDS is not low-weighted under default weights. |
| Only low types | e.g. CERTIFICATIONS + PUBLICATIONS + AWARDS |
Redistribution only; no ×0.4 low-type rule (fewer than two top types present). |
Configured weights apply to all types; missing types contribute zero but their weight is not reallocated—students with sparse types are not boosted by redistribution.
Each recompute persists skill_score_computation (when profile build runs with useExistingProfile):
evidence_ids_json, evidence_types_present_jsonconfigured_weights_json, dynamic_weights_json, top_weighted_types_json, low_weighted_types_jsonsource_scores_json, weighted_contributions_json, weighted_core (includes completeness bonus),
diversity_bonus, completeness_bonus, consistency_penalty, final_score, confidence_scoreformula_decisions_json: see belowcomputation_reason: string carried from the async job / transaction (see below)API: GET /skill-matrix/student/{studentId}/skill/{skillName}/computation-history?limit=10
EVIDENCE_UPDATE, EVIDENCE_BATCH, EVIDENCE_VERIFICATION, EVIDENCE_VERIFICATION_BULK, MANUAL_RECOMPUTE,
FORMULA_PUBLISH_RECOMPUTE, FORMULA_ROLLBACK_RECOMPUTE (plus any explicit string passed into
recomputeStudentSkills).
Including: DYNAMIC_WEIGHT_REDISTRIBUTION, LOW_PRIORITY_DOWNWEIGHTED, COMPLETENESS_BONUS_APPLIED,
DIVERSITY_BONUS_APPLIED, CONSISTENCY_PENALTY_APPLIED, HUMAN_OVERRIDE_APPLIED, SKILL_LEVEL_DECAY_APPLIED.
explainability_json)In addition to sourceScores, sourceWeights (configured or dynamic, depending on mode), weightedContributions,
topWeightedTypes, lowWeightedTypes, diversityBonus, completenessBonus, consistencyPenalty, finalScore:
modelFinalScoreBeforeOverride, humanOverrideAppliedemployerVisibleFinalScore when computedskillLevelDecayEnabled, skillLevelDecayBasis, skillLevelDecayHalfLifeDays,
skillLevelDecayBaseline, skillLevelDecayApplyOnRead, skillDecayReferenceAt, employerSkillDecayReferenceAt,
intrinsicModelScoreBeforeSkillDecayScenarios and full computation outputs below are shown only as tables (no JSON). Narrative blocks explain why
** each case behaves as it does. The field names match *
GET /skill-matrix/student/{studentId}/skill/{skillName}/computation-history* (SkillComputationDto) and the *
*explainability_json column on student_skill_profile. Numeric splits use the V2 seeded published
policy version1 weights (see above), with dynamic redistribution on, unless noted.
| Concept | Meaning |
|---|---|
| sourceScores (per type) | After rubric/self anchor, quality, confidence, recency, and top-k aggregation within that type. |
| configuredWeight | From active skill_formula_config (below). |
| dynamicWeight | Renormalized over types that have non-zero source score; low types may be ×0.4 before normalization when ≥2 top-weighted types are present. |
| weightedCore (ledger) | Σ (dynamicWeight × sourceScore) + completenessBonus—does not include diversity or consistency. |
| finalScore (ledger) | Same as displayed institutional final_skill_score for that run: after cap, decay, override. |
| confidenceScore | Depends on dates and verification; examples use rounded values. |
| topWeightedTypes / lowWeightedTypes | Exactly 3 keys with largest configured weights / 2 keys with smallest (see Engine buckets). Persisted list order may vary. |
Configured weights for examples (version1 from V2__rubric_preset_seed.sql):
| Evidence type | Weight |
|---|---|
| EXAMS | 0.17 |
| PROJECTS | 0.18 |
| EXPERIENCE | 0.19 |
| CERTIFICATIONS | 0.10 |
| TRAININGS | 0.09 |
| HACKATHONS | 0.07 |
| COMPETITIONS | 0.06 |
| PUBLICATIONS | 0.05 |
| PATENTS | 0.04 |
| AWARDS | 0.03 |
| CONFERENCES | 0.02 |
| SELF_ASSESSMENT | 0.00 |
Derived labels: top weighted = EXPERIENCE, PROJECTS, EXAMS; low weighted = SELF_ASSESSMENT, CONFERENCES (
with version1 / default zero self weight).
Scenario. A student adds one strong, verified certification for skill Spring Boot. No exams or projects yet.
Why this matters. Dynamic mode does not punish missing high-weight types: the only present type receives **100% ** of the redistributed weight, so the score reflects certification quality instead of being dragged down by empty buckets.
Pipeline (step-by-step).
| Step | Outcome |
|---|---|
| Types with score | CERTIFICATIONS only |
| Dynamic weights | CERTIFICATIONS → 1.000 (all mass on present types) |
| Sum of contributions | 8.2 (illustrative source score × 1.0) |
| Completeness bonus | 0 (no evidence in top-3 types EXPERIENCE / PROJECTS / EXAMS) |
| weightedCore | 8.2 |
| Diversity bonus | 0 (one type) |
| Consistency penalty | 0 (one type) |
| Profile-only cap | Not applied (CERTIFICATIONS is exempt) |
| Model final (before decay/override) | 8.2 |
Audit row / API (computation-history) — identifiers and context
| Field | Illustrative value |
|---|---|
| id | 10001 |
| profileId | 5001 |
| formulaConfigId | 42 |
| formulaVersionId | 1 |
| evidenceIds | 91001 |
| evidenceTypesPresent | CERTIFICATIONS |
| computationReason | EVIDENCE_UPDATE |
| computedAt | (ISO timestamp of recompute) |
Per-type snapshot (only non-zero row shown; zeros omitted for brevity)
| Type | configuredWeight | sourceScore | dynamicWeight | weightedContribution |
|---|---|---|---|---|
| CERTIFICATIONS | 0.10 | 8.2 | 1.0 | 8.2 |
Ledger totals and flags
| Field | Value |
|---|---|
| weightedCore | 8.2 |
| completenessBonus | 0 |
| diversityBonus | 0 |
| consistencyPenalty | 0 |
| finalScore | 8.2 |
| confidenceScore | ~44 (illustrative) |
| formulaDecisions | DYNAMIC_WEIGHT_REDISTRIBUTION |
Profile explainability_json (same run)
| Key | Value |
|---|---|
| sourceWeights (dynamic mode) | CERTIFICATIONS → 1.0 |
| weightedContributions | CERTIFICATIONS → 8.2 |
| topWeightedTypes | EXPERIENCE, PROJECTS, EXAMS |
| lowWeightedTypes | SELF_ASSESSMENT, CONFERENCES (order may vary) |
| completenessBonus | 0 |
| diversityBonus | 0 |
| consistencyPenalty | 0 |
| finalScore | 8.2 |
| modelFinalScoreBeforeOverride | 8.2 |
| humanOverrideApplied | false |
Scenario. Same skill has institutional exam evidence (aggregated 8.0) and a project (aggregated **7.0 **).
Why this matters. Two top-weighted types are present, so the student earns a completeness bonus. Multiple types also trigger diversity and a small consistency penalty when scores differ.
Pipeline.
| Step | Outcome |
|---|---|
| Dynamic split | EXAMS 0.17 / (0.17+0.18) ≈ 0.486; PROJECTS ≈ 0.514 |
| Contributions | EXAMS ~3.89; PROJECTS ~3.60; sum ~7.49 |
| Completeness | 2 top types × 0.05 → 0.10 |
| weightedCore | ~7.59 |
| Diversity | (2−1) × 0.20 → 0.20 |
| Consistency | 0.08 × σ(8,7) ≈ 0.04 |
| Model final | ~7.59 + 0.20 − 0.04 ≈ 7.75 |
Per-type snapshot
| Type | configuredWeight | sourceScore | dynamicWeight | weightedContribution |
|---|---|---|---|---|
| EXAMS | 0.17 | 8.0 | 0.486 | 3.89 |
| PROJECTS | 0.18 | 7.0 | 0.514 | 3.60 |
Ledger totals and flags
| Field | Value |
|---|---|
| weightedCore | ~7.59 |
| completenessBonus | 0.10 |
| diversityBonus | 0.20 |
| consistencyPenalty | 0.04 |
| finalScore | ~7.75 |
| confidenceScore | ~48.5 (illustrative) |
| formulaDecisions | DYNAMIC_WEIGHT_REDISTRIBUTION; COMPLETENESS_BONUS_APPLIED; DIVERSITY_BONUS_APPLIED; CONSISTENCY_PENALTY_APPLIED |
Scenario. Same skill adds conference evidence (aggregated 6.0) alongside exam 8.0 and project 7.0.
Why this matters. Under default / version1 weights, CONFERENCES is one of the two low-weighted types (with
SELF_ASSESSMENT). Because two top-weighted types (EXPERIENCE / PROJECTS / EXAMS — here exam +
project) are present, CONFERENCES uses configured weight × 0.4 before normalization, so a light conference line
cannot outweigh exam + project. (AWARDS would not get this treatment — it is mid-mass.)
Pipeline.
| Step | Outcome |
|---|---|
| Effective weights before normalize | EXAMS 0.17; PROJECTS 0.18; CONFERENCES 0.02×0.4 = 0.008 |
| Sum | 0.358 → dynamic ≈ 0.475 / 0.503 / 0.022 |
| Contributions sum | ≈ 7.45 |
| Completeness | +0.10 → weightedCore ≈ 7.55 |
| Diversity | +0.40 (three types) |
| Consistency | ≈ 0.065 |
| Model final | ≈ 7.89 |
Per-type snapshot
| Type | configuredWeight | effective before norm | dynamicWeight (illustr.) | sourceScore | weightedContribution (illustr.) |
|---|---|---|---|---|---|
| EXAMS | 0.17 | 0.17 | 0.475 | 8.0 | 3.80 |
| PROJECTS | 0.18 | 0.18 | 0.503 | 7.0 | 3.52 |
| CONFERENCES | 0.02 | 0.008 | 0.022 | 6.0 | 0.13 |
Ledger totals and flags
| Field | Value (illustr.) |
|---|---|
| weightedCore | ~7.55 |
| completenessBonus | 0.10 |
| diversityBonus | 0.40 |
| consistencyPenalty | ~0.065 |
| finalScore | ~7.89 |
| formulaDecisions | Includes LOW_PRIORITY_DOWNWEIGHTED and the same bonus/penalty flags as B |
Scenario. Only CERTIFICATIONS (8.0) and PUBLICATIONS (7.0)—no exam, project, or experience.
Why this matters. Weights still redistribute (67% / 33% by 0.10 vs 0.05), so the student is not forced to zero on missing exams. But no completeness bonus applies, because neither type is in the configured top three.
Pipeline.
| Step | Outcome |
|---|---|
| Dynamic split | CERT ~0.667; PUB ~0.333 |
| Contribution sum | ≈ 7.67 |
| Completeness | 0 |
| weightedCore | ~7.67 |
| Diversity | 0.20 |
| Consistency | ~0.04 |
| Model final | ~7.83 |
formulaDecisions: DYNAMIC_WEIGHT_REDISTRIBUTION only among bonuses/penalties (no COMPLETENESS_BONUS_APPLIED).
Scenario. Only PUBLICATIONS, aggregated 9.0.
Why this matters. For one evidence type that is not CERTIFICATIONS / PROJECTS / EXAMS / EXPERIENCE, the
engine caps the published score at profile_only_max_cap (default 5.5) so a single weak-category line
cannot look like a full-strength profile.
| Stage | Value |
|---|---|
| weightedCore | 9.0 |
| diversity / consistency | 0 |
| Pre-cap model total | 9.0 |
| finalScore (ledger + profile) | 5.5 (cap applied) |
Note: weighted_core in the ledger still reflects contributions + completeness; final_score is after
cap (and decay/override if any).
Scenario. Model result ~7.75 (as in Example B under version1); admin sets governed override 8.50.
Why this matters. Auditors read modelFinalScoreBeforeOverride vs finalScore; the ledger **final_score
** stores what students and HR see (8.50).
| Output | Value |
|---|---|
| finalScore / final_skill_score | 8.50 |
| modelFinalScoreBeforeOverride (explainability) | ~7.75 |
| humanOverrideApplied | true |
| confidenceScore | Usually unchanged from model path |
| formulaDecisions | Includes HUMAN_OVERRIDE_APPLIED (plus prior model flags) |
Scenario. One evidence row is INTERNAL (campus-only); another is BOTH (counts for employer view). Institutional scoring sees two types; employer bundle sees one.
Why this matters. There is one institutional computation-history row per skill recompute (institutional
pipeline). The profile still exposes employer_visible_final_score when the employer bundle is non-empty.
| Where | What it reflects |
|---|---|
| skill_score_computation / history | Institutional weights and evidence set |
| final_skill_score | Institutional, after cap / decay / override |
| employer_visible_final_score | Employer-visible subset only, same formula path |
| explainability: employerVisibleFinalScore | Recruiter-oriented headline when present |
| explainability: sourceWeights | Dynamic (or configured) weights for the profile context—employer-only rows can collapse to one type at 100% |
JobMatchResultDto)Scenario. Job mandatory: Java min 7.0, SQL min 6.0. Student scores 3.15 and 4.54 (both **unmet **). Nice-to-have rollup yields niceToHaveFitScore = 72. Mean profile confidence 62.
Why this matters. Mandatory fit still averages min(100, score/minRequired×100) per line—even when the bar is
failed—then combines with nice-to-have and confidence. If mandatoryPass is false, stored final_match_score
is half the blended score.
Mandatory lines (illustrative)
| Skill | minRequired | student score | Line fit % | Met? |
|---|---|---|---|---|
| Java | 7.0 | 3.15 | 45.0 | No |
| SQL | 6.0 | 4.54 | 75.67 | No |
Derived match fields
| Field | Value | How |
|---|---|---|
| mandatoryCoveragePct | 0 | 0 of 2 mandatory met |
| mandatoryPass | false | At least one unmet |
| mandatoryFitScore | ~60.33 | Average of 45.0 and 75.67 |
| niceToHaveFitScore | 72 | From nice-to-have requirements |
| evidence / confidence input | 62 | Mean confidence across student profiles |
| Blended (pre-gate) | ~63.5 | 0.6×60.33 + 0.25×72 + 0.15×62 |
| finalMatchScore | ~31.75 | × 0.5 when mandatoryPass is false |
API record (JobMatchResultDto fields)
| Field | Illustrative value |
|---|---|
| studentId | 120835 |
| mandatoryPass | false |
| mandatoryCoveragePct | 0.0 |
| mandatoryFitScore | 60.33 |
| niceToHaveFitScore | 72.0 |
| finalMatchScore | 31.75 |
| student | null (often filled by caller) |
Embedded match explainability (string explainabilityJson — logical columns)
| Key | Value |
|---|---|
| mandatoryCoverage | 0.0 |
| mandatoryFit | 60.33 |
| niceToHaveFit | 72.0 |
| confidence | 62.0 |
| scorePerspective | INSTITUTIONAL or EMPLOYER_VISIBLE per useEmployerVisibleScores |
| # | Check |
|---|---|
| 1 | Dynamic weights on types with score sum to 1.0 (others 0). |
| 2 | weightedCore ≈ sum of weightedContributions + completenessBonus. |
| 3 | Model raw = clamp [0,10] of (weightedCore + diversityBonus − consistencyPenalty); then profile-only cap; then skill decay; then override → matches finalScore on ledger and final_skill_score. |
| 4 | computationReason matches the trigger (e.g. EVIDENCE_UPDATE, MANUAL_RECOMPUTE, FORMULA_PUBLISH_RECOMPUTE). |
POST /skill-matrix/formula/publish (optional canary gate *
*skill.formula.canary.require-pass-for-publish**).validateFormulaConfiguration today; use checklists and reviews before publish.Guideline examples (policy, not automatic API validation):
[0.00, 0.40]).0.70).AWARDS + CONFERENCES) or research bundles (PUBLICATIONS + PATENTS) per
institutional policy.skill.compute.dlq exists for failed compute messages (replay is an ops
concern—there is no dedicated “replay” HTTP controller in this module).End-to-end behaviors below map to tables and numeric outputs in * Worked examples in tables* (Examples A–H).
EVIDENCE_UPDATE (or equivalent).version1, EXPERIENCE and PROJECTS rank above exams in weight—projects plus
internships together drive the strongest completeness story.EXAMS.EXAMS is a first-class evidence type: any exam outcome ingested as normal skill evidence (API / integrations)
flows through the same anchor, aggregation, redistribution, and ledger pipeline.EXAMS evidence rows or rubric updates consumed
here.JobMatchingService)mandatoryPass); unmet skills are listed.finalMatch = 0.6 × mandatoryFitScore + 0.25 × niceToHaveFitScore + 0.15 × confidence (on 0–100 scale
inputs as implemented).final_match_score is scaled by 0.5 relative to that formula (still persisted
for analytics).useEmployerVisibleScores=true when the requisition should align with employer-visible profiles.POST /skill-matrix/formula/canary; reports GET /skill-matrix/formula/canary/reports.POST /skill-matrix/formula/publish; optional recomputeAllStudentsAsync schedules *
*FORMULA_PUBLISH_RECOMPUTE**.FORMULA_ROLLBACK_RECOMPUTE.POST /skill-matrix/recompute?studentId= → MANUAL_RECOMPUTE.HUMAN_OVERRIDE_APPLIED.skill.compute.dlq. Monitor DLQ depth and replay or fix
poison messages using standard messaging runbooks.Reference anchors ship in V2__rubric_preset_seed.sql (tenant_id NULL). They set the institutional starting
score (0–10) used in the calibrated anchor when ingest does not override base_score. Higher = stronger default
signal for that evidence class.
| Evidence type / tier | Rubric score (0–10) | One-line meaning (from seed description) |
|---|---|---|
| (fallback) | 5.0 | Neutral anchor when no rule matches |
| PUBLICATIONS | 8.5 | Peer-reviewed / reputable publication |
| PATENTS | 9.0 | Granted patent |
| CERTIFICATIONS | 8.0 | Vendor / industry certification |
| EXAMS | 7.5 | Formal proctored or institution exam |
| EXPERIENCE | 7.5 | Employment / internship with outcomes |
| COMPETITIONS | 7.2 | Ranked or adjudicated competition |
| PROJECTS | 7.0 | Substantive project / portfolio work |
| AWARDS | 7.0 | Recognized award or honor |
| HACKATHONS | 6.8 | Time-boxed build event |
| TRAININGS | 6.5 | Structured course / workshop |
| CONFERENCES | 6.5 | Talk, poster, or participation |
| SELF_ASSESSMENT | 4.5 | Learner-declared—pair with other evidence |
| CERT … foundational | 7.0 | Entry-tier cert |
| CERT … associate | 7.5 | Associate-level cert |
| CERT … professional | 8.5 | Professional-tier cert |
| CERT … specialty | 9.0 | Specialty / expert-tier cert |
| PROJECT … course | 6.5 | Course / lab project |
| PROJECT … capstone | 8.0 | Capstone / major project |
| PROJECT … production | 8.5 | Production / real users |
Tenant overrides: tenant_id set on a row applies only to that tenant; priority and specificity decide which
row wins (RubricPresetService). GET /skill-matrix/rubric-presets/options supports UI and ingest.