Releases: SAY-5/launchbridge
Release list
v5.1.0
Explicit event IDs keep their identity. An X-Event-Id header or a payload id whose id:value key would exceed the 255 character ledger column is stored as id-hash: followed by the sha256 of that key, so two IDs sharing their first 252 characters no longer collapse onto one processed_events row and silently suppress the second event's deliveries. A retry still matches an entry written under the old truncated key when the full ID recorded on the original event is the same one, so events accepted by 5.0.0 keep deduplicating rather than being delivered twice.
The webhook and dry run routes are plain functions again and run in the threadpool, and a raw_body dependency reads the body and refuses an oversized one on the declared Content-Length first and then on the chunks as they arrive, so one slow insert no longer serializes every other request on the event loop. A bulk replay selects failed deliveries with FOR UPDATE OF deliveries SKIP LOCKED and re-reads each status inside the transaction, so two administrators replaying at the same time cannot open two replacement series for the same failure. The worker takes its retry decision from RetryPolicy.should_retry and passes the budget recorded on the delivery row, so editing the configuration cannot change the budget of a delivery already queued; pending_count, check_database and DestinationRegistry.for_source are gone, and the first could never have run.
The build under test is traceable from the image to the numbers: /healthz reports the GIT_SHA baked in at image build time, the smoke suite posts it with its totals, smoke_runs stores it under Alembic 0005 and /ops/overview returns it. The demo summary names the build, the machine and the target, and its ingest rate is measured over request time with the deliberate pause excluded. The smoke suite gained --read-only, which skips the three checks that rotate a secret or create replays and reports them as SKIP, and --receiver-header NAME=VALUE, which reaches a receiver fake behind a routing rule the way the Terraform trial exposes it; make smoke-remote refuses the localhost default. The ECS worker task maps the metrics port it documents, 9100, and make install and the CI jobs install from the lockfile.
The browser console under web/ gained a nonce store, so a byte identical replay of a request that was deduplicated answers 409 as the service does, non-ASCII escaped in its JSON the way the service escapes it before signing, and a vectors.json fixture written by tests/test_web_vectors.py that pins the signature, the content hash and the canonical envelope for the port to assert against. The self check no longer runs on a production page load: it is gated and reports its tally in the footer. Contrast tokens, a type floor, live regions, one status to tone map, a stacked diagram under 640 px and a section menu close the accessibility and phone gaps, and a web CI job with make web-ci runs the typecheck, the bundle and the 25 self check assertions while web/README.md states what the port does and does not cover.
The two concurrency claims in ARCHITECTURE.md are tests rather than prose: the same event posted from two threads leaves one ledger row, one delivery set, one 202 and one 200, and two workers draining one queue deliver every row once. 166 tests at this commit.
v5.0.0
Sources can now be onboarded and removed over the API: POST /sources creates one, returns its secret once with the webhook path and signing snippets, and the source can post immediately, while DELETE /sources/{source} closes the webhook again and leaves environment sources read only. GET /ops/overview answers the questions an on-call rotation asks first in one round trip: counters per source, queue depth and breaker state per destination, the deliveries sitting in failed with their last error, the last replay and how it ended, and the last smoke result. The delivery list became a search: status lists, event key, idempotency key, status code, replays only, an error substring, a since and until window, ascending or descending order and stable paging. Smoke runs report their own totals to POST /ops/smoke, backed by a new smoke_runs table in Alembic 0004, so a deployment can be asked when it was last checked. The suite is 141 tests, up from 128, and make demo reads the overview back and compares it against /stats.
v4.0.0
Inbound secrets can be rotated without a cutover window. POST /sources/{source}/rotate issues a new secret (returned once) and keeps the previous one verifying until the overlap expires, after which it is rejected as an invalid signature; rotating again replaces the previous key so at most two are live. GET /sources shows rotation state without exposing secrets.
Replay detection now runs on a nonce store (Alembic 0003): every accepted signature is recorded before anything else, so re-sending a request whose first copy was deduplicated is rejected too, and the worker expires nonces after twice the timestamp window. Outbound keys rotate through destinations.yaml with previous_secret and key_id, which add X-Signature-Previous and X-Key-Id to every delivery. The smoke suite has a rotation check (15 checks); 128 tests.
v3.0.0
Each destination can now carry a token-bucket rate limit and a circuit breaker. A delivery that finds the bucket empty or the circuit open is put back in the queue with a future due time: no attempt is spent, nothing is marked failed, and the backlog drains on its own once a half-open probe succeeds. Permanent 4xx responses do not trip the breaker, only transient failures do.
Breaker state lives in a new destination_states table (Alembic 0002) so a restarted worker resumes where it left off and the API can report it. GET /destinations shows config, circuit state and queue depth; three new Prometheus series cover deferrals, transitions and current state. 119 tests, including an up/down migration round trip.
v2.0.0
Destinations can now decide what they receive. Each entry in destinations.yaml takes sources, event_types globs and when predicates on payload fields, evaluated at ingest, plus a transform block (pick, drop, rename, templated set) that shapes the outbound payload while the stored event stays raw.
POST /dry-run/{source} takes a sample event and returns, per destination, whether it would be routed, the reason when not, and the exact payload it would get. The suite asserts that dry-run output matches what the receiver actually sees. 104 tests.
v1.0.0
First tagged release of the integration service. Signed inbound webhooks with timestamp and replay checks, a PostgreSQL dedup ledger keyed by source and event key, a delivery worker with SKIP LOCKED claiming and bounded exponential retries, and single or bulk replay of failed deliveries under the same idempotency key.
Ships with a compose stack, a 14-check smoke suite that runs against any base URL, a 300-event demo burst, and Terraform for ECS Fargate with RDS. 80 tests.