--- title: "1.11.10 — Deploy failures report themselves, and a release can no longer move every fleet at once" description: "django-mojo 1.11.10 closes the two halves of the 2026-08-14 deploy outage: an update script that cannot run now reports exactly why and releases the deploy plane instead of wedging it silently, and a new operator-controlled framework version hold means a PyPI release no longer changes what fleets in…" date: "2026-08-14" tags: ["release"] canonical: "https://django-mojo.sitesmojo.com/changelog/1-11-10/" --- django-mojo 1.11.10 closes the two halves of the 2026-08-14 deploy outage: an update script that cannot run now reports exactly why and releases the deploy plane instead of wedging it silently, and a new operator-controlled framework version hold means a PyPI release no longer changes what fleets install until someone says so. Hosted login now completes administrator-issued temporary passwords. ### Added - `EDGE_FRAMEWORK_VERSION` — a protected system setting that pins the django-mojo version every fleet deploy installs. Set from the Admin portal (superuser with fresh authentication); `hold` stays on the last converged fleet version; unset keeps installing the newest published release. Read live: a change applies from the next deploy. - The Admin platform page reports the hold (`framework_pin`: configured, value, mode, and what `hold` currently resolves to). - Node update scripts declare a deploy contract (a header marker, plus a `--contract` flag that answers even on an unprovisioned box). A provably stale fork is refused by name before it runs, instead of dying as an unexplained `exit 2`. - Deploy failure evidence carries a redacted tail of the update script's stderr, so a node-side root cause is readable from the platform record without shell access. - The node auditor flags an `aws/update.sh` that has lost its execute bit. - A push recorded against a dead deploy is automatically resumed by the reconciler's next sweep, instead of waiting for another push. ### Changed - A deploy that fails no longer blocks the plane: a terminal failed lease is immediately re-armable, so the next push starts a deploy (`queued: true`) instead of being recorded against the dead attempt until the coordination window expires. - An orchestrator whose deploy is superseded by a newer push stands down cleanly, rather than spinning to its timeout and filing a false canary incident. - Deploy-time nginx activation failures name the missing runtime include, and health-probe timeouts name the port-80 catch-all as the likely cause on edge-converged nodes. ### Fixed - An update script that could not be executed (lost execute bit, missing file), timed out, or was unconfigured bypassed all failure reporting — no incident, no evidence, and a single-runner fleet's deploys silently stopped, stranding every subsequent push. All outcomes now report and close the deployment. - The hosted login page completes administrator-issued temporary passwords: the forced-password response switches to the new-password form and finishes login, instead of stranding the user without a session. Custom login pages branch on `requires_password_change` and call `MojoAuth.completeForcedPassword()`. ### Upgrade notes - Edge-converged nodes must export a vhost-true `PROBE_URL`/`SANITY_URL` from their shim: the packaged localhost default hits the port-80 catch-all, fails the health gate on a healthy app, and makes a rollback report failure on a healthy node. - The documented edge nginx bootstrap needs the runtime include line (now in the docs); without it every deploy's render convergence fails. - Project-side update scripts should ship committed as executable, or better, as the packaged shim — the deploy plane now audits and refuses what it can prove stale. - Contract rule, both directions: anything the deploy plane reads across an upgrade boundary stays readable one generation back.