ServicesMatchmaking

Rulesets and Constraints

A ruleset decides who may be matched with whom. It is created once, named, and attached to any number of pools via ruleset_id. Two rule lists with different jobs:

  • Hard constraints must all evaluate true for a candidate group, or the group is discarded.
  • Soft preferences are scored and weighted; among the groups that pass the hard constraints, the highest-scoring one wins.

The rule shape

Each rule is { "rule_id", "expression", "description"?, "weight"? } (weight defaults to 1.0 and only matters for soft preferences). The expression is a tagged tree - every node is { "type": "<Operator>", "value": ... }, not a flat attribute/operator object:

{
  "type": "Equal",
  "value": {
    "left":  { "type": "TicketAttribute", "value": { "ticket_index": 0, "path": "region" } },
    "right": { "type": "TicketAttribute", "value": { "ticket_index": 1, "path": "region" } }
  }
}

TicketAttribute reads a field from a candidate ticket's attributes by position in the group (ticket_index 0 is one ticket, 1 the next). The operator set:

GroupOperators
ComparisonEqual, NotEqual, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual
LogicAnd, Or, Not
ArithmeticAdd, Subtract, Multiply, Divide, Abs
AggregatesSum, Count, Average, Max, Min
Range and setsInRange (value/min/max), Contains (collection/item)
LiteralsNumber, String, Boolean, Null

A worked example

A hard constraint requiring both tickets in the same region, plus a soft preference for skills within 200 points (Not(Abs(skill0 - skill1) > 200)):

snug matchmaking ruleset create -r docs4-region-lock -n "Docs4 Region Lock" \
  --hard-constraints '[{"rule_id":"same-region","description":"Both tickets in the same region","expression":{"type":"Equal","value":{"left":{"type":"TicketAttribute","value":{"ticket_index":0,"path":"region"}},"right":{"type":"TicketAttribute","value":{"ticket_index":1,"path":"region"}}}}}]' \
  --soft-preferences '[{"rule_id":"close-skill","weight":1.0,"expression":{"type":"Not","value":{"type":"GreaterThan","value":{"left":{"type":"Abs","value":{"type":"Subtract","value":{"left":{"type":"TicketAttribute","value":{"ticket_index":0,"path":"skill"}},"right":{"type":"TicketAttribute","value":{"ticket_index":1,"path":"skill"}}}}},"right":{"type":"Number","value":200}}}}}]'

snug matchmaking pool create -p docs4-ranked -n "Docs4 Ranked" -m streaming -r docs4-region-lock

Against that pool:

snug matchmaking ticket submit -p docs4-ranked -a '{"skill":1500,"region":"us-west"}'
# second user:
snug matchmaking ticket submit -p docs4-ranked -a '{"skill":1510,"region":"eu-central"}'
# both tickets: "status": "waiting"  - the hard constraint blocks the pair
snug matchmaking ticket submit -p docs4-ranked -a '{"skill":1620,"region":"us-west"}'
# the two us-west tickets: "status": "matched"; eu-central keeps waiting

Inspect and delete

snug matchmaking ruleset get -r docs4-region-lock
snug matchmaking ruleset delete -r docs4-region-lock

Rulesets are versioned (version in the response). Note a CLI wrinkle: in --output json mode, ruleset create prints the ruleset fields at the top level while ruleset get nests them under "ruleset".

Validation gotchas

  • The CLI parses --hard-constraints/--soft-preferences locally; a rule list that is not valid JSON in the tagged-tree shape fails client-side ("Invalid JSON for hard constraints") before any request is sent.
  • Raw HTTP is stricter than the envelope suggests: a malformed expression (for example the flat {"attribute": ..., "operator": ...} shape) is rejected during body deserialization with a plain-text 422 ("missing field type"), not an enveloped invalid_rule_expression error.
  • A missing ruleset referenced by pool create -r is not caught at pool creation. Worse, a submit to that streaming pool returns 404 ruleset_not_found after creating the ticket - it sits in the waiting queue consuming one of the user's ticket slots even though the call reported failure (verified). Create the ruleset first.

The exact request and response schemas are in the Matchmaking API reference.

On this page