First to Site
Release 3.9

Silent Project Status Revert - Fixed

Saving a Core Milestone project from the admin form no longer silently regresses its status to Unprocessed

Overview

Admins reported that saving a project in Core Milestone from the admin detail form would sometimes silently revert the status to Unprocessed, with no audit trail attributing the change. The regression was reproducible on preprod (Trello qXZZmJcI). Release 3.9 closes the loop.

Root cause

Three interacting defects combined to produce the silent revert:

  1. Sidecar mutation behind the form. Expanding a checklist accordion fired POST /api/project/update-assessment-commencement-date/{id}, which recorded the commencement timestamp and also mutated project.status to Commenced Assessment. The admin form's in-memory model was now out of sync with the DB.

  2. Disabled status field. For Core Milestone projects, the admin Project Status field was rendered as a disabled <select>. Disabled form controls are not submitted. Combined with the out-of-sync model, Symfony Form bound status to null on save.

  3. Recovery without attribution. ProjectManager::handleDefaultStatus() correctly defaults a null status to Unprocessed on partial-data-update paths. But because the async ProcessProjectHandler runs without an authenticated user, that recovery write left no system_log row - making the regression look like an unattributed platform action.

Fix

  • Drop the behind-the-form status mutation. The assessment-commencement endpoint now only records the timestamp; it no longer touches project.status. The paired projectStatus.setValue([11]) in custom-ea.js is also removed. Applied in both app/ and ordering/.
  • Replace the disabled select. For Core Milestone projects, the admin Project Status field now renders as an unmapped read-only TextField, so Symfony Form never binds a status value for those projects. Editable AssociationField is kept for every other state, with the Core Milestone option filtered out of the dropdown (it remains system-assigned via ProjectOrderListener).
  • Preserve the auto-transition for non-Core-Milestone projects. The intended auto-transition to Commenced Assessment when expanding a checklist accordion is retained for projects that are not in Core Milestone, where the status field is editable and the behind-the-form mutation never caused a null write. Frontend JS keeps a null-check on #Project_status so it stays a no-op for Core Milestone projects.

ProjectManager::handleDefaultStatus() is left untouched: its behaviour on genuine partial-data submissions is still wanted.

Behaviour after the fix

Project statusAdmin form status fieldOn save
Core Milestone (44)Read-only TextField, unmappedStatus is not submitted; DB value is preserved
Any other statusEditable AssociationFieldAdmin-chosen value is saved as before
Any status, checklist-accordion click(unchanged)Non-Core-Milestone: auto-transition to Commenced Assessment. Core Milestone: no-op

Preprod verification

Traced and reproduced against a Core Milestone project on preprod before and after the fix. Post-deploy, saving the admin detail form no longer regresses status; the auto-transition on checklist expansion still fires for eligible projects.

  • PR #840.
  • Trello qXZZmJcI - reproduction and tracing notes.