feat: plan orchestration (T-E) — snapshot, engine/validator run, publish/supersede #82
No reviewers
Labels
No labels
in-progress
in-review
needs-decision
priority: later
priority: next
priority: now
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!82
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/domain-planning"
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 a planning run, and the system carries it all the way through to a checked, publishable draft. Triggering a run captures exactly what the crews, jobs and presence data looked like at that moment, hands it to the real planning engine and the real validator, and stores the result as a new plan version with its proposed assignments, any jobs it couldn't place (and why), and any issues the validator flagged. Publishing that version supersedes only the earlier published plan on the dates it actually replaces — other dates the older plan covered keep running unchanged — and a published assignment is never edited in place; a later change always shows up as a new assignment in a new version, so the plan's history stays exact. Confirming a plan also moves its jobs from open to planned, and moves them back to open if a later plan drops them without replacing them. Planners can also ask, for any single job, which crew/time combinations could currently take it, computed live rather than pre-stored.
Related Issues
Closes #20
Row:
docs/12-implementation-plan.mdPH2 / T-EType of Change
Breaking Changes
None.
Test Plan
Tests green (unit tests against fakes for the state machines and the publish/supersede logic; integration tests against a real Postgres for the snapshot build, the full solve pipeline through the real engine and validator, and the publish/supersede scenario the ticket specifically asked for — publishing a second version for a date supersedes only the first version's coverage of that date, and its assignment on an untouched date is provably unmutated). The two existing test files that previously asserted "not implemented yet" for these five endpoints were updated to match the real behaviour; their role-gating checks are untouched.
Checklist
docs/updated for any behavioural change (ADR added if a prior decision was reversed)polaris.domainAdditional Context
The ticket brief assumed the engine and validator were still stubbed; both merged before this work started, so this calls the real
polaris.engine/polaris.validatordirectly — no stub anywhere, and no shape mismatch turned up between what they produce and what this ticket needed.A couple of judgment calls, both recorded in
docs/04-lifecycles.md: (1) until triage (PH3.2) exists, publishing a version treats every proposed assignment on it as accepted rather than requiringreview = acceptedfirst; (2) asolvetask's stored payload carries one extra key (solver_run_id) beyond the frozen contract shape, which is what letsGET /tasks/{id}report a solve task's result without a reverse lookup —task.payloadis a plain JSON column, so this doesn't touch the sealed contracts package.Publish and discard as HTTP endpoints stay PH3.4's
501stubs; this PR ships the domain service and its supersede semantics underneath them, exercised directly by integration tests, not through those endpoints.🤖 Generated with Claude Code
https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM
Replaces the PH1.7 501 stubs for these five endpoints with real handlers. POST /plans/runs is the one mutation here, going through domain.planning.runs.start_run under the same X-Reason convention every other mutating endpoint uses; the GET endpoints are plain read projections straight off the ORM, same pattern crud_router's own list/get routes use. GET /jobs/{id}/opportunities reuses the real engine's own opportunity generation rather than re-deriving that logic at the API layer. Refs #20 (T-E) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnMRecords the implementation notes docs/04-lifecycles.md's plan-version rules didn't already pin down: the validated->draft diagram edge is a new child row, not a same-row rollback; an old published version only flips to superseded once none of its dates are active; solver_run/plan_version/ assignment write their own audit rows since they aren't Auditable; publish treats every proposed assignment as accepted until PH3.2's triage exists; and a solve task's payload carries an extra solver_run_id key so GET /tasks/{id} can report its result without a reverse lookup. Refs #20 (T-E) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YioTVKBPoE6thZqbnTtnM