Skip to content

Release 2026.03.1 - #2033

Merged
divbzero merged 18 commits into
mainfrom
develop
Apr 7, 2026
Merged

Release 2026.03.1#2033
divbzero merged 18 commits into
mainfrom
develop

Conversation

@divbzero

@divbzero divbzero commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Includes changes tested in 2026.03.1-rc1.

sricharan-varanasi and others added 18 commits March 4, 2026 16:24
…pletion (#2023)

Fix: before selecting best_in_progress, filter out any in-progress submissions
whose end_time is older than best_completed.end_time. These are definitionally
stale - they predate the most recent completion and were superseded by a
restart-and-complete cycle.

Adds unit tests covering:
- per-submit_id collapsing
- best completed selection
- best in-progress selection with and without prior completions
- the exact restart bug scenario (A stale, B completed, C new in-progress)
- edge cases: empty input, multiple flows, boundary timestamps
…sion (#2020)

When a version mismatch is detected for a flow submission, adopt the
version from the existing answer group instead of rejecting with a 400.
This allows in-progress flows to be completed after an applet version
update. Re-validates flow progress with the corrected version's history
IDs.

* feat: add version-aware activity endpoint for deleted flow resume

Add optional 'version' query parameter to GET /activities/{id} endpoint.
When version is provided, fetches activity data from the immutable
history tables instead of the live activities table. This allows the
frontend to load activity items for activities that were deleted from
the current applet version but are still needed for resuming an
in-progress flow.

- Add _get_by_language() helper for multi-language to single-language conversion
- Add _get_activity_from_history() to fetch and convert history records
- Modify activity_retrieve() to accept optional version param

* feat: add flow_activity_ids to CompletedEntity for cross-device flow resume

* fix: version-aware in-progress flow filtering and COUNT-based activity_flow_order

* feat: add flow_name to CompletedEntity for cross-device resume

* fix: add null check for flow_history_id before dict access

* fix: exclude flowActivityIds and flowName from completed flows

- Add model_serializer to conditionally exclude flowActivityIds and flowName when None
- These fields should only appear for in-progress flows (is_flow_completed=False)
- Maintains backwards compatibility with existing API consumers
- Add null check for flow_history_id before dictionary access in CRUD

* test: add tests for cross-version flow resume
🔗 [Jira Ticket M2-10475](https://mindlogger.atlassian.net/browse/M2-10475)

Add index on `answers_items.answer_id` to speed up `JOIN` for the `AnswerSchema.answer_item` relationship.

Related to #2022.
🔗 [Jira Ticket M2-10475](https://mindlogger.atlassian.net/browse/M2-10475)

@jodybrookover reminded me to check the arbitrary database too.

The arbitrary database shares the same SQLAlchemy schemas but has a separate set of Alembic migrations. Turns out that the arbitrary database already has an index for `answers_items.answer_id` but was missing other indexes.

Changes include:
- Configure Alembic to generate blank revision with `uv run alembic -c alembic_arbitrary.ini revision`.
- Add indexes to arbitrary database for `answers.applet_id`, `answers.flow_history_id`, `answers.event_history_id`, and `answers.device_id`.

Related to #2021.
…#2018)

🔗 [Jira Ticket M2-9037](https://mindlogger.atlassian.net/browse/M2-9037)

This is a breaking change! Any previously available `POST /themes`, `PUT /themes/{pk}`, and `DELETE /themes/{pk}` endpoints will now fail and return `404 Not Found`.

Changes include:

- Removed the `POST /themes` (create theme) endpoint — any authenticated user could previously create themes visible to all MindLogger users, enabling abuse (profanity in names, inappropriate images)
- Removed the `PUT /themes/{pk}` (update theme) endpoint — same concern
- Removed the `DELETE /themes/{pk}` (delete theme) endpoint — any authenticated user could previously delete any and all themes including the default one
- Removed associated tests for the above endpoints

Only `GET /themes` remains. Themes can now only be managed directly in the database.

The underlying service and CRUD code for create, update, and delete are intact — the endpoints are simply no longer registered with the router. This makes it straightforward to restore or gate behind an admin/superuser permission in a future ticket if needed.
🔗 [Jira Ticket M2-9233](https://mindlogger.atlassian.net/browse/M2-9233)

Changes include:
- Added order by statement
- Added tests (which mostly ignore the style of the other tests that use the problematic personas)

Testing:
1. Login to the admin
2. Invite a user
3. delete the user/invite
4. invite the user again
5. repeat this a few times so you have a good chance of failure
6. In the admin, copy the invite link - it should work. Previously, it was returned non-deterministically and might not work
🔗 [Jira Ticket M2-10393](https://mindlogger.atlassian.net/browse/M2-10393)
🔗 [Jira Ticket M2-10460](https://mindlogger.atlassian.net/browse/M2-10460)

Changes include:

`make audit` to identify dependencies with reported vulnerabilities using `uv-secure`:

    make audit
    make audit SEVERITY=low       # same as `make audit`
    make audit SEVERITY=medium    # medium or greater severity
    make audit SEVERITY=high      # high or greater severity
    make audit SEVERITY=critical  # critical severity only

Upgrade dependencies to remove high vulnerabilities:

    uv add "aiohttp>=3.13.3"
    uv add "cryptography>=46.0.5"
    uv add "python-multipart==0.0.22"
    uv sync --upgrade-package azure-core
    uv sync --upgrade-package protobuf
    uv sync --upgrade-package pyasn1
    uv sync --upgrade-package starlette
    uv sync --upgrade-package urllib3

Upgrade dependencies to remove remaining vulnerabilities:

    uv add --dev "pre-commit>=4.5.1"
    uv sync --upgrade-package filelock
    uv sync --upgrade-package h2
    uv sync --upgrade-package orjson
    uv sync --upgrade-package virtualenv
    uv sync --upgrade-package Werkzeug

Remove unused dependencies:

    uv remove bytecode
    uv remove more-itertools
    uv remove pyopenssl
    uv remove --dev greenlet
    uv remove --dev ipdb
    uv remove --dev pudb
    uv remove --dev pytest-lazy-fixtures
    uv remove --dev reproschema

Install S3 type annotations for `boto3` in `dev` only:

    uv remove boto3-stubs
    uv add --dev "boto3-stubs[s3]>=1.40.60"

Before: 215 dependencies with 24 vulnerabilities (4 low, 10 medium, 10 high)
After: 184 dependencies with 0 vulnerabilities
🔗 [Jira Ticket M2-9695](https://mindlogger.atlassian.net/browse/M2-9695)
🔗 [Jira Ticket M2-10487](https://mindlogger.atlassian.net/browse/M2-10487)

We’ve accumulated a number of SQLAlchemy schema changes that aren’t reflected in the Alembic migrations and vice versa, so `uv run alembic revision --autogenerate` hasn’t been working cleanly. The following changes bring SQLAlchemy schemas and Alembic migrations back in sync. The PRs when schema and migration deviated are included for reference.

Add SQLAlchemy schemas missing in Alembic’s list of `migrations_apps`:
- `apps.activity_assignments.db.schemas` #1511
- `apps.integrations.loris.db.schemas` #1580

Update SQLAlchemy schemas to match Alembic migrations:
- `Text()` → `String()` for `answers.{applet,activity,flow}_history_id` #518
- `String(56)` → `String(100)` for `users.email` #528
- `name="token_purpose"` for `token_blacklist.type` enum #551
- `String(5)` → `String(20)` for `subjects.language` #1217
- `ForeignKey` → `UUID` for `activity_assignments.{activity_id,activity_flow_id}` #1533
- `nullable=False` for `event_histories.{version,periodicity}` #1718
- `nullable=False` for `events.{version,periodicity}` #1733
- `index=False` for `answers.{event_history_id,device_id}` #1754
- `Index(postgresql_using="gin")` for `subjects.meta` #1798
- `onupdate="CASCADE"` for `{subjects,events}.id` foreign keys #1802
- `UniqueConstraint` for `answers_ehr (submit_id, activity_id)` #1837
- `nullable=False` for `subjects.is_deleted` #1855
- `nullable=False` for `users.mfa_enabled` #1973

Add missing `token_blacklist.type` enum values:
- `MFA = "mfa"` #1976
- `DOWNLOAD_RECOVERY_CODES = "download_recovery_codes"` #1983

Drop tables and columns left over from schedule migration:
- `{activity,flow,user}_events` tables #1723
- `periodicity` table and `events.periodicity_id` column #1733
- `subjects.is_deleted_null` column #1855
- `applet_events_cleanup` table #1858

Drop redundant `(submit_id, activity_id)` composite index:
- Already indexed by `answers_ehr_submit_activity_key` unique constraint #1837

Create missing `consents` table:
- Defined for LORIS integration but never created #1580

After the changes, test autogenerate yields an empty migration:

    uv run alembic upgrade head
    uv run alembic revision --autogenerate -m "Test autogenerate migration"
@divbzero
divbzero requested a review from aweiland April 7, 2026 13:43
@divbzero
divbzero merged commit 3b2592f into main Apr 7, 2026
62 of 66 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants