---
type: reference
title: عقد إعادة التشغيل
summary: عقد run/seed/verdict الإلزامي الذي يجعل لعبة قابلة لإعادة التشغيل، وما تستقبله دالة run وتعيده، وكيف تربط البذرة أثرًا بجولة واحدة، وكيف يعيد الخادم تشغيله.
---

عقد إعادة التشغيل هو السطح الإلزامي الوحيد الذي تتّفق عليه لعبة **قابلة لإعادة التشغيل** مع المنصّة. يُنشَر كـ `@caputchin/replay-contract`: حزمة ضئيلة عمدًا بلا اعتماديات (تُحمَّل في عازل إعادة تشغيل مختوم، فلا تجرّ شيئًا). كل ما عداه عن لعبتك، المحرّك، والعارض، وهيئة الأثر، لك.

لعبة تشحن `run` مطابقًا **قابلة لإعادة التشغيل** فتستطيع **حراسة** مفتاح موقع؛ ولعبة بلا واحد ما زالت قابلة للتضمين، لكن كتجربة استخدام فقط (تُظهر **غير قابلة للإعادة**). انظر [اشحن لعبة إلى المتجر](/docs/marketplace-game-development/overview#replayable-vs-not-replayable) لذلك التمييز.

## دالة `run`

لعبة قابلة لإعادة التشغيل تشحن وحدة JS أو WASM تصدّر دالة واحدة اسمها `run`:

```ts
run(seed, config, trace) -> { passed, score, durationMs }
```

```ts
type RunFn<C = unknown> = (
  seed: Seed,
  config: C | null,
  trace: Uint8Array | string,
) => Verdict | Promise<Verdict>
```

| الوسيط | المصدر | المعنى |
|---|---|---|
| `seed` | الخادم | [بذرة](#the-seed) كل جولة. إعداد الجولة المملوك للخادم. |
| `config` | الخادم | إعداد اللعب، **قابل لأن يكون null ومعتم**: لا تفحصه المنصّة أبدًا، ويُعاد حلّه على الخادم عند إعادة التشغيل، لا يدّعيه العميل أبدًا. `null` يعني "استخدم افتراضيات run الخاصة". في الـ MVP يمرّر الخادم `null`؛ والإعداد لكل موقع مرحلة مؤجَّلة. |
| `trace` | العميل | الكتلة المعتمة التي بثّها عميل اللاعب، التي تفسّرها هذه الدالة وحدها. لا تحلّلها المنصّة ولا تكتب نوعها أبدًا؛ إنها بايتات خام أو نصّ، محدودة فقط بسقف حجم وحدّ وحدة معالجة العازل. |

ترتيب الوسائط يرمّز نموذج الثقة: `seed` و`config` إعداد الجولة على الخادم؛ و`trace` مُدخَل اللاعب. **القيم المؤثّرة في البوّابة (عتبة نجاح، أرواح) آمنة لقراءتها من `config` لكنها ستكون تجاوزًا لو قُرئت من `trace` العميل.**

يجب أن تصدّر الوحدة الدالة باسم `run` (الثابت `RUN_EXPORT_NAME`). يستدعيها مضيف إعادة التشغيل وينتظر النتيجة (إنشاء WASM غير متزامن في أول نداء).

## البذرة [#the-seed]

```ts
type Seed = readonly [number, number, number, number]   // 128 bits, 4 u32 words, MSW first
```

البذرة هي أدنى 128 بتًّا من `SHA-256(sessionId : gameId : roundIndex)`، محمولة كأربع كلمات 32-بتية غير موقّعة، الكلمة الأكثر دلالة أولًا. `deriveSeed(sessionId, gameId, roundIndex)` في الحزمة يحسبها؛ يشتقّها الخادم عند إصدار الجولة وعند إعادة تشغيلها مجدّدًا، فلا تركب السلك أبدًا كمُدخَل عميل موثوق.

والأهمّ، تربط البذرة **أثرًا بجلسة ولعبة وجولة واحدة**: إعادة تشغيل أثر غريب أو أقدم تحت بذرة مختلفة تنتج `passed: false`. ذلك الربط هو كيف يُدافَع عن حقن الأثر وهجمات إعادة التشغيل، فيجب أن تبذر كل العشوائية منها كي يتّفق اللعب الحيّ وإعادة تشغيل الخادم.

## الحُكم

```ts
interface Verdict {
  readonly passed: boolean      // drives the verification decision
  readonly score: number        // game-defined, any finite number
  readonly durationMs: number   // finite, non-negative
}
```

`passed` هو الحقل الوحيد الذي يقود قرار الـ captcha؛ و`score` و`durationMs` محمولان في الرمز المُصدَر (ولوحة نتائج مستقبلية). `parseVerdict(value)` في الحزمة يتحقّق من قيمة عائدة غير موثوقة و**يعامل نتيجة مشوّهة كجولة مرفوضة، لا ناجحة أبدًا**، فـ `run` يرمي أو يعيد قمامةً يفشل مغلقًا.

## الحتمية هي المتطلّب كله [#determinism-is-the-whole-requirement]

قاعدة العقد الصارمة الوحيدة: يجب أن يكون `run` **نقيًّا وحتميًّا عبر زمني تشغيل**، متصفّح اللاعب وعازل الخادم. `(seed, config, trace)` متطابق يجب أن ينتج حُكمًا متطابقًا في كليهما. الطرق الشائعة لكسر هذا، كلها يمسكها الفحص الذاتي للنشر كـ `run-not-conforming`:

- قراءة `Date.now()`، أو `performance.now()`، أو `Math.random()`، أو متغيّرات عامة أخرى غير حتمية؛
- قراءة حالة خارجية (DOM، شبكة، تخزين) لا يقدّمها عازل إعادة التشغيل؛
- الاعتماد على حساب فاصلة عائمة يختلف بين زمني التشغيل.

كيف تحقّق الحتمية (فاصلة ثابتة، أو فواصل WASM-spec، أو IEEE-754 إضافةً إلى غلاف تحييد) خيارك؛ المنصّة تستضيف إعادة التشغيل فقط. [عدّة المحرّك](/docs/marketplace-game-development/engine-kit) تقدّم أوّليات حتمية جاهزة إن آثرت ألّا تصنع خاصتك.

## كيف يستخدمه الخادم

```mermaid
sequenceDiagram
  participant P as متصفّح اللاعب
  participant S as خادم Caputchin
  participant R as عازل إعادة التشغيل
  S->>S: deriveSeed(sessionId, gameId, round)
  S->>P: أصدِر الجولة بالبذرة
  P->>P: العب، مسجّلًا الأثر
  P->>S: أرسِل الأثر عند النجاح
  S->>S: أعد اشتقاق البذرة نفسها
  S->>R: run(seed, config, trace)
  R-->>S: الحُكم { passed, score, durationMs }
  S->>S: parseVerdict، وقرّر
```

الأداة التي يحمّلها العازل هي حزمة `run` خاصتك، إمّا `entry` الحيّة أو [أداة `run`](/docs/marketplace-game-development/the-caputchin-json-manifest#the-run-artifact) المخصّصة من البيان.

## انظر أيضًا

- [عدّة engine-kit](/docs/marketplace-game-development/engine-kit): أنتج `run` مطابقًا من مُختزِل عادي، بالحتمية متولّاةً عنك.
- [بيان caputchin.json](/docs/marketplace-game-development/the-caputchin-json-manifest#the-run-artifact): إعلان أداة `run` ووحداتها.
- [ابنِ لعبة المتجر](/docs/marketplace-game-development/build-a-marketplace-game): تسجيل الأثر الذي يعيد هذا العقد تشغيله.
- [مرجع أخطاء النشر](/docs/marketplace-game-development/publish-failed-reference): نتيجة الفحص الذاتي `run-not-conforming`.
