S12 - Async feedback for scheduling
All checks were successful
Build, test and publish / verify (push) Successful in 7m25s

This commit is contained in:
2026-11-03 23:18:44 +01:00
parent f1785ed174
commit c241392132
34 changed files with 1310 additions and 79 deletions

View File

@@ -1,139 +0,0 @@
# S12 — Asynchronous feedback for scheduling
Status: REFINED
Agreed after the grill-me interview; shared understanding confirmed.
## User story
As a dance-school maintainer, I want feedback after starting Schedule Groups,
so that I can see whether the backend is still calculating, when it finishes
and what the outcome is, including when I leave and return to the show page.
## Background execution and concurrency
- Start scheduling in the backend without keeping the initiating HTTP request
open until the calculation finishes. Navigation, page reloads and disconnected
clients must not stop the calculation.
- The backend owns the current scheduling status for each show. All open
screens see the same status, including screens that did not start the run.
- Allow at most one active calculation per show. Disable Schedule Groups while
it is running and reject duplicate starts in the backend as well.
- Different shows may calculate concurrently. A global capacity limit and a
waiting queue are outside S12.
- Retain the existing 30-minute solver limit and scheduling rules.
## Progress and outcomes
- While running, show elapsed time, the current optimization phase (attendance,
spread or variety), and whether a valid solution has been found.
- Report a valid solution as soon as the solver discovers one, including during
a phase. Extend solver progress reporting rather than waiting for the phase
to finish. Do not apply intermediate solutions.
- Do not present a completion percentage or estimated finish time: the phases
do not represent proportional parts of the calculation time.
- Keep the latest status and outcome per show until a new calculation starts.
Show the finish time and distinguish an optimal solution from a valid solution
whose optimality was not proven within the time limit.
- For a successful result, show a concise summary with concrete results for
attendance, spread and variety, using understandable labels.
- Clearly distinguish invalid input, infeasibility, solver failure, time limit
without a valid solution, rejection because inputs changed, and interruption
by a backend restart. Explain why no result was applied and that existing
assignments were preserved.
## Applying results
- Retain the confirmation before starting that explains replacement of existing
assignments. A successful completed calculation automatically replaces them;
no preview/apply step is introduced.
- A valid solution may be applied when the time limit expires even if optimality
has not been proven.
- Preserve the existing scheduling input revision check. A result based on
outdated inputs must not replace the current assignments.
- Failed, infeasible, interrupted, stale and no-solution calculations preserve
existing assignments.
- Report success only after the resulting assignments have been saved. Keep
status and saved results consistent.
## Server-sent events and connection recovery
- Use server-sent events (SSE) for backend-to-frontend status updates.
- On initial connection and reconnection, provide the current backend status.
Correctness must not depend on receiving every previous event.
- Maintain updates across navigation within the application so completion
notifications can appear outside the show page.
- If the connection is lost, indicate that displayed status may be outdated
while the backend calculation continues. Reconnect and reconcile with the
current status when connectivity returns.
- Configure the application's proxy for streaming so updates reach the client
promptly rather than being buffered until completion.
## Completion notifications
- Show an application-wide snackbar when a calculation completes or fails,
including when the user has navigated to another application page.
- Include the show name, a short outcome and a View show action.
- Phase changes update progress without generating snackbars.
- After temporary connection loss, show a missed completion notification once
when the connection recovers. Reconnection must not repeatedly notify for
the same completion.
- Do not replay old snackbars on page reload or reopening the application;
show the retained status on the show page instead.
- Email, browser notifications and notifications outside the application are
outside S12.
## Persistence and backend restarts
- Retain the latest scheduling status and outcome across backend restarts,
aligned with the PostgreSQL persistence specified in
`S16_store-state-in-persistent-storage`.
- Calculations interrupted by a backend restart become recognizably Interrupted
rather than remaining Running indefinitely. Do not resume them automatically;
allow the user to start again.
- Previously saved results survive restart. Volatile in-memory status alone
does not satisfy S12; its implementation must integrate with S16 storage.
- Target the single active backend instance defined by S16. Distributed
execution and scheduling on another PC remain in S13.
## Out of scope
- Cancelling a calculation or applying an intermediate solution.
- History of earlier calculations beyond the latest status and outcome.
- Global capacity limits, queues and remote workers.
- Changes to scheduling objectives or constraints.
- This specification grants no coding-standards waiver.
## Acceptance criteria
- [ ] Starting Schedule Groups returns without waiting for solver completion;
leaving or reloading the page does not interrupt the calculation.
- [ ] Opening a show in another screen recovers its current backend status;
duplicate runs for the same show are prevented in frontend and backend,
while different shows can run concurrently.
- [ ] Running status shows elapsed time, phase and discovery of a valid solution
during a phase, without a fabricated completion percentage or ETA.
- [ ] SSE delivers status changes promptly through the deployed proxy. Initial
connection and reconnection reconcile the current state, and loss of
connectivity visibly marks status as potentially outdated.
- [ ] Successful runs automatically apply their result after the existing start
confirmation, retain stale-input protection and distinguish proven optimal
results from valid results at the time limit.
- [ ] The final display includes finish time and concrete attendance, spread and
variety results when successful; unsuccessful outcomes are distinguishable
and explain that previous assignments were preserved.
- [ ] An application-wide snackbar reports completion or failure with the show
name and View show action, including after navigation to another page.
- [ ] Connection recovery notifies once for a missed completion; phase changes,
repeated reconnection and reopening do not replay old snackbars.
- [ ] The latest status and outcome survive navigation, reload and backend
restart through persistent storage integrated with S16.
- [ ] After backend restart, interrupted calculations are marked Interrupted,
do not resume automatically and can be started again; saved results remain.
## Implementation handoff
This specification records the agreed design and behavior. Backend and frontend
changes, persistence integration, proxy configuration and validation are
subsequent implementation work. S12 replaces S9's synchronous request behavior
while retaining the existing scheduling and result-application protections.

