feat(effects): <HttpServer> — verified HTTP request handling via vera serve — release v0.0.193#845
Conversation
…pes (#305) S1 of the <HttpServer> stage (server-effects sprint, Stage B). The effect is a marker -- the accept loop lives in the host vera-serve driver, so a handler is an ordinary total, contract-checked handle(Request -> Response) function; no Diverge involved (premise corrected on the issue). - environment.py: HttpServer EffectInfo (no ops) + Request/Response AdtInfo (Request: method/path/headers/body; Response: status/headers/body; headers are Map<String, String>). - prelude.py: the two data decls inject CONDITIONALLY (a new _HTTP_SERVER_DATA block gated on _source_mentions_http_server, the Json/HtmlNode pattern) -- an always-inject first cut broke six no-overhead WAT pins because the Map headers field pulls heap machinery into pure programs; and a conditional _HTML_DATA placement before that never injected at all. User-defined data Request / data Response shadow the prelude. - compilability.py: HttpServer joins the effect whitelist (needs_memory: handlers touch Request/Response heap values). - _since.py: HttpServer since 0.0.193. RED-first: 5 checker tests (row acceptance pinned, registry introspection, prelude-type destructure/construct, State composition, status contract) + 1 codegen compilability/export test; the vacuous _check_ok variants were tightened to _check_clean when 3 of 4 passed before the change. Doc counts follow (5,588 tests). Refs #305 Co-Authored-By: Claude <[email protected]>
S2 of the <HttpServer> stage: the vera-serve driver serves a compiled program's handler with instance-per-request isolation (fresh execute() per request -- WASI.md check 9 measured instantiation at ~0.02 ms, so isolation is effectively free) and sequential v1 request handling. - vera/runtime/heap.py: InstanceCaller (adapts a (Store, Instance) pair to the caller protocol the heap helpers already use -- export lookup via __getitem__ + store-context delegation via __getattr__), build_request_adt (Request built from layout-supplied offsets, every intermediate allocation shadow-rooted per the #570/#692 discipline), decode_response_adt (read-only; status i64 + headers Map decode via _decode_attrs + body string). Both raise loudly on an unexpected layout shape rather than marshalling garbage. - CompileResult.adt_layouts: constructor layouts exported so the driver marshals with the exact offsets THIS compilation computed -- never hardcoded. - execute(): http_request=HttpRequestData(...) builds the Request ADT after instantiation and calls the handler with its pointer; ExecuteResult.http_response carries the decoded Response. - core.py: Pass-1 signatures for user fns whose params/return reference prelude ADTs were computed before the prelude registered those layouts (recorded 'unsupported' in fn_param_types even though the fn compiles in Pass 2); a post-injection pass re-registers exactly those (_register_fn is overwrite-idempotent). Found via the serve driver's handler validation, which reads fn_param_types. - vera/runtime/server.py: make_server(result, host, port) -- stdlib http.server, per-request execute(), handler traps (incl. runtime contract violations) map to 500 with the trap diagnostic JSON (trap_kind + frames, the vera run --json envelope shape), handler IO.print forwarded to the server console, loud ValueError when the program lacks a servable public handle(@request -> @response). RED-first (tests/test_serve.py, 7 tests): GET/POST echo round-trips (method/path/headers/body all cross the boundary), handler status propagation, contract-violation -> 500 with trap_kind, State<Int> isolation across requests (instance-per-request pinned), and two clean-validation errors. All on ephemeral ports. Doc counts follow (5,595 tests / 89 files). Refs #305 Co-Authored-By: Claude <[email protected]>
…305) S3 of the <HttpServer> stage plus the release machinery. - cli.py: cmd_serve (compile pipeline shared with cmd_run; clean exit-1 diagnostics for type errors / missing or wrong-signature handler / port-bind failure; Ctrl-C -> exit 130), --port/--host flags, dispatch + usage. RED-first CLI tests (missing file, type error before bind, missing-handler message). - examples/http_server.vera: the #305 headline demo -- a router whose status_of postcondition (result == 200 || result == 404) verifies at Tier 1 (vera verify: 6/6 Tier 1; the corpus tier pin moves 271/92/363 -> 277/92/369). examples/README.md row + count. - tests/conformance/ch09_http_server.vera at level VERIFY (needs no network, unlike ch09_http/ch09_inference at check) + manifest entry: 104 conformance programs. - Docs lockstep: spec 7.7.5 (marker effect), 9.5.6 (types, execution model, 500-on-violation), 12.9.3 (browser divergence row), SKILL.md HttpServer section + effect list, TOOLCHAIN.md serve recipe, CLAUDE.md commands + counts, AGENTS/FAQ/TESTING counts (suite grew to 5,614 via the corpus-parametrized tests), allowlist refresh with the fixer's three duplicate-key collisions resolved against the real spec lines (the known fix_allowlists pitfall). - Release v0.0.193: version sync across the six sites, CHANGELOG cut with the HttpServer section + link refs, ROADMAP milestone chain updated (#305 shipped), HISTORY: Stage-16 row, the By-the-numbers table gains a permanent 'HttpServer effect' milestone column (per maintainer direction, like the Inference column) with the trailing soundness column refreshed to v0.0.191, totals footer (1,800+ commits / 193 releases / 92 active days -- all from git data), and the stale opening sentence now reads Stage 16 / 92 days. Closes #305 Co-Authored-By: Claude <[email protected]>
Pins the shadow-rooting discipline in build_request_adt: with VERA_EAGER_GC=1 every allocation collects, so an unrooted method/path/headers/body allocation is swept mid-build and the echo returns garbage. Mutation-validated alongside the layout-shape guard and the Response status offset (each kill their discriminating test; suite restored green). Counts follow (5,615 tests). Refs #305 Co-Authored-By: Claude <[email protected]>
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 Walkthrough
🚥 Pre-merge checks | ❌ 3❌ Failed checks (3 inconclusive)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #845 +/- ##
==========================================
- Coverage 91.94% 91.90% -0.04%
==========================================
Files 92 93 +1
Lines 27626 27836 +210
Branches 332 332
==========================================
+ Hits 25400 25583 +183
- Misses 2218 2245 +27
Partials 8 8
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The CI-only check_spec_examples gate (not in pre-commit) failed on this branch: the new effect-HttpServer and Request/Response prelude data blocks needed FRAGMENT allowlist entries, and the 9.5.6 insertion (+33 lines) had orphaned four pre-existing signature-fragment entries (float_is_nan, url_join, string_chars family, md_parse) that fix_allowlists cannot re-anchor once detached -- re-keyed to their fence lines and the three stale old keys removed. Gate now exits 0; no duplicate keys. Found in parallel by the local gate re-run (full output, not tail) and the review-toolkit round. Refs #305 Co-Authored-By: Claude <[email protected]>
|
Review round 1 (pr-review-toolkit code-reviewer) — recorded. One merge-blocking finding, fixed in the commit just pushed:
Everything else came back verified clean: the core.py TypeAliasDecl branch byte-intact vs main with the #305 re-registration correctly scoped; layout-driven marshalling with loud shape guards and full shadow-rooting; |
|
@coderabbitai review |
✅ Action performedReview finished.
|
What
Verified HTTP request handling — the
<HttpServer>effect (#305) — and release v0.0.193. Stage B of the server-effects sprint (WASI.md).A server program defines a total, contract-checked handler and serves it:
The accept loop lives in the host — handlers need no
Diverge, are termination-checked like any function, and every contract on them is an ordinary Tier-1/Tier-3 obligation. The newexamples/http_server.veraproves its status-range postcondition (result == 200 || result == 404) statically at Tier 1 — the headline: verified HTTP handlers.Design
HttpServeris a marker effect (no operations; spec §7.7.5), registered likeAsync/Diverge.Request(method, path, headers, body) andResponse(status, headers, body) are prelude ADTs, injected only when referenced (the Json/HtmlNode conditional pattern — an always-inject first cut broke six no-overhead WAT pins because theMapheaders field pulls heap machinery into pure programs). User definitions shadow them.execute()(Stage-0 spike measured instantiation at ~0.02 ms).State<T>cannot leak between requests — pinned by test. Sequential handling in v1 (concurrency: WASI 0.3 compliance and native async I/O #406).CompileResult.adt_layoutsexports the constructor layouts this compilation computed;build_request_adt/decode_response_adt(vera/runtime/heap.py) fail loudly on an unexpected layout shape. A newInstanceCalleradapts a (Store, Instance) pair to the exact caller protocol the heap helpers already use (export lookup + store-context delegation) — validated empirically before building on it.trap_kind, message, frames — thevera run --jsonenvelope shape).unsupportedinfn_param_types(the fn still compiled in Pass 2); a post-injection pass now re-registers exactly those (_register_fnis overwrite-idempotent). Functions may also now declare prelude-ADT-typed signatures servably.Tests (all RED-first; 4 mutations kill)
tests/test_serve.py(8): GET/POST echo round-trips (method/path/headers/body all cross the boundary), status propagation, contract-violation → 500 withtrap_kind,State<Int>isolation across requests, eager-GC round-trip, two cleanmake_servervalidation errors. All ephemeral ports._check_clean— the vacuous_check_okvariants were tightened when 3 of 4 passed pre-change), State composition, status contract.Conformance + example
tests/conformance/ch09_http_server.veraat levelverify(needs no network, unlikech09_http/ch09_inferenceatcheck— rationale in the program header): 104 programs.examples/http_server.vera(36 examples),examples/README.mdrow.Docs
Spec §7.7.5 + §9.5.6 + §12.9.3; SKILL.md HttpServer section + effect list; TOOLCHAIN.md serve recipe; CLAUDE.md commands; TESTING/AGENTS/FAQ counts (suite at 5,615 via the corpus-parametrized tests); allowlist refresh with three fixer duplicate-key collisions resolved against the real spec lines.
Release v0.0.193
Version sync (6 sites), CHANGELOG cut + link refs, ROADMAP milestone chain updated, HISTORY: Stage-16 row plus the "By the numbers" table gains a permanent "HttpServer effect" milestone column (per maintainer direction, parallel to the v0.0.101 Inference column), the trailing soundness column refreshed to v0.0.191, totals footer and the opening sentence brought current (1,800+ commits / 193 releases / 92 active days — from git data).
Verification
ruff check(+--select S) clean without--fixvera verify examples/http_server.vera→ 6/6 Tier 1Closes #305
🤖 Generated with Claude Code