منحنى تطوّر نموذجك قد يكون كاذباً — واثنتا عشرة سطراً تكشف ذلك.
أداة صغيرة تفصل عمق النموذج عن سهولة المهمّة في منحنيات التقييم. بلا اعتماديات، وبحدودها معلَنة قبل استعمالها.
(الدالّة الأساسيّة muayara() اثنتا عشرة سطراً فعّالاً، والمحرّك كلّه سبعة
وثلاثون — مقيسة بـast لا محسوبة بالعين.)
هديّة مفتوحة من عماد سليمان علوان — UP2U2B LLC · الرياض.
تُقيَّم النماذج يوماً بعد يوم على مهامّ متغيّرة. وإذا رُسم منحنى الدرجات الخام عبر الزمن، فقد خلط المنحنى كمّيتين لا تفترقان:
درجة اليوم = عمق النموذج + سهولة مهمّة اليوم
فارتفاع المنحنى قد يعني «سهُلت المهمّة» لا «عَمُق النموذج».
وخطورته أنّه لا يُظهر نفسه: الأرقام صحيحة، والحساب سليم، والرسم جميل، ولا اختبار يسقط — والاستنتاج وحده باطل. تقرأ صعوداً فتقول «تحسّن»، وقد يكون الذي تغيّر هو المهمّة.
إن كان أكثر من متسابق يخوض المهمّة نفسها في اللحظة نفسها، فمتوسّط درجات تلك المهمّة هو مقياس صعوبتها. فيُطرح:
المعايَر(نموذج، مهمّة) = درجته − متوسّط درجات المهمّة نفسها
الصعوبة تسقط جبراً لا تخميناً: مجموع الانحرافات على المهمّة الواحدة صفر بالضرورة، فأيّ إزاحة في صعوبتها تزيح الجميع معاً ولا تغيّر انحراف أحد.
لا معامل يُضبط، ولا نموذج يُدرَّب، ولا افتراض توزيع. الخاصيّة هي الحلّ.
python3 muayara.py --burhanالبرهان — المهمّة سهُلت 10 درجات ولم يتغيّر ترتيب أحد:
صعوبة المهمّة: 12.5 ⟶ 22.5 (+10)
🔴 الخام «أ»: 5.0 ⟶ 15.0 (+10) ← مُضلِّل
✅ المعايَر «أ»: -7.5 ⟶ -7.5 (Δ=0) ← الصعوبة سقطت
ولو تحرّك المعايَر هنا لكانت الأداة وهماً ووجب إطفاؤها. ولهذا هذه الحالة
اختبارٌ في tests/ يسقط إن انكسرت الفكرة — لا فقرةٌ في وثيقة.
from muayara import silsila
# [(مفتاح زمنيّ، {اسم المتسابق: الدرجة}), ...]
natija = silsila([
("2026-01-01", {"model-a": 12, "model-b": 18, "model-c": 15}),
("2026-01-02", {"model-a": 20, "model-b": 26, "model-c": 23}), # مهمّة أسهل
# ...
])
for nafidha in natija:
print(nafidha["min"], "→", nafidha["max"])
print(" صعوبة المهامّ:", nafidha["suuba"]) # المُربِك مرسوماً صريحاً
print(" الخام: ", nafidha["kham"]) # يُعرض ليُرى التضليل
print(" المعايَر:", nafidha["muayar"]) # الصعوبة مطروحة
print(" أصفار: ", nafidha["asfar"]) # الفشل الصامت معدوداًمثال عامل كامل: examples/mithal.py — وقراءة نتيجته
تُحسب في الكود ولا تُكتب بيد.
None تعني «لا مِجَسّ» (العيّنة دون النصاب) — لا صفراً. والخطّ يُقطع
ولا يُوصل، لأنّ وصله يرسم علماً لا نملكه.
① تقيس التفاضل لا الارتقاء. لو تحسّن الجميع معاً بقي الجميع عند الصفر. ارتفاع نموذج يعني «سبق أقرانه» لا «عَمُق في ذاته». والارتقاء الجماعيّ خارج مدى هذه الأداة ويحتاج مهمّة مرجعيّة مجمّدة. (وهذا الحدّ منفَّذ في اختبار — لا موصوف في وثيقة.)
② النصاب خمسة. نافذة دون خمسة صفوف تُرجع None ولا يُنطق برقم.
③ الأصفار تُعدّ ولا تُحذف. الفشل الصامت يُخرج صفراً، وحذفه تجميل.
④ مهمّة بمتسابق واحد لا تُعايَر — لا متوسّط يُطرح منها.
⑤ تحتاج متسابقين على المهمّة نفسها. إن كان عندك نموذج واحد فهذه الأداة لا تنفعك — والصادق أن يُقال ذلك، لا أن يُباع الرقم.
الكود اثنتا عشرة سطراً. والذي يستحقّ النقل أربع قواعد:
١ · لا يُعرض رقم لم يُقَس بما يدّعي أنّه يقيسه.
عدد الأسطر في عنوان هذا الملفّ كان مكتوباً بيد فأُخطئ فيه، ثمّ قيس بـast
واستُدرك — والاستدراك في سجلّ القيود لا مطموس.
٢ · الضابط السالب قبل الموجب. اختبار ينجح لا يُثبت شيئاً وحده. الذي يُثبت: حالة لو مرّت لكانت الأداة كاذبة. هنا: مهمّة سهُلت والمعايَر لا يتحرّك. ابنِ اختبارك من هذه أوّلاً.
٣ · الحدّ يُعلَن قبل أن يُسأل عنه. من يذكر حدود أداته قبل أن يكتشفها المستعمِل يبيع أداة. ومن ينتظر السؤال يبيع انطباعاً.
٤ · «لا أعلم» نتيجة تُحمد.
None هنا ليست عطباً يُخفى — هي جواب: العيّنة لا تكفي. والصفر الكاذب
أسوأ من الفراغ الصادق.
من نظام يربّي نماذج ذكاء بالعربية بمنهجيّة موثّقة، لكلّ أثر فيه ختم زمنيّ وحرّاس يكشفون كذب النموذج نفسه.
كان في لوحة متابعته منحنى تطوّر يصعد. وكان يصعد مع سهولة الدرس. والعطب كان مسمّى في وثائقه قبل أن يُرسم المنحنى — فبُنيت هذه المعايرة لتفصل الاثنين، ثمّ نُشرت لأنّ العطب الذي وقعنا فيه يقع فيه غيرنا، ومن عرف عطباً فكتمه فقد كتم نصف العلم.
أساس هذا المشروع أب.
بُني هذا كلّه على فكرة واحدة: أنّ الإنسان يُورِّث منهجه لا مكاسبه — وأنّ الأب لا يعطي ابنه سمكة ولا صنّارة فحسب، بل الميزان الذي يعرف به الصادق من الكاذب حين لا يكون الأب حاضراً.
وأداة قياس تُخفى ليست ميزاناً؛ هي مفتاح خزنة. والميزان يُعطى.
فهذه إسهام — لكلّ أب في هذا الوطن يبني شيئاً ويريد أن يعرف: أتحسّن عملي حقّاً، أم أنّ الطريق سهُل؟ ولكلّ باحث عربيّ يقيس نموذجاً بلسانه — فأدوات التقييم العربيّة قليلة وأكثرها منصبّ على الهلوسة والسلامة، وقلّ ما يُكتب بالعربية في انضباط القياس نفسه.
خُذها كما هي، وحسّنها، وانسبها لمن بناها — وأعطِ أنت أيضاً.
الملاحظة والإصلاح مرحّب بهما. وأثمن ما تُرسله: ضابط سالب يكشف حدّاً لم نُعلنه. من أراك عطباً في عملك فقد أهداك أكثر ممّا أهديت.
Apache License 2.0 — انظر LICENSE وNOTICE. حقوق النشر © 2026 عماد سليمان علوان · UP2U2B LLC.
Your model's progress curve may be lying to you. Twelve lines catch it.
A small tool that separates model depth from task easiness in evaluation curves. Zero dependencies, and its limits are declared before use, not after.
An open gift from Emad Sulaiman Alwan — UP2U2B LLC · Riyadh.
Models are evaluated day after day on changing tasks. Plot the raw score over time and the curve has conflated two quantities:
today's score = model depth + today's task easiness
A rising curve may mean "the task got easier", not "the model got better."
What makes it dangerous is that it does not announce itself: the numbers are right, the arithmetic is sound, the chart is beautiful, no test fails — only the conclusion is wrong.
If more than one contestant takes the same task at the same moment, then that task's own mean is its difficulty. Subtract it:
calibrated(model, task) = its score − mean score on that same task
Difficulty cancels algebraically, not by estimation: deviations on a single task sum to zero by construction, so any shift in its difficulty moves everyone together and changes nobody's deviation.
No coefficient to tune, no model to train, no distributional assumption. The property is the fix.
python3 muayara.py --proofA task gets 10 points easier. Nobody's rank changes. The raw curve rises by 10. The calibrated curve does not move.
If it ever did move, the tool would be a lie and should be switched off — which
is why that exact case is a test in tests/ that fails if the idea breaks,
not a paragraph in a document.
from muayara import silsila
results = silsila([
("2026-01-01", {"model-a": 12, "model-b": 18, "model-c": 15}),
("2026-01-02", {"model-a": 20, "model-b": 26, "model-c": 23}), # easier task
])
for w in results:
print(w["min"], "→", w["max"])
print(" task difficulty:", w["suuba"]) # the confounder, drawn explicitly
print(" raw: ", w["kham"]) # shown so the illusion is visible
print(" calibrated: ", w["muayar"]) # difficulty subtracted
print(" zeros: ", w["asfar"]) # silent failures, countedNone means "no reading" (sample below quorum) — never zero. The line
breaks rather than connecting, because connecting it would draw knowledge we do
not have.
- Measures relative standing, not absolute growth. If everyone improves together, everyone stays at zero. A model rising means it outpaced its peers, not it deepened. Collective growth is outside this tool's range and needs a frozen reference task. (Enforced by a test, not documented.)
- Quorum is five. Fewer rows in a window returns
None; no number spoken. - Zeros are counted, never dropped. A silent failure scores zero; deleting it is cosmetics.
- A task with one contestant is skipped — there is no mean to subtract.
- You need multiple contestants on the same task. With a single model this tool is useless — and saying so is more honest than selling the number.
The code is twelve lines. What deserves copying is four rules:
1 · Never show a number that wasn't measured by what it claims to measure.
The line count in this file's headline was once written by hand and was wrong;
it is now counted with ast, and the correction sits in the commit log rather
than being erased.
2 · Negative controls before positive ones. A passing test proves little on its own. What proves something is a case that, had it passed, would have made the tool a liar. Here: a task got easier and the calibrated value did not move. Build that test first.
3 · Declare the limit before anyone asks. Whoever states their tool's limits before the user discovers them is selling a tool. Whoever waits for the question is selling an impression.
4 · "I don't know" is a result worth reporting.
None here is not a defect to hide — it is an answer: the sample is not
enough. A false zero is worse than an honest blank.
From a system that raises AI models in Arabic under a documented methodology, where every trace carries a timestamp seal and guards flag the model's own false claims.
Its dashboard had a progress curve that kept rising. It was rising with the lesson getting easier. The defect had been named in the project's own documents before the curve was ever drawn — so this calibration was built to separate the two, and then published, because a defect we fell into is one others fall into, and whoever knows a flaw and hides it has hidden half the knowledge.
The foundation of this project is fatherhood.
All of it rests on one idea: that a person bequeaths their method, not their gains — and that a father gives his child neither a fish nor merely a rod, but the scale by which truth is told from falsehood for when the father is not there.
A measuring tool kept hidden is not a scale; it is a vault key. Scales are meant to be handed over.
So this is a contribution — for every parent building something who needs to know: is my work actually improving, or did the road just get easier? And for every Arabic-speaking researcher measuring a model in their own tongue — Arabic evaluation resources exist but are few and mostly aimed at hallucination and safety; little is written in Arabic about measurement discipline itself.
Take it as it is, improve it, credit whoever built it — and give something yourself.
Issues and fixes are welcome. The most valuable thing you can send is a negative control that exposes a limit we failed to declare. Whoever shows you a flaw in your work has given you more than you gave them.
Apache License 2.0 — see LICENSE and NOTICE. Copyright © 2026 Emad Sulaiman Alwan · UP2U2B LLC.