Issues
MIR-727

WORKDIR fix regression: /app default removal breaks all existing apps

Done public

Problem

The WORKDIR fix (f24f27d7, shipped in v0.4.0) removed the /app default for StartDirectory from the deployment launcher, exec proxy, and build server. This breaks all existing app versions that were built without a start_directory in their config.

Impact on miren-club

Every app without a stored start_directory boots with CWD=/ instead of /app, crashes immediately (e.g., Cannot find module '/app.js'), and the resulting crash-loop storm (~2800 dead sandbox events per 5 minutes) overwhelms the runner reconciler — blocking lease acquisition for ALL apps, even healthy ones.

Apps affected: conference-app, hw-python, hw-node-yarn, hw-node-npm, hw-bun, demo, mirdle, hw-python-pipenv, and more.

User-facing symptoms

  • "error acquiring lease: app/chronoflow" on first request
  • 500 errors after ~60 second timeout
  • Sometimes works on refresh (if an old sandbox from before the server update is still alive)

Root Cause

The chain of failure:

  1. Old app versions were built before start_directory existed or was reliably set → config has no start_directory field
  2. Old launcher code defaulted empty StartDirectory to /app → sandboxes got Directory: /app
  3. New launcher code (WORKDIR fix) removed that default → sandboxes get Directory: ""
  4. New sandbox controller skips WithProcessCwd when Directory is empty → CWD falls through to image default (/)
  5. node app.js runs from /, can't find /app.js → exit code 1
  6. Every app without a stored start_directory crash-loops, generating thousands of events, overwhelming the reconciler, causing "error acquiring lease" for ALL apps

Verified by inspecting the conference-app version entity:

config:
    commands:
      - command: node app.js
        service: web
    # NO start_directory field!

And the resulting sandbox spec has no directory field in its container spec.

Fix

Restore /app defaults in the deployment launcher, exec proxy, and build server. Keep the sandbox controller change (conditional WithProcessCwd) since that part is correct.

Files:

  • controllers/deployment/launcher.go — restore if startDir == "" { startDir = "/app" }
  • servers/exec_proxy/exec_proxy.go — same
  • servers/build/build.go — restore else { spec.StartDirectory = "/app" }
  • servers/build/build_test.go — revert test expectation
  • api/core/schema.yml + schema.gen.go — revert doc strings

The sandbox controller change in controllers/sandbox/sandbox.go should be kept — it correctly avoids overwriting an image's WORKDIR with / when Directory is truly empty.