feat(engine,api): manual re-plan mode and POST /plans/versions/{id}/reoptimise #94
No reviewers
Labels
No labels
in-progress
in-review
ready-for-agent
seam-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
patrick/Polaris!94
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/engine-manual-mode"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
A planner can now trigger "Re-optimise" on a specific scope — a date range plus a chosen set of crews — against an existing plan version. Behind the scenes this runs the solver only over the crews and dates the planner picked; every other crew's schedule on those same dates, and anything already under way, is left exactly as it was. The result comes back as a new draft version built on top of the one the planner started from, so it can be reviewed and published the same way any other draft can.
Related Issues
Closes #35. Row PH5.3 in docs/12-implementation-plan.md.
Also files #93, a follow-up seam request: the worker doesn't yet dispatch a manual re-optimise run to this new engine behaviour end-to-end (it currently always uses the same engine the nightly run uses). That's flagged in detail on both issues and doesn't block this PR — this ticket's own scope (the engine behaviour itself, and the endpoint's validation/enqueue/child-version wiring) is complete and independently tested.
Type of Change
Breaking Changes
None.
Test Plan
Tests green: new engine-level unit tests cover out-of-scope crew-days and out-of-scope dates being returned unchanged, already-started work staying put, the planner's soft-lock-vs-free choice, and an existing lock still taking effect. New API-level integration tests (real Postgres) cover scope validation (unknown version, bad date range, range too wide, unknown crew), the missing-reason-header case, role gating, and the happy path enqueuing a run and returning a child version. Full backend suite (
ruff check,ruff format --check,mypy --strict,pytest -m "not smoke") passes.Checklist
docs/updated for any behavioural change (ADR added if a prior decision was reversed)polaris.domainAdditional Context
Two judgment calls worth a reviewer's eyes:
/reoptimiserow — only the genericPOST /plans/runs. This PR mounts it atPOST /plans/versions/{id}/reoptimise, matching the ticket's own file name and prose and the shape of its sibling per-version actions (/recalculate,/overrides,/publish,/discard), and adds the missing row to docs/09-api.md.No new dependencies.
🤖 Generated with Claude Code
https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Lets a planner trigger "Re-optimise" on an explicit scope (dates, crews) against an existing plan version. Validates the scope (version exists, dates are sane, crews exist), resolves it to the concrete scope_shift_ids, and enqueues a manual-mode solve run as a child version of the one being re-optimised, via the same domain.planning.runs.start_run machinery POST /plans/runs already uses - no reimplementation. docs/09-api.md's table only documents the generic POST /plans/runs; this ticket's own row names the file api/routers/plans/reoptimise.py and the ticket body's prose names the path, so it mounts under /plans/versions/{id} alongside its sibling per-version actions (recalculate, overrides, publish, discard) rather than as a variant of /plans/runs. PH5.3, issue #35. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM