بلاگ پر واپس جائیں
13 اگست، 2026Sergei Solod15 منٹ پڑھنے کا وقت

وہ ایک tick جس نے میرا CFR توڑ دیا: 5580 کیوں 5625 نہیں تھا اور 3751 کیوں 3750 نہیں تھا

میرا ویلیڈیٹر بار بار 16 fps MP4 کو رد کر رہا تھا کیونکہ ایک پیکٹ کا دورانیہ 5625 کے بجائے 5580 ٹک تھا۔ بعد میں 24 fps پر 3750 کی جگہ 3751 ٹک بھی ملا۔ ان دونوں ناکامیوں نے مجھے سورس ٹائمنگ، CFR کوانٹائزیشن، MP4 ٹائم بیس، PTS/DTS، ملٹی پلیکسنگ اور پیکٹ کی سطح کی توثیق کو الگ الگ سمجھنے پر مجبور کیا۔

FFmpegH.264CFRویڈیو ٹائم اسٹیمپسPTS اور DTSMP4 کی توثیق

ایک دن میری میڈیا پائپ لائن نے آؤٹ پٹ کا کچھ حصہ شائع کرنا بند کر دیا۔ وجہ ایک ایسی خرابی تھی جو پہلی نظر میں تقریباً مضحکہ خیز لگتی تھی:

Invalid CFR packet duration: 5580 ticks, expected 5625

ڈی کوڈر کریش نہیں ہوا تھا اور FFmpeg نے H.264 فائل بھی بنا دی تھی۔ فائل کو انکوڈنگ کے بعد میرا ویلیڈیٹر رد کر رہا تھا، کیونکہ آؤٹ پٹ کو مستقل فریم ریٹ پر ہونا تھا مگر ایک پیکٹ میری طے کی ہوئی ٹائمنگ گرڈ پر نہیں بیٹھ رہا تھا۔

میں نے کام دوبارہ چلایا۔ پھر 5580۔ ایک بار اور چلایا، پھر وہی 5580۔ بعد میں ایک دوسرے سورس نے بھی یہی قدر دی۔ یہ اہم ثبوت تھا: مسئلہ عارضی نیٹ ورک خرابی یا نایاب race condition نہیں تھا، بلکہ ایک قطعی اور بار بار پیدا ہونے والی قاعدے کی خلاف ورزی تھی۔

بعد میں ایک دوسری ناکامی ملی جو دیکھنے میں ملتی جلتی تھی مگر تکنیکی طور پر مختلف۔ 24 fps اور 90,000-tick ویڈیو ٹریک پر ہر عام نمونے کا دورانیہ بالکل 3750 ticks ہونا چاہیے تھا، مگر ویلیڈیٹر نے 3751 پکڑ لیا۔

ان دونوں کو صرف یہ کہہ کر ایک ہی وجہ سے جوڑ دینا کہ “FFmpeg راؤنڈنگ کرتا ہے” درست نہیں۔ 5580 اور 5625 میں 45 ticks، یعنی ٹھیک 0.5 ms کا فرق ہے۔ 3751 اور 3750 میں صرف ایک tick، تقریباً 11.1 مائیکرو سیکنڈ۔

ان دونوں خرابیوں نے مجھے وہ چار چیزیں الگ کرنے پر مجبور کیا جنہیں پہلے میں “FPS” کے اندر گڈمڈ کر دیتا تھا: فریم ریٹ، ٹائم بیس، PTS/DTS اور پیکٹ کا دورانیہ۔

CFR صرف “16 fps” لکھا ہوا لیبل نہیں

اب کسی بنائی گئی فائل کو CFR کہنے کا مطلب میرے لیے صرف یہ نہیں کہ ffprobe، 16/1 یا 24/1 دکھا دے۔

اس پائپ لائن میں CFR ایک زیادہ سخت قاعدہ ہے: پریزنٹیشن کے اوقات باقاعدہ گرڈ پر ہوں اور ہر عام ویڈیو نمونے کا دورانیہ اسی گرڈ کے ایک قدم کے برابر ہو۔

16 fps پر ایک فریم کا دورانیہ:

1 / 16 = 0.0625 s = 62.5 ms

اور 90,000 ticks/s ٹریک پر یہی وقفہ ایک بالکل درست صحیح عدد بنتا ہے:

90000 / 16 = 5625 ticks

