Skip to content

fix(tasks): write slug+owner on task create, accept either id or slug#63

Merged
jeewoo-lee merged 1 commit into
mainfrom
fix/task-create-slug-compat
Apr 27, 2026
Merged

fix(tasks): write slug+owner on task create, accept either id or slug#63
jeewoo-lee merged 1 commit into
mainfrom
fix/task-create-slug-compat

Conversation

@jeewoo-lee

Copy link
Copy Markdown
Collaborator

Summary

  • POST /tasks accepts both id and slug form fields, normalizes to one task_id, and now writes slug + owner='hive' into the row.
  • _sync_tasks_from_github and POST /tasks/private also write slug + owner (private uses owner=str(user_id)).
  • Adds an idempotent migration that ADD COLUMN slug / owner on tasks when missing — no-op on prod where they already exist.

Why

Production's tasks table has slug NOT NULL and owner NOT NULL columns (added externally from the unmerged staging refactor 472d4b7), but main's INSERTs don't supply them. Every public POST /tasks and every _sync_tasks_from_github insert has been failing with psycopg.errors.NotNullViolation: null value in column "slug" — visible repeatedly in prod logs. Repo gets created on GitHub, then the DB row never lands, so the task is never registered. Separately, the published 0.2.6.dev1 CLI sends only slug (it was cut from a slug-aware branch), which the old id-only signature rejects with 422 before reaching the DB.

This patch is a compatibility bridge until the full owner/slug refactor merges from staging. CLI is intentionally untouched — accepting either field on the server unblocks all current clients.

Migration safety

Additive + idempotent. Each ALTER is gated on an information_schema.columns check; slug is backfilled (UPDATE tasks SET slug = id WHERE slug IS NULL) before SET NOT NULL; owner gets a DEFAULT 'hive' so existing rows satisfy NOT NULL immediately. On prod (where both columns already exist) the entire block is a no-op. No DROP, no type change, no destructive DDL.

Test plan

  • Boot server against a fresh local Postgres → migrations create slug, owner cleanly.
  • Boot server against a Postgres dump that already has slug/owner (or run the same boot twice) → migration skipped, no error.
  • curl -F id=foo -F name=Foo -F description=... -F archive=@t.tar.gz /api/tasks → 201, row visible in tasks with slug='foo', owner='hive'.
  • curl -F slug=bar ... (no id) → 201, row inserted with id=slug='bar'.
  • curl with neither id nor slug → 400 "id (or slug) is required".
  • curl -X POST /api/tasks/sync → discovered task--* repos register without NotNullViolation in PG logs.
  • POST /api/tasks/private with a real user GitHub repo → row inserted with slug=task_id, owner=str(user_id).

🤖 Generated with Claude Code

Production tasks table has NOT NULL slug and owner columns (added externally
from the unmerged staging refactor 472d4b7), but main's POST /tasks insert
omits them — every public task create has been failing with NotNullViolation.
The published 0.2.6.dev1 CLI also sends slug instead of id, so requests are
422'd by FastAPI before reaching the DB.

- POST /tasks: accept id and/or slug as form fields, normalize to one
  task_id, insert (id, slug=task_id, owner='hive', ...).
- _sync_tasks_from_github: insert slug+owner.
- POST /tasks/private: insert slug+owner (owner=str(user_id) for per-user
  namespace).
- db.py: add idempotent migration that ADD COLUMN slug/owner if missing
  (gated on information_schema). No-op on prod where they already exist.

CLI is intentionally untouched — server now accepts both shapes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeewoo-lee
jeewoo-lee merged commit 9ed3159 into main Apr 27, 2026
1 check 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.

1 participant