لا يمكن إرفاق مصحح في الإنتاج
يظهر المصحح العملية من الداخل — لكن لا يمكن إرفاقه في الإنتاج، والتشغيل الحي لا يترك ما يمكن الإمساك به.
أثناء التطوير، يجمّد المصحح التنفيذ عند أي خطوة: تظهر المعاملات، والقيم الوسيطة، وما سينتقل لاحقًا. في الإنتاج هذا غير ممكن — لا يمكن إيقاف العملية الجارية من أجل طلب واحد، والمدخلات النادرة يصعب إعادة إنتاجها. كما لا يمكن مراقبة التشغيل أثناء سيره: فسلسلة الاستدعاءات تعيش في مكدس الاستدعاءات، وقيمها الوسيطة في المتغيرات المحلية، وبمجرد أن يعيد الاستدعاء التحكم، يختفي كل ذلك. تحتفظ السجلات بالقيم المختارة مسبقًا فقط؛ أما التتبع التقني فيرى الاستدعاءات ومدتها، لكنه لا يعرف أيّ منها خطوات تجارية، وأيّ القيم الوسيطة بينها مهمة. يتعين تخمين السبب من مؤشرات غير مباشرة.
البيانات موجودة أثناء التنفيذ — والمصحح يثبت ذلك. المفقود هو أمر آخر: حدّ معروف مسبقًا للتشغيل ولكل خطوة من خطواته، يمكن أن تُرفق به مراقبة أونلاين — دون إيقاف العملية الجارية.
{ validated_items: 3 } · كل القيم مرئيةإيقاف مؤقّت عند أي خطوة — state بأكمله مرئي
لا يمكن الإيقاف — الوسط غير مرئي
حدود التشغيل محددة سلفًا من قبل العمارة
لمراقبة التشغيل ككل، يجب أن يكون له حدّ دقيق — ولكل خطوة من خطواته أيضًا.
في AOA، العملية هي Action له حدّ خارجي هو Params → Result. تشغّلها الآلة — محرك AOA الذي ينفذ Action ويعرف سلفًا أين يبدأ التشغيل وأين ينتهي. في الداخل، ينقسم المسار إلى Aspects، ولكل منها حالته الوسيطة الخاصة، أي state. يستقبل الـ Aspect لقطة من الـ state السابق ويعيد state جديدًا خاصًا به — يحل هذا الجديد محل السابق بالكامل، لا يكمله. لذلك ينقل الـ Aspect صراحةً كل ما تحتاجه الخطوات التالية، ولا يتسرب شيء بين الخطوات من تلقاء نفسه؛ ويتحقق @result_* من المخرجات مباشرة عند الحدّ. هذه الحدود ليست أداة مراقبة، بل هي بنية العملية نفسها؛ لكنها بالضبط ما يمنح نقاطًا معروفة سلفًا يظهر عندها مدخل كل خطوة ومخرجها و state.
تعرف الآلة في أي لحظة إطار التشغيل ومساره التعاقدي بالكامل: ما الذي دخل كل Aspect وأي state خرج منه. الأثر القابل للملاحظة «تشغيل واحد» مجمّع بالفعل بواسطة العمارة نفسها — لم يبقَ سوى إطلاقه إلى الخارج.
{ }{ validated_items: 3 }{ validated_items: 3 }{ …, reservation_id: 'res_42' }{ …, reservation_id: 'res_42' }{ …, payment_id: 'pay_91' }التصحيح الأونلاين: التشغيل الحي مرئي من الخارج
بما أن الحدود معروفة، تصدر الآلة عند كل واحد منها حدثًا — ويجمع مراقب خارجي منها صورة حية للتشغيل.
عند الحدّ الخارجي تظهر القيم الفعلية لـ Params و Result، وعند كل حدّ داخلي — الـ state الوارد والصادر، والمدة، والخطأ. تعرف الآلة كل هذه النقاط وتصدر lifecycle events تلقائيًا؛ وتستقبلها إضافة من الخارج فتبني إسقاطًا أونلاين لتشغيل محدد — شجرة من الخطوات بمدخلات ومخرجات وأخطاء وأوقات حقيقية. الأمر نفسه في التطوير، وفي الاختبارات، وفي الإنتاج — دون استدعاءات تسجيل، أو مؤقّتات يدوية، أو كود تتبع داخل الطرق التجارية.
هذا ليس مصححًا مرفقًا ولا إيقافًا للعملية الجارية، بل هو إسقاطها الأونلاين الآمن. لا يرى المراقب سوى ما يسمح به العقد: تبقى الحقول الحساسة معتمة، ويكون عطل الإضافة نفسها معزولًا فلا يغيّر نتيجة العملية. هذا بالضبط هو Action X-Ray.
- start · Params
- validate · state → state′ · 0.4 ms
- reserve · state′ → state″ · 12 msمعتم
- charge · error · 3 ms
- finish · Result · 15 ms
تسلم الإضافة إلى الآلة عند الإنشاء — وتبقى الطرق التجارية دون مساس:
plugin = OpenTelemetryPlugin( tracer_provider=tracer_provider, logger_provider=logger_provider, service_name="checkout-service",)# The plugin lives outside the Action; business methods stay untouched.machine = ActionProductMachine(plugins=[plugin])result = await machine.run(Context(), CreateOrderAction(), params)في الاختبار — الأشعة السينية نفسها
اللقطة الأونلاين نفسها متاحة في الاختبار أيضًا: يشغّل TestBench العملية نفسها عبر الآلة نفسها.
لا ينشئ TestBench رؤية اختبارية خاصة — بل يشغّل الـ Action نفسه عبر الآلة نفسها والحدود نفسها. لا يتغير سوى العالم الخارجي: فبدلًا من الـ Context الخاص بالإنتاج و Resources و gateway، تستخدم تطبيقاتها الاختبارية، بينما تبقى roles و pipeline و checkers وتجميع Result حقيقية. يمكن تشغيل العملية بالكامل أو التوقف عند حدّ واحد — Aspect أو summary أو compensator — دون أي خطافات خاصة في الكود التجاري.
يتحقق الاختبار من الإسقاط نفسه المتاح في الإنتاج: ليس فقط Result النهائي، بل أيضًا أي state وسيط. يتغير الواقع المحيط بالعملية، لا العملية نفسها ولا طريقة مراقبتها.
roles · pipeline · checkers · تجميع Resultالإسقاط الأونلاين نفسهنفس الـ Action عبر TestBench — بالكامل أو عند حدّ واحد:
inventory = AsyncMock(spec=InventoryGateway)inventory.reserve.return_value = "res_42"bench = TestBench().with_user( user_id="customer", roles=(CustomerRole,)).with_mocks({InventoryGateway: inventory})# The whole operation — same machine, same boundariesresult = await bench.run(CreateOrderAction(), params, rollup=False)# Or stop at a single boundary and inspect its statestate_after = await bench.run_aspect( CreateOrderAction(), "reserve_aspect", params=params, state={"validated_items": 3},)assert state_after["reservation_id"] == "res_42"يصبح التصحيح الأونلاين خاصية من خصائص العمارة
يحدد AOA الحدّ الخارجي لـ Action وحدوده الداخلية على مستوى Aspects، ويحوّل state وسيطًا إلى عقد. أثناء التشغيل، تصبح هذه الحدود نفسها نظام إحداثيات لـ lifecycle events — والرؤية التي كانت تظهر سابقًا فقط تحت مصحح أو بعد إضافة أدوات قياس يدويًا، أصبحت الآن متاحة أونلاين لكل تنفيذ، بما في ذلك الإنتاج، دون أي كود بنية تحتية داخل العملية.