اس لیے 5625 ویلیڈیٹر میں ڈالی گئی من مانی قدر نہیں تھی۔ یہ آؤٹ پٹ قاعدے کے دو فیصلوں، 16 fps اور 90,000 ticks/s، سے براہِ راست نکلتی ہے۔

یہ سخت برابری اسی لیے معقول ہے کہ میں نے جان بوجھ کر ایسی فریم ریٹس منتخب کیں جو ٹائم اسکیل کو پورا تقسیم کرتی ہیں۔ اگر ہدفی cadence ایک ہی صحیح عدد دورانیے میں ظاہر نہ ہو سکے تو ویلیڈیٹر کو درست صحیح اعداد کا پیٹرن جانچنا چاہیے، کسی ناممکن ایک قدر کو نہیں۔

فریم ریٹ، ٹائم بیس اور MP4 ٹائم اسکیل الگ چیزیں ہیں

  • فریم ریٹ پریزنٹیشن کی رفتار بتاتا ہے۔ CFR 16 کا مطلب ہے ہر 62.5 ms میں ایک فریم دکھایا جائے۔
  • FFmpeg ٹائم بیس ایک صحیح عدد timestamp یونٹ کا دورانیہ ہے، مثلاً 1/90000 سیکنڈ۔
  • MP4 ٹریک کا ٹائم اسکیل اسی تصور کو فی سیکنڈ یونٹس کی تعداد میں ظاہر کرتا ہے۔ 90,000 کا مطلب ہے کہ ایک یونٹ 1/90000 سیکنڈ کا ہے۔
  • PTS بتاتا ہے کہ تصویر کب دکھائی جائے گی۔
  • DTS بتاتا ہے کہ انکوڈ شدہ پیکٹ کب ڈی کوڈ ہونا چاہیے۔
  • پیکٹ کا دورانیہ اسٹریم کے ٹائم بیس میں نمونے کا دورانیہ بیان کرتا ہے۔

B-فریمز کے ساتھ PTS اور DTS کا مختلف ہونا بالکل درست ہو سکتا ہے۔ اس لیے timestamps “ٹھیک” کرنے کے لیے سیدھا PTS = DTS کرنا خطرناک ہے؛ setts کی سرکاری دستاویزات بھی B-فریمز کی صورت میں یہ طریقہ تجویز نہیں کرتیں۔

میرا ویلیڈیٹر دونوں قدروں کو برابر کرنے کے بجائے یہ جانچتا ہے کہ ڈی کوڈ اور پریزنٹیشن آرڈر کا باہمی تعلق درست ہے یا نہیں۔

میں نے 90,000 ticks/s کیوں چنا

90,000 کوئی عالمگیر جادوئی عدد نہیں۔ میرے لیے اس کی خوبی یہ تھی کہ پائپ لائن میں اجازت یافتہ ہر فریم ریٹ ایک بالکل درست صحیح عدد دورانیہ دیتی تھی:

فریم ریٹ90,000 ticks/s پر فریم کا دورانیہ
10 fps9000 ticks
12 fps7500 ticks
15 fps6000 ticks
16 fps5625 ticks
18 fps5000 ticks
20 fps4500 ticks
24 fps3750 ticks
25 fps3600 ticks
30 fps3000 ticks

سورس کے ملی سیکنڈ ٹائمنگ سے بھی اس کا ایک آسان تعلق ہے:

1 ms = 90 ticks

FFmpeg کے MP4 ملٹی پلیکسر میں video_track_timescale موجود ہے، اس لیے میں ٹریک کی یہ گرڈ واضح طور پر مقرر کر سکتا ہوں۔ گرڈ خود ٹائمنگ درست نہیں کرتی؛ وہ صرف قاعدے کو ناپنے اور جانچنے کے قابل بناتی ہے۔

5580 نے بتایا کہ کہاں دیکھنا چاہیے

پہلی ناکامی کو دوبارہ وقت میں تبدیل کرنے پر عدد فوراً معنی خیز ہو جاتا ہے:

5580 / 90000 = 0.062 s = 62 ms

یہ بے ترتیب قدر نہیں تھی۔ میرے پاس ایک حقیقی متحرک سورس تھا: 3.063 سیکنڈ میں 49 دکھائے گئے فریم، اور فریم کی تاخیر 62 اور 63 ms کے درمیان باری باری بدلتی تھی:

49 / 3.063 ≈ 15.997 frames/s

