Skip to content

Fmting#17

Merged
cuzzo merged 14 commits intomasterfrom
fmting
May 8, 2026
Merged

Fmting#17
cuzzo merged 14 commits intomasterfrom
fmting

Conversation

@cuzzo
Copy link
Copy Markdown
Owner

@cuzzo cuzzo commented May 7, 2026

No description provided.

cuzzo and others added 13 commits May 7, 2026 22:34
Sweeps a .cht file (or directory) through `clear fmt` and checks that
the emitted Zig is byte-identical before and after formatting.
Strategy: transpile original .cht → Zig (before), Formatter.format
the source, transpile the formatted .cht → Zig (after), compare.
Strips `// CLR:N` line-number debug markers before comparing — those
shift when fmt rearranges source layout but carry no semantic value.

Wires through `clear fmt --verify <path>...` for direct use against
benchmarks/, examples/, transpile-tests/. Returns exit code = number
of files where output diverged or transpilation raised, so it composes
with shell scripts and pre-merge gates.

Why now: about to apply fmt to benchmarks/sequential/ in bulk. The
verifier is the safety net that catches "fmt subtly changed semantics"
before it gets baked into a checked-in change. Already paid off — the
first sweep flagged a real precedence bug in MethodRewriter that the
followup commit fixes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Found by FmtVerifier on benchmarks/sequential/11_pipeline_overhead.cht:
`toFloat(state MOD 1000)` was being rewritten to
`state MOD 1000.toFloat()`, which Zig parses as
`state MOD (1000.toFloat())` — integer mod silently became float
mod. Real semantics change.

Root cause: when MethodRewriter rewrites `f(arg)` to `arg.f()`, the
first argument's source text was inlined verbatim. For an arg like
`state MOD 1000` the result has different operator precedence than
the original.

Fix: inspect the AST shape of the first arg. If it's an Identifier,
Literal, MethodCall, FuncCall, GetField, GetIndex, StructLit,
ListLit, HashLit, or StringLit — i.e. a "tight" form that binds
tighter than `.method()` — emit it bare. Otherwise wrap in parens.
Also detect already-paren-wrapped source text and skip
double-wrapping.

Tests: 6 new specs in spec/method_rewriter_spec.rb cover the
binary-op case, unary-op case, identifier (no wrap), method chain
(no wrap), literal (no wrap), and the no-double-wrap case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Found while auditing fmt output on benchmarks/sequential/ before
applying in bulk. The original canonicalize_comment rule was
"exactly one space after #," which destroyed deliberate prose
indentation in:

  - ASCII tables in comment blocks (header vs row indent)
  - Indented bullet/sub-bullet lists
  - Code samples inside comment blocks

Old behavior: `#   row 1  | x` became `# row 1  | x`, breaking
column alignment with `# COL A    | COL B` headers.

New rule: ensure AT LEAST one space after `#`. Preserve any
additional user-typed spaces. Synthesize the missing first space
only when the user wrote `#text` with no separator. Trailing
whitespace is still stripped; empty `#` still stays `#`.

This matches gofmt / rustfmt's stance — they leave comment
internals alone. User-typed indent inside a comment is meaningful;
fmt shouldn't rewrite it.

Tests: 4 new specs in spec/clear_fmt_spec.rb cover multi-space
indent preservation, the `#text` -> `# text` case, an ASCII table
roundtrip, and an empty `#` line preserved verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds four auto-fixes to `clear fmt` (driven by semantic analysis,
applied as a source-level pre-pass before the existing formatter)
plus one warn-only lint surfaced through `clear fix`.

1. Drop `MUTABLE` when the binding is read but never reassigned.
   Annotator-driven via the existing `MUTABLE-never-reassigned`
   finding (auto-confidence). LintFixRewriter drains the finding
   and applies the edit.

2. Drop redundant `: Type` annotations like `s: Float64 = 0.0` ->
   `s = 0.0` when the literal RHS already determines the type.
   Walks the annotated AST, compares declared `type` against the
   value's inferred `full_type`. Only triggers on bare types — any
   decoration (sigil, capability, array, optional, error union,
   generic instance) keeps the annotation, since those carry intent
   the value alone may not express.

