Skip to content

Update dependency jupyddl to v2.5.0 - #16

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/jupyddl-2.x
Open

renovate[bot] wants to merge 1 commit into
mainfrom
renovate/jupyddl-2.x

Conversation

@renovate

@renovate renovate Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

This PR contains the following updates:

Package Change Age Confidence
jupyddl (changelog) ==2.3.0 → ==2.5.0 age confidence

Release Notes

openplan-labs/PythonPDDL (jupyddl)

v2.5.0

Compare Source

Added
  • Every merge is a release, decided by what was merged. Pull request
    titles are Conventional Commits (a pr-title check enforces it), and on
    each merge release.yml takes the largest bump the PR's title and commits
    ask for — fix → patch, feat → minor, feat! → major — bumps the version
    everywhere, dates this changelog, commits and tags main, and publishes to
    PyPI. No release PR and nothing to approve. A release:* label overrides
    the bump. See .docs/RELEASING.md.
  • The intent to publish, written down. .docs/PUBLISHING.md says why and
    where we mean to publish jupyddl as citable research software — a Zenodo DOI
    per release, a JOSS paper, ICAPS workshops for the research results — with a
    readiness checklist, the paper outline, the AI-usage disclosure JOSS requires
    and how contributors can be considered for authorship. The README states the
    project's aim (a framework to build on and to explain algorithms with) and
    its Cite section says which version the 2021 preprint describes.
  • Plugins. A package can now add planners, heuristics and generators by
    declaring jupyddl.planners, jupyddl.heuristics or jupyddl.generators
    entry points; once it is installed, jupyddl solve -s <its planner> works
    without anyone importing it. Discovery is lazy (the CLI runs it before
    building its parser, the library only when asked for a name it does not
    know), a built-in name always wins, a plugin that fails to import is skipped
    with a warning, and JUPYDDL_NO_PLUGINS=1 turns it off. jupyddl plugins
    lists what was found.
  • .docs/EXTENDING.md, a guide to building on the framework: a heuristic,
    a planner from a priority function, a planner from scratch with the full
    budget/observer contract, a generator, how to test the guarantees you claim,
    and how to ship it all as a plugin. Every example runs in the test suite, so
    the guide cannot drift from the API.
  • best_first accepts a tuple priority for tie-breaking
    (lambda g, h: (g + h, h)); observers are given its first element as f.
  • Community files for outside contributors: a security policy, a
    pull-request template, a Propose an algorithm issue template, and an
    "Adding an algorithm" section in CONTRIBUTING.md.
Changed
  • CI now runs on pull requests, including from forks. tests and build
    were on: [push], which never fires for a fork, so an outside contributor's
    PR showed no checks at all. They now run on every pull request and on pushes
    to main.

  • Documentation lives in one place: .docs/. It was spread over three
    directories — docs/ for the contributor files and the README charts,
    promo/ for the videos and screenshots, .docs/ for the research notes —
    with no rule saying which took what, so every new file was a guess. The
    research notes, the release runbook and every image, video and measurement
    cache are now under .docs/, with binaries in .docs/assets/. This also
    matches pymapf, the sibling project.

    Paths quoted in the released sections below are the ones that were correct
    at the time. promo/rl-data.json is now .docs/assets/rl-data.json, and
    docs/images/ is now .docs/assets/.

    CONTRIBUTING.md and CODE_OF_CONDUCT.md moved to .github/ rather than
    .docs/: GitHub only recognises those two files in the repository root,
    .github/ or docs/, so filing them under .docs/ would have silently
    dropped the contributing link on the issue and pull-request forms.

Fixed

