JsonProject.solve#

Schedules a JsonProject and accepts the scheduled dates as its baseline. Pass project data to load a project, or null / undefined to reschedule after apply. preview, loadProfile, evaluate, slots and suggestAssignments need a solved project.

For a one-shot run without a handle, use schedule.

Signature#

solve(data_json: string | null | undefined, options_json: string): string

Synchronous. Changes the project's state.

Request#

Argument Payload Required Description
data_json ProjectData no Replacement data. null or undefined schedules the current state
options_json SolveOptions yes Subtree, analytics and reporting switches. "{}" for defaults

Behavior#

  • With data: validates the replacement data, installs it, schedules it and accepts the result. The previous data is discarded. How the data is validated or repaired depends on the validation option the handle was created with.
  • Without data: schedules the current state when it has unsolved edits. When the project is already solved with equal options, it returns the cached result without scheduling again. The cache key is the whole options object.

Tasks touched by successful apply calls since the last solve appear in updates as direct updates, even when the planner leaves them where the edit put them. A cyclic project returns unchanged dates and keeps those tasks pending.

baselineId in the result names the accepted baseline. It changes only when the data or the dates change, so solving an unchanged state keeps it.

Response#

A success envelope with a ScheduleResult.

Errors#

kind code When
parse null data_json or options_json isn't valid JSON, misses a required field, or has an unknown field where one is rejected (for example an unknown option)
validation null The supplied data fails validation; path names the field when the engine found the problem
project needs-resync No data after an apply rejected an operation, and no solve with data has followed

After a parse or validation error the previous state and cached result are kept. Calling solve on a freed handle throws at host level; see Wire format.

Example#

Load a project, commit an edit and reschedule it, in Node:

const { JsonProject } = require("./pkg-node/plen_wasm.js");

const data = {
  config: { use_calendars: false },
  tasks: [
    { id: "a", start_date: "2026-08-10 08:00", duration: 2 },
    { id: "b", start_date: "2026-08-10 08:00", duration: 1 },
  ],
  links: [{ id: "ab", source: "a", target: "b" }],
};

const project = new JsonProject("{}");
try {
  const loaded = JSON.parse(project.solve(JSON.stringify(data), "{}"));
  if (!loaded.ok) throw new Error(loaded.error.message);

  // Nothing changed: the cached result comes back with the same token.
  const again = JSON.parse(project.solve(undefined, "{}"));
  console.log(again.result.baselineId === loaded.result.baselineId); // true

  project.apply(JSON.stringify({ tasks: { update: [{ id: "a", duration: 3 }] } }));

  const envelope = JSON.parse(project.solve(undefined, "{}"));
  if (envelope.ok) {
    for (const u of envelope.result.updates) {
      console.log(u.id, u.start_date, u.end_date);
    }
  } else {
    console.error(envelope.error.kind, envelope.error.code, envelope.error.message);
  }
} finally {
  project.free();
}

data_json for the first call:

{
  "config": { "use_calendars": false },
  "tasks": [
    { "id": "a", "start_date": "2026-08-10 08:00", "duration": 2 },
    { "id": "b", "start_date": "2026-08-10 08:00", "duration": 1 }
  ],
  "links": [{ "id": "ab", "source": "a", "target": "b" }]
}

Response of the first call (only the moved task is listed):

{
  "ok": true,
  "result": {
    "baselineId": "<opaque token>",
    "conflicts": [],
    "converged": true,
    "cycles": [],
    "notes": [],
    "updates": [
      { "id": "b", "kind": "task", "start_date": "2026-08-12 08:00", "end_date": "2026-08-13 08:00" }
    ]
  }
}

Response of the last call, after the edit to a:

{
  "ok": true,
  "result": {
    "baselineId": "<new opaque token>",
    "conflicts": [],
    "converged": true,
    "cycles": [],
    "notes": [],
    "updates": [
      { "id": "a", "kind": "task", "start_date": "2026-08-10 08:00", "end_date": "2026-08-13 08:00", "duration": 3 },
      { "id": "b", "kind": "task", "start_date": "2026-08-13 08:00", "end_date": "2026-08-14 08:00" }
    ]
  }
}