Skip to content

Adds a library hold at its own BasicHTTP location - #176

Merged
johnnyt merged 2 commits into
mainfrom
se-jg43-basichttp-front-example
Sep 30, 2026
Merged

johnnyt merged 2 commits into
mainfrom
se-jg43-basichttp-front-example

Conversation

@johnnyt

@johnnyt johnnyt commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

The reference host now shows statifier_router's durable BasicHTTP front, in the library world only.

What it does

  • StatifierExamples.HoldDesk: a router configuration of its own that sets :basichttp (base URL: the endpoint's URL plus /basichttp). Each hold execution it creates gets a location. StatifierExamples.RoutedWorkflow's parcel configuration sets no :basichttp, and a test asserts that.
  • The chart (priv/library/hold_desk.scxml): a patron's hold at a branch desk. On hold.requested it sends hold.placed with <send type="basichttp"> to the desk the request names, passing reply_to read from _ioprocessors['basichttp']['location']. It finishes in shelved on copy.shelved, or in desk_unreached on error.communication.
  • The outbound send: planned with StatifierRouter.BasicHTTP.deliver/3 and performed with perform/2 in the host's own executor (HoldDesk.execute/2). The router leaves outbound sends at the executor seam to the host. A delayed BasicHTTP send is refused.
  • The front: StatifierExamplesWeb.BasicHTTPController.event/2, routed for every method at /basichttp/:token outside the browser pipeline. It builds the request map, calls StatifierRouter.BasicHTTP.Front.handle/3 and answers Front.response/1: 204, 404, 405 with allow: POST, or 400.
  • The location table: priv/repo/migrations/20260930120001_add_statifier_router_locations.exs calls StatifierRouter.Migrations.up_locations/1 (down_locations/1 on rollback). It uses the same depot_id leading column as the app's first router migration.
  • The bearer capability: a location is a bearer capability (ruled by the operator, 2026-09-30). The new guide docs/guides/basichttp-front.md, the HoldDesk moduledoc and the controller moduledoc all say so.
  • Tests: test/statifier_examples_web/controllers/basic_http_controller_test.exs drives it end to end through the endpoint with Phoenix ConnTest on the app's SQLite. The outbound POST goes to a test transport (test/support/desk_transport.ex), which hands it back to the test. The test then POSTs copy.shelved at the reply_to location through the controller.

Dependencies

  • {:statifier_router, "~> 0.9.2"}. 0.9.2 is the first release whose migrations (V03, fixed in 0.9.1) and Addresses.reap/3 (fixed in 0.9.2) both run on this app's SQLite database. 0.9.0 ships the front.
  • {:statifier, "~> 2.10"}, which router 0.9.2 requires. It ships Statifier.Send.BasicHTTP.
  • mix.lock moves three entries: statifier 2.9.0 to 2.10.0, statifier_router 0.6.0 to 0.9.2, and statifier_persistence 0.21.0 to 0.24.0, which came in with the router update. The persistence requirement stays at ~> 0.20, and none of 0.22.0 to 0.24.0 adds a migration.
  • No version bump of this app.

Provenance

These changes are forced by the bead but were not in its file map:

  • Raw-body reader on the endpoint. Plug.Parsers consumes a form body before any action runs, and the front needs the body as it arrived. The parsers now take body_reader: {StatifierExamplesWeb.RawBody, :read_body, []}, which keeps the raw body only for /basichttp paths. Every other path reads as before.
  • Guide version tables. docs/guides/first-workflow.md, docs/guides/first-workflow-routed.md and docs/guides/migrating-waiting-executions.md state what mix.lock resolves. Their pin tables and move notes now name the new versions: version facts only, no new example. Three tests that pin versions in the recipes' first output line now match the new lines (first workflow, routed workflow, migrate waiting), and test/statifier_examples/mix_deps_test.exs asserts the new requirements and lock entries.
  • persistence 0.21 to 0.24. See Dependencies.
  • Review cure: the token stays out of the request log. The desk's POST path carries the location's token, and Phoenix logged it with the request line at :info. The endpoint's Plug.Telemetry now takes log: {StatifierExamplesWeb.Endpoint, :log_level, []}, which logs no request line under /basichttp; the route is log: false; and config :phoenix, :filter_parameters names token beside password. A test captures a POST at :debug and finds the token in no log line except Ecto's query lines. At :debug those print bound parameters, and the router binds the token, so the guide and the controller's moduledoc tell a host to keep :debug out of production.
  • error.communication, not a failed route. An executor {:error, _} for a send does not fail the delivery: statifier_persistence enters error.communication into the execution in the same step. The chart takes that to desk_unreached, and a test covers it.

Gate

Full mix quality on the committed tree (head after the review cure). The same tree (git write-tree before and after the run) was committed with the repo gate lock and a machine slot held throughout:

✓ Format: No changes needed (371ms)
✓ Compile: dev + test compiled (warnings as errors) (1.6s)
○ Doctor: skipped (:doctor not installed)
○ Docs: skipped (opt-in; set docs: [enabled: :auto] in .quality.exs)
○ Doc links: skipped (opt-in; set doc_links: [enabled: :auto] in .quality.exs)
○ Sobelow: skipped (:sobelow not installed)
○ Gettext: skipped (no .po files outside the source locale)
✓ Dependencies: No unused dependencies (398ms)
✓ Credo: No issues (1.7s)
✓ Dialyzer: No warnings (4.7s)
✓ Tests: 655 of 655 passed, 84.8% coverage (49.8s)
✓ All quality checks passed!

Each sabotage noted above a new test was run on its own, restored from a copy (byte-equal by cmp) and recompiled. Each turned a named test red on an assertion, including Phoenix ConnTest's response/2 status check.

The reference host now shows statifier_router's durable BasicHTTP
front in the library world. StatifierExamples.HoldDesk is a router
configuration of its own that sets :basichttp, so each hold it creates
gets a location; the parcel configuration sets none. A hold tells the
branch desk it was placed through the processor, planned and performed
in the host's executor, with its location as reply_to, and the desk's
copy.shelved POST at that location reaches BasicHTTPController, which
hands it to StatifierRouter.BasicHTTP.Front and answers response/1. A
send the desk refuses re-enters as error.communication and the hold
ends desk_unreached.

A new migration creates the location table with up_locations/1. The
router moves to ~> 0.9.2, the first release whose migrations and
address reaper run on SQLite, statifier to ~> 2.10, and mix.lock takes
statifier_persistence 0.24.0 with them; the guides' pin tables follow.

Refs: se-jg43
A location's token rode in the path of every desk POST, and Phoenix
logged that path at :info with the request line. The endpoint's
Plug.Telemetry now takes log_level/1, which logs no request line under
/basichttp; the route is log: false; and :filter_parameters names
token. A test captures a POST at :debug and finds the token in no log
line but Ecto's query lines, which print bound parameters at :debug;
the guide and the controller's moduledoc say so.

Refs: se-jg43
@johnnyt
johnnyt merged commit 1f59451 into main Sep 30, 2026
3 checks passed
@johnnyt
johnnyt deleted the se-jg43-basichttp-front-example branch September 30, 2026 21:12
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