62 ms + 63 ms = 125 ms
2 frames at 16 fps = 2 × 62.5 ms = 125 ms

سورس کی سطح پر 62/63 ms کا باری باری آنا ملی سیکنڈ گرڈ پر 16 fps کی بالکل معقول تقریب ہے۔

لیکن CFR 16 منتخب کرنے کے بعد آؤٹ پٹ کو ہدفی گرڈ پر ہونا چاہیے: ہر عام فریم 62.5 ms یا 5625 ticks کا۔

اس لیے 5580 ایک مضبوط سراغ تھا کہ سورس کا 62 ms دورانیہ اس مرحلے تک باقی رہا جہاں ٹائمنگ کو پہلے ہی CFR گرڈ پر کوانٹائز ہو جانا چاہیے تھا۔

میں ثبوت اور اندازے کی حد واضح رکھتا ہوں۔ محفوظ شدہ لاگ ثابت کرتا ہے کہ 90 kHz پر 5580 بالکل 62 ms ہے، اور حقیقی سورس میں 62/63 ms کی تاخیر موجود تھی۔ لیکن لاگ کی ایک سطر اکیلی یہ ثابت نہیں کرتی کہ کس فنکشن نے پہلی بار اس قدر کو آگے جانے دیا۔

1000 Hz ان پٹ گھڑی غلطی نہیں تھی

میں نے FFmpeg 7.1.5 اور ffconcat کے ساتھ اس حصے کو الگ سے دوبارہ پیدا کیا۔ اس ان پٹ کے ساتھ:

duration 0.010
option framerate 1000

پیکٹ timestamps مطلوبہ ملی سیکنڈ مقامات پر برقرار رہے:

0 ms
10 ms
20 ms
30 ms

اسی ابتدائی مرحلے پر ان پٹ ریٹ 30 رکھنے سے یہی ٹائمنگ تقریباً 0 اور 33.3 ms پر کوانٹائز ہو گئی۔

لہٰذا 1000 Hz ان پٹ گھڑی صحیح کام کر رہی تھی: معتبر سورس تاخیر کو 1 ms کی درستگی سے محفوظ رکھ رہی تھی۔ اس کا مطلب یہ نہیں کہ حتمی ویڈیو 1000 fps ہوگی۔

millisecond-accurate source delays
        ↓
authoritative source timeline
        ↓
choose target CFR
        ↓
explicitly quantize onto CFR grid
        ↓
preserve that grid through encoding and muxing

زیادہ ان پٹ درستگی خرابی نہیں ہے۔ اصل مسئلہ سورس ٹائمنگ سے ہدفی CFR تک منتقلی کی واضح حد نہ ہونا ہے۔

CFR وقت کی کنٹرول شدہ کوانٹائزیشن ہے

62/63 ms والا سورس دو فریم کے جوڑوں میں 16 fps سے قدرتی طور پر میل کھاتا ہے، کیونکہ دونوں 125 ms بنتے ہیں۔ لیکن حتمی فائل 62, 63, 62, 63 ms کے دورانیے رکھ کر صرف “16 fps” کا لیبل نہیں لگا سکتی؛ وہ پھر بھی متغیر دورانیے ہیں۔

62 ms, 63 ms, 62 ms, 63 ms
              ↓
62.5 ms, 62.5 ms, 62.5 ms, 62.5 ms

FFmpeg کا fps فلٹر اس تبدیلی کے لیے مناسب جگہ ہے۔ وہ ان پٹ timestamps اور منتخب راؤنڈنگ پالیسی کے مطابق فریم حذف یا دُہرا کر ہدفی فریم ریٹ بناتا ہے۔

ایک بار یہ مرحلہ ہدفی گرڈ بنا دے تو بعد کے مرحلے کو آزادانہ طور پر دوسری فریم ریٹ تبدیلی نہیں کرنی چاہیے۔ پائپ لائن میں ایک واضح اور دانستہ کوانٹائزیشن حد ہونی چاہیے۔

تین دوبارہ کوششوں نے کچھ کیوں نہیں بدلا

FAIL: duration 5580, expected 5625
retry 1/3
FAIL: duration 5580, expected 5625
retry 2/3
FAIL: duration 5580, expected 5625

یہ قابلِ اعتماد نظام بنانے کا سبق صرف ویڈیو تک محدود نہیں۔ دوبارہ کوشش ان خرابیوں کے لیے مناسب ہے جو اگلی کوشش میں غائب ہو سکتی ہیں: نیٹ ورک کی عارضی خرابی، عارضی اسٹوریج مسئلہ، وسائل کا دباؤ یا کوئی عارضی طور پر غیر دستیاب dependency۔

