Milestone 1: the smallest useful retail rota
Our first question is intentionally small:
Who covers each shift?
The decision model names the entity collection (staff) and the group
collection (shifts). The one rule requires at least one placement in each
shift. At this milestone, the model does not understand skills, time, hours,
availability, or preferences.
domain: RetailRostering
problem_type: my_rota
version: "0.1"
description: "Minimum retail shift coverage tutorial"
decision:
entities:
source: staff
identity: id
groups:
source: shifts
identity: id
domain:
total_over_entities: false
total_over_groups: true
search:
acceptor: simulated_annealing
constraints:
staffed:
name: "Every shift is covered"
description: "At least one employee must be assigned to every shift."
type: hard
default_enabled: true
contract: aggregate
parameters:
collect: count
compare: ">="
limit: 1
The manifest says what the problem means. The records say what this instance contains:
{
"staff": [
{"id": "alice"},
{"id": "ben"}
],
"shifts": [
{"id": "mon-open"},
{"id": "mon-close"}
]
}
Run the same contract directly in Python while developing the model:
from pathlib import Path
import yaml
from helixor_solvers.manifest_solver import solve_from_manifest
manifest = yaml.safe_load(Path("retail_rota.yaml").read_text())
problem = {
"staff": [{"id": "alice"}, {"id": "ben"}],
"shifts": [{"id": "mon-open"}, {"id": "mon-close"}],
}
result = solve_from_manifest(manifest, problem, problem_type="my_rota")
assert result["is_feasible"] is True
assert result["unevaluable_rules"] == []
print(result["placements"])
print(result["admission"])
The important result is not only the placement list. It is the admission certificate. A plan that cannot say which declared rules were evaluated is not a trustworthy answer.
What the first model does not mean#
It may assign one employee to both shifts. That is correct for the manifest we wrote: no rule forbids it. When an answer surprises you, ask which missing business statement would make it wrong, then add that statement through a shared contract. Do not patch the returned assignment in application code.