Adds the BasicHTTP front for durable executions - #138
Merged
Merged
Conversation
Implements the ADR-0002 Amendment of 2026-09-30. A configuration that sets :basichttp registers StatifierRouter.BasicHTTP under the W3C processor URI and basichttp, and each execution created under a new address row gets a location: the base URL and a minted 43-character token, stored in the new V04 locations table and handed to the create so the execution's _ioprocessors carries it. location/2 reads it and rotate_location/2 replaces it. StatifierRouter.BasicHTTP.Front decodes a POST with statifier's decoder, delivers through deliver_event/4 under the name basichttp with create: :never, deduplicates per execution on scxml-send-key, and maps the answer to 204, 404, 405, 400 or 500. Without the key nothing changes. statifier ~> 2.10. Refs: sr-xgi8
Cures the review finding that V04 in the version walk changed what up/1 and down/1 answer for every host. V04 leaves the walk: up/1 and down/1, capped or not, answer exactly as before this branch, and a host that sets :basichttp runs the location table with the new Migrations.up_locations/1 and down_locations/1 in a later migration of its own. V04's down drops the table only if it is there. The existing migration tests are back to main's, unchanged; a new module covers the pre-V04 rollback, the documented opt-in migration's full rollback and a host that opts in from one migration. Refs: sr-xgi8
The moduledocs of StatifierRouter.Migrations and StatifierRouter.Migrations.V04, and the README's upgrade section, now cite ADR-0002's Amendment of 2026-09-30 that decides the location table is opt-in, outside the version walk, where they name up_locations/1 and down_locations/1. Refs: sr-xgi8
johnnyt
force-pushed
the
sr-xgi8-basichttp-front
branch
from
September 30, 2026 16:43
ad08a23 to
f84c1b1
Compare
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.
Implements the two ADR-0002 Amendments of 2026-09-30 (
docs/adr/0002-addressing.md). The first is "Amendment (2026-09-30, sr-xgi8): a durable execution's BasicHTTP location is a rotatable token the router mints, and the front that answers at it", merged in PR 137. The second is "Amendment (2026-09-30, sr-xgi8): the location table is opt-in, outside the version walk", merged in PR 139. This is the code half of sr-xgi8. The location's shape and the front's authentication were ruled by the operator, 2026-09-30; everything else follows the two Amendments.What each decision of the first Amendment became
StatifierRouter.BasicHTTP.mint_token/0mints 32 bytes from:crypto.strong_rand_bytes/1as unpadded URL-safe base64, 43 characters.StatifierRouter.Migrations.V04creates thelocationstable:address_idreferences the address row'sidwithON DELETE CASCADE, and there are unique indexes onaddress_idandtoken. The reference follows the:primary_keytype.StatifierRouter.Migrations.up_locations/1anddown_locations/1, which take the storage options, the layout options and:primary_key, and no:fromor:version.up_locations/1creates only what is missing;down_locations/1drops the table only if it is there.StatifierRouter.Schema.Locationis the table's schema.StatifierRouter.Delivery's privatelocate/3inserts the location beside the address row that an:if_absentinsert wrote. It runs only when:basichttpis set, in the same transaction and savepoint, beforecreate/4.always_newexecution gets no location, and its entry is%{}.StatifierRouter.BasicHTTP.rotate_location/2makes one insert-or-replace onaddress_id. It answers{:error, {:no_address, id}}when no address row names the execution.location/2answers{:error, :no_location}when there is no location. A rotation does not reach the chart's_ioprocessors, as the record says.resolve/2reads the address row through its location. A token that is not token-shaped, an unknown token and a row stampedterminal_seen_atare each{:error, :unknown_location}. Delivery goes throughStatifierRouter.Delivery.deliver_event/4with the planbasichttp,create: :neverand the 259_200_000 ms horizon. The binding idbasichttpis reserved only on a configuration that sets the key;StatifierRouter.Config's privaterefuse_reserved_id/2does it.StatifierRouter.BasicHTTPimplementsStatifier.Send.Processor.ioprocessors_entry/2answersbase_url <> "/" <> token.deliver/3,cancel/2andperform/2delegate toStatifier.Send.BasicHTTP.StatifierRouter.Configgains the:basichttpkey. It is refused with{:declared_send_types, type}when a registration clashes and with{:exclusive_keys, :basichttp, :send_types}beside a host's own:send_types.Config.create_persistence_options/2rebuilds the create's snapshot withlocation_token:added. Steps carry the configuration's own snapshot.StatifierRouter.BasicHTTP.Fronthashandle/3andresponse/1. It is Plug-shaped with no process. The request map is:token,:method,:content_type,:body,:queryand:send_key. A refused request is{:invalid_request, keys}and never carries the token. It refuses while a route runs in the calling process. The message id isexecution_id/send_keywith a key, and minted fresh without one. The status table is the record's.StatifierRouter.BasicHTTPandStatifierRouter.BasicHTTP.Frontand in the README's new "A BasicHTTP front" section.What a host sees
:basichttp: nothing changes, the migrations included. No location row is written, the snapshot is built exactly as before, and no binding id is refused beyondexecution.StatifierRouter.Migrations.up/1anddown/1, capped or uncapped, answer exactly as on main: they never create, drop or require the location table, and they refuse no leading-column name they accepted before. The existing migration tests (host_columns_test,index_names_test,migrations_test,primary_key_test) are unchanged from main and pass against this code. The route rules are unchanged, androute.ex,routes.ex,send_handler.exandwebhook.exare untouched, so a URL in a route target stays refused. The test "without :basichttp mints nothing and builds the snapshot as before" pins the configuration half.up_locations/1anddown_locations/1with the same:table_prefix,:prefix, layout options and:primary_keyits earlier migrations pass. The README's "Upgrading the tables" and the Migrations moduledoc, "The location table, V04, is opt-in", show it. Because the table references the address table, that migration rolls back before the one that created V01's tables, which is the order Ecto's rollback takes for a later migration.Provenance
up/1anddown/1answer for existing hosts: an uncappeddown/1on a pre-V04 database, uncappedfrom: 2orfrom: 3migrations, and the leading-column refusal. The cure takes V04 out of the walk and gives it the two opt-in calls.V04.down/1drops the table only if it is there, as V03 renames only what it finds.V01.down/1is unchanged: on a database without V04 it answers as before, and on one with V04 the opt-in migration rolls back first. This follows the first Amendment's "a host that never sets the key does not need V04".up_locations/1anddown_locations/1with their options and refusals, tolerance in both directions, and the rollback order. It merged first. This branch was rebased onto it. The moduledocs ofStatifierRouter.MigrationsandStatifierRouter.Migrations.V04, and the README's "Upgrading the tables", cite it where they name the calls. No code changed in this cure.mix.lockchanged.mix deps.update statifiermoved statifier 2.9.0 -> 2.10.0 and its dependency predicator 9.4.1 -> 9.4.2.PG*defaults inconfig/test.exs.Gate
Full
mix quality, quoted whole:The committed tree is byte-identical to the tree this run was green on. The gate lock and a machine slot were held across both, so the commit was made without a second run.
Every new test in
test/statifier_router/basic_http_test.exsandtest/statifier_router/locations_migration_test.exscarries a sabotage note. The second file covers an uncapped first migration's rollback on a pre-V04 database, the documented opt-in migration's full rollback, a host that opts in from one migration (with the cascade and the unique token), a tolerantdown_locations/1, and the refusals ofup_locations/1. Each mutation was run against the lines this PR adds. Each one failed its test on an assertion, and the file was restored byte-equal before the next.A
changelog.d/sr-xgi8.mdfragment is included under Added.