PH1.4 — Engine contracts: PlanningSnapshot, PlanResult, Finding, projector/scorer I/O, task payloads, code lists, fixtures #12

Closed
opened 2026-09-11 09:02:09 +00:00 by bart · 2 comments
Collaborator

Parent

Row PH1.4 in docs/12-implementation-plan.md (branch, owned paths and doc section are defined there).

What to build

The frozen Pydantic contracts crossing module boundaries exist: PlanningSnapshot, PlanResult, Finding (code + params), projector and scorer I/O, and the TaskPayload union. Closed code lists (finding codes, error codes, notification kinds) are exported by polaris openapi as x-polaris-codes. Three fixture snapshots and a polaris replay-run --file skeleton ship with them. The adjusted_confidence hook signature is agreed here for T-B/T-G.

Acceptance criteria

  • A hand-built PlanningSnapshot serialises to JSON and back with equality
  • Every validator code from docs/04-lifecycles.md, every error code and every notification kind appears in x-polaris-codes in the generated spec (resolved via seam request #54, PR #65).
  • Fixtures exist: tiny (known optimum), medium, every-lock-type; each loads through the contracts
  • polaris replay-run --file <snapshot> runs end to end with a no-op engine
  • Import-rule test exists and passes: contracts import only core

Blocked by

  • #4 — API skeleton: core, router discovery, healthz, db + audit hook, alembic 0001, CLI
## Parent Row **PH1.4** in `docs/12-implementation-plan.md` (branch, owned paths and doc section are defined there). ## What to build The frozen Pydantic contracts crossing module boundaries exist: `PlanningSnapshot`, `PlanResult`, `Finding` (code + params), projector and scorer I/O, and the `TaskPayload` union. Closed code lists (finding codes, error codes, notification kinds) are exported by `polaris openapi` as `x-polaris-codes`. Three fixture snapshots and a `polaris replay-run --file` skeleton ship with them. The `adjusted_confidence` hook signature is agreed here for T-B/T-G. ## Acceptance criteria - [x] A hand-built `PlanningSnapshot` serialises to JSON and back with equality - [x] Every validator code from docs/04-lifecycles.md, every error code and every notification kind appears in `x-polaris-codes` in the generated spec (resolved via seam request #54, PR #65). - [x] Fixtures exist: tiny (known optimum), medium, every-lock-type; each loads through the contracts - [x] `polaris replay-run --file <snapshot>` runs end to end with a no-op engine - [x] Import-rule test exists and passes: contracts import only `core` ## Blocked by - #4 — API skeleton: core, router discovery, healthz, db + audit hook, alembic 0001, CLI
bart self-assigned this 2026-09-11 10:23:15 +00:00
Author
Collaborator

Starting PH1.4 on branch feature/engine-contracts (from develop, already includes PH0.2).

Owned paths for this ticket:

  • backend/src/polaris/contracts/**
  • backend/tests/fixtures/snapshots/**
  • backend/src/polaris/cli/replay_run.py

Will not touch polaris.{core,api,db} or polaris.worker/domain/tasks.py (owned by the concurrent #6 worker-skeleton session). Wiring the x-polaris-codes OpenAPI extension into polaris openapi -- if that needs a change to cli/openapi.py beyond what's clearly additive/owned, I'll flag it here as a seam request instead of editing outside contracts/.

Starting PH1.4 on branch `feature/engine-contracts` (from `develop`, already includes PH0.2). Owned paths for this ticket: - `backend/src/polaris/contracts/**` - `backend/tests/fixtures/snapshots/**` - `backend/src/polaris/cli/replay_run.py` Will not touch `polaris.{core,api,db}` or `polaris.worker`/`domain/tasks.py` (owned by the concurrent #6 worker-skeleton session). Wiring the `x-polaris-codes` OpenAPI extension into `polaris openapi` -- if that needs a change to `cli/openapi.py` beyond what's clearly additive/owned, I'll flag it here as a seam request instead of editing outside `contracts/`.
bart stopped working 2026-09-11 10:33:05 +00:00
9 minutes 50 seconds
Author
Collaborator

Progress update -- contracts, fixtures and replay-run skeleton are built and green (ruff, ruff format, mypy --strict, pytest all pass). Four of five acceptance criteria are ticked. Flagging a few things:

Seam request filed: #54 -- wiring x-polaris-codes into backend/openapi.json needs a 2-line change to polaris/cli/openapi.py, which this ticket doesn't own (see reasoning there). polaris.contracts.codes.build_x_polaris_codes() exists and is fully tested; only the actual wiring into the committed spec is blocked. Left that AC box unchecked with a note.

Two modelling decisions future tracks should know about (not formal Qns, since no doc left them open -- these are new ground this ticket had to cover):

  1. FindingCode severity is NOT always derivable from the E_/W_/I_ prefix. docs/04-lifecycles.md's validator table marks W_IDLE_CREW and W_WAITING as info severity despite the W_ prefix. polaris.contracts.codes.FINDING_SEVERITY is a per-code table (source of truth = the doc's severity column, not the prefix) -- T-D (validator, #19) should build Findings via Finding.for_code(...), which reads this table, rather than deriving severity from the code string.

  2. NotificationKind is an initial v1 list I inferred from the scenarios that mention a notification (plan_draft_ready, event_replan_ready, technician_day_changed, job_on_hold, solver_failed, ingest_rejected, vehicle_pattern_stale, job_unplannable) -- no doc enumerates a closed list. PH6.2 (api-notifications, #43) will likely need to add kinds; since contracts/ is sealed after PH1, that's a ! commit with a changelog entry per docs/12-implementation-plan.md, not a normal PR.

adjusted_confidence hook signature (for T-B #17 / T-G #22): polaris.contracts.scorer.AdjustedConfidenceFn -- a Protocol taking AdjustedConfidenceInputs (feed_confidence, site_score, vehicle_site_weekday_score, floor, ceiling) and returning float. T-B calls it per window it builds; T-G implements it in projector/adjust.py (PH4.3). See backend/tests/unit/contracts/test_projector_scorer.py::test_adjusted_confidence_hook_signature_is_usable for a worked example.

TaskPayload kinds: project_windows, solve, solve_event, validate, score -- solve covers daily/override/manual (mode carried in the payload); solve_event is the separate freeze-window path PH5.2 (#34) names its own handler file for. If T-E (#20) or PH5.2 want a different split, that's a contracts change (! commit) -- flagging now so it's a deliberate decision, not a surprise later.

Opening the PR next.

Progress update -- contracts, fixtures and replay-run skeleton are built and green (ruff, ruff format, mypy --strict, pytest all pass). Four of five acceptance criteria are ticked. Flagging a few things: **Seam request filed**: #54 -- wiring `x-polaris-codes` into `backend/openapi.json` needs a 2-line change to `polaris/cli/openapi.py`, which this ticket doesn't own (see reasoning there). `polaris.contracts.codes.build_x_polaris_codes()` exists and is fully tested; only the actual wiring into the committed spec is blocked. Left that AC box unchecked with a note. **Two modelling decisions future tracks should know about** (not formal `Qn`s, since no doc left them open -- these are new ground this ticket had to cover): 1. **`FindingCode` severity is NOT always derivable from the `E_`/`W_`/`I_` prefix.** `docs/04-lifecycles.md`'s validator table marks `W_IDLE_CREW` and `W_WAITING` as `info` severity despite the `W_` prefix. `polaris.contracts.codes.FINDING_SEVERITY` is a per-code table (source of truth = the doc's severity column, not the prefix) -- T-D (validator, #19) should build `Finding`s via `Finding.for_code(...)`, which reads this table, rather than deriving severity from the code string. 2. **`NotificationKind` is an initial v1 list I inferred from the scenarios that mention a notification** (`plan_draft_ready`, `event_replan_ready`, `technician_day_changed`, `job_on_hold`, `solver_failed`, `ingest_rejected`, `vehicle_pattern_stale`, `job_unplannable`) -- no doc enumerates a closed list. PH6.2 (`api-notifications`, #43) will likely need to add kinds; since `contracts/` is sealed after PH1, that's a `!` commit with a changelog entry per `docs/12-implementation-plan.md`, not a normal PR. **`adjusted_confidence` hook signature** (for T-B #17 / T-G #22): `polaris.contracts.scorer.AdjustedConfidenceFn` -- a `Protocol` taking `AdjustedConfidenceInputs` (`feed_confidence`, `site_score`, `vehicle_site_weekday_score`, `floor`, `ceiling`) and returning `float`. T-B calls it per window it builds; T-G implements it in `projector/adjust.py` (PH4.3). See `backend/tests/unit/contracts/test_projector_scorer.py::test_adjusted_confidence_hook_signature_is_usable` for a worked example. **`TaskPayload` kinds**: `project_windows`, `solve`, `solve_event`, `validate`, `score` -- `solve` covers `daily`/`override`/`manual` (mode carried in the payload); `solve_event` is the separate freeze-window path PH5.2 (#34) names its own handler file for. If T-E (#20) or PH5.2 want a different split, that's a contracts change (`!` commit) -- flagging now so it's a deliberate decision, not a surprise later. Opening the PR next.
bart closed this issue 2026-09-11 11:14:23 +00:00
Sign in to join this conversation.
No labels
ready-for-agent
No milestone
No project
No assignees
1 participant
Notifications
Total time spent: 9 minutes 50 seconds
bart
9 minutes 50 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
patrick/Polaris#12
No description provided.