# Scheduled jobs service fixture

Python standard library only. Existing tests use mocked repositories: `python3 -m unittest discover -s tests`. Start `python3 app.py --port 17808 --database /absolute/test.sqlite`. Run `python3 database.py /absolute/test.sqlite` to apply migrations. Build `python3 -m compileall -q app.py routes.py database.py worker.py`; delivery is these Python modules, with no container/signing requirement.

Implement authenticated tenant-scoped POST /jobs and GET /jobs/<id>. Synthetic fixture tokens are tenant-a-token and tenant-b-token, mapped server-side to tenant-a and tenant-b. Unauthenticated requests return 401; accessing another tenant's job returns 404 without disclosure. POST body: idempotencyKey string, runAt integer seconds, payload object containing a message string. Same tenant/key retried must create one job. Invalid input returns 400. Return a JSON job with id, runAt, payload, status. Existing GET /v1/ping response must remain exactly {"status":"ok","apiVersion":1}.

Worker is invoked by an external scheduler: `python3 worker.py --database /absolute/test.sqlite --now-seconds 100`. Execute due pending jobs, persist completed status, and append one durable execution event per job; repeated runs must not duplicate effects. Expose the worker's observed executed count in stdout JSON. Use injected now-seconds, not sleeps. Before feature migration, database.py creates the legacy_metadata table with a sentinel row; preserve it on upgrade. Exercise migration on such existing data in an isolated database. No deployment is authorized. Use real HTTP requests and SQLite, not only mocks, to verify feature behavior.
