-
-
Notifications
You must be signed in to change notification settings - Fork 0
Dependency Policy
Why some dependencies sit well behind their latest release, and what it would take to move them. Everything here is deliberate — if you are wondering why an automated bump keeps being closed, this is the page.
| Dependency | Held at | Why |
|---|---|---|
| PostgreSQL | 17 | A major Postgres version is a data migration, not a dependency bump |
| jQuery | 3.x | jQuery 4 removes APIs used in ~86 places, and Bootstrap 4 forbids it |
| Node | 24 LTS | Odd-numbered Node releases never get an LTS phase |
| marshmallow | 3.x | marshmallow 4 is a schema-wide migration |
| docxcompose / python-docx / docxtpl | pinned | The vendored report generator hard-pins them |
A PostgreSQL 18 server will not start on a PostgreSQL 17 data directory. Bumping the
image tag means every existing installation comes up with a crash-looping database, not a
warning. Moving majors requires a pg_dumpall, removing the volume, starting the new
version clean, and restoring — the shape scripts/migrate_postgres_17.sh implements for
the 12 → 17 move.
There is also no urgency: PostgreSQL 17 is supported until 2029. The 12 → 17 move was forced by end of life; this one is not.
The interface is Bootstrap 4 and jQuery 3. Two independent blockers:
-
Bootstrap 4 declares
jquery: "1.9.1 - 3". jQuery 4 is outside the range its dropdowns, modals, tabs, tooltips and collapses are built against. -
jQuery 4 removes APIs this codebase uses in roughly 86 places —
.bind(),$.proxy,$.trim,$.isFunction,$.isArray,.unbind(),$.parseJSONand others, before counting the bundled plugins.
Nothing fails at build time. The bundle would build, ship, and break in the browser one interaction at a time. Migrating means moving to Bootstrap 5 first — which drops jQuery entirely — then replacing jQuery UI and sweeping the removed APIs.
Node alternates: even-numbered releases become LTS, odd-numbered ones are "Current" for about six months and then reach end of life without ever becoming LTS. An automated bump sees a higher number, not the support policy — Node 25 was already past end of life when it was first proposed.
Node is build-time only here: it compiles the UI bundle, and the runtime image contains no Node binary. A major bump has also been verified to produce byte-identical bundles, so tracking Current buys nothing. The project moves to the next LTS deliberately.
flask-marshmallow 1.5.0 and later require marshmallow>=4.0.0, so flask-marshmallow is
held at 1.4.0 — the last release that still accepts marshmallow 3. marshmallow 4 changes
schema semantics across every serializer in datamgmt/, which is a project rather than an
upgrade.
docx_generator is vendored as a wheel and hard-pins docxcompose, python-docx and
docxtpl. Bumping any of them breaks .docx report generation. This stack is deliberately
frozen; see Development Guide.
Everything else tracks upstream, including SQLAlchemy, alembic, celery, Flask and
its extensions, cryptography, requests, and the nginx and Python base images.
setuptools is kept current despite a complication worth knowing about: setuptools 81
removed pkg_resources, which two dependencies still import at module load. A build-time
patch (source/patches/depatch_pkg_resources.py) rewrites those imports to importlib
equivalents. It is content-matched and fails the build loudly if a future version moves the
code, rather than regressing silently.
A green build is not evidence that a Python dependency upgrade worked. The pkg_resources
case is the reference example: pip install succeeds, docker build succeeds, the image is
produced — and the application dies at startup, because the missing module is only imported
when the app boots.
Check the things that actually break:
docker compose -f docker-compose.dev.yml build app
docker compose -f docker-compose.dev.yml up -d --force-recreate --no-deps app worker ai_worker
docker logs --tail 80 iriswebapp_app | grep -iE "traceback|failed to boot"
curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1/loginFor specific areas: generate a .docx report after touching the reporter stack, query
/graphql after touching graphene, confirm alembic_version advanced after touching
alembic, and exercise a CSRF-protected POST after touching Flask-WTF.
The release string IRIS-NG-v<major>.<minor>.<patch> is not valid PEP 440, so
packaging.version.parse() rejects it. Code comparing IRIS-NG versions must strip the
product prefix first — parse_iris_version() in updater.py does this. Before
IRIS-NG-v1.1.1 the comparison relied on LegacyVersion, which packaging removed in
version 22.
See also: Development Guide · Changelog