Wrong answers from the task model and the heuristics. Each of these returned a
plan, a cost or a value without complaint, and validate_plan accepted the
plans because it replays them through the same model. They are now pinned by
tests/test_semantics.py on tiny tasks whose right answer is obvious.

  • Derived facts were never retracted. An action that deleted the support of
    a derived fact left it true, and (not <derived>) held from the initial state
    on. Axioms are now recomputed from scratch after every step, and a negated
    derived fact is maintained with them. Negating a derived predicate inside
    another rule
    needs stratification and is now refused by name.
  • An atom both added and deleted left its complement true as well, so
    (not (at a)) and (at a) could hold together, and a when that re-added a
    deleted atom did the same. For complement facts the delete now wins.
  • Action costs. Under a (total-cost) metric an action with no cost effect
    now costs 0, as in IPC planners, rather than 1 — on pegsol and sokoban the
    "optimal" planners were optimising the wrong objective. A cost inside when
    was charged whether or not the condition held; it is now refused, as is a
    negative cost.
  • A numeric fluent that is never defined read as 0, so (distance a c) for
    a road that does not exist cost nothing. Conditions and effects reading one
    now fail, as PDDL 2.1 specifies.
  • blind was not admissible when any action is free, which every PDDL 3
    compilation introduces, so astar+blind could return a costlier plan.
  • h1/h2/hm crashed on every numeric or timed task, and LM-cut
    crashed on an empty goal
    , which made the default solve() crash too.
  • lmcut and h2 claimed admissibility on tasks with conditional effects,
    where they can overestimate. The instance flag now says so.
  • solve_task(task, "astar") used hff, which is not admissible, so the
    default A* was not optimal. Optimal planners now default to lmcut. -H none
    also fell through to hff; it now means blind.
  • make_heuristic(LMCutHeuristic, task) returned the class unbuilt, and the
    planner then crashed calling it on a state. Classes and partials are now built.
  • Results depended on PYTHONHASHSEED. Fact ids followed string hashing,
    so LM-cut broke ties differently in every process: gripper with astar/lmcut
    expanded 1725, 1758 or 1760 nodes and returned different plans. Ids are now
    assigned in sorted order, so a benchmark reproduces.
  • iddfs, idastar and ehc ignored their budget, so --time-limit 0.5
    on blocksworld12 ran for minutes. beam polled once per layer and bnb kept
    evaluating LM-cut on every sibling after the budget fired; both now stop at
    once. A new contract test runs every planner where the budget is the only
    thing that stops it.
  • A depth cap was reported as "no plan exists" (iddfs, bnb), and a
    bnb plan found under one as optimal. Hitting the cap now sets truncated,
    as does a search deeper than Python's recursion limit.
  • bfs and iddfs were listed as optimal. They minimise plan length;
    on errands they return cost 16 where 10 is optimal. They are no longer in
    OPTIMAL_PLANNERS, and the workbench no longer badges them.
  • The live dashboard said "no plan found" when the budget stopped the
    search, smeared every repaint on a narrow terminal (lines were never clipped
    to its width), and logged ten times too often when not on a terminal.
  • idastar, ehc, hc and beam without a heuristic raise a clear
    ValueError instead of a TypeError from deep inside the search;
    MultiObserver accepts positional arguments like the base class; the
    SearchObserver docstring no longer claims hooks are called defensively.
  • The command line's exit codes say what happened: 0 solved, 1 no plan, 2
    bad input, 3 stopped by a budget, 4 a plan that failed validation. Before,
    unsolvable, out-of-budget and a crash all exited 1. Bad input — a missing
    file, a parse error, an unknown planner — is one line on stderr instead of a
    traceback (JUPYDDL_DEBUG=1 brings the traceback back). --version exists.
  • jupyddl demo and jupyddl benchmark demos never finished: neither took
    a budget, and demo's blind runs on blocksworld12 do not end. Both now stop
    each search after 10 s by default; animate and demo accept
    --max-expansions and --time-limit like solve.
  • benchmark checks --planners, --heuristic and --metric before running
    rather than reporting nosuch 0/13, and every chart option checks for the
    viz extra before searching instead of failing (or silently writing
    nothing) afterwards.
  • A dead end crashed the charts (Axis limits cannot be NaN or Inf) and
    coloured the wavefront NaN; in the workbench, an infinite h or f made the
    progress message invalid JSON and aborted the run.
  • A trace's plan showed compiler bookkeeping (__observe-1#1) and
    disjunct tags; it now records the plan the user reads.
  • The sdist's own test suite failed: it dropped .github/ entirely while a
    test checks CONTRIBUTING.md is there. Only .github/workflows/ is left
    out now. build runs twine check --strict, like release does.
  • black is pinned to one major version in both the dev extra and the
    format workflow, which installed whatever was newest; Renovate now pins
    third-party actions to commit digests.
  • Learned-heuristic top-1 was neither held out nor tie-safe. A sibling
    scoring level with the successor the plan took counted as a correct ranking,
    so a model that outputs a constant scored 1.000 — and checkpoint selection,
    which reads top-1, could prefer a collapsed epoch. Corpus.split also gave
    the held-out side no ranking groups, so the "held out" top-1 jupyddl learn
    printed was measured over training instances. A tie with k siblings now
    earns 1/(k+1), a sibling identical to the chosen successor in features and
    step cost is not recorded at all, and selection and the reported top-1 use
    the held-out groups. The published figures came from the old rule; see the
    dated corrections in .docs/learned-heuristics.md and
    .docs/rl-for-search.md.
  • A DAgger or bootstrap state could validate against its own instance.
    split treated X#dagger1 as an instance apart from X; it now groups on
    the name before the #.
  • summarise_transfer averaged each heuristic over the runs it solved, so
    one that solved only the easy instance looked many times better than one that
    solved both. An unsolved run is now charged twice the budget, as
    search_cost charges it, and plan cost compares only instances every
    configuration with any coverage solved. The imitation-only blocksworld mean
    the docs quote as 366 is 6 329 under that rule.
  • A malformed learned heuristic loaded, then gave one answer with NumPy and
    another without.
    A network whose input width is not the feature vector's,
    a ragged row, a sizes field that does not describe the weights, a
    non-finite value or a non-positive scale is now a ValueError on load.
    MLP.set_flat checks the length before writing anything, instead of leaving
    a wrong-length vector half-applied.
  • Every negated fact shared one feature, not. Complement facts now key on
    the predicate they negate (not-sampled), so rovers and workshop get a slot
    per negated predicate. A model trained on a domain with negative
    preconditions before this sees different features now; retrain it.
  • train() with a pure ranking objective and no ranking groups returned its
    random initialisation as a trained model; it now raises. learn_heuristic
    spent a generator passed as sizes on its first read, recording [] and
    raising under cem_iterations; size arguments are now read once, on entry.
  • gripper and workshop ignored their seed. Twenty seeds gave one
    instance, so a split by seed held out copies of training instances, and the
    RL stage's tuning and validation sets were the same problems. The seed now
    decides which room each ball and the robot start in (every ball still has to
    change rooms), and how far along the pipeline each part starts. Every
    generated gripper and workshop instance changes
    ; demos/workshop is the one
    in which every part starts raw, and generate no longer reproduces it.
  • Generators could emit an instance solved before it starts. blocksworld
    compared tower lists in order and skipped the check for two blocks, where 75
    of the first 200 seeds came out trivial; random-strips could draw a goal
    that already held. Both now re-draw only in that case, so every instance that
    was not trivial is byte-identical to before.
  • The benchmark harness merged configurations that differed in planner
    arguments
    — wastar at weights 1 and 5 summarised as one entry with twice
    the instances — and recorded ("gbfs", None) as heuristic "" although it
    ran hff. Rows carry a config label with the arguments
    (wastar/hff(weight=5.0), also a new CSV column), which summarize and the
    dashboard group on; a repeated config is suffixed #2; and heuristic is
    what solve_task actually ran, worked out by the new
    jupyddl.api.resolve_heuristic.

