UnitVO

Single-Owner Dispatch & Offer Book Manual

Technical and operational guide to UnitVO's deterministic DispatchEngine, worker eligibility, 120-second atomic OfferBook, and tenant-scoped idempotency.

1. Why Single-Owner Dispatch Matters

In buildings and hotels, broadcast group-chat messages fail because everyone assumes someone else is handling the problem. UnitVO enforces Single-Owner Dispatch: every work order has one clear owner, one response timer, and an explicit escalation path.

2. Deterministic Worker Eligibility (DispatchEngine)

The C# DispatchEngine evaluates every worker deterministically:

RuleConditionFailure Reason Code
Shift Statusworker.OnShift == trueoff_shift
Safety Pauseworker.SafetyHold == falsesafety_hold
Active Loadworker.ActiveAssigned < worker.MaxActive (unless emergency override)at_capacity
Skill Matchworker.Skills contains required skillmissing_skill
CertificationIf RequiresCert == true, worker holds valid certificationmissing_certification
LanguageIf RequiredLanguage set, worker speaks languagemissing_language
Property Accessworker.Properties includes target propertywrong_property

Eligible workers are ranked by lowest active load, highest ZoneScore, lowest FatigueScore, and deterministic lexical tie-breaking on WorkerId.

3. Atomic Offer Book & 120-Second TTL

  • One Active Offer Per Item: Creating an offer reserves the work item so two dispatchers cannot simultaneously offer the same ticket to different workers.
  • 120-Second Expiration: Unaccepted offers expire after 120 seconds (UVO-OFFER-004), releasing the item for re-dispatch.
  • Eligibility Re-Verification on Accept: When a worker taps Accept, OfferBook.Accept re-runs DispatchEngine.Eligibility against the worker's live state. If the worker went off-shift or hit capacity while the offer was pending, acceptance is rejected with worker_no_longer_eligible.

4. Tenant-Scoped Context-Bound Idempotency (ScopedRequests)

Every state-mutating request is hashed over (OrganizationId, PropertyId, ActorId, ToolName, CanonicalPayload). Retrying with the same key and identical payload replays the original result; reusing the same key with a mutated payload returns a conflict error.