Skip to Content

Task Delivery

The task delivery service (WP-DTE-BE, modules/delivery) selects a stored, render-ready item from the item bank and serves it exactly as stored. The platform never composes, templates, or generates content at runtime.

Item-bank-only model

All items are authored and validated offline, then imported into the item bank through an import pipeline that runs Arabic agreement checks (gender, number, case), metadata validation, language-safety screening, and difficulty-prior (delta_prior) computation at import time. By the time an item enters the bank it is ready to be served without any runtime transformation.

When the delivery service runs, it does exactly three things: filter, serve, and log. No content is assembled, no language model is invoked, and no template is expanded.

Selection filters

Each serve request specifies a target context. The engine applies the following predicates in combination:

FilterDescription
subSkillIdMust match the sub-skill being practiced or assessed
taskModepractice, quick_check, or probe; each has distinct UX rules
scaffoldTierLevel_1_Foundation, Level_2_Targeted, or Level_3_Independence (probes skip tier)
difficultyBandDifficulty band anchored to delta_prior
dialectMSA / LEV; items whose dialect tags are absent are treated as dialect-agnostic
Recently servedItems served to the same student in the recent-serve window are excluded

When multiple items pass all filters the engine applies a fully deterministic tie-break: closest difficulty band first, then delta_prior ascending, then itemBankId lexicographic. The selection is byte-identical for identical inputs, which satisfies the V-6 determinism rule.

Scaffold tier resolution

The scaffold tier is per (student × skill × bundle × task type), never a global student-level attribute. For tiered task modes (practice or quick_check within an active bundle) the delivery service looks up the student’s student_scaffold_assignment row. If no assignment exists the serve returns no_eligible_item. A random fallback tier is never applied.

Probes (diagnostic quick_check outside a bundle) select tier-agnostically.

The no_eligible_item response

When no item passes all filters the response is still HTTP 200: the serve did not fail. The response body carries served: null plus a reason of no_eligible_item. The caller is responsible for surfacing the right UX.

Every no_eligible_item outcome writes a gap-queue row. The admin gap summary endpoint aggregates these rows by (sub_skill × tier × mode) so that offline content authoring teams know exactly which combinations need new items.

no_eligible_item is not an error. It is a gap signal. Never treat it as a 4xx or 5xx. Surface it to the content pipeline so the gap is filled offline.

Served-task-instance audit

Every successful serve writes a served_task_instance row with a UUID primary key. This UUID is the join token for printed QR worksheets (session-gen and paper-scan flows). UUIDs are non-enumerable and globally unique, making them safe to embed on physical paper, unlike auto-increment integers.

The audit row pins the following for permanent reproducibility:

  • Item-bank snapshot version and selection-policy version
  • Scaffold tier and rule version used
  • The recently-served exclusion window
  • Request context (sub-skill, mode, band, dialect)

Dry-run replay (V-6 verification)

POST /api/admin/delivery/dry-run-replay re-runs item selection against the same pinned versions. It writes nothing. The response reports whether each replayed request returns the byte-identical item. A false result is a determinism regression.

API reference

MethodPathPermissionNotes
POST/api/delivery/taskVIEW_OWN_CLASSES or RUN_BACKOFFICEServe one item; served:null is 200
GET/api/delivery/log/{taskInstanceId}RUN_BACKOFFICEFull serve audit for one instance
GET/api/admin/delivery/gap-summaryRUN_BACKOFFICEGap counts by (sub_skill × tier × mode)
POST/api/admin/delivery/dry-run-replayRUN_BACKOFFICEV-6 determinism assertion; read-only

There is no student-facing delivery endpoint. All delivery routes require a teacher or admin permission. Students never make direct calls to this service (B.17).

What delivery does not do

  • It does not generate or compose content at runtime.
  • It does not invoke a language model at any point.
  • It does not fall back to a substitute item when the requested tier has no match.
  • It does not validate Arabic agreement at serve time (that check runs at import).
  • It does not expose a student-facing endpoint.
Last updated on