Wrong answers from the PDDL front end. The parser and the PDDL 3 compilations
handed the grounder a different problem from the one written, so plans
validated — against the wrong problem. Each case is now pinned by
tests/test_frontend_semantics.py.

  • Durative actions merged their at-start and at-end effects, and an add
    beat a delete, so (at start (busy)) (at end (not (busy))) ended with
    (busy) true. The at-end effects now apply after the at-start ones and win a
    conflict, and over-all and at-end conditions are checked in the state after
    the at-start effects rather than before them. always is checked in that
    state too; the other trajectory constraints are refused when a durative
    action has at-start effects, because their monitors cannot see it.
  • sometime-after could not be met by the final state. An obligation
    recorded by the last action's monitor could never be discharged, so the
    plan [t, r] was reported unsolvable; the goal now accepts the response
    holding at the end.
  • forall around a trajectory constraint moved inside it:
    (forall (?x) (sometime (lit ?x))) meant one moment with every ?x lit at
    once. It is now one constraint per object. A soft constraint under forall
    crashed with an AttributeError; it is refused by name like the others.
  • A goal preference under forall kept its free variable and could never
    be satisfied; it is now one preference per object. Under not, or, imply
    or exists a preference silently made the goal false; it is now an error.
  • Timed initial literals slipped past the PDDL 3 machinery. The
    at-most-once and sometime-after monitors ignored the states literals
    fired in, a literal could fire after the preferences had been paid out, and
    a plan could end before a literal that was already due had fired.
  • Object fluents in trajectory constraints were read as numeric
    comparisons; they are now compiled as everywhere else. Assigning one object
    fluent's value to another took the function's name for an object; it is
    refused.
  • The metric. A preference the metric does not mention cost 1 to violate
    rather than nothing, a metric without (total-cost) still charged for
    actions, maximize was silently minimised, and (total-time) charged an
    instantaneous action 1. maximize, any metric other than (total-cost) or
    (total-time) plus weighted (is-violated p) terms, and a metric pricing a
    preference the goal does not declare are now refused.
  • ground() edited the domain it was given, so a second problem grounded
    against the same parsed domain inherited the first one's synthetic actions
    and lost the domain's own constraints.
  • Misspelt PDDL was accepted. :preconditon gave an action with no
    precondition and (:goals ...) a problem with an empty goal; unknown keys
    and sections and a missing :goal are now errors that name them. Malformed
    input — (?x -), (when (q)), (:goal) — raised a bare IndexError; it is
    a PDDLError, and an unbalanced parenthesis names its line.
  • Objects called nan, inf or infinity were read as numbers.
  • (increase (total-cost) (road-length ?a ?b)) was refused although
    :action-costs is listed as native. A cost over static functions is now
    evaluated when grounding, so the IPC transport domains load. :fluents
    now implies :object-fluents, and :ucpop, :domain-axioms and
    :safety-constraints are refused by name rather than as unknown flags.

