0.1.113 — Backend prints build provenance at every worker boot

User directive verbatim:

"you should create some debug logs to print the compiled version on backends so that I can know if the docker is using some cache that I dont' know."

The /api/v1/handshake/ endpoint already returns version / commit / build_time from the deployed image — but only when a request can reach the endpoint. If a Docker build silently serves a stale layer cache, or a blue/green deploy mid-cutover routes traffic to the new container before the new routes are registered, the SPA-side handshake reports the truth but the operator has no way to see it from the logs.

What's new

backend/creators/apps.py now defines a CreatorsConfig.ready() method that runs once per gunicorn worker boot and emits a single INFO-level line on the django logger:

[2026-05-05 03:14:22 +0000] [pid] [INFO] django:
  Backend image started:
  Backend.Notechondria.Boot/version_log —
  version=0.1.113 commit=8f0e200ab7c4 build_time=2026-05-05T03:13:50Z
  deploy_target=northflank.
  Grep this line per gunicorn worker boot to confirm the
  deployed image's build provenance even when
  /api/v1/handshake/ is unreachable (e.g. stale Docker layer
  cache, broken route, blue/green mid-cutover).

The log line:

  • Reads from the same _build_metadata() helper that backs /api/v1/handshake/, so the provenance fields are identical regardless of which surface you read.
  • Truncates the commit SHA to 12 chars to keep the line ergonomic.
  • Falls back to <unknown> / <unset> when a field can't be resolved, never crashes — the boot path stays safe.
  • Skips the RUN_MAIN=false branch so manage.py runserver's autoreload parent doesn't double-log on every dev save.

The message follows AGENTS.md §1.8: consequence ("Backend image started"), source module + process (Backend.Notechondria.Boot/version_log), cause (the provenance tuple itself, plus the why-this-line-exists explanation).

Operator runbook

After this round deploys to Northflank, on every worker boot (image roll, scale-up, or worker recycle on idle timeout) you'll see one matching log line per worker. Filter Northflank logs by Backend.Notechondria.Boot/version_log to see the provenance trail.

# Northflank shell, last 100 boot lines:
fgrep 'Backend.Notechondria.Boot/version_log' /var/log/<your-log>

Or in the Northflank web UI:

  1. Service → Logs
  2. Filter: Backend.Notechondria.Boot/version_log

The fastest sanity check after redeploy is to compare the logged version= against the value you just bumped in VERSION. If a redeploy reports version=0.1.105 even though VERSION says 0.1.113, Docker reused a cached layer that includes the old VERSION file — typically because the build context didn't change recently enough to invalidate the COPY VERSION /home/VERSION layer's cache key.

Files changed

  • backend/creators/apps.py — added import logging, import os, module-level logger = logging.getLogger("django"), and the CreatorsConfig.ready() method that logs the boot line.

Verification

  • python3 -m py_compile clean on backend/creators/apps.py.
  • LOGGING = ... in settings.py:180 already routes the django logger at INFO to the console handler (stderr), which Northflank captures into its log stream — no additional logging config needed.
  • RUN_MAIN=false skip prevents double-logging on dev reload; the production gunicorn path doesn't set that variable so the boot line fires once per worker.

No model changes, no migrations, behavior unchanged for any existing endpoint.