View File

@@ -69,6 +69,34 @@ JSON remains the import/export format, rather than the primary storage model.
interrupted, rather than remain indefinitely marked as running. They do not
resume automatically. Previously saved results remain available.
## Persistent scheduling status (transferred from S12)
The maintainer explicitly moved durable scheduling status and backend-restart
recovery from S12 to S16 when completing S12. S12 supplies background execution,
status snapshots, SSE and notifications within the lifetime of the backend.
- Persist the latest calculation per show in PostgreSQL, including its run
identifier, school/show identity, start and finish timestamps, state, latest
phase, whether a valid solution was found, outcome explanation and final
attendance/spread/variety summary when available. A run history is not required.
- Persist acceptance of a run before acknowledging its start. After restart or
crash, an accepted calculation must remain identifiable even if it never
produced a result.
- Commit successful assignment replacement and its completed run status
atomically. Publish success through the status API and SSE only after the
transaction commits. A failed commit must not leave a successful status with
missing assignments, or replaced assignments with an outdated running status.
- On startup, mark calculations left Running by the previous backend instance
as Interrupted before serving their recovered status. Explain that no new
result was applied, retain previously saved assignments and allow a new run.
Do not resume calculations automatically or retain their old run-slot guards.
- Recover the latest status and outcome through S12's existing status endpoint
and initial/reconnection SSE snapshots. Preserve stable run identifiers so
reconnecting clients can deduplicate notifications; reopening the application
must not replay old completion snackbars.
- Verify recovery after both graceful restart and abrupt process termination,
including a calculation running at termination and a completed saved result.
## Database failures and schema changes
- Refuse mutations while the database is unavailable and provide a clear failure
@@ -103,8 +131,14 @@ for now. S16 does not promise recovery after loss of the database or its volume.
another: the stale edit receives a clear conflict response, and the user
can reload and retry.
- [ ] Scheduling results based on outdated input revisions are rejected.
- [ ] Interrupted calculations are recognizably interrupted after restart;
previously saved results remain available.
- [ ] The latest accepted scheduling run, its stable identifier, timestamps,
progress, outcome and objective summary survive normal restart and crash
and are returned through the status API and SSE snapshots.
- [ ] Successful assignment replacement and completed run status commit
atomically; success is published only after durable commit.
- [ ] Calculations left Running become Interrupted before recovered status is
served; previous assignments remain, no automatic resumption occurs and a
new run can start. Reopening does not replay old completion snackbars.
- [ ] Database unavailability prevents successful mutation acknowledgements;
startup connection and migration failures are clearly reported.
- [ ] An empty database can be initialized through Flyway and populated through