Skip to content

Cut macOS widget memory and visualizer CPU - #49

Merged
SunkenInTime merged 21 commits into
masterfrom
agent/macos-visualizer-perf
Aug 3, 2026
Merged

Cut macOS widget memory and visualizer CPU#49
SunkenInTime merged 21 commits into
masterfrom
agent/macos-visualizer-perf

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Aug 3, 2026

Copy link
Copy Markdown
Owner

What changed

  • carry the measured macOS widget-memory cuts and their receipts
  • move Visualizer text updates onto provider signals without root rerenders
  • keep its segmented meter on Canvas with pixel-aligned direct Metal rectangles
  • retain the Canvas view tree across paint-only frame updates
  • disable Native's continuous event journal for production Widget builds while preserving explicit profiling modes
  • pin the restacked Native implementation from Cut macOS visualizer render cost native#27

Why

The audio Visualizer was rebuilding TSX/layout state and entering avoidable raster and trace paths on every frame. Those costs came from the generic provider, Canvas, renderer, and trace seams—not from text labels and not from Canvas being the wrong primitive.

Impact

The developer-facing shape stays ordinary TSX: labels remain <text>, animated meter geometry remains <canvas>, and no visualizer-specific native primitive is introduced.

Adjacent production A/B receipts on an Apple M2 measured:

  • pixel-aligned direct Metal rectangles: 16.316% → 13.225% complete-workload CPU
  • retained Canvas updates: 6.425% → 3.597%
  • production Widget trace off: 3.597% → 2.818%
  • final active pair: 0.972% CPU per Widget, with provider frame delivery preserved

The receipt is in docs/macos-visualizer-perf-2026-07-31.md.

Dependency

Validation

  • npm ci
  • npm run build
  • npm test — 80/80
  • npm run typecheck
  • npm run audit:release
  • runtime: zig build test-platform-services
  • runtime: zig build -Doptimize=ReleaseFast
  • runtime: zig build test
  • host: zig build -Doptimize=ReleaseFast
  • host: zig build test -Doptimize=ReleaseFast
  • Native validation is recorded on Cut macOS visualizer render cost native#27.

Summary by CodeRabbit

  • New Features

    • Added reactive provider signals for time, CPU, memory, audio, and media values.
    • Text elements can now display mapped signal values that update without full widget renders.
    • Added a clock widget example and improved the audio visualizer’s live updates.
    • Added same-view canvas updates to reduce unnecessary rebuilds.
  • Bug Fixes

    • Provider diagnostics now identify missing subscriptions and unknown providers for both hook types.
  • Performance

    • Event tracing is now disabled by default, reducing diagnostic overhead.

