Add Http effect with get and post operations (#57)#357
Conversation
effect Http {
op get(String -> Result<String, String>);
op post(String, String -> Result<String, String>);
}
Host-backed algebraic effect following the IO pattern. Python runtime
uses urllib.request (zero dependencies). Browser runtime uses
synchronous XMLHttpRequest. Functions must declare effects(<Http>).
New conformance test ch09_http (62 programs). New example http.vera
(JSONPlaceholder API). 12 new unit tests (6 checker + 6 codegen).
Version bump to v0.0.99.
Known limitations filed as #351-#356: no custom headers, no status
codes, no timeout, no Content-Type, browser uses deprecated XHR,
no PUT/PATCH/DELETE.
Closes #57.
Co-Authored-By: Claude <noreply@anthropic.invalid>
📝 WalkthroughWalkthroughThis PR adds a built‑in Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant VeraProgram as Vera program
participant WASM as Wasm module
participant Host as Host import (Python/Browser)
participant Network as Remote HTTP server
VeraProgram->>WASM: call Http.get(url) (effects(<Http>))
WASM->>Host: invoke import vera.http_get(urlPtr, urlLen)
Host->>Network: perform HTTP GET (urllib / XHR)
Network-->>Host: response or network error
Host-->>WASM: return Result.Ok(responseText) or Result.Err(errorMsg)
WASM-->>VeraProgram: return Result<String, String>
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #357 +/- ##
==========================================
- Coverage 91.41% 91.22% -0.20%
==========================================
Files 48 48
Lines 18333 18429 +96
Branches 213 215 +2
==========================================
+ Hits 16760 16811 +51
- Misses 1569 1614 +45
Partials 4 4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/build_site.py (1)
110-129:⚠️ Potential issue | 🟡 MinorKeep
llms.txtaligned with the new Http copy.
build_index_md()now advertisesHttp, but thebuild_llms_txt()prose earlier in this file still lists only IO/State/Exceptions/Async. After regeneration the site’s two AI-facing entry points will disagree about the effect surface in the same release.Also applies to: 303-327
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/build_site.py` around lines 110 - 129, The build_llms_txt() output was not updated to include the new Http effect, causing inconsistency with build_index_md(); update build_llms_txt() so its prose lists Http alongside IO/State/Exceptions/Async (and any other effects advertised by build_index_md()), and ensure the same effect wording and order are used; check the related block around lines referenced (other occurrences ~303-327) for duplicate text generation and update those too so both entry points (build_llms_txt and build_index_md) produce identical effect-surface descriptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ROADMAP.md`:
- Around line 25-28: The roadmap text incorrectly states that HTTP requires JSON
bodies and mixes WASI versions; update the paragraph to say Http ships raw
String request/response bodies (so JSON is optional, not a prerequisite), change
the WASI reference for incoming-handler support to match the rest of the file
(use WASI 0.3 if other references use 0.3), and ensure the dependency chain
wording (Map → JSON → HTTP Server → MCP Server) reflects that JSON and HTTP are
separate optional steps; also apply the same corrections to the related entries
mentioned (lines referenced as 62-64) so all mentions and issue IDs (`#58`, `#57`,
`#237/`#305/#306) and phrasing are consistent across the file.
In `@scripts/check_skill_examples.py`:
- Around line 118-121: The ALLOWLIST dict has duplicate numeric keys (e.g., key
1289 and key 1464) causing silent overwrites; open the ALLOWLIST literal, remove
or merge the duplicated entries so each key appears only once (preserve all
intended tuple values by combining them if needed), and ensure the final dict
contains unique keys corresponding to the original allowlist intent; check the
ALLOWLIST variable in scripts/check_skill_examples.py and update any tests or
comments that referenced the removed duplicate entries.
In `@scripts/check_spec_examples.py`:
- Around line 249-250: The spec example for fetch_both is now type-incorrect
because the Http API returns Result<String, String> not Json; update the spec
block in spec/09-standard-library.md (the fetch_both example that uses
async(Http.get(...))) to reflect the new Http signature and correct types (e.g.,
handle the Result<String,String> from Http.get, map or parse the Ok String into
Json or adjust fetch_both's return type to Future<Result<...>>), and remove the
CHECK_ALLOWLIST entry that hides this stale example in
scripts/check_spec_examples.py so the test validates the corrected spec instead
of skipping it. Ensure you update the fetch_both example and any type
annotations in that block to be consistent with async(Http.get(...)) returning a
future over Result<String,String>.
In `@tests/test_checker.py`:
- Around line 2123-2129: Extend the Http.post tests by adding a negative
type-check case alongside the existing test_http_post_type_checks: call the test
helper used for failures (e.g., _check_bad) with a snippet invoking Http.post
where the body argument is the wrong type (for example `@Int` instead of `@String`)
so the checker flags a type error; place this new assertion near
test_http_post_type_checks and reference Http.post and the _check_bad helper to
locate where to add it.
In `@tests/test_codegen.py`:
- Around line 9059-9078: Update the two tests so they not only assert the
expected import is present but also assert the other sibling import is absent:
in test_http_get_compiles (which checks for "http_get") also assert that
"http_post" is not in result.wat, and in test_http_post_compiles (which checks
for "http_post") also assert that "http_get" is not in result.wat; locate these
tests by their function names test_http_get_compiles and test_http_post_compiles
and add the negated assertions against result.wat.
- Around line 9139-9161: The test test_http_post_mocked only asserts the success
path for Http.post; add two checks: (1) a failure-path test that mocks
urllib.request.urlopen to raise an HTTP error (or return a mock that yields an
error response) and assert the function returns Err and its payload propagates,
and (2) a request-shape assertion inside the existing patch (or a new test) that
inspects the arguments passed to urllib.request.urlopen (e.g., using patch
side_effect or MagicMock.assert_called_with) to verify the POST URL and body are
set correctly; update references in the test function test_http_post_mocked (and
any new test functions) and keep using _compile_ok and execute to run the
compiled source so the added mocks exercise Http.post semantics.
In `@tests/test_verifier.py`:
- Around line 1601-1603: Update the stale docstring string that currently reads
"145 T1 / 15 T3 without module resolution" to the correct baseline "162 T1 / 17
T3 without module resolution" so it matches the assertions (assert t1 == 162,
assert t3 == 17, assert total == 179) in tests/test_verifier.py; locate the
docstring containing the exact phrase "145 T1 / 15 T3 without module resolution"
and replace it with "162 T1 / 17 T3 without module resolution".
In `@vera/browser/runtime.mjs`:
- Around line 1609-1644: The HTTP host imports (imports.vera.http_get and
imports.vera.http_post created in buildImportObject) currently assume
XMLHttpRequest and fail on Node.js; update both bindings to detect runtime: if
typeof XMLHttpRequest !== "undefined" keep the existing synchronous XHR code;
else if typeof fetch !== "undefined" implement an alternative using fetch (use
async/await and integrate with your async WebAssembly strategy — e.g., asyncify
or returning a promise to the host) to produce
allocResultOkString/allocResultErrString responses; otherwise return an explicit
allocResultErrString("Unsupported runtime: no XMLHttpRequest or fetch
available") so Node.js runs get a clear unsupported-runtime error. Ensure you
update both http_get and http_post functions accordingly.
In `@vera/codegen/compilability.py`:
- Around line 39-40: The mixed-effect diagnostic message needs to include "Http"
in the list of currently compilable effects; locate the code that builds/emits
the mixed-effect warning (the same module where eff.name == "Http" and
self._needs_memory is set) and update the rationale string that currently lists
"pure/IO/State/Exn/Async" to also include "Http" so effects(<Http, Foo>) reports
Http as supported in the mixed-effect warning.
In `@vera/wasm/calls.py`:
- Around line 353-357: The Http branch that emits host calls (when
call.qualifier == "Http") forgets to mark that the module needs allocator
plumbing; update the branch handling for these calls (the block that computes
wasm_name, adds to self._http_ops_used, and appends the instruction) to also set
self.needs_alloc = True so allocator wiring is kept when only Http.get/post are
used — ensure this is done before emitting or registering the call (refer to
variables/methods: call.qualifier, wasm_name, self._http_ops_used,
instructions.append, and self.needs_alloc).
In `@vera/wasm/context.py`:
- Around line 392-395: The code currently assumes any qualified effect call
that's not "Http" is void (using expr.qualifier), which is wrong and breaks
value-returning effects like State.get; change the logic to determine void-ness
by consulting the effect's actual signature instead of hard-coding defaults:
look up the effect descriptor/signature for expr.qualifier (e.g., from the
module/effects registry or whatever structure holds effect metadata used
elsewhere in this file) and return False only if that signature indicates a
value/Result is returned (otherwise True), so ExprStmt handling correctly drops
or preserves stack values based on the effect's real return type.
---
Outside diff comments:
In `@scripts/build_site.py`:
- Around line 110-129: The build_llms_txt() output was not updated to include
the new Http effect, causing inconsistency with build_index_md(); update
build_llms_txt() so its prose lists Http alongside IO/State/Exceptions/Async
(and any other effects advertised by build_index_md()), and ensure the same
effect wording and order are used; check the related block around lines
referenced (other occurrences ~303-327) for duplicate text generation and update
those too so both entry points (build_llms_txt and build_index_md) produce
identical effect-surface descriptions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: cf7643ec-9680-481f-b29f-58276494c6c3
⛔ Files ignored due to path filters (6)
docs/index.htmlis excluded by!docs/**docs/index.mdis excluded by!docs/**docs/llms-full.txtis excluded by!docs/**docs/llms.txtis excluded by!docs/**examples/http.verais excluded by!**/*.veratests/conformance/ch09_http.verais excluded by!**/*.vera
📒 Files selected for processing (31)
AGENTS.mdCHANGELOG.mdCLAUDE.mdFAQ.mdREADME.mdROADMAP.mdSKILL.mdTESTING.mdpyproject.tomlscripts/build_site.pyscripts/check_readme_examples.pyscripts/check_skill_examples.pyscripts/check_spec_examples.pyspec/09-standard-library.mdtests/conformance/manifest.jsontests/test_checker.pytests/test_codegen.pytests/test_readme.pytests/test_verifier.pyvera/README.mdvera/__init__.pyvera/browser/runtime.mjsvera/codegen/api.pyvera/codegen/assembly.pyvera/codegen/compilability.pyvera/codegen/core.pyvera/codegen/functions.pyvera/environment.pyvera/wasm/calls.pyvera/wasm/context.pyvera/wasm/inference.py
👮 Files not reviewed due to content moderation or server errors (6)
- README.md
- SKILL.md
- FAQ.md
- vera/codegen/api.py
- TESTING.md
- spec/09-standard-library.md
- Fix duplicate allowlist keys in check_skill_examples.py (1289, 1464) - Set needs_alloc for Http qualified calls - Add Http to compilability diagnostic message - Add test_http_post_wrong_type checker test - Add per-operation import gating tests (get-only, post-only) - Add Http to build_site.py effects listing - Fix ROADMAP WASI version and Http body description - Improve _is_void_expr comment for future effect extensibility - Fix doc counts (3,015 tests) Co-Authored-By: Claude <noreply@anthropic.invalid>
|
@coderabbitai Fixed the outside-diff item: |
|
Tip For best results, initiate chat on the files or code changes.
|
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
tests/test_codegen.py (1)
9167-9190:⚠️ Potential issue | 🟠 Major
Http.postruntime test still misses request semantics and error-path coverage.At Line 9187, the mock accepts any call shape, so a method/body wiring regression would still pass. Add request-shape assertions and a failing
Http.postpath.Proposed test tightening
def test_http_post_mocked(self) -> None: @@ - with patch("urllib.request.urlopen", return_value=mock_resp): + with patch("urllib.request.urlopen", return_value=mock_resp) as mock_urlopen: exec_result = execute(result) assert exec_result.value == 7 + req = mock_urlopen.call_args.args[0] + assert req.full_url == "http://example.com" + assert req.get_method() == "POST" + assert req.data == b"data" + + def test_http_post_mocked_failure(self) -> None: + """Mocked Http.post failure returns Err.""" + from unittest.mock import patch + + source = """ +public fn main(-> `@Int`) + requires(true) ensures(true) effects(<Http>) +{ + let `@Result`<String, String> = Http.post("http://example.com", "data"); + match `@Result`<String, String>.0 { + Ok(`@String`) -> 0, + Err(`@String`) -> string_length(`@String.0`) + } +} +""" + result = _compile_ok(source) + with patch("urllib.request.urlopen", side_effect=Exception("post failed")): + exec_result = execute(result) + assert exec_result.value is not None + assert exec_result.value > 0As per coding guidelines: add codegen/runtime tests for built-in functions covering normal cases, edge cases (empty inputs, zero values), and composition with other built-ins.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_codegen.py` around lines 9167 - 9190, Update the test_http_post_mocked test to assert the actual request shape passed to urllib.request.urlopen and to add a failing Http.post path: instrument the MagicMock or patch for urllib.request.urlopen to validate the request URL, method/body/headers expected by Http.post (so failures in wiring are caught) and add a second subtest where urlopen raises an exception or returns an error response to exercise the Err branch of the compiled code; adjust usages of test helper functions (_compile_ok, execute) and the mock_resp setup in this test to verify both success (response body "created") and error behaviors for Http.post.tests/test_checker.py (1)
2112-2173:⚠️ Potential issue | 🟡 MinorMissing negative test for
Http.postbody parameter.The test suite lacks coverage for an incorrect body argument type. A previous review comment requested
test_http_post_wrong_body_type, and whilst you indicated it was fixed in 7ae2cb2, the test does not appear in this diff.Currently,
test_http_post_wrong_type(lines 2155-2161) validates rejection ofHttp.post(42, "body")(wrong URL type), but there's no test forHttp.post("url", 42)(wrong body type). Multi-parameter built-ins elsewhere in this file (e.g.,json_array_get, line 2070) test each parameter independently.🧪 Proposed test addition
def test_http_post_wrong_type(self) -> None: """Http.post(42, "body") with Int URL is a type error.""" _check_err(""" public fn post(`@Unit` -> `@Result`<String, String>) requires(true) ensures(true) effects(<Http>) { Http.post(42, "body") } """, "type") + def test_http_post_wrong_body_type(self) -> None: + """Http.post("url", 42) with Int body is a type error.""" + _check_err(""" +public fn post(`@String` -> `@Result`<String, String>) + requires(true) ensures(true) effects(<Http>) +{ Http.post(`@String.0`, 42) } +""", "type") + def test_http_with_io(self) -> None:As per coding guidelines: Add type checker tests in tests/test_checker.py for built-in functions, with at minimum one test with correct types and one with a wrong argument type.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_checker.py` around lines 2112 - 2173, Add a new negative test method in the TestHttpChecker class named test_http_post_wrong_body_type that mirrors test_http_post_wrong_type but passes a String URL and an Int body (e.g. Http.post(`@String.0`, 42)) and asserts a type error via _check_err with the "type" message; place it alongside the other tests in TestHttpChecker so the body-parameter type rejection for Http.post is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ROADMAP.md`:
- Line 62: Replace the phrase "HTTP effect — requires JSON for request/response
bodies." in ROADMAP.md with wording that matches the accurate behavior described
earlier (HTTP returns raw String and JSON parsing is separate), e.g. "HTTP
effect — composes with JSON for typed API responses" so the document is
consistent with the Http operation description that returns raw `String`.
In `@tests/test_codegen.py`:
- Around line 9107-9116: Update the test `test_http_no_imports_when_unused` (or
add a new sibling test) to cover the declared-but-unused edge `effects(<Http>)`:
change the `source` program's signature to use `effects(<Http>)` instead of
`effects(pure)` (or create a second `source` with `effects(<Http>)`) and call
`_compile_ok(source)` as before; then assert that `"http_get"` and `"http_post"`
are not present in `result.wat`. Ensure you reference the same helper
`_compile_ok` and keep the assertions identical to the existing ones.
---
Duplicate comments:
In `@tests/test_checker.py`:
- Around line 2112-2173: Add a new negative test method in the TestHttpChecker
class named test_http_post_wrong_body_type that mirrors
test_http_post_wrong_type but passes a String URL and an Int body (e.g.
Http.post(`@String.0`, 42)) and asserts a type error via _check_err with the
"type" message; place it alongside the other tests in TestHttpChecker so the
body-parameter type rejection for Http.post is covered.
In `@tests/test_codegen.py`:
- Around line 9167-9190: Update the test_http_post_mocked test to assert the
actual request shape passed to urllib.request.urlopen and to add a failing
Http.post path: instrument the MagicMock or patch for urllib.request.urlopen to
validate the request URL, method/body/headers expected by Http.post (so failures
in wiring are caught) and add a second subtest where urlopen raises an exception
or returns an error response to exercise the Err branch of the compiled code;
adjust usages of test helper functions (_compile_ok, execute) and the mock_resp
setup in this test to verify both success (response body "created") and error
behaviors for Http.post.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0681605f-900a-4cfe-9cc9-5d0e029fc6e9
⛔ Files ignored due to path filters (1)
docs/llms.txtis excluded by!docs/**
📒 Files selected for processing (9)
ROADMAP.mdTESTING.mdscripts/build_site.pyscripts/check_skill_examples.pytests/test_checker.pytests/test_codegen.pyvera/codegen/compilability.pyvera/wasm/calls.pyvera/wasm/context.py
- Fix fetch_both spec example: correct types to Result<String, String>, move from CHECK_ALLOWLIST to ALLOWLIST as FUTURE (async not compiled) - Add XMLHttpRequest guard in browser runtime: returns clear Err on Node.js instead of crashing with "XMLHttpRequest is not defined" - Fix ROADMAP wording: Http returns raw String, JSON is separate - Add test_http_declared_but_unused: effects(<Http>) with no ops - Fix duplicate allowlist keys (1289, 1464) in check_skill_examples.py - Fix doc counts (3,016 tests) Co-Authored-By: Claude <noreply@anthropic.invalid>
|
Merging with codecov/patch at 90.56% (target 95.36%). The ~5% gap is structural:
Project coverage is 95.35% (-0.02% from baseline). All 3,016 tests pass. |
|
@coderabbitai help |
ChatThere are 3 ways to chat with CodeRabbit:
CodeRabbit commands
Other keywords and placeholders
Status, support, documentation and community
|
Summary
Completes the critical path dependency chain:
Map→JSON→ HTTP → Server → MCP.Http effect
New files
Known limitations (filed as issues)
Documentation
Closes #57.
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Known Limitations
Tests
Documentation
Chores