Skip to content

Release v0.0.157#690

Merged
aallan merged 2 commits into
mainfrom
release-v0.0.157
May 19, 2026
Merged

Release v0.0.157#690
aallan merged 2 commits into
mainfrom
release-v0.0.157

Conversation

@aallan

@aallan aallan commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

Release v0.0.157 — ships the terminal half of IO.read_char (#618).

Unblocks real-time CLI programs (paced REPLs, terminal games) that couldn't be written before because IO.read_line is line-buffered. Browser half awaits JSPI suspend/resume from #609; same primitive IO.sleep will use.

What's in this release

Added

  • IO.read_char effect operation: op read_char(Unit -> @Result<String, String>). Returns one Unicode character from stdin, or Err("EOF") when the stream closes (Ctrl-D on a Unix TTY also maps to EOF).
    • Unix TTY: termios cbreak mode via tty.setcbreak(). cbreak preserves ISIG so Ctrl-C still raises SIGINT (unlike raw mode which would suppress it). Ctrl-D mapped to EOF since ICANON is off in cbreak.
    • Windows TTY: msvcrt.getwch() for raw single-key reads.
    • Non-TTY (piped/redirected): sys.stdin.read(1) shared across platforms — identical encoding behaviour, no msvcrt.getwch() on redirected stdin.
    • Browser: stub returns Result.Err pointing at #609 + #618; wiring is in place so when JSPI lands only the hostReadChar body needs replacing.
    • Added per the same IO-effect-extension pattern as IO.sleep / IO.time / IO.stderr (#463): a single new op on the existing effect, not a new <Terminal> effect.

Tests

  • New conformance test tests/conformance/ch07_io_read_char.vera (verify-level — pins the type signature and effect-row wiring).
  • 3 new subprocess tests in tests/test_cli.py::TestIOOperations covering the piped-input path: happy path, EOF, UTF-8 round-trip.
  • 6 new in-process tests in tests/test_codegen.py::TestIOOperations covering the stdin_buf fixture path: single read, empty-buf EOF, sequential cursor advance, read-then-EOF, UTF-8, and the intentional non-TTY \x04-stays-literal asymmetry.

Documentation

  • spec/07-effects.md — added read_char row to the IO operations table; bumped operation count "ten → eleven".
  • spec/12-runtime.md — added vera.read_char import row and browser-runtime IO behaviour table entry.
  • SKILL.md — added IO.read_char row; bumped operation count in two places; updated browser-runtime summary.
  • examples/read_char.vera — new example demonstrating the read-one-char pattern with full failure-mode handling.
  • CHANGELOG.md — comprehensive [0.0.157] section detailing the implementation journey.

Review trail — for posterity

This was a four-CodeRabbit-round + internal multi-agent review journey on PR #689. Each layer caught material things the others missed.

Round Caught what
CodeRabbit ×1 (commit 217845a) 8 inline + 1 outside-diff — doc-count drift sweep, encoding="utf-8" on subprocess.run, initial try/except wrapping for system errors
CodeRabbit ×2 (9983b2c) 1 inline + 2 outside-diff — Windows TTY-vs-pipe routing (Windows was bypassing the os.isatty check, hitting msvcrt.getwch() even for piped stdin)
pr-review-toolkit multi-agent (e6d549e) code-reviewer + pr-test-analyzer + comment-analyzer + silent-failure-hunter ran in parallel. Caught: KeyboardInterrupt escape via wasmtime trampoline (#589-class — host_sleep already had this fix; the missing except KeyboardInterrupt in host_read_char was a real bug AND my "same stance as host_sleep" comment was factually wrong); termios restore masking the read error; tcgetattr error reporting the wrong message; redundant local import os; stale conformance-test cross-reference (test_codegen.pytest_cli.py); zero coverage of the stdin_buf fixture path (added 5 new tests).
CodeRabbit ×3 (2bc2cb6) 2 inline — tty.setraw() clears ISIG (the previous round's except KeyboardInterrupt clause was actually unreachable in TTY mode — Ctrl-C arrived as \x03 byte instead of raising); restore_exc was being swallowed instead of surfaced when reads succeeded
Lint S110 caught the leftover try/except: pass pattern (coincidentally fixed by the round-3 restore_exc capture, demonstrating defense-in-depth)
CodeRabbit ×4 (9e4a903) 2 inline — Ctrl-D (\x04) in cbreak mode needs to map to Err("EOF") since ICANON is off and Ctrl-D arrives as a literal byte; CHANGELOG had stale "raw-mode" wording surviving from before the round-3 setcbreak switch

The headline win: setrawsetcbreak was a latent correctness bug that would have shipped to users. Three rounds of review couldn't have caught it without all three: my agents reasoned about WHY the except KeyboardInterrupt was needed, but CodeRabbit pattern-matched on "setraw + KeyboardInterrupt" as a known incompatibility, and the lint caught the residual swallow.

Validation

  • pytest tests/3,806 passed, 15 skipped, 16 stress-deselected (+99 browser tests)
  • mypy vera/ clean
  • ruff check --select S vera/ clean (the previously-failing S110 rule passes after the restore_exc capture)
  • python scripts/check_conformance.py — 87/87
  • python scripts/check_examples.py — 35/35 (check + verify)
  • python scripts/check_doc_counts.py — consistent (3,936 tests, 32 files, 87 conformance, 35 examples)
  • python scripts/check_version_sync.py — v0.0.157 across 6 files
  • python scripts/check_limitations_sync.py — consistent (28/17/4)
  • All doc validators (spec, SKILL, README, FAQ, examples, HTML) — pass
  • python scripts/check_site_assets.py — up-to-date
  • Smoke test: echo "X" | vera run examples/read_char.veraYou pressed: X
  • All 23 CI checks green on the merged PR (commit 9e4a903)

Post-merge

Standard release-tag workflow once merged: pull main, tag v0.0.157 on the merge commit, push tag, gh release create v0.0.157 with the extracted CHANGELOG section.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a character-reading effect operation with platform-specific terminal handling, interrupt signal mirroring and EOF behaviour.
  • Documentation

    • Updated changelog, history and README to document the v0.0.157 release and adjust counts.
  • Chores

    • Bumped project version to v0.0.157 across metadata and package exports.

Review Change Stack

`IO.read_char` effect operation for single-character input
(#618 terminal half).  Browser half awaits JSPI from #609.

Bump version across 6 files: vera/__init__.py, pyproject.toml,
uv.lock, README.md, docs/index.html.  CHANGELOG.md and
HISTORY.md updated for the release entry; site assets
regenerated.

Closing the loop on #618: this PR was a four-CodeRabbit-round
+ pr-review-toolkit-multi-agent-review journey.  Final shape:

- Unix TTY uses termios cbreak mode (`tty.setcbreak()`) which
  preserves ISIG so Ctrl-C still raises SIGINT (not the raw
  mode I initially used).
- Windows TTY uses `msvcrt.getwch()`.
- Non-TTY (piped/redirected stdin) shared across platforms
  via `sys.stdin.read(1)` for identical encoding behaviour.
- KeyboardInterrupt at every blocking call raises
  `_VeraExit(130)` (mirrors `host_sleep`'s #589-class
  WasmTrapError avoidance).
- Termios restore failure captured separately so it doesn't
  mask the read error.
- Ctrl-D in cbreak mode maps to `Err("EOF")` (since ICANON
  is off in cbreak); piped `\x04` stays a literal byte
  (since a pipe is a byte stream).
- Browser stub returns clear `Result.Err` pointing at #609 +
  #618; wiring is in place so when JSPI lands, only the
  hostReadChar body needs replacing.

Co-Authored-By: Claude <noreply@anthropic.invalid>
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 366e59c1-2c77-4aaf-b768-7c5b0ee136a9

📥 Commits

Reviewing files that changed from the base of the PR and between f10dde2 and 5fe4980.

📒 Files selected for processing (2)
  • HISTORY.md
  • README.md

📝 Walkthrough

Walkthrough

This PR releases v0.0.157 by coordinating version updates across package metadata (pyproject.toml, vera.init.py), release documentation (CHANGELOG.md, HISTORY.md), and project status (README.md). The Stage 12 entry documents the new IO.read_char effect operation with platform-specific terminal handling.

Changes

v0.0.157 Release Coordination

Layer / File(s) Summary
Metadata and package exports
pyproject.toml, vera/__init__.py
Project version bumped to 0.0.157 in pyproject.toml; __version__ and version updated in vera/__init__.py.
Release notes and project status
CHANGELOG.md, HISTORY.md, README.md
CHANGELOG.md adds ## [0.0.157] - 2026-05-19 and updates compare links (Unreleased -> v0.0.157...HEAD, adds [0.0.157] comparison). HISTORY.md adds Stage 12 notes documenting IO.read_char (Unix TTY cbreak, Windows getwch, non-TTY UTF‑8 pipe handling, interrupt mirroring, Ctrl‑D/EOF mapping) and increments total tagged releases to 157. README.md project status lines and example count updated.

Sequence Diagram(s)

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • aallan/vera#651: Another release-prep bump updating version metadata and release headers, directly related to coordinated version/documentation changes.

Suggested labels

compiler, tests, spec, docs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Release v0.0.157' directly and concisely summarizes the main change—a version bump release—which is precisely what the changeset implements across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release-v0.0.157

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented May 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.88%. Comparing base (e185940) to head (5fe4980).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #690   +/-   ##
=======================================
  Coverage   90.88%   90.88%           
=======================================
  Files          60       60           
  Lines       23529    23529           
  Branches      259      259           
=======================================
  Hits        21384    21384           
  Misses       2138     2138           
  Partials        7        7           
Flag Coverage Δ
javascript 57.43% <ø> (ø)
python 94.62% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@HISTORY.md`:
- Line 304: Update the HISTORY.md entry for the IO.read_char effect to remove
the claim of "explicit UTF-8 encoding" for the non-TTY path and replace it with
wording that matches the implementation: state that the non‑TTY fallback reads a
single byte/character using sys.stdin.read(1) (single-character read behavior)
rather than performing an explicit re-encoding; reference the IO.read_char
effect operation and the non‑TTY/pipe path in the same sentence so the release
note matches the runtime contract.

In `@README.md`:
- Line 186: Replace every stale in-file occurrence of the old example count so
the README is consistent: update the string "35 examples" (currently at the
first project-summary sentence) and the string "34 example Vera programs" (in
the project tree section) to the new total (use the same numeric value in both
places) — search for those exact phrases in README.md and replace both
occurrences with the updated example count.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4680da4c-1c27-46d1-8ac6-cf4a24d30ddf

📥 Commits

Reviewing files that changed from the base of the PR and between e185940 and f10dde2.

⛔ Files ignored due to path filters (5)
  • docs/index.html is excluded by !docs/**
  • docs/index.md is excluded by !docs/**
  • docs/llms-full.txt is excluded by !docs/**
  • docs/llms.txt is excluded by !docs/**
  • uv.lock is excluded by !**/*.lock, !uv.lock
📒 Files selected for processing (5)
  • CHANGELOG.md
  • HISTORY.md
  • README.md
  • pyproject.toml
  • vera/__init__.py

Comment thread HISTORY.md Outdated
Comment thread README.md
@aallan aallan closed this May 19, 2026
@aallan aallan deleted the release-v0.0.157 branch May 19, 2026 12:53
@aallan aallan restored the release-v0.0.157 branch May 19, 2026 12:54
@aallan aallan reopened this May 19, 2026
Two minor doc accuracy fixes:

1. HISTORY.md L304 — the v0.0.157 release row claimed the non-TTY
   pipe path uses "explicit UTF-8 encoding", but the implementation
   just calls `sys.stdin.read(1)` with whatever encoding stdin
   already has (no explicit re-encoding step).  The `encoding="utf-8"`
   is on the test subprocess calls, not the production code path.
   Replaced with "reading one character via `sys.stdin.read(1)`"
   which accurately describes the runtime contract.

2. README.md L230 — project-tree comment still said "34 example
   Vera programs" while L186 was already updated to 35.  Brought
   the two references into agreement.

Co-Authored-By: Claude <noreply@anthropic.invalid>
@aallan aallan merged commit 8f9e15b into main May 19, 2026
23 checks passed
@aallan aallan deleted the release-v0.0.157 branch May 19, 2026 13:20
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