لیکن ایک ہی ان پٹ اور ایک ہی الگورتھم سے پیدا ہونے والی قطعی قاعدے کی خلاف ورزی دوبارہ کوشش سے ٹھیک نہیں ہوتی۔

  • عارضی ناکامی — دوبارہ کوشش مدد کر سکتی ہے؛
  • خراب ان پٹ — اسے دوسرے راستے پر بھیجیں یا رد کریں؛
  • قطعی invariant کی خلاف ورزی — دوبارہ کوشش بند کریں اور پائپ لائن کی تشخیص کریں۔

بار بار آنے والا 5580 تیسرے گروپ میں تھا۔

پھر 3750 کے بجائے 3751 ملا

24 fps پر متوقع قدر بالکل درست صحیح عدد ہے:

90000 / 24 = 3750 ticks

پھر بھی ایک حقیقی concat شدہ آؤٹ پٹ میں ایک پیکٹ کا دورانیہ یہ تھا:

3751 ticks

فرق صرف اتنا تھا:

1 / 90000 s ≈ 11.111 µs

کوئی ناظر ایک tick محسوس نہیں کرے گا۔ اسی لیے ویلیڈیٹر کو ±1 کی رعایت دینا آسان حل لگتا تھا۔

میں نے ایسا نہیں کیا۔ اس گرڈ پر 24 fps کے لیے 3750 بالکل درست طور پر ظاہر کیا جا سکتا ہے۔ 3751 کوئی ناگزیر نمائشی سمجھوتا نہیں تھا، بلکہ ثبوت تھا کہ درست گرڈ کا invariant کہیں کھو گیا۔

اسٹریم کاپی کا مطلب یہ نہیں کہ timestamps کو چھوا ہی نہیں گیا

پائپ لائن مطابقت رکھنے والے H.264 حصوں کو دوسری lossy انکوڈنگ کے بغیر concat کرتی تھی:

ffmpeg -f concat -safe 0 -i segments.ffconcat \
  -c:v copy \
  final.mp4

-c:v copy کا مطلب ہے کہ کمپریس شدہ H.264 ڈیٹا کو ڈی کوڈ کر کے دوبارہ انکوڈ نہیں کیا جاتا۔ اس کا مطلب یہ نہیں کہ ملٹی پلیکسنگ کی سطح پر ٹائمنگ کا کوئی کام نہیں ہوتا۔

concat demuxer کی دستاویزات واضح طور پر کہتی ہیں کہ ہر فائل کا دورانیہ اگلی فائل کے timestamps کو ایڈجسٹ کرنے کے لیے استعمال ہوتا ہے۔ FFmpeg صحیح عدد timestamps کو مختلف rational time bases کے درمیان rescale بھی کرتا ہے، اور libavutil واضح راؤنڈنگ موڈز والی rescaling فنکشنز فراہم کرتا ہے۔

یہ بات میرے مخصوص 3751 کے لیے concat کو واحد سبب ثابت نہیں کرتی، مگر “bitstream کاپی ہوا ہے، اس لیے پیکٹ timestamps بدل نہیں سکتے” والا ذہنی ماڈل غلط ثابت ہوتا ہے۔

کمپریس شدہ تصویری ڈیٹا کی یکسانیت اور timestamp گرڈ کی یکسانیت الگ خصوصیات ہیں۔

PTS اور DTS کو ایک خوبصورت مساوات سے ٹھیک نہیں کیا جا سکتا

PTS = N * frame_duration
DTS = N * frame_duration

B-فریم والے H.264 میں یہ غلط ہو سکتا ہے، کیونکہ ڈی کوڈ آرڈر اور پریزنٹیشن آرڈر ایک دوسرے سے مختلف ہو سکتے ہیں۔

صحیح مقصد زیادہ محدود ہے: معتبر segment timeline سے معلوم پریزنٹیشن گرڈ اور پیکٹ کے دورانیے بحال کیے جائیں، جبکہ قانونی decode-order تعلق برقرار رہے۔

اسی لیے میں سیاق سے آزاد “جادوئی setts expression” شائع نہیں کرتا۔ درست expression کا انحصار segment boundaries، منتخب rates اور اس timing metadata پر ہے جس سے حتمی timeline بنی۔

