What is a Constraint Registry?

A constraint registry is a structured catalog of every rule, limit, and soft preference your optimizer enforces. It gives each constraint an ID, a human name, metadata, and formatting rules so you can:

  • Trace assignments and violations back to specific rules (explainability)
  • Auto-generate readable rationales
  • Run automated data quality and feasibility checks before the model fails

Think of it as a source-of-truth JSON (or YAML/CSV) file that both engineers and business owners can read.


Demo Admin Interface and Core Fields You Should Capture

Open demo in full screen

Minimum set (hard to live without):

  • id (stable, machine-safe key): WeekendOff_MinTwo
  • name (human-readable): Minimum Two Weekends Off Per Month
  • type: hard or soft
  • group: Fairness, Fatigue, Licensure, etc.
  • description: one short sentence
  • bounds or formula: the actual logic (e.g., min=2 weekends off)
  • weight or penalty: numeric cost for soft rules
  • priority: qualitative or numeric rank (tie-breaker vs. weight)
  • template: sentence skeleton for rationale text
  • owner: who can change it (role or team)
  • version and effective_date: for audit trails

Nice-to-have:

  • unit (hours, shifts, people)
  • jurisdiction or contract_ref (policy or union clause reference)
  • tags (safety, cost, morale)
  • deprecated flag
  • last_modified_by, last_modified_at
  • test_cases (IDs of data scenarios used to validate it)

Example JSON Snippet

{
  "id": "Fatigue_MaxConsecNights",
  "name": "Max Consecutive Night Shifts",
  "type": "hard",
  "group": "Fatigue",
  "description": "No person may work more than 3 consecutive night shifts.",
  "bounds": {
    "max_consecutive": 3,
    "shift_type": "night"
  },
  "weight": null,
  "priority": 90,
  "template": "We broke {rule} by {amount} because alternatives created higher risk elsewhere.",
  "owner": "Workforce Policy Team",
  "version": "1.2",
  "effective_date": "2025-01-01",
  "tags": ["safety", "fatigue"],
  "jurisdiction": "Hospital policy 4.3",
  "deprecated": false,
  "last_modified_by": "j.smith",
  "last_modified_at": "2025-06-15T10:42:00Z"
}

Soft rule example:

{
  "id": "Pref_ShiftType_Days",
  "name": "Preferred Day Shifts",
  "type": "soft",
  "group": "Preference",
  "description": "Nurses prefer day shifts when availability allows.",
  "formula": "penalty_per_night_shift = 5",
  "weight": 5,
  "priority": 10,
  "template": "We assigned a non-preferred shift to balance overtime and coverage.",
  "owner": "Nursing Ops",
  "version": "0.9",
  "effective_date": "2024-09-01"
}

CSV works too; just ensure you serialize structured fields (like bounds) as JSON strings or separate columns (max_consecutive, shift_type, etc.).


Formatting Tips

  1. Stable IDs: Once published, don’t rename IDs. Add a deprecated flag instead.
  2. One rule per row/object: No multi-rule blobs; keep it atomic.
  3. Explicit nulls: If a hard rule has no weight, store null, not an empty string.
  4. Template variables: Use consistent placeholders ({rule}, {amount}, {unit}, {alt_cost}).
  5. Version everything: Treat the registry like code—Git it, review it, release it.

Wiring the Registry into the Optimizer

At Build Time

  • Load registry into your model-building code.
  • Map each registry entry to its constraint or objective term.
  • Store the id on the model object (constraint name, suffix, or attribute).

At Solve Time

  • Capture slacks, duals, and objective contributions keyed by id.
  • Use the template to generate explanations.

At Review Time

  • Link UI tooltips and violation panels directly to registry metadata.
  • Show owner, description, and effective_date so decision makers know what can change.

Data Quality & Feasibility Diagnostics

Goal

Catch contradictory rules or bad input (like availability all zero) before the solver throws “infeasible”.

Pre-solve Checks (Static)

Run these checks as a CI-like step or nightly build:

  • Schema validation: All required fields present? Types correct?
  • Bounds sanity: min <= max, positive weights for soft rules, type ∈ {hard, soft}.
  • Duplicate IDs: Block merges with repeats.
  • Deprecated collisions: Don’t use rules marked deprecated unless explicitly allowed.
  • Cross-rule contradictions:

  • Two hard rules require mutually exclusive states (e.g., “min 2 weekends off” and “must cover all weekends with same person”).

  • Weight zero on a “soft” rule (it will never matter; probably a mistake).
  • Availability sanity:

  • For each skill/unit, is there at least one qualified person available in the horizon? If not, flag.

  • Check that total required coverage ≤ total available hours (rough heuristic before solve).

Lightweight Feasibility Probe

Before the full model:

  • Solve a relaxed version (drop soft rules, relax some bounds) to see if the core is feasible.
  • If infeasible, extract an IIS (Irreducible Inconsistent Subsystem) from the solver to highlight the minimal conflicting set of rules. Map those constraints back to registry IDs and report them.

Automated IIS Reporting

When infeasible:

  1. Ask solver (CP-SAT, Gurobi, CPLEX) for IIS.
  2. Translate constraint names → registry entries.
  3. Output a concise report:

Infeasible due to: - Fatigue_MaxConsecNights (hard, weight n/a) - ICU_Charge_Min (hard) Suggestion: Relax one by 1 unit or add 2 qualified staff.

Data Quality Scripts (Pseudo-code)

import json
from jsonschema import validate

with open("constraint_registry.json") as f:
    registry = json.load(f)

# 1. Schema check
validate(instance=registry, schema=constraint_schema)

# 2. Bounds sanity
for r in registry:
    if r["type"] == "hard" and r.get("weight"):
        warn("Hard rule has weight; did you mean soft?")

    b = r.get("bounds", {})
    if "min" in b and "max" in b and b["min"] > b["max"]:
        error(f"{r['id']}: min > max")

# 3. Availability sanity (toy example)
if total_required_hours(unit="ICU") > total_available_hours(skill="ICU"):
    error("ICU coverage impossible with current availability")

# 4. Contradiction heuristics
# Example: MaxConsecNights=3 AND MinConsecNights=4 for same group

Continuous Diagnostics Pipeline

  1. Registry Change PR → automated schema + contradiction tests → reviewer approves.
  2. Nightly Data Pull → availability + demand sanity checks.
  3. Pre-solve Feasibility Probe → catch infeasible cases and alert owners.
  4. Post-solve Explainability → generate rationales, log violations, collect metrics.
  5. Dashboard → track most frequently violated rules and data issues; feed back into staffing policies.

Outcomes You Get Right Away

  • Fewer “why did it fail” late-night Slack threads.
  • Faster iteration on policies because rules are decoupled from code.
  • Cleaner audit trail and easier compliance reviews.
  • Better trust: people see rules, know who owns them, and can request changes transparently.