v2.4.0

Compare Source

Added
  • A Research view in the workbench. jupyddl.learn shipped in 2.3.0 with
    its results only in .docs/ and a video, which meant the published site said
    nothing about the biggest addition in the release. The view carries the
    measured run: imitation against hff and goalcount, the per-instance
    spread behind the mean, the logistics loss and why the feature space causes
    it, and the three claims that turned out to be wrong. Its numbers are built
    from promo/rl-data.json — the same cache the RL video renders from — so
    the page and the video cannot drift apart, and a test pins them together.
Fixed
  • Reading the workbench no longer costs a 10 MB download. <main> was
    hidden until Pyodide reported ready, so every page of prose, the requirement
    matrix and the new Research view sat behind a full-screen spinner waiting for
    a runtime none of them use. The shell now renders immediately from the
    committed bundle, the boot notice is a status bar rather than a splash
    screen, and only the controls that actually run a planner stay disabled until
    the interpreter arrives.
Changed
  • Python 3.10 is the new floor, and the matrix runs 3.10 through 3.14.
    3.9 reached end of life in October 2025; requires-python moved to match
    what is actually tested.
  • The pddl-examples submodule advances to a corpus that now grows on its own:
    it imports fresh domains from planning.domains daily.
  • All URLs follow the organisation's rename to openplan-labs.
Removed
  • Mergify. Its auto-merge rule waited on an approving review that a
    single-maintainer project does not produce, and its reviewer-assign rule
    pinged an inactive account; every recent pull request was merged by hand.

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@mergify

mergify Bot commented Oct 4, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@renovate
renovate Bot force-pushed the renovate/jupyddl-2.x branch from ce9dc6a to 1bb8ba4 Compare November 7, 2026 15:18
@renovate renovate Bot changed the title Update dependency jupyddl to v2.4.0 Update dependency jupyddl to v2.5.0 Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants