# Under the hood

> A stateless constraint-solver service on Java and Timefold, one engine for project plans and shift rosters, a preview-apply-undo contract that never writes a plan on its own, and a solver that never holds credentials to your data

Source: https://aipril.dev/docs/scheduling/under-the-hood

## A solver, not a formula

Leveling a task network under dependencies and capacity is a search problem, not a calculation:
there are many candidate plans and the job is to find a feasible one that is also good. Nothing else
in the platform does that. The rules in [Processes](https://aipril.dev/docs/processes.md) compare values; the
[data engine](https://aipril.dev/docs/engine.md) aggregates them. Neither searches.

So scheduling is its own service: **a Java service built on Timefold Solver**, running beside the
other platform services. Timefold was chosen over the alternatives because it ships reference
constraint models for employee rostering, which is the second job this engine does.

## One engine, two domains

Project recalculation and shift rostering are two constraint models inside the same service, with
one admission control shared between them. A third consumer that needs "a feasible schedule under
constraints" is a new model, not a new solver.

Rules are split into **hard** - dependencies, capacity, earliest start, latest finish - and **soft**
- deadlines, the length of the plan, and staying close to the current one. A plan that breaks a hard
rule is never offered.

## The solver holds nothing

The service is stateless and has no credentials to the platform's data. The platform's own backend
reads the project from [Processes](https://aipril.dev/docs/processes.md), sends the solver a self-contained problem, and
writes the result back itself. Every run is recorded in the organisation's database, which is what
makes a preview reproducible and an undo exact.

## Preview, apply, undo

- A **preview** is stored and expires after a short window.
- **Apply** checks that the project has not changed since the preview was built and refuses if it
  has - a plan computed without somebody's edit is not written over it.
- **Undo** reverses a whole run, not one task at a time.
- An infeasible result is **refused with an explanation**: every rule that fired, with its weight
  and the tasks, resource and day involved. The rule names in the explanation are the same keys an
  administrator uses to weight rules, so "this rule is too heavy" and "lower this rule" speak one
  language.

## Who may recalculate

Only a person, acting directly or through the assistant as themselves. Service accounts and AI
employees acting on their own are refused, and so are automations running on a person's behalf.
Rewriting a project's dates is a decision with an owner, and the audit trail names them.

## Limits you set

The platform sets ceilings - how long a solve may run, how many tasks one solve takes, how far
ahead it plans, how many solves run at once, how often an organisation may start one. Each
organisation sets its own policy under those ceilings: which objective it optimises for and how the
rules are weighted.

## Where it shows up

The Gantt chart in [Projects](https://aipril.dev/docs/solutions/projects.md), the roster and resource-load widgets for
[pages and portals](https://aipril.dev/docs/cms.md), and the assistant. Task dates live in
[Processes](https://aipril.dev/docs/processes.md); assignments of people to tasks live in a
[spreadsheet](https://aipril.dev/docs/spreadsheets.md) the project owns, so they can be edited like any other table.
