Opaque ids for connections/webhooks; flat run routes; drop run_number#155
Merged
Conversation
WIP checkpoint. Adds ConnectionId/PipelineId/WebhookId prefixed-id newtypes (boundary-only, wrap the UUID PK). Converts connections off slug: drop slug column/constraints/name-unique index, model+constraint enum, by-id creator finder, connection-run _all list returns connection id, Connection response exposes id. Establishes the template for webhooks + pipelines. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address API-shape review of config identity:
- connections + webhooks addressed by server-generated prefixed opaque ids
(conn_<uuid>, whk_<uuid>); slug dropped (column, constraints, name-unique
index); name is now mutable and non-unique. pipelines/policies/contexts keep
slugs (human-cited in pipeline definitions).
- pipeline runs addressed by their own opaque id (run_<uuid>) at a flat
/workspaces/{ws}/runs/{runId}/ (+ /detections/, /redactions/); removes the
3-parameter run item routes. create/list stay nested under the pipeline.
- run_number removed from both pipeline and connection run tables (column,
unique constraint, gap-free counter function + trigger); runs are identified
by their UUID.
- connection sync-run HTTP endpoints removed; the table, model, and query layer
are retained for internal per-run data (e.g. last-synced state).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… cleanup
- Restore per-workspace connection name uniqueness (UNIQUE(ws, lower(trim(name))))
dropped alongside slug; add NameUnique constraint arm -> 409 with a clear message.
- find_workspace_run_by_id now filters the owning pipeline's deleted_at and returns
the pipeline alongside the run, so the handler drops its redundant second lookup
and a soft-deleted pipeline hides its runs consistently.
- Scope find_connection_run_by_id through the owning connection's workspace (was
unscoped) to prevent a future cross-tenant leak.
- Remove dead pipeline-run finders (find_workspace_pipeline_run_by_id,
find_pipeline_run_in_workspace) superseded by find_workspace_run_by_id.
- Drop stale DROP FUNCTION set_*_run_number() from both down.sql; fix comments
that still described (pipeline/connection, number) run addressing.
- Rename the pipeline-run handler + response modules to `runs` to match the flat
/workspaces/{ws}/runs/{runId} resource.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A connection's last_synced is the completed_at of its most recent successful (status=completed) sync run, derived rather than stored (consistent with the existing sync-state view). Adds last_successful_sync_at as a single grouped query so a page of connections costs one round-trip (no N+1); a failed or cancelled run does not move the timestamp. This wires the previously-dormant connection-run query layer to its first consumer. Verified live: last_synced is absent until a completed run exists, then reflects the completed run's time and ignores a later failed run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refines the resource-identity model after an API-shape review, applying one discriminator consistently: does a human type or cite the identifier? Human-operated resources keep slugs; machine-referenced ones move to server-generated opaque ids. Also flattens run addressing and removes the now-unused per-parent run numbers.
Identity model
conn_<uuid>/whk_<uuid>run_<uuid>Researched against GitHub/Stripe/Svix/etc. (cited in-thread): opaque-id-as-URL-key is the norm for machine-referenced resources; GitHub keeps
/user+/users/{login}split and addresses workflow runs by flat global id — the model followed here.Changes
PrefixedIdmacro → distinctConnectionId,WebhookId,RunIdnewtypes. Boundary-only: they wrap the existing UUID PK and validate the<prefix>_<uuid>shape on parse, so the DB column staysUuid(no new columns, no data backfill). Distinct types prevent cross-wiring (e.g. aWebhookIdwon't parse on a connection route → 400).slugdropped (column,UNIQUE(ws, slug), length/format CHECKs, and theUNIQUE(ws, lower(name))index); server-generated ids;name/display_namenow mutable and non-unique. Routes{connectionSlug}/{webhookSlug}→{connectionId}/{webhookId}./pipelines/{pipelineSlug}/runs/{runNumber}/…to/workspaces/{ws}/runs/{runId}/,/detections/,/redactions/— removing the only 3-parameter routes. Create/list stay nested under the pipeline (create is naturally per-pipeline).run_numberremoved from both pipeline and connection run tables (column, per-parent unique constraint, gap-free counter function + trigger). Runs are identified by their UUID.Pipelines'
policySlugs/contextSlugsreferences are untouched — policies and contexts stay slug-addressed.Verification
check/clippy --all-targets -D warnings/nightly fmt/rustdoc -D warnings/test(13 suites). Migrations reset+reapplied;schema.rsregenerated and idempotent.conn_/whk_<uuid>with no slug; CRUD by prefixed id; wrong-prefix id on a route → 400; detect returnsrun_<uuid>; run GET/detections/redactions resolve flat at/runs/{runId}/. OpenAPI confirmed: noconnectionSlug/webhookSlug/{runNumber}routes remain; flat/runs/{runId}/*present; pipelines still slug-addressed.🤖 Generated with Claude Code