3. Generic-bracket attach: `Foo<T, U>` instead of `Foo < T , U >`.
   Per-line pre-pass marks `<`/`>` tokens that are generic brackets
   (TYPE_ID-prefixed open with a clean matching close); the spacing
   logic then attaches them tightly without affecting comparison
   operators.

4. Struct-literal brace attach + interior padding: `Foo{ field: v }`
   instead of `Foo { field: v }` and instead of `Foo{field: v}`.
   The TYPE_ID-`{`-pattern is detected and disambiguated from
   STRUCT/UNION/ENUM body opens (which keep their leading space).
   Empty `Foo{}` stays tight (no padding inserted).

5. (warning only, no auto-fix) Multiple statements on one line
   (`a = 1; b = 2; c = 3;`) emits a `:lint` warning during
   `clear fix`. Splitting these into separate lines is a layout
   judgement call (indent / blank lines / inline comments) that
   fmt shouldn't make automatically — surface the smell, let the
   user decide.

Implementation:
- src/tools/lint_fix_rewriter.rb (new) — runs the annotator with
  FixCollector enabled, drains findings, walks the AST for
  type-annotation redundancy, applies all edits in one pass.
  Falls back gracefully on annotation failure (fmt must still
  format files with compile errors).
- src/tools/multi_statement_linter.rb (new) — tracks `;` at
  top-level depth, ignoring strings/comments/bracketed contexts.
  Wired into `clear fix` next to PredicateRewriter.lint!.
- src/tools/formatter.rb — calls LintFixRewriter as the first
  rewriter in the format pipeline; adds generic-bracket and
  struct-literal-brace pre-passes that compute per-line index
  sets used by `needs_space?`.

Tests:
- spec/clear_fmt_spec.rb adds 12 specs covering all four rules
  end-to-end through `Formatter.format`.
- spec/lint_fix_rewriter_spec.rb (new, 10 specs) targets the
  rewriter in isolation including the broken-source robustness
  case.
- spec/multi_statement_linter_spec.rb (new, 7 specs) covers the
  warn-only lint plus its no-touch-strings/comments edge cases.