Dara Adedeji and others added 15 commits August 2, 2026 17:48
Native SDK branch macos-memory-shared-renderer-prep (600d6cf6) carries
the autorelease-pool, analytic-rounded-clip, and Metal tiled-image
memory work; the tiled-image change still needs live verification.
The briefs scope the two follow-up passes: the error-propagation seams
(partially landed via #43) and the receipt sweep over every numeric
limit. The shared-renderer experiment plan lives in the handoff doc
accompanying this work.
The branch is now the complete working set for the macOS memory /
shared-renderer work: docs/macos-memory-handoff.md is the entry point
(diagnosis so far, phased experiment plan, falsification gates), and
myclock/ is the clean isolated-benchmark fixture the bakeoff harness
and Phase 0/1 measurements use.
…partially rescinded

Myclock on Mac15,6 (M3 Pro, macOS 26.5.2) measures 125 MB with 85 MB
dirty owned-unmapped-graphics on this exact branch state, while bare
Metal/IOSurface window probes on the same machine cost 9.7/8.5 MiB.
The Air's Phase 0 probes were honest but window-scoped; the wall is in
what Weaver's renderer does, not in the Metal entry fee. New
evidence-led investigation order appended for the next agent.
The handoff doc keeps the correction (the finding that rescinds the
Phase 0 gate); the investigation of what allocates the 85 MB is separate
work for the Mac15,6 machine and lives in docs/gpu-ledger-wall-brief.md,
with its own end state, evidence-led order, and stop rule.
Bare probes on Mac15,6 turn the ~85-96 MB owned-unmapped-graphics ledger
on and off with no weaver code: sustained Metal command submission at
>=1 Hz commits a ~95 MB per-process driver arena (presentation and
window not required; offscreen clears reproduce it), reclaimed within
seconds of submission silence. IOSurface-on-CALayer presentation with no
in-process Metal never touches it, even at 60 Hz updates. Weaver pins
the arena forever because renderFrame presents unconditionally at 60 Hz.
Receipt, probe matrix, and the recommendation recorded in the brief;
probe sources archived under .zig-cache/macos-memory/gpu-ledger-wall/.
The shared-renderer decision stays with Dara per the brief's stop rule.
The handoff's stopped plan is un-stopped: the GPU-ledger brief's probes
named the 85 MB (per-process Metal submission working set, paid by
whoever submits, ~0 for device-less IOSurface widgets), and Dara
re-approved the shared-renderer architecture on that receipt. Phase 1
is the next work; its gate expectation is restated for M3-class
machines where the arena inflates the old Air-calibrated totals.
One file scoped to the 2026-07-30 session: the subscription-fee mental
model, the probe method that produced the on/off receipt (sustained-
cadence probes, exact-config matching, ledger-category cross-checks,
PID discipline), what the finding settles, and the corrections it makes
to prior session records. Durable state stays in the handoff and the
GPU-ledger brief; this is the lessons file.
Phase 1 runs on Mac15,6 where the arena exists. The gate becomes
categorical: no submission arena in any widget process (graphics ledger
~0), widget total judged as content cost. Widget side submits no Metal;
event-driven presenting stays out of the spike; host shape expectations
from the N-layer probe recorded.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds provider-backed signals and signal-bound text rendering, updates clock and audio examples, separates retained canvas updates from tree generations, adds runtime memory and tracing diagnostics, improves macOS measurement tooling, and records error, GPU, memory, and limit investigations.

Changes

Provider signal support

Layer / File(s) Summary
Signal contracts and runtime
sdk/index.d.ts, sdk/src/reconciler.ts, sdk/src/index.ts, sdk/CONTRACT.md
Adds Signal<T>, useProviderSignal, mapped signals, signal-bound text, subscriptions, cleanup, and public exports.
Examples and validation
examples/myclock/*, examples/visualizer/widget.tsx, sdk/test/*, cli/src/index.ts, cli/test/cli.test.mjs
Uses time and audio signals. Tests updates, unmount behavior, validation, and missing subscriptions for both provider hooks.

Runtime rendering and measurement

Layer / File(s) Summary
Retained canvas projection
runtime/src/tree.zig, runtime/src/main.zig
Tracks canvas-only generations and projects same-view canvas frames without rebuilding the retained tree.
Runtime diagnostics and native alignment
runtime/src/js_engine.zig, runtime/src/main.zig, runtime/build.zig, runtime/native-sdk, scripts/release-audit.mjs
Adds QuickJS memory reporting, optional memory receipts, disabled default tracing, and the updated native SDK commit.
macOS measurement harness
scripts/macos-audio-cost.py, docs/macos-visualizer-perf-2026-07-31.md
Adds revision selection, cumulative CPU and WindowServer measurements, process sampling, source validation, and benchmark results.

Investigation documentation

Layer / File(s) Summary
Error and limit investigations
docs/error-propagation-brief.md, docs/receipt-sweep-brief.md
Documents silent failure seams, required diagnostics, stale-state handling, budget receipts, synchronized limits, and acceptance criteria.
GPU and memory investigations
docs/gpu-ledger-*.md, docs/macos-memory-handoff.md
Records sustained Metal submission measurements, macOS memory findings, shared-renderer phases, validation status, and follow-up gates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Widget
  participant Signal
  participant Reconciler
  participant CanvasRuntime
  Widget->>Signal: read provider value
  Signal->>Reconciler: notify subscribed text binding
  Reconciler->>CanvasRuntime: project same-view canvas update
  CanvasRuntime->>CanvasRuntime: update canvas_generation
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's main goals: reducing macOS widget memory usage and Visualizer CPU cost.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/macos-visualizer-perf

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

@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: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (7)
runtime/src/tree.zig-256-256 (1)

256-256: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve canvas_generation in transaction snapshots.

cloneInto copies generation but not canvas_generation. resetEmpty also does not initialize canvas_generation. A snapshot allocated by beginBatch can therefore restore an undefined canvas revision after abortBatch.

Copy the field in cloneInto. Initialize it in resetEmpty. Add a canvas-only batch-abort test.

Proposed fix
 fn cloneInto(self: *const Tree, destination: *Tree) Error!void {
     resetEmpty(destination, self.allocator);
     destination.root = self.root;
     destination.generation = self.generation;
+    destination.canvas_generation = self.canvas_generation;
     destination.next_node_lifetime = self.next_node_lifetime;
 fn resetEmpty(tree: *Tree, allocator: std.mem.Allocator) void {
     tree.root = null;
     tree.generation = 0;
+    tree.canvas_generation = 0;
     tree.next_node_lifetime = 1;
🤖 Prompt for 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.

In `@runtime/src/tree.zig` at line 256, Preserve canvas_generation across
transaction snapshots: update cloneInto to copy the source canvas_generation,
initialize canvas_generation in resetEmpty, and add a batch-abort test covering
canvas revision restoration through beginBatch and abortBatch.
docs/receipt-sweep-brief.md-37-39 (1)

37-39: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Specify the language for the shell fence.

markdownlint-cli2 reports MD040 at Line 37. Mark this block as shell code.

Proposed fix
-```
+```sh
 rg -n 'pub const max_|const max_|_cap|Limit|MAX_' runtime/src cli/src sdk/src
🤖 Prompt for 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.

In `@docs/receipt-sweep-brief.md` around lines 37 - 39, Specify the shell language
on the fenced code block containing the rg command by changing its opening fence
to use sh, while leaving the command unchanged.

Source: Linters/SAST tools

docs/receipt-sweep-brief.md-84-84 (1)

84-84: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Remove the stale unreceipted status.

The supplied runtime/src/main.zig:76-89 context already contains receipt comments for max_images and max_image_load_attempts. Move these entries to the receipted list, or record only the remaining verification work.

Proposed fix
-- `runtime/src/main.zig:73-74` `max_images = 16`, `max_image_load_attempts = 3`.
+- `runtime/src/main.zig:76-89` `max_images = 16`, `max_image_load_attempts = 3` — receipt present; verify synchronization only.
🤖 Prompt for 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.

In `@docs/receipt-sweep-brief.md` at line 84, Update the receipt status entry for
max_images and max_image_load_attempts in the documentation to remove them from
the unreceipted list, since runtime/src/main.zig already contains receipt
comments; move the entries to the receipted list or retain only any genuinely
outstanding verification work.
myclock/widget.tsx-1-19 (1)

1-19: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

This example sits outside examples/ and does not exercise the PR feature.

Every other example lives under examples/, for example examples/visualizer/widget.tsx. This widget uses useProvider("time"), not useProviderSignal, so it adds no coverage for provider signals. Combined with the machine-specific paths in myclock/tsconfig.json, the directory looks like a local scratch workspace. Move it to examples/myclock/ if it is intended to ship, or remove it from the PR.

🤖 Prompt for 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.

In `@myclock/widget.tsx` around lines 1 - 19, Remove the standalone myclock widget
from the PR, or relocate it under examples/myclock/ with the corresponding
configuration updates if it is intended as a shipped example; do not retain it
as a machine-specific scratch workspace outside examples. If kept, update the
widget to use useProviderSignal so it exercises the provider-signals feature.
sdk/test/reconciler.test.mjs-324-329 (1)

324-329: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert that the text node actually unmounted before you capture the baseline.

Line 324-325 calls context.hideText() and awaits one microtask. If the render scheduler needs more than one tick, textWritesAfterUnmount is captured while the text node is still mounted, and line 329 then passes for the wrong reason. Add a positive assertion that the swap to <panel> happened.

💚 Proposed fix
   context.hideText();
   await Promise.resolve();
+  assert.ok(fixtureOperations.some(([name, type]) => name === "createNode" && type === "panel"),
+    "the fixture did not re-render to <panel>; the unmount assertion below would be vacuous");
   const textWritesAfterUnmount = fixtureOperations.filter(([name]) => name === "setText").length;
   fixtureProviderCallback('{"provider":"audio","value":{"rms":0.7,"bands":[0.9]}}');
   assert.equal(context.readRms(), 0.7);
   assert.equal(fixtureOperations.filter(([name]) => name === "setText").length, textWritesAfterUnmount);
+  assert.equal(fixtureOperations.some(([name]) => name === "reportError"), false);
 });
🤖 Prompt for 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.

In `@sdk/test/reconciler.test.mjs` around lines 324 - 329, In the test around
context.hideText(), positively verify that the rendered text node has been
replaced by the <panel> element before capturing textWritesAfterUnmount. Keep
awaiting the scheduler as needed, then assert the swap using the existing
fixture/render state symbols before establishing the baseline and continuing
with the provider callback assertions.
docs/macos-memory-handoff.md-525-530 (1)

525-530: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the shell continuation and comment placement.

Place the explanatory comment before the command or after the complete command. Keep each continuation backslash as the final character on its line.

🤖 Prompt for 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.

In `@docs/macos-memory-handoff.md` around lines 525 - 530, Fix the command example
around the macOS renderer bakeoff invocation by moving the “or: software”
explanation before the command or after the completed command, and ensure every
line-continuation backslash remains the final character on its line.
docs/error-propagation-brief.md-74-80 (1)

74-80: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Update the image-limit documentation. The pinned Native revision uses a 1 MiB decoded-RGBA limit. A 256×256 RGBA image uses 262,144 bytes (256 KiB) and passes this limit. weaver check parses local image dimensions and reports the decoded byte calculation; it does not decode pixel data. Runtime failures report dimensions and the requested byte count. Restrict the downscale and placeholder guidance to images that exceed 1 MiB.

🤖 Prompt for 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.

In `@docs/error-propagation-brief.md` around lines 74 - 80, Update the image-limit
section to document the pinned Native revision’s 1 MiB decoded-RGBA limit,
correct the 256×256 RGBA calculation to 262,144 bytes (256 KiB) and state that
it passes. Clarify that weaver check parses local dimensions and reports
decoded-byte calculations without decoding pixels, while runtime failures report
dimensions and requested bytes; restrict downscale and placeholder guidance to
images exceeding 1 MiB.
🧹 Nitpick comments (9)
scripts/macos-audio-cost.py (1)

80-85: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Capture all CPU times in one snapshot at each boundary.

Lines 80-85 run a separate ps command for each PID. Each CPU delta therefore has a different measurement interval. WindowServer uses another interval. The output describes aligned one-second CPU deltas, but these calls do not produce aligned samples.

Read pid and cputime for all Widget, host, and WindowServer PIDs in one ps invocation before and after the sleep. Record timestamps adjacent to each snapshot.

As per coding guidelines, “Treat widget memory and CPU performance as core product requirements; target performance that matches or exceeds Rainmeter.”

🤖 Prompt for 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.

In `@scripts/macos-audio-cost.py` around lines 80 - 85, Update the CPU sampling
flow around process_cpu_time so each boundary performs one ps invocation
covering all widget, host, and WindowServer PIDs, then records the timestamp
immediately adjacent to that snapshot. Derive cpu_before, cpu_after,
window_server_cpu_before, and window_server_cpu_after from the corresponding
shared snapshots so every delta uses aligned measurement intervals.

Source: Coding guidelines

docs/gpu-ledger-wall-brief.md (1)

46-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Record the existing software-path switch.

The supplied scripts/macos-renderer-bakeoff.py harness already sets WEAVER_FORCE_SOFTWARE=1 for the software candidate. Replace “find the forcing mechanism” with the exact variable and command so the measurement procedure remains reproducible.

🤖 Prompt for 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.

In `@docs/gpu-ledger-wall-brief.md` around lines 46 - 51, Update the
“Software-candidate discriminator” procedure in gpu-ledger-wall-brief.md to
replace the instruction to find the forcing mechanism with the exact existing
switch WEAVER_FORCE_SOFTWARE=1 and the command used by
scripts/macos-renderer-bakeoff.py. Preserve the software-candidate measurement
and comparison steps.
sdk/index.d.ts (1)

37-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Signal<T> and the useProviderSignal overloads are duplicated in two hand-maintained files.

sdk/index.d.ts lines 37-41 and 96-100 restate what sdk/src/reconciler.ts lines 58-62 and 335-339 already declare. The two copies can drift silently, because nothing compares them. Consider generating index.d.ts from the source declarations, or add a test that asserts both Signal shapes and all provider overloads stay identical.

Also applies to: 96-100

🤖 Prompt for 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.

In `@sdk/index.d.ts` around lines 37 - 41, Remove the duplicated hand-maintained
Signal and useProviderSignal declarations from sdk/index.d.ts by generating them
from the corresponding declarations in sdk/src/reconciler.ts, or add an
automated test that compares both Signal shapes and every provider overload to
prevent drift.
sdk/CONTRACT.md (1)

98-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the weaver check error text for useProviderSignal.

Line 99-100 records the exact check error for useProvider. cli/src/index.ts now emits a second form for the signal hook: useProviderSignal("audio") requires subscribe: ["audio"] in the widget config. Add that form so agents can match both messages from the contract alone.

📝 Proposed documentation update
 Rules: hooks follow React's rules (top level, stable order). `useProvider`
 requires the provider in `config.subscribe` — checked at `weaver check`,
 error: `useProvider("time") requires subscribe: ["time"] in the widget config`.
+`useProviderSignal` carries the same requirement and reports it with the hook
+name that used it, e.g. `useProviderSignal("audio") requires subscribe:
+["audio"] in the widget config`.
🤖 Prompt for 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.

In `@sdk/CONTRACT.md` around lines 98 - 108, Update the CONTRACT.md documentation
near the existing useProvider weaver check error to also record the exact
useProviderSignal error form, including the provider name placeholder and
required subscribe configuration. Keep both messages available for agents to
match.
cli/test/cli.test.mjs (1)

186-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the case where both hooks use the same unsubscribed provider.

The new behavior at cli/src/index.ts line 1673-1676 emits one error per hook per provider. This test covers only useProviderSignal("memory"). Add a fixture in which useProvider("memory") and useProviderSignal("memory") both appear without the subscription, then assert both messages. That is the only assertion that pins the per-hook split.

🤖 Prompt for 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.

In `@cli/test/cli.test.mjs` around lines 186 - 190, Extend the CLI test fixture
around missingSignalSubscription so it includes both useProvider("memory") and
useProviderSignal("memory") without the memory subscription, then assert that
stderr contains the distinct missing-subscription error for each hook. Preserve
the existing exit-status assertion and ensure both messages are checked.
sdk/src/reconciler.ts (1)

677-690: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

bindHostText rebinds whenever the caller passes a fresh mapped signal.

instance.textBinding === binding compares object identity. signal.map(...) returns a new object on every call, so a widget that maps inside the render body unsubscribes and resubscribes on every component render. examples/visualizer/widget.tsx line 43 does this. The behavior is correct, but the churn is avoidable.

Consider documenting in sdk/CONTRACT.md that a mapped signal used as a <text> child should be created once, for example with useRef, or memoize map results per source-and-projector pair.

🤖 Prompt for 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.

In `@sdk/src/reconciler.ts` around lines 677 - 690, Document in sdk/CONTRACT.md
that mapped signals used as <text> children should be created once and reused,
such as by storing them with useRef or memoizing map results per
source-and-projector pair, so bindHostText does not repeatedly unsubscribe and
resubscribe when renders produce fresh mapped signal objects.
examples/visualizer/widget.tsx (1)

100-103: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

The RMS strip keeps origin-anchored geometry while the bar meter is now centered.

Lines 58-59 center the bar meter with meterX. The strip at line 102 still starts at x = 0 and spans segments * 13 - 1 = 311 px. If the canvas width differs from 311 px, the two elements no longer share an edge. Center the strip with the same computation, or state in a comment that the offset is intentional.

🤖 Prompt for 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.

In `@examples/visualizer/widget.tsx` around lines 100 - 103, Update the RMS strip
drawing loop in the widget rendering logic to use the same centered horizontal
offset as the bar meter’s meterX calculation, so its geometry remains aligned
across varying canvas widths; preserve the existing segment colors and
dimensions.
sdk/test/reconciler.test.mjs (1)

279-291: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the new signal error paths.

The PR introduces three developer-visible errors that no test exercises:

  • A bound <text> must contain exactly one Signal child at sdk/src/reconciler.ts line 520.
  • <text> children must be strings, numbers, or one Signal at line 525.
  • Signal.subscribe(listener) requires a function and Signal.map(project) requires a function at lines 1174, 1179, 1195, and 1199.

These messages are part of the public contract that agents match against. A test that asserts each string prevents silent wording drift.

🤖 Prompt for 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.

In `@sdk/test/reconciler.test.mjs` around lines 279 - 291, Add tests in
sdk/test/reconciler.test.mjs covering each new developer-facing validation path:
bound text with zero or multiple Signal children, invalid
non-string/number/non-Signal text children, and non-function arguments to
Signal.subscribe and Signal.map. Assert the exact public error strings,
including “A bound <text> must contain exactly one Signal child”, “<text>
children must be strings, numbers, or one Signal”, “Signal.subscribe(listener)
requires a function”, and “Signal.map(project) requires a function”.

Source: Coding guidelines

cli/src/index.ts (1)

1529-1530: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the provider list from one source, and report unknown provider names.

Two points:

  1. Line 1529 declares the provider union and line 1655 repeats the same five names as a runtime array. If a provider is added to only one of them, the visitor silently ignores it and weaver check loses coverage for that provider.
  2. The condition at line 1655 skips any literal that is not a known provider. useProviderSignal("memmory") passes check with no error, then fails at runtime with the subscribe message, which points the developer at the wrong fix.
♻️ Proposed change
-  type ProviderName = "time" | "cpu" | "memory" | "audio" | "media";
+  const providerNames = ["time", "cpu", "memory", "audio", "media"] as const;
+  type ProviderName = typeof providerNames[number];
   const usedProviders = new Map<ProviderName, Set<"useProvider" | "useProviderSignal">>();
     if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
         (node.expression.text === "useProvider" || node.expression.text === "useProviderSignal")) {
       const argument = node.arguments[0];
-      if (argument && ts.isStringLiteral(argument) && ["time", "cpu", "memory", "audio", "media"].includes(argument.text)) {
+      if (argument && ts.isStringLiteral(argument) && (providerNames as readonly string[]).includes(argument.text)) {
         const provider = argument.text as ProviderName;
         const hooks = usedProviders.get(provider) ?? new Set<"useProvider" | "useProviderSignal">();
         hooks.add(node.expression.text);
         usedProviders.set(provider, hooks);
+      } else if (argument && ts.isStringLiteral(argument)) {
+        errors.push(locationMessage(
+          node.getSourceFile(),
+          argument,
+          `${node.expression.text}("${argument.text}") names no known provider; available providers: ${providerNames.join(", ")}`,
+        ));
       }
     }

Based on the coding guideline "messages must contain enough context and actionable information to fix the problem without reading the implementation".

Also applies to: 1652-1660

🤖 Prompt for 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.

In `@cli/src/index.ts` around lines 1529 - 1530, Derive the runtime provider
iteration in the visitor around usedProviders from the single ProviderName
source instead of repeating the five provider literals, keeping the type and
runtime list synchronized when providers change. Update the unknown-provider
handling so unsupported literal names are reported with an actionable error
identifying the invalid provider and expected providers, rather than being
silently skipped.

Source: Coding guidelines

🤖 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 `@docs/error-propagation-brief.md`:
- Around line 143-150: Extend the suggested acceptance test to assert atomicity
for both paths: when the initial render fails, verify no partial generation is
exposed; when a hot swap fails, verify the previously active bundle remains
unchanged and active. Keep the existing budget-error, logging, and visible
error-surface assertions intact.
- Around line 61-65: Update validateLoweredTreeBudgets in the weaver check flow
to inspect the lowered representation rather than authored JSX, so generated
text, canvases, and retained nodes are counted. Enforce all four
budgets—max_nodes, max_children, max_text_bytes, and max_canvases—and report
both the configured limit and requested amount for every failure.
- Around line 98-107: Update “Seam 6 — canvas prerequisites are unchecked” to
acknowledge that cli/src/index.ts already performs static validation via
canvasAncestorProblem, emitting CanvasNeedsUnclippedAncestors and
CanvasNeedsOpaqueAncestors through weaver check. Limit the remaining issue to
runtime logging when the canvas surface is denied dynamically, and replace the
stale CanvasNeedsExplicitSize line-1373 reference with the validator’s 1527–1681
range.

In `@docs/gpu-ledger-session-2026-07-30.md`:
- Around line 39-43: The conclusion in docs/gpu-ledger-session-2026-07-30.md
lines 39-43 should apply only to measured 1 Hz submissions, while preserving the
finding that 0.2 Hz submissions do not establish the arena; avoid generalizing
to every live widget. Update docs/gpu-ledger-wall-brief.md lines 143-147 by
replacing “any live widget” with the measured submission-rate condition, with no
other changes required.
- Around line 12-17: docs/gpu-ledger-session-2026-07-30.md lines 12-17: either
add measurements using 2–5 second idle gaps that directly support the reclaim
interval, or narrow the statement to the evidenced release window.
docs/gpu-ledger-wall-brief.md lines 126-128: apply the same evidence-bound
wording to the recommendation, without asserting an unsupported 2–5 second
interval.

In `@docs/gpu-ledger-wall-brief.md`:
- Around line 109-118: Revise the measurement table around the “Graphics ledger
(steady)” column to use a semantically accurate label and add explicit metadata
for sample count, measurement window, and aggregation type. Annotate each
affected value, including the initial, 0.2 Hz, and post-stop rows, as a mean,
range, peak, or final sample without changing the reported measurements.
- Around line 11-12: Update the branch metadata in the document header and
corresponding session record to clearly identify the measurement commit: either
make the header match the recorded Weaver commit or explicitly label the
pre-measurement and post-measurement commits in the `78f8cdf → 0db488a`
transition so the reported results have an unambiguous source state.

In `@docs/macos-memory-handoff.md`:
- Around line 131-136: Rewrite the background statement around the “owned
unmapped graphics” baseline to scope it to M3 Pro-class hardware and sustained
GPU submission workloads, rather than every widget or rendering path
universally. Explicitly note that the wall is near zero on the M2 Air, and avoid
presenting ~130 MB as a universal per-widget floor.
- Around line 112-119: Update the “Remaining work, in order” section to remove
the completed tile-validation tasks and record the post-patch visual
verification and 841/841 test result. Revise the later test-status section
around the existing checkpoint so it consistently states that the test passed
after the tile patch, or explicitly marks that checkpoint as non-final if
another validation is authoritative.
- Around line 32-38: Update the Native SDK setup instructions in the macOS
memory handoff to check out commit 6a8e6178 in detached mode instead of
following the mutable macos-memory-shared-renderer-prep branch, preserving the
existing repository and submodule setup steps.
- Around line 498-505: Update the Phase 1 paragraph so it no longer says the
gates are unchanged or predicts a 20s–30s MB widget process. Make acceptance
depend on retaining approximately zero graphics ledger, consistent with the
Phase 1 gate, and describe total footprint as a hardware-specific measurement
rather than a fixed estimate.

In `@docs/receipt-sweep-brief.md`:
- Around line 140-142: Update the acceptance-check command in the receipt-sweep
brief to reuse the complete inventory patterns, including _cap, Limit, and
camelCase max names, across runtime, CLI, and SDK sources. Add the SDK
soft-limit sweep and validate for every discovered definition that an adjacent
receipt or protocol/OS-bound comment exists at the definition site, rather than
only counting matching names.
- Around line 107-120: Update the “Mirrored constants” section to list the CLI
image-budget constants maxImageStreamBytes, nativeImagePixelByteLimit, and
nativeWidgetSourceByteLimit alongside their runtime counterparts, including
max_image_stream_bytes and max_image_rgba_bytes from runtime/src/main.zig.
Ensure the acceptance check explicitly covers runtime/src/main.zig while
preserving the existing node and depth mirror entries.

In `@myclock/tsconfig.json`:
- Around line 12-20: Resolve the committed myclock scratch workspace by either
moving it under examples/ as a proper example or removing it from the PR. For
myclock/tsconfig.json lines 12-20, if retained, replace the machine-specific SDK
paths with portable paths relative to baseUrl and match examples/visualizer's
tsconfig pattern; for myclock/widget.tsx lines 1-19, move it under examples/ and
switch its implementation to useProviderSignal if it demonstrates this PR,
otherwise remove it.

In `@runtime/native-sdk`:
- Line 1: Wait for SunkenInTime/native#27 to merge, then update the
runtime/native-sdk submodule pointer from the current PR head to the resulting
merge commit before merging this change.

In `@runtime/src/main.zig`:
- Around line 694-710: Update the canvas loop around canvas_state to iterate
with each slot index, check model.tree.canvas_occupied for that index, and skip
unoccupied slots before reading canvas_state.owner or calling nodeConst.
Preserve the existing handling for occupied canvas slots.
- Around line 687-690: Update the same-view update handling around the msg
switch and projectSameViewUpdate so canvas_generation changes from timer or
provider callbacks are detected and the new command batch is submitted even
without an active frame callback. Preserve the existing behavior for
canvas_frame messages and ensure non-frame setCanvasCommands commits either
trigger the canvas update directly or request a frame.

In `@scripts/macos-audio-cost.py`:
- Around line 201-203: Validate visualizer_source before applying the two
replacements in the installation flow: require exactly one occurrence each of
the Visualizer name marker and the offset marker. If either count is not one,
fail with the selected revision, the missing or invalid marker, and remediation
to use a compatible revision or update the source markers; only proceed with
replacement after both validations pass.

In `@sdk/src/reconciler.ts`:
- Around line 1182-1185: Update emit in the signal implementation to invoke
every listener through runWidgetCallback, ensuring one throwing listener does
not stop subsequent listeners and errors are handled consistently. Iterate over
a snapshot of listeners so subscription changes during emission do not alter the
current dispatch.
- Around line 517-529: Update the static `<text>` handling in the reconciler to
filter `vnode.children` with `isRenderable` before mapping them to strings,
allowing conditional `false`, `null`, and `undefined` children. Keep rejecting
other non-string/non-number children, and include `received ${typeof child}` in
that validation error.

---

Minor comments:
In `@docs/error-propagation-brief.md`:
- Around line 74-80: Update the image-limit section to document the pinned
Native revision’s 1 MiB decoded-RGBA limit, correct the 256×256 RGBA calculation
to 262,144 bytes (256 KiB) and state that it passes. Clarify that weaver check
parses local dimensions and reports decoded-byte calculations without decoding
pixels, while runtime failures report dimensions and requested bytes; restrict
downscale and placeholder guidance to images exceeding 1 MiB.

In `@docs/macos-memory-handoff.md`:
- Around line 525-530: Fix the command example around the macOS renderer bakeoff
invocation by moving the “or: software” explanation before the command or after
the completed command, and ensure every line-continuation backslash remains the
final character on its line.

In `@docs/receipt-sweep-brief.md`:
- Around line 37-39: Specify the shell language on the fenced code block
containing the rg command by changing its opening fence to use sh, while leaving
the command unchanged.
- Line 84: Update the receipt status entry for max_images and
max_image_load_attempts in the documentation to remove them from the unreceipted
list, since runtime/src/main.zig already contains receipt comments; move the
entries to the receipted list or retain only any genuinely outstanding
verification work.

In `@myclock/widget.tsx`:
- Around line 1-19: Remove the standalone myclock widget from the PR, or
relocate it under examples/myclock/ with the corresponding configuration updates
if it is intended as a shipped example; do not retain it as a machine-specific
scratch workspace outside examples. If kept, update the widget to use
useProviderSignal so it exercises the provider-signals feature.

In `@runtime/src/tree.zig`:
- Line 256: Preserve canvas_generation across transaction snapshots: update
cloneInto to copy the source canvas_generation, initialize canvas_generation in
resetEmpty, and add a batch-abort test covering canvas revision restoration
through beginBatch and abortBatch.

In `@sdk/test/reconciler.test.mjs`:
- Around line 324-329: In the test around context.hideText(), positively verify
that the rendered text node has been replaced by the <panel> element before
capturing textWritesAfterUnmount. Keep awaiting the scheduler as needed, then
assert the swap using the existing fixture/render state symbols before
establishing the baseline and continuing with the provider callback assertions.

---

Nitpick comments:
In `@cli/src/index.ts`:
- Around line 1529-1530: Derive the runtime provider iteration in the visitor
around usedProviders from the single ProviderName source instead of repeating
the five provider literals, keeping the type and runtime list synchronized when
providers change. Update the unknown-provider handling so unsupported literal
names are reported with an actionable error identifying the invalid provider and
expected providers, rather than being silently skipped.

In `@cli/test/cli.test.mjs`:
- Around line 186-190: Extend the CLI test fixture around
missingSignalSubscription so it includes both useProvider("memory") and
useProviderSignal("memory") without the memory subscription, then assert that
stderr contains the distinct missing-subscription error for each hook. Preserve
the existing exit-status assertion and ensure both messages are checked.

In `@docs/gpu-ledger-wall-brief.md`:
- Around line 46-51: Update the “Software-candidate discriminator” procedure in
gpu-ledger-wall-brief.md to replace the instruction to find the forcing
mechanism with the exact existing switch WEAVER_FORCE_SOFTWARE=1 and the command
used by scripts/macos-renderer-bakeoff.py. Preserve the software-candidate
measurement and comparison steps.

In `@examples/visualizer/widget.tsx`:
- Around line 100-103: Update the RMS strip drawing loop in the widget rendering
logic to use the same centered horizontal offset as the bar meter’s meterX
calculation, so its geometry remains aligned across varying canvas widths;
preserve the existing segment colors and dimensions.

In `@scripts/macos-audio-cost.py`:
- Around line 80-85: Update the CPU sampling flow around process_cpu_time so
each boundary performs one ps invocation covering all widget, host, and
WindowServer PIDs, then records the timestamp immediately adjacent to that
snapshot. Derive cpu_before, cpu_after, window_server_cpu_before, and
window_server_cpu_after from the corresponding shared snapshots so every delta
uses aligned measurement intervals.

In `@sdk/CONTRACT.md`:
- Around line 98-108: Update the CONTRACT.md documentation near the existing
useProvider weaver check error to also record the exact useProviderSignal error
form, including the provider name placeholder and required subscribe
configuration. Keep both messages available for agents to match.

In `@sdk/index.d.ts`:
- Around line 37-41: Remove the duplicated hand-maintained Signal and
useProviderSignal declarations from sdk/index.d.ts by generating them from the
corresponding declarations in sdk/src/reconciler.ts, or add an automated test
that compares both Signal shapes and every provider overload to prevent drift.

In `@sdk/src/reconciler.ts`:
- Around line 677-690: Document in sdk/CONTRACT.md that mapped signals used as
<text> children should be created once and reused, such as by storing them with
useRef or memoizing map results per source-and-projector pair, so bindHostText
does not repeatedly unsubscribe and resubscribe when renders produce fresh
mapped signal objects.

In `@sdk/test/reconciler.test.mjs`:
- Around line 279-291: Add tests in sdk/test/reconciler.test.mjs covering each
new developer-facing validation path: bound text with zero or multiple Signal
children, invalid non-string/number/non-Signal text children, and non-function
arguments to Signal.subscribe and Signal.map. Assert the exact public error
strings, including “A bound <text> must contain exactly one Signal child”,
“<text> children must be strings, numbers, or one Signal”,
“Signal.subscribe(listener) requires a function”, and “Signal.map(project)
requires a function”.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a9a005e9-6002-46ce-8916-ae2e6e43b6d9

📥 Commits

Reviewing files that changed from the base of the PR and between 9a79a3d and e6adc6b.

⛔ Files ignored due to path filters (2)
  • myclock/dist/bundle.js is excluded by !**/dist/**
  • myclock/dist/widget.json is excluded by !**/dist/**
📒 Files selected for processing (23)
  • cli/src/index.ts
  • cli/test/cli.test.mjs
  • docs/error-propagation-brief.md
  • docs/gpu-ledger-session-2026-07-30.md
  • docs/gpu-ledger-wall-brief.md
  • docs/macos-memory-handoff.md
  • docs/macos-visualizer-perf-2026-07-31.md
  • docs/receipt-sweep-brief.md
  • examples/visualizer/widget.tsx
  • myclock/tsconfig.json
  • myclock/widget.tsx
  • runtime/build.zig
  • runtime/native-sdk
  • runtime/src/js_engine.zig
  • runtime/src/main.zig
  • runtime/src/tree.zig
  • scripts/macos-audio-cost.py
  • scripts/release-audit.mjs
  • sdk/CONTRACT.md
  • sdk/index.d.ts
  • sdk/src/index.ts
  • sdk/src/reconciler.ts
  • sdk/test/reconciler.test.mjs

Comment thread docs/error-propagation-brief.md Outdated
Comment thread docs/error-propagation-brief.md Outdated
Comment thread docs/error-propagation-brief.md Outdated
Comment thread docs/gpu-ledger-session-2026-07-30.md Outdated
Comment thread docs/gpu-ledger-session-2026-07-30.md Outdated
Comment thread runtime/src/main.zig
Comment thread runtime/src/main.zig Outdated
Comment thread scripts/macos-audio-cost.py Outdated
Comment thread sdk/src/reconciler.ts
Comment thread sdk/src/reconciler.ts
@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Greptile Summary

This change repins the Native SDK to the visualizer rendering merge and updates the release audit to require that exact revision.

The Native SDK integration path was exercised successfully: npm run audit:release accepted the 4c5c0999 pin, focused SDK/reconciler/CLI tests passed 26/26, TypeScript typechecking passed, and the CLI build completed successfully. No defects were found.

T-Rex validation blocked

Direct Native runtime build and test execution could not run because the required Zig tool is missing from this Linux environment (zig: not found). macOS-specific Canvas and host rendering execution also requires a macOS environment.

Confidence Score: 5/5

The PR is safe to merge; no blocking failure remains in the executable integration paths.

The release audit, focused SDK/reconciler/CLI contract tests, TypeScript typecheck, and CLI build all completed successfully with the new Native SDK pin. Native runtime rendering could not be compiled in this environment because Zig and macOS rendering support are unavailable.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the release audit and confirmed the Native SDK pin is 4c5c0999 with no platform or private API leaked into the SDK.
  • Executed focused SDK reconciler, CLI contract tests, TypeScript typechecking, and the CLI build; all tests completed successfully, including 26 passing focused tests.
  • Verified that the pin change updates the Native SDK revision from ad6172a to 4c5c099 and that the release audit checks this exact revision and the outer-runtime contract.
  • Attempted the direct Zig runtime test gate but could not start because the Zig tool is not installed.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (7): Last reviewed commit: "Repin Native SDK after visualizer merge" | Re-trigger Greptile

Comment thread runtime/src/main.zig

Copy link
Copy Markdown
Owner Author

@greptileai

Copy link
Copy Markdown
Owner Author

@greptileai

Comment thread runtime/src/main.zig Outdated
@SunkenInTime

Copy link
Copy Markdown
Owner Author

@greptileai

Copy link
Copy Markdown
Owner Author

Addressed the CodeRabbit review in 4eeda31.

  • fixed all valid implementation, test, measurement-harness, example-layout, and documentation findings
  • moved the root Myclock scratch fixture to examples/myclock with portable config and provider signals
  • resolved the non-frame Canvas claim as not applicable after tracing and executing the timer/provider rebuild path
  • intentionally kept the Native pointer thread open as a merge-order tripwire until Native styling 09: add overlay stacks and bounded overflow #27 merges

Validation: npm run build, 82/82 npm test, npm run typecheck, both example checks, runtime zig build test, runtime ReleaseFast, Python compile/focused helper checks, and npm run audit:release all pass.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Owner Author

@greptileai

@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 `@docs/macos-memory-handoff.md`:
- Around line 496-501: Update the earlier Phase 1 acceptance gate in the macOS
memory handoff document to remove the conflicting 20s–30s widget-footprint
requirement. Align it with the ledger_tag_graphics_footprint-near-zero criterion
used in the later Phase 1 text, or explicitly mark the legacy gate as superseded
while preserving separate reporting of hardware-specific content cost.
- Around line 521-525: Align the comment immediately above the macOS renderer
bakeoff command with the actual --candidate value, ensuring both identify the
same benchmark; if this is intended to be the software comparison, update the
command to use software, otherwise revise the comment to describe
metal-composite.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d2281fb-94cf-425c-8fb8-ac8dd7fdd502

📥 Commits

Reviewing files that changed from the base of the PR and between 8ce15dc and 4eeda31.

📒 Files selected for processing (17)
  • cli/src/index.ts
  • cli/test/cli.test.mjs
  • docs/error-propagation-brief.md
  • docs/gpu-ledger-session-2026-07-30.md
  • docs/gpu-ledger-wall-brief.md
  • docs/macos-memory-handoff.md
  • docs/receipt-sweep-brief.md
  • examples/myclock/tsconfig.json
  • examples/myclock/widget.tsx
  • examples/visualizer/widget.tsx
  • runtime/src/main.zig
  • runtime/src/tree.zig
  • scripts/macos-audio-cost.py
  • sdk/CONTRACT.md
  • sdk/src/reconciler.ts
  • sdk/test/contract-tables.test.mjs
  • sdk/test/reconciler.test.mjs
🚧 Files skipped from review as they are similar to previous changes (11)
  • cli/test/cli.test.mjs
  • docs/gpu-ledger-session-2026-07-30.md
  • runtime/src/tree.zig
  • docs/receipt-sweep-brief.md
  • sdk/CONTRACT.md
  • docs/error-propagation-brief.md
  • examples/visualizer/widget.tsx
  • runtime/src/main.zig
  • scripts/macos-audio-cost.py
  • sdk/src/reconciler.ts
  • docs/gpu-ledger-wall-brief.md

Comment thread docs/macos-memory-handoff.md
Comment thread docs/macos-memory-handoff.md

Copy link
Copy Markdown
Owner Author

@greptileai

Copy link
Copy Markdown
Owner Author

@greptileai

@SunkenInTime
SunkenInTime marked this pull request as ready for review August 3, 2026 07:32
@SunkenInTime
SunkenInTime merged commit 4a1f064 into master Aug 3, 2026
6 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.

1 participant