میں نے setts کیوں استعمال کیا

FFmpeg کا setts bitstream filter ویڈیو کو decode اور دوبارہ encode کیے بغیر پیکٹ PTS، DTS، duration اور output time base بدل سکتا ہے۔

concat کے بعد normalization کے لیے یہی مناسب سطح تھی: H.264 کا کمپریس شدہ ڈیٹا ویسا ہی رہنے دیں، مگر معلوم segment metadata سے اخذ شدہ packet timeline دوبارہ نافذ کریں۔

known segment timeline
+ known CFR
+ 90000-tick grid
        ↓
known valid packet positions and durations
        ↓
normalize packet timing
        ↓
validate again

یہ “duration 3751 ہو تو ایک کم کر دو” سے بالکل مختلف ہے۔ اصلاح timing model سے نکلنی چاہیے، آج کے error message سے نہیں۔

میں نے ±1 tick کی رعایت کیوں قبول نہیں کی

بہت سے نظاموں میں چھوٹی رعایت درست ہوتی ہے۔ اگر cadence منتخب صحیح عدد time base میں بالکل درست ظاہر نہ ہو سکے تو ویلیڈیٹر کو ضروری rounding pattern ماڈل کرنا چاہیے۔

میرا قاعدہ مختلف تھا۔ اجازت یافتہ rates اس طرح منتخب تھیں کہ 90000 / fps صحیح عدد ہو:

16 fps → 5625
24 fps → 3750
30 fps → 3000

جب متوقع duration بالکل درست ظاہر ہو سکتی ہے تو عام ±1 کسی غیر واضح invariant violation کو خاموشی سے قابلِ قبول حالت بنا دیتی ہے۔

ایک tick بصری طور پر غیر اہم ہے۔ لیکن یہ غیر اہم نہیں کہ ڈیزائن کیا ہوا قاعدہ بغیر وجہ سمجھے کیوں کھو گیا۔

  • اگر گرڈ کو لازماً باری باری مختلف صحیح عدد durations استعمال کرنے ہوں تو درست pattern کی توثیق کریں؛
  • اگر duration ایک ہی درست صحیح عدد ہونا چاہیے تو عین وہی عدد لازم قرار دیں؛
  • ویلیڈیٹر کو کامیاب کرنے کے لیے ±1 کو عالمگیر شارٹ کٹ نہ بنائیں۔

میں پیکٹ کی سطح پر CFR کیسے جانچتا ہوں

avg_frame_rate جیسا stream metadata مفید خلاصہ ہے، مگر اس قاعدے کے لیے کافی نہیں۔

ffprobe -v error \
  -select_streams v:0 \
  -show_streams \
  -show_packets \
  -of json \
  final.mp4

میں اصل stream time base اور ہر پیکٹ کے pts، dts اور duration دیکھتا ہوں۔

expected = 90000 / 16   // 5625

for each normal video packet:
    assert packet.duration == 5625

assert decode ordering is legal
assert PTS/DTS relationship is legal for the codec
assert presentation timeline matches planned frame count and duration

“عام پیکٹ” کی شرط اہم ہے۔ edit lists، trimming، جان بوجھ کر خاص بنایا گیا آخری sample یا container کا کوئی اور رویہ واضح modeling مانگ سکتا ہے۔ میں اسے ہر MP4 کے لیے عالمگیر قانون نہیں کہہ رہا۔

لیکن جس generator کی ساخت میرے کنٹرول میں ہے، وہاں سخت توثیق “تقریباً 16 fps” کہنے سے کہیں زیادہ مفید ہے۔

میٹا ڈیٹا کی توثیق اور مکمل ڈی کوڈنگ الگ سوالوں کے جواب دیتی ہیں

درست timestamps یہ ثابت نہیں کرتے کہ پورا H.264 stream لازماً decode ہوگا۔ اسی طرح صاف decode یہ ثابت نہیں کرتا کہ timing contract بھی درست ہے۔

ffprobe / packet validation
→ structure, timestamps, durations, stream parameters

full decode
→ whether the complete compressed stream can actually be decoded

پیکٹ جانچ کے بعد بھی میں یہ چلاتا ہوں:

ffmpeg -v error -xerror -err_detect explode \
  -i final.mp4 -f null -

فائل صرف تب شائع ہوتی ہے جب دونوں مرحلے کامیاب ہوں۔ encoder کا exit code 0 اب میرے لیے “مکمل” ہونے کی تعریف نہیں ہے۔

