JsonProject.slots#
Turns a Pool of workers with skills and a list of Requirements into the Slots that suggestAssignments takes. Existing active assignments are bound to the slots, so repeated runs stay stable after a commit. Needs a solved JsonProject with no unsolved edits.
Signature#
pool_json: string, requirements_json: string: string
Synchronous and read-only: reads the project's accepted state and never modifies the handle. In the browser build, call it only after init() has resolved.
Request#
| Argument | Payload | Required | Description |
|---|---|---|---|
pool_json |
Pool |
yes | Workers that may be assigned. Pool order sets the order of each slot's allowed. |
requirements_json |
Requirement[] |
yes | What each task needs. [] returns an empty array. |
Pool#
The workers to choose from, in order of preference.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
workers |
Worker[] |
yes | Candidate workers. Their order is the order of allowed in every slot. |
Worker#
One resource of the project and its skills.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
resource |
Id |
yes | A resource of the project. Each resource can appear as one worker only. | |
skills |
Skill[] |
no | [] |
The worker's skills. null = []. |
Skill#
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
Id |
yes | Skill name. Listed at most once per worker. | |
value |
number |
no | 1 |
Skill grade, e.g. 0/1 or an integer level. Must be finite. null = 1. |
Requirement#
What one task needs: count workers that satisfy every skill match.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
Id |
yes | Unique among the requirements. Slot ids are built from it. | |
task |
Id |
yes | A scheduled task of the project. | |
matches |
SkillMatch[] |
yes | Conditions a worker must meet, all of them. [] allows every pool worker. |
|
count |
number |
no | 1 |
Number of slots, a whole number >= 1. null = 1. |
units |
number |
no | 1 |
Value of a new assignment created for a slot (1 = 100 %). Finite and > 0. null = 1. |
assignments |
Id[] | null |
no | null |
Explicit binding of existing assignments to this requirement's slots, replacing automatic binding. null or absent = automatic binding; [] = all slots empty. At most count entries. |
The slot ids of a requirement become assignment ids on its task once a proposal is committed. Keep each requirement id on the same task across runs: reusing it for another task makes the call fail at requirements[i].id.
SkillMatch#
One condition on a worker's skill grade. A skill the worker doesn't list counts as 0.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
skill |
Id |
yes | Skill to check. | |
op |
string |
no | "at_least" |
"at_least" (grade >= value), "no_more" (grade <= value), "equal" (grade == value). null = "at_least". |
value |
number |
no | 1 |
Grade to compare with. Must be finite. null = 1. |
{ "skill": "backend" } means "has the skill".
All five shapes reject unknown fields.
Response#
The success envelope carries a Slot[]: for each requirement, count slots, in requirement order, then instance order. The envelope shape is described in Wire format.
| Slot field | Value |
|---|---|
id |
"<requirement id>#<n>", n = 1..count (for example be#1, be#2) |
task |
The requirement's task |
allowed |
Pool workers for which every match of the requirement holds, in pool order |
value |
The requirement's units |
assignment |
The existing active assignment bound to this slot; omitted when the slot is empty |
The array can be passed to suggestAssignments as is (JSON.stringify(envelope.result)).
Behavior#
The task's existing active assignments are bound per task, across all requirements on that task, in three steps:
- Slot id. An assignment whose id is one of the requirement's slot ids binds to that slot, even when its resource isn't in
allowed. The slot is then broken ("broken"inSuggestOptions.targets). This step runs for every requirement of the task before any explicit list. - Explicit list. A non-null
assignmentsreplaces automatic binding for that requirement. A listed slot-id assignment keeps its slot, the other entries take the remaining slots in order, and leftover slots stay empty. - Matching. A deterministic maximum bipartite matching binds the remaining assignments to the empty slots of requirements without a list. An assignment can take a slot only when its resource is in the slot's
allowed. Input order decides between equal matchings, and an earlier requirement can't take the only worker a later one fits.
Assignments left unbound stay on the task without a slot.
Errors#
The first failing check wins: decoding of both arguments, then the project state, then the pool, then each requirement in input order.
| Error | When |
|---|---|
kind: "parse" |
Malformed JSON, wrong JSON type (e.g. an array for pool_json), a missing required field (workers, resource, id, task, matches, skill), or an unknown field. path: null. |
kind: "validation", path: null |
A value the decoder rejects: an unknown op string, or a count that isn't a nonnegative whole number. |
kind: "project", code: "no-baseline" |
The project was never solved, or has unsolved edits after apply. |
kind: "validation" with a path |
The pool or a requirement doesn't fit the project. See the table below. |
Validation paths:
| Path | When |
|---|---|
pool.workers[i].resource |
Unknown resource, or the same resource listed as two workers |
pool.workers[i].skills[j].id |
The same skill listed twice on one worker |
pool.workers[i].skills[j].value |
Not finite |
requirements[i].id |
Duplicate requirement id, or one of its slot ids is an active assignment on another task |
requirements[i].task |
Unknown or unscheduled task |
requirements[i].count |
0 |
requirements[i].units |
Not finite or <= 0 |
requirements[i].matches[j].value |
Not finite |
requirements[i].assignments |
More entries than count, or an assignment with one of this requirement's slot ids left out of the list |
requirements[i].assignments[k] |
Unknown or inactive assignment, an assignment on another task, or one bound twice (the message names the other requirement when it already holds it, e.g. already bound to requirement "fe") |
There's no stale-baseline: the call takes no baselineId.
Errors come back in the returned envelope; the call doesn't throw for bad input. Calling it on a freed handle throws at host level. See Error handling.
Example#
The project has tasks B and C, resources ann, bob and cy, and an assignment a1 of ann on B.
Request (pool_json):
Request (requirements_json):
Response:
a1 is bound to be#1 by matching, because ann is in its allowed. cy has qa at grade 1 only, so qa#1 allows bob alone.
Host call in Node, passing the slots on to suggestAssignments:
const = ;
const = ;
const = ;
const = ;
const = new;
Related#
Slot- the result shapeJsonProject.suggestAssignments- fills, repairs or rebalances the slots- Skills and requirements - workers, skills and requirements end to end
- Suggesting assignments - what happens to the slots next