Verified: 4005 Ruby specs, 514 transpile-tests (0 leaks), all
14 benchmarks/sequential/*.cht files re-fmt cleanly and the
FmtVerifier sweep shows byte-identical Zig output before and
after on each.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the previous benchmark fmt commit. All 14 files re-fmt'd
under the four new rules introduced in the preceding commit:

- MUTABLE drop where binding is never reassigned.
- `: Type` annotation drop where the literal RHS already
  determines the type (Int64, Float64, etc).
- Generic-bracket attach: `HashMap<Int64, Float64>` instead of
  `HashMap < Int64, Float64 >`.
- Struct-literal brace attach + interior padding:
  `Node{ val: 5 }` instead of `Node {val: 5}`.

Plus 14_iterator/bench.cht: the hand-written iterator helpers
(`hasNext`, `currentVal`, `advance`) switched from `FN` to
`METHOD`. fmt then UFCS-rewrites all call sites
(`hasNext(iter)` -> `iter.hasNext()`, etc), which is the
canonical CLEAR shape for that style of API.

Verified: FmtVerifier sweep — every benchmark transpiles to the
same Zig before and after fmt. 3 width warnings remain on long
print/interpolation lines (09_frame_vs_heap, 11_pipeline_overhead),
which are out of fmt's scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 specs covering the equivalence-check logic without exercising
the full transpile pipeline. Stubs `FmtVerifier.transpile` and
`Formatter.format` so the tests focus on:

- Identical Zig outputs → ok=true
- Diverging Zig outputs → ok=false with a unified-diff excerpt
- `// CLR:N` line markers stripped before comparison (the only
  legitimate fmt-induced delta in emitted Zig)
- Code-line differences alongside CLR markers still flagged
- Transpile / Formatter raises captured as `error` field
- `verify_dir` walks recursively and returns one Result per file
- `report` prints details and returns the failure count as exit
  code (matches CLI behaviour)

Plus a sub-describe for `.normalize_for_compare` itself: strips
standalone `// CLR:N` lines, leaves inline forms alone, no-op on
Zig without markers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Production-style hot loops shouldn't pay the cooperative-yield-check
tax on every iteration. Switch FOR / WHILE to TIGHT FOR / TIGHT WHILE
in the 7 sequential benchmarks where it's safe.

NOT converted (and why):

- 11_pipeline_overhead — SPECIFICALLY measures pipeline overhead vs
  handwritten loops including yield-check cost. Non-TIGHT is the
  experiment.
- 03_alloc_throughput — has both `benchRegular` (FOR) and
  `benchTight` (TIGHT WHILE) by design as a yield-overhead reference.
- 06_simd — its FOR body calls `dot4` which is `@reentrant`;
  TIGHT-loop-cannot-call-reentrant-function compiler error.
- 05_string_builder — loop body frame-allocates a String[]@list per
  iteration. TIGHT skips the per-iteration saveLoopMark / restoreLoopMark
  (mir_lowering.rb:6441), so the frame arena grew unbounded
  (10000 iters × ~50KB each = 576MB RSS, 3x slower).
- 09_frame_vs_heap — same shape: loop body frame-allocates strings via
  interpolation each iteration. TIGHT caused 6MB → 29MB RSS and a 56%
  slowdown.

The 05/09 finding is worth filing as a compiler bug:
mir_lowering.rb:6441 unconditionally skips saveLoopMark / restoreLoopMark
for TIGHT loops, but CLAUDE.md INV-7 says "Every loop body that allocates
from the frame arena must have per-iteration mark/rewind. (Enforced by:
FRAME_OVERFLOW check)." TIGHT + frame-alloc currently violates that
invariant silently. The MIR checker should reject TIGHT loops whose
body has frame allocs (or the lowering should still emit the mark
under TIGHT — TIGHT means "skip yield check," not "skip arena hygiene").
Filed in the commit message rather than fixed here because this branch
is fmt-scope only.

Smoke benchmark numbers (single run each, --smoke uses --optimized):

  benchmark              before     after     RSS before  RSS after
  04_hashmap              0.104 s   0.100 s   67 MB       67 MB
  07_pointer_chase        0.046 s   0.027 s   60 MB       61 MB    (-41%)
  08_sort                 0.099 s   0.097 s   62 MB       62 MB
  10_pool_vs_multiowned   0.078 s   0.074 s  181 MB      181 MB
  12_weak_ref_graph       0.021 s   0.015 s   30 MB       30 MB    (-29%)
  13_soa_layout           0.013 s   0.009 s   56 MB       56 MB    (-31%)
  14_iterator             0.003 s   0.003 s    6 MB        6 MB

All wins or no-change. Ranges from ~0% (already optimal) up to 41%
faster. RSS unchanged everywhere.

Verified: FmtVerifier sweep — all 14 benchmarks transpile to the
same Zig before and after fmt. 4017 Ruby specs, 514 transpile-tests
(0 leaks) all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three edge cases surfaced applying fmt to benchmarks/server/:

1. `String@raw` annotation was being dropped as "redundant" because
   the decoration check used `Type#any_sync?`, which deliberately
   excludes `:raw` and `:symbol` (data-access modes, not locks).
   But `String@raw` and `String` use different indexing semantics
   (byte vs UTF-8 codepoint), so dropping the annotation silently
   changes runtime behavior. Switch the check to read `Type#sync`
   directly — ANY sync stamp is decoration for fmt purposes.

2. `MUTABLE` was being dropped from bindings passed mutably through
   a `BG { ... }` capture. The annotator's lint marks
   `info.reg.var_mutated` only for direct reassignment, not for
   "passed as MUTABLE arg" — and BG captures don't propagate the
   mutation back to the outer scope at all. Dropping MUTABLE there
   broke the next compile with "Argument N is MUTABLE, but you
   passed immutable variable X." Two-layer fix:
   - annotator.rb extends the lint guard to also skip when
     `info.mutated` is set (catches direct MUTABLE-arg passes
     like `bar(arr)` where `bar` declares `MUTABLE xs`).
   - lint_fix_rewriter.rb walks the AST collecting every name
     referenced inside a BG/BG-STREAM block, and skips MUTABLE-drop
     for those names. Defensive — until the annotator's mutation
     analysis propagates through BG captures, this avoids the
     specific compile-fail pattern.

3. FmtVerifier was flagging `// CLEAR_PROFILE_TASK_SITE id=N
   line=L column=C` debug comments as differences when fmt
   rearranged source (line/col shift). Same class of metadata as
   `// CLR:N` markers — strip them in `normalize_for_compare`.

Tests: 3 new specs in spec/lint_fix_rewriter_spec.rb cover the
BG-capture skip, the no-skip case (binding not in BG), and the
String@raw preservation case.

Verified: 4017 Ruby specs, 514 transpile-tests (0 leaks) all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
01_tcp_kvstore, 02_json_api, 03_pathological all formatted under the
current rules: indent normalization, MUTABLE-drop on read-only
bindings, `: Type` drop on literal-RHS declarations (Int64 / Float64
where context determines), generic-bracket attach
(`HashMap<K, V>`), struct-literal attach + interior padding, leading-
comment whitespace preserved, predicate canonicalization
(`x.length() > 0` -> `x.any?()`, etc).

All three .cht files build cleanly post-fmt. The FmtVerifier sweep
flags some byte-level Zig deltas where the predicate rewriter emits
canonical helper calls instead of inline length comparisons (e.g.
`@as(i64, @intcast(resp.len)) > 0` -> `resp.len > 0` via `.any?()`).
These are intentional — the rewriter exists to produce that output —
and the resulting Zig is semantically equivalent. Build success +
existing test suite passing is the actual correctness signal here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 .cht files reformatted under the current rules. examples/minivm/
is excluded per its deprecated/active-VM split (CLAUDE.md: scheme
and interpreter paths are deprecated; _bc_runner is hand-tuned
hot-path code).

Files modified:

  examples/concurrent_reports/reports.cht
  examples/data_pipeline/pipeline.cht
  examples/graphdb/graph.cht
  examples/json_parser/json.cht
  examples/litedb/litedb.cht
  examples/parallel_du/du.cht
  examples/testing/{basic_test,freeze_candidate,stub_ufcs}.cht
  examples/web_crawler/src/main.cht
  examples/footguns/{05_toctou,06_memory_ordering,07_causal_ordering,
                     10_alias_mutation,12_deadlock}/main.cht

Files NOT modified (refused-to-format on parse error):

  examples/footguns/{02_data_race, 04_task_leak, 08_buffer_overflow,
                     09_uninitialized_read, 11_iterator_invalidation}/main.cht

Those five footgun demos contain syntax that no longer parses under
the current language — likely the syntax churn (`s>` → `|>`, `--`
→ `#`, etc) outpaced the demo. fmt's parse-validation refuses to
write rather than corrupting them, which is the right call. Worth
filing as a separate cleanup task.

Build status unchanged by fmt: pre-fmt and post-fmt produce the
same build pass/fail set. The footgun demos that DO parse still
fail to build at the annotator/MIR stage — that's by design (they
demonstrate compiler safety errors). web_crawler fails on a
missing http.zig import in both states.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Seven footgun demos had rotted past the language churn and refused
to parse, so the previous "fmt examples/" commit left them
untouched. Bring them current, then format under the same rules.

Per-file changes:

  01_use_after_free
    - `[]Int64` -> `Int64[]` (suffix-bracket array syntax)

  02_data_race
    - `REPEAT N TIMES ... END` -> `FOR i IN (0 ..< N) DO ... END`

  03_memory_leak
    - `RETURNS T OR RAISE` -> `RETURNS !T` (modern fallible signature)
    - `expr OR { handler }` block-handler form is no longer
      supported; `OR RAISE` / `OR EXIT` are the modern shapes.
      Replaced the demo's call-site error block with a comment
      explaining the modern propagation idioms.

  04_task_leak
    - `BG { fn() };` -> `BG { fn(); };` (BG body needs `;`)
    - `REPEAT N TIMES ... END` -> `FOR i IN (0 ..< N) DO ... END`

  08_buffer_overflow
    - `[Int]` -> `Int64[]` (CLEAR has no bare `Int`; it's `Int64`)
    - `WHILE cond { ... }` -> `WHILE cond DO ... END`
    - `arr[i]! = val` -> `arr[i] = val` (no mutation suffix on
      indexed assignment in modern CLEAR)
    - Added `MUTABLE` and explicit type on the loop-counter
      bindings that the new fmt rules expected.

  09_uninitialized_read
    - `Int` -> `Int64` (4 sites)
    - `WHILE cond { ... }` -> `WHILE cond DO ... END`
    - Added `MUTABLE` on `sum` and `i` (they're reassigned).

  11_iterator_invalidation
    - `list | filter(...) | collect()` -> `list |> WHERE ... |> COUNT _`
      (modern pipeline operator + stage keywords)
    - `list | reduce(0, ...)` -> `list |> REDUCE(0_i64) acc + _`
    - `[Type] @shared:locked` -> `Type[]@list:shared:locked`
      (suffix-bracket + capability syntax)
    - `list.append!(50)` -> `list.append(50)` (no UFCS-mutation `!`)

Build status (semantic-stage only — fmt is verified separately
by re-parsing post-write):

  09_uninitialized_read    builds clean
  Other 6                  fail at annotator/MIR level

The failures are not fmt regressions — these demos exercise
features (struct cleanup with TAKES, polymorphic @shared:locked
under BG, etc) that are still in flight or were never fully
implemented for the demo. Whether each demo's "expected error" is
actually firing for the right reason is a follow-up; this commit
just gets them parseable + formatted again so future fmt sweeps
include them.

Verified: 4020 Ruby specs, 514 transpile-tests (0 leaks).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Formatted under the same rules used in the previous benchmark sweeps:
indent normalization, MUTABLE-drop on read-only bindings, redundant
`: Type` drop on literal-RHS declarations, generic-bracket attach,
struct-literal attach + interior padding, leading-comment whitespace
preserved, predicate canonicalization. METHOD-flagged calls get
UFCS-rewritten where the receiver type matches.

NOT fmt'd (and why):

- 02_concurrent_search/bench.cht — calls `readFile(filepath)`,
  which fmt UFCS-rewrites to `filepath.readFile()`. The FSM lowering
  for I/O-suspending calls isn't UFCS-form-agnostic and crashes with
  `FsmOps arg index 0 out of range (0 args)` after the rewrite.
  Pre-existing fmt+FSM interaction bug; reverted to leave the file
  untouched.

- 14_nested_lock/bench.cht — has `IF cond THEN s1; s2; END`
  multi-statement one-liners that fmt's IF-expansion pass mishandles,
  collapsing trailing comments and following blocks into a single
  323-char line that no longer parses. Pre-existing fmt bug;
  reverted. The file would benefit from the multi-statement-per-line
  warning that already exists in this branch — splitting the THEN
  body into its own line first would let fmt re-engage cleanly.

Both reverted files build clean before fmt and represent fmt
limitations rather than benchmark-author errors. Worth filing as
separate fmt-bug tickets:
  1. UFCS-rewriter should skip stdlib functions whose lowering has
     position-sensitive arg-shape requirements (FSM-IO calls).
  2. Multi-statement-after-THEN expansion mishandles trailing
     comments + following blocks.

Of the 16 files that were fmt'd, all 16 build clean. The
FmtVerifier flags some byte-level Zig deltas where the predicate
rewriter emits canonical helper calls or where guard-counter IDs
shifted due to AST changes — both semantically equivalent.

Profile-data .cht files in `*.profile/` directories are gitignored
and not affected by this commit.

Verified: 4020 Ruby specs, 514 transpile-tests (0 leaks).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pre-existing fmt bugs surfaced by the concurrent benchmark sweep,
both of which forced reverts in the previous commit. Fixed here with
tests, then the two reverted files re-formatted under the new code.

Bug 1 — UFCS-rewrite of FSM-lowered stdlib (e.g. `readFile`):
  `readFile(filepath)` was being rewritten to `filepath.readFile()`
  because the registry entry has `is_method: true`. But its lowering
  reads positional args via FsmOps templates — once the first arg
  moves into the receiver slot, the FSM emitter crashes with
  "FsmOps arg index 0 out of range (0 args)."

  Fix in src/tools/method_rewriter.rb: skip stdlib entries that have
  BOTH `suspends: true` AND any `fsm_*` template key. Detection is
  structural so future FSM-lowered helpers get the skip automatically.

Bug 2 — `BG { @parallel -> FOR ... DO ...; ...; END }` collapsing to
one massive line:
  Three interacting fmt bugs combined here. `count_statements_in_block`
  didn't track DO/THEN nesting, so inner `;` looked like top-level
  statements and the wrap fired wrong; `emit_bg_do_wrapped` also
  used to NL-on-`;` regardless of nesting; and most importantly,
  `expand_method_chains` stripped ALL NLs from chain segments
  including ones nested inside an argument-position
  `BG { ... }` block.

  Fixes in src/tools/formatter.rb:
    - count_statements_in_block tracks DO/THEN block depth and
      counts a single top-level block (FOR/IF/WHILE/MATCH) as one
      statement.
    - bg_body_needs_wrap? wraps single-statement bodies when the
      single statement opens a nested block, so the body still
      gets multi-line layout.
    - emit_bg_do_wrapped tracks DO/THEN depth too and only NLs
      on `;` at the BG-level top.
    - expand_if_while_for tracks DO/THEN depth so inner one-liner
      blocks (`IF a > b THEN lo = b; hi = a; END`) don't get torn
      apart when expanding their containing FOR/WHILE/IF.
    - expand_method_chains strips NLs ONLY at chain-segment top
      level — not those nested inside `(args)` / `{ body }`.

  Additional fix in src/tools/fmt_verifier.rb: extend
  normalize_for_compare to also strip lowering-emitted ID counters
  in synthesized variable names (`__bank_guard_3700` /
  `__sort_guard_3940_1` etc). Equivalent CLEAR programs whose AST
  shifted under fmt produce the same Zig logic with different IDs;
  these are diagnostic counters, not semantic.

Tests: 5 new specs total — 2 in spec/method_rewriter_spec.rb
covering the FSM skip + non-FSM still-rewrites cases, 3 in
spec/clear_fmt_spec.rb covering BG-with-FOR-body wrap, NL
preservation through method-chain BG args, and inner-one-liner-IF
preservation through outer-FOR expansion.

Could be folded into the earlier MethodRewriter / lint-rules
commits if a single squash is preferred at PR time; left as a
follow-up commit here so the diff is reviewable in isolation.

Files re-fmt'd under the fixes:
  benchmarks/concurrent/02_concurrent_search/bench.cht
  benchmarks/concurrent/14_nested_lock/bench.cht

Verified: FmtVerifier sweep — all 19 concurrent benchmarks pass
(02 and 14 now OK; the previously-failing files build clean).
4025 Ruby specs, 514 transpile-tests (0 leaks) all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 7, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 95.53451% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.73%. Comparing base (07b3f81) to head (af2d15a).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
src/tools/formatter.rb 95.37% 20 Missing ⚠️
src/tools/multi_statement_linter.rb 84.21% 9 Missing ⚠️
src/tools/fmt_verifier.rb 94.91% 3 Missing ⚠️
src/tools/lint_fix_rewriter.rb 99.42% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #17      +/-   ##
==========================================
+ Coverage   89.60%   89.73%   +0.12%     
==========================================
  Files         170      173       +3     
  Lines       45996    46723     +727     
  Branches    11290    11604     +314     
==========================================
+ Hits        41216    41927     +711     
- Misses       4780     4796      +16     
Flag Coverage Δ
ruby 85.71% <95.53%> (+0.33%) ⬆️
zig 95.57% <ø> (-0.02%) ⬇️

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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

🐰 Bencher Report

Branchfmting
Testbedubuntu-latest

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
Benchmarkleak-build-msMeasure (units) x 1e3leak-countMeasure (units)leak-run-msMeasure (units)
benchmarks/concurrent/05_backpressure/bench📈 view plot
⚠️ NO THRESHOLD
5.62 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
1,863.95 units
benchmarks/concurrent/10_shard_vs_locked/bench📈 view plot
⚠️ NO THRESHOLD
5.17 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
60,004.94 units
benchmarks/concurrent/16_observables/bench📈 view plot
⚠️ NO THRESHOLD
5.20 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
95.84 units
benchmarks/inter-clear/03_concurrent_mvcc_vs_rwlock/bench📈 view plot
⚠️ NO THRESHOLD
5.67 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
210.56 units
benchmarks/sequential/07_pointer_chase/bench📈 view plot
⚠️ NO THRESHOLD
5.09 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
596.12 units
benchmarks/sequential/12_weak_ref_graph/bench📈 view plot
⚠️ NO THRESHOLD
5.13 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
130.57 units
benchmarks/server/03_pathological/server📈 view plot
⚠️ NO THRESHOLD
5.25 units x 1e3📈 view plot
⚠️ NO THRESHOLD
0.00 units📈 view plot
⚠️ NO THRESHOLD
1,002.87 units
🐰 View full continuous benchmarking report in Bencher

@cuzzo cuzzo force-pushed the fmting branch 2 times, most recently from 4579413 to 2031fe3 Compare May 8, 2026 01:15
Builds on the previous round of formatter fixes. Seven bugs total:

- **MATCH `;,` arm separator** — `;` at depth 0 forced a NL before
  the trailing arm comma. The statement-terminator helper now absorbs
  an immediately-following `,` (idempotently — even if a prior pass
  already split them).

- **Inline `@cap:cap` chain** — the default `:` rule (no space before,
  space after) treated chains like a type annotation. Added a
  capability-chain check that walks back through `:identifier:...:`
  segments (skipping `(...)` args) and bottoms out at an `@cap` VAR_ID.
  Normal `: Type` annotations and `REQUIRES x: LOCKED` are unaffected.

- **MATCH block layout** — multi-line `MATCH ... START ... END` had
  arms at the same column as `START` and END at column 0, multi-line
  arm bodies stayed flush with the arm pattern, and `DEFAULT`
  outdented like CATCH/DEFAULT in TRY. New `expand_match_blocks` emits
  arms at +1 from `START`, multi-statement arm bodies at +2 with the
  trailing `,` flush against the body's last `;`, END at MATCH-line
  indent. DEFAULT is tagged with `:KEEP_INDENT` to suppress render's
  OUTDENT_LEADING for that line.

- **Multi-branch IF/ELSE_IF chain with same-line bodies** — repro from
  examples/json_parser/parseString. `expand_then_do_blocks` now also
  fires when any branch has inline body, body walker pushes inline
  bodies onto their own line at +1, ELSE/ELSE_IF outdent works
  naturally. Body walker's keyword-block-depth tracker counts
  IF/WHILE/FOR/TEST/WHEN openers (not THEN/DO) so ELSE_IF's own THEN
  doesn't falsely nest.

- **BG body with leading `@strategy ->`** — repro from
  benchmarks/concurrent/09_kvstore. `BG { @parallel -> body }` had a
  `->` whose OPEN_TERMINAL render rule raised body depth, but no END
  inside to lower it back; only `}` closes (-1). Statements after the
  BG ended up one column too deep. `emit_bg_do_wrapped` now detects a
  top-level `->` in the BG body and emits a balancing INDENT_CLOSE
  before `}`.

- **Capability chain with parenthesized argument** — repro from
  benchmarks/concurrent/09_kvstore (`@shared:sharded(128):locked`).
  The chain detector bailed when it hit `)`, leaving the trailing
  `: locked` rendered with a space. `capability_chain_colon?` now
  skips a trailing `(...)` group before falling back to the
  identifier.

- **`END` always opens a new line** — repro from json_parser
  jsonToString JBool arm where `END RETURN "false";` stayed glued.
  New `nl_after_end` post-pass forces a NL after every END, except
  when END is followed by a close-bracket or `;` (`}`, `)`, `]`, `;`).

Re-fmt'd the affected branch files. 4130 unit specs, 0 failures.
litedb / graphdb run clean; json_parser, kvstore, atomic_ptr,
pubsub, false_sharing, rwlock_starvation, nested_lock all build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cuzzo cuzzo merged commit 54578a4 into master May 8, 2026
31 checks passed
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.

2 participants