دونوں ناکامیوں نے حقیقت میں کیا ثابت کیا

5580 کے لیے میں تصدیق کر سکتا ہوں: دوبارہ کوششوں میں وہی قطعی قدر آئی؛ 90 kHz پر 5580 بالکل 62 ms ہے؛ حقیقی سورس میں 62/63 ms تاخیر موجود تھی؛ CFR 16 کو 62.5 ms یا 5625 ticks چاہیے؛ اور 1000 Hz ان پٹ تجربے نے ملی سیکنڈ تاخیر درست محفوظ رکھی۔

یہ سورس duration کے اس مرحلے تک رسنے کی مضبوط وضاحت بنتی ہے جہاں CFR پہلے ہی بن چکا ہونا چاہیے تھا، مگر محفوظ شدہ error line اکیلی درست مسئلہ پیدا کرنے والا فنکشن ثابت نہیں کرتی۔

3751 کے لیے میں یہ بھی تصدیق کر سکتا ہوں کہ حقیقی آؤٹ پٹ میں 24 fps کے متوقع 3750 کی جگہ 3751-tick پیکٹ تھا؛ پائپ لائن stream-copy concat استعمال کرتی تھی؛ concat کے بعد packet normalization میں setts حل کا حصہ بنا؛ اور FFmpeg concat timestamp adjustment اور packet-level timestamp rewriting دونوں دستاویز کرتا ہے۔

یہ حقائق integer rescaling یا muxing/concat boundary rounding کے ساتھ مطابقت رکھتے ہیں، مگر “concat ہمیشہ ایک tick بڑھاتا ہے” ثابت نہیں کرتے۔

اب میرا عملی طریقۂ کار

  1. اندازے والے FPS فیلڈ کے بجائے معتبر سورس timeline دوبارہ بناتا ہوں۔
  2. اصل ملی سیکنڈ تاخیر کافی درست input clock پر محفوظ رکھتا ہوں۔
  3. ہدف CFR الگ سے منتخب کرتا ہوں۔
  4. سورس timeline کو واضح طور پر CFR گرڈ پر کوانٹائز کرتا ہوں۔
  5. جہاں ممکن ہو ایسا track timescale استعمال کرتا ہوں جو اجازت یافتہ rates کو بالکل درست ظاہر کرے۔
  6. انکوڈنگ کے بعد کسی اگلے مرحلے کو frame-rate conversion دوبارہ آزادانہ طور پر نہیں کرنے دیتا۔
  7. concat سے پہلے time base، frame count، PTS/DTS اور packet duration کی توثیق کرتا ہوں۔
  8. stream-copy concat سے پہلے codec configuration اور timing compatibility جانچتا ہوں۔
  9. concat کے بعد packet grid دوبارہ دیکھتا ہوں؛ -c:v copy کو timestamp identity کا ثبوت نہیں سمجھتا۔
  10. اگر normalization درکار ہو تو اسے معلوم timeline سے اخذ کر کے packet level پر لاگو کرتا ہوں۔
  11. ہر پیکٹ دوبارہ validate کرتا ہوں۔
  12. حتمی فائل مکمل decode کرتا ہوں۔
  13. تمام قواعد پاس ہونے کے بعد ہی atomically شائع کرتا ہوں۔

میرا آخری اصول: CFR ایک صحیح عدد timing contract ہے

پہلے 16 fps خود ہی کافی وضاحت لگتا تھا۔ اب نہیں۔

time base = 1/90000
normal frame duration = 5625 ticks
presentation cadence = 62.5 ms
packet timeline follows that grid
PTS/DTS remain legal for H.264 reordering

5580 اہم تھا کیونکہ اس نے پرانی ملی سیکنڈ گرڈ ظاہر کر دی۔ 3751 اس لیے اہم تھا کہ وہ تقریباً غیر مرئی تھا: صرف ایک tick کافی تھا یہ ثابت کرنے کے لیے کہ نظام نے وہ invariant محفوظ رکھنا چھوڑ دیا ہے جسے ڈیزائن کے مطابق برقرار رہنا چاہیے تھا۔

اب میرا قاعدہ سادہ ہے: “CFR” کے لیبل کو validate نہ کریں؛ اس timing کو validate کریں جس سے وہ لیبل درست ثابت ہونا چاہیے۔

بنیادی دستاویزات