From 3214fffa2be7f53bdbedd92eb87bba86bdd2c41c Mon Sep 17 00:00:00 2001 From: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:26:37 -0400 Subject: [PATCH 1/2] examples: consolidate to the shipped set, move measurement widgets to fixtures Shipped examples are now clock, system, pomodoro, now-playing, weather, noro-shell, noro-signal, and visualizer, each a complete widget in the house style. The styling-* showcases, dpi-diagnostic, gradient-stack, m4b-*, and tideglass move to test/fixtures where the tests and measurement scripts that drive them live; myclock and retro-player-shell are gone. The conjure skill moves to .agents/skills with a .claude/skills mirror, README gains an examples table, and capture-smoke covers system, now-playing, and weather with provider fixtures. Co-Authored-By: Claude Fable 5.1 --- .../skills}/conjure-widget/SKILL.md | 24 +- .../skills}/conjure-widget/agents/openai.yaml | 0 .claude/skills/conjure-widget/SKILL.md | 135 ++ .../skills/conjure-widget/agents/openai.yaml | 4 + README.md | 27 +- cli/test/example-surface-smoke.mjs | 37 +- docs/agent-widget-capture.md | 2 +- docs/dpi-scaling.md | 2 +- docs/media-v2-results.md | 2 +- examples/clock/bundle.js | 52 - examples/clock/widget.json | 8 - examples/clock/widget.tsx | 76 +- examples/gradient-stack/tsconfig.json | 17 - examples/myclock/tsconfig.json | 12 - examples/myclock/widget.tsx | 34 - examples/now-playing/widget.tsx | 133 +- examples/pomodoro/widget.tsx | 148 ++- .../retro-player-shell/GeistPixel-Square.ttf | Bin 94800 -> 0 bytes examples/retro-player-shell/OFL.txt | 93 -- examples/retro-player-shell/assets/grille.png | Bin 53383 -> 0 bytes .../retro-player-shell/assets/night-bloom.jpg | Bin 13574 -> 0 bytes examples/retro-player-shell/widget.tsx | 69 -- examples/styling-fonts/GeistPixel-Square.ttf | Bin 94800 -> 0 bytes examples/styling-fonts/OFL.txt | 93 -- examples/styling-fonts/widget.tsx | 17 - examples/styling-icons/widget.tsx | 44 - examples/styling-interaction/tsconfig.json | 17 - examples/styling-shadows/widget.tsx | 19 - examples/styling-spacing/tsconfig.json | 19 - examples/styling-spacing/widget.tsx | 23 - examples/styling-stack/tsconfig.json | 17 - examples/styling-stack/widget.tsx | 24 - examples/styling-text/tsconfig.json | 19 - examples/system/widget.tsx | 101 +- .../{styling-fonts => weather}/tsconfig.json | 0 examples/weather/widget.tsx | 208 ++++ scripts/verify-dpi.ps1 | 2 +- scripts/verify-gradient-gpu.ps1 | 2 +- sdk/CONTRACT.md | 2 +- test/capture-smoke.mjs | 35 +- test/capture/media-stopped.provider.json | 18 + test/capture/system.provider.json | 1093 +++++++++++++++++ .../fixtures/dpi-diagnostic}/tsconfig.json | 2 +- .../fixtures}/dpi-diagnostic/widget.tsx | 0 .../fixtures/gradient-stack}/tsconfig.json | 4 +- .../fixtures}/gradient-stack/widget.tsx | 0 .../fixtures/m4b-parity}/tsconfig.json | 2 +- .../fixtures}/m4b-parity/widget.tsx | 0 .../fixtures}/m4b-synthetic/tsconfig.json | 0 .../fixtures}/m4b-synthetic/widget.tsx | 0 .../styling-images/assets/weaver.png | Bin .../fixtures}/styling-images/tsconfig.json | 4 +- .../fixtures}/styling-images/widget.tsx | 0 .../styling-interaction}/tsconfig.json | 4 +- .../fixtures}/styling-interaction/widget.tsx | 0 .../fixtures/styling-text}/tsconfig.json | 4 +- .../fixtures}/styling-text/widget.tsx | 0 .../fixtures}/tideglass/tsconfig.json | 4 +- .../fixtures}/tideglass/widget.tsx | 0 59 files changed, 1920 insertions(+), 732 deletions(-) rename {skills => .agents/skills}/conjure-widget/SKILL.md (83%) rename {skills => .agents/skills}/conjure-widget/agents/openai.yaml (100%) create mode 100644 .claude/skills/conjure-widget/SKILL.md create mode 100644 .claude/skills/conjure-widget/agents/openai.yaml delete mode 100644 examples/clock/bundle.js delete mode 100644 examples/clock/widget.json delete mode 100644 examples/gradient-stack/tsconfig.json delete mode 100644 examples/myclock/tsconfig.json delete mode 100644 examples/myclock/widget.tsx delete mode 100644 examples/retro-player-shell/GeistPixel-Square.ttf delete mode 100644 examples/retro-player-shell/OFL.txt delete mode 100644 examples/retro-player-shell/assets/grille.png delete mode 100644 examples/retro-player-shell/assets/night-bloom.jpg delete mode 100644 examples/retro-player-shell/widget.tsx delete mode 100644 examples/styling-fonts/GeistPixel-Square.ttf delete mode 100644 examples/styling-fonts/OFL.txt delete mode 100644 examples/styling-fonts/widget.tsx delete mode 100644 examples/styling-icons/widget.tsx delete mode 100644 examples/styling-interaction/tsconfig.json delete mode 100644 examples/styling-shadows/widget.tsx delete mode 100644 examples/styling-spacing/tsconfig.json delete mode 100644 examples/styling-spacing/widget.tsx delete mode 100644 examples/styling-stack/tsconfig.json delete mode 100644 examples/styling-stack/widget.tsx delete mode 100644 examples/styling-text/tsconfig.json rename examples/{styling-fonts => weather}/tsconfig.json (100%) create mode 100644 examples/weather/widget.tsx create mode 100644 test/capture/media-stopped.provider.json create mode 100644 test/capture/system.provider.json rename {examples/m4b-parity => test/fixtures/dpi-diagnostic}/tsconfig.json (73%) rename {examples => test/fixtures}/dpi-diagnostic/widget.tsx (100%) rename {examples/retro-player-shell => test/fixtures/gradient-stack}/tsconfig.json (70%) rename {examples => test/fixtures}/gradient-stack/widget.tsx (100%) rename {examples/dpi-diagnostic => test/fixtures/m4b-parity}/tsconfig.json (73%) rename {examples => test/fixtures}/m4b-parity/widget.tsx (100%) rename {examples => test/fixtures}/m4b-synthetic/tsconfig.json (100%) rename {examples => test/fixtures}/m4b-synthetic/widget.tsx (100%) rename {examples => test/fixtures}/styling-images/assets/weaver.png (100%) rename {examples => test/fixtures}/styling-images/tsconfig.json (70%) rename {examples => test/fixtures}/styling-images/widget.tsx (100%) rename {examples/styling-icons => test/fixtures/styling-interaction}/tsconfig.json (70%) rename {examples => test/fixtures}/styling-interaction/widget.tsx (100%) rename {examples/styling-shadows => test/fixtures/styling-text}/tsconfig.json (73%) rename {examples => test/fixtures}/styling-text/widget.tsx (100%) rename {examples => test/fixtures}/tideglass/tsconfig.json (74%) rename {examples => test/fixtures}/tideglass/widget.tsx (100%) diff --git a/skills/conjure-widget/SKILL.md b/.agents/skills/conjure-widget/SKILL.md similarity index 83% rename from skills/conjure-widget/SKILL.md rename to .agents/skills/conjure-widget/SKILL.md index 2e81f023..0d2d78bd 100644 --- a/skills/conjure-widget/SKILL.md +++ b/.agents/skills/conjure-widget/SKILL.md @@ -24,7 +24,7 @@ honest. Report any part Weaver does not support as a boundary. 2. Read the relevant current sections under **Contract routing** before choosing elements, hooks, providers, classes, assets, network access, or capabilities. When the request uses interaction, changing time, provider data, or replay, - read [`docs/agent-widget-capture.md`](../../docs/agent-widget-capture.md) now. + read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now. Define stable capture inputs and a name for each state the request needs so every pass renders the same evidence. 3. Start the **Live loop** before the first source edit. Run @@ -81,7 +81,7 @@ For each defined state: ## Contract routing -[`sdk/CONTRACT.md`](../../sdk/CONTRACT.md) is authoritative and chronological; +[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological; later amendments supersede earlier scheduling notes. Read only the headings the widget needs: @@ -100,6 +100,26 @@ widget needs: a number only for an intentional fixed cadence, and `0` once animation settles. +Read the shipped example closest to the request before writing the first +element; they are the house style and each one proves one slice of the +contract on the current runtime: + +- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider, + layered gradient surface, a canvas that redraws once per render. +- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory` + providers, provider history in an effect, canvas charts with explicit sizes. +- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`, + `useInterval`, buttons with `hover:`/`pressed:` states, centered labels. +- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media` + provider, conditional artwork, transport capability, click-to-seek. +- [`examples/weather`](../../../examples/weather/widget.tsx): declared + `origins`, `wfetch` with honest loading and failure states, literal icons + chosen per branch. +- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and + [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled + fonts, tiled image assets, and an `audio` signal driving a display-rate + canvas. + Use `weaver check` as the final authority for statically knowable widget errors. Do not infer browser DOM, CSS, package, or network behavior that the contract does not provide. diff --git a/skills/conjure-widget/agents/openai.yaml b/.agents/skills/conjure-widget/agents/openai.yaml similarity index 100% rename from skills/conjure-widget/agents/openai.yaml rename to .agents/skills/conjure-widget/agents/openai.yaml diff --git a/.claude/skills/conjure-widget/SKILL.md b/.claude/skills/conjure-widget/SKILL.md new file mode 100644 index 00000000..0d2d78bd --- /dev/null +++ b/.claude/skills/conjure-widget/SKILL.md @@ -0,0 +1,135 @@ +--- +name: conjure-widget +description: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows. +--- + +# Conjure a Weaver widget + +Turn the request into one checked and captured widget while the user watches it +take shape on the desktop. Start the **Live loop** before the first source edit. +Its audience is the user. It keeps `weaver dev` running in the background so +each valid save can appear while the next edit is underway. Use the **Render +loop** for the agent's deterministic inspection and interaction proof. Get the +first coherent tree on screen early, then inspect each capture while changing +the code. Preserve the requested visual and interaction intent. Keep the widget +honest. Report any part Weaver does not support as a boundary. + +## Workflow + +1. Inspect the target before editing. For a new widget, run + `npx --no-install weaver init ` from the Weaver repository root; the + final path segment becomes the starter display name. For an existing widget, + read its `widget.tsx`, local modules, assets, and licenses without running + `init` over it. +2. Read the relevant current sections under **Contract routing** before choosing + elements, hooks, providers, classes, assets, network access, or capabilities. + When the request uses interaction, changing time, provider data, or replay, + read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now. + Define stable capture inputs and a name for each state the request needs so + every pass renders the same evidence. +3. Start the **Live loop** before the first source edit. Run + `npx --no-install weaver dev ` in a long-lived background session and + keep its output available and its widget visible to the user. Return to + authoring once the command reports that it is watching. Keep observing the + Live loop for the next 10 seconds while authoring continues. Report the + user-facing live view as available only if that interval ends without a + `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can + finish while later edits continue. If the current platform cannot run + Weaver's desktop host or presentation health fails, record the exact failure, + use the Render loop, and report the user-facing live view as unavailable. +4. Build the first coherent visual slice in `/widget.tsx` with one literal + default export: + `export default widget({ ... }, () => <... />);`. Import Weaver APIs from + `@weaver/sdk`; keep other modules, assets, and their licenses inside the + widget source root. +5. Enter the **Render loop** as soon as that slice can render. Run it before + building the rest of the widget, then after each edit that can change pixels, + semantics, or interaction behavior. No such edit is complete until its PNG + has been opened and inspected. +6. After the final source save, keep the **Live loop** running until it reports + that save through `weaver dev bundle ready for in-place hot swap` or + `weaver dev restarted widget: window config changed`. An `OUT OF DATE` + message keeps this step open until the source is fixed and `weaver dev` + reports that it caught up. Then keep the process running when the user wants + the final widget left open. Otherwise, stop it. Use Render loop artifacts for + every visual, semantic, and interaction receipt. +7. Report the widget path, captured images, behavior exercised, receipt evidence, + whether the user-facing live view ran or its exact failure, and each remaining + boundary. Completion requires the requested result, not merely successful + commands. + +## Render loop + +For each defined state: + +1. Run `npx --no-install weaver check ` until it exits successfully. Fix + every named widget error. Preserve unsupported intent as a reported boundary + rather than suppressing unknown utilities, undeclared providers or origins, + invalid assets, or import failures. +2. Run `npx --no-install weaver capture --out .png` with the + state's fixed clock, semantic actions, provider fixture, or session journal. +3. Open the PNG with the available image-viewing tool. File creation and a green + receipt are not visual proof. Inspect layout, overlap, clipping, duplication, + spacing, alignment, contrast, assets, and the requested state at the actual + widget dimensions. +4. Inspect `.snapshot.txt` and `.receipt.json`. The + receipt must have `status: "ok"`; the semantic tree must expose the intended + content and controls; every warning and pending item must be understood. +5. Compare the rendered state with the request. Fix the visible and semantic + mismatches found in that pass, then restart the loop. For interactions, prove + both the initial state and every requested post-action state. + +## Contract routing + +[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological; +later amendments supersede earlier scheduling notes. Read only the headings the +widget needs: + +- For module shape, literal config, hooks, and reload behavior, read **Module + shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**. +- For the current element and class set, read **Consolidated v0.4 authoring + tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment + when those branches apply. +- For buttons, sliders, press coordinates, or interaction styles, read **PR 11: + native interaction states and press events**. Use native `hover:` and + `pressed:` classes for visual feedback instead of rendering pointer state + through JavaScript. +- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas, + audio, media observation, artwork, or transport, read the matching M3 or + **Media v2 amendment** heading. Use `fps="display"` for fluid canvas motion, + a number only for an intentional fixed cadence, and `0` once animation + settles. + +Read the shipped example closest to the request before writing the first +element; they are the house style and each one proves one slice of the +contract on the current runtime: + +- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider, + layered gradient surface, a canvas that redraws once per render. +- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory` + providers, provider history in an effect, canvas charts with explicit sizes. +- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`, + `useInterval`, buttons with `hover:`/`pressed:` states, centered labels. +- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media` + provider, conditional artwork, transport capability, click-to-seek. +- [`examples/weather`](../../../examples/weather/widget.tsx): declared + `origins`, `wfetch` with honest loading and failure states, literal icons + chosen per branch. +- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and + [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled + fonts, tiled image assets, and an `audio` signal driving a display-rate + canvas. + +Use `weaver check` as the final authority for statically knowable widget errors. +Do not infer browser DOM, CSS, package, or network behavior that the contract +does not provide. + +## Framework failures + +A documented unsupported behavior is a widget boundary. A minimized supported +widget that still fails is a framework reproduction. So is invalid widget input +that produces an opaque or internal error instead of an actionable diagnostic. +Preserve the widget, exact command, complete output, and platform. Inside the +Weaver source checkout, follow the root instructions for framework friction. +Outside it, report the reproduction and blocker without weakening the widget or +claiming completion. diff --git a/.claude/skills/conjure-widget/agents/openai.yaml b/.claude/skills/conjure-widget/agents/openai.yaml new file mode 100644 index 00000000..6a4cea7a --- /dev/null +++ b/.claude/skills/conjure-widget/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Conjure Widget" + short_description: "Create or change a Weaver desktop widget" + default_prompt: "Use $conjure-widget to make me a desktop widget." diff --git a/README.md b/README.md index 38a18418..8b673ed4 100644 --- a/README.md +++ b/README.md @@ -216,9 +216,32 @@ See [`macos-m12-results.md`](docs/macos-m12-results.md) and the live blockers. Or do it the intended way: point your coding agent at -[`skills/conjure-widget/SKILL.md`](skills/conjure-widget/SKILL.md) and ask it +[`.agents/skills/conjure-widget/SKILL.md`](.agents/skills/conjure-widget/SKILL.md) and ask it for the widget you actually want. +## Examples + +Each directory under [`examples/`](examples) is one complete widget that +checks and captures on the current runtime. They are the house style, and the +first thing an agent should read before conjuring something similar. + +| Example | Shows | +|---|---| +| [`clock`](examples/clock/widget.tsx) | the `time` provider, a layered gradient surface, a canvas dial that redraws once per render | +| [`system`](examples/system/widget.tsx) | `cpu` and `memory` providers, a minute of history kept in an effect, canvas charts | +| [`pomodoro`](examples/pomodoro/widget.tsx) | `useStorage`, `useInterval`, buttons with native `hover:` and `pressed:` states | +| [`now-playing`](examples/now-playing/widget.tsx) | the `media` provider, conditional artwork, `media-transport`, click-to-seek | +| [`weather`](examples/weather/widget.tsx) | declared `origins` and `wfetch` against Open-Meteo, with honest loading and failure states | +| [`noro-shell`](examples/noro-shell/widget.tsx), [`noro-signal`](examples/noro-signal/widget.tsx) | pixel-faithful media skins: bundled fonts, tiled image assets, transport | +| [`visualizer`](examples/visualizer/widget.tsx) | the `audio` signal driving a display-rate canvas that sleeps on silence | + +Render any of them without a desktop session: + +```sh +node cli/bin/weaver.js capture examples/system \ + --provider-fixture test/capture/system.provider.json --out /tmp/system.png +``` + ## How it's put together | Path | What | @@ -226,7 +249,7 @@ for the widget you actually want. | `runtime/` | `weaver-widget[.exe]` — Zig, embeds QuickJS-NG, renders via the Native SDK fork (submodule `runtime/native-sdk`) | | `sdk/` | `@weaver/sdk` — the authoring API: reconciler, hooks, class compiler. Contract frozen in [`sdk/CONTRACT.md`](sdk/CONTRACT.md) | | `cli/` | `weaver` — init / check / bundle / capture / dev / pack / inspect / install / uninstall / logs | -| `skills/` | agent skills (conjuring is the primary authoring path) | +| `.agents/skills/` | agent skills, mirrored in `.claude/skills/` (conjuring is the primary authoring path) | | `docs/adr/` | why things are the way they are — start here to understand the project | | `CONTEXT.md` | the domain glossary | diff --git a/cli/test/example-surface-smoke.mjs b/cli/test/example-surface-smoke.mjs index e8e48ab7..1bb21da2 100644 --- a/cli/test/example-surface-smoke.mjs +++ b/cli/test/example-surface-smoke.mjs @@ -6,29 +6,34 @@ import { fileURLToPath } from "node:url"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); const cli = join(repoRoot, "cli", "bin", "weaver.js"); -const fixtures = [ - "clock", - "pomodoro", - "system", - "now-playing", - "noro-shell", - "visualizer", - "dpi-diagnostic", - "m4b-parity", - "m4b-synthetic", +// Every shipped example plus the measurement fixtures that scripts/ and docs/ +// still drive. Each must check and bundle on a clean checkout. +const surfaces = [ + "examples/clock", + "examples/system", + "examples/pomodoro", + "examples/now-playing", + "examples/weather", + "examples/noro-shell", + "examples/noro-signal", + "examples/visualizer", + "test/fixtures/dpi-diagnostic", + "test/fixtures/m4b-parity", + "test/fixtures/m4b-synthetic", + "test/fixtures/gradient-stack", ]; -for (const fixture of fixtures) { - const source = join(repoRoot, "examples", fixture); +for (const surface of surfaces) { + const source = join(repoRoot, surface); const dist = join(source, "dist"); const distExisted = existsSync(dist); for (const command of ["check", "bundle"]) { const result = spawnSync(process.execPath, [cli, command, source], { cwd: repoRoot, encoding: "utf8" }); - assert.equal(result.status, 0, `${command} failed for ${fixture}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`); + assert.equal(result.status, 0, `${command} failed for ${surface}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`); } - assert.equal(existsSync(join(dist, "bundle.js")), true, `${fixture} bundle is missing`); - assert.equal(existsSync(join(dist, "widget.json")), true, `${fixture} manifest is missing`); + assert.equal(existsSync(join(dist, "bundle.js")), true, `${surface} bundle is missing`); + assert.equal(existsSync(join(dist, "widget.json")), true, `${surface} manifest is missing`); if (!distExisted) rmSync(dist, { recursive: true, force: true }); } -process.stdout.write(`Checked and bundled ${fixtures.length} portable example surfaces.\n`); +process.stdout.write(`Checked and bundled ${surfaces.length} portable widget surfaces.\n`); diff --git a/docs/agent-widget-capture.md b/docs/agent-widget-capture.md index 809e0a13..dbe2f981 100644 --- a/docs/agent-widget-capture.md +++ b/docs/agent-widget-capture.md @@ -77,7 +77,7 @@ node cli/bin/weaver.js capture examples/pomodoro \ --action-file test/capture/pomodoro.actions \ --out /tmp/pomodoro.png -node cli/bin/weaver.js capture examples/styling-interaction \ +node cli/bin/weaver.js capture test/fixtures/styling-interaction \ --action-file test/capture/styling-interaction.actions \ --out /tmp/styling-interaction.png ``` diff --git a/docs/dpi-scaling.md b/docs/dpi-scaling.md index d68a700e..30c00d34 100644 --- a/docs/dpi-scaling.md +++ b/docs/dpi-scaling.md @@ -140,7 +140,7 @@ clean version-mismatch failure instead of framing deadlock. ## Deterministic and live verification -`examples/dpi-diagnostic` is a transparent 480 x 320 DIP fixture with a +`test/fixtures/dpi-diagnostic` is a transparent 480 x 320 DIP fixture with a retained card, immediate canvas, four colored edge markers and corners, content crossing the retained/immediate seam, and right/bottom clickable targets. `scripts/verify-dpi.ps1` launches the real host, widget runtime, named pipe, diff --git a/docs/media-v2-results.md b/docs/media-v2-results.md index ad7b07a6..19a9433e 100644 --- a/docs/media-v2-results.md +++ b/docs/media-v2-results.md @@ -80,7 +80,7 @@ The Windows slice is complete through the noro gate: - Existing previous, play/pause, and next buttons deliver real SMTC commands. - The former static 312x3 progress stack is a pixel-matched click-to-seek button using the press event's normalized local `event.u`. -- `skills/conjure-widget/SKILL.md` teaches `MediaData.artPath`, +- `.agents/skills/conjure-widget/SKILL.md` teaches `MediaData.artPath`, `useMediaTransport`, the `media-transport` capability, and promise semantics. The full viewed visual checklist and capture inventory are in diff --git a/examples/clock/bundle.js b/examples/clock/bundle.js deleted file mode 100644 index de3b075e..00000000 --- a/examples/clock/bundle.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; - -const card = native.createNode("panel"); -native.setProp(card, "padding", 14); -native.setProp(card, "radius", 18); -native.setProp(card, "background", "#11141cdb"); - -const content = native.createNode("column"); -native.setProp(content, "gap", 1); - -const timeRow = native.createNode("row"); -native.setProp(timeRow, "gap", 7); - -const hoursMinutes = native.createNode("text"); -native.setProp(hoursMinutes, "fontScale", 2.2); -native.setProp(hoursMinutes, "fontWeight", "medium"); - -const seconds = native.createNode("text"); -native.setProp(seconds, "fontScale", 1.05); -native.setProp(seconds, "fontWeight", "medium"); -native.setProp(seconds, "opacity", 0.72); - -const dateLine = native.createNode("text"); -native.setProp(dateLine, "fontScale", 0.84); -native.setProp(dateLine, "opacity", 0.64); - -native.appendChild(timeRow, hoursMinutes); -native.appendChild(timeRow, seconds); -native.appendChild(content, timeRow); -native.appendChild(content, dateLine); -native.appendChild(card, content); -native.setRoot(card); - -function pad2(value) { - return String(value).padStart(2, "0"); -} - -function tick() { - const now = new Date(); - native.setText(hoursMinutes, pad2(now.getHours()) + ":" + pad2(now.getMinutes())); - native.setText(seconds, ":" + pad2(now.getSeconds())); - native.setText(dateLine, now.toLocaleDateString(undefined, { - weekday: "short", - month: "short", - day: "numeric" - })); -} - -tick(); -native.setInterval(1000); -native.onTimer(tick); -native.log("clock mounted"); diff --git a/examples/clock/widget.json b/examples/clock/widget.json deleted file mode 100644 index 8114aa5d..00000000 --- a/examples/clock/widget.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Clock", - "size": [240, 110], - "anchor": { "corner": "top-right", "offset": [24, 24] }, - "layer": "desktop", - "transparent": true -} - diff --git a/examples/clock/widget.tsx b/examples/clock/widget.tsx index cb5bb49b..add6eae1 100644 --- a/examples/clock/widget.tsx +++ b/examples/clock/widget.tsx @@ -1,19 +1,77 @@ -import { useProvider, widget } from "@weaver/sdk"; +import { useProvider, widget, type CanvasCtx, type TimeData } from "@weaver/sdk"; + +// The first widget: one provider, one canvas, no timers of its own. +// The `time` provider ticks once per second while subscribed; each tick +// re-renders the text nodes and redraws the dial. Nothing else runs. + +const weekdays: Record = { + Sun: "Sunday", Mon: "Monday", Tue: "Tuesday", Wed: "Wednesday", + Thu: "Thursday", Fri: "Friday", Sat: "Saturday", +}; +const months: Record = { + Jan: "January", Feb: "February", Mar: "March", Apr: "April", May: "May", Jun: "June", + Jul: "July", Aug: "August", Sep: "September", Oct: "October", Nov: "November", Dec: "December", +}; + +function longDate(time: TimeData): string { + return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`; +} + +// Draws a small analog dial. Runs once per render (no `fps`), so it costs +// nothing between provider ticks. +function drawDial(ctx: CanvasCtx, time: TimeData): void { + ctx.clear(); + const cx = ctx.width / 2; + const cy = ctx.height / 2; + const radius = Math.min(cx, cy) - 2; + const hours = Number(time.hh) % 12; + const minutes = Number(time.mm); + const seconds = Number(time.ss); + + for (let index = 0; index < 12; index += 1) { + const angle = (index / 12) * Math.PI * 2 - Math.PI / 2; + const outer = radius; + const inner = index % 3 === 0 ? radius - 7 : radius - 4; + ctx.line( + cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner, + cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer, + index % 3 === 0 ? 2 : 1, index % 3 === 0 ? "#ffffffb3" : "#ffffff4d", + ); + } + + const hand = (turns: number, length: number, width: number, color: string) => { + const angle = turns * Math.PI * 2 - Math.PI / 2; + ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color); + }; + hand((hours + minutes / 60) / 12, radius * 0.52, 3, "#f5f6f8"); + hand((minutes + seconds / 60) / 60, radius * 0.78, 2, "#f5f6f8"); + hand(seconds / 60, radius * 0.86, 1, "#f59e0b"); + ctx.fillCircle(cx, cy, 3, "#f59e0b"); +} export default widget({ name: "Clock", - size: [240, 110], + size: [320, 132], anchor: { corner: "top-right", offset: [24, 24] }, subscribe: ["time"], }, () => { const time = useProvider("time"); return ( - - - {time.hh}:{time.mm} - :{time.ss} - - {time.weekday}, {time.month} {time.day} - + + + + {time.hh}:{time.mm} + {time.ss} + + {longDate(time)} + + drawDial(ctx, time)} /> + ); }); diff --git a/examples/gradient-stack/tsconfig.json b/examples/gradient-stack/tsconfig.json deleted file mode 100644 index fb8488ea..00000000 --- a/examples/gradient-stack/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "baseUrl": ".", - "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] - } - }, - "include": ["widget.tsx"] -} diff --git a/examples/myclock/tsconfig.json b/examples/myclock/tsconfig.json deleted file mode 100644 index bb61204c..00000000 --- a/examples/myclock/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "types": ["@weaver/sdk"] - }, - "include": ["widget.tsx"] -} diff --git a/examples/myclock/widget.tsx b/examples/myclock/widget.tsx deleted file mode 100644 index 878dead7..00000000 --- a/examples/myclock/widget.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useProviderSignal, widget, type TimeData } from "@weaver/sdk"; - -function hourMinute(value: TimeData): string { - return `${value.hh}:${value.mm}`; -} - -function seconds(value: TimeData): string { - return value.ss; -} - -function date(value: TimeData): string { - return `${value.weekday}, ${value.month} ${value.day}`; -} - -export default widget({ - name: "Myclock", - size: [240, 110], - anchor: { corner: "top-right", offset: [24, 24] }, - subscribe: ["time"], -}, () => { - const time = useProviderSignal("time"); - const hourMinuteSignal = time.map(hourMinute); - const secondsSignal = time.map(seconds); - const dateSignal = time.map(date); - return ( - - - {hourMinuteSignal} - {secondsSignal} - - {dateSignal} - - ); -}); diff --git a/examples/now-playing/widget.tsx b/examples/now-playing/widget.tsx index 4711c27d..c8f5921a 100644 --- a/examples/now-playing/widget.tsx +++ b/examples/now-playing/widget.tsx @@ -1,58 +1,105 @@ -import { useMediaTransport, useProvider, widget } from "@weaver/sdk"; +import { useMediaTransport, useProvider, widget, type CanvasCtx } from "@weaver/sdk"; -const segmentCount = 24; +// System media: artwork, metadata, and transport. `media` is change-pushed +// (1 Hz position while playing), so the progress canvas redraws only when a +// frame arrives. Seeking uses the press event's normalized `u` coordinate. + +function timestamp(ms: number): string { + const seconds = Math.max(0, Math.floor(ms / 1000)); + return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`; +} + +function drawProgress(ctx: CanvasCtx, fraction: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff1f"); + const width = Math.max(0, Math.min(1, fraction)) * ctx.width; + if (width > 0) ctx.fillRoundRect(0, 0, Math.max(ctx.height, width), ctx.height, radius, "#f5f6f8"); +} export default widget({ name: "Now Playing", - size: [440, 160], + size: [400, 132], anchor: { corner: "bottom-left", offset: [24, 24] }, - layer: "desktop", subscribe: ["media"], capabilities: ["media-transport"], }, () => { const media = useProvider("media"); const transport = useMediaTransport(); - const progress = media.durationMs > 0 ? Math.max(0, Math.min(1, media.positionMs / media.durationMs)) : 0; - const filled = Math.round(progress * segmentCount); + const playing = media.status === "playing"; + const hasTrack = media.title.length > 0; + const progress = media.durationMs > 0 ? media.positionMs / media.durationMs : 0; + return ( - - - - { - ctx.clear(); - const pulse = media.playing ? 0.72 + Math.sin(frame.t * Math.PI * 2) * 0.18 : 0.45; - ctx.fillCircle(7, 7, 5 * pulse, "#8b5cf6"); - }} - /> - NOW PLAYING - - - - + + {media.artPath - ? - : } - - {media.title || "Nothing playing"} - {media.artist || media.album || (media.title ? "Unknown artist" : "Open a media app to begin")} - {media.sourceApp || "Unknown source"} + ? + : ( + + + + )} + + + + + {hasTrack ? media.title : "Nothing playing"} + {hasTrack ? (media.artist || media.album || "Unknown artist") : "Play something in any app"} + + + + + + drawProgress(ctx, progress)} /> + + + + + + + {media.durationMs > 0 ? `${timestamp(media.positionMs)} / ${timestamp(media.durationMs)}` : media.sourceApp} + + - - - {Array.from({ length: segmentCount }, (_, index) => ( - index < filled - ? - : - ))} - - + + ); }); diff --git a/examples/pomodoro/widget.tsx b/examples/pomodoro/widget.tsx index 58d3cf3f..5084a0ce 100644 --- a/examples/pomodoro/widget.tsx +++ b/examples/pomodoro/widget.tsx @@ -1,71 +1,129 @@ -import { useInterval, useStorage, widget } from "@weaver/sdk"; +import { useInterval, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; -interface PomodoroState { - minutes: number; - remaining: number; +// A tiny app: persisted state, one timer, buttons with native hover and +// pressed states, and a canvas ring that redraws once per second. + +type Mode = "focus" | "short" | "long"; + +const minutes: Record = { focus: 25, short: 5, long: 15 }; +const headings: Record = { focus: "FOCUS", short: "SHORT BREAK", long: "LONG BREAK" }; +const focusColor = "#ff7a59"; +const breakColor = "#5eead4"; + +interface TimerState { + mode: Mode; + remaining: number; // seconds running: boolean; } +function clock(seconds: number): string { + return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`; +} + +// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out. +function drawRing(ctx: CanvasCtx, fraction: number, color: string): void { + ctx.clear(); + const cx = ctx.width / 2; + const cy = ctx.height / 2; + const outer = Math.min(cx, cy) - 2; + const inner = outer - 11; + const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60); + for (let index = 0; index < 60; index += 1) { + const angle = (index / 60) * Math.PI * 2 - Math.PI / 2; + const cos = Math.cos(angle); + const sin = Math.sin(angle); + ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : "#ffffff1f"); + } +} + export default widget({ name: "Pomodoro", - size: [320, 210], - anchor: { corner: "top-right", offset: [24, 158] }, + size: [300, 344], + anchor: { corner: "top-right", offset: [24, 180] }, }, () => { - const [timer, setTimer] = useStorage("timer", { - minutes: 25, - remaining: 25 * 60, - running: false, - }); + const [timer, setTimer] = useStorage("timer", { mode: "focus", remaining: minutes.focus * 60, running: false }); + const total = minutes[timer.mode] * 60; + const focus = timer.mode === "focus"; + const color = focus ? focusColor : breakColor; + // Ticks once per second while running. While paused the interval is + // stretched to an hour so the widget does not wake up for nothing. useInterval(() => { - if (!timer.running) return; setTimer((current) => { + if (!current.running) return current; if (current.remaining <= 1) return { ...current, remaining: 0, running: false }; return { ...current, remaining: current.remaining - 1 }; }); - }, 1000); + }, timer.running ? 1000 : 3_600_000); - const shownMinutes = Math.floor(timer.remaining / 60); - const shownSeconds = timer.remaining % 60; - const clock = `${String(shownMinutes).padStart(2, "0")}:${String(shownSeconds).padStart(2, "0")}`; + const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false }); + const chip = (mode: Mode, label: string) => { + const selected = timer.mode === mode; + return ( + + ); + }; return ( - - - - FOCUS TIMER - {clock} + + + {headings[timer.mode]} + {minutes[timer.mode]} MIN + + + + drawRing(ctx, timer.remaining / total, color)} /> + + {clock(timer.remaining)} + + {timer.remaining === 0 ? "DONE" : timer.running ? "RUNNING" : "PAUSED"} + - {timer.running ? "Focusing" : "Ready"} + + + + {chip("focus", "Focus")} + {chip("short", "Short break")} + {chip("long", "Long break")} - - - Session length - {timer.minutes} min - - { - const rounded = Math.max(5, Math.round(minutes)); - setTimer((current) => ({ ...current, minutes: rounded, remaining: current.running ? current.remaining : rounded * 60 })); - }} - /> - - + + diff --git a/examples/retro-player-shell/GeistPixel-Square.ttf b/examples/retro-player-shell/GeistPixel-Square.ttf deleted file mode 100644 index caa0a610af8788ce5bb1672bb94c7b7de6d68e2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94800 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 diff --git a/examples/retro-player-shell/OFL.txt b/examples/retro-player-shell/OFL.txt deleted file mode 100644 index 04e95fc5..00000000 --- a/examples/retro-player-shell/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -https://openfontlicense.org - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/examples/retro-player-shell/assets/grille.png b/examples/retro-player-shell/assets/grille.png deleted file mode 100644 index b264f7d3d2115ee2a107da6ddd8fcffcc5164f93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53383 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 ZHa1V!D}S_jR@ZXwynxaQ=|cXl{WmnR)^`8^ diff --git a/examples/retro-player-shell/widget.tsx b/examples/retro-player-shell/widget.tsx deleted file mode 100644 index 9f19159f..00000000 --- a/examples/retro-player-shell/widget.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { widget } from "@weaver/sdk"; - -const noop = () => {}; - -export default widget({ - name: "Retro Player Shell", - size: [820, 580], - anchor: { corner: "top-right", offset: [32, 32] }, -}, () => ( - - - - - WEAVER HI-FI SYSTEM - MODEL WR-04 / STATIC SIGNAL - - - 10:24 PM - - - - - - - - - - NIGHT BLOOM - - 03:18 / 05:42 - - - SECOND NATURE - CHANNEL SURFING / SIDE A - - - - - - - - - - - - - - - - -)); diff --git a/examples/styling-fonts/GeistPixel-Square.ttf b/examples/styling-fonts/GeistPixel-Square.ttf deleted file mode 100644 index caa0a610af8788ce5bb1672bb94c7b7de6d68e2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94800 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 diff --git a/examples/styling-fonts/OFL.txt b/examples/styling-fonts/OFL.txt deleted file mode 100644 index 04e95fc5..00000000 --- a/examples/styling-fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -https://openfontlicense.org - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/examples/styling-fonts/widget.tsx b/examples/styling-fonts/widget.tsx deleted file mode 100644 index 2758b296..00000000 --- a/examples/styling-fonts/widget.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { widget } from "@weaver/sdk"; - -export default widget({ - name: "Styling Fonts", - size: [420, 250], - anchor: { corner: "top-right", offset: [24, 24] }, -}, () => ( - - - BUNDLED PIXEL FACE - Built-in sans · weight ladder - Built-in mono 02:47:19 - - A single custom face keeps its own outlines for every requested weight; add weight-suffixed files to select real variants. - - -)); diff --git a/examples/styling-icons/widget.tsx b/examples/styling-icons/widget.tsx deleted file mode 100644 index 85f14ba2..00000000 --- a/examples/styling-icons/widget.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { widget } from "@weaver/sdk"; - -export default widget({ - name: "Styling Icons", - size: [500, 350], - anchor: { corner: "top-right", offset: [24, 24] }, -}, () => ( - - - - - - Bundle-time vector icons - Full Lucide catalog · tree-shaken M/L/C/Z paths - - - - - - - - - - - - - named - - - - custom fill - - - - custom stroke - - - - currentColor - - - - -)); diff --git a/examples/styling-interaction/tsconfig.json b/examples/styling-interaction/tsconfig.json deleted file mode 100644 index fb8488ea..00000000 --- a/examples/styling-interaction/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "baseUrl": ".", - "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] - } - }, - "include": ["widget.tsx"] -} diff --git a/examples/styling-shadows/widget.tsx b/examples/styling-shadows/widget.tsx deleted file mode 100644 index b2758039..00000000 --- a/examples/styling-shadows/widget.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { widget } from "@weaver/sdk"; - -export default widget({ - name: "Styling Shadows", - size: [380, 250], - anchor: { corner: "top-right", offset: [24, 24] }, -}, () => ( - - - Shadow breadth - - - - - - outset · inset · arbitrary - - -)); diff --git a/examples/styling-spacing/tsconfig.json b/examples/styling-spacing/tsconfig.json deleted file mode 100644 index 4248ebc1..00000000 --- a/examples/styling-spacing/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "skipLibCheck": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "types": [], - "baseUrl": ".", - "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] - } - }, - "include": ["widget.tsx"] -} diff --git a/examples/styling-spacing/widget.tsx b/examples/styling-spacing/widget.tsx deleted file mode 100644 index 145cc9b9..00000000 --- a/examples/styling-spacing/widget.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { widget } from "@weaver/sdk"; - -export default widget({ - name: "Styling Spacing", - size: [320, 200], - anchor: { corner: "top-right", offset: [24, 24] }, -}, () => ( - - Styling breadth - - - - - - - - Directional padding - 02:47 · Fractions, bounds, aspect ratio, and clamped text - - - - -)); diff --git a/examples/styling-stack/tsconfig.json b/examples/styling-stack/tsconfig.json deleted file mode 100644 index fb8488ea..00000000 --- a/examples/styling-stack/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "baseUrl": ".", - "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] - } - }, - "include": ["widget.tsx"] -} diff --git a/examples/styling-stack/widget.tsx b/examples/styling-stack/widget.tsx deleted file mode 100644 index 8b17b039..00000000 --- a/examples/styling-stack/widget.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { widget } from "@weaver/sdk"; - -export default widget({ - name: "Styling Stack", - size: [420, 280], - anchor: { corner: "top-right", offset: [24, 24] }, -}, () => ( - - - Overlay stack - - - - - Children paint in order - - rounded clip - - - - - - -)); diff --git a/examples/styling-text/tsconfig.json b/examples/styling-text/tsconfig.json deleted file mode 100644 index 4248ebc1..00000000 --- a/examples/styling-text/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "skipLibCheck": true, - "jsx": "react-jsx", - "jsxImportSource": "@weaver/sdk", - "types": [], - "baseUrl": ".", - "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] - } - }, - "include": ["widget.tsx"] -} diff --git a/examples/system/widget.tsx b/examples/system/widget.tsx index 34f80c62..25932fea 100644 --- a/examples/system/widget.tsx +++ b/examples/system/widget.tsx @@ -1,27 +1,102 @@ -import { useProvider, widget } from "@weaver/sdk"; +import { useEffect, useProvider, widget, type CanvasCtx, type CpuData } from "@weaver/sdk"; + +// CPU and memory from the host at 1 Hz. The text nodes update in the retained +// tree; the three canvases redraw once per provider frame (no `fps`, so no +// frame clock of their own). + +const historyLength = 60; +const history: number[] = []; + +const accent = "#2dd4bf"; +const accentSoft = "#2dd4bf33"; +const track = "#ffffff14"; + +function gigabytes(mb: number): string { + return (mb / 1024).toFixed(1); +} + +function drawHistory(ctx: CanvasCtx): void { + ctx.clear(); + const step = ctx.width / (historyLength - 1); + const floor = ctx.height - 1; + const points: number[] = []; + const offset = historyLength - history.length; + for (let index = 0; index < history.length; index += 1) { + const x = (offset + index) * step; + const y = floor - (history[index] / 100) * (ctx.height - 4); + // Area under the line: one thin column per sample. + ctx.fillRect(x, y, Math.max(1, step), floor - y, accentSoft); + points.push(x, y); + } + ctx.line(0, floor, ctx.width, floor, 1, track); + if (points.length >= 4) ctx.polyline(points, 1.5, accent); +} + +function drawCores(ctx: CanvasCtx, cpu: CpuData): void { + ctx.clear(); + const count = Math.max(1, cpu.perCore.length); + const gap = 3; + const width = (ctx.width - gap * (count - 1)) / count; + for (let index = 0; index < count; index += 1) { + const x = index * (width + gap); + const load = Math.max(0, Math.min(1, (cpu.perCore[index] ?? 0) / 100)); + ctx.fillRoundRect(x, 0, width, ctx.height, 2, track); + const height = Math.max(2, load * ctx.height); + ctx.fillRoundRect(x, ctx.height - height, width, height, 2, load > 0.85 ? "#fb7185" : accent); + } +} + +function drawMemory(ctx: CanvasCtx, percent: number): void { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, ctx.height / 2, track); + const width = Math.max(ctx.height, (Math.max(0, Math.min(100, percent)) / 100) * ctx.width); + ctx.fillRoundRect(0, 0, width, ctx.height, ctx.height / 2, "#f5f6f8"); +} export default widget({ name: "System Monitor", - size: [300, 150], + size: [340, 196], anchor: { corner: "top-left", offset: [24, 24] }, subscribe: ["cpu", "memory"], }, () => { const cpu = useProvider("cpu"); const memory = useProvider("memory"); + useEffect(() => { + history.push(cpu.percent); + if (history.length > historyLength) history.shift(); + }, [cpu]); + return ( - - SYSTEM - - - CPU - {cpu.percent.toFixed(1)}% - - - MEMORY - {memory.usedMb} MB - of {memory.totalMb} MB · {memory.percent.toFixed(1)}% + + + + CPU + + {cpu.percent.toFixed(0)} + % + + + + drawCores(ctx, cpu)} /> + + + + MEMORY + + {gigabytes(memory.usedMb)} + / {gigabytes(memory.totalMb)} GB + + + drawMemory(ctx, memory.percent)} /> + ); }); diff --git a/examples/styling-fonts/tsconfig.json b/examples/weather/tsconfig.json similarity index 100% rename from examples/styling-fonts/tsconfig.json rename to examples/weather/tsconfig.json diff --git a/examples/weather/widget.tsx b/examples/weather/widget.tsx new file mode 100644 index 00000000..ea046d42 --- /dev/null +++ b/examples/weather/widget.tsx @@ -0,0 +1,208 @@ +import { useEffect, useInterval, useState, useStorage, wfetch, widget } from "@weaver/sdk"; + +// Declared-origin networking: the widget may only reach hosts listed in +// `origins`. Open-Meteo needs no API key. Change `place` to your city and +// `units` to "fahrenheit" if you prefer. + +const place = { name: "San Francisco", latitude: 37.77, longitude: -122.42 }; +const units: "celsius" | "fahrenheit" = "celsius"; +const refreshMs = 15 * 60 * 1000; + +interface Day { date: string; code: number; high: number; low: number } +interface Forecast { + temperature: number; + code: number; + isDay: boolean; + wind: number; + humidity: number; + days: Day[]; + fetchedAt: number; +} + +const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + +// WMO weather interpretation codes, as returned by Open-Meteo. +function describe(code: number): string { + if (code === 0) return "Clear"; + if (code <= 2) return "Partly cloudy"; + if (code === 3) return "Overcast"; + if (code <= 48) return "Fog"; + if (code <= 57) return "Drizzle"; + if (code <= 67) return "Rain"; + if (code <= 77) return "Snow"; + if (code <= 82) return "Showers"; + if (code <= 86) return "Snow showers"; + return "Thunderstorm"; +} + +type Sky = "sun" | "moon" | "cloud-sun" | "cloud-moon" | "cloud" | "cloud-fog" | "cloud-drizzle" | "cloud-rain" | "cloud-snow" | "cloud-lightning"; + +function skyFor(code: number, isDay: boolean): Sky { + if (code === 0) return isDay ? "sun" : "moon"; + if (code <= 2) return isDay ? "cloud-sun" : "cloud-moon"; + if (code === 3) return "cloud"; + if (code <= 48) return "cloud-fog"; + if (code <= 57) return "cloud-drizzle"; + if (code <= 67 || (code >= 80 && code <= 82)) return "cloud-rain"; + if (code <= 86) return "cloud-snow"; + return "cloud-lightning"; +} + +// Icon names must be literals so `weaver check` can validate and embed only +// the referenced geometry, hence one branch per sky. +function skyIcon(sky: Sky, size: "large" | "small"): JSX.Element { + const cls = size === "large" ? "size-[36px] text-[#ffffff]" : "size-[16px] text-[#ffffff]/85"; + switch (sky) { + case "sun": return ; + case "moon": return ; + case "cloud-sun": return ; + case "cloud-moon": return ; + case "cloud": return ; + case "cloud-fog": return ; + case "cloud-drizzle": return ; + case "cloud-rain": return ; + case "cloud-snow": return ; + case "cloud-lightning": return ; + } +} + +function weekday(date: string): string { + return weekdays[new Date(`${date}T12:00:00`).getDay()] ?? date; +} + +function number(value: unknown): number | null { + return typeof value === "number" && Number.isFinite(value) ? value : null; +} + +function parseForecast(payload: unknown): Forecast | null { + if (typeof payload !== "object" || payload === null) return null; + const current = (payload as { current?: Record }).current; + const daily = (payload as { daily?: Record }).daily; + if (!current || !daily) return null; + const temperature = number(current.temperature_2m); + const code = number(current.weather_code); + if (temperature === null || code === null) return null; + const dates = Array.isArray(daily.time) ? daily.time : []; + const days: Day[] = []; + for (let index = 0; index < dates.length; index += 1) { + const dayCode = number(daily.weather_code?.[index]); + const high = number(daily.temperature_2m_max?.[index]); + const low = number(daily.temperature_2m_min?.[index]); + if (typeof dates[index] !== "string" || dayCode === null || high === null || low === null) continue; + days.push({ date: dates[index] as string, code: dayCode, high, low }); + } + return { + temperature, + code, + isDay: current.is_day !== 0, + wind: number(current.wind_speed_10m) ?? 0, + humidity: number(current.relative_humidity_2m) ?? 0, + days, + fetchedAt: Date.now(), + }; +} + +function updatedAt(epochMs: number): string { + const date = new Date(epochMs); + return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`; +} + +export default widget({ + name: "Weather", + size: [320, 212], + anchor: { corner: "top-left", offset: [24, 244] }, + origins: ["api.open-meteo.com"], +}, () => { + const [forecast, setForecast] = useStorage("forecast", null); + const [status, setStatus] = useState<"loading" | "ok" | "error">("loading"); + + const refresh = async () => { + setStatus("loading"); + try { + const response = await wfetch( + `https://api.open-meteo.com/v1/forecast?latitude=${place.latitude}&longitude=${place.longitude}` + + "¤t=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m,is_day" + + "&daily=weather_code,temperature_2m_max,temperature_2m_min" + + `&timezone=auto&forecast_days=5&temperature_unit=${units}`, + ); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + const parsed = parseForecast(await response.json()); + if (!parsed) throw new Error("unexpected payload"); + setForecast(parsed); + setStatus("ok"); + } catch { + setStatus("error"); + } + }; + useEffect(() => { void refresh(); }, []); + useInterval(() => { void refresh(); }, refreshMs); + + const today = forecast?.days[0]; + const footer = status === "error" + ? "Couldn't reach api.open-meteo.com · retrying in 15 min" + : forecast + ? `Updated ${updatedAt(forecast.fetchedAt)}` + : "Fetching forecast…"; + + return ( + + + + {place.name} + {forecast ? describe(forecast.code) : "—"} + + {forecast + ? skyIcon(skyFor(forecast.code, forecast.isDay), "large") + : } + + + + + {forecast + ? {Math.round(forecast.temperature)} + : --} + ° + + + + {today ? `H ${Math.round(today.high)}° L ${Math.round(today.low)}°` : ""} + + + {forecast ? `${Math.round(forecast.wind)} km/h · ${Math.round(forecast.humidity)}% humidity` : ""} + + + + + + {(forecast?.days ?? [null, null, null, null, null]).slice(0, 5).map((day, index) => ( + + {day ? weekday(day.date).toUpperCase() : "—"} + {day + ? skyIcon(skyFor(day.code, true), "small") + : } + {day ? `${Math.round(day.high)}°` : ""} + + ))} + + + {footer} + + ); +}); diff --git a/scripts/verify-dpi.ps1 b/scripts/verify-dpi.ps1 index 05745efc..9645c96d 100644 --- a/scripts/verify-dpi.ps1 +++ b/scripts/verify-dpi.ps1 @@ -131,7 +131,7 @@ $RepoRoot = [IO.Path]::GetFullPath($RepoRoot) $OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory) [IO.Directory]::CreateDirectory($OutputDirectory) | Out-Null $cli = Join-Path $RepoRoot "cli\dist\index.js" -$fixture = Join-Path $RepoRoot "examples\dpi-diagnostic" +$fixture = Join-Path $RepoRoot "test\fixtures\dpi-diagnostic" $results = [ordered]@{ startedUtc = [DateTime]::UtcNow.ToString("o") repoRoot = $RepoRoot diff --git a/scripts/verify-gradient-gpu.ps1 b/scripts/verify-gradient-gpu.ps1 index 3038ae84..c3be1f2d 100644 --- a/scripts/verify-gradient-gpu.ps1 +++ b/scripts/verify-gradient-gpu.ps1 @@ -51,7 +51,7 @@ $OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory) [IO.Directory]::CreateDirectory($OutputDirectory) | Out-Null $NativeRoot = Join-Path $RepoRoot "runtime\native-sdk" $Cli = Join-Path $RepoRoot "cli\dist\index.js" -$Example = Join-Path $RepoRoot "examples\gradient-stack" +$Example = Join-Path $RepoRoot "test\fixtures\gradient-stack" $CaptureHelper = Join-Path $RepoRoot "renderer\zig-out\bin\weaver-window-capture.exe" $StateRoot = Join-Path $OutputDirectory "state" $ResultPath = Join-Path $OutputDirectory "results.json" diff --git a/sdk/CONTRACT.md b/sdk/CONTRACT.md index aaf8c6e9..2d81a346 100644 --- a/sdk/CONTRACT.md +++ b/sdk/CONTRACT.md @@ -304,7 +304,7 @@ actionable — the primary reader is an agent in a fix-it loop. ## The conjure skill -`skills/conjure-widget/SKILL.md` in this repo: teaches an agent to go from a +`.agents/skills/conjure-widget/SKILL.md` in this repo: teaches an agent to go from a user's description to `weaver init` → edit widget.tsx → `weaver check` → `weaver dev`, including this contract inline or by reference, the class table, and the M1 boundaries (no providers beyond time, no input elements yet). diff --git a/test/capture-smoke.mjs b/test/capture-smoke.mjs index b350e753..66b72cbd 100644 --- a/test/capture-smoke.mjs +++ b/test/capture-smoke.mjs @@ -12,17 +12,17 @@ const fixedClock = "2026-08-24T17:30:00.000Z"; try { const clock = capture("clock", "examples/clock"); - assert.deepEqual([clock.output.widthPx, clock.output.heightPx], [240, 110]); + assert.deepEqual([clock.output.widthPx, clock.output.heightPx], [320, 132]); const resizedClock = capture("clock-resized", "examples/clock", [ "--action-file", join(root, "test", "capture", "resize.actions"), ]); assert.deepEqual([resizedClock.output.widthPx, resizedClock.output.heightPx], [962, 719]); - const text = capture("styling-text", "examples/styling-text"); + const text = capture("styling-text", "test/fixtures/styling-text"); assert.ok(text.renderer.pixelsDifferentFromClear > 0); - const images = capture("styling-images", "examples/styling-images"); + const images = capture("styling-images", "test/fixtures/styling-images"); assert.equal(images.renderer.images, 3); assert.equal(images.pending.images, 0); @@ -34,16 +34,16 @@ try { assert.match(snapshotText(pomodoroAfter), /role=button name="Pause"/); assert.match(snapshotText(pomodoroAfter), /role=text name="24:59"/); - const interactionBefore = capture("interaction-before", "examples/styling-interaction"); - const interactionAfter = capture("interaction-after", "examples/styling-interaction", [ + const interactionBefore = capture("interaction-before", "test/fixtures/styling-interaction"); + const interactionAfter = capture("interaction-after", "test/fixtures/styling-interaction", [ "--action-file", join(root, "test", "capture", "styling-interaction.actions"), ]); assert.notEqual(imageHash(interactionBefore), imageHash(interactionAfter)); assert.match(snapshotText(interactionAfter), /role=slider .* value=0\.9/); assert.match(snapshotText(interactionAfter), /role=text name="90%"/); - const tideglassBefore = capture("tideglass-before", "examples/tideglass"); - const tideglassAfter = capture("tideglass-after", "examples/tideglass", [ + const tideglassBefore = capture("tideglass-before", "test/fixtures/tideglass"); + const tideglassAfter = capture("tideglass-after", "test/fixtures/tideglass", [ "--action-file", join(root, "test", "capture", "tideglass.actions"), ]); assert.notEqual(imageHash(tideglassBefore), imageHash(tideglassAfter)); @@ -52,6 +52,24 @@ try { assert.deepEqual(tideglassAfter.interactions.actions, ["click", "click"]); assert.equal(tideglassAfter.pending.timers, 0); + const system = capture("system", "examples/system", [ + "--provider-fixture", join(root, "test", "capture", "system.provider.json"), + ]); + assert.match(snapshotText(system), /role=text name="MEMORY"/); + assert.match(snapshotText(system), /role=text name="9\.6"/); + + const nowPlaying = capture("now-playing", "examples/now-playing", [ + "--provider-fixture", join(root, "test", "capture", "noro.provider.json"), + ]); + assert.match(snapshotText(nowPlaying), /role=button name="Pause"/); + assert.match(snapshotText(nowPlaying), /role=button name="Seek"/); + assert.match(snapshotText(nowPlaying), /name="0:42 \/ 3:00"/); + + // The forecast fetch is real network and may or may not land inside the + // capture window, so only the static frame is asserted. + const weather = capture("weather", "examples/weather"); + assert.match(snapshotText(weather), /role=text name="San Francisco"/); + const noro = capture("noro", "examples/noro-shell", [ "--provider-fixture", join(root, "test", "capture", "noro.provider.json"), ]); @@ -158,6 +176,9 @@ try { ]); assert.equal(ambiguous.error?.name, "CaptureTargetAmbiguous"); assert.deepEqual(ambiguous.error?.candidates?.map(({ role, name }) => ({ role, name })), [ + { role: "button", name: "Focus" }, + { role: "button", name: "Short break" }, + { role: "button", name: "Long break" }, { role: "button", name: "Start" }, { role: "button", name: "Reset" }, ]); diff --git a/test/capture/media-stopped.provider.json b/test/capture/media-stopped.provider.json new file mode 100644 index 00000000..9042321c --- /dev/null +++ b/test/capture/media-stopped.provider.json @@ -0,0 +1,18 @@ +{ + "schema": "weaver.provider-fixture.v1", + "frames": [ + { + "provider": "media", + "value": { + "title": "", + "artist": "", + "album": "", + "status": "stopped", + "playing": false, + "sourceApp": "", + "positionMs": 0, + "durationMs": 0 + } + } + ] +} diff --git a/test/capture/system.provider.json b/test/capture/system.provider.json new file mode 100644 index 00000000..b1de1689 --- /dev/null +++ b/test/capture/system.provider.json @@ -0,0 +1,1093 @@ +{ + "schema": "weaver.provider-fixture.v1", + "frames": [ + { + "provider": "cpu", + "value": { + "percent": 12.9, + "perCore": [ + 7.7, + 16.1, + 6.4, + 14.2, + 11.3, + 6.2, + 13.7, + 5.8, + 12.5, + 6.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 12.5, + "perCore": [ + 11.9, + 18.5, + 7.0, + 8.7, + 15.2, + 20.5, + 14.4, + 11.5, + 20.9, + 5.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 18.1, + "perCore": [ + 14.1, + 10.6, + 10.0, + 14.5, + 26.5, + 11.5, + 20.9, + 22.3, + 16.0, + 20.1 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 14.3, + "perCore": [ + 6.8, + 9.5, + 18.3, + 13.6, + 11.5, + 16.6, + 14.1, + 11.3, + 20.4, + 18.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 16.2, + "perCore": [ + 18.5, + 17.5, + 24.9, + 21.8, + 12.5, + 27.1, + 9.0, + 15.3, + 22.4, + 9.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 18.4, + "perCore": [ + 8.3, + 23.3, + 25.6, + 21.0, + 28.3, + 14.8, + 24.0, + 21.5, + 21.2, + 18.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 21.1, + "perCore": [ + 34.3, + 21.4, + 26.6, + 10.1, + 27.7, + 26.2, + 35.7, + 31.0, + 16.2, + 19.0 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 20.5, + "perCore": [ + 8.8, + 20.5, + 12.7, + 11.3, + 9.8, + 28.7, + 11.7, + 14.8, + 18.6, + 31.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.3, + "perCore": [ + 17.0, + 19.3, + 26.8, + 25.4, + 26.4, + 13.2, + 16.3, + 15.0, + 26.8, + 28.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.9, + "perCore": [ + 11.3, + 12.6, + 12.6, + 18.4, + 20.9, + 13.3, + 7.3, + 16.9, + 15.7, + 20.3 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 22.7, + "perCore": [ + 29.4, + 24.3, + 27.3, + 29.0, + 10.7, + 35.6, + 32.1, + 34.9, + 32.6, + 20.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 19.2, + "perCore": [ + 10.3, + 23.5, + 9.2, + 9.4, + 12.9, + 11.7, + 16.2, + 9.0, + 7.7, + 11.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.1, + "perCore": [ + 14.9, + 7.4, + 26.2, + 20.4, + 10.1, + 12.4, + 14.5, + 14.9, + 9.6, + 25.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 21.9, + "perCore": [ + 22.1, + 22.6, + 11.2, + 11.7, + 18.5, + 16.3, + 32.4, + 13.4, + 9.4, + 35.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 18.5, + "perCore": [ + 10.9, + 20.5, + 8.1, + 20.1, + 30.9, + 28.2, + 24.2, + 13.7, + 16.2, + 11.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 19.2, + "perCore": [ + 21.0, + 27.2, + 15.9, + 13.3, + 28.0, + 32.3, + 29.0, + 27.8, + 28.1, + 26.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 15.1, + "perCore": [ + 16.2, + 13.0, + 6.6, + 6.6, + 11.5, + 11.1, + 19.6, + 24.8, + 14.8, + 24.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 18.7, + "perCore": [ + 30.8, + 16.4, + 12.9, + 13.0, + 12.3, + 12.5, + 22.7, + 29.4, + 28.0, + 19.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 15.8, + "perCore": [ + 22.7, + 8.0, + 19.8, + 25.0, + 22.3, + 21.7, + 16.1, + 10.0, + 22.5, + 13.1 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 15.7, + "perCore": [ + 26.0, + 14.3, + 14.4, + 25.5, + 21.0, + 9.7, + 8.8, + 9.3, + 24.7, + 22.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 10.7, + "perCore": [ + 15.8, + 18.0, + 13.5, + 9.2, + 11.9, + 6.1, + 4.5, + 17.8, + 13.4, + 11.6 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 14.5, + "perCore": [ + 14.0, + 22.2, + 21.4, + 9.8, + 10.5, + 11.3, + 10.3, + 16.9, + 10.7, + 13.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 8.8, + "perCore": [ + 13.9, + 7.5, + 8.7, + 10.2, + 13.8, + 8.3, + 14.0, + 9.2, + 9.6, + 9.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 7.3, + "perCore": [ + 7.1, + 4.6, + 3.0, + 10.5, + 4.5, + 7.4, + 9.8, + 8.2, + 6.0, + 7.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 9.8, + "perCore": [ + 13.9, + 5.3, + 11.0, + 7.1, + 7.4, + 13.7, + 10.4, + 11.1, + 13.6, + 15.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 8.5, + "perCore": [ + 10.2, + 9.0, + 9.1, + 11.1, + 8.4, + 9.3, + 8.7, + 13.9, + 11.2, + 13.1 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 11.1, + "perCore": [ + 8.2, + 12.5, + 18.0, + 16.5, + 6.4, + 6.2, + 10.8, + 5.5, + 7.9, + 5.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 9.2, + "perCore": [ + 13.0, + 14.3, + 5.5, + 12.2, + 11.5, + 5.4, + 14.2, + 15.2, + 6.3, + 15.0 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 7.4, + "perCore": [ + 7.6, + 12.5, + 11.0, + 4.5, + 7.1, + 7.9, + 6.2, + 4.8, + 6.0, + 9.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 15.0, + "perCore": [ + 16.8, + 14.6, + 6.4, + 12.5, + 18.2, + 16.0, + 7.3, + 25.2, + 21.4, + 24.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 24.9, + "perCore": [ + 18.5, + 11.2, + 35.1, + 18.7, + 14.1, + 23.6, + 39.4, + 36.4, + 18.3, + 14.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 38.0, + "perCore": [ + 43.4, + 49.8, + 19.6, + 18.0, + 49.2, + 36.2, + 18.8, + 61.5, + 46.5, + 54.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 39.5, + "perCore": [ + 59.8, + 19.2, + 60.2, + 39.1, + 33.2, + 44.2, + 63.4, + 29.6, + 22.5, + 42.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 44.9, + "perCore": [ + 24.4, + 27.4, + 20.9, + 29.7, + 36.2, + 35.8, + 62.3, + 34.9, + 47.2, + 28.3 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 47.6, + "perCore": [ + 20.2, + 34.5, + 20.0, + 64.4, + 53.2, + 30.8, + 48.4, + 76.9, + 25.6, + 69.7 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 47.7, + "perCore": [ + 49.8, + 70.8, + 43.4, + 50.5, + 61.7, + 80.0, + 40.3, + 70.7, + 62.9, + 58.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 44.7, + "perCore": [ + 38.0, + 21.0, + 25.4, + 22.0, + 60.9, + 32.7, + 27.3, + 22.8, + 66.7, + 68.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 41.2, + "perCore": [ + 31.6, + 29.4, + 32.2, + 41.1, + 24.9, + 40.4, + 30.6, + 68.0, + 68.6, + 45.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 31.8, + "perCore": [ + 52.6, + 25.5, + 27.4, + 12.8, + 28.5, + 32.3, + 33.5, + 21.0, + 33.6, + 12.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 23.7, + "perCore": [ + 12.3, + 21.8, + 10.8, + 10.2, + 18.9, + 16.7, + 27.5, + 25.8, + 32.6, + 29.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.5, + "perCore": [ + 27.1, + 15.9, + 14.5, + 29.5, + 10.4, + 23.5, + 21.7, + 8.0, + 26.1, + 27.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.9, + "perCore": [ + 24.2, + 26.1, + 10.4, + 19.3, + 18.9, + 26.6, + 25.9, + 26.4, + 20.8, + 27.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 19.0, + "perCore": [ + 24.8, + 13.3, + 8.4, + 10.9, + 16.5, + 10.2, + 28.3, + 21.4, + 23.2, + 23.1 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 19.7, + "perCore": [ + 20.4, + 8.0, + 28.3, + 27.1, + 20.8, + 21.6, + 24.8, + 9.6, + 26.8, + 14.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 16.7, + "perCore": [ + 12.4, + 22.4, + 11.1, + 22.7, + 27.8, + 17.4, + 14.9, + 17.0, + 21.5, + 23.3 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 20.3, + "perCore": [ + 25.1, + 10.2, + 12.0, + 14.8, + 27.8, + 16.2, + 23.1, + 8.5, + 9.7, + 15.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 20.9, + "perCore": [ + 27.2, + 26.8, + 16.3, + 22.4, + 21.0, + 21.1, + 11.6, + 32.7, + 13.8, + 35.0 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 22.6, + "perCore": [ + 9.6, + 22.5, + 33.2, + 37.5, + 22.3, + 16.9, + 15.2, + 36.8, + 15.2, + 26.1 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.8, + "perCore": [ + 19.2, + 29.1, + 10.2, + 26.1, + 18.9, + 27.6, + 23.4, + 12.5, + 27.9, + 18.4 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 16.9, + "perCore": [ + 6.8, + 17.5, + 16.6, + 13.4, + 9.8, + 14.3, + 13.7, + 25.2, + 6.8, + 23.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 21.4, + "perCore": [ + 11.9, + 34.3, + 28.3, + 33.6, + 16.6, + 18.9, + 19.5, + 36.3, + 24.9, + 18.6 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 18.4, + "perCore": [ + 13.9, + 8.5, + 9.8, + 27.3, + 14.2, + 29.7, + 13.3, + 13.7, + 19.5, + 11.9 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.4, + "perCore": [ + 28.5, + 26.9, + 25.3, + 21.2, + 27.6, + 28.2, + 19.3, + 23.2, + 8.1, + 23.5 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 17.1, + "perCore": [ + 23.5, + 21.1, + 13.2, + 7.9, + 27.4, + 9.6, + 17.3, + 14.4, + 13.4, + 23.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 19.3, + "perCore": [ + 14.3, + 24.2, + 15.3, + 21.7, + 17.6, + 11.9, + 11.8, + 13.0, + 30.5, + 20.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 13.9, + "perCore": [ + 21.9, + 23.5, + 13.6, + 8.1, + 9.0, + 7.2, + 11.7, + 7.2, + 9.8, + 10.2 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 15.0, + "perCore": [ + 23.2, + 20.6, + 14.0, + 14.0, + 16.2, + 13.3, + 12.6, + 7.2, + 11.4, + 24.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 11.3, + "perCore": [ + 11.9, + 13.8, + 17.2, + 7.7, + 8.5, + 8.2, + 10.4, + 11.1, + 18.5, + 17.0 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 14.8, + "perCore": [ + 6.3, + 6.5, + 19.6, + 23.2, + 15.0, + 17.2, + 5.9, + 13.5, + 23.8, + 21.8 + ] + } + }, + { + "provider": "cpu", + "value": { + "percent": 13.7, + "perCore": [ + 22.9, + 9.9, + 7.4, + 8.3, + 14.8, + 17.7, + 22.3, + 18.4, + 17.1, + 19.2 + ] + } + }, + { + "provider": "memory", + "value": { + "usedMb": 9830, + "totalMb": 16384, + "percent": 60.0 + } + } + ] +} \ No newline at end of file diff --git a/examples/m4b-parity/tsconfig.json b/test/fixtures/dpi-diagnostic/tsconfig.json similarity index 73% rename from examples/m4b-parity/tsconfig.json rename to test/fixtures/dpi-diagnostic/tsconfig.json index daa9010a..47cf729c 100644 --- a/examples/m4b-parity/tsconfig.json +++ b/test/fixtures/dpi-diagnostic/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../sdk/tsconfig.json", + "extends": "../../../sdk/tsconfig.json", "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@weaver/sdk" diff --git a/examples/dpi-diagnostic/widget.tsx b/test/fixtures/dpi-diagnostic/widget.tsx similarity index 100% rename from examples/dpi-diagnostic/widget.tsx rename to test/fixtures/dpi-diagnostic/widget.tsx diff --git a/examples/retro-player-shell/tsconfig.json b/test/fixtures/gradient-stack/tsconfig.json similarity index 70% rename from examples/retro-player-shell/tsconfig.json rename to test/fixtures/gradient-stack/tsconfig.json index fb8488ea..3baf8dbb 100644 --- a/examples/retro-player-shell/tsconfig.json +++ b/test/fixtures/gradient-stack/tsconfig.json @@ -9,8 +9,8 @@ "jsxImportSource": "@weaver/sdk", "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@weaver/sdk": ["../../../sdk/index.d.ts"], + "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] } }, "include": ["widget.tsx"] diff --git a/examples/gradient-stack/widget.tsx b/test/fixtures/gradient-stack/widget.tsx similarity index 100% rename from examples/gradient-stack/widget.tsx rename to test/fixtures/gradient-stack/widget.tsx diff --git a/examples/dpi-diagnostic/tsconfig.json b/test/fixtures/m4b-parity/tsconfig.json similarity index 73% rename from examples/dpi-diagnostic/tsconfig.json rename to test/fixtures/m4b-parity/tsconfig.json index daa9010a..47cf729c 100644 --- a/examples/dpi-diagnostic/tsconfig.json +++ b/test/fixtures/m4b-parity/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../sdk/tsconfig.json", + "extends": "../../../sdk/tsconfig.json", "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@weaver/sdk" diff --git a/examples/m4b-parity/widget.tsx b/test/fixtures/m4b-parity/widget.tsx similarity index 100% rename from examples/m4b-parity/widget.tsx rename to test/fixtures/m4b-parity/widget.tsx diff --git a/examples/m4b-synthetic/tsconfig.json b/test/fixtures/m4b-synthetic/tsconfig.json similarity index 100% rename from examples/m4b-synthetic/tsconfig.json rename to test/fixtures/m4b-synthetic/tsconfig.json diff --git a/examples/m4b-synthetic/widget.tsx b/test/fixtures/m4b-synthetic/widget.tsx similarity index 100% rename from examples/m4b-synthetic/widget.tsx rename to test/fixtures/m4b-synthetic/widget.tsx diff --git a/examples/styling-images/assets/weaver.png b/test/fixtures/styling-images/assets/weaver.png similarity index 100% rename from examples/styling-images/assets/weaver.png rename to test/fixtures/styling-images/assets/weaver.png diff --git a/examples/styling-images/tsconfig.json b/test/fixtures/styling-images/tsconfig.json similarity index 70% rename from examples/styling-images/tsconfig.json rename to test/fixtures/styling-images/tsconfig.json index fb8488ea..3baf8dbb 100644 --- a/examples/styling-images/tsconfig.json +++ b/test/fixtures/styling-images/tsconfig.json @@ -9,8 +9,8 @@ "jsxImportSource": "@weaver/sdk", "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@weaver/sdk": ["../../../sdk/index.d.ts"], + "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] } }, "include": ["widget.tsx"] diff --git a/examples/styling-images/widget.tsx b/test/fixtures/styling-images/widget.tsx similarity index 100% rename from examples/styling-images/widget.tsx rename to test/fixtures/styling-images/widget.tsx diff --git a/examples/styling-icons/tsconfig.json b/test/fixtures/styling-interaction/tsconfig.json similarity index 70% rename from examples/styling-icons/tsconfig.json rename to test/fixtures/styling-interaction/tsconfig.json index fb8488ea..3baf8dbb 100644 --- a/examples/styling-icons/tsconfig.json +++ b/test/fixtures/styling-interaction/tsconfig.json @@ -9,8 +9,8 @@ "jsxImportSource": "@weaver/sdk", "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@weaver/sdk": ["../../../sdk/index.d.ts"], + "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] } }, "include": ["widget.tsx"] diff --git a/examples/styling-interaction/widget.tsx b/test/fixtures/styling-interaction/widget.tsx similarity index 100% rename from examples/styling-interaction/widget.tsx rename to test/fixtures/styling-interaction/widget.tsx diff --git a/examples/styling-shadows/tsconfig.json b/test/fixtures/styling-text/tsconfig.json similarity index 73% rename from examples/styling-shadows/tsconfig.json rename to test/fixtures/styling-text/tsconfig.json index 4248ebc1..318a70a8 100644 --- a/examples/styling-shadows/tsconfig.json +++ b/test/fixtures/styling-text/tsconfig.json @@ -11,8 +11,8 @@ "types": [], "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@weaver/sdk": ["../../../sdk/index.d.ts"], + "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] } }, "include": ["widget.tsx"] diff --git a/examples/styling-text/widget.tsx b/test/fixtures/styling-text/widget.tsx similarity index 100% rename from examples/styling-text/widget.tsx rename to test/fixtures/styling-text/widget.tsx diff --git a/examples/tideglass/tsconfig.json b/test/fixtures/tideglass/tsconfig.json similarity index 74% rename from examples/tideglass/tsconfig.json rename to test/fixtures/tideglass/tsconfig.json index 8c42381b..e02d05f7 100644 --- a/examples/tideglass/tsconfig.json +++ b/test/fixtures/tideglass/tsconfig.json @@ -11,8 +11,8 @@ "types": [], "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@weaver/sdk": ["../../../sdk/index.d.ts"], + "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] } }, "include": [ diff --git a/examples/tideglass/widget.tsx b/test/fixtures/tideglass/widget.tsx similarity index 100% rename from examples/tideglass/widget.tsx rename to test/fixtures/tideglass/widget.tsx From 7e89f274ffc9dffdff3c7650c6705f1f30a79d1c Mon Sep 17 00:00:00 2001 From: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:26:58 -0400 Subject: [PATCH 2/2] experiments: render-loop cadence bench, two-model results, and framework findings Twenty agents (10 Opus, 10 gpt-6-astra) built one widget under three capture cadences; Fable graded all twenty blind. PROTOCOL.md is the reusable bench, SYNTHESIS.md the combined read, DECISIONS.md the evidence behind the three open items, CANVAS-LAYOUT-SIZE.md the mechanism of the canvas defect with draw-log receipts. Per-run sources, self-reports, uniform re-captures, usage and save receipts, and the reproduction probes (panel, canvas, rounding) are kept; intermediate agent captures and build output are not. Findings from this bench landed as #76 to #82. Also ignores .claude/worktrees. Co-Authored-By: Claude Fable 5.1 --- .gitignore | 3 + .../render-loop-cadence/BRIEF-FOR-ASTRA.md | 143 ++ .../render-loop-cadence/CANVAS-LAYOUT-SIZE.md | 110 ++ experiments/render-loop-cadence/DECISIONS.md | 169 ++ experiments/render-loop-cadence/GATES.tsv | 10 + experiments/render-loop-cadence/MAPPING.txt | 10 + experiments/render-loop-cadence/PROTOCOL.md | 112 ++ experiments/render-loop-cadence/REPORT.md | 141 ++ experiments/render-loop-cadence/SYNTHESIS.md | 154 ++ .../render-loop-cadence/astra/GATES.tsv | 11 + .../render-loop-cadence/astra/MAPPING.txt | 10 + .../astra/MEASUREMENTS.tsv | 11 + .../render-loop-cadence/astra/NOTES.md | 48 + .../render-loop-cadence/astra/SCORES.md | 50 + .../render-loop-cadence/astra/clicks.actions | 26 + .../astra/evidence/A1-commands.json | 56 + .../astra/evidence/A1-tool-results.json | 118 ++ .../astra/evidence/A1-usage.json | 285 +++ .../astra/evidence/A2-commands.json | 62 + .../astra/evidence/A2-tool-results.json | 142 ++ .../astra/evidence/A2-usage.json | 343 ++++ .../astra/evidence/B1-commands.json | 146 ++ .../astra/evidence/B1-tool-results.json | 218 +++ .../astra/evidence/B1-usage.json | 343 ++++ .../astra/evidence/B2-commands.json | 128 ++ .../astra/evidence/B2-tool-results.json | 246 +++ .../astra/evidence/B2-usage.json | 459 +++++ .../astra/evidence/B3-commands.json | 104 + .../astra/evidence/B3-tool-results.json | 250 +++ .../astra/evidence/B3-usage.json | 517 +++++ .../astra/evidence/B4-commands.json | 110 ++ .../astra/evidence/B4-tool-results.json | 190 ++ .../astra/evidence/B4-usage.json | 343 ++++ .../astra/evidence/C1-commands.json | 200 ++ .../astra/evidence/C1-tool-results.json | 432 ++++ .../astra/evidence/C1-usage.json | 836 ++++++++ .../astra/evidence/C2-commands.json | 182 ++ .../astra/evidence/C2-tool-results.json | 306 +++ .../astra/evidence/C2-usage.json | 517 +++++ .../astra/evidence/C3-commands.json | 206 ++ .../astra/evidence/C3-tool-results.json | 332 ++++ .../astra/evidence/C3-usage.json | 546 ++++++ .../astra/evidence/C4-commands.json | 194 ++ .../astra/evidence/C4-tool-results.json | 348 ++++ .../astra/evidence/C4-usage.json | 604 ++++++ .../astra/evidence/artifact-sha256.json | 530 +++++ .../examples/clock/widget.tsx | 77 + .../examples/pomodoro/widget.tsx | 131 ++ .../evidence/authoring-inputs/sdk/CONTRACT.md | 835 ++++++++ .../astra/evidence/command-audit.json | 82 + .../experiment-inputs/BRIEF-FOR-ASTRA.md | 143 ++ .../evidence/experiment-inputs/PROTOCOL.md | 112 ++ .../experiment-inputs/common-prompt.md | 40 + .../evidence/experiment-inputs/cond-A.md | 2 + .../evidence/experiment-inputs/cond-B.md | 2 + .../evidence/experiment-inputs/cond-C.md | 7 + .../evidence/experiment-inputs/grade-prep.sh | 37 + .../experiment-inputs/watch-saves.mjs | 15 + .../failed-captures/C1-02.combined-output.txt | 3 + .../failed-captures/C1-02.receipt.json | 1 + .../failed-captures/C2-03.combined-output.txt | 3 + .../failed-captures/C2-03.receipt.json | 1 + .../failed-captures/C3-03.combined-output.txt | 3 + .../failed-captures/C3-03.receipt.json | 1 + .../failed-captures/C4-04.combined-output.txt | 3 + .../failed-captures/C4-04.receipt.json | 1 + .../astra/evidence/failed-captures/index.json | 58 + .../astra/evidence/git-diff-before.patch | 1740 +++++++++++++++++ .../astra/evidence/git-status-after.txt | 79 + .../astra/evidence/git-status-before.txt | 79 + .../astra/evidence/prompt-verification.json | 62 + .../astra/evidence/toolchain-after.json | 12 + .../astra/evidence/toolchain-before.json | 12 + .../astra/evidence/verification.json | 26 + .../astra/final-captures/A1-after.png | Bin 0 -> 256283 bytes .../final-captures/A1-after.receipt.json | 70 + .../final-captures/A1-after.snapshot.txt | 49 + .../astra/final-captures/A1-initial.png | Bin 0 -> 256283 bytes .../final-captures/A1-initial.receipt.json | 61 + .../final-captures/A1-initial.snapshot.txt | 49 + .../astra/final-captures/A2-after.png | Bin 0 -> 256283 bytes .../final-captures/A2-after.receipt.json | 70 + .../final-captures/A2-after.snapshot.txt | 47 + .../astra/final-captures/A2-initial.png | Bin 0 -> 256283 bytes .../final-captures/A2-initial.receipt.json | 61 + .../final-captures/A2-initial.snapshot.txt | 47 + .../astra/final-captures/B1-after.png | Bin 0 -> 256283 bytes .../final-captures/B1-after.receipt.json | 70 + .../final-captures/B1-after.snapshot.txt | 47 + .../astra/final-captures/B1-initial.png | Bin 0 -> 256283 bytes .../final-captures/B1-initial.receipt.json | 61 + .../final-captures/B1-initial.snapshot.txt | 47 + .../astra/final-captures/B2-after.png | Bin 0 -> 256283 bytes .../final-captures/B2-after.receipt.json | 70 + .../final-captures/B2-after.snapshot.txt | 51 + .../astra/final-captures/B2-initial.png | Bin 0 -> 256283 bytes .../final-captures/B2-initial.receipt.json | 61 + .../final-captures/B2-initial.snapshot.txt | 51 + .../astra/final-captures/B3-after.png | Bin 0 -> 256283 bytes .../final-captures/B3-after.receipt.json | 70 + .../final-captures/B3-after.snapshot.txt | 47 + .../astra/final-captures/B3-initial.png | Bin 0 -> 256283 bytes .../final-captures/B3-initial.receipt.json | 61 + .../final-captures/B3-initial.snapshot.txt | 47 + .../astra/final-captures/B4-after.png | Bin 0 -> 256283 bytes .../final-captures/B4-after.receipt.json | 70 + .../final-captures/B4-after.snapshot.txt | 49 + .../astra/final-captures/B4-initial.png | Bin 0 -> 256283 bytes .../final-captures/B4-initial.receipt.json | 61 + .../final-captures/B4-initial.snapshot.txt | 48 + .../astra/final-captures/C1-after.png | Bin 0 -> 256283 bytes .../final-captures/C1-after.receipt.json | 70 + .../final-captures/C1-after.snapshot.txt | 47 + .../astra/final-captures/C1-initial.png | Bin 0 -> 256283 bytes .../final-captures/C1-initial.receipt.json | 61 + .../final-captures/C1-initial.snapshot.txt | 47 + .../astra/final-captures/C2-after.png | Bin 0 -> 256283 bytes .../final-captures/C2-after.receipt.json | 70 + .../final-captures/C2-after.snapshot.txt | 47 + .../astra/final-captures/C2-initial.png | Bin 0 -> 256283 bytes .../final-captures/C2-initial.receipt.json | 61 + .../final-captures/C2-initial.snapshot.txt | 47 + .../astra/final-captures/C3-after.png | Bin 0 -> 256283 bytes .../final-captures/C3-after.receipt.json | 70 + .../final-captures/C3-after.snapshot.txt | 47 + .../astra/final-captures/C3-initial.png | Bin 0 -> 256283 bytes .../final-captures/C3-initial.receipt.json | 61 + .../final-captures/C3-initial.snapshot.txt | 47 + .../astra/final-captures/C4-after.png | Bin 0 -> 256283 bytes .../final-captures/C4-after.receipt.json | 70 + .../final-captures/C4-after.snapshot.txt | 49 + .../astra/final-captures/C4-initial.png | Bin 0 -> 256283 bytes .../final-captures/C4-initial.receipt.json | 61 + .../final-captures/C4-initial.snapshot.txt | 49 + .../astra/harness/collect-usage.py | 89 + .../astra/harness/events.jsonl | 31 + .../astra/harness/extract-commands.cjs | 48 + .../astra/harness/final-recapture.py | 122 ++ .../astra/harness/schedule.json | 42 + .../astra/harness/watch-saves.mjs | 15 + .../astra/harness/watcher-process.json | 5 + .../render-loop-cadence/astra/prompts/A1.md | 43 + .../render-loop-cadence/astra/prompts/A2.md | 43 + .../render-loop-cadence/astra/prompts/B1.md | 43 + .../render-loop-cadence/astra/prompts/B2.md | 43 + .../render-loop-cadence/astra/prompts/B3.md | 43 + .../render-loop-cadence/astra/prompts/B4.md | 43 + .../render-loop-cadence/astra/prompts/C1.md | 48 + .../render-loop-cadence/astra/prompts/C2.md | 48 + .../render-loop-cadence/astra/prompts/C3.md | 48 + .../render-loop-cadence/astra/prompts/C4.md | 48 + .../astra/runs/A1/REPORT.md | 9 + .../astra/runs/A1/tsconfig.json | 25 + .../astra/runs/A1/widget.tsx | 74 + .../astra/runs/A2/REPORT.md | 10 + .../astra/runs/A2/tsconfig.json | 25 + .../astra/runs/A2/widget.tsx | 83 + .../astra/runs/B1/REPORT.md | 18 + .../astra/runs/B1/clicks.actions | 26 + .../astra/runs/B1/reset.actions | 33 + .../astra/runs/B1/tsconfig.json | 25 + .../astra/runs/B1/widget.tsx | 66 + .../astra/runs/B2/REPORT.md | 17 + .../astra/runs/B2/clicks.actions | 26 + .../astra/runs/B2/reset.actions | 33 + .../astra/runs/B2/tsconfig.json | 25 + .../astra/runs/B2/widget.tsx | 80 + .../astra/runs/B3/REPORT.md | 13 + .../astra/runs/B3/clicks.actions | 26 + .../astra/runs/B3/reset.actions | 33 + .../astra/runs/B3/tsconfig.json | 25 + .../astra/runs/B3/widget.tsx | 85 + .../astra/runs/B4/REPORT.md | 18 + .../astra/runs/B4/clicks.actions | 26 + .../astra/runs/B4/reset.actions | 33 + .../astra/runs/B4/tsconfig.json | 25 + .../astra/runs/B4/widget.tsx | 78 + .../astra/runs/C1/REPORT.md | 24 + .../astra/runs/C1/clicks.actions | 26 + .../astra/runs/C1/reset.actions | 33 + .../astra/runs/C1/tsconfig.json | 25 + .../astra/runs/C1/widget.tsx | 58 + .../astra/runs/C2/REPORT.md | 15 + .../astra/runs/C2/clicks.actions | 26 + .../astra/runs/C2/reset.actions | 33 + .../astra/runs/C2/tsconfig.json | 25 + .../astra/runs/C2/widget.tsx | 54 + .../astra/runs/C3/REPORT.md | 14 + .../astra/runs/C3/clicks.actions | 26 + .../astra/runs/C3/reset.actions | 33 + .../astra/runs/C3/tsconfig.json | 25 + .../astra/runs/C3/widget.tsx | 63 + .../astra/runs/C4/REPORT.md | 26 + .../astra/runs/C4/clicks.actions | 26 + .../astra/runs/C4/reset.actions | 33 + .../astra/runs/C4/tsconfig.json | 25 + .../astra/runs/C4/widget.tsx | 59 + .../render-loop-cadence/astra/usage.tsv | 11 + .../canvas-probe/cp-display-plain/capture.png | Bin 0 -> 76953 bytes .../cp-display-plain/capture.snapshot.txt | 8 + .../canvas-probe/cp-display-plain/widget.tsx | 10 + .../canvas-probe/cp-one/none.png | Bin 0 -> 67343 bytes .../canvas-probe/cp-one/none.snapshot.txt | 9 + .../canvas-probe/cp-one/tick.png | Bin 0 -> 67343 bytes .../canvas-probe/cp-one/tick.snapshot.txt | 9 + .../canvas-probe/cp-one/ticks2.png | Bin 0 -> 67343 bytes .../canvas-probe/cp-one/ticks2.snapshot.txt | 9 + .../canvas-probe/cp-one/widget.tsx | 15 + .../canvas-probe/cp-pair/none.png | Bin 0 -> 86563 bytes .../canvas-probe/cp-pair/none.snapshot.txt | 11 + .../canvas-probe/cp-pair/tick.png | Bin 0 -> 86563 bytes .../canvas-probe/cp-pair/tick.snapshot.txt | 11 + .../canvas-probe/cp-pair/ticks2.png | Bin 0 -> 86563 bytes .../canvas-probe/cp-pair/ticks2.snapshot.txt | 11 + .../canvas-probe/cp-pair/widget.tsx | 19 + .../canvas-probe/cp-shrink/tick.png | Bin 0 -> 76953 bytes .../canvas-probe/cp-shrink/tick.snapshot.txt | 8 + .../canvas-probe/cp-shrink/widget.tsx | 24 + .../canvas-probe/probe1/capture.png | Bin 0 -> 76953 bytes .../canvas-probe/probe1/capture.snapshot.txt | 11 + .../canvas-probe/probe1/widget.tsx | 23 + .../canvas-probe/tick.actions | 1 + .../canvas-probe/ticks2.actions | 1 + .../render-loop-cadence/clicks.actions | 8 + .../render-loop-cadence/common-prompt.md | 40 + experiments/render-loop-cadence/cond-A.md | 2 + experiments/render-loop-cadence/cond-B.md | 2 + experiments/render-loop-cadence/cond-C.md | 7 + .../final-captures/A1-after.png | Bin 0 -> 256283 bytes .../final-captures/A1-after.snapshot.txt | 49 + .../final-captures/A1-initial.png | Bin 0 -> 256283 bytes .../final-captures/A1-initial.snapshot.txt | 49 + .../final-captures/A2-after.png | Bin 0 -> 256283 bytes .../final-captures/A2-after.snapshot.txt | 49 + .../final-captures/A2-initial.png | Bin 0 -> 256283 bytes .../final-captures/A2-initial.snapshot.txt | 49 + .../final-captures/B1-after.png | Bin 0 -> 256283 bytes .../final-captures/B1-after.snapshot.txt | 49 + .../final-captures/B1-initial.png | Bin 0 -> 256283 bytes .../final-captures/B1-initial.snapshot.txt | 49 + .../final-captures/B2-after.png | Bin 0 -> 256283 bytes .../final-captures/B2-after.snapshot.txt | 50 + .../final-captures/B2-initial.png | Bin 0 -> 256283 bytes .../final-captures/B2-initial.snapshot.txt | 50 + .../final-captures/B3-after.png | Bin 0 -> 256283 bytes .../final-captures/B3-after.snapshot.txt | 49 + .../final-captures/B3-initial.png | Bin 0 -> 256283 bytes .../final-captures/B3-initial.snapshot.txt | 49 + .../final-captures/B4-after.png | Bin 0 -> 256283 bytes .../final-captures/B4-after.snapshot.txt | 49 + .../final-captures/B4-initial.png | Bin 0 -> 256283 bytes .../final-captures/B4-initial.snapshot.txt | 49 + .../final-captures/C1-after.png | Bin 0 -> 256283 bytes .../final-captures/C1-after.snapshot.txt | 96 + .../final-captures/C1-initial.png | Bin 0 -> 256283 bytes .../final-captures/C1-initial.snapshot.txt | 96 + .../final-captures/C2-after.png | Bin 0 -> 256283 bytes .../final-captures/C2-after.snapshot.txt | 52 + .../final-captures/C2-initial.png | Bin 0 -> 256283 bytes .../final-captures/C2-initial.snapshot.txt | 52 + .../final-captures/C3-after.png | Bin 0 -> 256283 bytes .../final-captures/C3-after.snapshot.txt | 49 + .../final-captures/C3-initial.png | Bin 0 -> 256283 bytes .../final-captures/C3-initial.snapshot.txt | 49 + .../final-captures/C4-after.png | Bin 0 -> 256283 bytes .../final-captures/C4-after.snapshot.txt | 52 + .../final-captures/C4-initial.png | Bin 0 -> 256283 bytes .../final-captures/C4-initial.snapshot.txt | 52 + experiments/render-loop-cadence/grade-prep.sh | 37 + .../panel-probe/panel-probe.png | Bin 0 -> 96193 bytes .../panel-probe/panel-probe.snapshot.txt | 15 + .../panel-probe/widget.tsx | 22 + .../render-loop-cadence/runs/A1/REPORT.md | 49 + .../render-loop-cadence/runs/A1/widget.tsx | 120 ++ .../render-loop-cadence/runs/A2/REPORT.md | 70 + .../render-loop-cadence/runs/A2/widget.tsx | 124 ++ .../render-loop-cadence/runs/B1/REPORT.md | 34 + .../render-loop-cadence/runs/B1/widget.tsx | 110 ++ .../render-loop-cadence/runs/B2/REPORT.md | 58 + .../render-loop-cadence/runs/B2/widget.tsx | 101 + .../render-loop-cadence/runs/B3/REPORT.md | 73 + .../render-loop-cadence/runs/B3/widget.tsx | 118 ++ .../render-loop-cadence/runs/B4/REPORT.md | 37 + .../render-loop-cadence/runs/B4/widget.tsx | 106 + .../render-loop-cadence/runs/C1/REPORT.md | 54 + .../render-loop-cadence/runs/C1/widget.tsx | 123 ++ .../render-loop-cadence/runs/C2/REPORT.md | 54 + .../render-loop-cadence/runs/C2/widget.tsx | 106 + .../render-loop-cadence/runs/C3/REPORT.md | 48 + .../render-loop-cadence/runs/C3/widget.tsx | 103 + .../render-loop-cadence/runs/C4/REPORT.md | 24 + .../render-loop-cadence/runs/C4/widget.tsx | 121 ++ experiments/render-loop-cadence/usage.tsv | 10 + .../render-loop-cadence/watch-saves.mjs | 15 + 294 files changed, 21595 insertions(+) create mode 100644 experiments/render-loop-cadence/BRIEF-FOR-ASTRA.md create mode 100644 experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md create mode 100644 experiments/render-loop-cadence/DECISIONS.md create mode 100644 experiments/render-loop-cadence/GATES.tsv create mode 100644 experiments/render-loop-cadence/MAPPING.txt create mode 100644 experiments/render-loop-cadence/PROTOCOL.md create mode 100644 experiments/render-loop-cadence/REPORT.md create mode 100644 experiments/render-loop-cadence/SYNTHESIS.md create mode 100644 experiments/render-loop-cadence/astra/GATES.tsv create mode 100644 experiments/render-loop-cadence/astra/MAPPING.txt create mode 100644 experiments/render-loop-cadence/astra/MEASUREMENTS.tsv create mode 100644 experiments/render-loop-cadence/astra/NOTES.md create mode 100644 experiments/render-loop-cadence/astra/SCORES.md create mode 100644 experiments/render-loop-cadence/astra/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/evidence/A1-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/A1-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/A1-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/A2-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/A2-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/A2-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B1-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B1-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B1-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B2-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B2-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B2-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B3-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B3-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B3-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B4-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B4-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/B4-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C1-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C1-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C1-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C2-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C2-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C2-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C3-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C3-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C3-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C4-commands.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C4-tool-results.json create mode 100644 experiments/render-loop-cadence/astra/evidence/C4-usage.json create mode 100644 experiments/render-loop-cadence/astra/evidence/artifact-sha256.json create mode 100644 experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/clock/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/pomodoro/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/evidence/authoring-inputs/sdk/CONTRACT.md create mode 100644 experiments/render-loop-cadence/astra/evidence/command-audit.json create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/BRIEF-FOR-ASTRA.md create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/PROTOCOL.md create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/common-prompt.md create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/cond-A.md create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/cond-B.md create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/cond-C.md create mode 100755 experiments/render-loop-cadence/astra/evidence/experiment-inputs/grade-prep.sh create mode 100644 experiments/render-loop-cadence/astra/evidence/experiment-inputs/watch-saves.mjs create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C1-02.combined-output.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C1-02.receipt.json create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C2-03.combined-output.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C2-03.receipt.json create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C3-03.combined-output.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C3-03.receipt.json create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C4-04.combined-output.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/C4-04.receipt.json create mode 100644 experiments/render-loop-cadence/astra/evidence/failed-captures/index.json create mode 100644 experiments/render-loop-cadence/astra/evidence/git-diff-before.patch create mode 100644 experiments/render-loop-cadence/astra/evidence/git-status-after.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/git-status-before.txt create mode 100644 experiments/render-loop-cadence/astra/evidence/prompt-verification.json create mode 100644 experiments/render-loop-cadence/astra/evidence/toolchain-after.json create mode 100644 experiments/render-loop-cadence/astra/evidence/toolchain-before.json create mode 100644 experiments/render-loop-cadence/astra/evidence/verification.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/A1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/A2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B3-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/B4-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C3-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-after.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-after.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-initial.png create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-initial.receipt.json create mode 100644 experiments/render-loop-cadence/astra/final-captures/C4-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/astra/harness/collect-usage.py create mode 100644 experiments/render-loop-cadence/astra/harness/events.jsonl create mode 100644 experiments/render-loop-cadence/astra/harness/extract-commands.cjs create mode 100644 experiments/render-loop-cadence/astra/harness/final-recapture.py create mode 100644 experiments/render-loop-cadence/astra/harness/schedule.json create mode 100644 experiments/render-loop-cadence/astra/harness/watch-saves.mjs create mode 100644 experiments/render-loop-cadence/astra/harness/watcher-process.json create mode 100644 experiments/render-loop-cadence/astra/prompts/A1.md create mode 100644 experiments/render-loop-cadence/astra/prompts/A2.md create mode 100644 experiments/render-loop-cadence/astra/prompts/B1.md create mode 100644 experiments/render-loop-cadence/astra/prompts/B2.md create mode 100644 experiments/render-loop-cadence/astra/prompts/B3.md create mode 100644 experiments/render-loop-cadence/astra/prompts/B4.md create mode 100644 experiments/render-loop-cadence/astra/prompts/C1.md create mode 100644 experiments/render-loop-cadence/astra/prompts/C2.md create mode 100644 experiments/render-loop-cadence/astra/prompts/C3.md create mode 100644 experiments/render-loop-cadence/astra/prompts/C4.md create mode 100644 experiments/render-loop-cadence/astra/runs/A1/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/A1/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/A1/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/A2/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/A2/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/A2/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/B1/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/B1/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B1/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B1/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/B1/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/B2/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/B2/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B2/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B2/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/B2/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/B3/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/B3/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B3/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B3/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/B3/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/B4/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/B4/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B4/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/B4/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/B4/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/C1/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/C1/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C1/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C1/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/C1/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/C2/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/C2/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C2/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C2/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/C2/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/C3/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/C3/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C3/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C3/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/C3/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/runs/C4/REPORT.md create mode 100644 experiments/render-loop-cadence/astra/runs/C4/clicks.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C4/reset.actions create mode 100644 experiments/render-loop-cadence/astra/runs/C4/tsconfig.json create mode 100644 experiments/render-loop-cadence/astra/runs/C4/widget.tsx create mode 100644 experiments/render-loop-cadence/astra/usage.tsv create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-display-plain/widget.tsx create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/none.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/none.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/tick.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/tick.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-one/widget.tsx create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/none.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/none.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/tick.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/tick.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-pair/widget.tsx create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.png create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/cp-shrink/widget.tsx create mode 100644 experiments/render-loop-cadence/canvas-probe/probe1/capture.png create mode 100644 experiments/render-loop-cadence/canvas-probe/probe1/capture.snapshot.txt create mode 100644 experiments/render-loop-cadence/canvas-probe/probe1/widget.tsx create mode 100644 experiments/render-loop-cadence/canvas-probe/tick.actions create mode 100644 experiments/render-loop-cadence/canvas-probe/ticks2.actions create mode 100644 experiments/render-loop-cadence/clicks.actions create mode 100644 experiments/render-loop-cadence/common-prompt.md create mode 100644 experiments/render-loop-cadence/cond-A.md create mode 100644 experiments/render-loop-cadence/cond-B.md create mode 100644 experiments/render-loop-cadence/cond-C.md create mode 100644 experiments/render-loop-cadence/final-captures/A1-after.png create mode 100644 experiments/render-loop-cadence/final-captures/A1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/A1-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/A1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/A2-after.png create mode 100644 experiments/render-loop-cadence/final-captures/A2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/A2-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/A2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B1-after.png create mode 100644 experiments/render-loop-cadence/final-captures/B1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B1-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/B1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B2-after.png create mode 100644 experiments/render-loop-cadence/final-captures/B2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B2-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/B2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B3-after.png create mode 100644 experiments/render-loop-cadence/final-captures/B3-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B3-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/B3-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B4-after.png create mode 100644 experiments/render-loop-cadence/final-captures/B4-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/B4-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/B4-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C1-after.png create mode 100644 experiments/render-loop-cadence/final-captures/C1-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C1-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/C1-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C2-after.png create mode 100644 experiments/render-loop-cadence/final-captures/C2-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C2-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/C2-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C3-after.png create mode 100644 experiments/render-loop-cadence/final-captures/C3-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C3-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/C3-initial.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C4-after.png create mode 100644 experiments/render-loop-cadence/final-captures/C4-after.snapshot.txt create mode 100644 experiments/render-loop-cadence/final-captures/C4-initial.png create mode 100644 experiments/render-loop-cadence/final-captures/C4-initial.snapshot.txt create mode 100755 experiments/render-loop-cadence/grade-prep.sh create mode 100644 experiments/render-loop-cadence/panel-probe/panel-probe.png create mode 100644 experiments/render-loop-cadence/panel-probe/panel-probe.snapshot.txt create mode 100644 experiments/render-loop-cadence/panel-probe/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/A1/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/A1/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/A2/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/A2/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/B1/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/B1/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/B2/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/B2/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/B3/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/B3/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/B4/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/B4/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/C1/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/C1/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/C2/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/C2/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/C3/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/C3/widget.tsx create mode 100644 experiments/render-loop-cadence/runs/C4/REPORT.md create mode 100644 experiments/render-loop-cadence/runs/C4/widget.tsx create mode 100644 experiments/render-loop-cadence/usage.tsv create mode 100644 experiments/render-loop-cadence/watch-saves.mjs diff --git a/.gitignore b/.gitignore index 3f9e2dd5..598b1e91 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ Thumbs.db # Syncthing .stfolder/ .stignore + +# Agent worktrees +.claude/worktrees/ diff --git a/experiments/render-loop-cadence/BRIEF-FOR-ASTRA.md b/experiments/render-loop-cadence/BRIEF-FOR-ASTRA.md new file mode 100644 index 00000000..769e8870 --- /dev/null +++ b/experiments/render-loop-cadence/BRIEF-FOR-ASTRA.md @@ -0,0 +1,143 @@ +# Briefing for Astra: the render-loop cadence bench + +You are being asked to run the second half of a two-model experiment on Weaver, +a desktop widget platform authored in TSX (repo: `/Users/dara/Dev/Projects/weaver`). +Fable (Claude) ran the first half with 10 Opus sub-agents. You run the same +protocol with your own sub-agents. Fable then grades both sets blind and Dara +synthesizes. This file tells you everything the bench is and why, so you can run +it without asking. Read `PROTOCOL.md` in this folder for the exact spec, and +`common-prompt.md` plus `cond-A.md`, `cond-B.md`, `cond-C.md` for the exact +prompts the Opus agents received. Reuse those prompts verbatim so the two runs +differ only in model. + +## The question + +Weaver has an agent skill, `.agents/skills/conjure-widget/SKILL.md`, that tells +an authoring agent how to build a widget. Part of that skill is the **Render +loop**: run `weaver check`, run `weaver capture` (a headless renderer that +publishes a PNG, a semantic snapshot, and a JSON receipt), open the PNG, look at +it, fix what you see. The skill currently asks for that loop after every edit +that can change pixels. + +Dara wants to know, from measurement rather than intuition: + +1. Does an agent build a better widget when it can see rendered pixels at all? +2. If so, is it enough to look once at the end, or does looking during the + build change the result? +3. What does each cadence cost in tokens, tool calls, and wall time? + +There is a second motive. Dara wants the user to watch the widget take shape on +the desktop while the agent works. Agents tend to write the whole widget in one +chunk, so nothing visibly builds. If progressive capture turns out to be free or +better, the skill can ask for it and the incremental build comes along for free. + +## The design + +One spec, one toolchain, one model, three conditions, fresh directory per +agent, no shared context between agents, no `weaver dev` (the live desktop +view) for anyone. + +- **A check-only.** May run `weaver check` freely. Never runs `weaver capture`. + Never sees pixels or a snapshot. +- **B final-capture.** Writes the whole widget first, then runs the Render loop + and iterates until satisfied. +- **C progressive-capture.** Runs the Render loop after each of four visual + slices: frame and header, day cells, progress bar, buttons plus the + after-clicks state. + +Allocation: A×2, B×4, C×4. B versus C is the contrast that matters. A is the +control that tells us whether pixels matter at all. + +The widget is "Focus Week": a 320×200 habit tracker with a header, seven +equal-width day cells with today highlighted, a progress bar with a "N / 20" +label, and "Log session" and "Reset week" buttons backed by `useStorage`. It +was chosen for layout traps that static checks cannot catch: seven cells +filling a fixed width, text legibility on a dark surface, a label that must not +overlap the bar, a fixed height budget with four stacked regions. + +Capture inputs are fixed so every run produces comparable evidence: clock +`2026-09-04T09:41:00.000Z` (a Friday), an empty storage root for the initial +state, and `clicks.actions` (three clicks on "Log session") for the after-clicks +state. Expected after-clicks: Friday 3, others 0, "3 / 20", bar at 15%. + +## What each agent must leave behind + +`widget.tsx`, a `captures/` folder with every capture it ran (numbered, never +overwritten, so the file count is a receipt for how often it looked), and a +`REPORT.md` with check count, capture count, defects fixed because of pixels, +unmet spec items, and self-confidence 0 to 10. The prompts already ask for this. + +## What the orchestrator (you) must record + +These receipts are what make the numbers comparable across the two models: + +- **Saves.** A watcher that polls each run's `widget.tsx` mtime and size every + 500 ms and appends a line per change. Fable's is `watch-saves.mjs`, referenced + in `PROTOCOL.md`; the Opus log is `saves.log` here. Self-reported save counts + are not accepted. +- **Per-agent usage.** Tokens, tool calls, wall time. Whatever your harness + exposes; record it in a `usage.tsv` with one line per run. +- **Uniform re-capture.** After all agents finish, you (not the agents) re-run + `weaver check` and both captures for every run with the fixed inputs, so + grading uses identical evidence regardless of what the agent captured. +- **Objective gates** per run: check passes, both receipts `status: "ok"`, + snapshot contains buttons named exactly "Log session" and "Reset week", + after-clicks snapshot contains "3 / 20". + +Fable's `grade-prep.sh` did the re-capture, gates, and anonymization in one +pass; its logic is described in `PROTOCOL.md` under Measurement. + +## Grading + +Fable grades. Do not grade your own run. Fable copies every run's final +captures and source to anonymized names, scores them on the six-item rubric in +`PROTOCOL.md` (0 to 3 each, 18 max), and only then reads the mapping. Your job +is to leave the raw material in a shape that makes that possible. + +## Where to put your run + +`experiments/render-loop-cadence/astra/` with the same layout as the Opus run: +`runs//` (source, report, captures), `usage.tsv`, `saves.log`, `GATES.tsv`, +and a short `NOTES.md` on anything that deviated from the protocol. + +## Environment rules + +- Run every `npx --no-install weaver ...` command from the repo root. From a + widget directory `npx` fails with an unrelated resolution error that several + Opus agents mistook for a widget problem. +- Do not modify any file under the repo other than your `astra/` folder. Do not + run `weaver dev`. Agents write widgets under `/tmp/weaver-exp-astra/runs//` + (not `/tmp/weaver-exp/`, which still holds the Opus run) and you archive + them into `astra/runs/` afterwards. Substitute that root for `` in the + prompts. +- Your harness runs three children at a time, so your 10 agents run in batches. + Record the batch schedule in `NOTES.md` and report per-agent wall time from + dispatch to completion, not from experiment start. The Opus run had all 10 + in parallel. +- Do not update the toolchain. The Opus run used Weaver commit `ab20771` with + `runtime/native-sdk` at `464ff65f`. Same commits, or the replicate is not a + replicate. Confirm with `git rev-parse --short HEAD` and + `git submodule status runtime/native-sdk`. +- Do not fix framework bugs your agents hit, even obvious ones. Record them. + The Opus run hit several and they are part of the + result. + +## What not to read until your run is finished + +`REPORT.md` in this folder holds the Opus results, scores, and the framework +findings. Reading it before your agents run would let you steer around what +Opus hit. Read it afterwards to sanity-check that your receipts line up with +Fable's, then leave the comparison to Fable. + +## Model and effort + +Use whatever sub-agent model you would normally use for widget authoring, at +the effort you would normally use. Record both in `NOTES.md`. The Opus run +used Opus at default effort. + +## If something is unclear + +Write the question into `astra/NOTES.md` under "Questions before running", +answer it yourself with the most conservative reading of `PROTOCOL.md`, state +the assumption, and proceed. Dara would rather have a run with stated +assumptions than no run. diff --git a/experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md b/experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md new file mode 100644 index 00000000..f225f814 --- /dev/null +++ b/experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md @@ -0,0 +1,110 @@ +# Framework finding: a canvas never keeps its layout size + +Three Astra agents, working independently, wrote the idiomatic thing for a +progress bar in a flex row, ``, saw a blank +bar in capture, and "fixed" it by hardcoding a pixel width. Every shipped +example hardcodes canvas widths too, which is why nobody had noticed. This is +a framework defect, not an agent blind spot. Receipts are in `canvas-probe/`. + +## What happens + +1. **Mount.** The SDK creates the canvas binding with the class-declared size: + `instance.props.width ?? 0` (`sdk/src/reconciler.ts:719`). For `w-0 grow` + that is 0. The first draw runs at 0×8 and paints nothing. +2. **Layout.** Native SDK lays the row out and gives the canvas 181×8. The + snapshot reports those bounds. The runtime has a read-back path for this: + `syncNativeState` (`runtime/src/main.zig:563`) compares each canvas's layout + frame with the last one it saw and fires `onCanvasResize` to JS when it + changed. The SDK handler (`reconciler.ts:217`) updates the binding and + redraws. So far, correct by design. +3. **Timing.** `syncNativeState` runs only inside Native SDK's `syncModel`, + which runs at the start of `dispatch`, `drainEffects`, and `rebuild` + (`runtime/native-sdk/src/runtime/ui_app.zig:1106,1159,1284`). Nothing + runs it after the layout pass itself. A widget with no timers, providers, + or input never dispatches after its first frame, so the resize never + fires. Capture with a fixed clock is exactly that widget. +4. **The clobber.** When a dispatch does happen and the resize fires, the + canvas draws once at 181×8. Then the component re-renders (a time tick, a + state change) and `updateCanvasBinding` runs again for the canvas + (`reconciler.ts:785-789`). It overwrites `binding.width` and + `binding.height` with the declared size, 0×8, rebuilds the context, and + redraws immediately at 0×8 (`reconciler.ts:812`). The bar goes blank. +5. **No recovery.** The runtime fires the resize only when the layout value + changes (`tree.zig:977`). The layout has not changed. The canvas stays + blank until something else moves the layout. + +The draw log from `cp-one` shows the whole sequence. Its label re-renders once +per clock tick and prints every width the draw callback has seen so far: + +| Ticks | Draw widths seen | Bar in the PNG | +|---|---|---| +| 0 | 0 | blank | +| 1 | 0, 181 | blank (the post-render redraw at 0 came after the label) | +| 2 | 0, 181, 0, 183 | blank | + +The resize refired at tick 2 only because the label text got wider and moved +the layout by 2px. In Focus Week nothing moves, so the bar is blank forever. + +## Why the display-rate probes looked fine + +`cp-pair` puts a one-shot canvas and an `fps="display"` canvas in the same +widget. Both render full width, before and after ticks. The display canvas +keeps a frame chain running, every frame is a dispatch, every dispatch runs +`syncModel`, and the re-render clobber is repaired on the next frame because +the surface clock redraws with whatever the binding holds at that moment. It +works by accident of cadence. Remove the display canvas and the one-shot +canvas is blank again (`cp-one`). + +## This is not capture-only + +Live is not verified on screen (my desktop screenshot missed the window), but +the code path is the same: a live Focus Week widget subscribes to `time`, so +the first tick after launch delivers the resize and the same tick's re-render +clobbers it. Live has the same blank bar. Capture did not lie to the agents. +It showed them the real bug, and then the contract's advice to use explicit +pixel sizes taught them to route around it. + +`CanvasNeedsExplicitSize` in `cli/src/index.ts:2859` is the tell. Its message +says "a percentage resolves against 0 and every draw silently no-ops +(ctx.width === 0)". The check knows about the silent zero and forbids two of +the ways to reach it. `w-0 grow` is a third way it does not forbid. The check +is a patch over this defect. + +## The fix, in order + +Landed as unmde/weaver#78, steps 1 to 4 together. + +1. **SDK: never overwrite a layout-delivered size with a declared one.** + `updateCanvasBinding` should treat the declared size as the initial guess + at mount only. On update, keep `binding.width`/`binding.height` unless the + declared size itself changed. This alone fixes the clobber and makes + `w-0 grow` work in every widget that dispatches at least once. +2. **Runtime: deliver canvas layout after every layout pass, not at the next + dispatch.** Run the canvas part of `syncNativeState` after `rebuild` + computes layout, and request a frame when any canvas resized. This fixes + static widgets, including every fixed-clock capture, and removes the + dependence on a stray tick. +3. **Check: delete `CanvasNeedsExplicitSize`** once 1 and 2 land, and update + the contract so a canvas is sized by layout like every other element. + Explicit sizes stay allowed; they stop being required. +4. **Capture: make the receipt say what the pixels cannot.** Record, per + canvas, the size its last draw used and the size layout gave it. Emit a + warning when they differ. A blank bar with a receipt line reading + `canvas #12 drew at 0×8, layout gave 181×8` is a diagnosis. A blank bar + alone is a guess. This is the capture-mechanic change that would have + handed three agents the fix instead of a workaround. + +## Probes + +All in `canvas-probe/`, each with source, PNG, and snapshot: + +- `probe1`: lone `w-0 grow` canvas, no dispatch. Blank. +- `cp-display-plain`: lone `fps="display"` grow canvas. Full. +- `cp-pair`: one-shot and display canvases together, 0/1/2 ticks. Both full. +- `cp-one`: lone one-shot canvas with draw log, 0/1/2 ticks. Blank; log shows + the 181 draw and the 0 redraw. +- `cp-shrink` (`canvas-probe7`): canvas declared 300px, layout gives 144px, + one tick. Draw callback still sees 300. Declared sizes that disagree with + layout are wrong in the other direction too. + +Toolchain: Weaver `ab20771`, Native SDK `464ff65f`, macOS headless capture. diff --git a/experiments/render-loop-cadence/DECISIONS.md b/experiments/render-loop-cadence/DECISIONS.md new file mode 100644 index 00000000..01babaef --- /dev/null +++ b/experiments/render-loop-cadence/DECISIONS.md @@ -0,0 +1,169 @@ +# Open decisions from the render-loop cadence run, with evidence + +Three findings were left open after PRs #76, #77, #78 because they looked +like design calls. Evidence gathered 2026-09-05. One of them turned out to be +a bug with a one-line fix and zero impact on shipped examples, so it became +PR #79. The other two are real decisions and are laid out below with the +receipts and a recommendation. + +## 1. A data-driven width has no supported route (finding 3) + +Decision taken: option B. Landed as unmde/weaver#80 (stacked on #78). + +### What happens today + +`weaver check` requires every `class` to resolve statically to at most 32 +literal strings (`cli/src/index.ts:835`), so it can validate every utility +before the widget runs. The resolver follows string literals, `const` +bindings, ternaries, `+` concatenation, and template literals whose holes are +themselves resolvable. A width computed from data, `w-[${px}px]`, resolves to +nothing and fails with: + +``` +class must resolve to at most 32 literal strings so weaver check can validate every utility +``` + +The message names the cap and not a route. Twenty agents building the same +progress bar produced six workarounds: `` (14 runs), a 21-branch +ternary ladder of literal widths (3), a `w-N/20` fraction table (1), a +gradient hard stop at a computed fraction (1), and a 20-tick meter (1). All +twenty needed a data-driven width; none found the same door. + +### What the runtime already does + +- `compileClass` in `sdk/src/class-compiler.ts` runs at render time whenever + an element's class string changes (`reconciler.ts:546-551`). It is the same + compiler `check` uses. It parses `w-[43.7px]` to `{width: 43.7}` and rejects + `w-[-5px]`, `w-[abcpx]`, `w-[1e3px]`, and `w-[15%]` with a named + `UtilityError` and a suggestion. `w-[1000000px]` is accepted. +- An unknown utility at runtime throws through `runWidgetCallback`, which + fails the widget onto its error surface. Capture reports it as + `CaptureWidgetFailed` with the diagnostic. It is loud. +- Cost, measured with the compiler bundled in isolation: 1000 distinct + dynamic class strings compile in 6.16 ms, about 6 µs each. A bar whose width + changes once per second recompiles once per second. +- Twelve utilities accept a bracketed arbitrary value: `w`, `h`, `size`, + `p`/`px`/`py`/…, `m`…, `gap`, `rounded`, `border`, `text`, `leading`, + `tracking`, `grow`, `aspect`, `shadow`, `font`, `bg`/`from`/`via`/`to`. + +### Options + +**A. Keep the cap, fix the message.** Name the doors: `w-N/M` fractions for +quantized values, `` for continuous geometry, the typed `background` +gradient hard stop. Zero runtime change. Agents still write 21-branch ladders +when the data is continuous, and every canvas bar is a semantic hole (no +node in the tree, pixels are its only receipt). + +**B. Typed holes in arbitrary values (recommended).** Let a template hole +appear only inside a bracketed arbitrary value of a known utility, and only +when TypeScript types the hole as `number`: `w-[${px}px]` passes, `${cls}` +does not. `check` still knows every utility statically. The value is +validated at runtime by the same compiler, which already rejects bad values +loudly, at 6 µs per change. The check has a `TypeChecker` in hand already +(`cli/src/index.ts:2523`). Contract gains one sentence. This is the smallest +change that lets a progress bar be one `` with a real width. + +**C. A `style` prop.** A parallel styling system for one use case. Two ways +to say width, two validators, two documentation surfaces. Not recommended. + +### Evidence to run before B ships + +A check unit test for the accepted and rejected hole shapes, and one capture +smoke where a `w-[${n}px]` bar re-renders across a tick and the snapshot +bounds move. Both are cheap and sit beside the tests added in #78. + +## 2. `npx --no-install weaver` outside the repo tree (finding 6) + +Decision taken: A and B together. Landed as unmde/weaver#82; the skill side is #81. + +### What happens + +From any directory inside the repo, including `examples/clock`, `npx +--no-install weaver` resolves the workspace bin (`node_modules/.bin/weaver` +→ `cli/bin/weaver.js`, version 0.1.0) and works. From `/tmp`, where every +experiment widget lived, npm walks up, finds no workspace, and consults the +registry: + +``` +npm error npx canceled due to missing packages and no YES option: ["weaver@0.3.1"] +``` + +That `weaver@0.3.1` is not ours. The public npm package `weaver` is an +"Interactive process management system" last published 2022-06-28. Without +`--no-install`, `npx weaver` in a widget directory would download and run a +stranger's package. `--no-install` is the only thing standing between an agent +following the skill and that outcome, and its failure message reads like our +CLI is missing. `weaver` is not on `PATH` (`which weaver`: not found), and +`weaver init` prints `Next: weaver check ` as if it were. + +Scoped names are free on the registry: `@weaver/cli`, `@weaver/sdk`, and +`@weaver/weaver` all return 404. The root `package.json` is `private: true`, +so nothing publishes today. + +### Options + +**A. Link the bin during setup (recommended, do now).** `npm run build` +already exists; add `npm link --workspace cli` (or a documented one-time +`npm link`) so `weaver` is on `PATH` for anyone who has built the repo. The +skill and `init`'s "Next:" line then say `weaver check ` and mean it. +Keep `npx --no-install` as a fallback in the skill for unlinked checkouts, +with a sentence that it only works inside the repo tree. + +**B. Rename the CLI package to a scoped name.** `@weaver/cli` with bin +`weaver`. Kills the registry collision permanently, so a future `npx +@weaver/cli` can never run someone else's code. Independent of A and worth +doing before anything publishes; irrelevant to the agents' failure until then. + +**C. Absolute path in the skill.** `node /cli/bin/weaver.js`. Works +everywhere, ugly, and every doc that says `weaver …` still lies. + +Recommendation: A now, B before first publish. + +## 3. Small boxes get ~2px corner rounding (finding 4): a bug, fixed in #79 + +### What happens + +Weaver maps an unset radius to `null` when projecting a painted box +(`runtime/src/main.zig:943`, `if (retained.radius > 0) … else null`), and +Native SDK reads `null` as "use the theme radius", whose smallest token is +6 px (`tokens.zig:385`). `rounded-[0px]` sets 0, which the same test treats +as unset. So every painted box without a `rounded-*` class is rounded, and +`rounded-[0px]` cannot turn it off. On a 320 px card that is invisible. On a +14 px progress segment it is a scallop, which is what two Opus agents saw and +one redesigned its bar around. + +### Receipt + +Probe `canvas-probe/../round`: five 8 px bars. Per-column count of accent +pixels, first 48 columns: + +| Variant | master | unset-radius-is-zero | +|---|---|---| +| 20 gapless `grow` segments in a `rounded-full overflow-hidden` track | `468888888888863468888…` | `468888888888888888888…` | +| same, `rounded-[0px]` on each segment | `468888888888863468888…` | `888888888888888888888…` | +| same, no radius class | `468888888888863468888…` | `888888888888888888888…` | +| single fill | `468888888888888888888…` | `888888888888888888888…` | +| 20 `w-[14px]` segments | `468888888888634688888…` | `888888888888888888888…` | + +On master every segment boundary loses two to four rows at both ends. With the +fix, only the track's own `rounded-full` clip rounds anything. + +### Impact on shipped examples + +Same widget sources, same fixtures, same clock, two runtime binaries built +from the same commit with only line 943 changed: + +| Example | Pixels changed | +|---|---| +| clock | 0 of 42,240 | +| pomodoro | 0 of 103,200 | +| weather | 0 of 67,840 | +| system | 0 of 66,640 | +| now-playing | 0 of 52,800 | +| round probe | 796 of 38,400 | + +Every shipped example specifies its radii. Nothing depends on the theme +default. The decision "unset radius means 0, like CSS" has no cost, so it is +not a decision. PR #79 makes the change, adds a runtime test that a painted +box without a rounded utility projects radius 0, and states the default in +the contract. diff --git a/experiments/render-loop-cadence/GATES.tsv b/experiments/render-loop-cadence/GATES.tsv new file mode 100644 index 00000000..ee38a9c2 --- /dev/null +++ b/experiments/render-loop-cadence/GATES.tsv @@ -0,0 +1,10 @@ +C4 check=weaver check passed: /tmp/weaver-exp/runs/C4 initial=ok after=ok buttons=2 label3of20=1 captures=8 saves=12 lines=121 first=2026-09-05T01:16:21.728Z last=2026-09-05T01:20:21.140Z +C3 check=weaver check passed: /tmp/weaver-exp/runs/C3 initial=ok after=ok buttons=2 label3of20=1 captures=6 saves=7 lines=103 first=2026-09-05T01:16:19.225Z last=2026-09-05T01:19:42.076Z +B1 check=weaver check passed: /tmp/weaver-exp/runs/B1 initial=ok after=ok buttons=2 label3of20=1 captures=4 saves=5 lines=110 first=2026-09-05T01:16:19.225Z last=2026-09-05T01:18:48.996Z +B2 check=weaver check passed: /tmp/weaver-exp/runs/B2 initial=ok after=ok buttons=2 label3of20=1 captures=5 saves=4 lines=101 first=2026-09-05T01:16:14.716Z last=2026-09-05T01:20:34.659Z +C1 check=weaver check passed: /tmp/weaver-exp/runs/C1 initial=ok after=ok buttons=2 label3of20=1 captures=13 saves=12 lines=123 first=2026-09-05T01:16:20.728Z last=2026-09-05T01:23:16.453Z +A1 check=weaver check passed: /tmp/weaver-exp/runs/A1 initial=ok after=ok buttons=2 label3of20=1 captures=0 saves=6 lines=120 first=2026-09-05T01:18:48.496Z last=2026-09-05T01:25:49.219Z +B3 check=weaver check passed: /tmp/weaver-exp/runs/B3 initial=ok after=ok buttons=2 label3of20=1 captures=8 saves=3 lines=118 first=2026-09-05T01:16:23.733Z last=2026-09-05T01:20:52.693Z +C2 check=weaver check passed: /tmp/weaver-exp/runs/C2 initial=ok after=ok buttons=2 label3of20=1 captures=11 saves=15 lines=106 first=2026-09-05T01:16:25.737Z last=2026-09-05T01:22:56.915Z +A2 check=weaver check passed: /tmp/weaver-exp/runs/A2 initial=ok after=ok buttons=2 label3of20=1 captures=0 saves=5 lines=124 first=2026-09-05T01:20:39.166Z last=2026-09-05T01:22:55.913Z +B4 check=weaver check passed: /tmp/weaver-exp/runs/B4 initial=ok after=ok buttons=2 label3of20=1 captures=5 saves=4 lines=106 first=2026-09-05T01:16:18.223Z last=2026-09-05T01:21:27.251Z diff --git a/experiments/render-loop-cadence/MAPPING.txt b/experiments/render-loop-cadence/MAPPING.txt new file mode 100644 index 00000000..3914ee1f --- /dev/null +++ b/experiments/render-loop-cadence/MAPPING.txt @@ -0,0 +1,10 @@ +w01 C4 +w02 C3 +w03 B1 +w04 B2 +w05 C1 +w06 A1 +w07 B3 +w08 C2 +w09 A2 +w10 B4 diff --git a/experiments/render-loop-cadence/PROTOCOL.md b/experiments/render-loop-cadence/PROTOCOL.md new file mode 100644 index 00000000..5754263b --- /dev/null +++ b/experiments/render-loop-cadence/PROTOCOL.md @@ -0,0 +1,112 @@ +# Render-loop cadence experiment + +Question: does an authoring agent produce a better Weaver widget when it looks +at rendered pixels during the build, only at the end, or never? + +Every run builds the same widget from the same spec on the same toolchain. +Only the capture cadence changes. Agents never run `weaver dev`. + +## Conditions + +- **A check-only.** The agent may run `weaver check` as often as it likes. It + never runs `weaver capture` and never sees pixels or a snapshot. It stops + when it believes the widget matches the spec. +- **B final-capture.** The agent writes the whole widget first. Only when it + believes the widget is complete does it run the Render loop (check, capture + both states, open the PNGs, read the snapshots). It may then fix and + re-capture as many rounds as it wants. +- **C progressive-capture.** The agent runs the Render loop after each visual + slice, in this order: (1) frame and header, (2) day cells, (3) progress bar, + (4) buttons and the after-clicks state. It may re-capture within a slice. + +Allocation for a 10-agent run: A×2, B×4, C×4. Same model, same effort, fresh +directory per agent, no shared context between agents. + +## Widget spec (identical for every run) + +Name: **Focus Week**. Size **320×200**. Anchor top-right, offset 24,24. + +1. Header row. Left: the title "Focus week". Right, aligned to the same + baseline: the current weekday and date, for example "Fri, Sep 4". +2. Seven day cells in one row, Monday through Sunday, equal width, filling the + available width. Each cell shows the weekday letter (M T W T F S S) above + that day's session count. Today's cell is visibly highlighted. Days with + zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, + with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. + Secondary: "Reset week" sets every day to zero. Both have native `hover:` + and `pressed:` styles. Counts persist across restarts with `useStorage`. +5. Visual bar: the shipped examples' house style. Dark translucent surface, + rounded corners, restrained palette, clear hierarchy, nothing clipped or + overlapping, text legible at 1× scale. + +Data: `time` provider for today. Weekday comes from `time.weekday` (short +name). Session counts keyed by weekday. No other providers, no network. + +## Capture inputs (fixed for every run) + +- Clock: `--clock 2026-09-04T09:41:00.000Z` (a Friday). +- State `initial`: no actions, isolated empty storage. +- State `after-clicks`: action file `clicks.actions`: + +```json +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { "action": "click", "target": { "role": "button", "name": "Log session" } }, + { "action": "click", "target": { "role": "button", "name": "Log session" } }, + { "action": "click", "target": { "role": "button", "name": "Log session" } } + ] +} +``` + +Expected after-clicks state: Friday shows 3, every other day 0, label "3 / 20", +bar at 15%. + +## Commands + +From the Weaver repository root, with `` the run's widget directory: + +```sh +npx --no-install weaver init +npx --no-install weaver check +npx --no-install weaver capture --clock 2026-09-04T09:41:00.000Z --out /captures/NN-initial.png +npx --no-install weaver capture --clock 2026-09-04T09:41:00.000Z --action-file /clicks.actions --out /captures/NN-after-clicks.png +``` + +`NN` is a zero-padded counter that increments on every capture the agent +runs, so the capture files are the receipt for how many times it looked. + +## What each agent must leave behind + +- `/widget.tsx` (the deliverable). +- `/captures/` (every capture it ran; empty for condition A). +- `/REPORT.md` with: condition letter, number of `weaver check` runs, + number of `weaver capture` runs, a list of every defect it fixed *because it + saw pixels or a snapshot* (B and C only), any spec item it could not meet + and why, and its own confidence (0 to 10) that the widget matches the spec. + +## Measurement (done by the grader, not the agent) + +- A watcher records every `widget.tsx` save (mtime and byte size) per run, so + save counts and wall time do not rely on self-report. +- After all runs finish the grader re-captures both states for every run with + the same inputs, so grading uses identical evidence for every condition. +- Captures are copied to anonymized names and graded before the condition + mapping is unmasked. + +## Rubric (0 to 3 each, 18 max) + +1. Spec completeness: every numbered item present and behaving. +2. Layout: no overlap, clipping, or misalignment; the seven cells fill the row. +3. Hierarchy and type: title, date, counts, labels read in the intended order. +4. Surface and color: house style, contrast, highlight of today is obvious. +5. Interaction proof: after-clicks state is exactly as expected; semantic tree + exposes both buttons by name. +6. Code: one literal `widget()` export, no dead code, no hacks around the + contract. + +Objective gates recorded alongside: `weaver check` passes; both receipts have +`status: "ok"`; snapshot contains buttons named "Log session" and "Reset week"; +after-clicks snapshot shows "3 / 20". diff --git a/experiments/render-loop-cadence/REPORT.md b/experiments/render-loop-cadence/REPORT.md new file mode 100644 index 00000000..c576a3a3 --- /dev/null +++ b/experiments/render-loop-cadence/REPORT.md @@ -0,0 +1,141 @@ +# Render-loop cadence: Opus run, 2026-09-04 + +> Combined two-model synthesis is in `SYNTHESIS.md`. Astra's replicate and its blind grades are under `astra/`. + +Ten Opus agents, one spec (Focus Week, 320×200), one toolchain, three capture +cadences. See `PROTOCOL.md` for the design, `common-prompt.md` and `cond-*.md` +for the exact agent prompts, `runs//` for each agent's `widget.tsx` and +self-report, `final-captures/` for the grader's uniform re-captures, and +`GATES.tsv`, `usage.tsv`, `saves.log` for the receipts behind every number. + +Grading was done on anonymized copies (`MAPPING.txt`) before unmasking. + +## Result table + +| Run | Cond | Score /18 | Captures | Saves | Tokens | Tool uses | Wall (min) | Self-confidence | +|---|---|---|---|---|---|---|---|---| +| A1 | check-only | **10** | 0 | 6 | 109.5k | 56 | 10.6 | 7 | +| A2 | check-only | 18 | 0 | 5 | 97.3k | 44 | 8.1 | 7 | +| B1 | final | 17 | 4 | 5 | 68.4k | 33 | 3.8 | 9 | +| B2 | final | 18 | 5 | 4 | 80.7k | 48 | 6.0 | 9 | +| B3 | final | 18 | 8 | 3 | 90.2k | 44 | 6.5 | 9 | +| B4 | final | 17 | 5 | 4 | 84.7k | 42 | 6.6 | 9 | +| C1 | progressive | 16 | 13 | 12 | 80.8k | 55 | 8.2 | 9 | +| C2 | progressive | 17 | 11 | 15 | 84.9k | 59 | 7.8 | 9 | +| C3 | progressive | 18 | 6 | 7 | 67.7k | 40 | 4.8 | 9 | +| C4 | progressive | 17 | 8 | 12 | 62.6k | 38 | 5.0 | 9 | + +| Cond | Mean score | Worst | Mean tokens | Mean wall | Mean captures | Mean saves | +|---|---|---|---|---|---|---| +| A check-only | 14.0 | 10 | 103k | 9.3 min | 0 | 5.5 | +| B final | 17.5 | 17 | 81k | 5.7 min | 5.5 | 4.0 | +| C progressive | 17.0 | 16 | 74k | 6.4 min | 9.5 | 11.5 | + +All ten passed every objective gate: `weaver check` ok, both receipts +`status: "ok"`, both buttons exposed by exact name, after-clicks label "3 / 20". +The gates cannot tell A1 from the others. Only pixels can. + +## Rubric notes per run + +- **A1 (10).** Weekday letters render underneath the counts at identical bounds + and both are pinned top-left in 55px-tall cells. Cause: `` stacks its + children instead of laying them out as a column, contrary to + `sdk/CONTRACT.md` lines 127 and 604. Reproduced in `panel-probe/`. The agent + derived its layout from the Zig layout source and never saw the result. + Self-confidence 7/10 did not flag it. +- **A2 (18).** Clean. Canvas progress bar. Proof that a blind agent *can* land + it; A1 is proof there is no net when it does not. +- **B1 (17).** Clean; dimmest weekday letters of the set. +- **B2, B3 (18).** Clean. B3's captures caught a 2px width error from assuming + the 1px border consumed layout space. +- **B4 (17).** Clean; outlined secondary button at equal visual weight to the + primary weakens hierarchy slightly. +- **C1 (16).** Shipped a 20-tick meter instead of a continuous bar after + concluding a continuous fill was impossible. It is not (C2, C4, A1, A2 and all + B runs did it four different ways), so this is a wrong conclusion drawn from + a real renderer quirk, see framework findings. +- **C2 (17).** Clean; 21-branch literal ladder for the fill width. +- **C3 (18).** Clean; used slice-3 snapshot bounds to size the buttons to the + space that was actually left. +- **C4 (17).** Clean; 21-branch ladder. Slice-2 capture caught a `grow` day row + that had swallowed the whole widget. + +## What pixels caught, by condition + +- **Every capturing agent (7 of 8) raised text alphas after seeing 1× pixels.** + Secondary text at `/35` to `/40` opacity is illegible on the house dark + surface, and no agent predicted that from source. Both A agents shipped at + those alphas. +- **B (final) found:** legibility (B1, B2, B4), 2px width miscalculation (B3), + label crowding the bar (B4). No structural defects, so nothing that would + have benefited from an earlier look. +- **C (progressive) found:** a `grow` row eating the layout (C4, slice 2), a + would-be button clip caught from snapshot bounds before the buttons existed + (C3, slice 3), the segmented-bar pill artifact (C1, C2, slice 3), plus the + same legibility fixes. C agents also used intermediate snapshot bounds as a + budget for the next slice. + +## Reading + +1. **Seeing pixels is necessary.** Worst case without them is a broken widget + that passes every static and semantic gate with 7/10 self-confidence. The + two A agents also spent the most tokens and time of any condition, because + they compensated by reading runtime source to predict layout. +2. **Final-only and progressive tie on final quality at n=4.** 17.5 vs 17.0 is + inside the noise of one rubric point. Both have a worst case of 16 or 17. +3. **Progressive is not more expensive in tokens.** It runs roughly twice the + captures and three times the saves, yet averaged fewer tokens than B (74k vs + 81k) and similar wall time. Captures are cheap; the agent's reasoning is the + cost, and early pixels appear to shorten it. +4. **Progressive catches structural mistakes when they are cheap.** C4's `grow` + row and C3's height budget were fixed with two elements on screen. A B agent + making the same mistake would fix it in a full tree. None did in this run, + so this is mechanism, not a measured effect. +5. **Progressive can also mislead.** C1 saw a renderer quirk mid-build and + redesigned the spec item around it. More looks means more chances to + over-react to what is seen. +6. **Progressive produces the visible incremental build for free.** Every C + run saved 7 to 15 times in slices that each rendered. That is exactly the + "watch it take shape" effect the Live loop wants, with no quality or token + penalty measured here. + +## Framework findings surfaced by the run + +1. **`` stacks children.** Contract says column layout. Minimal repro in + `panel-probe/`: two texts inside a `` get identical bounds; the same + texts inside a `` lay out correctly. Landmine: A1 detonated it. +2. **The 32-literal class cap has no obvious route for a data-driven width.** + Ten agents produced five workarounds: `` (5 runs), 21-branch literal + ladder (2), `w-N/20` fraction table (1), gradient hard stop (1), tick meter + (1). The check error names the cap but not a supported path. DX gap. +3. **Small boxes get ~2px corner rounding that `rounded-[0px]` does not + remove.** Observed independently by C1 and C2 on 14px-wide segments inside + an `overflow-hidden` track. Worth a renderer look. +4. **`key` on an intrinsic element is a TS error.** Hit by 4 of 10 agents; each + lost a check round to it. +5. **`CanvasNeedsExplicitSize` rejects `w-full`.** Hit by 2 agents. The message + worked; both fixed it in one round. +6. **`npx --no-install weaver` fails from the widget directory.** Several agents + lost a call to a wrong-cwd npx error. Not a widget error, so easy to misread. + +## Recommendation for the conjure-widget skill + +- Keep the Render loop mandatory at completion. Condition A is the argument. +- Move from "capture after every pixel-changing edit" to a slice cadence: + capture the first coherent frame, capture each added visual region, capture + every requested state at the end. This is condition C, which cost nothing + measurable and is the honest source of a progressive build on the desktop. +- Add one line to the skill: when a capture shows a renderer behavior that + contradicts the contract, report it as a framework reproduction and keep + the spec item; do not redesign around it (the C1 failure mode). +- Add a legibility floor to the house-style guidance: secondary text on the + dark surface at `/45` or above. Seven of eight agents converged on this + number after looking. + +## Limits + +n=2/4/4 on one spec and one model. The spec had one layout trap the pixels +were needed for (dim text) and one the contract lied about (panel). A spec with +more layout risk would likely widen the B vs C gap in C's favor; a simpler one +would narrow A's deficit. The GPT run on the same protocol is the second +sample. diff --git a/experiments/render-loop-cadence/SYNTHESIS.md b/experiments/render-loop-cadence/SYNTHESIS.md new file mode 100644 index 00000000..1dba85bb --- /dev/null +++ b/experiments/render-loop-cadence/SYNTHESIS.md @@ -0,0 +1,154 @@ +# Render-loop cadence: two-model synthesis + +Twenty agents built the same widget from the same spec on the same toolchain +under three capture cadences. Ten were Opus (default effort, orchestrated by +Fable, all ten in parallel). Ten were gpt-6-astra (high effort, orchestrated by +Astra, batches of three). Fable graded all twenty blind on the same rubric. +Receipts: `REPORT.md` and `runs/` for Opus, `astra/SCORES.md` and `astra/` for +Astra, `PROTOCOL.md` for the design. + +## Scores, all twenty runs + +| Cond | n | Opus | Astra | Combined mean | Worst | +|---|---|---|---|---|---| +| A check-only | 4 | 10, 18 | 18, 18 | 16.0 | **10** | +| B final capture | 8 | 17, 18, 18, 17 | 18, 17, 18, 18 | 17.6 | 17 | +| C progressive | 8 | 16, 17, 18, 17 | 18, 18, 18, 16 | 17.25 | 16 | + +## Cost by condition, relative to B within each model + +| | Opus wall | Opus tokens | Astra wall | Astra tool calls | Astra output tokens | +|---|---|---|---|---|---| +| A | 1.6× | 1.3× | 0.8× | 0.7× | 0.7× | +| B | 1.0× | 1.0× | 1.0× | 1.0× | 1.0× | +| C | 1.1× | 0.9× | 1.4× | 1.6× | 1.3× | + +Absolute numbers are in each model's table. Opus's tokens are the harness +aggregate; Astra's output tokens are the closest comparable column. + +## Answers to the three questions + +**1. Do agents build better widgets when they can see pixels?** +Pixels are a net, not a lift. Three of four blind runs scored a perfect 18. +The fourth shipped day cells with the letters drawn under the counts, passed +every static and semantic gate, and reported 7/10 confidence. Nothing but a +PNG catches that. Whether the net is worth its cost depends on how often the +blind agent falls, and at n=4 the answer is "one in four, with a wide interval". +For Opus the blind runs were also the most expensive: the agents read Zig +layout source to predict what a capture shows in half a second. + +**2. Is looking once at the end enough, or does looking during the build +change the result?** +On final quality, no difference. B led C by a fraction of a point in both +models, inside noise. The lowest-scoring capturing run in each model was a C +run, and both lost points the same way: they saw something mid-build and +redesigned around it. Opus C1 replaced the progress bar with a tick meter after +a renderer quirk; Astra C4 shrank the title to match the date's text metrics +and flattened its own hierarchy. Two data points, same mechanism: more looks +means more chances to over-fit to the current frame. On the other side, Opus C4 +caught a `grow` row swallowing the widget at slice 2, and Opus C3 sized its +buttons from slice-3 snapshot bounds. Progressive catches structural mistakes +while they are cheap, and also invites cosmetic churn. + +**3. What does each cadence cost?** +Model-dependent. Opus C was cost-neutral against B. Astra C cost 1.4× the +wall time and 1.6× the tool calls of B. Astra's blind runs were the cheapest +of all twenty; Opus's blind runs were the most expensive of its ten. + +## What pixels caught, by model + +The catch lists barely overlap, which says the value of looking is in the +agent's blind spots, not in a fixed checklist: + +- **Opus:** legibility at 1× in seven of eight capturing runs, a `grow` row + eating the layout, a 2px border-arithmetic error, and the segmented-bar pill + artifact. Zero legibility fixes were needed by Astra; every Astra draft + shipped secondary text at `/60` or above. +- **Astra:** a `w-0 grow` canvas that has layout bounds but paints nothing, in + three of eight capturing runs. No Opus run used a grow-sized canvas. Also one + 2px canvas-versus-track mismatch and one header-metrics alignment. + +Both models needed the PNG and the snapshot together. The Opus panel bug was +visible in snapshot bounds (two texts, identical bounds) but the agent never +looked. The Astra canvas bug was invisible in the snapshot (correct nonzero +bounds) and only the PNG showed the blank. + +## The visible-build motive + +Progressive capture produced 7 saves per widget for Astra and 11.5 for Opus, +against 4 for final-capture in both models. Each save under condition C +rendered a coherent partial widget. That is the "watch it take shape" effect, +produced by the honest loop. The price is zero to 40% more wall time depending +on the model, and no measured quality change. + +## Framework findings, both runs + +1. **`` stacks its children.** Contract says column layout. Repro in + `panel-probe/`. Detonated by Opus A1. Astra used `` once, for a bar + fill with no children, so it never triggered. +2. **A canvas never keeps its layout size.** The SDK seeds the canvas with + its class-declared size, the runtime delivers the real layout size only at + the next dispatch, and every re-render overwrites the delivered size with + the declared one and redraws blank. `w-0 grow` therefore paints nothing in + any static widget and in any time-driven widget after its first tick, in + capture and live alike. Every shipped example hardcodes canvas widths, + which is why it went unnoticed. Full mechanism, draw-log receipts, and a + four-step fix in `CANVAS-LAYOUT-SIZE.md`; probes in `canvas-probe/`. Hit + by three Astra agents, who were then steered by the contract into + hardcoding widths. `CanvasNeedsExplicitSize` is a patch over this defect. +3. **The 32-literal class cap has no obvious route for a data-driven width.** + Twenty agents, six workarounds: `` (14 runs), literal ladder (3), + `w-N/20` fraction table (1), gradient hard stop (1), tick meter (1). The + error names the cap but not a supported path. +4. **Small boxes get ~2px corner rounding that `rounded-[0px]` does not + remove.** Two independent Opus observations. +5. **`key` on an intrinsic element is a TypeScript error.** Hit by 4 Opus and + at least 4 Astra agents. Cheapest fix in the whole list. +6. **`npx --no-install weaver` fails from the widget directory** with an error + that reads like a widget problem. Several Opus agents lost a call to it. +7. **All four Astra C agents ran capture while check was failing.** Capture + published nothing and the agents recovered, so the DX held. Noted because + it shows agents treat check and capture as one step. + +## Recommendation for the conjure-widget skill + +- **Final Render loop is mandatory, with both the PNG and the snapshot read.** + The one broken widget in twenty passed everything else. +- **Replace "capture after every pixel-changing edit" with the four-slice + cadence tested here** when the user is meant to watch the build, and allow + final-only when they are not. Quality is the same either way; the slice + cadence buys the visible build for zero to 40% more wall time. +- **Add one guard against over-fitting to a frame:** fix what contradicts the + spec or the contract; report renderer behavior that contradicts the contract + as a framework reproduction and keep the spec item; do not redesign a spec + item to smooth over something that merely looks unfamiliar. Both models' + weakest capturing run broke this. +- **State a legibility floor for secondary text on the dark surface** (`/45` + or above). Seven of eight Opus agents converged on it after looking; Astra + was already there. +- **Fix findings 1, 2, and 5 before the next run.** They are the cheapest + wins and two of them are silent. + +## Fixes landed as PRs (2026-09-05) + +- Finding 1, `` stacks children: unmde/weaver#76. +- Finding 2, canvas never keeps its layout size: unmde/weaver#78 (SDK size + retention, runtime post-layout dispatch, `CanvasNeedsExplicitSize` retired, + `CanvasDrewForStaleLayout` capture warning, pixel-probe smoke fixture). +- Finding 5, `key` on intrinsic elements: unmde/weaver#77. +- Finding 4, small-box rounding: unmde/weaver#79. Evidence showed it was a bug + (unset radius mapped to the native theme default) with zero pixel impact on + shipped examples, not a decision. +- Finding 3, data-driven widths: unmde/weaver#80 adds a number-typed pixel + hole to `weaver check`. Finding 6, npx outside the tree: unmde/weaver#82 + puts `weaver` on PATH and scopes the package. The skill recommendations + above landed as unmde/weaver#81. Evidence and options in `DECISIONS.md`. + +## Limits + +Two models, one spec, n=2/4/4 per model. The spec had two landmines the +contract did not warn about, and each model tripped a different one. A spec +with more layout risk would likely separate B from C in C's favor; a simpler +spec would erase A's deficit entirely, as it nearly did for Astra. Astra ran +at high effort and Opus at default, so the cross-model comparison is +indicative, not controlled. Within-model comparisons are the ones to trust. diff --git a/experiments/render-loop-cadence/astra/GATES.tsv b/experiments/render-loop-cadence/astra/GATES.tsv new file mode 100644 index 00000000..b981933e --- /dev/null +++ b/experiments/render-loop-cadence/astra/GATES.tsv @@ -0,0 +1,11 @@ +run condition check_pass check_exit initial_status initial_exit initial_error after_clicks_status after_clicks_exit after_clicks_error initial_both_named_buttons after_clicks_both_named_buttons after_clicks_3_of_20 agent_published_pngs observed_saves first_observed_save_utc last_observed_save_utc widget_sha256 source_unchanged_by_recheck all_objective_gates +A1 A True 0 ok 0 ok 0 True True True 0 3 2026-09-05T15:30:45.439Z 2026-09-05T15:32:07.581Z c6a87be53dfe29ab461036e1bbf369abc17c257306ebef14d6b618433927ce18 True True +A2 A True 0 ok 0 ok 0 True True True 0 3 2026-09-05T15:37:28.761Z 2026-09-05T15:38:59.538Z 114dee45fbaeb5f335ef5ed09071a1aea057d3d2edc57fa9677cc5140cbceb3c True True +B1 B True 0 ok 0 ok 0 True True True 5 4 2026-09-05T15:30:29.910Z 2026-09-05T15:32:46.153Z 5dd994506d8345bf1ed89c1fcedfa2722e7ccf415f85ce95de54ac34a7baa619 True True +B2 B True 0 ok 0 ok 0 True True True 5 5 2026-09-05T15:37:24.249Z 2026-09-05T15:40:07.738Z 755a31cf203cffe571a784d725d34aab8e2c564db3c322fbf172eb0c0f91409b True True +B3 B True 0 ok 0 ok 0 True True True 5 4 2026-09-05T15:43:03.269Z 2026-09-05T15:45:05.645Z 75ef381b47dacf6c02d6bdf2c52a7fa44ec08b415ccd0247c65a507d0d6d0cd7 True True +B4 B True 0 ok 0 ok 0 True True True 3 3 2026-09-05T15:43:16.307Z 2026-09-05T15:44:45.576Z 6e02b5a6ceab77c4384fa4e74fa50073e7426590c79a5909eb20f363b19756d2 True True +C1 C True 0 ok 0 ok 0 True True True 7 8 2026-09-05T15:30:44.938Z 2026-09-05T15:34:31.339Z f53dc0b258f808fe8a7e041c3ac8768bdc58ac691bfcb5bda81e85e7b00dfbbf True True +C2 C True 0 ok 0 ok 0 True True True 6 6 2026-09-05T15:37:36.286Z 2026-09-05T15:40:24.286Z 7eedca57e692580b197beca8233409a1999530345101d462c5e420f8b4df14cb True True +C3 C True 0 ok 0 ok 0 True True True 6 6 2026-09-05T15:42:56.747Z 2026-09-05T15:45:45.763Z ce12b3d87d406972654b71ad9c82f3ae1e51cf31a81c73a1f27999854818dde7 True True +C4 C True 0 ok 0 ok 0 True True True 7 8 2026-09-05T15:48:09.204Z 2026-09-05T15:51:01.726Z af0df9e06014d0c3e53bd0a0c34be53dae47a96c4037ff20622555bb8a9a50f0 True True diff --git a/experiments/render-loop-cadence/astra/MAPPING.txt b/experiments/render-loop-cadence/astra/MAPPING.txt new file mode 100644 index 00000000..ebeafe54 --- /dev/null +++ b/experiments/render-loop-cadence/astra/MAPPING.txt @@ -0,0 +1,10 @@ +x01 B1 +x02 B2 +x03 B4 +x04 C3 +x05 A1 +x06 A2 +x07 C4 +x08 B3 +x09 C2 +x10 C1 diff --git a/experiments/render-loop-cadence/astra/MEASUREMENTS.tsv b/experiments/render-loop-cadence/astra/MEASUREMENTS.tsv new file mode 100644 index 00000000..d1095687 --- /dev/null +++ b/experiments/render-loop-cadence/astra/MEASUREMENTS.tsv @@ -0,0 +1,11 @@ +run condition batch checks capture_attempts published_captures observed_saves input_tokens cached_input_tokens output_tokens total_tokens model_tool_calls wall_seconds all_objective_gates +A1 A 1 2 0 0 3 262911 215680 2735 265646 8 180.184 True +A2 A 2 2 0 0 3 337510 303744 2628 340138 10 180.778 True +B1 B 1 3 5 5 4 421619 380160 4249 425868 10 222.055 True +B2 B 2 4 5 5 5 553963 502016 4192 558155 14 252.541 True +B3 B 3 3 5 5 4 660833 603520 4239 665072 16 257.123 True +B4 B 3 3 3 3 3 385415 360960 3563 388978 10 207.375 True +C1 C 1 8 8 7 8 1240717 1190912 5418 1246135 27 365.935 True +C2 C 2 6 7 6 6 691977 647552 4955 696932 16 293.542 True +C3 C 3 7 7 6 6 784341 714880 5011 789352 17 296.422 True +C4 C 4 9 8 7 8 860944 813952 5170 866114 19 325.005 True diff --git a/experiments/render-loop-cadence/astra/NOTES.md b/experiments/render-loop-cadence/astra/NOTES.md new file mode 100644 index 00000000..a1e37726 --- /dev/null +++ b/experiments/render-loop-cadence/astra/NOTES.md @@ -0,0 +1,48 @@ +# Astra render-loop cadence replicate + +Complete: ten independent `gpt-6-astra` agents at `high` reasoning effort, with allocation A×2 / B×4 / C×4. All ten pass every uniform objective gate. No subjective scores or cross-model quality conclusions were assigned; Fable owns blind grading. + +## Questions before running + +- **How to schedule ten agents with three child slots?** Four batches, listed below; each batch finished before the next began. C4 ran alone. Opus ran ten concurrently, so concurrency differs. +- **How to reuse prompts and isolate context?** Each agent used `fork_turns="none"`. Only `/tmp/weaver-exp` → `/tmp/weaver-exp-astra` and `` were substituted in the original prompt text. An identical one-sentence wrapper directed each agent to its own prompt file. Exact copies and verification hashes are archived. No agent received another run's findings, follow-up coaching, or the Opus results. +- **How to reconcile normal widget workflows?** The explicit benchmark rules override live rendering and framework repair: no `weaver dev`, only the assigned capture cadence, and no framework repairs. +- **What about condition A's folder?** Its exact prompt required `captures/` absent during authoring. It remains absent in both temporary A runs; an empty directory was added only to each archived copy. The A agents never received grader captures. +- **What does the watcher count?** The original watcher, with only paths substituted, polled mtime and size every 500 ms. `saves.log` records observed changes, including initialization. Multiple saves within one poll can coalesce; it is not a lossless filesystem trace. +- **What about existing checkout edits?** Both required commits matched: Weaver `ab20771`, Native SDK `464ff65f`. Existing contract/example and other edits were preserved. Their snapshots, hashes, and the pre/post tracked diff are archived. The tracked diff and recorded authoring inputs remained unchanged throughout. Matching commits does not establish that uncommitted inputs match Opus's earlier run. +- **What usage can be measured?** Harness token events, emitted model tool calls, and dispatch/completion timestamps were available for every run. No missing value was replaced with an estimate. + +## Batch schedule + +All times are UTC on 2026-09-05. Each run's precise dispatch, harness start, completion, and wall duration are in `usage.tsv`. + +| Batch | Runs | First dispatch | Last completion | +|---|---|---|---| +| 1 | A1, B1, C1 | 15:29:35 | 15:36:16 | +| 2 | A2, B2, C2 | 15:36:26 | 15:41:56 | +| 3 | B3, C3, B4 | 15:42:04 | 15:47:18 | +| 4 | C4 | 15:47:28 | 15:52:53 | + +## Measurements and provenance + +The agents made 47 checks and 48 capture attempts, producing 44 successful captures; four failed attempts produced no PNG. The watcher observed 50 saves. These totals exclude the orchestrator's subsequent ten checks and twenty uniform captures. Per-run values are in `MEASUREMENTS.tsv`; raw commands, token events, and textual tool outputs are in `evidence/`. + +`usage.tsv` uses final harness `total_token_usage` events. Input tokens include cached input; reasoning output is a subset of output. Neither subset should be added again. `model_tool_calls` counts emitted function/custom calls: one `functions.exec` call can contain several shell or image-tool operations. The AST command audit separately extracts literal shell-command inputs; all ten agents' reported check/capture counts match them. Wall time is harness completion minus the timestamp immediately before dispatch, including spawn latency, never time since experiment start. + +The Opus report and usage file were first read only after all Astra agents and the uniform recapture completed. Both sets report all objective gates passing; those gates do not establish visual quality. Opus's usage file exposes aggregate `tokens` and `tool_uses` without cache/accounting breakdown. Direct cross-model token or tool-count equivalence is therefore unverified. The models also use different platform/tool contexts and effort settings (Astra high, Opus default). + +## Protocol deviations and retained observations + +- Every C agent attempted one capture after a failed check: C1/02, C2/03, C3/03, C4/04. Each failed static validation, published no artifacts, and left a numbering gap. C2–C4 then attempted to open the absent image. These are recorded ordering failures, not successful render-loop passes. All agents recovered and inspected the required slices before proceeding. Reports, original tool outputs, and extracted failure receipts are preserved; none of the runs was restarted or coached. +- All eight B/C agents additionally captured three logs followed by Reset week. These extra captures remain in their usage totals and archives. Uniform grading uses only the two prescribed states and the unchanged three-click action file. +- B1, B3, and C1 reported an invisible grow-sized canvas despite nonzero semantic bounds, then used explicit canvas widths. The original captures and source-edit commands are retained. No framework diagnosis, repair, toolchain update, or PR was performed. +- Restart persistence was not independently tested: every capture intentionally uses isolated empty storage. The agents document that boundary and use the specified storage hook. + +## Handoff to Fable + +- `runs//`: unchanged submitted source, report, and every successful agent capture. Failed capture receipts live in `evidence/failed-captures/` because Weaver did not publish those attempts. +- `final-captures/-initial.*` and `-after.*`: flat copies matching the Opus grading layout. They are byte-identical to the uniform evidence under `final//`, which also retains full commands, exit codes, stdout, and stderr. Receipt paths refer to those original evidence files. +- `GATES.tsv`: all objective gates. `MEASUREMENTS.tsv`, `usage.tsv`, and `saves.log`: per-run receipts. `evidence/artifact-sha256.json` and `verification.json`: archive integrity and fixed-input checks. +- `prompts/`, `harness/`, and `evidence/experiment-inputs/`: reproducible inputs and measurement scripts. Authoring input snapshots are in `evidence/authoring-inputs/`. + +All twenty uniform PNGs are 320×200. Every receipt has the pinned commits, the specified clock, and `storage: "isolated-empty"`. All sources match their archived hashes and were unchanged by uniform verification. The watcher has been stopped. Raw material is ready for Fable to anonymize and grade; no mapping or subjective score has been generated by Astra. diff --git a/experiments/render-loop-cadence/astra/SCORES.md b/experiments/render-loop-cadence/astra/SCORES.md new file mode 100644 index 00000000..1bfc6634 --- /dev/null +++ b/experiments/render-loop-cadence/astra/SCORES.md @@ -0,0 +1,50 @@ +# Astra run: Fable's blind grades + +Graded 2026-09-05 from Fable's own uniform re-capture of each `runs//widget.tsx` +(clock 2026-09-04T09:41:00.000Z, empty storage, `clicks.actions`). Copies were +anonymized as x01..x10 (`MAPPING.txt`), scored on the PROTOCOL.md rubric, and the +scores were written to disk before the mapping was read. Fable's re-captures are +alongside Astra's under `final-captures/fable-recapture-*`; the two sets are +visually identical. + +| Run | Cond | Blind id | Score /18 | Note | +|---|---|---|---|---| +| A1 | check-only | x05 | 18 | clean | +| A2 | check-only | x06 | 18 | clean | +| B1 | final | x01 | 18 | clean; no bar caption, label only | +| B2 | final | x02 | 17 | both buttons equal width, primary loses emphasis | +| B3 | final | x08 | 18 | clean | +| B4 | final | x03 | 18 | clean; 20-branch `w-N/20` ladder, no canvas | +| C1 | progressive | x10 | 18 | clean | +| C2 | progressive | x09 | 18 | clean | +| C3 | progressive | x04 | 18 | clean | +| C4 | progressive | x07 | 16 | title shrunk to 14px to match date metrics; whole widget reads dimmer, hierarchy flattens | + +| Cond | Mean | Worst | Mean wall | Mean tool calls | Mean output tokens | Mean total tokens (cache-inclusive) | Captures | Saves | +|---|---|---|---|---|---|---|---|---| +| A | 18.0 | 18 | 3.0 min | 9 | 2.7k | 303k | 0 | 3 | +| B | 17.75 | 17 | 3.9 min | 12.5 | 4.1k | 510k | 4.5 | 4 | +| C | 17.5 | 16 | 5.3 min | 19.75 | 5.1k | 900k | 6.5 | 7 | + +Wall time is dispatch to completion per agent, from Astra's `usage.tsv`. Astra +ran in batches of three; Opus ran ten in parallel. Astra's token totals include +cached input and are not comparable to the Opus token column. + +## Pixel-driven fixes reported by Astra's agents + +- B1, B3, C1: progress canvas sized `w-0 grow` had nonzero semantic bounds but + painted nothing. Fixed with an explicit pixel width. Reproduced by Fable in + `../canvas-probe/`. +- B2: canvas 286px inside a 288px track; snapshot exposed the 2px gap. +- C4: title and date had different vertical metrics; both set to 14px. +- B4, C2, C3: none. A1, A2: not applicable. + +No Astra agent reported a legibility fix. All ten shipped secondary text at +`/60` or above from the first draft. + +## Observations outside the rubric + +All ten widgets share one palette (the pomodoro example's teal), one layout, +and near-identical structure. Astra treats the shipped examples as the house +style and reproduces it closely. Opus varied accent and structure across runs. +Astra's sources are 54 to 85 lines against Opus's 101 to 124. diff --git a/experiments/render-loop-cadence/astra/clicks.actions b/experiments/render-loop-cadence/astra/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/A1-commands.json b/experiments/render-loop-cadence/astra/evidence/A1-commands.json new file mode 100644 index 00000000..18efe084 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/A1-commands.json @@ -0,0 +1,56 @@ +[ + { + "timestamp": "2026-09-05T15:29:52.685Z", + "call_id": "call_K4TcibQMiWDjahlv45S5Hz3y", + "command": "cat /tmp/weaver-exp-astra/prompts/A1.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:05.880Z", + "call_id": "call_anAwFGOUZSFxs6RsUvSiNlyh", + "command": "cat .agents/skills/conjure-widget/SKILL.md; rg -n 'Module shape|widget\\(config, component\\)|Hooks|Consolidated v0.4 authoring tables|useStorage|PR 11: native interaction states and press events' sdk/CONTRACT.md; cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:12.520Z", + "call_id": "call_9yEwtHV77gi0OFTMiQv99WeA", + "command": "sed -n '1,115p' sdk/CONTRACT.md; sed -n '398,440p' sdk/CONTRACT.md; sed -n '538,765p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:44.815Z", + "call_id": "call_PHsfN1RX2MxSpYfhJV5Ws4Fc", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/A1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:44.815Z", + "call_id": "call_PHsfN1RX2MxSpYfhJV5Ws4Fc", + "command": "rg -n 'fillRect|CanvasCtx|accessibilityLabel' sdk/CONTRACT.md; cat /tmp/weaver-exp-astra/runs/A1/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:52.718Z", + "call_id": "call_pbqHFPNmXKOZ2jXehZeNnCj8", + "command": "sed -n '319,363p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:54.600Z", + "call_id": "call_RicrFtazBY3XsK1NDlZH9lrm", + "command": "cat > /tmp/weaver-exp-astra/runs/A1/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget } from \"@weaver/sdk\";\n\ntype Weekday = \"Mon\" | \"Tue\" | \"Wed\" | \"Thu\" | \"Fri\" | \"Sat\" | \"Sun\";\ntype Counts = Record;\nconst days: Weekday[] = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\nconst emptyWeek: Counts = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 };\nconst goal = 20;\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [counts, setCounts] = useStorage(\"sessions-by-weekday\", emptyWeek);\n const today = time.weekday as Weekday;\n const total = days.reduce((sum, day) => sum + counts[day], 0);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day) => (\n \n {day[0]}\n {counts[day]}\n \n ))}\n \n\n \n \n WEEKLY SESSIONS\n {total} / {goal}\n \n {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff14\");\n if (total > 0) {\n ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / goal, 1), ctx.height, 3, \"#5eead4\");\n }\n }} />\n \n\n \n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:07.033Z", + "call_id": "call_dtYZukSyZl0JyXS05itUFNuJ", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path('/tmp/weaver-exp-astra/runs/A1/widget.tsx')\ns = p.read_text().replace(' /tmp/weaver-exp-astra/runs/A1/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: A (check-only).\n- `weaver check` runs: 2. Final check passed.\n- `weaver capture` runs: 0. No captures directory created.\n- Defects fixed because of pixels or a snapshot: none.\n- Check-driven fixes: removed unsupported JSX `key`; gave the canvas an explicit 286 px width, calculated from the 320 px widget minus 32 px horizontal padding and 2 px border.\n- Spec items not met: none known. Visual layout, click results, native state feedback, and restart persistence were not observed because this condition permits only static checks. The implementation uses weekday-keyed persistent counts, native hover and pressed styles, and the time provider only.\n- Confidence: 8 / 10. The final source passes the authoritative static check, but visual and interaction behavior remain unverified.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/A1-tool-results.json b/experiments/render-loop-cadence/astra/evidence/A1-tool-results.json new file mode 100644 index 00000000..7ba32b2e --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/A1-tool-results.json @@ -0,0 +1,118 @@ +[ + { + "timestamp": "2026-09-05T15:29:52.800Z", + "call_id": "call_K4TcibQMiWDjahlv45S5Hz3y", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"601d72\",\"wall_time_seconds\":0.000007709,\"exit_code\":0,\"original_token_count\":1219,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/A1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/A1`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/A1` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/A1/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/A1/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/A1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/A1/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/A1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/A1/clicks.actions --out /tmp/weaver-exp-astra/runs/A1/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/A1/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: A (check-only)\\nYou may run `weaver check` as often as you like. You must NEVER run `weaver capture`, and you never see pixels or a snapshot. Build from the contract, the examples and your own reasoning. Stop when you believe the widget matches the spec. Leave /tmp/weaver-exp-astra/runs/A1/captures absent.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:05.958Z", + "call_id": "call_anAwFGOUZSFxs6RsUvSiNlyh", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"58f1c4\",\"wall_time_seconds\":0.000002834,\"exit_code\":0,\"original_token_count\":4258,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n20:## Module shape\\n43:## `widget(config, component)`\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\nimport { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:12.676Z", + "call_id": "call_9yEwtHV77gi0OFTMiQv99WeA", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"099ef1\",\"wall_time_seconds\":0.000003042,\"exit_code\":0,\"original_token_count\":4706,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n body?: string;\\n}): Promise<{ status: number; ok: boolean; text(): Promise; json(): Promise }>;\\n```\\n\\n- HTTPS only. The URL's host must exactly match an entry in `config.origins`;\\n otherwise the promise rejects with\\n `OriginNotDeclared: add \\\"api.example.com\\\" to origins in your widget config`.\\n- `weaver check` statically flags string-literal fetch URLs whose host is not\\n declared. Runtime enforcement is authoritative.\\n- Timeout 15s. No cookies; redirects are returned rather than followed; total\\n request and response caps are 5 MB each.\\n\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n\\n```ts\\nuseProvider(\\\"cpu\\\") // { percent: number, perCore: number[] } 1 Hz\\nuseProvider(\\\"memory\\\") // { usedMb: number, totalMb: number, percent: number } 1 Hz\\n```\\n\\nDelivered by `weaverd` (the host). `time` remains SDK-local. Subscribing\\nwithout the host running is a runtime error that names the fix (`weaver up`);\\n`weaver dev` auto-starts the host.\\n\\n`cpu.percent` is whole-machine utilization from 0\u2013100, not the sum of cores;\\n`perCore` reports the same 0\u2013100 utilization for each logical core. Memory\\n`usedMb` is physical memory that is not currently free or reclaimable idle\\ncache, `totalMb` is installed physical memory, and `percent` is their ratio.\\nThese meanings stay platform-neutral even though each host uses its public OS\\ncounters to project them.\\n\\n## The host and its CLI verbs\\n\\n```\\nweaver up | down start/stop weaverd (singleton, tray-less in M2)\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A1\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:32:07.033Z", + "type": "custom_tool_call", + "call_id": "call_dtYZukSyZl0JyXS05itUFNuJ", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nfrom pathlib import Path\\np = Path('/tmp/weaver-exp-astra/runs/A1/widget.tsx')\\ns = p.read_text().replace(' /tmp/weaver-exp-astra/runs/A1/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: A (check-only).\\n- `weaver check` runs: 2. Final check passed.\\n- `weaver capture` runs: 0. No captures directory created.\\n- Defects fixed because of pixels or a snapshot: none.\\n- Check-driven fixes: removed unsupported JSX `key`; gave the canvas an explicit 286 px width, calculated from the 320 px widget minus 32 px horizontal padding and 2 px border.\\n- Spec items not met: none known. Visual layout, click results, native state feedback, and restart persistence were not observed because this condition permits only static checks. The implementation uses weekday-keyed persistent counts, native hover and pressed styles, and the time provider only.\\n- Confidence: 8 / 10. The final source passes the authoritative static check, but visual and interaction behavior remain unverified.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:29:52.801Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 0, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 0, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:05.959Z", + "info": { + "total_token_usage": { + "input_tokens": 39801, + "cached_input_tokens": 7808, + "cache_write_input_tokens": 0, + "output_tokens": 229, + "reasoning_output_tokens": 54, + "total_tokens": 40030 + }, + "last_token_usage": { + "input_tokens": 20598, + "cached_input_tokens": 7808, + "cache_write_input_tokens": 0, + "output_tokens": 190, + "reasoning_output_tokens": 54, + "total_tokens": 20788 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:12.677Z", + "info": { + "total_token_usage": { + "input_tokens": 65509, + "cached_input_tokens": 28288, + "cache_write_input_tokens": 0, + "output_tokens": 299, + "reasoning_output_tokens": 54, + "total_tokens": 65808 + }, + "last_token_usage": { + "input_tokens": 25708, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 70, + "reasoning_output_tokens": 0, + "total_tokens": 25778 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:45.166Z", + "info": { + "total_token_usage": { + "input_tokens": 96288, + "cached_input_tokens": 53760, + "cache_write_input_tokens": 0, + "output_tokens": 698, + "reasoning_output_tokens": 355, + "total_tokens": 96986 + }, + "last_token_usage": { + "input_tokens": 30779, + "cached_input_tokens": 25472, + "cache_write_input_tokens": 0, + "output_tokens": 399, + "reasoning_output_tokens": 301, + "total_tokens": 31178 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:52.786Z", + "info": { + "total_token_usage": { + "input_tokens": 127835, + "cached_input_tokens": 84352, + "cache_write_input_tokens": 0, + "output_tokens": 754, + "reasoning_output_tokens": 369, + "total_tokens": 128589 + }, + "last_token_usage": { + "input_tokens": 31547, + "cached_input_tokens": 30592, + "cache_write_input_tokens": 0, + "output_tokens": 56, + "reasoning_output_tokens": 14, + "total_tokens": 31603 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:55.215Z", + "info": { + "total_token_usage": { + "input_tokens": 160120, + "cached_input_tokens": 115712, + "cache_write_input_tokens": 0, + "output_tokens": 2209, + "reasoning_output_tokens": 535, + "total_tokens": 162329 + }, + "last_token_usage": { + "input_tokens": 32285, + "cached_input_tokens": 31360, + "cache_write_input_tokens": 0, + "output_tokens": 1455, + "reasoning_output_tokens": 166, + "total_tokens": 33740 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:07.731Z", + "info": { + "total_token_usage": { + "input_tokens": 194091, + "cached_input_tokens": 147840, + "cache_write_input_tokens": 0, + "output_tokens": 2411, + "reasoning_output_tokens": 599, + "total_tokens": 196502 + }, + "last_token_usage": { + "input_tokens": 33971, + "cached_input_tokens": 32128, + "cache_write_input_tokens": 0, + "output_tokens": 202, + "reasoning_output_tokens": 64, + "total_tokens": 34173 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:25.851Z", + "info": { + "total_token_usage": { + "input_tokens": 228337, + "cached_input_tokens": 181632, + "cache_write_input_tokens": 0, + "output_tokens": 2682, + "reasoning_output_tokens": 634, + "total_tokens": 231019 + }, + "last_token_usage": { + "input_tokens": 34246, + "cached_input_tokens": 33792, + "cache_write_input_tokens": 0, + "output_tokens": 271, + "reasoning_output_tokens": 35, + "total_tokens": 34517 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:36.143Z", + "info": { + "total_token_usage": { + "input_tokens": 262911, + "cached_input_tokens": 215680, + "cache_write_input_tokens": 0, + "output_tokens": 2735, + "reasoning_output_tokens": 634, + "total_tokens": 265646 + }, + "last_token_usage": { + "input_tokens": 34574, + "cached_input_tokens": 34048, + "cache_write_input_tokens": 0, + "output_tokens": 53, + "reasoning_output_tokens": 0, + "total_tokens": 34627 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/A2-commands.json b/experiments/render-loop-cadence/astra/evidence/A2-commands.json new file mode 100644 index 00000000..11109c8e --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/A2-commands.json @@ -0,0 +1,62 @@ +[ + { + "timestamp": "2026-09-05T15:36:42.075Z", + "call_id": "call_3nx7IDwap1gi4esvMS3zwrOR", + "command": "cat /tmp/weaver-exp-astra/prompts/A2.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:36:52.078Z", + "call_id": "call_zSPykTU4Ec9ze7YIBT7OGVBp", + "command": "cat .agents/skills/conjure-widget/SKILL.md && rg -n 'Module shape|widget\\(config|Hooks|Consolidated v0.4|useStorage|PR 11' sdk/CONTRACT.md && cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:01.990Z", + "call_id": "call_NtSV0aao84qKny90mRgac2kt", + "command": "sed -n '1,126p' sdk/CONTRACT.md && sed -n '400,433p' sdk/CONTRACT.md && sed -n '538,738p' sdk/CONTRACT.md && cat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:28.031Z", + "call_id": "call_XZfPpkQsBP1USnRb97PT4glX", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/A2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:37.570Z", + "call_id": "call_NpBCg77dHnU9LXSby4fPO8UQ", + "command": "cat /tmp/weaver-exp-astra/runs/A2/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:25.088Z", + "call_id": "call_ZZ3yonNywUlNdaor6QXpsIlA", + "command": "cat > /tmp/weaver-exp-astra/runs/A2/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget } from \"@weaver/sdk\";\n\nconst days = [\n { key: \"Mon\", letter: \"M\" },\n { key: \"Tue\", letter: \"T\" },\n { key: \"Wed\", letter: \"W\" },\n { key: \"Thu\", letter: \"T\" },\n { key: \"Fri\", letter: \"F\" },\n { key: \"Sat\", letter: \"S\" },\n { key: \"Sun\", letter: \"S\" },\n];\nconst emptyWeek: Record = {\n Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0,\n};\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\n const total = days.reduce((sum, day) => sum + counts[day.key], 0);\n const fraction = Math.min(1, total / 20);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day) => (\n \n {day.letter}\n {counts[day.key]}\n \n ))}\n \n\n \n \n \n \n {total} / 20\n \n\n \n setCounts((current) => ({ ...current, [time.weekday]: current[time.weekday] + 1 }))}\n >\n \n Log session\n \n \n setCounts({ ...emptyWeek })}\n >\n \n Reset week\n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:38.711Z", + "call_id": "call_1zLkOQzgfDshczEkBV2zrnQW", + "command": "rg -n 'fillRect|fillRounded|CanvasCtx|##.*canvas' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:45.569Z", + "call_id": "call_ukbyk2darEjgbw6n5R5Dmcw6", + "command": "sed -n '322,375p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:59.185Z", + "call_id": "call_hVO0jmIRQTacxjCSJ0aeMmcf", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path('/tmp/weaver-exp-astra/runs/A2/widget.tsx')\ns = p.read_text().replace(' key={day.key}\\n', '')\ns = s.replace(''' \n \n ''', ''' {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff1f\");\n if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, \"#5eead4\");\n }}\n />''')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:15.426Z", + "call_id": "call_MRkHsI1dOX5Kqowq4RWDC5jE", + "command": "cat > /tmp/weaver-exp-astra/runs/A2/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: A (check-only).\n- `weaver check` runs: 2; final run passed.\n- `weaver capture` runs: 0. The captures directory was not created.\n- Defects fixed because of pixels or a snapshot: none.\n- Spec items not met: none known from contract review and static checking. Visual layout, interaction execution, and restart persistence were not empirically verified because this condition prohibits captures and development sessions.\n- Confidence: 8 / 10.\n\nThe check identified an unsupported JSX key prop and a computed class string; both were corrected. The progress bar uses a canvas drawing on render, without an animation timer. Storage contains weekday-keyed counts. Layout reserves separate space for the progress label, uses seven equal flex widths, and budgets the four rows plus gaps within the 168px inner height.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/A2-tool-results.json b/experiments/render-loop-cadence/astra/evidence/A2-tool-results.json new file mode 100644 index 00000000..15f89937 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/A2-tool-results.json @@ -0,0 +1,142 @@ +[ + { + "timestamp": "2026-09-05T15:36:42.134Z", + "call_id": "call_3nx7IDwap1gi4esvMS3zwrOR", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"b5ab54\",\"wall_time_seconds\":0.000003958,\"exit_code\":0,\"original_token_count\":1219,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/A2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/A2`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/A2` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/A2/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/A2/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/A2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/A2/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/A2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/A2/clicks.actions --out /tmp/weaver-exp-astra/runs/A2/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/A2/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: A (check-only)\\nYou may run `weaver check` as often as you like. You must NEVER run `weaver capture`, and you never see pixels or a snapshot. Build from the contract, the examples and your own reasoning. Stop when you believe the widget matches the spec. Leave /tmp/weaver-exp-astra/runs/A2/captures absent.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:36:52.167Z", + "call_id": "call_zSPykTU4Ec9ze7YIBT7OGVBp", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"420738\",\"wall_time_seconds\":0.000002667,\"exit_code\":0,\"original_token_count\":4281,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\nimport { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:37:02.072Z", + "call_id": "call_NtSV0aao84qKny90mRgac2kt", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"7c88f4\",\"wall_time_seconds\":0.000003,\"exit_code\":0,\"original_token_count\":5918,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one.\\nRoot hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart.\\nAny slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh.\\nEvaluation failure leaves the prior context, window, and state running; window-config changes restart the process.\\n\\n## Elements (JSX intrinsics)\\n\\n| Element | M1 renders | Props beyond `class`/`children` |\\n|---|---|---|\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 |\\n```\\n\\n- HTTPS only. The URL's host must exactly match an entry in `config.origins`;\\n otherwise the promise rejects with\\n `OriginNotDeclared: add \\\"api.example.com\\\" to origins in your widget config`.\\n- `weaver check` statically flags string-literal fetch URLs whose host is not\\n declared. Runtime enforcement is authoritative.\\n- Timeout 15s. No cookies; redirects are returned rather than followed; total\\n request and response caps are 5 MB each.\\n\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n\\n```ts\\nuseProvider(\\\"cpu\\\") // { percent: number, perCore: number[] } 1 Hz\\nuseProvider(\\\"memory\\\") // { usedMb: number, totalMb: number, percent: number } 1 Hz\\n```\\n\\nDelivered by `weaverd` (the host). `time` remains SDK-local. Subscribing\\nwithout the host running is a runtime error that names the fix (`weaver up`);\\n`weaver dev` auto-starts the host.\\n\\n`cpu.percent` is whole-machine utilization from 0\u2013100, not the sum of cores;\\n`perCore` reports the same 0\u2013100 utilization for each logical core. Memory\\n`usedMb` is physical memory that is not currently free or reclaimable idle\\ncache, `totalMb` is installed physical memory, and `percent` is their ratio.\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n setCounts({ ...emptyWeek })}\\n >\\n \\n Reset week\\n \\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A2\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:38:38.711Z", + "type": "custom_tool_call", + "call_id": "call_1zLkOQzgfDshczEkBV2zrnQW", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"rg -n 'fillRect|fillRounded|CanvasCtx|##.*canvas' sdk/CONTRACT.md\",max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:38:45.569Z", + "type": "custom_tool_call", + "call_id": "call_ukbyk2darEjgbw6n5R5Dmcw6", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"sed -n '322,375p' sdk/CONTRACT.md\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:38:59.185Z", + "type": "custom_tool_call", + "call_id": "call_hVO0jmIRQTacxjCSJ0aeMmcf", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nfrom pathlib import Path\\np = Path('/tmp/weaver-exp-astra/runs/A2/widget.tsx')\\ns = p.read_text().replace(' key={day.key}\\\\n', '')\\ns = s.replace(''' \\n \\n ''', ''' {\\n ctx.clear();\\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \\\"#ffffff1f\\\");\\n if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, \\\"#5eead4\\\");\\n }}\\n />''')\\np.write_text(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/A2\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:39:15.426Z", + "type": "custom_tool_call", + "call_id": "call_MRkHsI1dOX5Kqowq4RWDC5jE", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/A2/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: A (check-only).\\n- `weaver check` runs: 2; final run passed.\\n- `weaver capture` runs: 0. The captures directory was not created.\\n- Defects fixed because of pixels or a snapshot: none.\\n- Spec items not met: none known from contract review and static checking. Visual layout, interaction execution, and restart persistence were not empirically verified because this condition prohibits captures and development sessions.\\n- Confidence: 8 / 10.\\n\\nThe check identified an unsupported JSX key prop and a computed class string; both were corrected. The progress bar uses a canvas drawing on render, without an animation timer. Storage contains weekday-keyed counts. Layout reserves separate space for the progress label, uses seven equal flex widths, and budgets the four rows plus gaps within the 168px inner height.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:36:42.134Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:36:52.167Z", + "info": { + "total_token_usage": { + "input_tokens": 39802, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 197, + "reasoning_output_tokens": 22, + "total_tokens": 39999 + }, + "last_token_usage": { + "input_tokens": 20599, + "cached_input_tokens": 19072, + "cache_write_input_tokens": 0, + "output_tokens": 158, + "reasoning_output_tokens": 22, + "total_tokens": 20757 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:02.073Z", + "info": { + "total_token_usage": { + "input_tokens": 65497, + "cached_input_tokens": 56960, + "cache_write_input_tokens": 0, + "output_tokens": 276, + "reasoning_output_tokens": 22, + "total_tokens": 65773 + }, + "last_token_usage": { + "input_tokens": 25695, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 79, + "reasoning_output_tokens": 0, + "total_tokens": 25774 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:28.369Z", + "info": { + "total_token_usage": { + "input_tokens": 97488, + "cached_input_tokens": 82432, + "cache_write_input_tokens": 0, + "output_tokens": 593, + "reasoning_output_tokens": 292, + "total_tokens": 98081 + }, + "last_token_usage": { + "input_tokens": 31991, + "cached_input_tokens": 25472, + "cache_write_input_tokens": 0, + "output_tokens": 317, + "reasoning_output_tokens": 270, + "total_tokens": 32308 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:37.787Z", + "info": { + "total_token_usage": { + "input_tokens": 129882, + "cached_input_tokens": 114304, + "cache_write_input_tokens": 0, + "output_tokens": 634, + "reasoning_output_tokens": 292, + "total_tokens": 130516 + }, + "last_token_usage": { + "input_tokens": 32394, + "cached_input_tokens": 31872, + "cache_write_input_tokens": 0, + "output_tokens": 41, + "reasoning_output_tokens": 0, + "total_tokens": 32435 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:25.897Z", + "info": { + "total_token_usage": { + "input_tokens": 162587, + "cached_input_tokens": 146560, + "cache_write_input_tokens": 0, + "output_tokens": 1857, + "reasoning_output_tokens": 315, + "total_tokens": 164444 + }, + "last_token_usage": { + "input_tokens": 32705, + "cached_input_tokens": 32256, + "cache_write_input_tokens": 0, + "output_tokens": 1223, + "reasoning_output_tokens": 23, + "total_tokens": 33928 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:38.792Z", + "info": { + "total_token_usage": { + "input_tokens": 196698, + "cached_input_tokens": 179072, + "cache_write_input_tokens": 0, + "output_tokens": 1991, + "reasoning_output_tokens": 351, + "total_tokens": 198689 + }, + "last_token_usage": { + "input_tokens": 34111, + "cached_input_tokens": 32512, + "cache_write_input_tokens": 0, + "output_tokens": 134, + "reasoning_output_tokens": 36, + "total_tokens": 34245 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:45.650Z", + "info": { + "total_token_usage": { + "input_tokens": 231051, + "cached_input_tokens": 212992, + "cache_write_input_tokens": 0, + "output_tokens": 2031, + "reasoning_output_tokens": 351, + "total_tokens": 233082 + }, + "last_token_usage": { + "input_tokens": 34353, + "cached_input_tokens": 33920, + "cache_write_input_tokens": 0, + "output_tokens": 40, + "reasoning_output_tokens": 0, + "total_tokens": 34393 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:00.064Z", + "info": { + "total_token_usage": { + "input_tokens": 266192, + "cached_input_tokens": 233472, + "cache_write_input_tokens": 0, + "output_tokens": 2321, + "reasoning_output_tokens": 351, + "total_tokens": 268513 + }, + "last_token_usage": { + "input_tokens": 35141, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 290, + "reasoning_output_tokens": 0, + "total_tokens": 35431 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:15.483Z", + "info": { + "total_token_usage": { + "input_tokens": 301695, + "cached_input_tokens": 268416, + "cache_write_input_tokens": 0, + "output_tokens": 2576, + "reasoning_output_tokens": 371, + "total_tokens": 304271 + }, + "last_token_usage": { + "input_tokens": 35503, + "cached_input_tokens": 34944, + "cache_write_input_tokens": 0, + "output_tokens": 255, + "reasoning_output_tokens": 20, + "total_tokens": 35758 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:27.595Z", + "info": { + "total_token_usage": { + "input_tokens": 337510, + "cached_input_tokens": 303744, + "cache_write_input_tokens": 0, + "output_tokens": 2628, + "reasoning_output_tokens": 371, + "total_tokens": 340138 + }, + "last_token_usage": { + "input_tokens": 35815, + "cached_input_tokens": 35328, + "cache_write_input_tokens": 0, + "output_tokens": 52, + "reasoning_output_tokens": 0, + "total_tokens": 35867 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/B1-commands.json b/experiments/render-loop-cadence/astra/evidence/B1-commands.json new file mode 100644 index 00000000..7f65c691 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B1-commands.json @@ -0,0 +1,146 @@ +[ + { + "timestamp": "2026-09-05T15:30:06.372Z", + "call_id": "call_Lq7E9B0lHl6vdXvisLx9do1m", + "command": "cat /tmp/weaver-exp-astra/prompts/B1.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:16.558Z", + "call_id": "call_gpnrDyDZAoLySVuTrjAv6CoG", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:16.558Z", + "call_id": "call_gpnrDyDZAoLySVuTrjAv6CoG", + "command": "rg -n 'Module shape|widget\\(config, component\\)|Hooks|Consolidated v0.4 authoring tables|useStorage|PR 11: native interaction' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "command": "sed -n '1,130p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "command": "sed -n '395,445p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "command": "sed -n '538,790p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "command": "cat examples/pomodoro/widget.tsx examples/clock/widget.tsx docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/B1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:28.793Z", + "call_id": "call_9D7STZ0eRl1aEqc12zqFPtcP", + "command": "cat /tmp/weaver-exp-astra/runs/B1/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:28.793Z", + "call_id": "call_9D7STZ0eRl1aEqc12zqFPtcP", + "command": "cat > /tmp/weaver-exp-astra/runs/B1/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget } from \"@weaver/sdk\";\n\ntype Weekday = \"Mon\" | \"Tue\" | \"Wed\" | \"Thu\" | \"Fri\" | \"Sat\" | \"Sun\";\nconst days: Weekday[] = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\nconst emptyWeek: Record = {\n Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0,\n};\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\n const today = time.weekday as Weekday;\n const total = days.reduce((sum, day) => sum + counts[day], 0);\n const progress = Math.min(total / 20, 1);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day) => (\n \n {day[0]}\n {counts[day]}\n \n ))}\n \n\n \n \n \n \n {total} / 20\n \n\n \n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:40.166Z", + "call_id": "call_ylyvZaLpOWzyV0olQGUdZ2II", + "command": "rg -n 'fillRect|fillRound|CanvasCtx|canvas.*retained' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:40.166Z", + "call_id": "call_ylyvZaLpOWzyV0olQGUdZ2II", + "command": "sed -n '455,505p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:07.726Z", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "command": "sed -n '311,362p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:07.726Z", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/B1/widget.tsx'\ns=open(p).read().replace('\n \n ''',''' {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff1a\");\n if (progress > 0) ctx.fillRoundRect(0, 0, ctx.width * progress, ctx.height, 3, \"#5eead4\");\n }} />''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:07.726Z", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "command": "mkdir -p /tmp/weaver-exp-astra/runs/B1/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B1/clicks.actions\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B1/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:07.726Z", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B1/clicks.actions --out /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:17.673Z", + "call_id": "call_tVSId6vf6Wg1HglZ181Ylc3X", + "command": "cat /tmp/weaver-exp-astra/runs/B1/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B1/captures/01-initial.receipt.json /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:45.830Z", + "call_id": "call_PS3Rs8VtD58RMcUwxcruxmqe", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/B1/widget.tsx'\ns=open(p).read().replace(' /tmp/weaver-exp-astra/runs/B1/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: B (final capture).\n- `weaver check` runs: 3. First failed on unsupported JSX `key` and a dynamic class; both subsequent runs passed, including the final source.\n- `weaver capture` runs: 5. Every receipt has `status: \"ok\"`.\n- Defects fixed because of pixels or snapshots: the progress bar was invisible in captures 01 and 02 even though its semantic canvas bounds were 224×6. Replacing `w-0 grow` on the canvas with explicit `w-[224px]` made both track and fill visible in captures 03 and 04. The width comes from the measured 288px content row minus its 12px gap and 52px label.\n- Spec items not met: none known. Persistence uses `useStorage` with a weekday-keyed record; restart persistence was not independently exercised because captures use isolated empty storage.\n- Confidence: 9/10.\n\nFinal visual and semantic evidence:\n\n- `captures/03-initial.png`: Friday highlighted, all seven counts zero, `0 / 20`, visible empty track.\n- `captures/04-after-clicks.png`: Friday 3, other days zero, `3 / 20`, fill at 15% of the 224px track.\n- `captures/05-after-reset.png`: three logs followed by Reset week returns every count to zero and empties the track.\n\nAll five PNGs were opened and inspected at their 320×200, scale-1 dimensions; all snapshots and receipts were read. The final captures show aligned header text, equal day cells, legible text, distinct controls, and no clipping or overlap. Both button names match exactly. Native hover feedback is visible after clicks; both controls also declare native pressed styles.\n\nThe single pending timer is the subscribed time provider. No fetches, external providers, unresolved images, or frame requests remain. Receipts warn that the repository already contains uncommitted changes; no repository files were edited. No live development window was started, as requested.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/B1-tool-results.json b/experiments/render-loop-cadence/astra/evidence/B1-tool-results.json new file mode 100644 index 00000000..af9b85b9 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B1-tool-results.json @@ -0,0 +1,218 @@ +[ + { + "timestamp": "2026-09-05T15:30:06.449Z", + "call_id": "call_Lq7E9B0lHl6vdXvisLx9do1m", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"0ae8ee\",\"wall_time_seconds\":0.000004041,\"exit_code\":0,\"original_token_count\":1230,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/B1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B1`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B1` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B1/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/B1/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B1/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B1/clicks.actions --out /tmp/weaver-exp-astra/runs/B1/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/B1/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: B (final capture)\\nWrite the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:16.658Z", + "call_id": "call_gpnrDyDZAoLySVuTrjAv6CoG", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"a3ec2b\",\"wall_time_seconds\":0.00000375,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"167b93\",\"wall_time_seconds\":0.000003375,\"exit_code\":0,\"original_token_count\":82,\"output\":\"20:## Module shape\\n43:## `widget(config, component)`\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:29.629Z", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"status\":\"fulfilled\",\"value\":{\"chunk_id\":\"366351\",\"wall_time_seconds\":0.000003083,\"exit_code\":0,\"original_token_count\":1546,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one.\\nRoot hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart.\\nAny slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh.\\nEvaluation failure leaves the prior context, window, and state running; window-config changes restart the process.\\n\\n## Elements (JSX intrinsics)\\n\\n| Element | M1 renders | Props beyond `class`/`children` |\\n|---|---|---|\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 (a styled box; column layout) |\\n| `` | yes | \u2014 (children: strings/numbers, or one `Signal`) |\\n| `` | yes | exactly one of literal `name` or literal `d`; custom paths also accept `viewBox`/`stroke`; no children |\\n| `` | check-error \\\"arrives in M2\\\" | `src` |\\n\"}}" + }, + { + "type": "input_text", + "text": "{\"status\":\"fulfilled\",\"value\":{\"chunk_id\":\"0549f1\",\"wall_time_seconds\":0.000001375,\"exit_code\":0,\"original_token_count\":551,\"output\":\"function wfetch(url: string, init?: {\\n method?: \\\"GET\\\" | \\\"POST\\\";\\n headers?: Record;\\n body?: string;\\n}): Promise<{ status: number; ok: boolean; text(): Promise; json(): Promise }>;\\n```\\n\\n- HTTPS only. The URL's host must exactly match an entry in `config.origins`;\\n otherwise the promise rejects with\\n `OriginNotDeclared: add \\\"api.example.com\\\" to origins in your widget config`.\\n- `weaver check` statically flags string-literal fetch URLs whose host is not\\n declared. Runtime enforcement is authoritative.\\n- Timeout 15s. No cookies; redirects are returned rather than followed; total\\n request and response caps are 5 MB each.\\n\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n\\n```ts\\nuseProvider(\\\"cpu\\\") // { percent: number, perCore: number[] } 1 Hz\\nuseProvider(\\\"memory\\\") // { usedMb: number, totalMb: number, percent: number } 1 Hz\\n```\\n\\nDelivered by `weaverd` (the host). `time` remains SDK-local. Subscribing\\nwithout the host running is a runtime error that names the fix (`weaver up`);\\n`weaver dev` auto-starts the host.\\n\\n`cpu.percent` is whole-machine utilization from 0\u2013100, not the sum of cores;\\n`perCore` reports the same 0\u2013100 utilization for each logical core. Memory\\n`usedMb` is physical memory that is not currently free or reclaimable idle\\ncache, `totalMb` is installed physical memory, and `percent` is their ratio.\\nThese meanings stay platform-neutral even though each host uses its public OS\\ncounters to project them.\\n\\n## The host and its CLI verbs\\n\\n```\\nweaver up | down start/stop weaverd (singleton, tray-less in M2)\\nweaver pack write portable source to .weave\\nweaver install validate, own, build, register, and run source\\nweaver uninstall stop + unregister\\nweaver status table: name \u00b7 pid \u00b7 private-MB \u00b7 cpu% \u00b7 uptime (ADR 0005 billing)\\n```\\n\"}}" + }, + { + "type": "input_text", + "text": "{\"status\":\"fulfilled\",\"value\":{\"chunk_id\":\"7686c7\",\"wall_time_seconds\":0.000001667,\"exit_code\":0,\"original_token_count\":3228,\"output\":\"## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n# Agent widget capture\\n\\n`weaver capture` renders a checked widget without opening a desktop window or\\nstarting Weaver's host, registry, provider daemon, or development loop. It is\\nthe deterministic inspection path for agents, tests, and CI:\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/clock --out /tmp/clock.png\\n```\\n\\nA successful run publishes three files together:\\n\\n- `/tmp/clock.png` \u2014 pixels from Native SDK's reference renderer.\\n- `/tmp/clock.snapshot.txt` \u2014 the semantic tree used by automation.\\n- `/tmp/clock.receipt.json` \u2014 provenance, renderer counters, pending work,\\n measured timings, input hashes, and warnings.\\n\\nStandard output is exactly one compact `weaver.capture.v1` receipt. Diagnostics\\ngo to standard error. A failed run also emits one error receipt, exits nonzero,\\nand does not publish a partial artifact set. If widget execution falls back to\\nits runtime error surface during an action or replay, capture reports\\n`CaptureWidgetFailed` instead of treating those error pixels as a successful\\nwidget render. The widget's own diagnostic (the thrown message and stack, or\\nthe unhandled rejection) travels with that failure: the receipt carries it as\\n`error.diagnostic` and standard error prints it on a `diagnostic:` line, so the\\ncapture output alone names what to fix.\\n\\nCapture uses a fresh temporary data, storage, geometry, log, and artwork root.\\nIt neither reads nor changes the live widget state. The clock starts at the ISO\\ninstant recorded in `inputs.clock`; pass `--clock ` when a capture\\nmust reproduce exactly. Time advances only through an action or a replayed\\nsession. No arbitrary wait is used to decide that rendering is done.\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/clock \\\\\\n --clock 2026-08-24T17:30:00.000Z \\\\\\n --out /tmp/clock.png\\n```\\n\\n## Semantic actions\\n\\nPass `--action-file ` to drive the ordinary automation dispatcher after\\nthe initial frame. Targets use semantic role and accessible name, not retained\\nnode IDs or screen coordinates:\\n\\n```json\\n{\\n \\\"schema\\\": \\\"weaver.capture.actions.v1\\\",\\n \\\"actions\\\": [\\n {\\n \\\"action\\\": \\\"click\\\",\\n \\\"target\\\": { \\\"role\\\": \\\"button\\\", \\\"name\\\": \\\"Start\\\" }\\n },\\n { \\\"action\\\": \\\"advance-clock\\\", \\\"milliseconds\\\": 1000 }\\n ]\\n}\\n```\\n\\nSupported actions are `click`, `drag`, `wheel`, `text`, `key`, `action`,\\n`context-menu`, `resize`, and `advance-clock`. A target may match `role`,\\n`name`, `enabled`, `selected`, and `value`; `role` or `name` is required and\\nthe match must be unique. `drag` takes normalized `from` and `to` values.\\n`advance-clock` drives eligible Weaver timers synchronously through the null\\nplatform, then renders any frame the widget actually requests.\\n\\n`useStorage` keeps its production 200 ms write coalescing, but capture uses an\\nisolated storage root and a runtime-owned capture-mode capability to persist\\nthose writes immediately. A writable widget clock cannot enable that path. An\\ninteraction that only changes stored state therefore needs no artificial\\n`advance-clock`; `pending.timers` continues to report timers created by widget\\nbehavior.\\n\\nExamples live in [`test/capture`](../test/capture):\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/pomodoro \\\\\\n --action-file test/capture/pomodoro.actions \\\\\\n --out /tmp/pomodoro.png\\n\\nnode cli/bin/weaver.js capture test/fixtures/styling-interaction \\\\\\n --action-file test/capture/styling-interaction.actions \\\\\\n --out /tmp/styling-interaction.png\\n```\\n\\n## Provider fixtures\\n\\nCapture never connects to a live provider endpoint. A widget subscribed to\\n`cpu`, `memory`, `audio`, or `media` must receive explicit recorded input with\\n`--provider-fixture `. Every subscribed non-time provider must appear in\\nthe fixture and undeclared providers are rejected.\\n\\n```json\\n{\\n \\\"schema\\\": \\\"weaver.provider-fixture.v1\\\",\\n \\\"frames\\\": [\\n {\\n \\\"provider\\\": \\\"media\\\",\\n \\\"value\\\": {\\n \\\"title\\\": \\\"Capture Proof\\\",\\n \\\"artist\\\": \\\"Weaver\\\",\\n \\\"status\\\": \\\"playing\\\",\\n \\\"playing\\\": true,\\n \\\"positionMs\\\": 42000,\\n \\\"durationMs\\\": 180000\\n }\\n }\\n ]\\n}\\n```\\n\\nFrames enter through the same provider dispatch path as live host frames. The\\nfixture file's SHA-256 is recorded in the receipt:\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/noro-shell \\\\\\n --provider-fixture test/capture/noro.provider.json \\\\\\n --out /tmp/noro.png\\n```\\n\\n## Session journals\\n\\n`--session-journal ` replays an existing Native SDK session journal with\\nverification enabled and captures its final retained state. A journal and an\\naction file are alternative event sources and cannot be supplied together.\\nThe journal hash is recorded in the receipt.\\n\\n## Reading the receipt\\n\\nTreat `status`, `error`, and `pending` as the decision surface. `renderer`\\nreports the retained revision, driven frames, command and semantic-node counts,\\nregistered images and fonts, and the number of pixels that differ from the\\nsurface clear color. A successful but visibly empty widget therefore has an\\nexplicit receipt instead of relying on a screenshot guess. `pending` reports\\ntimers, fetches, unresolved images, providers, and real queued frame requests;\\nthe capture command does not hide them by sleeping or by imposing a guessed\\ntimeout.\\n\\n`provenance` records the Weaver and Native SDK commits plus the exact bundled\\nJavaScript hash. A dirty checkout is allowed but is called out in `warnings`.\\n\\nAfter building the runtime, run the repository acceptance corpus with\\n`npm run test:capture`. It checks non-flat pixels, semantic state changes,\\nprovider failure and fixture behavior, ambiguous-target candidates, artifact\\npublication, and byte-identical fixed-clock session replay.\\n\"}}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"408cf3\",\"wall_time_seconds\":0.306406042,\"exit_code\":0,\"original_token_count\":24,\"output\":\"Initialized /tmp/weaver-exp-astra/runs/B1\\nNext: weaver check '/tmp/weaver-exp-astra/runs/B1'\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:31:29.493Z", + "call_id": "call_9D7STZ0eRl1aEqc12zqFPtcP", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.7 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"093af7\",\"wall_time_seconds\":0.000004416,\"exit_code\":0,\"original_token_count\":149,\"output\":\"import { useProvider, widget } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"B1\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"74aacb\",\"wall_time_seconds\":0.470230167,\"exit_code\":1,\"original_token_count\":110,\"output\":\"weaver failed (3 errors)\\n- /tmp/weaver-exp-astra/runs/B1/widget.tsx:41:18: class must resolve to at most 32 literal strings so weaver check can validate every utility\\n- TypeScript: ../../../../../tmp/weaver-exp-astra/runs/B1/widget.tsx(30,19): error TS2322: Type '{ children: Element[]; key: Weekday; class: string; }' is not assignable to type 'GradientBoxProps'.\\n- TypeScript: Property 'key' does not exist on type 'GradientBoxProps'.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:31:40.273Z", + "call_id": "call_ylyvZaLpOWzyV0olQGUdZ2II", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"3fb456\",\"wall_time_seconds\":0.000005416,\"exit_code\":0,\"original_token_count\":51,\"output\":\"331:interface CanvasCtx {\\n334: fillRect(x: number, y: number, w: number, h: number, color: string): void;\\n335: fillRoundRect(x: number, y: number, w: number, h: number, r: number, color: string): void;\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"32149b\",\"wall_time_seconds\":0.000002292,\"exit_code\":0,\"original_token_count\":625,\"output\":\"per-widget cost. Registrations persist across host restarts.\\n\\n---\\n\\n# Styling breadth amendment (v0.4)\\n\\nEverything above stands. This section grows with the numbered styling stack;\\nutilities not yet listed here remain loud `weaver check` errors.\\n\\n## PR 01: spacing and sizing\\n\\nThe scale remains 1 unit = 4 logical px. Bracketed pixel values are accepted\\nwhere shown. Utilities are applied left-to-right; a later utility wins on the\\nsame side or axis. Negative margins are supported; padding and sizes are\\nnon-negative.\\n\\n| Utility | Maps to |\\n|---|---|\\n| `p-N`, `p-[Npx]` | uniform padding |\\n| `px/py/pt/pr/pb/pl-N`, bracketed `Npx` forms | directional padding; side values override uniform padding |\\n| `m/mx/my/mt/mr/mb/ml-N`, bracketed `Npx` forms, optional leading `-` | external per-side margin |\\n| `w-N`, `h-N`, bracketed `Npx` forms | fixed width or height |\\n| `w-full`, `h-full`, `w-A/B`, `h-A/B` | percentage of the parent's content box |\\n| `w-auto`, `h-auto` | clear an earlier size on that axis |\\n| `size-N`, `size-[Npx]`, `size-full` | set both axes together |\\n| `min-w/max-w/min-h/max-h-N`, bracketed `Npx` forms | per-axis size bounds |\\n| `aspect-square`, `aspect-video`, `aspect-[W/H]`, `aspect-[N]` | derive the missing axis when exactly one axis is definite |\\n| `aspect-auto` | clear an earlier aspect ratio |\\n\\nPercentage sizes are calculated from the parent's content box before margins;\\nmin/max bounds then clamp the laid-out frame. `aspect-*` does nothing when both\\naxes are definite or both are automatic.\\n\\n## PR 02: flex completeness\\n\\n| Utility | Maps to |\\n|---|---|\\n| `justify-around`, `justify-evenly` | Tailwind main-axis free-space distribution |\\n| `grow-N`, `grow-[N]` | numeric flex-grow factor (`grow` remains 1) |\\n| `shrink`, `shrink-0` | opt in/out of compression below the preferred size |\\n| `self-auto/start/center/end/stretch` | per-child cross-axis alignment |\\n| `flex-wrap`, `flex-nowrap` | enable/disable row or column line wrapping |\\n\\nWeaver elements default to `shrink: 1`, matching Tailwind. When preferred\\nsizes overflow a line, eligible children give up space in proportion to their\\navailable shrink capacity (preferred size minus min-size floor); `shrink-0`\\nchildren never compress. If all floors still exceed the container, overflow\\nremains explicit and the Native debug diagnostic fires. Wrapped lines use the\\ncontainer's `gap` on both axes. `items-baseline` remains an end-alignment\\napproximation; true font baseline layout is outside this styling slice.\\n\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:32:09.819Z", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 2.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"8f266a\",\"wall_time_seconds\":0.0000035,\"exit_code\":0,\"original_token_count\":595,\"output\":\"\\n## v0 done-condition (unchanged)\\n\\nOn a machine that has never seen this repo: `weaver init clock` + one agent\\nprompt editing widget.tsx + `weaver dev clock` \u2192 ticking translucent clock on\\nthe desktop.\\n\\n---\\n\\n# M3 amendment (v0.3)\\n\\n## `` \u2014 immediate mode (the ADR 0009 exception)\\n\\n```tsx\\n { \u2026 }} />\\n```\\n\\n```ts\\ninterface CanvasFrame { t: number; dt: number } // seconds\\ntype CanvasFrameRate = number | \\\"display\\\";\\ninterface CanvasCtx {\\n width: number; height: number; // logical px\\n clear(color?: string): void; // default: transparent\\n fillRect(x: number, y: number, w: number, h: number, color: string): void;\\n fillRoundRect(x: number, y: number, w: number, h: number, r: number, color: string): void;\\n fillCircle(cx: number, cy: number, r: number, color: string): void;\\n line(x1: number, y1: number, x2: number, y2: number, width: number, color: string): void;\\n polyline(points: number[], width: number, color: string): void; // flat x,y pairs\\n}\\n```\\n\\n- `fps=\\\"display\\\"` draws once per native surface frame, matching a 60 Hz or\\n high-refresh display without guessing its rate. This is the default choice\\n for fluid visualizers: `fps={active ? \\\"display\\\" : 0}`.\\n- A positive numeric `fps` requests a fixed lower cadence and remains capped\\n at 60 for compatibility. `fps={0}` pauses the frame clock entirely (0% cost)\\n while keeping the last frame on screen; omitted draws once per React render.\\n- `onFrame` runs on the selected native clock; commands batch into one\\n immediate-mode buffer per frame. Colors are `#rgb/#rrggbb/#rrggbbaa`.\\n- A canvas with `fps=\\\"display\\\"` or `fps > 0` is an *animated* widget and is\\n billed accordingly (ADR 0005); everything outside the canvas stays\\n retained/idle-zero.\\n\\n## Providers: `audio` and `media` (host-fed)\\n\\n```ts\\nuseProvider(\\\"audio\\\") // { rms: number, bands: number[] } 32 bands 0..1, 30 Hz,\\n // system loopback \u2014 silence sends nothing (idle-zero)\\nuseProviderSignal(\\\"audio\\\") // same data without scheduling a root render;\\n // canvas reads .value, text binds with .map(...)\\nuseProvider(\\\"media\\\") // { title: string, artist: string, album: string,\\n // playing: boolean, positionMs: number, durationMs: number }\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"87ddaa\",\"wall_time_seconds\":0.451072125,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/B1\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"31a241\",\"wall_time_seconds\":0.549520458,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"2939640271054288742e1a821160fb789a48244dc18b1f41b336cbac098eada8\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/01-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/01-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":43,\\\"nodes\\\":44,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":328121,\\\"spawn\\\":51875,\\\"startup\\\":35721,\\\"render\\\":1802,\\\"encode\\\":493,\\\"write\\\":493,\\\"total\\\":427498},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"07a814\",\"wall_time_seconds\":0.558410584,\"exit_code\":0,\"original_token_count\":343,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"2939640271054288742e1a821160fb789a48244dc18b1f41b336cbac098eada8\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":5,\\\"retainedRevision\\\":4,\\\"commands\\\":44,\\\"nodes\\\":44,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":339749,\\\"spawn\\\":56890,\\\"startup\\\":32164,\\\"render\\\":1812,\\\"encode\\\":510,\\\"write\\\":284,\\\"total\\\":431408},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\",\\\"actionFileSha256\\\":\\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"},\\\"interactions\\\":{\\\"actions\\\":[\\\"click\\\",\\\"click\\\",\\\"click\\\"],\\\"mediaCommands\\\":[]},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:32:17.747Z", + "call_id": "call_tVSId6vf6Wg1HglZ181Ylc3X", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f240a6\",\"wall_time_seconds\":0.000005292,\"exit_code\":0,\"original_token_count\":5968,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=37995000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=83927 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=43 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=21 canvas_frame_encoder_commands=131 canvas_frame_encoder_cache_actions=86 canvas_frame_encoder_pipeline_binds=21 canvas_frame_encoder_draws=21 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=43 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=43 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=19 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=40 canvas_frame_gpu_packet_cache_actions=86 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=468 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=44 widget_semantics=44 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#5404126479162880160 role=group name=\\\"\\\" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9682609897917696589 role=group name=\\\"\\\" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"0 / 20\\\" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#4456204386640616177 role=group name=\\\"\\\" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9787074478480440413 role=button name=\\\"Log session\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413\\n widget @w1/widget-canvas#2627286533109177756 role=text name=\\\"Log session\\\" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282\\n widget @w1/widget-canvas#2335965760644945153 role=button name=\\\"Reset week\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#13497137971391810392 role=group name=\\\"\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153\\n widget @w1/widget-canvas#10422795391015277995 role=text name=\\\"Reset week\\\" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392\\nready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=43828000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=84076 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788622329780876000 gpu_input_latency_ns=2868000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=21 canvas_frame_encoder_commands=142 canvas_frame_encoder_cache_actions=97 canvas_frame_encoder_pipeline_binds=21 canvas_frame_encoder_draws=21 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=48 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=25 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=40 canvas_frame_gpu_packet_cache_actions=97 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=494 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=44 widget_semantics=44 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"3\\\" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#5404126479162880160 role=group name=\\\"\\\" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9682609897917696589 role=group name=\\\"\\\" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"3 / 20\\\" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#4456204386640616177 role=group name=\\\"\\\" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9787074478480440413 role=button name=\\\"Log session\\\" bounds=(16,146 170x34) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press]\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413\\n widget @w1/widget-canvas#2627286533109177756 role=text name=\\\"Log session\\\" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282\\n widget @w1/widget-canvas#2335965760644945153 role=button name=\\\"Reset week\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#13497137971391810392 role=group name=\\\"\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153\\n widget @w1/widget-canvas#10422795391015277995 role=text name=\\\"Reset week\\\" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"2939640271054288742e1a821160fb789a48244dc18b1f41b336cbac098eada8\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/01-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/01-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 43,\\n \\\"nodes\\\": 44,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 328121,\\n \\\"spawn\\\": 51875,\\n \\\"startup\\\": 35721,\\n \\\"render\\\": 1802,\\n \\\"encode\\\": 493,\\n \\\"write\\\": 493,\\n \\\"total\\\": 427498\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"2939640271054288742e1a821160fb789a48244dc18b1f41b336cbac098eada8\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 5,\\n \\\"retainedRevision\\\": 4,\\n \\\"commands\\\": 44,\\n \\\"nodes\\\": 44,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 339749,\\n \\\"spawn\\\": 56890,\\n \\\"startup\\\": 32164,\\n \\\"render\\\": 1812,\\n \\\"encode\\\": 510,\\n \\\"write\\\": 284,\\n \\\"total\\\": 431408\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\",\\n \\\"actionFileSha256\\\": \\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"\\n },\\n \\\"interactions\\\": {\\n \\\"actions\\\": [\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\"\\n ],\\n \\\"mediaCommands\\\": []\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:32:47.935Z", + "call_id": "call_PS3Rs8VtD58RMcUwxcruxmqe", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 2.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"e50949\",\"wall_time_seconds\":0.451466125,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/B1\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"99d248\",\"wall_time_seconds\":0.559054166,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/03-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/03-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":43,\\\"nodes\\\":44,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":339881,\\\"spawn\\\":54407,\\\"startup\\\":38679,\\\"render\\\":1739,\\\"encode\\\":489,\\\"write\\\":275,\\\"total\\\":440973},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"c76379\",\"wall_time_seconds\":0.5338285,\"exit_code\":0,\"original_token_count\":343,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/04-after-clicks.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/04-after-clicks.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":5,\\\"retainedRevision\\\":4,\\\"commands\\\":44,\\\"nodes\\\":44,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":316368,\\\"spawn\\\":54572,\\\"startup\\\":32003,\\\"render\\\":1730,\\\"encode\\\":489,\\\"write\\\":230,\\\"total\\\":406803},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\",\\\"actionFileSha256\\\":\\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"},\\\"interactions\\\":{\\\"actions\\\":[\\\"click\\\",\\\"click\\\",\\\"click\\\"],\\\"mediaCommands\\\":[]},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"0998d3\",\"wall_time_seconds\":0.000003,\"exit_code\":0,\"original_token_count\":4289,\"output\":\"03-initial\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#5404126479162880160 role=group name=\\\"\\\" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9682609897917696589 role=group name=\\\"\\\" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"0 / 20\\\" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#4456204386640616177 role=group name=\\\"\\\" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9787074478480440413 role=button name=\\\"Log session\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413\\n widget @w1/widget-canvas#2627286533109177756 role=text name=\\\"Log session\\\" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282\\n widget @w1/widget-canvas#2335965760644945153 role=button name=\\\"Reset week\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#13497137971391810392 role=group name=\\\"\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153\\n widget @w1/widget-canvas#10422795391015277995 role=text name=\\\"Reset week\\\" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/03-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/03-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 43,\\n \\\"nodes\\\": 44,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 339881,\\n \\\"spawn\\\": 54407,\\n \\\"startup\\\": 38679,\\n \\\"render\\\": 1739,\\n \\\"encode\\\": 489,\\n \\\"write\\\": 275,\\n \\\"total\\\": 440973\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n04-after-clicks\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"3\\\" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#5404126479162880160 role=group name=\\\"\\\" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9682609897917696589 role=group name=\\\"\\\" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"3 / 20\\\" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#4456204386640616177 role=group name=\\\"\\\" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9787074478480440413 role=button name=\\\"Log session\\\" bounds=(16,146 170x34) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press]\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413\\n widget @w1/widget-canvas#2627286533109177756 role=text name=\\\"Log session\\\" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282\\n widget @w1/widget-canvas#2335965760644945153 role=button name=\\\"Reset week\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#13497137971391810392 role=group name=\\\"\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153\\n widget @w1/widget-canvas#10422795391015277995 role=text name=\\\"Reset week\\\" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/04-after-clicks.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/04-after-clicks.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 5,\\n \\\"retainedRevision\\\": 4,\\n \\\"commands\\\": 44,\\n \\\"nodes\\\": 44,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 316368,\\n \\\"spawn\\\": 54572,\\n \\\"startup\\\": 32003,\\n \\\"render\\\": 1730,\\n \\\"encode\\\": 489,\\n \\\"write\\\": 230,\\n \\\"total\\\": 406803\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\",\\n \\\"actionFileSha256\\\": \\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"\\n },\\n \\\"interactions\\\": {\\n \\\"actions\\\": [\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\"\\n ],\\n \\\"mediaCommands\\\": []\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:33:02.561Z", + "call_id": "call_CDeEQFTcdHbtlrGyjvDhwef1", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"2478e1\",\"wall_time_seconds\":0.820269917,\"exit_code\":0,\"original_token_count\":345,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/05-after-reset.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/B1/captures/05-after-reset.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":6,\\\"retainedRevision\\\":5,\\\"commands\\\":43,\\\"nodes\\\":44,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":383541,\\\"spawn\\\":58322,\\\"startup\\\":32726,\\\"render\\\":1772,\\\"encode\\\":497,\\\"write\\\":222,\\\"total\\\":490122},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\",\\\"actionFileSha256\\\":\\\"547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a\\\"},\\\"interactions\\\":{\\\"actions\\\":[\\\"click\\\",\\\"click\\\",\\\"click\\\",\\\"click\\\"],\\\"mediaCommands\\\":[]},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"704fa2\",\"wall_time_seconds\":0.000002958,\"exit_code\":0,\"original_token_count\":3021,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=45498000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=86451 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=6 gpu_timestamp_ns=84333335 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788622382486754000 gpu_input_latency_ns=2500000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=5 canvas_commands=43 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=147 canvas_frame_encoder_cache_actions=98 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=43 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=48 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=25 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=41 canvas_frame_gpu_packet_cache_actions=98 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=504 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=10 widget_nodes=44 widget_semantics=44 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#5404126479162880160 role=group name=\\\"\\\" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9682609897917696589 role=group name=\\\"\\\" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"0 / 20\\\" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160\\n widget @w1/widget-canvas#4456204386640616177 role=group name=\\\"\\\" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#9787074478480440413 role=button name=\\\"Log session\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press]\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413\\n widget @w1/widget-canvas#2627286533109177756 role=text name=\\\"Log session\\\" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282\\n widget @w1/widget-canvas#2335965760644945153 role=button name=\\\"Reset week\\\" bounds=(194,146 110x34) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press]\\n widget @w1/widget-canvas#13497137971391810392 role=group name=\\\"\\\" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153\\n widget @w1/widget-canvas#10422795391015277995 role=text name=\\\"Reset week\\\" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/05-after-reset.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/B1/captures/05-after-reset.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 6,\\n \\\"retainedRevision\\\": 5,\\n \\\"commands\\\": 43,\\n \\\"nodes\\\": 44,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 383541,\\n \\\"spawn\\\": 58322,\\n \\\"startup\\\": 32726,\\n \\\"render\\\": 1772,\\n \\\"encode\\\": 497,\\n \\\"write\\\": 222,\\n \\\"total\\\": 490122\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\",\\n \\\"actionFileSha256\\\": \\\"547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a\\\"\\n },\\n \\\"interactions\\\": {\\n \\\"actions\\\": [\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\"\\n ],\\n \\\"mediaCommands\\\": []\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:33:28.872Z", + "call_id": "call_FS886wIwUpywM62Po9BCFWH4", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"c21879\",\"wall_time_seconds\":0.000004334,\"exit_code\":0,\"original_token_count\":0,\"output\":\"\"}" + } + ] + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/B1-usage.json b/experiments/render-loop-cadence/astra/evidence/B1-usage.json new file mode 100644 index 00000000..d33bb44f --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B1-usage.json @@ -0,0 +1,343 @@ +{ + "run": "B1", + "thread": { + "id": "01a07230-e095-7bf1-a335-d22b994b2ceb", + "rollout_path": "/Users/dara/.codex/sessions/2026/09/05/rollout-2026-09-05T11-30-00-01a07230-e095-7bf1-a335-d22b994b2ceb.jsonl", + "created_at": 1788622200, + "agent_path": "/root/astra_b1", + "model": "gpt-6-astra", + "reasoning_effort": "high", + "tokens_used": 425868 + }, + "dispatch_utc": "2026-09-05T15:29:54.830782+00:00", + "harness_start_utc": "2026-09-05T15:30:01.072Z", + "completion_utc": "2026-09-05T15:33:36.886Z", + "usage_timestamp": "2026-09-05T15:33:36.881Z", + "total_token_usage": { + "input_tokens": 421619, + "cached_input_tokens": 380160, + "cache_write_input_tokens": 0, + "output_tokens": 4249, + "reasoning_output_tokens": 435, + "total_tokens": 425868 + }, + "tool_call_counts": { + "exec": 10 + }, + "tool_calls": [ + { + "timestamp": "2026-09-05T15:30:06.372Z", + "type": "custom_tool_call", + "call_id": "call_Lq7E9B0lHl6vdXvisLx9do1m", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/prompts/B1.md\",max_output_tokens:20000}));\n" + }, + { + "timestamp": "2026-09-05T15:30:16.558Z", + "type": "custom_tool_call", + "call_id": "call_gpnrDyDZAoLySVuTrjAv6CoG", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat .agents/skills/conjure-widget/SKILL.md\",max_output_tokens:20000}));\ntext(await tools.exec_command({cmd:\"rg -n 'Module shape|widget\\\\(config, component\\\\)|Hooks|Consolidated v0.4 authoring tables|useStorage|PR 11: native interaction' sdk/CONTRACT.md\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:30:29.080Z", + "type": "custom_tool_call", + "call_id": "call_LTRx6wGbQSmPH25xWQVvqFwy", + "name": "exec", + "input": "const r = await Promise.allSettled([\ntools.exec_command({cmd:\"sed -n '1,130p' sdk/CONTRACT.md\"}),\ntools.exec_command({cmd:\"sed -n '395,445p' sdk/CONTRACT.md\"}),\ntools.exec_command({cmd:\"sed -n '538,790p' sdk/CONTRACT.md\",max_output_tokens:16000}),\ntools.exec_command({cmd:\"cat examples/pomodoro/widget.tsx examples/clock/widget.tsx docs/agent-widget-capture.md\",max_output_tokens:18000})\n]);r.forEach(text);\ntext(await tools.exec_command({cmd:\"npx --no-install weaver init /tmp/weaver-exp-astra/runs/B1\",yield_time_ms:10000,max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:31:28.793Z", + "type": "custom_tool_call", + "call_id": "call_9D7STZ0eRl1aEqc12zqFPtcP", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B1/widget.tsx\",max_output_tokens:4000}));\ntext(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/B1/widget.tsx <<'EOF'\\nimport { useProvider, useStorage, widget } from \\\"@weaver/sdk\\\";\\n\\ntype Weekday = \\\"Mon\\\" | \\\"Tue\\\" | \\\"Wed\\\" | \\\"Thu\\\" | \\\"Fri\\\" | \\\"Sat\\\" | \\\"Sun\\\";\\nconst days: Weekday[] = [\\\"Mon\\\", \\\"Tue\\\", \\\"Wed\\\", \\\"Thu\\\", \\\"Fri\\\", \\\"Sat\\\", \\\"Sun\\\"];\\nconst emptyWeek: Record = {\\n Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0,\\n};\\n\\nexport default widget({\\n name: \\\"Focus Week\\\",\\n size: [320, 200],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n const [counts, setCounts] = useStorage>(\\\"sessions-by-weekday\\\", emptyWeek);\\n const today = time.weekday as Weekday;\\n const total = days.reduce((sum, day) => sum + counts[day], 0);\\n const progress = Math.min(total / 20, 1);\\n\\n return (\\n \\n \\n Focus week\\n {time.weekday}, {time.month} {time.day}\\n \\n\\n \\n {days.map((day) => (\\n \\n {day[0]}\\n {counts[day]}\\n \\n ))}\\n \\n\\n \\n \\n \\n \\n {total} / 20\\n \\n\\n \\n \\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B1\",yield_time_ms:10000,max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:31:40.166Z", + "type": "custom_tool_call", + "call_id": "call_ylyvZaLpOWzyV0olQGUdZ2II", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"rg -n 'fillRect|fillRound|CanvasCtx|canvas.*retained' sdk/CONTRACT.md\",max_output_tokens:3000}));\ntext(await tools.exec_command({cmd:\"sed -n '455,505p' sdk/CONTRACT.md\"}));\n" + }, + { + "timestamp": "2026-09-05T15:32:07.726Z", + "type": "custom_tool_call", + "call_id": "call_eIBYjz5yxNbLp6XqqTQStW7J", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"sed -n '311,362p' sdk/CONTRACT.md\"}));\ntext(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/B1/widget.tsx'\\ns=open(p).read().replace('\\n \\n ''',''' {\\n ctx.clear();\\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \\\"#ffffff1a\\\");\\n if (progress > 0) ctx.fillRoundRect(0, 0, ctx.width * progress, ctx.height, 3, \\\"#5eead4\\\");\\n }} />''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B1\",yield_time_ms:10000,max_output_tokens:5000}));\ntext(await tools.exec_command({cmd:\"mkdir -p /tmp/weaver-exp-astra/runs/B1/captures\\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B1/clicks.actions\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B1/captures/01-initial.png\",yield_time_ms:10000,max_output_tokens:5000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B1/clicks.actions --out /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.png\",yield_time_ms:10000,max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:32:17.673Z", + "type": "custom_tool_call", + "call_id": "call_tVSId6vf6Wg1HglZ181Ylc3X", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B1/captures/01-initial.png\"})).image_url);\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B1/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B1/captures/01-initial.receipt.json /tmp/weaver-exp-astra/runs/B1/captures/02-after-clicks.receipt.json\",max_output_tokens:10000}));\n" + }, + { + "timestamp": "2026-09-05T15:32:45.830Z", + "type": "custom_tool_call", + "call_id": "call_PS3Rs8VtD58RMcUwxcruxmqe", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/B1/widget.tsx'\\ns=open(p).read().replace(' /tmp/weaver-exp-astra/runs/B1/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: B (final capture).\\n- `weaver check` runs: 3. First failed on unsupported JSX `key` and a dynamic class; both subsequent runs passed, including the final source.\\n- `weaver capture` runs: 5. Every receipt has `status: \\\"ok\\\"`.\\n- Defects fixed because of pixels or snapshots: the progress bar was invisible in captures 01 and 02 even though its semantic canvas bounds were 224\u00d76. Replacing `w-0 grow` on the canvas with explicit `w-[224px]` made both track and fill visible in captures 03 and 04. The width comes from the measured 288px content row minus its 12px gap and 52px label.\\n- Spec items not met: none known. Persistence uses `useStorage` with a weekday-keyed record; restart persistence was not independently exercised because captures use isolated empty storage.\\n- Confidence: 9/10.\\n\\nFinal visual and semantic evidence:\\n\\n- `captures/03-initial.png`: Friday highlighted, all seven counts zero, `0 / 20`, visible empty track.\\n- `captures/04-after-clicks.png`: Friday 3, other days zero, `3 / 20`, fill at 15% of the 224px track.\\n- `captures/05-after-reset.png`: three logs followed by Reset week returns every count to zero and empties the track.\\n\\nAll five PNGs were opened and inspected at their 320\u00d7200, scale-1 dimensions; all snapshots and receipts were read. The final captures show aligned header text, equal day cells, legible text, distinct controls, and no clipping or overlap. Both button names match exactly. Native hover feedback is visible after clicks; both controls also declare native pressed styles.\\n\\nThe single pending timer is the subscribed time provider. No fetches, external providers, unresolved images, or frame requests remain. Receipts warn that the repository already contains uncommitted changes; no repository files were edited. No live development window was started, as requested.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:30:06.449Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:16.658Z", + "info": { + "total_token_usage": { + "input_tokens": 39802, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 192, + "reasoning_output_tokens": 18, + "total_tokens": 39994 + }, + "last_token_usage": { + "input_tokens": 20599, + "cached_input_tokens": 19072, + "cache_write_input_tokens": 0, + "output_tokens": 153, + "reasoning_output_tokens": 18, + "total_tokens": 20752 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:29.629Z", + "info": { + "total_token_usage": { + "input_tokens": 62559, + "cached_input_tokens": 58496, + "cache_write_input_tokens": 0, + "output_tokens": 363, + "reasoning_output_tokens": 18, + "total_tokens": 62922 + }, + "last_token_usage": { + "input_tokens": 22757, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 171, + "reasoning_output_tokens": 0, + "total_tokens": 22928 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:29.493Z", + "info": { + "total_token_usage": { + "input_tokens": 95672, + "cached_input_tokens": 81024, + "cache_write_input_tokens": 0, + "output_tokens": 1753, + "reasoning_output_tokens": 208, + "total_tokens": 97425 + }, + "last_token_usage": { + "input_tokens": 33113, + "cached_input_tokens": 22528, + "cache_write_input_tokens": 0, + "output_tokens": 1390, + "reasoning_output_tokens": 190, + "total_tokens": 34503 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:40.273Z", + "info": { + "total_token_usage": { + "input_tokens": 130605, + "cached_input_tokens": 113920, + "cache_write_input_tokens": 0, + "output_tokens": 1866, + "reasoning_output_tokens": 246, + "total_tokens": 132471 + }, + "last_token_usage": { + "input_tokens": 34933, + "cached_input_tokens": 32896, + "cache_write_input_tokens": 0, + "output_tokens": 113, + "reasoning_output_tokens": 38, + "total_tokens": 35046 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:09.819Z", + "info": { + "total_token_usage": { + "input_tokens": 166484, + "cached_input_tokens": 148736, + "cache_write_input_tokens": 0, + "output_tokens": 2551, + "reasoning_output_tokens": 307, + "total_tokens": 169035 + }, + "last_token_usage": { + "input_tokens": 35879, + "cached_input_tokens": 34816, + "cache_write_input_tokens": 0, + "output_tokens": 685, + "reasoning_output_tokens": 61, + "total_tokens": 36564 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:17.749Z", + "info": { + "total_token_usage": { + "input_tokens": 204720, + "cached_input_tokens": 184448, + "cache_write_input_tokens": 0, + "output_tokens": 2729, + "reasoning_output_tokens": 307, + "total_tokens": 207449 + }, + "last_token_usage": { + "input_tokens": 38236, + "cached_input_tokens": 35712, + "cache_write_input_tokens": 0, + "output_tokens": 178, + "reasoning_output_tokens": 0, + "total_tokens": 38414 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:47.937Z", + "info": { + "total_token_usage": { + "input_tokens": 250761, + "cached_input_tokens": 222464, + "cache_write_input_tokens": 0, + "output_tokens": 3358, + "reasoning_output_tokens": 385, + "total_tokens": 254119 + }, + "last_token_usage": { + "input_tokens": 46041, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 629, + "reasoning_output_tokens": 78, + "total_tokens": 46670 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:02.562Z", + "info": { + "total_token_usage": { + "input_tokens": 304400, + "cached_input_tokens": 268416, + "cache_write_input_tokens": 0, + "output_tokens": 3675, + "reasoning_output_tokens": 411, + "total_tokens": 308075 + }, + "last_token_usage": { + "input_tokens": 53639, + "cached_input_tokens": 45952, + "cache_write_input_tokens": 0, + "output_tokens": 317, + "reasoning_output_tokens": 26, + "total_tokens": 53956 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:28.873Z", + "info": { + "total_token_usage": { + "input_tokens": 362723, + "cached_input_tokens": 321920, + "cache_write_input_tokens": 0, + "output_tokens": 4192, + "reasoning_output_tokens": 435, + "total_tokens": 366915 + }, + "last_token_usage": { + "input_tokens": 58323, + "cached_input_tokens": 53504, + "cache_write_input_tokens": 0, + "output_tokens": 517, + "reasoning_output_tokens": 24, + "total_tokens": 58840 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:36.881Z", + "info": { + "total_token_usage": { + "input_tokens": 421619, + "cached_input_tokens": 380160, + "cache_write_input_tokens": 0, + "output_tokens": 4249, + "reasoning_output_tokens": 435, + "total_tokens": 425868 + }, + "last_token_usage": { + "input_tokens": 58896, + "cached_input_tokens": 58240, + "cache_write_input_tokens": 0, + "output_tokens": 57, + "reasoning_output_tokens": 0, + "total_tokens": 58953 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/B2-commands.json b/experiments/render-loop-cadence/astra/evidence/B2-commands.json new file mode 100644 index 00000000..b5d85d10 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B2-commands.json @@ -0,0 +1,128 @@ +[ + { + "timestamp": "2026-09-05T15:37:00.242Z", + "call_id": "call_VjiSOJWLuywb25cwDPwvsAud", + "command": "cat /tmp/weaver-exp-astra/prompts/B2.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:14.083Z", + "call_id": "call_cv0YVJVx5SP0EyIXiZJ23G36", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:14.083Z", + "call_id": "call_cv0YVJVx5SP0EyIXiZJ23G36", + "command": "rg -n '^#{1,6} .*([Mm]odule shape|widget\\(config, component\\)|Hooks|Consolidated v0.4 authoring tables|useStorage|PR 11)' sdk/CONTRACT.md\ncat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:23.661Z", + "call_id": "call_ey0soro57V6bZEcuDo9u2una", + "command": "sed -n '20,135p' sdk/CONTRACT.md\nsed -n '410,451p' sdk/CONTRACT.md\nsed -n '538,740p' sdk/CONTRACT.md\ncat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:23.661Z", + "call_id": "call_ey0soro57V6bZEcuDo9u2una", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/B2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:53.735Z", + "call_id": "call_lVIW0ovLKvb0avj84ApemYXz", + "command": "cat /tmp/weaver-exp-astra/runs/B2/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:53.735Z", + "call_id": "call_lVIW0ovLKvb0avj84ApemYXz", + "command": "rg -n 'dynamic|template|arbitrary|accessibilityLabel|key=' sdk/CONTRACT.md | head -35", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:42.859Z", + "call_id": "call_WV44B1YGx9XlN2PMYZOYYMDg", + "command": "cat > /tmp/weaver-exp-astra/runs/B2/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget } from \"@weaver/sdk\";\n\nconst days = [\n { key: \"Mon\", letter: \"M\" },\n { key: \"Tue\", letter: \"T\" },\n { key: \"Wed\", letter: \"W\" },\n { key: \"Thu\", letter: \"T\" },\n { key: \"Fri\", letter: \"F\" },\n { key: \"Sat\", letter: \"S\" },\n { key: \"Sun\", letter: \"S\" },\n];\nconst emptyWeek: Record = {\n Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0,\n};\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [sessions, setSessions] = useStorage>(\"sessions-by-weekday\", emptyWeek);\n const total = days.reduce((sum, day) => sum + sessions[day.key], 0);\n const fraction = Math.min(1, total / 20);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day) => (\n \n {day.letter}\n {sessions[day.key]}\n \n ))}\n \n\n \n \n WEEKLY SESSIONS\n {total} / 20\n \n \n \n \n \n\n \n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:50.296Z", + "call_id": "call_jL3yUypaLc3wHUz8WvyVbNMx", + "command": "rg -n 'fillRect|fillRound|CanvasCtx|##.*canvas' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:01.909Z", + "call_id": "call_z57ZkKm7QAB3B0Y7mU74ua0u", + "command": "sed -n '322,365p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:01.909Z", + "call_id": "call_z57ZkKm7QAB3B0Y7mU74ua0u", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/B2/widget.tsx'\ns=open(p).read().replace('', ' {\\n ctx.clear();\\n if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, \"#5eead4\");\\n }} />')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:10.984Z", + "call_id": "call_DH7yXD3z5xEBcmn2QcrJSDfy", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/B2/widget.tsx'\ns=open(p).read().replace(' /tmp/weaver-exp-astra/runs/B2/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: B (final capture).\n- Explicit `weaver check` runs: 4. The final check passed.\n- `weaver capture` runs: 5. Every receipt has status `ok`.\n- Defects fixed because pixels or a snapshot exposed them:\n - The progress canvas was 286 px wide inside a 288 px track. The first snapshots exposed the mismatch; corrected the canvas to 288 px, so three sessions fill exactly 15% of the track.\n- Spec items not met: none known.\n- Confidence: 9 / 10.\n\nThe complete widget was written before the first capture. Static diagnostics first corrected an unsupported JSX `key`, a computed utility string, and a percentage-sized canvas; those fixes were not discovered through pixels or snapshots.\n\nOpened and inspected all five PNGs at their real 320×200 dimensions. Final evidence is `captures/03-initial.png`, `captures/04-after-clicks.png`, and `captures/05-after-reset.png`, with their matching snapshots and receipts. Friday is highlighted, all seven initial counts are visible zeros, three Log session clicks produce Friday 3 and `3 / 20`, and Reset week restores every count to zero. Text and controls are legible without overlap or clipping, and the progress label stays above the bar. The snapshots confirm seven equal-width cells and both exact accessible button names.\n\nBoth buttons declare native hover and pressed styles. Hover feedback is visible in the corresponding interaction captures. Storage uses the documented persistent `useStorage` hook with a weekday-keyed object; cross-process persistence was not separately exercised because capture creates isolated empty storage each run.\n\nThe single pending timer is the subscribed time provider. There are no pending fetches, images, external providers, or frame requests. Receipts warn that the shared Weaver checkout already contains uncommitted changes; this task modified no repository files. No live view was started, as instructed.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/B2-tool-results.json b/experiments/render-loop-cadence/astra/evidence/B2-tool-results.json new file mode 100644 index 00000000..3317f82e --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B2-tool-results.json @@ -0,0 +1,246 @@ +[ + { + "timestamp": "2026-09-05T15:37:00.353Z", + "call_id": "call_VjiSOJWLuywb25cwDPwvsAud", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"e0a643\",\"wall_time_seconds\":0.000005709,\"exit_code\":0,\"original_token_count\":1230,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/B2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B2`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B2` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B2/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/B2/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B2/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B2/clicks.actions --out /tmp/weaver-exp-astra/runs/B2/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/B2/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: B (final capture)\\nWrite the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:37:14.212Z", + "call_id": "call_cv0YVJVx5SP0EyIXiZJ23G36", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"a5b9f6\",\"wall_time_seconds\":0.000001959,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"fc1ff8\",\"wall_time_seconds\":0.000002792,\"exit_code\":0,\"original_token_count\":2253,\"output\":\"20:## Module shape\\n43:## `widget(config, component)`\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\nimport { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:37:24.156Z", + "call_id": "call_ey0soro57V6bZEcuDo9u2una", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"a6638e\",\"wall_time_seconds\":0.000001834,\"exit_code\":0,\"original_token_count\":5906,\"output\":\"## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one.\\nRoot hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart.\\nAny slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh.\\nEvaluation failure leaves the prior context, window, and state running; window-config changes restart the process.\\n\\n## Elements (JSX intrinsics)\\n\\n| Element | M1 renders | Props beyond `class`/`children` |\\n|---|---|---|\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 (a styled box; column layout) |\\n| `` | yes | \u2014 (children: strings/numbers, or one `Signal`) |\\n| `` | yes | exactly one of literal `name` or literal `d`; custom paths also accept `viewBox`/`stroke`; no children |\\n| `` | check-error \\\"arrives in M2\\\" | `src` |\\n| `\\n```\\n\\n`onPress` remains required on `\\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B2\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:38:50.296Z", + "type": "custom_tool_call", + "call_id": "call_jL3yUypaLc3wHUz8WvyVbNMx", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"rg -n 'fillRect|fillRound|CanvasCtx|##.*canvas' sdk/CONTRACT.md\",max_output_tokens:1500}));\n" + }, + { + "timestamp": "2026-09-05T15:39:01.909Z", + "type": "custom_tool_call", + "call_id": "call_z57ZkKm7QAB3B0Y7mU74ua0u", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"sed -n '322,365p' sdk/CONTRACT.md\",max_output_tokens:3000}));\ntext(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/B2/widget.tsx'\\ns=open(p).read().replace('', ' {\\\\n ctx.clear();\\\\n if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, \\\"#5eead4\\\");\\\\n }} />')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B2\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:39:10.984Z", + "type": "custom_tool_call", + "call_id": "call_DH7yXD3z5xEBcmn2QcrJSDfy", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/B2/widget.tsx'\\ns=open(p).read().replace(' /tmp/weaver-exp-astra/runs/B2/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: B (final capture).\\n- Explicit `weaver check` runs: 4. The final check passed.\\n- `weaver capture` runs: 5. Every receipt has status `ok`.\\n- Defects fixed because pixels or a snapshot exposed them:\\n - The progress canvas was 286 px wide inside a 288 px track. The first snapshots exposed the mismatch; corrected the canvas to 288 px, so three sessions fill exactly 15% of the track.\\n- Spec items not met: none known.\\n- Confidence: 9 / 10.\\n\\nThe complete widget was written before the first capture. Static diagnostics first corrected an unsupported JSX `key`, a computed utility string, and a percentage-sized canvas; those fixes were not discovered through pixels or snapshots.\\n\\nOpened and inspected all five PNGs at their real 320\u00d7200 dimensions. Final evidence is `captures/03-initial.png`, `captures/04-after-clicks.png`, and `captures/05-after-reset.png`, with their matching snapshots and receipts. Friday is highlighted, all seven initial counts are visible zeros, three Log session clicks produce Friday 3 and `3 / 20`, and Reset week restores every count to zero. Text and controls are legible without overlap or clipping, and the progress label stays above the bar. The snapshots confirm seven equal-width cells and both exact accessible button names.\\n\\nBoth buttons declare native hover and pressed styles. Hover feedback is visible in the corresponding interaction captures. Storage uses the documented persistent `useStorage` hook with a weekday-keyed object; cross-process persistence was not separately exercised because capture creates isolated empty storage each run.\\n\\nThe single pending timer is the subscribed time provider. There are no pending fetches, images, external providers, or frame requests. Receipts warn that the shared Weaver checkout already contains uncommitted changes; this task modified no repository files. No live view was started, as instructed.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:37:00.354Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 7808, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 7808, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:14.213Z", + "info": { + "total_token_usage": { + "input_tokens": 39802, + "cached_input_tokens": 26752, + "cache_write_input_tokens": 0, + "output_tokens": 222, + "reasoning_output_tokens": 28, + "total_tokens": 40024 + }, + "last_token_usage": { + "input_tokens": 20599, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 183, + "reasoning_output_tokens": 28, + "total_tokens": 20782 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:24.156Z", + "info": { + "total_token_usage": { + "input_tokens": 65504, + "cached_input_tokens": 47232, + "cache_write_input_tokens": 0, + "output_tokens": 336, + "reasoning_output_tokens": 28, + "total_tokens": 65840 + }, + "last_token_usage": { + "input_tokens": 25702, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 114, + "reasoning_output_tokens": 0, + "total_tokens": 25816 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:53.844Z", + "info": { + "total_token_usage": { + "input_tokens": 97641, + "cached_input_tokens": 72704, + "cache_write_input_tokens": 0, + "output_tokens": 780, + "reasoning_output_tokens": 387, + "total_tokens": 98421 + }, + "last_token_usage": { + "input_tokens": 32137, + "cached_input_tokens": 25472, + "cache_write_input_tokens": 0, + "output_tokens": 444, + "reasoning_output_tokens": 359, + "total_tokens": 32581 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:43.827Z", + "info": { + "total_token_usage": { + "input_tokens": 130783, + "cached_input_tokens": 104704, + "cache_write_input_tokens": 0, + "output_tokens": 2092, + "reasoning_output_tokens": 396, + "total_tokens": 132875 + }, + "last_token_usage": { + "input_tokens": 33142, + "cached_input_tokens": 32000, + "cache_write_input_tokens": 0, + "output_tokens": 1312, + "reasoning_output_tokens": 9, + "total_tokens": 34454 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:50.365Z", + "info": { + "total_token_usage": { + "input_tokens": 165420, + "cached_input_tokens": 137728, + "cache_write_input_tokens": 0, + "output_tokens": 2153, + "reasoning_output_tokens": 407, + "total_tokens": 167573 + }, + "last_token_usage": { + "input_tokens": 34637, + "cached_input_tokens": 33024, + "cache_write_input_tokens": 0, + "output_tokens": 61, + "reasoning_output_tokens": 11, + "total_tokens": 34698 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:02.647Z", + "info": { + "total_token_usage": { + "input_tokens": 200260, + "cached_input_tokens": 172160, + "cache_write_input_tokens": 0, + "output_tokens": 2381, + "reasoning_output_tokens": 407, + "total_tokens": 202641 + }, + "last_token_usage": { + "input_tokens": 34840, + "cached_input_tokens": 34432, + "cache_write_input_tokens": 0, + "output_tokens": 228, + "reasoning_output_tokens": 0, + "total_tokens": 35068 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:11.687Z", + "info": { + "total_token_usage": { + "input_tokens": 236214, + "cached_input_tokens": 206848, + "cache_write_input_tokens": 0, + "output_tokens": 2539, + "reasoning_output_tokens": 407, + "total_tokens": 238753 + }, + "last_token_usage": { + "input_tokens": 35954, + "cached_input_tokens": 34688, + "cache_write_input_tokens": 0, + "output_tokens": 158, + "reasoning_output_tokens": 0, + "total_tokens": 36112 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:26.384Z", + "info": { + "total_token_usage": { + "input_tokens": 272401, + "cached_input_tokens": 242560, + "cache_write_input_tokens": 0, + "output_tokens": 2630, + "reasoning_output_tokens": 407, + "total_tokens": 275031 + }, + "last_token_usage": { + "input_tokens": 36187, + "cached_input_tokens": 35712, + "cache_write_input_tokens": 0, + "output_tokens": 91, + "reasoning_output_tokens": 0, + "total_tokens": 36278 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:34.858Z", + "info": { + "total_token_usage": { + "input_tokens": 309124, + "cached_input_tokens": 278528, + "cache_write_input_tokens": 0, + "output_tokens": 2740, + "reasoning_output_tokens": 407, + "total_tokens": 311864 + }, + "last_token_usage": { + "input_tokens": 36723, + "cached_input_tokens": 35968, + "cache_write_input_tokens": 0, + "output_tokens": 110, + "reasoning_output_tokens": 0, + "total_tokens": 36833 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:44.316Z", + "info": { + "total_token_usage": { + "input_tokens": 346470, + "cached_input_tokens": 315136, + "cache_write_input_tokens": 0, + "output_tokens": 2911, + "reasoning_output_tokens": 407, + "total_tokens": 349381 + }, + "last_token_usage": { + "input_tokens": 37346, + "cached_input_tokens": 36608, + "cache_write_input_tokens": 0, + "output_tokens": 171, + "reasoning_output_tokens": 0, + "total_tokens": 37517 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:10.393Z", + "info": { + "total_token_usage": { + "input_tokens": 392021, + "cached_input_tokens": 352256, + "cache_write_input_tokens": 0, + "output_tokens": 3447, + "reasoning_output_tokens": 446, + "total_tokens": 395468 + }, + "last_token_usage": { + "input_tokens": 45551, + "cached_input_tokens": 37120, + "cache_write_input_tokens": 0, + "output_tokens": 536, + "reasoning_output_tokens": 39, + "total_tokens": 46087 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:20.552Z", + "info": { + "total_token_usage": { + "input_tokens": 439580, + "cached_input_tokens": 397696, + "cache_write_input_tokens": 0, + "output_tokens": 3639, + "reasoning_output_tokens": 446, + "total_tokens": 443219 + }, + "last_token_usage": { + "input_tokens": 47559, + "cached_input_tokens": 45440, + "cache_write_input_tokens": 0, + "output_tokens": 192, + "reasoning_output_tokens": 0, + "total_tokens": 47751 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:49.478Z", + "info": { + "total_token_usage": { + "input_tokens": 496496, + "cached_input_tokens": 445184, + "cache_write_input_tokens": 0, + "output_tokens": 4132, + "reasoning_output_tokens": 478, + "total_tokens": 500628 + }, + "last_token_usage": { + "input_tokens": 56916, + "cached_input_tokens": 47488, + "cache_write_input_tokens": 0, + "output_tokens": 493, + "reasoning_output_tokens": 32, + "total_tokens": 57409 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:56.688Z", + "info": { + "total_token_usage": { + "input_tokens": 553963, + "cached_input_tokens": 502016, + "cache_write_input_tokens": 0, + "output_tokens": 4192, + "reasoning_output_tokens": 478, + "total_tokens": 558155 + }, + "last_token_usage": { + "input_tokens": 57467, + "cached_input_tokens": 56832, + "cache_write_input_tokens": 0, + "output_tokens": 60, + "reasoning_output_tokens": 0, + "total_tokens": 57527 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/B3-commands.json b/experiments/render-loop-cadence/astra/evidence/B3-commands.json new file mode 100644 index 00000000..50252a8c --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B3-commands.json @@ -0,0 +1,104 @@ +[ + { + "timestamp": "2026-09-05T15:42:19.202Z", + "call_id": "call_7BXheFuMTH65VWpADXJQvr8Y", + "command": "cat /tmp/weaver-exp-astra/prompts/B3.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:31.378Z", + "call_id": "call_j7mkVlTgzO3Rt79bGscGr03P", + "command": "cat .agents/skills/conjure-widget/SKILL.md; rg -n 'Module shape|widget\\(config|Hooks|Consolidated v0.4 authoring tables|useStorage|PR 11: native' sdk/CONTRACT.md; cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:38.391Z", + "call_id": "call_elRQYQIQA5MrHuUX68P3RzZ9", + "command": "sed -n '1,130p' sdk/CONTRACT.md; sed -n '410,435p' sdk/CONTRACT.md; sed -n '538,750p' sdk/CONTRACT.md; cat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:02.336Z", + "call_id": "call_VbLz3HYGPcIelgaGA3oqEucE", + "command": "rg -n 'fillRect|roundRect|fillRound|CanvasCtx|accessibilityLabel' sdk/CONTRACT.md; npx --no-install weaver init /tmp/weaver-exp-astra/runs/B3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:09.448Z", + "call_id": "call_qW4cSOvqsVaALho7z3CZpGDk", + "command": "cat /tmp/weaver-exp-astra/runs/B3/widget.tsx; sed -n '320,355p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:04.126Z", + "call_id": "call_ak4sUGHuoOSvwWxkJdpv9mMA", + "command": "cat > /tmp/weaver-exp-astra/runs/B3/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget, type CanvasCtx } from \"@weaver/sdk\";\n\nconst days = [\n { key: \"Mon\", letter: \"M\" },\n { key: \"Tue\", letter: \"T\" },\n { key: \"Wed\", letter: \"W\" },\n { key: \"Thu\", letter: \"T\" },\n { key: \"Fri\", letter: \"F\" },\n { key: \"Sat\", letter: \"S\" },\n { key: \"Sun\", letter: \"S\" },\n];\nconst emptyWeek: Record = {\n Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0,\n};\n\nfunction drawProgress(ctx: CanvasCtx, total: number): void {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff20\");\n if (total > 0) {\n ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, \"#5eead4\");\n }\n}\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\n const total = days.reduce((sum, day) => sum + counts[day.key], 0);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day) => (\n \n {day.letter}\n {counts[day.key]}\n \n ))}\n \n\n \n drawProgress(ctx, total)} />\n {total} / 20\n \n\n \n setCounts((current) => ({ ...current, [time.weekday]: current[time.weekday] + 1 }))}\n >\n \n Log session\n \n \n setCounts({ ...emptyWeek })}\n >\n \n Reset week\n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:15.895Z", + "call_id": "call_JyBEA2QaTL0Ubc8tBnM5wGYl", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path('/tmp/weaver-exp-astra/runs/B3/widget.tsx')\np.write_text(p.read_text().replace(' key={day.key}\\n', ''))\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:23.925Z", + "call_id": "call_G5pjvXMcs8lp2NqqN0WDegoQ", + "command": "mkdir -p /tmp/weaver-exp-astra/runs/B3/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B3/clicks.actions\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:31.350Z", + "call_id": "call_ujxNWJaVJHlXNB9iHUQAPaSY", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:43.401Z", + "call_id": "call_UuMK0ZaA8P2tEey9IfrMMSiZ", + "command": "cat /tmp/weaver-exp-astra/runs/B3/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/01-initial.receipt.json /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:05.162Z", + "call_id": "call_ZaOkqF4yBFssomHli0BVeXib", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path('/tmp/weaver-exp-astra/runs/B3/widget.tsx')\ns = p.read_text().replace('class=\"w-[0px] grow h-[6px]\"', 'class=\"w-[232px] h-[6px] shrink-0\"')\ns = s.replace('class=\"text-[12px] font-medium tabular-nums text-[#f5f6f8]/75\"', 'class=\"w-[0px] grow text-right text-[12px] font-medium tabular-nums text-[#f5f6f8]/75\"')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:14.525Z", + "call_id": "call_ue2mR55IshIg4YamohAM8lMl", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/03-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:14.525Z", + "call_id": "call_ue2mR55IshIg4YamohAM8lMl", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/04-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:29.067Z", + "call_id": "call_r3YiLmzJq6clLmKAitwD2qSd", + "command": "cat /tmp/weaver-exp-astra/runs/B3/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/04-after-clicks.snapshot.txt; python3 - <<'PY'\nimport json\nfrom pathlib import Path\nfor name in ['03-initial', '04-after-clicks']:\n p=Path('/tmp/weaver-exp-astra/runs/B3/captures')/(name+'.receipt.json')\n r=json.loads(p.read_text()); print(name, r['status'], r['pending'], r['warnings'])\nPY", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:41.506Z", + "call_id": "call_Sr2kaGgMQzB9eL09FcTyrKeA", + "command": "python3 - <<'PY'\nimport json\nfrom pathlib import Path\nroot=Path('/tmp/weaver-exp-astra/runs/B3')\na=json.loads((root/'clicks.actions').read_text())\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\n(root/'reset.actions').write_text(json.dumps(a, indent=2)+'\\n')\nPY\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/reset.actions --out /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:50.849Z", + "call_id": "call_JZA9oiDCn0fBd24xr9hqwYd2", + "command": "cat /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:14.509Z", + "call_id": "call_E46VNRbJgulHf3vURJ4EQSLP", + "command": "cat > /tmp/weaver-exp-astra/runs/B3/REPORT.md <<'EOF'\n# Focus Week\n\n- Condition: B (final capture).\n- `weaver check` runs: 3. First failed because `column` does not accept a `key` prop; the following two passed.\n- `weaver capture` runs: 5. All receipts have status `ok`; every PNG was opened at its native 320×200 dimensions and every snapshot was read.\n- Defects fixed because pixels or snapshots exposed them:\n - The progress canvas had `w-[0px] grow`: its semantic bounds grew, but its drawing remained invisible. Changed it to an explicit 232 px drawing width, following the examples' explicit canvas dimensions, and reserved a separate 44 px label region with a 12 px gap. Captures 03 and 04 show the empty track and 15% fill respectively.\n- Spec items not met: none identified. Persistence uses `useStorage` with a weekday-keyed object; capture isolates storage, so restart persistence was not separately exercised. No live dev session was run, as instructed.\n- Confidence: 9/10.\n\nFinal evidence: `captures/03-initial.png` shows Friday highlighted and seven zeros; `captures/04-after-clicks.png` shows Friday 3, six zeros, `3 / 20`, and 15% fill. `captures/05-after-reset.png` verifies three logs followed by Reset week returns all seven days and the total to zero. The semantic trees expose exactly `Log session` and `Reset week` as button names. Both buttons use native hover and pressed styles. No clipping or overlap was observed at 1× scale.\n\nThe receipts' sole warning reports pre-existing uncommitted repository changes; this task modified no repository files. The one pending timer is the subscribed time provider; there are no fetches, unresolved images, external providers, or queued frames.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/B3-tool-results.json b/experiments/render-loop-cadence/astra/evidence/B3-tool-results.json new file mode 100644 index 00000000..1065ed1b --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B3-tool-results.json @@ -0,0 +1,250 @@ +[ + { + "timestamp": "2026-09-05T15:42:19.339Z", + "call_id": "call_7BXheFuMTH65VWpADXJQvr8Y", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f35074\",\"wall_time_seconds\":0.000003167,\"exit_code\":0,\"original_token_count\":1230,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/B3 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B3`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B3` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B3/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/B3/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/B3/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: B (final capture)\\nWrite the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:42:31.461Z", + "call_id": "call_j7mkVlTgzO3Rt79bGscGr03P", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"2bb4ab\",\"wall_time_seconds\":0.000002917,\"exit_code\":0,\"original_token_count\":4281,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\nimport { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:42:38.461Z", + "call_id": "call_elRQYQIQA5MrHuUX68P3RzZ9", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"4c6423\",\"wall_time_seconds\":0.000002708,\"exit_code\":0,\"original_token_count\":6008,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one.\\nRoot hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart.\\nAny slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh.\\nEvaluation failure leaves the prior context, window, and state running; window-config changes restart the process.\\n\\n## Elements (JSX intrinsics)\\n\\n| Element | M1 renders | Props beyond `class`/`children` |\\n|---|---|---|\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 (a styled box; column layout) |\\n| `` | yes | \u2014 (children: strings/numbers, or one `Signal`) |\\n| `` | yes | exactly one of literal `name` or literal `d`; custom paths also accept `viewBox`/`stroke`; no children |\\n| `` | check-error \\\"arrives in M2\\\" | `src` |\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n\\n```ts\\nuseProvider(\\\"cpu\\\") // { percent: number, perCore: number[] } 1 Hz\\nuseProvider(\\\"memory\\\") // { usedMb: number, totalMb: number, percent: number } 1 Hz\\n```\\n\\nDelivered by `weaverd` (the host). `time` remains SDK-local. Subscribing\\nwithout the host running is a runtime error that names the fix (`weaver up`);\\n`weaver dev` auto-starts the host.\\n\\n`cpu.percent` is whole-machine utilization from 0\u2013100, not the sum of cores;\\n`perCore` reports the same 0\u2013100 utilization for each logical core. Memory\\n`usedMb` is physical memory that is not currently free or reclaimable idle\\ncache, `totalMb` is installed physical memory, and `percent` is their ratio.\\nThese meanings stay platform-neutral even though each host uses its public OS\\ncounters to project them.\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n setCounts({ ...emptyWeek })}\\n >\\n \\n Reset week\\n \\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:15.895Z", + "type": "custom_tool_call", + "call_id": "call_JyBEA2QaTL0Ubc8tBnM5wGYl", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nfrom pathlib import Path\\np = Path('/tmp/weaver-exp-astra/runs/B3/widget.tsx')\\np.write_text(p.read_text().replace(' key={day.key}\\\\n', ''))\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:23.925Z", + "type": "custom_tool_call", + "call_id": "call_G5pjvXMcs8lp2NqqN0WDegoQ", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"mkdir -p /tmp/weaver-exp-astra/runs/B3/captures\\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B3/clicks.actions\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/01-initial.png\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:31.350Z", + "type": "custom_tool_call", + "call_id": "call_ujxNWJaVJHlXNB9iHUQAPaSY", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.png\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:43.401Z", + "type": "custom_tool_call", + "call_id": "call_UuMK0ZaA8P2tEey9IfrMMSiZ", + "name": "exec", + "input": "const results = await Promise.allSettled([\ntools.view_image({path:\"/tmp/weaver-exp-astra/runs/B3/captures/01-initial.png\"}),\ntools.view_image({path:\"/tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.png\"}),\ntools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B3/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/01-initial.receipt.json /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/02-after-clicks.receipt.json\",max_output_tokens:8000})\n]); \nfor (const r of results) {if(r.status===\"fulfilled\" && r.value.image_url) image(r.value.image_url);else text(r);}\n" + }, + { + "timestamp": "2026-09-05T15:45:05.162Z", + "type": "custom_tool_call", + "call_id": "call_ZaOkqF4yBFssomHli0BVeXib", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nfrom pathlib import Path\\np = Path('/tmp/weaver-exp-astra/runs/B3/widget.tsx')\\ns = p.read_text().replace('class=\\\"w-[0px] grow h-[6px]\\\"', 'class=\\\"w-[232px] h-[6px] shrink-0\\\"')\\ns = s.replace('class=\\\"text-[12px] font-medium tabular-nums text-[#f5f6f8]/75\\\"', 'class=\\\"w-[0px] grow text-right text-[12px] font-medium tabular-nums text-[#f5f6f8]/75\\\"')\\np.write_text(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B3\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:14.525Z", + "type": "custom_tool_call", + "call_id": "call_ue2mR55IshIg4YamohAM8lMl", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/03-initial.png\",max_output_tokens:2000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/04-after-clicks.png\",max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:29.067Z", + "type": "custom_tool_call", + "call_id": "call_r3YiLmzJq6clLmKAitwD2qSd", + "name": "exec", + "input": "const results=await Promise.allSettled([\ntools.view_image({path:\"/tmp/weaver-exp-astra/runs/B3/captures/03-initial.png\"}),\ntools.view_image({path:\"/tmp/weaver-exp-astra/runs/B3/captures/04-after-clicks.png\"}),\ntools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B3/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/04-after-clicks.snapshot.txt; python3 - <<'PY'\\nimport json\\nfrom pathlib import Path\\nfor name in ['03-initial', '04-after-clicks']:\\n p=Path('/tmp/weaver-exp-astra/runs/B3/captures')/(name+'.receipt.json')\\n r=json.loads(p.read_text()); print(name, r['status'], r['pending'], r['warnings'])\\nPY\",max_output_tokens:6500})\n]); for(const r of results){if(r.status===\"fulfilled\"&&r.value.image_url) image(r.value.image_url);else text(r);}\n" + }, + { + "timestamp": "2026-09-05T15:45:41.506Z", + "type": "custom_tool_call", + "call_id": "call_Sr2kaGgMQzB9eL09FcTyrKeA", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\nfrom pathlib import Path\\nroot=Path('/tmp/weaver-exp-astra/runs/B3')\\na=json.loads((root/'clicks.actions').read_text())\\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\n(root/'reset.actions').write_text(json.dumps(a, indent=2)+'\\\\n')\\nPY\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/reset.actions --out /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.png\",max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:50.849Z", + "type": "custom_tool_call", + "call_id": "call_JZA9oiDCn0fBd24xr9hqwYd2", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/B3/captures/05-after-reset.receipt.json\",max_output_tokens:4000}));\n" + }, + { + "timestamp": "2026-09-05T15:46:14.509Z", + "type": "custom_tool_call", + "call_id": "call_E46VNRbJgulHf3vURJ4EQSLP", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/B3/REPORT.md <<'EOF'\\n# Focus Week\\n\\n- Condition: B (final capture).\\n- `weaver check` runs: 3. First failed because `column` does not accept a `key` prop; the following two passed.\\n- `weaver capture` runs: 5. All receipts have status `ok`; every PNG was opened at its native 320\u00d7200 dimensions and every snapshot was read.\\n- Defects fixed because pixels or snapshots exposed them:\\n - The progress canvas had `w-[0px] grow`: its semantic bounds grew, but its drawing remained invisible. Changed it to an explicit 232 px drawing width, following the examples' explicit canvas dimensions, and reserved a separate 44 px label region with a 12 px gap. Captures 03 and 04 show the empty track and 15% fill respectively.\\n- Spec items not met: none identified. Persistence uses `useStorage` with a weekday-keyed object; capture isolates storage, so restart persistence was not separately exercised. No live dev session was run, as instructed.\\n- Confidence: 9/10.\\n\\nFinal evidence: `captures/03-initial.png` shows Friday highlighted and seven zeros; `captures/04-after-clicks.png` shows Friday 3, six zeros, `3 / 20`, and 15% fill. `captures/05-after-reset.png` verifies three logs followed by Reset week returns all seven days and the total to zero. The semantic trees expose exactly `Log session` and `Reset week` as button names. Both buttons use native hover and pressed styles. No clipping or overlap was observed at 1\u00d7 scale.\\n\\nThe receipts' sole warning reports pre-existing uncommitted repository changes; this task modified no repository files. The one pending timer is the subscribed time provider; there are no fetches, unresolved images, external providers, or queued frames.\\nEOF\",max_output_tokens:2000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:42:19.340Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:42:31.461Z", + "info": { + "total_token_usage": { + "input_tokens": 39801, + "cached_input_tokens": 37888, + "cache_write_input_tokens": 0, + "output_tokens": 199, + "reasoning_output_tokens": 31, + "total_tokens": 40000 + }, + "last_token_usage": { + "input_tokens": 20598, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 160, + "reasoning_output_tokens": 31, + "total_tokens": 20758 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:42:38.462Z", + "info": { + "total_token_usage": { + "input_tokens": 65499, + "cached_input_tokens": 58368, + "cache_write_input_tokens": 0, + "output_tokens": 278, + "reasoning_output_tokens": 31, + "total_tokens": 65777 + }, + "last_token_usage": { + "input_tokens": 25698, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 79, + "reasoning_output_tokens": 0, + "total_tokens": 25777 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:02.792Z", + "info": { + "total_token_usage": { + "input_tokens": 97603, + "cached_input_tokens": 83840, + "cache_write_input_tokens": 0, + "output_tokens": 594, + "reasoning_output_tokens": 274, + "total_tokens": 98197 + }, + "last_token_usage": { + "input_tokens": 32104, + "cached_input_tokens": 25472, + "cache_write_input_tokens": 0, + "output_tokens": 316, + "reasoning_output_tokens": 243, + "total_tokens": 32420 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:09.531Z", + "info": { + "total_token_usage": { + "input_tokens": 130177, + "cached_input_tokens": 115712, + "cache_write_input_tokens": 0, + "output_tokens": 662, + "reasoning_output_tokens": 284, + "total_tokens": 130839 + }, + "last_token_usage": { + "input_tokens": 32574, + "cached_input_tokens": 31872, + "cache_write_input_tokens": 0, + "output_tokens": 68, + "reasoning_output_tokens": 10, + "total_tokens": 32642 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:04.805Z", + "info": { + "total_token_usage": { + "input_tokens": 163582, + "cached_input_tokens": 148096, + "cache_write_input_tokens": 0, + "output_tokens": 2005, + "reasoning_output_tokens": 351, + "total_tokens": 165587 + }, + "last_token_usage": { + "input_tokens": 33405, + "cached_input_tokens": 32384, + "cache_write_input_tokens": 0, + "output_tokens": 1343, + "reasoning_output_tokens": 67, + "total_tokens": 34748 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:16.664Z", + "info": { + "total_token_usage": { + "input_tokens": 198474, + "cached_input_tokens": 181376, + "cache_write_input_tokens": 0, + "output_tokens": 2163, + "reasoning_output_tokens": 362, + "total_tokens": 200637 + }, + "last_token_usage": { + "input_tokens": 34892, + "cached_input_tokens": 33280, + "cache_write_input_tokens": 0, + "output_tokens": 158, + "reasoning_output_tokens": 11, + "total_tokens": 35050 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:24.739Z", + "info": { + "total_token_usage": { + "input_tokens": 233596, + "cached_input_tokens": 216064, + "cache_write_input_tokens": 0, + "output_tokens": 2293, + "reasoning_output_tokens": 362, + "total_tokens": 235889 + }, + "last_token_usage": { + "input_tokens": 35122, + "cached_input_tokens": 34688, + "cache_write_input_tokens": 0, + "output_tokens": 130, + "reasoning_output_tokens": 0, + "total_tokens": 35252 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:32.139Z", + "info": { + "total_token_usage": { + "input_tokens": 269293, + "cached_input_tokens": 235008, + "cache_write_input_tokens": 0, + "output_tokens": 2396, + "reasoning_output_tokens": 362, + "total_tokens": 271689 + }, + "last_token_usage": { + "input_tokens": 35697, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 103, + "reasoning_output_tokens": 0, + "total_tokens": 35800 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:43.480Z", + "info": { + "total_token_usage": { + "input_tokens": 305607, + "cached_input_tokens": 270464, + "cache_write_input_tokens": 0, + "output_tokens": 2599, + "reasoning_output_tokens": 362, + "total_tokens": 308206 + }, + "last_token_usage": { + "input_tokens": 36314, + "cached_input_tokens": 35456, + "cache_write_input_tokens": 0, + "output_tokens": 203, + "reasoning_output_tokens": 0, + "total_tokens": 36517 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:05.894Z", + "info": { + "total_token_usage": { + "input_tokens": 349803, + "cached_input_tokens": 306560, + "cache_write_input_tokens": 0, + "output_tokens": 2980, + "reasoning_output_tokens": 504, + "total_tokens": 352783 + }, + "last_token_usage": { + "input_tokens": 44196, + "cached_input_tokens": 36096, + "cache_write_input_tokens": 0, + "output_tokens": 381, + "reasoning_output_tokens": 142, + "total_tokens": 44577 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:16.070Z", + "info": { + "total_token_usage": { + "input_tokens": 394450, + "cached_input_tokens": 350720, + "cache_write_input_tokens": 0, + "output_tokens": 3157, + "reasoning_output_tokens": 504, + "total_tokens": 397607 + }, + "last_token_usage": { + "input_tokens": 44647, + "cached_input_tokens": 44160, + "cache_write_input_tokens": 0, + "output_tokens": 177, + "reasoning_output_tokens": 0, + "total_tokens": 44824 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:29.178Z", + "info": { + "total_token_usage": { + "input_tokens": 440199, + "cached_input_tokens": 395264, + "cache_write_input_tokens": 0, + "output_tokens": 3398, + "reasoning_output_tokens": 504, + "total_tokens": 443597 + }, + "last_token_usage": { + "input_tokens": 45749, + "cached_input_tokens": 44544, + "cache_write_input_tokens": 0, + "output_tokens": 241, + "reasoning_output_tokens": 0, + "total_tokens": 45990 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:42.569Z", + "info": { + "total_token_usage": { + "input_tokens": 492676, + "cached_input_tokens": 440960, + "cache_write_input_tokens": 0, + "output_tokens": 3646, + "reasoning_output_tokens": 558, + "total_tokens": 496322 + }, + "last_token_usage": { + "input_tokens": 52477, + "cached_input_tokens": 45696, + "cache_write_input_tokens": 0, + "output_tokens": 248, + "reasoning_output_tokens": 54, + "total_tokens": 52725 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:50.953Z", + "info": { + "total_token_usage": { + "input_tokens": 545907, + "cached_input_tokens": 493312, + "cache_write_input_tokens": 0, + "output_tokens": 3747, + "reasoning_output_tokens": 558, + "total_tokens": 549654 + }, + "last_token_usage": { + "input_tokens": 53231, + "cached_input_tokens": 52352, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 53332 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:14.572Z", + "info": { + "total_token_usage": { + "input_tokens": 603123, + "cached_input_tokens": 546432, + "cache_write_input_tokens": 0, + "output_tokens": 4185, + "reasoning_output_tokens": 558, + "total_tokens": 607308 + }, + "last_token_usage": { + "input_tokens": 57216, + "cached_input_tokens": 53120, + "cache_write_input_tokens": 0, + "output_tokens": 438, + "reasoning_output_tokens": 0, + "total_tokens": 57654 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:21.257Z", + "info": { + "total_token_usage": { + "input_tokens": 660833, + "cached_input_tokens": 603520, + "cache_write_input_tokens": 0, + "output_tokens": 4239, + "reasoning_output_tokens": 558, + "total_tokens": 665072 + }, + "last_token_usage": { + "input_tokens": 57710, + "cached_input_tokens": 57088, + "cache_write_input_tokens": 0, + "output_tokens": 54, + "reasoning_output_tokens": 0, + "total_tokens": 57764 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/B4-commands.json b/experiments/render-loop-cadence/astra/evidence/B4-commands.json new file mode 100644 index 00000000..17c474e7 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B4-commands.json @@ -0,0 +1,110 @@ +[ + { + "timestamp": "2026-09-05T15:42:49.693Z", + "call_id": "call_VHAgqRgLIip6clGj9RDEnbon", + "command": "cat /tmp/weaver-exp-astra/prompts/B4.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:07.156Z", + "call_id": "call_q2PIyUIDzpQRxX2PJwhFhE8H", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:07.156Z", + "call_id": "call_q2PIyUIDzpQRxX2PJwhFhE8H", + "command": "rg -n '^#{1,6} .*|Module shape|widget\\(config|useStorage|PR 11|Consolidated v0.4' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:07.156Z", + "call_id": "call_q2PIyUIDzpQRxX2PJwhFhE8H", + "command": "cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:15.606Z", + "call_id": "call_3vMILMZZQ686sAkJc6GZORed", + "command": "sed -n '20,114p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:15.606Z", + "call_id": "call_3vMILMZZQ686sAkJc6GZORed", + "command": "sed -n '410,418p' sdk/CONTRACT.md; sed -n '464,505p' sdk/CONTRACT.md; sed -n '538,632p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:15.606Z", + "call_id": "call_3vMILMZZQ686sAkJc6GZORed", + "command": "cat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:15.606Z", + "call_id": "call_3vMILMZZQ686sAkJc6GZORed", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/B4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:22.739Z", + "call_id": "call_xZTnCSgGefatR3KrRBlr1rtA", + "command": "cat /tmp/weaver-exp-astra/runs/B4/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:22.739Z", + "call_id": "call_xZTnCSgGefatR3KrRBlr1rtA", + "command": "cat > /tmp/weaver-exp-astra/runs/B4/widget.tsx <<'EOF'\nimport { useProvider, useStorage, widget } from \"@weaver/sdk\";\n\nconst days = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\nconst letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\nconst emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 };\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n const [sessions, setSessions] = useStorage>(\"sessions\", emptyWeek);\n const total = days.reduce((sum, day) => sum + sessions[day], 0);\n const progress = Math.min(total, 20);\n\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n\n \n {days.map((day, index) => (\n \n {letters[index]}\n {sessions[day]}\n \n ))}\n \n\n \n \n {progress > 0 ? : null}\n \n {total} / 20\n \n\n \n \n \n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:45.155Z", + "call_id": "call_2zMfSKZrIeI2JoC53v7U3a9F", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/B4/widget.tsx'\ns=open(p).read()\nwidth='\\n'.join(' progress === '+str(i)+' ? \"w-'+str(i)+'/20 h-full bg-[#5eead4] rounded-full\" :' for i in range(1,20))+'\\n \"w-full h-full bg-[#5eead4] rounded-full\";'\ns=s.replace(' const progress = Math.min(total, 20);',' const progress = Math.min(total, 20);\\n const progressClass =\\n'+width)\ns=s.replace('class={`w-${progress}/20 h-full bg-[#5eead4] rounded-full`}', 'class={progressClass}')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:45.155Z", + "call_id": "call_2zMfSKZrIeI2JoC53v7U3a9F", + "command": "mkdir -p /tmp/weaver-exp-astra/runs/B4/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B4/clicks.actions\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B4/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:55.553Z", + "call_id": "call_2gs0oucYUoYTnCdmzIm5d6av", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/clicks.actions --out /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:55.553Z", + "call_id": "call_2gs0oucYUoYTnCdmzIm5d6av", + "command": "cat /tmp/weaver-exp-astra/runs/B4/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/01-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:03.922Z", + "call_id": "call_cnbOBVAj3Nk8qFsXhdLAm5I9", + "command": "cat /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:20.431Z", + "call_id": "call_VYTzx6YDkqqqji1lklmBjT1w", + "command": "python3 - <<'PY'\nimport json\np='/tmp/weaver-exp-astra/runs/B4/'\ndata=json.load(open(p+'clicks.actions'))\ndata['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\njson.dump(data,open(p+'reset.actions','w'),indent=2)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/reset.actions --out /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:29.781Z", + "call_id": "call_crhMQGsEEnUF5qbL5035Ov8V", + "command": "cat /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:57.826Z", + "call_id": "call_aStKTLpYu2yCi3MwxwWGQAhn", + "command": "cat > /tmp/weaver-exp-astra/runs/B4/REPORT.md <<'EOF'\n# Focus Week — B4\n\n- Condition: B (final capture). The complete widget was authored before the first capture.\n- `weaver check` runs: 3 (first failed on an unbounded dynamic class; two subsequent runs passed).\n- `weaver capture` runs: 3, all with status `ok`.\n- Defects fixed because of pixels or snapshots: none.\n- Spec items not met: none identified. Persistence uses `useStorage` with a record keyed by weekday; restarting a live widget was not exercised because live execution was prohibited. Reset is manual, as specified.\n- Confidence: 9/10.\n\nOpened and inspected every PNG at its native 320×200 dimensions and read every snapshot and receipt:\n\n- `captures/01-initial.png`: Friday highlighted, seven zero counts, `0 / 20`, empty bar, equal day cells and aligned header. Text, spacing, contrast, and button bounds are clean.\n- `captures/02-after-clicks.png`: Friday 3, every other day 0, `3 / 20`; semantic fill width 31.800001 against track width 212 confirms 15%. Primary native hover color is visible.\n- `captures/03-after-reset.png`: three logs followed by Reset week returns every count and the total to zero and empties the bar. Secondary native hover color is visible.\n\nAccessible button names are exactly `Log session` and `Reset week`. Both declare native hover and pressed styles. The widget subscribes only to time and makes no network calls. All receipts report no pending fetches, images, providers, or frame requests; the time subscription accounts for the pending timer. Their sole warning records pre-existing uncommitted checkout changes; no repository files were modified. `weaver dev` was not run.\n\nThe static-check fix replaced an arbitrary interpolated progress class with an explicit set of validated width classes for the 20-session goal. It happened before the first capture and was not a pixel-driven repair.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/B4-tool-results.json b/experiments/render-loop-cadence/astra/evidence/B4-tool-results.json new file mode 100644 index 00000000..cc8cdb2b --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/B4-tool-results.json @@ -0,0 +1,190 @@ +[ + { + "timestamp": "2026-09-05T15:42:49.760Z", + "call_id": "call_VHAgqRgLIip6clGj9RDEnbon", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"4e6717\",\"wall_time_seconds\":0.000003292,\"exit_code\":0,\"original_token_count\":1230,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/B4 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B4`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B4` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B4/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/B4/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B4/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/clicks.actions --out /tmp/weaver-exp-astra/runs/B4/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/B4/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: B (final capture)\\nWrite the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:43:07.317Z", + "call_id": "call_q2PIyUIDzpQRxX2PJwhFhE8H", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"0a8205\",\"wall_time_seconds\":0.00000375,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"44a3ed\",\"wall_time_seconds\":0.000003458,\"exit_code\":0,\"original_token_count\":380,\"output\":\"1:# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n115:## Hot swap\\n121:## Elements (JSX intrinsics)\\n138:## `class` utilities (M1 set)\\n198:### Gradient backgrounds\\n247:### Bundled fonts\\n269:### Icons\\n292:## CLI\\n305:## The conjure skill\\n312:## v0 done-condition (unchanged)\\n320:# M3 amendment (v0.3)\\n322:## `` \u2014 immediate mode (the ADR 0009 exception)\\n354:## Providers: `audio` and `media` (host-fed)\\n374:# M2 amendment (v0.2)\\n378:## Interactive elements (were \\\"arrives in M2\\\")\\n391:## `weaver.fetch` \u2014 the declared-origins network (ADR 0002)\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n419:## Providers: `cpu` and `memory` (host-fed)\\n437:## The host and its CLI verbs\\n459:# Styling breadth amendment (v0.4)\\n464:## PR 01: spacing and sizing\\n488:## PR 02: flex completeness\\n506:## PR 09: overlay stacks and bounded overflow\\n524:## PR 10: image fitting, rounded masks, and tiling\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n633:# Media v2 amendment (v0.5)\\n638:## PR 01: playback status and source application\\n679:## PR 02: album art and dynamic image sources\\n738:## PR 03: media transport capability\\n825:## PR 05: noro acceptance surface\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"43cbc9\",\"wall_time_seconds\":0.000002542,\"exit_code\":0,\"original_token_count\":2195,\"output\":\"import { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:43:16.208Z", + "call_id": "call_3vMILMZZQ686sAkJc6GZORed", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.6 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"9754fa\",\"wall_time_seconds\":0.000003541,\"exit_code\":0,\"original_token_count\":1030,\"output\":\"## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"35cd7f\",\"wall_time_seconds\":0.000002583,\"exit_code\":0,\"original_token_count\":2154,\"output\":\"## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## PR 01: spacing and sizing\\n\\nThe scale remains 1 unit = 4 logical px. Bracketed pixel values are accepted\\nwhere shown. Utilities are applied left-to-right; a later utility wins on the\\nsame side or axis. Negative margins are supported; padding and sizes are\\nnon-negative.\\n\\n| Utility | Maps to |\\n|---|---|\\n| `p-N`, `p-[Npx]` | uniform padding |\\n| `px/py/pt/pr/pb/pl-N`, bracketed `Npx` forms | directional padding; side values override uniform padding |\\n| `m/mx/my/mt/mr/mb/ml-N`, bracketed `Npx` forms, optional leading `-` | external per-side margin |\\n| `w-N`, `h-N`, bracketed `Npx` forms | fixed width or height |\\n| `w-full`, `h-full`, `w-A/B`, `h-A/B` | percentage of the parent's content box |\\n| `w-auto`, `h-auto` | clear an earlier size on that axis |\\n| `size-N`, `size-[Npx]`, `size-full` | set both axes together |\\n| `min-w/max-w/min-h/max-h-N`, bracketed `Npx` forms | per-axis size bounds |\\n| `aspect-square`, `aspect-video`, `aspect-[W/H]`, `aspect-[N]` | derive the missing axis when exactly one axis is definite |\\n| `aspect-auto` | clear an earlier aspect ratio |\\n\\nPercentage sizes are calculated from the parent's content box before margins;\\nmin/max bounds then clamp the laid-out frame. `aspect-*` does nothing when both\\naxes are definite or both are automatic.\\n\\n## PR 02: flex completeness\\n\\n| Utility | Maps to |\\n|---|---|\\n| `justify-around`, `justify-evenly` | Tailwind main-axis free-space distribution |\\n| `grow-N`, `grow-[N]` | numeric flex-grow factor (`grow` remains 1) |\\n| `shrink`, `shrink-0` | opt in/out of compression below the preferred size |\\n| `self-auto/start/center/end/stretch` | per-child cross-axis alignment |\\n| `flex-wrap`, `flex-nowrap` | enable/disable row or column line wrapping |\\n\\nWeaver elements default to `shrink: 1`, matching Tailwind. When preferred\\nsizes overflow a line, eligible children give up space in proportion to their\\navailable shrink capacity (preferred size minus min-size floor); `shrink-0`\\nchildren never compress. If all floors still exceed the container, overflow\\nremains explicit and the Native debug diagnostic fires. Wrapped lines use the\\ncontainer's `gap` on both axes. `items-baseline` remains an end-alignment\\napproximation; true font baseline layout is outside this styling slice.\\n\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n \\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:45.155Z", + "type": "custom_tool_call", + "call_id": "call_2zMfSKZrIeI2JoC53v7U3a9F", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/B4/widget.tsx'\\ns=open(p).read()\\nwidth='\\\\n'.join(' progress === '+str(i)+' ? \\\"w-'+str(i)+'/20 h-full bg-[#5eead4] rounded-full\\\" :' for i in range(1,20))+'\\\\n \\\"w-full h-full bg-[#5eead4] rounded-full\\\";'\\ns=s.replace(' const progress = Math.min(total, 20);',' const progress = Math.min(total, 20);\\\\n const progressClass =\\\\n'+width)\\ns=s.replace('class={`w-${progress}/20 h-full bg-[#5eead4] rounded-full`}', 'class={progressClass}')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4\",max_output_tokens:4000}));\ntext(await tools.exec_command({cmd:\"mkdir -p /tmp/weaver-exp-astra/runs/B4/captures\\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/B4/clicks.actions\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B4/captures/01-initial.png\",max_output_tokens:5000,yield_time_ms:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:44:55.553Z", + "type": "custom_tool_call", + "call_id": "call_2gs0oucYUoYTnCdmzIm5d6av", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/clicks.actions --out /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.png\",yield_time_ms:1000,max_output_tokens:5000}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B4/captures/01-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B4/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/01-initial.receipt.json\",max_output_tokens:7000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:03.922Z", + "type": "custom_tool_call", + "call_id": "call_cnbOBVAj3Nk8qFsXhdLAm5I9", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/02-after-clicks.receipt.json\",max_output_tokens:7300}));\n" + }, + { + "timestamp": "2026-09-05T15:45:20.431Z", + "type": "custom_tool_call", + "call_id": "call_VYTzx6YDkqqqji1lklmBjT1w", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\np='/tmp/weaver-exp-astra/runs/B4/'\\ndata=json.load(open(p+'clicks.actions'))\\ndata['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\njson.dump(data,open(p+'reset.actions','w'),indent=2)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/B4\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/reset.actions --out /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.png\",max_output_tokens:4000,yield_time_ms:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:29.781Z", + "type": "custom_tool_call", + "call_id": "call_crhMQGsEEnUF5qbL5035Ov8V", + "name": "exec", + "input": "text(await tools.write_stdin({session_id:22113,chars:\"\",yield_time_ms:1000,max_output_tokens:4000}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/B4/captures/03-after-reset.receipt.json\",max_output_tokens:7000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:57.826Z", + "type": "custom_tool_call", + "call_id": "call_aStKTLpYu2yCi3MwxwWGQAhn", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/B4/REPORT.md <<'EOF'\\n# Focus Week \u2014 B4\\n\\n- Condition: B (final capture). The complete widget was authored before the first capture.\\n- `weaver check` runs: 3 (first failed on an unbounded dynamic class; two subsequent runs passed).\\n- `weaver capture` runs: 3, all with status `ok`.\\n- Defects fixed because of pixels or snapshots: none.\\n- Spec items not met: none identified. Persistence uses `useStorage` with a record keyed by weekday; restarting a live widget was not exercised because live execution was prohibited. Reset is manual, as specified.\\n- Confidence: 9/10.\\n\\nOpened and inspected every PNG at its native 320\u00d7200 dimensions and read every snapshot and receipt:\\n\\n- `captures/01-initial.png`: Friday highlighted, seven zero counts, `0 / 20`, empty bar, equal day cells and aligned header. Text, spacing, contrast, and button bounds are clean.\\n- `captures/02-after-clicks.png`: Friday 3, every other day 0, `3 / 20`; semantic fill width 31.800001 against track width 212 confirms 15%. Primary native hover color is visible.\\n- `captures/03-after-reset.png`: three logs followed by Reset week returns every count and the total to zero and empties the bar. Secondary native hover color is visible.\\n\\nAccessible button names are exactly `Log session` and `Reset week`. Both declare native hover and pressed styles. The widget subscribes only to time and makes no network calls. All receipts report no pending fetches, images, providers, or frame requests; the time subscription accounts for the pending timer. Their sole warning records pre-existing uncommitted checkout changes; no repository files were modified. `weaver dev` was not run.\\n\\nThe static-check fix replaced an arbitrary interpolated progress class with an explicit set of validated width classes for the 20-session goal. It happened before the first capture and was not a pixel-driven repair.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:42:49.761Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:07.318Z", + "info": { + "total_token_usage": { + "input_tokens": 39802, + "cached_input_tokens": 37888, + "cache_write_input_tokens": 0, + "output_tokens": 222, + "reasoning_output_tokens": 23, + "total_tokens": 40024 + }, + "last_token_usage": { + "input_tokens": 20599, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 183, + "reasoning_output_tokens": 23, + "total_tokens": 20782 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:16.208Z", + "info": { + "total_token_usage": { + "input_tokens": 65942, + "cached_input_tokens": 58368, + "cache_write_input_tokens": 0, + "output_tokens": 381, + "reasoning_output_tokens": 23, + "total_tokens": 66323 + }, + "last_token_usage": { + "input_tokens": 26140, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 159, + "reasoning_output_tokens": 0, + "total_tokens": 26299 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:23.541Z", + "info": { + "total_token_usage": { + "input_tokens": 97365, + "cached_input_tokens": 89600, + "cache_write_input_tokens": 0, + "output_tokens": 1803, + "reasoning_output_tokens": 276, + "total_tokens": 99168 + }, + "last_token_usage": { + "input_tokens": 31423, + "cached_input_tokens": 31232, + "cache_write_input_tokens": 0, + "output_tokens": 1422, + "reasoning_output_tokens": 253, + "total_tokens": 32845 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:46.695Z", + "info": { + "total_token_usage": { + "input_tokens": 130560, + "cached_input_tokens": 121856, + "cache_write_input_tokens": 0, + "output_tokens": 2269, + "reasoning_output_tokens": 355, + "total_tokens": 132829 + }, + "last_token_usage": { + "input_tokens": 33195, + "cached_input_tokens": 32256, + "cache_write_input_tokens": 0, + "output_tokens": 466, + "reasoning_output_tokens": 79, + "total_tokens": 33661 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:56.363Z", + "info": { + "total_token_usage": { + "input_tokens": 164711, + "cached_input_tokens": 154880, + "cache_write_input_tokens": 0, + "output_tokens": 2469, + "reasoning_output_tokens": 355, + "total_tokens": 167180 + }, + "last_token_usage": { + "input_tokens": 34151, + "cached_input_tokens": 33024, + "cache_write_input_tokens": 0, + "output_tokens": 200, + "reasoning_output_tokens": 0, + "total_tokens": 34351 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:03.997Z", + "info": { + "total_token_usage": { + "input_tokens": 203414, + "cached_input_tokens": 188800, + "cache_write_input_tokens": 0, + "output_tokens": 2573, + "reasoning_output_tokens": 355, + "total_tokens": 205987 + }, + "last_token_usage": { + "input_tokens": 38703, + "cached_input_tokens": 33920, + "cache_write_input_tokens": 0, + "output_tokens": 104, + "reasoning_output_tokens": 0, + "total_tokens": 38807 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:21.611Z", + "info": { + "total_token_usage": { + "input_tokens": 246199, + "cached_input_tokens": 227456, + "cache_write_input_tokens": 0, + "output_tokens": 2906, + "reasoning_output_tokens": 419, + "total_tokens": 249105 + }, + "last_token_usage": { + "input_tokens": 42785, + "cached_input_tokens": 38656, + "cache_write_input_tokens": 0, + "output_tokens": 333, + "reasoning_output_tokens": 64, + "total_tokens": 43118 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:29.851Z", + "info": { + "total_token_usage": { + "input_tokens": 289392, + "cached_input_tokens": 270208, + "cache_write_input_tokens": 0, + "output_tokens": 3036, + "reasoning_output_tokens": 419, + "total_tokens": 292428 + }, + "last_token_usage": { + "input_tokens": 43193, + "cached_input_tokens": 42752, + "cache_write_input_tokens": 0, + "output_tokens": 130, + "reasoning_output_tokens": 0, + "total_tokens": 43323 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:57.891Z", + "info": { + "total_token_usage": { + "input_tokens": 337139, + "cached_input_tokens": 313344, + "cache_write_input_tokens": 0, + "output_tokens": 3508, + "reasoning_output_tokens": 419, + "total_tokens": 340647 + }, + "last_token_usage": { + "input_tokens": 47747, + "cached_input_tokens": 43136, + "cache_write_input_tokens": 0, + "output_tokens": 472, + "reasoning_output_tokens": 0, + "total_tokens": 48219 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:05.405Z", + "info": { + "total_token_usage": { + "input_tokens": 385415, + "cached_input_tokens": 360960, + "cache_write_input_tokens": 0, + "output_tokens": 3563, + "reasoning_output_tokens": 419, + "total_tokens": 388978 + }, + "last_token_usage": { + "input_tokens": 48276, + "cached_input_tokens": 47616, + "cache_write_input_tokens": 0, + "output_tokens": 55, + "reasoning_output_tokens": 0, + "total_tokens": 48331 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/C1-commands.json b/experiments/render-loop-cadence/astra/evidence/C1-commands.json new file mode 100644 index 00000000..b07d7f92 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C1-commands.json @@ -0,0 +1,200 @@ +[ + { + "timestamp": "2026-09-05T15:30:26.179Z", + "call_id": "call_NgjNmwgNrvWQKpsdL6jsqYsx", + "command": "cat /tmp/weaver-exp-astra/prompts/C1.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:36.478Z", + "call_id": "call_9ReNz36mkTkd0amgbXtReN67", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:36.478Z", + "call_id": "call_9ReNz36mkTkd0amgbXtReN67", + "command": "rg -n 'Module shape|widget\\(config|Hooks|Consolidated v0.4|useStorage|PR 11:' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:36.478Z", + "call_id": "call_9ReNz36mkTkd0amgbXtReN67", + "command": "cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:44.462Z", + "call_id": "call_D7umGUu2fh81XdLSdvyq7W8f", + "command": "sed -n '1,115p' sdk/CONTRACT.md\nsed -n '410,445p' sdk/CONTRACT.md\nsed -n '538,750p' sdk/CONTRACT.md\ncat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:44.462Z", + "call_id": "call_D7umGUu2fh81XdLSdvyq7W8f", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:30:51.004Z", + "call_id": "call_mYCEOjDRlEsTDHXl19hzSLf8", + "command": "cat /tmp/weaver-exp-astra/runs/C1/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:19.250Z", + "call_id": "call_Mt9XtcmH0Vrtx9BRK9tY2uBB", + "command": "cat > /tmp/weaver-exp-astra/runs/C1/widget.tsx <<'EOF'\nimport { useProvider, widget } from \"@weaver/sdk\";\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n \n );\n});\nEOF\nmkdir -p /tmp/weaver-exp-astra/runs/C1/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/C1/clicks.actions\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:19.250Z", + "call_id": "call_Mt9XtcmH0Vrtx9BRK9tY2uBB", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:27.391Z", + "call_id": "call_ghtaYmPeAO61sn1Vy5BR4HbJ", + "command": "cat /tmp/weaver-exp-astra/runs/C1/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/01-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:52.750Z", + "call_id": "call_gIzIZPbyryrqZ8ybtcdMjuTN", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C1/widget.tsx'\ns=open(p).read().replace('export default widget', 'const days = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\\nconst letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\n\\nexport default widget')\ns=s.replace(' \\n ', ''' \n \n {days.map((day, index) => (\n \n {letters[index]}\n 0\n \n ))}\n \n ''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:31:52.750Z", + "call_id": "call_gIzIZPbyryrqZ8ybtcdMjuTN", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/02-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:01.678Z", + "call_id": "call_7cqYBfBcH0J0eBVVawwfsRQS", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C1/widget.tsx'\ns=open(p).read().replace('\\n );', ''' \n \n 0 ? `w-${Math.min(total, 20)}/20 h-full rounded-full bg-[#5eead4]` : \"w-0 h-full\"} />\n \n {total} / 20\n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:32:56.965Z", + "call_id": "call_Z238XfaizpNG3pDmgvwY3md3", + "command": "rg -n 'CanvasCtx|fillRect|canvas.*M3|##.*canvas' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:33:10.371Z", + "call_id": "call_i9K5T7iPDDHKmC3OLacJ2Lom", + "command": "sed -n '322,353p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:33:10.371Z", + "call_id": "call_i9K5T7iPDDHKmC3OLacJ2Lom", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C1/widget.tsx'\ns=open(p).read().replace(''' \n 0 ? `w-${Math.min(total, 20)}/20 h-full rounded-full bg-[#5eead4]` : \"w-0 h-full\"} />\n ''', ''' {\n ctx.clear();\n ctx.fillRect(0, 0, ctx.width, ctx.height, \"#ffffff1a\");\n ctx.fillRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, \"#5eead4\");\n }} />''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:33:22.664Z", + "call_id": "call_QR4YGAIk3VbYMwmzFUsBPd3D", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/04-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:33:32.153Z", + "call_id": "call_jo9Dak3Eri6KAffBW1tkGz59", + "command": "cat /tmp/weaver-exp-astra/runs/C1/captures/04-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/04-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:33:50.003Z", + "call_id": "call_3ousYMIvWgGEbctGdyM6aPdf", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C1/widget.tsx'\ns=open(p).read().replace(' = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 };\\nconst letters =')\ns=s.replace(' const total = 0;', ' const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\\n const total = days.reduce((sum, day) => sum + counts[day], 0);')\ns=s.replace('text-[#f5f6f8]\">0', 'text-[#f5f6f8]\">{counts[day]}')\ns=s.replace(' \\n );', ''' \n \n \n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:34:38.641Z", + "call_id": "call_KyZPvyuVCIySUofcME6t8P97", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/06-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:34:46.102Z", + "call_id": "call_ZmizR0nJMgH49ca1DkgA9umo", + "command": "cat /tmp/weaver-exp-astra/runs/C1/captures/06-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/06-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:34:53.138Z", + "call_id": "call_V4UhGYU9GnnQtBxz4FslBO1s", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/clicks.actions --out /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:35:00.784Z", + "call_id": "call_BKcKSXYx21Mtr9di21VUS7pj", + "command": "cat /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:35:16.319Z", + "call_id": "call_T0ZwvlOwPKSFkechGMGysvF0", + "command": "python3 - <<'PY'\nimport json\np='/tmp/weaver-exp-astra/runs/C1/'\na=json.load(open(p+'clicks.actions'))\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\nopen(p+'reset.actions','w').write(json.dumps(a, indent=2)+'\\n')\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1", + "literal": true + }, + { + "timestamp": "2026-09-05T15:35:25.472Z", + "call_id": "call_ziu1AFqtLzpzxs4p1TqU8V7E", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/reset.actions --out /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:35:33.580Z", + "call_id": "call_oezqCikYotqpQOb2VvpsiC1X", + "command": "cat /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:36:07.525Z", + "call_id": "call_0TvNXGhbqnk60X1C3wkumD5O", + "command": "cat > /tmp/weaver-exp-astra/runs/C1/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: C (progressive capture).\n- `weaver check` runs: 8 (6 passed, 2 failed while authoring). Final source passed.\n- `weaver capture` runs: 8 (7 succeeded, 1 failed at static validation). Capture 02 produced no artifacts because an unsupported `key` prop remained; numbering was preserved.\n- Confidence: 9 / 10.\n\n## Defects fixed because of pixels or snapshots\n\n- Capture 04 showed no progress track despite a 224×6 semantic canvas bound. The canvas had `w-0 grow`, so its drawing width was zero. Changed it to explicit `w-[224px]`, consistent with the shipped canvas examples. Capture 05 visibly confirmed the track; capture 07 confirmed the filled portion at 15%.\n\n## Verification\n\nBuilt and inspected each slice before starting the next: frame/header (01), day cells (03), progress (04 then 05), buttons/storage (06 initial, 07 after three clicks). Also captured reset after three clicks (08).\n\nOpened every successful PNG at its actual 320×200 size, read its semantic snapshot and receipt, and confirmed `status: \"ok\"`. Captures show equal-width Monday–Sunday cells, Friday highlighted, visible zero counts, separated bar and total, readable button labels, and no clipping or overlap. Capture 07 shows Friday 3, six zeros, `3 / 20`, and a 15% fill. Capture 08 shows seven zeros and `0 / 20`. Exact accessible names are `Log session` and `Reset week`.\n\nStorage uses `useStorage` with a record keyed by weekday. Persistence across restarts follows that SDK contract; captures intentionally use isolated empty storage and do not independently prove a live restart. Native hover and pressed classes are defined on both buttons; the post-action snapshots and pixels show each button's hover state.\n\nThe one pending timer is the subscribed time provider. There are no fetches, other providers, unresolved images, or queued frame requests. The only successful-receipt warning is that the existing Weaver checkout has uncommitted changes. No repository file was edited and `weaver dev` was not run, as instructed.\n\n## Unmet spec items\n\nNone identified. The week is reset through the specified Reset week button; no automatic rollover was requested.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/C1-tool-results.json b/experiments/render-loop-cadence/astra/evidence/C1-tool-results.json new file mode 100644 index 00000000..00065fb5 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C1-tool-results.json @@ -0,0 +1,432 @@ +[ + { + "timestamp": "2026-09-05T15:30:26.247Z", + "call_id": "call_NgjNmwgNrvWQKpsdL6jsqYsx", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"771cb3\",\"wall_time_seconds\":0.000003459,\"exit_code\":0,\"original_token_count\":1288,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/C1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C1`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C1` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C1/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/C1/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/clicks.actions --out /tmp/weaver-exp-astra/runs/C1/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/C1/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: C (progressive capture)\\nBuild in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next:\\n1. Frame and header row only (capture initial state).\\n2. Add the seven day cells (capture initial state).\\n3. Add the progress bar (capture initial state).\\n4. Add the buttons and storage (capture initial state AND after-clicks state).\\nFix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:36.626Z", + "call_id": "call_9ReNz36mkTkd0amgbXtReN67", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"428c55\",\"wall_time_seconds\":0.000002708,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"24473a\",\"wall_time_seconds\":0.000003166,\"exit_code\":0,\"original_token_count\":106,\"output\":\"20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"deca67\",\"wall_time_seconds\":0.000002584,\"exit_code\":0,\"original_token_count\":2195,\"output\":\"import { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:30:44.950Z", + "call_id": "call_D7umGUu2fh81XdLSdvyq7W8f", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"3fff41\",\"wall_time_seconds\":0.000005833,\"exit_code\":0,\"original_token_count\":5877,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n\\n```ts\\nuseProvider(\\\"cpu\\\") // { percent: number, perCore: number[] } 1 Hz\\nuseProvider(\\\"memory\\\") // { usedMb: number, totalMb: number, percent: number } 1 Hz\\n```\\n\\nDelivered by `weaverd` (the host). `time` remains SDK-local. Subscribing\\nwithout the host running is a runtime error that names the fix (`weaver up`);\\n`weaver dev` auto-starts the host.\\n\\n`cpu.percent` is whole-machine utilization from 0\u2013100, not the sum of cores;\\n`perCore` reports the same 0\u2013100 utilization for each logical core. Memory\\n`usedMb` is physical memory that is not currently free or reclaimable idle\\ncache, `totalMb` is installed physical memory, and `percent` is their ratio.\\nThese meanings stay platform-neutral even though each host uses its public OS\\ncounters to project them.\\n\\n## The host and its CLI verbs\\n\\n```\\nweaver up | down start/stop weaverd (singleton, tray-less in M2)\\nweaver pack write portable source to .weave\\nweaver install validate, own, build, register, and run source\\nweaver uninstall stop + unregister\\nweaver status table: name \u00b7 pid \u00b7 private-MB \u00b7 cpu% \u00b7 uptime (ADR 0005 billing)\\n```\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n \\n \\n \\n );''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1\",\"max_output_tokens\":2000}));\n" + }, + { + "timestamp": "2026-09-05T15:34:38.641Z", + "type": "custom_tool_call", + "call_id": "call_KyZPvyuVCIySUofcME6t8P97", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/06-initial.png\",\"max_output_tokens\":1500}));\n" + }, + { + "timestamp": "2026-09-05T15:34:46.102Z", + "type": "custom_tool_call", + "call_id": "call_ZmizR0nJMgH49ca1DkgA9umo", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C1/captures/06-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C1/captures/06-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/06-initial.receipt.json\",\"max_output_tokens\":6500}));\n" + }, + { + "timestamp": "2026-09-05T15:34:53.138Z", + "type": "custom_tool_call", + "call_id": "call_V4UhGYU9GnnQtBxz4FslBO1s", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/clicks.actions --out /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.png\",\"max_output_tokens\":1500}));\n" + }, + { + "timestamp": "2026-09-05T15:35:00.784Z", + "type": "custom_tool_call", + "call_id": "call_BKcKSXYx21Mtr9di21VUS7pj", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/07-after-clicks.receipt.json\",\"max_output_tokens\":6500}));\n" + }, + { + "timestamp": "2026-09-05T15:35:16.319Z", + "type": "custom_tool_call", + "call_id": "call_T0ZwvlOwPKSFkechGMGysvF0", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\np='/tmp/weaver-exp-astra/runs/C1/'\\na=json.load(open(p+'clicks.actions'))\\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\nopen(p+'reset.actions','w').write(json.dumps(a, indent=2)+'\\\\n')\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C1\",\"max_output_tokens\":1000}));\n" + }, + { + "timestamp": "2026-09-05T15:35:25.472Z", + "type": "custom_tool_call", + "call_id": "call_ziu1AFqtLzpzxs4p1TqU8V7E", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/reset.actions --out /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.png\",\"max_output_tokens\":1500}));\n" + }, + { + "timestamp": "2026-09-05T15:35:33.580Z", + "type": "custom_tool_call", + "call_id": "call_oezqCikYotqpQOb2VvpsiC1X", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C1/captures/08-after-reset.receipt.json\",\"max_output_tokens\":6500}));\n" + }, + { + "timestamp": "2026-09-05T15:36:07.525Z", + "type": "custom_tool_call", + "call_id": "call_0TvNXGhbqnk60X1C3wkumD5O", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/C1/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: C (progressive capture).\\n- `weaver check` runs: 8 (6 passed, 2 failed while authoring). Final source passed.\\n- `weaver capture` runs: 8 (7 succeeded, 1 failed at static validation). Capture 02 produced no artifacts because an unsupported `key` prop remained; numbering was preserved.\\n- Confidence: 9 / 10.\\n\\n## Defects fixed because of pixels or snapshots\\n\\n- Capture 04 showed no progress track despite a 224\u00d76 semantic canvas bound. The canvas had `w-0 grow`, so its drawing width was zero. Changed it to explicit `w-[224px]`, consistent with the shipped canvas examples. Capture 05 visibly confirmed the track; capture 07 confirmed the filled portion at 15%.\\n\\n## Verification\\n\\nBuilt and inspected each slice before starting the next: frame/header (01), day cells (03), progress (04 then 05), buttons/storage (06 initial, 07 after three clicks). Also captured reset after three clicks (08).\\n\\nOpened every successful PNG at its actual 320\u00d7200 size, read its semantic snapshot and receipt, and confirmed `status: \\\"ok\\\"`. Captures show equal-width Monday\u2013Sunday cells, Friday highlighted, visible zero counts, separated bar and total, readable button labels, and no clipping or overlap. Capture 07 shows Friday 3, six zeros, `3 / 20`, and a 15% fill. Capture 08 shows seven zeros and `0 / 20`. Exact accessible names are `Log session` and `Reset week`.\\n\\nStorage uses `useStorage` with a record keyed by weekday. Persistence across restarts follows that SDK contract; captures intentionally use isolated empty storage and do not independently prove a live restart. Native hover and pressed classes are defined on both buttons; the post-action snapshots and pixels show each button's hover state.\\n\\nThe one pending timer is the subscribed time provider. There are no fetches, other providers, unresolved images, or queued frame requests. The only successful-receipt warning is that the existing Weaver checkout has uncommitted changes. No repository file was edited and `weaver dev` was not run, as instructed.\\n\\n## Unmet spec items\\n\\nNone identified. The week is reset through the specified Reset week button; no automatic rollover was requested.\\nEOF\",\"max_output_tokens\":1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:30:26.248Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:36.627Z", + "info": { + "total_token_usage": { + "input_tokens": 39862, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 211, + "reasoning_output_tokens": 19, + "total_tokens": 40073 + }, + "last_token_usage": { + "input_tokens": 20659, + "cached_input_tokens": 19072, + "cache_write_input_tokens": 0, + "output_tokens": 172, + "reasoning_output_tokens": 19, + "total_tokens": 20831 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:44.951Z", + "info": { + "total_token_usage": { + "input_tokens": 65697, + "cached_input_tokens": 58496, + "cache_write_input_tokens": 0, + "output_tokens": 325, + "reasoning_output_tokens": 19, + "total_tokens": 66022 + }, + "last_token_usage": { + "input_tokens": 25835, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 114, + "reasoning_output_tokens": 0, + "total_tokens": 25949 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:30:51.077Z", + "info": { + "total_token_usage": { + "input_tokens": 97897, + "cached_input_tokens": 84096, + "cache_write_input_tokens": 0, + "output_tokens": 366, + "reasoning_output_tokens": 19, + "total_tokens": 98263 + }, + "last_token_usage": { + "input_tokens": 32200, + "cached_input_tokens": 25600, + "cache_write_input_tokens": 0, + "output_tokens": 41, + "reasoning_output_tokens": 0, + "total_tokens": 32241 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:20.803Z", + "info": { + "total_token_usage": { + "input_tokens": 130406, + "cached_input_tokens": 116096, + "cache_write_input_tokens": 0, + "output_tokens": 916, + "reasoning_output_tokens": 145, + "total_tokens": 131322 + }, + "last_token_usage": { + "input_tokens": 32509, + "cached_input_tokens": 32000, + "cache_write_input_tokens": 0, + "output_tokens": 550, + "reasoning_output_tokens": 126, + "total_tokens": 33059 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:27.478Z", + "info": { + "total_token_usage": { + "input_tokens": 163962, + "cached_input_tokens": 148480, + "cache_write_input_tokens": 0, + "output_tokens": 1017, + "reasoning_output_tokens": 145, + "total_tokens": 164979 + }, + "last_token_usage": { + "input_tokens": 33556, + "cached_input_tokens": 32384, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 33657 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:31:54.165Z", + "info": { + "total_token_usage": { + "input_tokens": 199418, + "cached_input_tokens": 181888, + "cache_write_input_tokens": 0, + "output_tokens": 1539, + "reasoning_output_tokens": 160, + "total_tokens": 200957 + }, + "last_token_usage": { + "input_tokens": 35456, + "cached_input_tokens": 33408, + "cache_write_input_tokens": 0, + "output_tokens": 522, + "reasoning_output_tokens": 15, + "total_tokens": 35978 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:02.398Z", + "info": { + "total_token_usage": { + "input_tokens": 236035, + "cached_input_tokens": 217216, + "cache_write_input_tokens": 0, + "output_tokens": 1660, + "reasoning_output_tokens": 178, + "total_tokens": 237695 + }, + "last_token_usage": { + "input_tokens": 36617, + "cached_input_tokens": 35328, + "cache_write_input_tokens": 0, + "output_tokens": 121, + "reasoning_output_tokens": 18, + "total_tokens": 36738 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:10.182Z", + "info": { + "total_token_usage": { + "input_tokens": 272847, + "cached_input_tokens": 253824, + "cache_write_input_tokens": 0, + "output_tokens": 1744, + "reasoning_output_tokens": 178, + "total_tokens": 274591 + }, + "last_token_usage": { + "input_tokens": 36812, + "cached_input_tokens": 36608, + "cache_write_input_tokens": 0, + "output_tokens": 84, + "reasoning_output_tokens": 0, + "total_tokens": 36896 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:19.635Z", + "info": { + "total_token_usage": { + "input_tokens": 310183, + "cached_input_tokens": 290560, + "cache_write_input_tokens": 0, + "output_tokens": 1845, + "reasoning_output_tokens": 178, + "total_tokens": 312028 + }, + "last_token_usage": { + "input_tokens": 37336, + "cached_input_tokens": 36736, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 37437 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:45.855Z", + "info": { + "total_token_usage": { + "input_tokens": 350910, + "cached_input_tokens": 327808, + "cache_write_input_tokens": 0, + "output_tokens": 2277, + "reasoning_output_tokens": 316, + "total_tokens": 353187 + }, + "last_token_usage": { + "input_tokens": 40727, + "cached_input_tokens": 37248, + "cache_write_input_tokens": 0, + "output_tokens": 432, + "reasoning_output_tokens": 138, + "total_tokens": 41159 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:32:57.038Z", + "info": { + "total_token_usage": { + "input_tokens": 392172, + "cached_input_tokens": 368512, + "cache_write_input_tokens": 0, + "output_tokens": 2353, + "reasoning_output_tokens": 340, + "total_tokens": 394525 + }, + "last_token_usage": { + "input_tokens": 41262, + "cached_input_tokens": 40704, + "cache_write_input_tokens": 0, + "output_tokens": 76, + "reasoning_output_tokens": 24, + "total_tokens": 41338 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:11.226Z", + "info": { + "total_token_usage": { + "input_tokens": 433645, + "cached_input_tokens": 409728, + "cache_write_input_tokens": 0, + "output_tokens": 2646, + "reasoning_output_tokens": 340, + "total_tokens": 436291 + }, + "last_token_usage": { + "input_tokens": 41473, + "cached_input_tokens": 41216, + "cache_write_input_tokens": 0, + "output_tokens": 293, + "reasoning_output_tokens": 0, + "total_tokens": 41766 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:23.585Z", + "info": { + "total_token_usage": { + "input_tokens": 475985, + "cached_input_tokens": 451072, + "cache_write_input_tokens": 0, + "output_tokens": 2794, + "reasoning_output_tokens": 364, + "total_tokens": 478779 + }, + "last_token_usage": { + "input_tokens": 42340, + "cached_input_tokens": 41344, + "cache_write_input_tokens": 0, + "output_tokens": 148, + "reasoning_output_tokens": 24, + "total_tokens": 42488 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:32.228Z", + "info": { + "total_token_usage": { + "input_tokens": 518913, + "cached_input_tokens": 493312, + "cache_write_input_tokens": 0, + "output_tokens": 2895, + "reasoning_output_tokens": 364, + "total_tokens": 521808 + }, + "last_token_usage": { + "input_tokens": 42928, + "cached_input_tokens": 42240, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 43029 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:50.848Z", + "info": { + "total_token_usage": { + "input_tokens": 565346, + "cached_input_tokens": 536192, + "cache_write_input_tokens": 0, + "output_tokens": 3130, + "reasoning_output_tokens": 445, + "total_tokens": 568476 + }, + "last_token_usage": { + "input_tokens": 46433, + "cached_input_tokens": 42880, + "cache_write_input_tokens": 0, + "output_tokens": 235, + "reasoning_output_tokens": 81, + "total_tokens": 46668 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:33:58.141Z", + "info": { + "total_token_usage": { + "input_tokens": 612086, + "cached_input_tokens": 582528, + "cache_write_input_tokens": 0, + "output_tokens": 3214, + "reasoning_output_tokens": 445, + "total_tokens": 615300 + }, + "last_token_usage": { + "input_tokens": 46740, + "cached_input_tokens": 46336, + "cache_write_input_tokens": 0, + "output_tokens": 84, + "reasoning_output_tokens": 0, + "total_tokens": 46824 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:34:04.700Z", + "info": { + "total_token_usage": { + "input_tokens": 659355, + "cached_input_tokens": 629248, + "cache_write_input_tokens": 0, + "output_tokens": 3315, + "reasoning_output_tokens": 445, + "total_tokens": 662670 + }, + "last_token_usage": { + "input_tokens": 47269, + "cached_input_tokens": 46720, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 47370 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:34:31.574Z", + "info": { + "total_token_usage": { + "input_tokens": 710210, + "cached_input_tokens": 676480, + "cache_write_input_tokens": 0, + "output_tokens": 3903, + "reasoning_output_tokens": 476, + "total_tokens": 714113 + }, + "last_token_usage": { + "input_tokens": 50855, + "cached_input_tokens": 47232, + "cache_write_input_tokens": 0, + "output_tokens": 588, + "reasoning_output_tokens": 31, + "total_tokens": 51443 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:34:39.588Z", + "info": { + "total_token_usage": { + "input_tokens": 761727, + "cached_input_tokens": 727296, + "cache_write_input_tokens": 0, + "output_tokens": 3987, + "reasoning_output_tokens": 476, + "total_tokens": 765714 + }, + "last_token_usage": { + "input_tokens": 51517, + "cached_input_tokens": 50816, + "cache_write_input_tokens": 0, + "output_tokens": 84, + "reasoning_output_tokens": 0, + "total_tokens": 51601 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:34:46.179Z", + "info": { + "total_token_usage": { + "input_tokens": 813772, + "cached_input_tokens": 778752, + "cache_write_input_tokens": 0, + "output_tokens": 4088, + "reasoning_output_tokens": 476, + "total_tokens": 817860 + }, + "last_token_usage": { + "input_tokens": 52045, + "cached_input_tokens": 51456, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 52146 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:34:54.096Z", + "info": { + "total_token_usage": { + "input_tokens": 869691, + "cached_input_tokens": 830720, + "cache_write_input_tokens": 0, + "output_tokens": 4191, + "reasoning_output_tokens": 476, + "total_tokens": 873882 + }, + "last_token_usage": { + "input_tokens": 55919, + "cached_input_tokens": 51968, + "cache_write_input_tokens": 0, + "output_tokens": 103, + "reasoning_output_tokens": 0, + "total_tokens": 56022 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:35:00.860Z", + "info": { + "total_token_usage": { + "input_tokens": 926223, + "cached_input_tokens": 886528, + "cache_write_input_tokens": 0, + "output_tokens": 4295, + "reasoning_output_tokens": 476, + "total_tokens": 930518 + }, + "last_token_usage": { + "input_tokens": 56532, + "cached_input_tokens": 55808, + "cache_write_input_tokens": 0, + "output_tokens": 104, + "reasoning_output_tokens": 0, + "total_tokens": 56636 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:35:17.146Z", + "info": { + "total_token_usage": { + "input_tokens": 986738, + "cached_input_tokens": 942976, + "cache_write_input_tokens": 0, + "output_tokens": 4556, + "reasoning_output_tokens": 553, + "total_tokens": 991294 + }, + "last_token_usage": { + "input_tokens": 60515, + "cached_input_tokens": 56448, + "cache_write_input_tokens": 0, + "output_tokens": 261, + "reasoning_output_tokens": 77, + "total_tokens": 60776 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:35:26.258Z", + "info": { + "total_token_usage": { + "input_tokens": 1047588, + "cached_input_tokens": 1003392, + "cache_write_input_tokens": 0, + "output_tokens": 4656, + "reasoning_output_tokens": 553, + "total_tokens": 1052244 + }, + "last_token_usage": { + "input_tokens": 60850, + "cached_input_tokens": 60416, + "cache_write_input_tokens": 0, + "output_tokens": 100, + "reasoning_output_tokens": 0, + "total_tokens": 60950 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:35:33.672Z", + "info": { + "total_token_usage": { + "input_tokens": 1109048, + "cached_input_tokens": 1064192, + "cache_write_input_tokens": 0, + "output_tokens": 4757, + "reasoning_output_tokens": 553, + "total_tokens": 1113805 + }, + "last_token_usage": { + "input_tokens": 61460, + "cached_input_tokens": 60800, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 61561 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:36:07.611Z", + "info": { + "total_token_usage": { + "input_tokens": 1174550, + "cached_input_tokens": 1125504, + "cache_write_input_tokens": 0, + "output_tokens": 5366, + "reasoning_output_tokens": 608, + "total_tokens": 1179916 + }, + "last_token_usage": { + "input_tokens": 65502, + "cached_input_tokens": 61312, + "cache_write_input_tokens": 0, + "output_tokens": 609, + "reasoning_output_tokens": 55, + "total_tokens": 66111 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:36:16.422Z", + "info": { + "total_token_usage": { + "input_tokens": 1240717, + "cached_input_tokens": 1190912, + "cache_write_input_tokens": 0, + "output_tokens": 5418, + "reasoning_output_tokens": 608, + "total_tokens": 1246135 + }, + "last_token_usage": { + "input_tokens": 66167, + "cached_input_tokens": 65408, + "cache_write_input_tokens": 0, + "output_tokens": 52, + "reasoning_output_tokens": 0, + "total_tokens": 66219 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/C2-commands.json b/experiments/render-loop-cadence/astra/evidence/C2-commands.json new file mode 100644 index 00000000..99358ee1 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C2-commands.json @@ -0,0 +1,182 @@ +[ + { + "timestamp": "2026-09-05T15:37:15.355Z", + "call_id": "call_XTj3CCi6WvUgKJEysuGnIpyb", + "command": "cat /tmp/weaver-exp-astra/prompts/C2.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:25.905Z", + "call_id": "call_dE76p8rSMZsxQn9UOSok6mzM", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:25.905Z", + "call_id": "call_dE76p8rSMZsxQn9UOSok6mzM", + "command": "rg -n '^#{1,5} |Module shape|widget\\(config|useStorage|native interaction' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:25.905Z", + "call_id": "call_dE76p8rSMZsxQn9UOSok6mzM", + "command": "cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:35.638Z", + "call_id": "call_gXkBjJFCp6oHAZCOelLLgzfU", + "command": "sed -n '20,115p' sdk/CONTRACT.md\nsed -n '410,419p' sdk/CONTRACT.md\nsed -n '538,633p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:35.638Z", + "call_id": "call_gXkBjJFCp6oHAZCOelLLgzfU", + "command": "cat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:37:35.638Z", + "call_id": "call_gXkBjJFCp6oHAZCOelLLgzfU", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:06.131Z", + "call_id": "call_YSOMd3cHv21NTnGhp2ANYrXE", + "command": "cat /tmp/weaver-exp-astra/runs/C2/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:06.131Z", + "call_id": "call_YSOMd3cHv21NTnGhp2ANYrXE", + "command": "cat > /tmp/weaver-exp-astra/runs/C2/widget.tsx <<'EOF'\nimport { useProvider, widget } from \"@weaver/sdk\";\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n \n );\n});\nEOF\nmkdir -p /tmp/weaver-exp-astra/runs/C2/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/C2/clicks.actions\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:06.131Z", + "call_id": "call_YSOMd3cHv21NTnGhp2ANYrXE", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:15.979Z", + "call_id": "call_ONSBZDLiQ4oGFPsPQoIzTYe8", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/01-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:45.046Z", + "call_id": "call_lm2NuNgeO9WNMW1NJ1Jut01E", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C2/widget.tsx'\ns=open(p).read().replace('export default widget', 'const days = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\\nconst letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\n\\nexport default widget')\ns=s.replace(' \\n ', ''' \n \n {days.map((day, index) => (\n \n {letters[index]}\n 0\n \n ))}\n \n ''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:45.046Z", + "call_id": "call_lm2NuNgeO9WNMW1NJ1Jut01E", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/02-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:38:45.046Z", + "call_id": "call_lm2NuNgeO9WNMW1NJ1Jut01E", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/02-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/02-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:22.909Z", + "call_id": "call_BsfvfTd9cSNn1LuLI6XE4Jmf", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C2/widget.tsx'\ns=open(p).read().replace(' const time = useProvider(\"time\");', ' const time = useProvider(\"time\");\\n const total = 0;')\ns=s.replace(' \\n );', ''' \n \n \n \n {total} / 20\n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:22.909Z", + "call_id": "call_BsfvfTd9cSNn1LuLI6XE4Jmf", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/03-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:22.909Z", + "call_id": "call_BsfvfTd9cSNn1LuLI6XE4Jmf", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/03-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:30.321Z", + "call_id": "call_BgFUzXPB18j3IC2o4neADo28", + "command": "sed -n '322,354p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:45.717Z", + "call_id": "call_ArX6bRbePA1i2IkMt0AP7QGp", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C2/widget.tsx'\ns=open(p).read().replace(''' \n \n ''',''' {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff1a\");\n if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, \"#5eead4\");\n }} />''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:55.751Z", + "call_id": "call_Sp2GoOtk2kcTI9QPHkAazNgu", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/04-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:39:55.751Z", + "call_id": "call_Sp2GoOtk2kcTI9QPHkAazNgu", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/04-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/04-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:40:23.956Z", + "call_id": "call_UMd4ZxZFNsT1wEzm84WJeeJX", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C2/widget.tsx'\ns=open(p).read().replace('useProvider, widget','useProvider, useStorage, widget')\ns=s.replace('const letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];','const letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\nconst emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 };')\ns=s.replace(' const total = 0;', ' const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\\n const total = days.reduce((sum, day) => sum + counts[day], 0);')\ns=s.replace('text-[#f5f6f8]\">0', 'text-[#f5f6f8]\">{counts[day]}')\ns=s.replace(' \\n );',''' \n \n \n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:40:35.824Z", + "call_id": "call_OUlDwXjQ7bs2CCu8PRDV1qTa", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/05-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:40:35.824Z", + "call_id": "call_OUlDwXjQ7bs2CCu8PRDV1qTa", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/05-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/05-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:40:48.356Z", + "call_id": "call_Fgp1tn2ZH3jRGaLz2zT3yPjn", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/clicks.actions --out /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:40:48.356Z", + "call_id": "call_Fgp1tn2ZH3jRGaLz2zT3yPjn", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:41:08.683Z", + "call_id": "call_oGuofh5Cvcgn8y62KgO6vNTE", + "command": "python3 - <<'PY'\nimport json\np='/tmp/weaver-exp-astra/runs/C2/'\na=json.load(open(p+'clicks.actions'))\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\nopen(p+'reset.actions','w').write(json.dumps(a,indent=2)+'\\n')\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2", + "literal": true + }, + { + "timestamp": "2026-09-05T15:41:20.506Z", + "call_id": "call_5DgiT10oZGKbHLP620WCTsiO", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/reset.actions --out /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:41:20.506Z", + "call_id": "call_5DgiT10oZGKbHLP620WCTsiO", + "command": "cat /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:41:45.473Z", + "call_id": "call_r3BJKWzKecTzkFuXuVHlPpl9", + "command": "cat > /tmp/weaver-exp-astra/runs/C2/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: C (progressive capture).\n- `weaver check` runs: 6 (5 passed, 1 rejected a computed class string).\n- `weaver capture` runs: 7 (6 successful; attempt 03 failed static validation and published no PNG).\n- Defects fixed because of pixels or a snapshot: none.\n- Static diagnostic fix: replaced the computed bar-width class with a documented canvas drawing. No framework files changed.\n- Unmet spec items: none identified. Persistence uses `useStorage` with a record keyed Mon through Sun; capture isolation does not exercise an actual desktop restart.\n- Confidence: 9/10.\n\nThe four slices were inspected at 320×200: frame/header in 01, seven cells in 02, progress in 04, and complete initial/three-click states in 05 and 06. Each successful PNG was opened and its snapshot and receipt read. The failed 03 attempt was mistakenly invoked immediately after the failed check; the diagnostic was then fixed and check passed before capture 04 and before proceeding to the next slice.\n\nCapture 06 shows Friday at 3, every other day at 0, the label `3 / 20`, and a 15% bar. Capture 07 additionally proves Reset week restores every count to 0 and empties the bar. Semantic snapshots expose exactly named `Log session` and `Reset week` buttons. Native hover and pressed classes are present on both controls; post-click hover appearance was visible in the captures.\n\nAll successful receipts have status `ok`, no fetches, unresolved images, or queued frame requests. The single pending timer is associated with the subscribed time provider. The checkout provenance warning reports pre-existing uncommitted changes; this task did not modify repository files. `weaver dev` was not run, as instructed.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/C2-tool-results.json b/experiments/render-loop-cadence/astra/evidence/C2-tool-results.json new file mode 100644 index 00000000..5d1c27a0 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C2-tool-results.json @@ -0,0 +1,306 @@ +[ + { + "timestamp": "2026-09-05T15:37:15.412Z", + "call_id": "call_XTj3CCi6WvUgKJEysuGnIpyb", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"6a99d6\",\"wall_time_seconds\":0.000003083,\"exit_code\":0,\"original_token_count\":1288,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/C2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C2`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C2` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C2/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/C2/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/clicks.actions --out /tmp/weaver-exp-astra/runs/C2/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/C2/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: C (progressive capture)\\nBuild in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next:\\n1. Frame and header row only (capture initial state).\\n2. Add the seven day cells (capture initial state).\\n3. Add the progress bar (capture initial state).\\n4. Add the buttons and storage (capture initial state AND after-clicks state).\\nFix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:37:26.060Z", + "call_id": "call_dE76p8rSMZsxQn9UOSok6mzM", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"95f963\",\"wall_time_seconds\":0.000003459,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f912cd\",\"wall_time_seconds\":0.000002542,\"exit_code\":0,\"original_token_count\":380,\"output\":\"1:# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n115:## Hot swap\\n121:## Elements (JSX intrinsics)\\n138:## `class` utilities (M1 set)\\n198:### Gradient backgrounds\\n247:### Bundled fonts\\n269:### Icons\\n292:## CLI\\n305:## The conjure skill\\n312:## v0 done-condition (unchanged)\\n320:# M3 amendment (v0.3)\\n322:## `` \u2014 immediate mode (the ADR 0009 exception)\\n354:## Providers: `audio` and `media` (host-fed)\\n374:# M2 amendment (v0.2)\\n378:## Interactive elements (were \\\"arrives in M2\\\")\\n391:## `weaver.fetch` \u2014 the declared-origins network (ADR 0002)\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n419:## Providers: `cpu` and `memory` (host-fed)\\n437:## The host and its CLI verbs\\n459:# Styling breadth amendment (v0.4)\\n464:## PR 01: spacing and sizing\\n488:## PR 02: flex completeness\\n506:## PR 09: overlay stacks and bounded overflow\\n524:## PR 10: image fitting, rounded masks, and tiling\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n633:# Media v2 amendment (v0.5)\\n638:## PR 01: playback status and source application\\n679:## PR 02: album art and dynamic image sources\\n738:## PR 03: media transport capability\\n825:## PR 05: noro acceptance surface\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"a32806\",\"wall_time_seconds\":0.000003042,\"exit_code\":0,\"original_token_count\":2195,\"output\":\"import { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:37:36.003Z", + "call_id": "call_gXkBjJFCp6oHAZCOelLLgzfU", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.3 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"status\":\"fulfilled\",\"value\":{\"chunk_id\":\"a91f22\",\"wall_time_seconds\":0.000001708,\"exit_code\":0,\"original_token_count\":2641,\"output\":\"## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n## Providers: `cpu` and `memory` (host-fed)\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n \\n \\n \\n );''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:40:35.824Z", + "type": "custom_tool_call", + "call_id": "call_OUlDwXjQ7bs2CCu8PRDV1qTa", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/05-initial.png\",yield_time_ms:10000,max_output_tokens:1500}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C2/captures/05-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C2/captures/05-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/05-initial.receipt.json\",max_output_tokens:8500}));\n" + }, + { + "timestamp": "2026-09-05T15:40:48.356Z", + "type": "custom_tool_call", + "call_id": "call_Fgp1tn2ZH3jRGaLz2zT3yPjn", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/clicks.actions --out /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.png\",yield_time_ms:10000,max_output_tokens:1600}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/06-after-clicks.receipt.json\",max_output_tokens:8500}));\n" + }, + { + "timestamp": "2026-09-05T15:41:08.683Z", + "type": "custom_tool_call", + "call_id": "call_oGuofh5Cvcgn8y62KgO6vNTE", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\np='/tmp/weaver-exp-astra/runs/C2/'\\na=json.load(open(p+'clicks.actions'))\\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\nopen(p+'reset.actions','w').write(json.dumps(a,indent=2)+'\\\\n')\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C2\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:41:20.506Z", + "type": "custom_tool_call", + "call_id": "call_5DgiT10oZGKbHLP620WCTsiO", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/reset.actions --out /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.png\",yield_time_ms:10000,max_output_tokens:1600}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C2/captures/07-after-reset.receipt.json\",max_output_tokens:8500}));\n" + }, + { + "timestamp": "2026-09-05T15:41:45.473Z", + "type": "custom_tool_call", + "call_id": "call_r3BJKWzKecTzkFuXuVHlPpl9", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/C2/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: C (progressive capture).\\n- `weaver check` runs: 6 (5 passed, 1 rejected a computed class string).\\n- `weaver capture` runs: 7 (6 successful; attempt 03 failed static validation and published no PNG).\\n- Defects fixed because of pixels or a snapshot: none.\\n- Static diagnostic fix: replaced the computed bar-width class with a documented canvas drawing. No framework files changed.\\n- Unmet spec items: none identified. Persistence uses `useStorage` with a record keyed Mon through Sun; capture isolation does not exercise an actual desktop restart.\\n- Confidence: 9/10.\\n\\nThe four slices were inspected at 320\u00d7200: frame/header in 01, seven cells in 02, progress in 04, and complete initial/three-click states in 05 and 06. Each successful PNG was opened and its snapshot and receipt read. The failed 03 attempt was mistakenly invoked immediately after the failed check; the diagnostic was then fixed and check passed before capture 04 and before proceeding to the next slice.\\n\\nCapture 06 shows Friday at 3, every other day at 0, the label `3 / 20`, and a 15% bar. Capture 07 additionally proves Reset week restores every count to 0 and empties the bar. Semantic snapshots expose exactly named `Log session` and `Reset week` buttons. Native hover and pressed classes are present on both controls; post-click hover appearance was visible in the captures.\\n\\nAll successful receipts have status `ok`, no fetches, unresolved images, or queued frame requests. The single pending timer is associated with the subscribed time provider. The checkout provenance warning reports pre-existing uncommitted changes; this task did not modify repository files. `weaver dev` was not run, as instructed.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:37:15.413Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:26.060Z", + "info": { + "total_token_usage": { + "input_tokens": 39864, + "cached_input_tokens": 37888, + "cache_write_input_tokens": 0, + "output_tokens": 203, + "reasoning_output_tokens": 15, + "total_tokens": 40067 + }, + "last_token_usage": { + "input_tokens": 20661, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 164, + "reasoning_output_tokens": 15, + "total_tokens": 20825 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:37:36.003Z", + "info": { + "total_token_usage": { + "input_tokens": 66045, + "cached_input_tokens": 56832, + "cache_write_input_tokens": 0, + "output_tokens": 354, + "reasoning_output_tokens": 15, + "total_tokens": 66399 + }, + "last_token_usage": { + "input_tokens": 26181, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 151, + "reasoning_output_tokens": 0, + "total_tokens": 26332 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:07.803Z", + "info": { + "total_token_usage": { + "input_tokens": 96890, + "cached_input_tokens": 82816, + "cache_write_input_tokens": 0, + "output_tokens": 983, + "reasoning_output_tokens": 183, + "total_tokens": 97873 + }, + "last_token_usage": { + "input_tokens": 30845, + "cached_input_tokens": 25984, + "cache_write_input_tokens": 0, + "output_tokens": 629, + "reasoning_output_tokens": 168, + "total_tokens": 31474 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:16.040Z", + "info": { + "total_token_usage": { + "input_tokens": 129101, + "cached_input_tokens": 113536, + "cache_write_input_tokens": 0, + "output_tokens": 1084, + "reasoning_output_tokens": 183, + "total_tokens": 130185 + }, + "last_token_usage": { + "input_tokens": 32211, + "cached_input_tokens": 30720, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 32312 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:38:46.509Z", + "info": { + "total_token_usage": { + "input_tokens": 163207, + "cached_input_tokens": 145536, + "cache_write_input_tokens": 0, + "output_tokens": 1715, + "reasoning_output_tokens": 236, + "total_tokens": 164922 + }, + "last_token_usage": { + "input_tokens": 34106, + "cached_input_tokens": 32000, + "cache_write_input_tokens": 0, + "output_tokens": 631, + "reasoning_output_tokens": 53, + "total_tokens": 34737 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:24.389Z", + "info": { + "total_token_usage": { + "input_tokens": 201726, + "cached_input_tokens": 179584, + "cache_write_input_tokens": 0, + "output_tokens": 2440, + "reasoning_output_tokens": 463, + "total_tokens": 204166 + }, + "last_token_usage": { + "input_tokens": 38519, + "cached_input_tokens": 34048, + "cache_write_input_tokens": 0, + "output_tokens": 725, + "reasoning_output_tokens": 227, + "total_tokens": 39244 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:30.374Z", + "info": { + "total_token_usage": { + "input_tokens": 241570, + "cached_input_tokens": 217984, + "cache_write_input_tokens": 0, + "output_tokens": 2508, + "reasoning_output_tokens": 489, + "total_tokens": 244078 + }, + "last_token_usage": { + "input_tokens": 39844, + "cached_input_tokens": 38400, + "cache_write_input_tokens": 0, + "output_tokens": 68, + "reasoning_output_tokens": 26, + "total_tokens": 39912 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:46.549Z", + "info": { + "total_token_usage": { + "input_tokens": 282018, + "cached_input_tokens": 257792, + "cache_write_input_tokens": 0, + "output_tokens": 2791, + "reasoning_output_tokens": 499, + "total_tokens": 284809 + }, + "last_token_usage": { + "input_tokens": 40448, + "cached_input_tokens": 39808, + "cache_write_input_tokens": 0, + "output_tokens": 283, + "reasoning_output_tokens": 10, + "total_tokens": 40731 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:39:56.788Z", + "info": { + "total_token_usage": { + "input_tokens": 322823, + "cached_input_tokens": 298112, + "cache_write_input_tokens": 0, + "output_tokens": 2972, + "reasoning_output_tokens": 499, + "total_tokens": 325795 + }, + "last_token_usage": { + "input_tokens": 40805, + "cached_input_tokens": 40320, + "cache_write_input_tokens": 0, + "output_tokens": 181, + "reasoning_output_tokens": 0, + "total_tokens": 40986 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:24.803Z", + "info": { + "total_token_usage": { + "input_tokens": 367649, + "cached_input_tokens": 338816, + "cache_write_input_tokens": 0, + "output_tokens": 3605, + "reasoning_output_tokens": 539, + "total_tokens": 371254 + }, + "last_token_usage": { + "input_tokens": 44826, + "cached_input_tokens": 40704, + "cache_write_input_tokens": 0, + "output_tokens": 633, + "reasoning_output_tokens": 40, + "total_tokens": 45459 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:36.818Z", + "info": { + "total_token_usage": { + "input_tokens": 413180, + "cached_input_tokens": 383616, + "cache_write_input_tokens": 0, + "output_tokens": 3786, + "reasoning_output_tokens": 539, + "total_tokens": 416966 + }, + "last_token_usage": { + "input_tokens": 45531, + "cached_input_tokens": 44800, + "cache_write_input_tokens": 0, + "output_tokens": 181, + "reasoning_output_tokens": 0, + "total_tokens": 45712 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:40:49.341Z", + "info": { + "total_token_usage": { + "input_tokens": 463152, + "cached_input_tokens": 429056, + "cache_write_input_tokens": 0, + "output_tokens": 3989, + "reasoning_output_tokens": 539, + "total_tokens": 467141 + }, + "last_token_usage": { + "input_tokens": 49972, + "cached_input_tokens": 45440, + "cache_write_input_tokens": 0, + "output_tokens": 203, + "reasoning_output_tokens": 0, + "total_tokens": 50175 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:41:09.569Z", + "info": { + "total_token_usage": { + "input_tokens": 517698, + "cached_input_tokens": 478976, + "cache_write_input_tokens": 0, + "output_tokens": 4246, + "reasoning_output_tokens": 610, + "total_tokens": 521944 + }, + "last_token_usage": { + "input_tokens": 54546, + "cached_input_tokens": 49920, + "cache_write_input_tokens": 0, + "output_tokens": 257, + "reasoning_output_tokens": 71, + "total_tokens": 54803 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:41:21.507Z", + "info": { + "total_token_usage": { + "input_tokens": 572575, + "cached_input_tokens": 533376, + "cache_write_input_tokens": 0, + "output_tokens": 4443, + "reasoning_output_tokens": 610, + "total_tokens": 577018 + }, + "last_token_usage": { + "input_tokens": 54877, + "cached_input_tokens": 54400, + "cache_write_input_tokens": 0, + "output_tokens": 197, + "reasoning_output_tokens": 0, + "total_tokens": 55074 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:41:45.530Z", + "info": { + "total_token_usage": { + "input_tokens": 632029, + "cached_input_tokens": 588160, + "cache_write_input_tokens": 0, + "output_tokens": 4881, + "reasoning_output_tokens": 610, + "total_tokens": 636910 + }, + "last_token_usage": { + "input_tokens": 59454, + "cached_input_tokens": 54784, + "cache_write_input_tokens": 0, + "output_tokens": 438, + "reasoning_output_tokens": 0, + "total_tokens": 59892 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:41:56.113Z", + "info": { + "total_token_usage": { + "input_tokens": 691977, + "cached_input_tokens": 647552, + "cache_write_input_tokens": 0, + "output_tokens": 4955, + "reasoning_output_tokens": 610, + "total_tokens": 696932 + }, + "last_token_usage": { + "input_tokens": 59948, + "cached_input_tokens": 59392, + "cache_write_input_tokens": 0, + "output_tokens": 74, + "reasoning_output_tokens": 0, + "total_tokens": 60022 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/C3-commands.json b/experiments/render-loop-cadence/astra/evidence/C3-commands.json new file mode 100644 index 00000000..1d342fab --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C3-commands.json @@ -0,0 +1,206 @@ +[ + { + "timestamp": "2026-09-05T15:42:34.621Z", + "call_id": "call_C3rSEDBl91aS0FjlsomvNcBJ", + "command": "cat /tmp/weaver-exp-astra/prompts/C3.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:46.566Z", + "call_id": "call_KdRwgV7qMjHibUonUTUgfbDi", + "command": "cat .agents/skills/conjure-widget/SKILL.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:46.566Z", + "call_id": "call_KdRwgV7qMjHibUonUTUgfbDi", + "command": "rg -n 'Module shape|widget\\(config|Hooks|Consolidated v0.4|useStorage|PR 11' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:46.566Z", + "call_id": "call_KdRwgV7qMjHibUonUTUgfbDi", + "command": "cat examples/pomodoro/widget.tsx examples/clock/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:55.885Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "command": "sed -n '1,165p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:55.885Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "command": "sed -n '410,440p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:55.885Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "command": "sed -n '538,780p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:55.885Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "command": "cat docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:42:55.885Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:27.218Z", + "call_id": "call_PC6D7nQgTpTl2IzNYEhztUei", + "command": "cat /tmp/weaver-exp-astra/runs/C3/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:27.218Z", + "call_id": "call_PC6D7nQgTpTl2IzNYEhztUei", + "command": "cat > /tmp/weaver-exp-astra/runs/C3/widget.tsx <<'EOF'\nimport { useProvider, widget } from \"@weaver/sdk\";\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n \n );\n});\nEOF\nmkdir -p /tmp/weaver-exp-astra/runs/C3/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/C3/clicks.actions\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:27.218Z", + "call_id": "call_PC6D7nQgTpTl2IzNYEhztUei", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:34.037Z", + "call_id": "call_MQxTRJuWiF7mnX1xxRcq6xT8", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/01-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:59.370Z", + "call_id": "call_Vy6cjqoUvK6NnvCCeLcRhFLi", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np=Path('/tmp/weaver-exp-astra/runs/C3/widget.tsx')\ns=p.read_text().replace('export default widget({', 'const days = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"] as const;\\nconst letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\n\\nexport default widget({')\ns=s.replace(' \\n ', ''' \n \n {days.map((day, index) => (\n \n {letters[index]}\n 0\n \n ))}\n \n ''')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:59.370Z", + "call_id": "call_Vy6cjqoUvK6NnvCCeLcRhFLi", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/02-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:43:59.370Z", + "call_id": "call_Vy6cjqoUvK6NnvCCeLcRhFLi", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/02-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/02-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:26.114Z", + "call_id": "call_g7zBxcXPGFb1oniXkQj6t3jc", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np=Path('/tmp/weaver-exp-astra/runs/C3/widget.tsx')\ns=p.read_text().replace(' const time = useProvider(\"time\");', ' const time = useProvider(\"time\");\\n const total = 0;')\ns=s.replace(' \\n );', ''' \n \n \n \n {total} / 20\n \n \n );''')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:26.114Z", + "call_id": "call_g7zBxcXPGFb1oniXkQj6t3jc", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/03-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:26.114Z", + "call_id": "call_g7zBxcXPGFb1oniXkQj6t3jc", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/03-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:35.535Z", + "call_id": "call_haUeyr4L1UVweeUNn365pQrb", + "command": "rg -n 'fillRect|CanvasCtx|fillRound|roundRect' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:55.123Z", + "call_id": "call_dETz1FaAXQ78mFO9zaT20lIW", + "command": "sed -n '315,365p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:44:55.123Z", + "call_id": "call_dETz1FaAXQ78mFO9zaT20lIW", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np=Path('/tmp/weaver-exp-astra/runs/C3/widget.tsx')\ns=p.read_text().replace(''' \n \n ''', ''' {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff1a\");\n if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, \"#5eead4\");\n }} />''')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:15.606Z", + "call_id": "call_oSFUlooyzm3Auvqa4hwVOPsw", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/04-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:15.606Z", + "call_id": "call_oSFUlooyzm3Auvqa4hwVOPsw", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/04-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/04-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:45.441Z", + "call_id": "call_bXbVjpJasA4OY6ITAcjeGttI", + "command": "python3 - <<'PY'\nfrom pathlib import Path\np=Path('/tmp/weaver-exp-astra/runs/C3/widget.tsx')\ns=p.read_text().replace('useProvider, widget','useProvider, useStorage, widget')\ns=s.replace('const letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];', 'const letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\ntype Day = typeof days[number];\\nconst emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 };')\ns=s.replace(' const total = 0;', ' const [counts, setCounts] = useStorage>(\"sessions-by-weekday\", emptyWeek);\\n const total = days.reduce((sum, day) => sum + counts[day], 0);')\ns=s.replace('text-[#f5f6f8]\">0', 'text-[#f5f6f8]\">{counts[day]}')\ns=s.replace(' \\n );', ''' \n setCounts((current) => ({ ...current, [time.weekday]: current[time.weekday as Day] + 1 }))}\n >\n \n Log session\n \n \n setCounts({ ...emptyWeek })}\n >\n \n Reset week\n \n \n \n \n );''')\np.write_text(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:55.338Z", + "call_id": "call_UPcnkPDHtahFtS9cNfXfCBVo", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/05-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:45:55.338Z", + "call_id": "call_UPcnkPDHtahFtS9cNfXfCBVo", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/05-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/05-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:03.498Z", + "call_id": "call_nB45VOHCUu0iPoaTaWW2SBAk", + "command": "npx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:14.990Z", + "call_id": "call_vQsqr7G1lzIxoQdCpCI6DgLo", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/clicks.actions --out /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:14.990Z", + "call_id": "call_vQsqr7G1lzIxoQdCpCI6DgLo", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:29.325Z", + "call_id": "call_Dfalz8GfGzhGdZkvVMt4zd5q", + "command": "python3 - <<'PY'\nimport json\nfrom pathlib import Path\nroot=Path('/tmp/weaver-exp-astra/runs/C3')\na=json.loads((root/'clicks.actions').read_text())\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\n(root/'reset.actions').write_text(json.dumps(a, indent=2)+'\\n')\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:39.787Z", + "call_id": "call_B1C7ARVGc8Cc3zkiR8uDLW63", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/reset.actions --out /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:46:39.787Z", + "call_id": "call_B1C7ARVGc8Cc3zkiR8uDLW63", + "command": "cat /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:47:07.348Z", + "call_id": "call_Yf0KlnwvG8jgnHatjsn8ECzi", + "command": "cat > /tmp/weaver-exp-astra/runs/C3/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: C (progressive capture).\n- `weaver check` runs: 7 (6 passed, 1 failed; final run passed).\n- `weaver capture` runs: 7 (6 successful, 1 failed before rendering).\n- Defects fixed because of pixels or a snapshot: none. Each rendered slice was inspected at its actual 320×200 dimensions and had no observed clipping, overlap, or alignment defect.\n- Spec items not met: none known. Persistence uses `useStorage` with a record keyed Mon through Sun; restart persistence relies on the documented hook contract and was not separately exercised by the isolated captures. Reset is manual through Reset week.\n- Confidence: 9/10.\n\nThe four slices were captured in order: frame/header (01), days (02), progress (04), and buttons/storage (05 initial, 06 after three clicks). Capture 07 additionally verifies Reset week after three clicks. Every published PNG was opened, its semantic snapshot read, and its receipt confirmed `status: \"ok\"`. Capture 06 shows Friday 3, six zero counts, `3 / 20`, and the 15% bar. Capture 07 returns all counts to zero and clears the bar. Both accessible button names match exactly. The successful receipts report only the expected time-provider timer, no fetches or pending frame requests, and the existing dirty-checkout provenance warning.\n\nOne authoring error was fixed from checker diagnostics: a computed width class was not statically enumerable. The progress bar now uses the documented canvas drawing API. Capture attempt 03 was inadvertently invoked after that failed check and also failed with the same actionable diagnostic; it published no PNG or snapshot. The next check passed before capture 04. Capture counters were not reused.\n\nNo `weaver dev` was run, as instructed. No repository file was edited.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/C3-tool-results.json b/experiments/render-loop-cadence/astra/evidence/C3-tool-results.json new file mode 100644 index 00000000..f0b3a1a6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C3-tool-results.json @@ -0,0 +1,332 @@ +[ + { + "timestamp": "2026-09-05T15:42:34.674Z", + "call_id": "call_C3rSEDBl91aS0FjlsomvNcBJ", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"cce459\",\"wall_time_seconds\":0.000003666,\"exit_code\":0,\"original_token_count\":1288,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/C3 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C3`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C3` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C3/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/C3/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/clicks.actions --out /tmp/weaver-exp-astra/runs/C3/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/C3/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: C (progressive capture)\\nBuild in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next:\\n1. Frame and header row only (capture initial state).\\n2. Add the seven day cells (capture initial state).\\n3. Add the progress bar (capture initial state).\\n4. Add the buttons and storage (capture initial state AND after-clicks state).\\nFix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:42:46.743Z", + "call_id": "call_KdRwgV7qMjHibUonUTUgfbDi", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.2 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"36fb73\",\"wall_time_seconds\":0.0000035,\"exit_code\":0,\"original_token_count\":1981,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"68b7bf\",\"wall_time_seconds\":0.00000375,\"exit_code\":0,\"original_token_count\":106,\"output\":\"20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"e3fea3\",\"wall_time_seconds\":0.000003,\"exit_code\":0,\"original_token_count\":2195,\"output\":\"import { useInterval, useStorage, widget, type CanvasCtx } from \\\"@weaver/sdk\\\";\\n\\n// A tiny app: persisted state, one timer, buttons with native hover and\\n// pressed states, and a canvas ring that redraws once per second.\\n\\ntype Mode = \\\"focus\\\" | \\\"short\\\" | \\\"long\\\";\\n\\nconst minutes: Record = { focus: 25, short: 5, long: 15 };\\nconst headings: Record = { focus: \\\"FOCUS\\\", short: \\\"SHORT BREAK\\\", long: \\\"LONG BREAK\\\" };\\nconst focusColor = \\\"#ff7a59\\\";\\nconst breakColor = \\\"#5eead4\\\";\\n\\ninterface TimerState {\\n mode: Mode;\\n remaining: number; // seconds\\n running: boolean;\\n}\\n\\nfunction clock(seconds: number): string {\\n return `${String(Math.floor(seconds / 60)).padStart(2, \\\"0\\\")}:${String(seconds % 60).padStart(2, \\\"0\\\")}`;\\n}\\n\\n// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out.\\nfunction drawRing(ctx: CanvasCtx, fraction: number, color: string): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const outer = Math.min(cx, cy) - 2;\\n const inner = outer - 11;\\n const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60);\\n for (let index = 0; index < 60; index += 1) {\\n const angle = (index / 60) * Math.PI * 2 - Math.PI / 2;\\n const cos = Math.cos(angle);\\n const sin = Math.sin(angle);\\n ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : \\\"#ffffff1f\\\");\\n }\\n}\\n\\nexport default widget({\\n name: \\\"Pomodoro\\\",\\n size: [300, 344],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 180] },\\n}, () => {\\n const [timer, setTimer] = useStorage(\\\"timer\\\", { mode: \\\"focus\\\", remaining: minutes.focus * 60, running: false });\\n const total = minutes[timer.mode] * 60;\\n const focus = timer.mode === \\\"focus\\\";\\n const color = focus ? focusColor : breakColor;\\n\\n // Ticks once per second while running. While paused the interval is\\n // stretched to an hour so the widget does not wake up for nothing.\\n useInterval(() => {\\n setTimer((current) => {\\n if (!current.running) return current;\\n if (current.remaining <= 1) return { ...current, remaining: 0, running: false };\\n return { ...current, remaining: current.remaining - 1 };\\n });\\n }, timer.running ? 1000 : 3_600_000);\\n\\n const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false });\\n const chip = (mode: Mode, label: string) => {\\n const selected = timer.mode === mode;\\n return (\\n select(mode)}\\n >\\n \\n {label}\\n \\n \\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:42:56.434Z", + "call_id": "call_Fhn8IpPyV7s2ZjLULkevU3Qg", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"status\":\"fulfilled\",\"value\":{\"chunk_id\":\"8433bd\",\"wall_time_seconds\":0.000003167,\"exit_code\":0,\"original_token_count\":2112,\"output\":\"# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n\\nThis is the authoring contract for Weaver widgets. It is the product's face:\\nagents learn Weaver from this file. Implementation must match it exactly;\\nanything not implementable in M1 must fail at `weaver check` with a clear\\n\\\"arrives in M2\\\" message \u2014 never silently no-op.\\n\\nDesign invariants (from ADRs 0001/0003/0005/0009):\\n- One TSX module per widget; `widget()` is the default export.\\n- Styling is Tailwind-shaped `class` strings; arbitrary values allowed;\\n unknown utilities are check-time errors with fix-its.\\n- Idle-zero: no state change \u2192 no ops \u2192 no repaint. The SDK never polls.\\n- The reconciler runs in JS and emits retained-tree ops (never full frames).\\n- `weaver check` estimates the exported widget's lowered Native tree through\\n local components and one level of relative imports, taking the maximum across\\n conditional JSX returns and counting statically evident implicit text nodes.\\n Dynamic collections and unresolved component output remain subject to the\\n authoritative Native runtime node/depth limits.\\n\\n## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## Hot swap\\n`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one.\\nRoot hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart.\\nAny slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh.\\nEvaluation failure leaves the prior context, window, and state running; window-config changes restart the process.\\n\\n## Elements (JSX intrinsics)\\n\\n| Element | M1 renders | Props beyond `class`/`children` |\\n|---|---|---|\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 |\\n| `` | yes | \u2014 (a styled box; column layout) |\\n| `` | yes | \u2014 (children: strings/numbers, or one `Signal`) |\\n| `` | yes | exactly one of literal `name` or literal `d`; custom paths also accept `viewBox`/`stroke`; no children |\\n| `` | check-error \\\"arrives in M2\\\" | `src` |\\n| `\\n```\\n\\n`onPress` remains required on `\\n setCounts({ ...emptyWeek })}\\n >\\n \\n Reset week\\n \\n \\n \\n \\n );''')\\np.write_text(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:45:55.338Z", + "type": "custom_tool_call", + "call_id": "call_UPcnkPDHtahFtS9cNfXfCBVo", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/05-initial.png\",max_output_tokens:3000}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C3/captures/05-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C3/captures/05-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/05-initial.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:46:03.498Z", + "type": "custom_tool_call", + "call_id": "call_nB45VOHCUu0iPoaTaWW2SBAk", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver check /tmp/weaver-exp-astra/runs/C3\",max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:46:14.990Z", + "type": "custom_tool_call", + "call_id": "call_vQsqr7G1lzIxoQdCpCI6DgLo", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/clicks.actions --out /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.png\",max_output_tokens:3000}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/06-after-clicks.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:46:29.325Z", + "type": "custom_tool_call", + "call_id": "call_Dfalz8GfGzhGdZkvVMt4zd5q", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\nfrom pathlib import Path\\nroot=Path('/tmp/weaver-exp-astra/runs/C3')\\na=json.loads((root/'clicks.actions').read_text())\\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\n(root/'reset.actions').write_text(json.dumps(a, indent=2)+'\\\\n')\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C3\",max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:46:39.787Z", + "type": "custom_tool_call", + "call_id": "call_B1C7ARVGc8Cc3zkiR8uDLW63", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/reset.actions --out /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.png\",max_output_tokens:3000}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C3/captures/07-after-reset.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:47:07.348Z", + "type": "custom_tool_call", + "call_id": "call_Yf0KlnwvG8jgnHatjsn8ECzi", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/C3/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: C (progressive capture).\\n- `weaver check` runs: 7 (6 passed, 1 failed; final run passed).\\n- `weaver capture` runs: 7 (6 successful, 1 failed before rendering).\\n- Defects fixed because of pixels or a snapshot: none. Each rendered slice was inspected at its actual 320\u00d7200 dimensions and had no observed clipping, overlap, or alignment defect.\\n- Spec items not met: none known. Persistence uses `useStorage` with a record keyed Mon through Sun; restart persistence relies on the documented hook contract and was not separately exercised by the isolated captures. Reset is manual through Reset week.\\n- Confidence: 9/10.\\n\\nThe four slices were captured in order: frame/header (01), days (02), progress (04), and buttons/storage (05 initial, 06 after three clicks). Capture 07 additionally verifies Reset week after three clicks. Every published PNG was opened, its semantic snapshot read, and its receipt confirmed `status: \\\"ok\\\"`. Capture 06 shows Friday 3, six zero counts, `3 / 20`, and the 15% bar. Capture 07 returns all counts to zero and clears the bar. Both accessible button names match exactly. The successful receipts report only the expected time-provider timer, no fetches or pending frame requests, and the existing dirty-checkout provenance warning.\\n\\nOne authoring error was fixed from checker diagnostics: a computed width class was not statically enumerable. The progress bar now uses the documented canvas drawing API. Capture attempt 03 was inadvertently invoked after that failed check and also failed with the same actionable diagnostic; it published no PNG or snapshot. The next check passed before capture 04. Capture counters were not reused.\\n\\nNo `weaver dev` was run, as instructed. No repository file was edited.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:42:34.674Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:42:46.744Z", + "info": { + "total_token_usage": { + "input_tokens": 39862, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 228, + "reasoning_output_tokens": 30, + "total_tokens": 40090 + }, + "last_token_usage": { + "input_tokens": 20659, + "cached_input_tokens": 19072, + "cache_write_input_tokens": 0, + "output_tokens": 189, + "reasoning_output_tokens": 30, + "total_tokens": 20848 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:42:56.434Z", + "info": { + "total_token_usage": { + "input_tokens": 65715, + "cached_input_tokens": 56960, + "cache_write_input_tokens": 0, + "output_tokens": 380, + "reasoning_output_tokens": 30, + "total_tokens": 66095 + }, + "last_token_usage": { + "input_tokens": 25853, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 152, + "reasoning_output_tokens": 0, + "total_tokens": 26005 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:28.719Z", + "info": { + "total_token_usage": { + "input_tokens": 99312, + "cached_input_tokens": 82688, + "cache_write_input_tokens": 0, + "output_tokens": 1014, + "reasoning_output_tokens": 209, + "total_tokens": 100326 + }, + "last_token_usage": { + "input_tokens": 33597, + "cached_input_tokens": 25728, + "cache_write_input_tokens": 0, + "output_tokens": 634, + "reasoning_output_tokens": 179, + "total_tokens": 34231 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:43:34.104Z", + "info": { + "total_token_usage": { + "input_tokens": 134284, + "cached_input_tokens": 116096, + "cache_write_input_tokens": 0, + "output_tokens": 1115, + "reasoning_output_tokens": 209, + "total_tokens": 135399 + }, + "last_token_usage": { + "input_tokens": 34972, + "cached_input_tokens": 33408, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 35073 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:00.960Z", + "info": { + "total_token_usage": { + "input_tokens": 171155, + "cached_input_tokens": 150912, + "cache_write_input_tokens": 0, + "output_tokens": 1713, + "reasoning_output_tokens": 229, + "total_tokens": 172868 + }, + "last_token_usage": { + "input_tokens": 36871, + "cached_input_tokens": 34816, + "cache_write_input_tokens": 0, + "output_tokens": 598, + "reasoning_output_tokens": 20, + "total_tokens": 37469 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:27.400Z", + "info": { + "total_token_usage": { + "input_tokens": 212386, + "cached_input_tokens": 187776, + "cache_write_input_tokens": 0, + "output_tokens": 2295, + "reasoning_output_tokens": 315, + "total_tokens": 214681 + }, + "last_token_usage": { + "input_tokens": 41231, + "cached_input_tokens": 36864, + "cache_write_input_tokens": 0, + "output_tokens": 582, + "reasoning_output_tokens": 86, + "total_tokens": 41813 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:35.599Z", + "info": { + "total_token_usage": { + "input_tokens": 254796, + "cached_input_tokens": 206720, + "cache_write_input_tokens": 0, + "output_tokens": 2379, + "reasoning_output_tokens": 350, + "total_tokens": 257175 + }, + "last_token_usage": { + "input_tokens": 42410, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 84, + "reasoning_output_tokens": 35, + "total_tokens": 42494 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:44:55.869Z", + "info": { + "total_token_usage": { + "input_tokens": 297414, + "cached_input_tokens": 249088, + "cache_write_input_tokens": 0, + "output_tokens": 2676, + "reasoning_output_tokens": 350, + "total_tokens": 300090 + }, + "last_token_usage": { + "input_tokens": 42618, + "cached_input_tokens": 42368, + "cache_write_input_tokens": 0, + "output_tokens": 297, + "reasoning_output_tokens": 0, + "total_tokens": 42915 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:16.393Z", + "info": { + "total_token_usage": { + "input_tokens": 341093, + "cached_input_tokens": 291584, + "cache_write_input_tokens": 0, + "output_tokens": 2851, + "reasoning_output_tokens": 350, + "total_tokens": 343944 + }, + "last_token_usage": { + "input_tokens": 43679, + "cached_input_tokens": 42496, + "cache_write_input_tokens": 0, + "output_tokens": 175, + "reasoning_output_tokens": 0, + "total_tokens": 43854 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:46.080Z", + "info": { + "total_token_usage": { + "input_tokens": 388782, + "cached_input_tokens": 335232, + "cache_write_input_tokens": 0, + "output_tokens": 3579, + "reasoning_output_tokens": 449, + "total_tokens": 392361 + }, + "last_token_usage": { + "input_tokens": 47689, + "cached_input_tokens": 43648, + "cache_write_input_tokens": 0, + "output_tokens": 728, + "reasoning_output_tokens": 99, + "total_tokens": 48417 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:45:56.150Z", + "info": { + "total_token_usage": { + "input_tokens": 437272, + "cached_input_tokens": 382848, + "cache_write_input_tokens": 0, + "output_tokens": 3754, + "reasoning_output_tokens": 449, + "total_tokens": 441026 + }, + "last_token_usage": { + "input_tokens": 48490, + "cached_input_tokens": 47616, + "cache_write_input_tokens": 0, + "output_tokens": 175, + "reasoning_output_tokens": 0, + "total_tokens": 48665 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:04.200Z", + "info": { + "total_token_usage": { + "input_tokens": 490195, + "cached_input_tokens": 431232, + "cache_write_input_tokens": 0, + "output_tokens": 3799, + "reasoning_output_tokens": 449, + "total_tokens": 493994 + }, + "last_token_usage": { + "input_tokens": 52923, + "cached_input_tokens": 48384, + "cache_write_input_tokens": 0, + "output_tokens": 45, + "reasoning_output_tokens": 0, + "total_tokens": 52968 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:15.873Z", + "info": { + "total_token_usage": { + "input_tokens": 543234, + "cached_input_tokens": 484096, + "cache_write_input_tokens": 0, + "output_tokens": 3996, + "reasoning_output_tokens": 449, + "total_tokens": 547230 + }, + "last_token_usage": { + "input_tokens": 53039, + "cached_input_tokens": 52864, + "cache_write_input_tokens": 0, + "output_tokens": 197, + "reasoning_output_tokens": 0, + "total_tokens": 53236 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:30.194Z", + "info": { + "total_token_usage": { + "input_tokens": 600843, + "cached_input_tokens": 537088, + "cache_write_input_tokens": 0, + "output_tokens": 4238, + "reasoning_output_tokens": 483, + "total_tokens": 605081 + }, + "last_token_usage": { + "input_tokens": 57609, + "cached_input_tokens": 52992, + "cache_write_input_tokens": 0, + "output_tokens": 242, + "reasoning_output_tokens": 34, + "total_tokens": 57851 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:46:40.768Z", + "info": { + "total_token_usage": { + "input_tokens": 658769, + "cached_input_tokens": 594560, + "cache_write_input_tokens": 0, + "output_tokens": 4429, + "reasoning_output_tokens": 483, + "total_tokens": 663198 + }, + "last_token_usage": { + "input_tokens": 57926, + "cached_input_tokens": 57472, + "cache_write_input_tokens": 0, + "output_tokens": 191, + "reasoning_output_tokens": 0, + "total_tokens": 58117 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:47:07.419Z", + "info": { + "total_token_usage": { + "input_tokens": 721268, + "cached_input_tokens": 652416, + "cache_write_input_tokens": 0, + "output_tokens": 4945, + "reasoning_output_tokens": 555, + "total_tokens": 726213 + }, + "last_token_usage": { + "input_tokens": 62499, + "cached_input_tokens": 57856, + "cache_write_input_tokens": 0, + "output_tokens": 516, + "reasoning_output_tokens": 72, + "total_tokens": 63015 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:47:18.292Z", + "info": { + "total_token_usage": { + "input_tokens": 784341, + "cached_input_tokens": 714880, + "cache_write_input_tokens": 0, + "output_tokens": 5011, + "reasoning_output_tokens": 555, + "total_tokens": 789352 + }, + "last_token_usage": { + "input_tokens": 63073, + "cached_input_tokens": 62464, + "cache_write_input_tokens": 0, + "output_tokens": 66, + "reasoning_output_tokens": 0, + "total_tokens": 63139 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/C4-commands.json b/experiments/render-loop-cadence/astra/evidence/C4-commands.json new file mode 100644 index 00000000..1d309c15 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C4-commands.json @@ -0,0 +1,194 @@ +[ + { + "timestamp": "2026-09-05T15:47:48.100Z", + "call_id": "call_XXjBSmT734JmVunTe8nqWWBC", + "command": "cat /tmp/weaver-exp-astra/prompts/C4.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:47:58.318Z", + "call_id": "call_6Hxo83QoAdfwyLHT7RuCfaWw", + "command": "cat .agents/skills/conjure-widget/SKILL.md && rg -n '^#+ .*|Module shape|widget\\(config|useStorage|PR 11|Consolidated v0.4' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:08.364Z", + "call_id": "call_KtigcUemo92EfOoh52ZFhr3A", + "command": "sed -n '20,114p' sdk/CONTRACT.md; sed -n '410,418p' sdk/CONTRACT.md; sed -n '459,523p' sdk/CONTRACT.md; sed -n '538,632p' sdk/CONTRACT.md; cat examples/pomodoro/widget.tsx examples/clock/widget.tsx docs/agent-widget-capture.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:08.364Z", + "call_id": "call_KtigcUemo92EfOoh52ZFhr3A", + "command": "npx --no-install weaver init /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:30.377Z", + "call_id": "call_EjeAywKOSGYPSfk950P2RfPT", + "command": "cat /tmp/weaver-exp-astra/runs/C4/widget.tsx", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:30.377Z", + "call_id": "call_EjeAywKOSGYPSfk950P2RfPT", + "command": "mkdir -p /tmp/weaver-exp-astra/runs/C4/captures\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/C4/clicks.actions\ncat > /tmp/weaver-exp-astra/runs/C4/widget.tsx <<'EOF'\nimport { useProvider, widget } from \"@weaver/sdk\";\n\nexport default widget({\n name: \"Focus Week\",\n size: [320, 200],\n anchor: { corner: \"top-right\", offset: [24, 24] },\n subscribe: [\"time\"],\n}, () => {\n const time = useProvider(\"time\");\n return (\n \n \n Focus week\n {time.weekday}, {time.month} {time.day}\n \n \n );\n});\nEOF\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:30.377Z", + "call_id": "call_EjeAywKOSGYPSfk950P2RfPT", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/01-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:48:40.412Z", + "call_id": "call_umhjfB9Mpti843ayigBQcsON", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/01-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:00.368Z", + "call_id": "call_LOxD5Ox9V9ckx5ttBvkUu9Up", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\ns=open(p).read().replace('text-[16px] font-semibold', 'text-[14px] font-semibold').replace('text-[12px] text-[#f5f6f8]/65','text-[14px] text-[#f5f6f8]/65')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:00.368Z", + "call_id": "call_LOxD5Ox9V9ckx5ttBvkUu9Up", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/02-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:00.368Z", + "call_id": "call_LOxD5Ox9V9ckx5ttBvkUu9Up", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/02-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/02-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:26.755Z", + "call_id": "call_z4LTKnjN69dfSd4ShypMc0Ck", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\ns=open(p).read().replace('\\nexport default', '\\nconst weekdays = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\\nconst letters = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"];\\n\\nexport default')\ns=s.replace(' \\n ', ''' \n \n {weekdays.map((day, index) => (\n \n {letters[index]}\n 0\n \n ))}\n \n ''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:26.755Z", + "call_id": "call_z4LTKnjN69dfSd4ShypMc0Ck", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/03-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:26.755Z", + "call_id": "call_z4LTKnjN69dfSd4ShypMc0Ck", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/03-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:48.624Z", + "call_id": "call_tIt5RBe0oL6x5dY80hpS3fGE", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\ns=open(p).read().replace(' const time = useProvider(\"time\");', ' const time = useProvider(\"time\");\\n const total = 0;')\ns=s.replace(' \\n );', ''' \n \n Weekly goal\n {total} / 20\n \n \n \n \n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:48.624Z", + "call_id": "call_tIt5RBe0oL6x5dY80hpS3fGE", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/04-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:48.624Z", + "call_id": "call_tIt5RBe0oL6x5dY80hpS3fGE", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/04-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/04-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:49:55.030Z", + "call_id": "call_4gOEnqwTnaHWzGMtKVFeW15G", + "command": "sed -n '322,353p' sdk/CONTRACT.md", + "literal": true + }, + { + "timestamp": "2026-09-05T15:50:10.079Z", + "call_id": "call_6tijk9R4pYW9t6rXBZ6hvdGB", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\ns=open(p).read().replace(''' \n \n ''', ''' {\n ctx.clear();\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \"#ffffff1a\");\n if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, \"#5eead4\");\n }} />''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:50:18.106Z", + "call_id": "call_ss3h9Hncll12auk0OTTel0sN", + "command": "python3 - <<'PY'\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\ns=open(p).read().replace('>(\"sessions-by-weekday\", emptyWeek);\\n const total = weekdays.reduce((sum, day) => sum + counts[day], 0);')\ns=s.replace('text-[#f5f6f8]\">0', 'text-[#f5f6f8]\">{counts[day]}')\ns=s.replace(' \\n );', ''' \n \n \n \n \n );''')\nopen(p,'w').write(s)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:12.521Z", + "call_id": "call_mfktqWEtRWGcxbxUge6cHSf2", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/06-initial.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:12.521Z", + "call_id": "call_mfktqWEtRWGcxbxUge6cHSf2", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/06-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/06-initial.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:18.898Z", + "call_id": "call_znSEYpmxYSbzxwphfB5Ounmq", + "command": "npx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:30.518Z", + "call_id": "call_dS0JdBwObRcjIjEJ5WcgYJCS", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/clicks.actions --out /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:30.518Z", + "call_id": "call_dS0JdBwObRcjIjEJ5WcgYJCS", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:51:44.258Z", + "call_id": "call_xftdccrtHc0qzB3inRujyP6a", + "command": "python3 - <<'PY'\nimport json\np='/tmp/weaver-exp-astra/runs/C4/'\na=json.load(open(p+'clicks.actions'))\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\njson.dump(a,open(p+'reset.actions','w'),indent=2)\nPY\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4", + "literal": true + }, + { + "timestamp": "2026-09-05T15:52:04.771Z", + "call_id": "call_txsUDTUGj0hkvWrjGWhayEN0", + "command": "npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/reset.actions --out /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.png", + "literal": true + }, + { + "timestamp": "2026-09-05T15:52:04.771Z", + "call_id": "call_txsUDTUGj0hkvWrjGWhayEN0", + "command": "cat /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.receipt.json", + "literal": true + }, + { + "timestamp": "2026-09-05T15:52:41.415Z", + "call_id": "call_YxtMUBTWvfiImGRK8RYukaJi", + "command": "cat > /tmp/weaver-exp-astra/runs/C4/REPORT.md <<'EOF'\n# Focus Week report\n\n- Condition: C (progressive capture).\n- `weaver check` runs: 9 (7 passed, 2 failed with actionable authoring diagnostics; final check passed).\n- `weaver capture` runs: 8 (7 successful, 1 failed before rendering).\n- Confidence: 9 / 10.\n\n## Defects fixed because of pixels or snapshots\n\n- Slice 1: the original 16px title and 12px date had different vertical text metrics in capture 01. Changed both to 14px, retaining the title's semibold weight. Capture 02 confirms matching y=20.5 and height=17.5 text bounds and visually aligned text.\n\n## Evidence\n\n- Slice 1: captures 01 and 02, frame and header.\n- Slice 2: capture 03, seven equal-width weekday cells (37.714287px each), Friday highlighted, all counts zero.\n- Slice 3: capture 05, goal label above the bar with a clear gap. Capture attempt 04 failed static validation of a computed class and produced no artifacts. Replaced the computed class with the documented canvas drawing API, then fixed its width to the measured 288px content width after the checker rejected percentage canvas sizing.\n- Slice 4: capture 06, full initial widget. Capture 07, three Log session clicks: Friday 3, all other days 0, label 3 / 20, bar 15% (43.2 / 288px).\n- Additional interaction: capture 08, three Log session clicks followed by Reset week: all seven counts zero, label 0 / 20, empty bar.\n- Opened and inspected every successful PNG at 320x200, read every semantic snapshot and receipt. All successful receipts have status `ok`. Both exact button names appear in semantics. Both buttons have native hover and pressed classes; post-action captures show their hover feedback.\n- Counts use `useStorage` with a JSON object keyed Mon through Sun. Restart persistence relies on that documented SDK contract; capture deliberately uses fresh isolated storage each run.\n- Receipts report the pre-existing dirty repository warning. No repository files were modified. One pending timer is consistent with the time subscription; no fetches, images, other providers, or pending frame requests appear.\n- No live view was started, as the task explicitly forbids `weaver dev`.\n\n## Unmet spec items\n\nNone identified. No automatic calendar-week rollover was added; Reset week explicitly clears the stored weekday counts as requested.\nEOF", + "literal": true + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/C4-tool-results.json b/experiments/render-loop-cadence/astra/evidence/C4-tool-results.json new file mode 100644 index 00000000..bfefa461 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C4-tool-results.json @@ -0,0 +1,348 @@ +[ + { + "timestamp": "2026-09-05T15:47:48.175Z", + "call_id": "call_XXjBSmT734JmVunTe8nqWWBC", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"cf5330\",\"wall_time_seconds\":0.000004875,\"exit_code\":0,\"original_token_count\":1288,\"output\":\"You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below.\\n\\n## Your widget directory\\n/tmp/weaver-exp-astra/runs/C4 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C4`; it will not exist yet)\\n\\n## Rules\\n- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments.\\n- Import Weaver APIs only from \\\"@weaver/sdk\\\". Keep one literal default export: `export default widget({ ... }, () => <... />);`\\n- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: \\\"Module shape\\\", \\\"widget(config, component)\\\", \\\"Hooks\\\", \\\"Consolidated v0.4 authoring tables\\\", \\\"useStorage\\\", and \\\"PR 11: native interaction states and press events\\\". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide.\\n- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C4` is the authority for statically knowable widget errors. It must pass before you finish.\\n\\n## Widget spec\\nName: \\\"Focus Week\\\". Size 320\u00d7200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers.\\n\\n1. Header row. Left: the title \\\"Focus week\\\". Right, aligned to the same baseline: the current weekday and date, for example \\\"Fri, Sep 4\\\" (from time.weekday, time.month, time.day).\\n2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show \\\"0\\\".\\n3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form \\\"12 / 20\\\" placed so that it never overlaps the bar.\\n4. Two buttons in one row. Primary: \\\"Log session\\\" adds one session to today. Secondary: \\\"Reset week\\\" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday.\\n5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1\u00d7 scale.\\n\\nThe buttons' accessible names must be exactly \\\"Log session\\\" and \\\"Reset week\\\".\\n\\n## Capture commands (only if your condition below allows capture)\\nFixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C4/clicks.actions first. It clicks \\\"Log session\\\" three times; the expected result is Friday showing 3, every other day 0, label \\\"3 / 20\\\", bar at 15%.\\n\\n```\\nmkdir -p /tmp/weaver-exp-astra/runs/C4/captures\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/NN-initial.png\\nnpx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/clicks.actions --out /tmp/weaver-exp-astra/runs/C4/captures/NN-after-clicks.png\\n```\\nNN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status \\\"ok\\\". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error.\\n\\n## When you are done\\nWrite /tmp/weaver-exp-astra/runs/C4/REPORT.md containing:\\n- Condition letter.\\n- Number of `weaver check` runs and number of `weaver capture` runs you made.\\n- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write \\\"none\\\" if you never captured or found nothing).\\n- Any spec item you could not meet and why.\\n- Your confidence (0 to 10) that the widget matches the spec.\\nThen reply with a two-line summary. Do not paste code into your reply.\\n\\n## Your condition: C (progressive capture)\\nBuild in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next:\\n1. Frame and header row only (capture initial state).\\n2. Add the seven day cells (capture initial state).\\n3. Add the progress bar (capture initial state).\\n4. Add the buttons and storage (capture initial state AND after-clicks state).\\nFix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied.\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:47:58.393Z", + "call_id": "call_6Hxo83QoAdfwyLHT7RuCfaWw", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"9c7c02\",\"wall_time_seconds\":0.000003834,\"exit_code\":0,\"original_token_count\":2360,\"output\":\"---\\nname: conjure-widget\\ndescription: Create or change a Weaver desktop widget, then prove its code, pixels, semantics, and requested interactions. Use for widget authoring requests; framework implementation belongs to Weaver maintainer workflows.\\n---\\n\\n# Conjure a Weaver widget\\n\\nTurn the request into one checked and captured widget while the user watches it\\ntake shape on the desktop. Start the **Live loop** before the first source edit.\\nIts audience is the user. It keeps `weaver dev` running in the background so\\neach valid save can appear while the next edit is underway. Use the **Render\\nloop** for the agent's deterministic inspection and interaction proof. Get the\\nfirst coherent tree on screen early, then inspect each capture while changing\\nthe code. Preserve the requested visual and interaction intent. Keep the widget\\nhonest. Report any part Weaver does not support as a boundary.\\n\\n## Workflow\\n\\n1. Inspect the target before editing. For a new widget, run\\n `npx --no-install weaver init ` from the Weaver repository root; the\\n final path segment becomes the starter display name. For an existing widget,\\n read its `widget.tsx`, local modules, assets, and licenses without running\\n `init` over it.\\n2. Read the relevant current sections under **Contract routing** before choosing\\n elements, hooks, providers, classes, assets, network access, or capabilities.\\n When the request uses interaction, changing time, provider data, or replay,\\n read [`docs/agent-widget-capture.md`](../../../docs/agent-widget-capture.md) now.\\n Define stable capture inputs and a name for each state the request needs so\\n every pass renders the same evidence.\\n3. Start the **Live loop** before the first source edit. Run\\n `npx --no-install weaver dev ` in a long-lived background session and\\n keep its output available and its widget visible to the user. Return to\\n authoring once the command reports that it is watching. Keep observing the\\n Live loop for the next 10 seconds while authoring continues. Report the\\n user-facing live view as available only if that interval ends without a\\n `weaver dev ERROR` presentation-health diagnostic. Rebuilds and hot swaps can\\n finish while later edits continue. If the current platform cannot run\\n Weaver's desktop host or presentation health fails, record the exact failure,\\n use the Render loop, and report the user-facing live view as unavailable.\\n4. Build the first coherent visual slice in `/widget.tsx` with one literal\\n default export:\\n `export default widget({ ... }, () => <... />);`. Import Weaver APIs from\\n `@weaver/sdk`; keep other modules, assets, and their licenses inside the\\n widget source root.\\n5. Enter the **Render loop** as soon as that slice can render. Run it before\\n building the rest of the widget, then after each edit that can change pixels,\\n semantics, or interaction behavior. No such edit is complete until its PNG\\n has been opened and inspected.\\n6. After the final source save, keep the **Live loop** running until it reports\\n that save through `weaver dev bundle ready for in-place hot swap` or\\n `weaver dev restarted widget: window config changed`. An `OUT OF DATE`\\n message keeps this step open until the source is fixed and `weaver dev`\\n reports that it caught up. Then keep the process running when the user wants\\n the final widget left open. Otherwise, stop it. Use Render loop artifacts for\\n every visual, semantic, and interaction receipt.\\n7. Report the widget path, captured images, behavior exercised, receipt evidence,\\n whether the user-facing live view ran or its exact failure, and each remaining\\n boundary. Completion requires the requested result, not merely successful\\n commands.\\n\\n## Render loop\\n\\nFor each defined state:\\n\\n1. Run `npx --no-install weaver check ` until it exits successfully. Fix\\n every named widget error. Preserve unsupported intent as a reported boundary\\n rather than suppressing unknown utilities, undeclared providers or origins,\\n invalid assets, or import failures.\\n2. Run `npx --no-install weaver capture --out .png` with the\\n state's fixed clock, semantic actions, provider fixture, or session journal.\\n3. Open the PNG with the available image-viewing tool. File creation and a green\\n receipt are not visual proof. Inspect layout, overlap, clipping, duplication,\\n spacing, alignment, contrast, assets, and the requested state at the actual\\n widget dimensions.\\n4. Inspect `.snapshot.txt` and `.receipt.json`. The\\n receipt must have `status: \\\"ok\\\"`; the semantic tree must expose the intended\\n content and controls; every warning and pending item must be understood.\\n5. Compare the rendered state with the request. Fix the visible and semantic\\n mismatches found in that pass, then restart the loop. For interactions, prove\\n both the initial state and every requested post-action state.\\n\\n## Contract routing\\n\\n[`sdk/CONTRACT.md`](../../../sdk/CONTRACT.md) is authoritative and chronological;\\nlater amendments supersede earlier scheduling notes. Read only the headings the\\nwidget needs:\\n\\n- For module shape, literal config, hooks, and reload behavior, read **Module\\n shape**, **`widget(config, component)`**, **Hooks**, and **Hot swap**.\\n- For the current element and class set, read **Consolidated v0.4 authoring\\n tables**. Read **Bundled fonts**, **Icons**, and the matching styling amendment\\n when those branches apply.\\n- For buttons, sliders, press coordinates, or interaction styles, read **PR 11:\\n native interaction states and press events**. Use native `hover:` and\\n `pressed:` classes for visual feedback instead of rendering pointer state\\n through JavaScript.\\n- For fetch, storage, CPU, or memory, read the matching M2 heading. For canvas,\\n audio, media observation, artwork, or transport, read the matching M3 or\\n **Media v2 amendment** heading. Use `fps=\\\"display\\\"` for fluid canvas motion,\\n a number only for an intentional fixed cadence, and `0` once animation\\n settles.\\n\\nRead the shipped example closest to the request before writing the first\\nelement; they are the house style and each one proves one slice of the\\ncontract on the current runtime:\\n\\n- [`examples/clock`](../../../examples/clock/widget.tsx): `time` provider,\\n layered gradient surface, a canvas that redraws once per render.\\n- [`examples/system`](../../../examples/system/widget.tsx): `cpu` and `memory`\\n providers, provider history in an effect, canvas charts with explicit sizes.\\n- [`examples/pomodoro`](../../../examples/pomodoro/widget.tsx): `useStorage`,\\n `useInterval`, buttons with `hover:`/`pressed:` states, centered labels.\\n- [`examples/now-playing`](../../../examples/now-playing/widget.tsx): `media`\\n provider, conditional artwork, transport capability, click-to-seek.\\n- [`examples/weather`](../../../examples/weather/widget.tsx): declared\\n `origins`, `wfetch` with honest loading and failure states, literal icons\\n chosen per branch.\\n- [`examples/noro-shell`](../../../examples/noro-shell/widget.tsx) and\\n [`examples/visualizer`](../../../examples/visualizer/widget.tsx): bundled\\n fonts, tiled image assets, and an `audio` signal driving a display-rate\\n canvas.\\n\\nUse `weaver check` as the final authority for statically knowable widget errors.\\nDo not infer browser DOM, CSS, package, or network behavior that the contract\\ndoes not provide.\\n\\n## Framework failures\\n\\nA documented unsupported behavior is a widget boundary. A minimized supported\\nwidget that still fails is a framework reproduction. So is invalid widget input\\nthat produces an opaque or internal error instead of an actionable diagnostic.\\nPreserve the widget, exact command, complete output, and platform. Inside the\\nWeaver source checkout, follow the root instructions for framework friction.\\nOutside it, report the reproduction and blocker without weakening the widget or\\nclaiming completion.\\n1:# @weaver/sdk \u2014 public API contract (v0.2 \u2014 M1 surface + the M2 amendment at the end)\\n20:## Module shape\\n43:## `widget(config, component)`\\n46:export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n74:## Hooks\\n115:## Hot swap\\n121:## Elements (JSX intrinsics)\\n138:## `class` utilities (M1 set)\\n198:### Gradient backgrounds\\n247:### Bundled fonts\\n269:### Icons\\n292:## CLI\\n305:## The conjure skill\\n312:## v0 done-condition (unchanged)\\n320:# M3 amendment (v0.3)\\n322:## `` \u2014 immediate mode (the ADR 0009 exception)\\n354:## Providers: `audio` and `media` (host-fed)\\n374:# M2 amendment (v0.2)\\n378:## Interactive elements (were \\\"arrives in M2\\\")\\n391:## `weaver.fetch` \u2014 the declared-origins network (ADR 0002)\\n410:## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n413:function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n419:## Providers: `cpu` and `memory` (host-fed)\\n437:## The host and its CLI verbs\\n459:# Styling breadth amendment (v0.4)\\n464:## PR 01: spacing and sizing\\n488:## PR 02: flex completeness\\n506:## PR 09: overlay stacks and bounded overflow\\n524:## PR 10: image fitting, rounded masks, and tiling\\n538:## PR 11: native interaction states and press events\\n593:## Consolidated v0.4 authoring tables\\n633:# Media v2 amendment (v0.5)\\n638:## PR 01: playback status and source application\\n679:## PR 02: album art and dynamic image sources\\n738:## PR 03: media transport capability\\n825:## PR 05: noro acceptance surface\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:48:08.895Z", + "call_id": "call_KtigcUemo92EfOoh52ZFhr3A", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f35009\",\"wall_time_seconds\":0.000003959,\"exit_code\":0,\"original_token_count\":7036,\"output\":\"## Module shape\\n\\n```tsx\\nimport { widget, useProvider, useState } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n```\\n\\n## `widget(config, component)`\\n\\n```ts\\nexport function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule;\\n\\nexport interface WidgetConfig {\\n name: string;\\n size: [width: number, height: number]; // logical px\\n anchor?: {\\n monitor?: \\\"primary\\\"; // M1: primary only\\n corner: \\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\";\\n offset?: [x: number, y: number]; // default [24, 24]\\n };\\n layer?: \\\"desktop\\\" | \\\"normal\\\" | \\\"topmost\\\"; // default \\\"desktop\\\"\\n clickThrough?: boolean; // default false\\n subscribe?: (\\\"time\\\")[]; // M1: \\\"time\\\" only; full list M2\\n origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2\\n capabilities?: never[]; // M1: must be empty; ladder arrives M2\\n}\\n```\\n\\n`weaver check` validates config statically (it is extracted from the default\\nexport at bundle time; config must be a literal object \u2014 no computed values).\\n\\n`anchor` is the widget's placement until the user drags it. Every widget is\\ndraggable by its whole surface (buttons and sliders keep their interactions);\\nthe dragged position is user state stored outside the widget \u2014 it survives\\nrestarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it\\ngoes stale (e.g. its monitor was unplugged). Widget code cannot read or write\\nit (ADR 0016).\\n\\n## Hooks\\n\\n```ts\\nexport function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void];\\nexport function useRef(initial: T): { current: T };\\nexport function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;\\nexport function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned\\nexport function useProvider(name: \\\"time\\\"): TimeData; // M1: \\\"time\\\" only\\nexport function useProviderSignal(name: \\\"time\\\"): Signal;\\n\\nexport interface Signal {\\n readonly value: T;\\n subscribe(listener: (value: T) => void): () => void;\\n map(project: (value: T) => U): Signal;\\n}\\n\\nexport interface TimeData { // updates once per second while subscribed\\n hh: string; mm: string; ss: string; // zero-padded locale-agnostic\\n weekday: string; month: string; // short names (\\\"Sun\\\", \\\"Jul\\\")\\n day: number; year: number;\\n epochMs: number;\\n}\\n```\\n\\nRules: hooks follow React's rules (top level, stable order). `useProvider`\\nrequires the provider in `config.subscribe` \u2014 checked at `weaver check`,\\nerror: `useProvider(\\\"time\\\") requires subscribe: [\\\"time\\\"] in the widget config`.\\n`useProviderSignal` carries the same requirement and names the hook in its\\nerror: `useProviderSignal(\\\"audio\\\") requires subscribe: [\\\"audio\\\"] in the widget\\nconfig`.\\n\\n`useProvider` is the declarative path: each value schedules a component render.\\n`useProviderSignal` is the high-frequency retained path: it updates `.value`\\nwithout rendering the component. A canvas samples `.value` inside `onFrame`.\\nA `` may contain one mapped signal, which updates only that native text\\nnode; format the whole label in `signal.map(...)`. `subscribe` is for edge\\ntransitions such as waking a paused canvas, not for rebuilding the tree on each\\nprovider frame. `map` memoizes by source signal and projector identity. Define a\\nprojector once outside the component (`const label = signal.map(format)`) so\\nunrelated renders reuse the binding instead of unsubscribing and resubscribing.\\n\\n## `useStorage` \u2014 scoped persistence (quiet standard surface)\\n\\n```ts\\nfunction useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void];\\n```\\n\\nJSON-serializable values only; persisted per widget (survives restarts and\\n`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw.\\n\\n# Styling breadth amendment (v0.4)\\n\\nEverything above stands. This section grows with the numbered styling stack;\\nutilities not yet listed here remain loud `weaver check` errors.\\n\\n## PR 01: spacing and sizing\\n\\nThe scale remains 1 unit = 4 logical px. Bracketed pixel values are accepted\\nwhere shown. Utilities are applied left-to-right; a later utility wins on the\\nsame side or axis. Negative margins are supported; padding and sizes are\\nnon-negative.\\n\\n| Utility | Maps to |\\n|---|---|\\n| `p-N`, `p-[Npx]` | uniform padding |\\n| `px/py/pt/pr/pb/pl-N`, bracketed `Npx` forms | directional padding; side values override uniform padding |\\n| `m/mx/my/mt/mr/mb/ml-N`, bracketed `Npx` forms, optional leading `-` | external per-side margin |\\n| `w-N`, `h-N`, bracketed `Npx` forms | fixed width or height |\\n| `w-full`, `h-full`, `w-A/B`, `h-A/B` | percentage of the parent's content box |\\n| `w-auto`, `h-auto` | clear an earlier size on that axis |\\n| `size-N`, `size-[Npx]`, `size-full` | set both axes together |\\n| `min-w/max-w/min-h/max-h-N`, bracketed `Npx` forms | per-axis size bounds |\\n| `aspect-square`, `aspect-video`, `aspect-[W/H]`, `aspect-[N]` | derive the missing axis when exactly one axis is definite |\\n| `aspect-auto` | clear an earlier aspect ratio |\\n\\nPercentage sizes are calculated from the parent's content box before margins;\\nmin/max bounds then clamp the laid-out frame. `aspect-*` does nothing when both\\naxes are definite or both are automatic.\\n\\n## PR 02: flex completeness\\n\\n| Utility | Maps to |\\n|---|---|\\n| `justify-around`, `justify-evenly` | Tailwind main-axis free-space distribution |\\n| `grow-N`, `grow-[N]` | numeric flex-grow factor (`grow` remains 1) |\\n| `shrink`, `shrink-0` | opt in/out of compression below the preferred size |\\n| `self-auto/start/center/end/stretch` | per-child cross-axis alignment |\\n| `flex-wrap`, `flex-nowrap` | enable/disable row or column line wrapping |\\n\\nWeaver elements default to `shrink: 1`, matching Tailwind. When preferred\\nsizes overflow a line, eligible children give up space in proportion to their\\navailable shrink capacity (preferred size minus min-size floor); `shrink-0`\\nchildren never compress. If all floors still exceed the container, overflow\\nremains explicit and the Native debug diagnostic fires. Wrapped lines use the\\ncontainer's `gap` on both axes. `items-baseline` remains an end-alignment\\napproximation; true font baseline layout is outside this styling slice.\\n\\n## PR 09: overlay stacks and bounded overflow\\n\\n`` is the overlay sibling of `` and ``. Every child starts\\nat the stack's content-box origin, paints in child order, and uses its own\\nwidth, height, margin, and alignment utilities. Overlay composition therefore\\nuses ordinary child utilities such as `w-full h-full`; there is no positioned\\nlayout API.\\n\\n| Utility | Maps to |\\n|---|---|\\n| `overflow-hidden` | clip descendant painting to this element's resolved rounded bounds |\\n\\nThe clip applies to canvases, images, text, panels, and nested content.\\nPer-corner `rounded-*` utilities shape the mask, including asymmetric corners.\\nThis is the intended way to give a canvas-backed visual rounded edges. An\\nopacity ancestor remains unsupported for ``; apply that opacity while\\ndrawing the canvas instead.\\n\\n## PR 11: native interaction states and press events\\n\\n`hover:` and `pressed:` are supported only for the five native-swappable\\nvisual channels below. Every other state-prefixed utility is a loud\\n`weaver check` error naming these supported forms.\\n\\n| Utility | Native override |\\n|---|---|\\n| `hover:bg-`, `pressed:bg-` | background color |\\n| `hover:text-`, `pressed:text-` | foreground/text color |\\n| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0\u2013100) |\\n| `hover:border-`, `pressed:border-` | border color; border width remains the base style |\\n| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` |\\n\\nNamed Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same\\nforms and values as their unprefixed counterparts. Overrides inherit every\\nbase channel they do not name. Pressed wins over hover when both native states\\nare active; disabled elements use the base style. Swaps use retained native\\nstate and its existing invalidation path: no JS callback, timer, polling, or\\nper-frame work is introduced. The earlier M2 note that hover styling was\\nunscheduled is superseded by this bounded surface.\\n\\nOn a non-pressable node, `hover:` and `pressed:` utilities resolve against\\nthe nearest pressable ancestor (`\\n```\\n\\n`onPress` remains required on `\\n );\\n };\\n\\n return (\\n \\n \\n {headings[timer.mode]}\\n {minutes[timer.mode]} MIN\\n \\n\\n \\n drawRing(ctx, timer.remaining / total, color)} />\\n \\n {clock(timer.remaining)}\\n \\n {timer.remaining === 0 ? \\\"DONE\\\" : timer.running ? \\\"RUNNING\\\" : \\\"PAUSED\\\"}\\n \\n \\n \\n\\n \\n {chip(\\\"focus\\\", \\\"Focus\\\")}\\n {chip(\\\"short\\\", \\\"Short break\\\")}\\n {chip(\\\"long\\\", \\\"Long break\\\")}\\n \\n\\n \\n setTimer((current) => ({\\n ...current,\\n remaining: current.remaining === 0 ? total : current.remaining,\\n running: !current.running,\\n }))}\\n >\\n \\n {timer.running ? \\\"Pause\\\" : \\\"Start\\\"}\\n \\n \\n select(timer.mode)}\\n >\\n \\n \\n \\n \\n );\\n});\\nimport { useProvider, widget, type CanvasCtx, type TimeData } from \\\"@weaver/sdk\\\";\\n\\n// The first widget: one provider, one canvas, no timers of its own.\\n// The `time` provider ticks once per second while subscribed; each tick\\n// re-renders the text nodes and redraws the dial. Nothing else runs.\\n\\nconst weekdays: Record = {\\n Sun: \\\"Sunday\\\", Mon: \\\"Monday\\\", Tue: \\\"Tuesday\\\", Wed: \\\"Wednesday\\\",\\n Thu: \\\"Thursday\\\", Fri: \\\"Friday\\\", Sat: \\\"Saturday\\\",\\n};\\nconst months: Record = {\\n Jan: \\\"January\\\", Feb: \\\"February\\\", Mar: \\\"March\\\", Apr: \\\"April\\\", May: \\\"May\\\", Jun: \\\"June\\\",\\n Jul: \\\"July\\\", Aug: \\\"August\\\", Sep: \\\"September\\\", Oct: \\\"October\\\", Nov: \\\"November\\\", Dec: \\\"December\\\",\\n};\\n\\nfunction longDate(time: TimeData): string {\\n return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`;\\n}\\n\\n// Draws a small analog dial. Runs once per render (no `fps`), so it costs\\n// nothing between provider ticks.\\nfunction drawDial(ctx: CanvasCtx, time: TimeData): void {\\n ctx.clear();\\n const cx = ctx.width / 2;\\n const cy = ctx.height / 2;\\n const radius = Math.min(cx, cy) - 2;\\n const hours = Number(time.hh) % 12;\\n const minutes = Number(time.mm);\\n const seconds = Number(time.ss);\\n\\n for (let index = 0; index < 12; index += 1) {\\n const angle = (index / 12) * Math.PI * 2 - Math.PI / 2;\\n const outer = radius;\\n const inner = index % 3 === 0 ? radius - 7 : radius - 4;\\n ctx.line(\\n cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner,\\n cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer,\\n index % 3 === 0 ? 2 : 1, index % 3 === 0 ? \\\"#ffffffb3\\\" : \\\"#ffffff4d\\\",\\n );\\n }\\n\\n const hand = (turns: number, length: number, width: number, color: string) => {\\n const angle = turns * Math.PI * 2 - Math.PI / 2;\\n ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color);\\n };\\n hand((hours + minutes / 60) / 12, radius * 0.52, 3, \\\"#f5f6f8\\\");\\n hand((minutes + seconds / 60) / 60, radius * 0.78, 2, \\\"#f5f6f8\\\");\\n hand(seconds / 60, radius * 0.86, 1, \\\"#f59e0b\\\");\\n ctx.fillCircle(cx, cy, 3, \\\"#f59e0b\\\");\\n}\\n\\nexport default widget({\\n name: \\\"Clock\\\",\\n size: [320, 132],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {longDate(time)}\\n \\n drawDial(ctx, time)} />\\n \\n );\\n});\\n# Agent widget capture\\n\\n`weaver capture` renders a checked widget without opening a desktop window or\\nstarting Weaver's host, registry, provider daemon, or development loop. It is\\nthe deterministic inspection path for agents, tests, and CI:\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/clock --out /tmp/clock.png\\n```\\n\\nA successful run publishes three files together:\\n\\n- `/tmp/clock.png` \u2014 pixels from Native SDK's reference renderer.\\n- `/tmp/clock.snapshot.txt` \u2014 the semantic tree used by automation.\\n- `/tmp/clock.receipt.json` \u2014 provenance, renderer counters, pending work,\\n measured timings, input hashes, and warnings.\\n\\nStandard output is exactly one compact `weaver.capture.v1` receipt. Diagnostics\\ngo to standard error. A failed run also emits one error receipt, exits nonzero,\\nand does not publish a partial artifact set. If widget execution falls back to\\nits runtime error surface during an action or replay, capture reports\\n`CaptureWidgetFailed` instead of treating those error pixels as a successful\\nwidget render. The widget's own diagnostic (the thrown message and stack, or\\nthe unhandled rejection) travels with that failure: the receipt carries it as\\n`error.diagnostic` and standard error prints it on a `diagnostic:` line, so the\\ncapture output alone names what to fix.\\n\\nCapture uses a fresh temporary data, storage, geometry, log, and artwork root.\\nIt neither reads nor changes the live widget state. The clock starts at the ISO\\ninstant recorded in `inputs.clock`; pass `--clock ` when a capture\\nmust reproduce exactly. Time advances only through an action or a replayed\\nsession. No arbitrary wait is used to decide that rendering is done.\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/clock \\\\\\n --clock 2026-08-24T17:30:00.000Z \\\\\\n --out /tmp/clock.png\\n```\\n\\n## Semantic actions\\n\\nPass `--action-file ` to drive the ordinary automation dispatcher after\\nthe initial frame. Targets use semantic role and accessible name, not retained\\nnode IDs or screen coordinates:\\n\\n```json\\n{\\n \\\"schema\\\": \\\"weaver.capture.actions.v1\\\",\\n \\\"actions\\\": [\\n {\\n \\\"action\\\": \\\"click\\\",\\n \\\"target\\\": { \\\"role\\\": \\\"button\\\", \\\"name\\\": \\\"Start\\\" }\\n },\\n { \\\"action\\\": \\\"advance-clock\\\", \\\"milliseconds\\\": 1000 }\\n ]\\n}\\n```\\n\\nSupported actions are `click`, `drag`, `wheel`, `text`, `key`, `action`,\\n`context-menu`, `resize`, and `advance-clock`. A target may match `role`,\\n`name`, `enabled`, `selected`, and `value`; `role` or `name` is required and\\nthe match must be unique. `drag` takes normalized `from` and `to` values.\\n`advance-clock` drives eligible Weaver timers synchronously through the null\\nplatform, then renders any frame the widget actually requests.\\n\\n`useStorage` keeps its production 200 ms write coalescing, but capture uses an\\nisolated storage root and a runtime-owned capture-mode capability to persist\\nthose writes immediately. A writable widget clock cannot enable that path. An\\ninteraction that only changes stored state therefore needs no artificial\\n`advance-clock`; `pending.timers` continues to report timers created by widget\\nbehavior.\\n\\nExamples live in [`test/capture`](../test/capture):\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/pomodoro \\\\\\n --action-file test/capture/pomodoro.actions \\\\\\n --out /tmp/pomodoro.png\\n\\nnode cli/bin/weaver.js capture test/fixtures/styling-interaction \\\\\\n --action-file test/capture/styling-interaction.actions \\\\\\n --out /tmp/styling-interaction.png\\n```\\n\\n## Provider fixtures\\n\\nCapture never connects to a live provider endpoint. A widget subscribed to\\n`cpu`, `memory`, `audio`, or `media` must receive explicit recorded input with\\n`--provider-fixture `. Every subscribed non-time provider must appear in\\nthe fixture and undeclared providers are rejected.\\n\\n```json\\n{\\n \\\"schema\\\": \\\"weaver.provider-fixture.v1\\\",\\n \\\"frames\\\": [\\n {\\n \\\"provider\\\": \\\"media\\\",\\n \\\"value\\\": {\\n \\\"title\\\": \\\"Capture Proof\\\",\\n \\\"artist\\\": \\\"Weaver\\\",\\n \\\"status\\\": \\\"playing\\\",\\n \\\"playing\\\": true,\\n \\\"positionMs\\\": 42000,\\n \\\"durationMs\\\": 180000\\n }\\n }\\n ]\\n}\\n```\\n\\nFrames enter through the same provider dispatch path as live host frames. The\\nfixture file's SHA-256 is recorded in the receipt:\\n\\n```sh\\nnode cli/bin/weaver.js capture examples/noro-shell \\\\\\n --provider-fixture test/capture/noro.provider.json \\\\\\n --out /tmp/noro.png\\n```\\n\\n## Session journals\\n\\n`--session-journal ` replays an existing Native SDK session journal with\\nverification enabled and captures its final retained state. A journal and an\\naction file are alternative event sources and cannot be supplied together.\\nThe journal hash is recorded in the receipt.\\n\\n## Reading the receipt\\n\\nTreat `status`, `error`, and `pending` as the decision surface. `renderer`\\nreports the retained revision, driven frames, command and semantic-node counts,\\nregistered images and fonts, and the number of pixels that differ from the\\nsurface clear color. A successful but visibly empty widget therefore has an\\nexplicit receipt instead of relying on a screenshot guess. `pending` reports\\ntimers, fetches, unresolved images, providers, and real queued frame requests;\\nthe capture command does not hide them by sleeping or by imposing a guessed\\ntimeout.\\n\\n`provenance` records the Weaver and Native SDK commits plus the exact bundled\\nJavaScript hash. A dirty checkout is allowed but is called out in `warnings`.\\n\\nAfter building the runtime, run the repository acceptance corpus with\\n`npm run test:capture`. It checks non-flat pixels, semantic state changes,\\nprovider failure and fixture behavior, ambiguous-target candidates, artifact\\npublication, and byte-identical fixed-clock session replay.\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"bd3408\",\"wall_time_seconds\":0.300576,\"exit_code\":0,\"original_token_count\":24,\"output\":\"Initialized /tmp/weaver-exp-astra/runs/C4\\nNext: weaver check '/tmp/weaver-exp-astra/runs/C4'\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:48:31.926Z", + "call_id": "call_EjeAywKOSGYPSfk950P2RfPT", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.5 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"a33792\",\"wall_time_seconds\":0.000006875,\"exit_code\":0,\"original_token_count\":149,\"output\":\"import { useProvider, widget } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"C4\\\",\\n size: [240, 110],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n {time.hh}:{time.mm}\\n {time.ss}\\n \\n {time.weekday}, {time.month} {time.day}\\n \\n );\\n});\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"79af47\",\"wall_time_seconds\":0.576613083,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"c9ff49\",\"wall_time_seconds\":0.576323458,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"24a9f46fca43852663b51a999b9c265ecdf102b7626c68cbe8c94637dfebfa14\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/01-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/01-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":4,\\\"nodes\\\":5,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":327075,\\\"spawn\\\":75730,\\\"startup\\\":44786,\\\"render\\\":1002,\\\"encode\\\":514,\\\"write\\\":637,\\\"total\\\":459383},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:48:40.475Z", + "call_id": "call_umhjfB9Mpti843ayigBQcsON", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.0 seconds\nOutput:\n" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f20c0b\",\"wall_time_seconds\":0.000003958,\"exit_code\":0,\"original_token_count\":1402,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=46285000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=21322 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=4 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=2 canvas_frame_encoder_commands=29 canvas_frame_encoder_cache_actions=22 canvas_frame_encoder_pipeline_binds=2 canvas_frame_encoder_draws=2 canvas_frame_pipelines=2 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=2 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=2 canvas_frame_uploads=0 canvas_frame_retains=2 canvas_frame_evicts=0 canvas_frame_effects=0 canvas_frame_shadows=0 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=0 canvas_frame_effect_evicts=0 canvas_frame_glyphs=16 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=16 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=4 canvas_frame_gpu_packet_cache_actions=22 canvas_frame_gpu_packet_cached_resources=2 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=5/1024 widget_semantics=5/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=120 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=5 widget_semantics=5 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,18 91.01953x20) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(249.73633,20.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"24a9f46fca43852663b51a999b9c265ecdf102b7626c68cbe8c94637dfebfa14\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/01-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/01-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 4,\\n \\\"nodes\\\": 5,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 327075,\\n \\\"spawn\\\": 75730,\\n \\\"startup\\\": 44786,\\n \\\"render\\\": 1002,\\n \\\"encode\\\": 514,\\n \\\"write\\\": 637,\\n \\\"total\\\": 459383\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:49:01.960Z", + "call_id": "call_LOxD5Ox9V9ckx5ttBvkUu9Up", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.6 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"68539d\",\"wall_time_seconds\":0.681307458,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"456f74\",\"wall_time_seconds\":0.530101917,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"589cb9940fe4cf5add1f414190485729486da5c43b4848988fc11ee4b5552fa2\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/02-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/02-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":4,\\\"nodes\\\":5,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":299806,\\\"spawn\\\":52810,\\\"startup\\\":38553,\\\"render\\\":1060,\\\"encode\\\":488,\\\"write\\\":267,\\\"total\\\":410051},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"21b2d9\",\"wall_time_seconds\":0.000002625,\"exit_code\":0,\"original_token_count\":1403,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40085000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=23269 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=4 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=2 canvas_frame_encoder_commands=29 canvas_frame_encoder_cache_actions=22 canvas_frame_encoder_pipeline_binds=2 canvas_frame_encoder_draws=2 canvas_frame_pipelines=2 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=2 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=2 canvas_frame_uploads=0 canvas_frame_retains=2 canvas_frame_evicts=0 canvas_frame_effects=0 canvas_frame_shadows=0 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=0 canvas_frame_effect_evicts=0 canvas_frame_glyphs=16 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=16 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=4 canvas_frame_gpu_packet_cache_actions=22 canvas_frame_gpu_packet_cached_resources=2 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=5/1024 widget_semantics=5/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=120 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=5 widget_semantics=5 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"589cb9940fe4cf5add1f414190485729486da5c43b4848988fc11ee4b5552fa2\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/02-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/02-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 4,\\n \\\"nodes\\\": 5,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 299806,\\n \\\"spawn\\\": 52810,\\n \\\"startup\\\": 38553,\\n \\\"render\\\": 1060,\\n \\\"encode\\\": 488,\\n \\\"write\\\": 267,\\n \\\"total\\\": 410051\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:49:28.386Z", + "call_id": "call_z4LTKnjN69dfSd4ShypMc0Ck", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.6 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"d52fb3\",\"wall_time_seconds\":0.670913542,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f13bbd\",\"wall_time_seconds\":0.561963959,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"a21e5745f80ba0dba409bd15f61973348374cc5b906e74c83de8a0da04e138f6\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/03-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/03-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":32,\\\"nodes\\\":34,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":335126,\\\"spawn\\\":52725,\\\"startup\\\":38990,\\\"render\\\":1464,\\\"encode\\\":483,\\\"write\\\":287,\\\"total\\\":438080},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"9cc6dc\",\"wall_time_seconds\":0.00001225,\"exit_code\":0,\"original_token_count\":2561,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40911000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=23449 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=32 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=16 canvas_frame_encoder_commands=91 canvas_frame_encoder_cache_actions=56 canvas_frame_encoder_pipeline_binds=16 canvas_frame_encoder_draws=16 canvas_frame_pipelines=2 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=2 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=16 canvas_frame_uploads=0 canvas_frame_retains=16 canvas_frame_evicts=0 canvas_frame_effects=0 canvas_frame_shadows=0 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=0 canvas_frame_effect_evicts=0 canvas_frame_glyphs=22 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=22 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=16 canvas_frame_text_lines=16 canvas_frame_text_uploads=0 canvas_frame_text_retains=16 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=32 canvas_frame_gpu_packet_cache_actions=56 canvas_frame_gpu_packet_cached_resources=16 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=34/1024 widget_semantics=34/1024 context_menu_items=0/512 text_layout_plans=16/2048 text_layout_lines=16/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=312 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=34 widget_semantics=34 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"a21e5745f80ba0dba409bd15f61973348374cc5b906e74c83de8a0da04e138f6\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/03-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/03-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 32,\\n \\\"nodes\\\": 34,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 335126,\\n \\\"spawn\\\": 52725,\\n \\\"startup\\\": 38990,\\n \\\"render\\\": 1464,\\n \\\"encode\\\": 483,\\n \\\"write\\\": 287,\\n \\\"total\\\": 438080\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:49:50.014Z", + "call_id": "call_tIt5RBe0oL6x5dY80hpS3fGE", + "output": [ + { + "type": "input_text", + "text": "Script failed\nWall time 1.4 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"5b005b\",\"wall_time_seconds\":0.619080792,\"exit_code\":1,\"original_token_count\":42,\"output\":\"weaver failed (1 error)\\n- /tmp/weaver-exp-astra/runs/C4/widget.tsx:36:18: class must resolve to at most 32 literal strings so weaver check can validate every utility\\n\"}" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"7f6e96\",\"wall_time_seconds\":0.417439334,\"exit_code\":1,\"original_token_count\":346,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"error\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/04-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/04-initial.snapshot.txt\\\",\\\"widthPx\\\":0,\\\"heightPx\\\":0,\\\"scale\\\":1,\\\"pngBytes\\\":0},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[],\\\"framesDriven\\\":0,\\\"retainedRevision\\\":0,\\\"commands\\\":0,\\\"nodes\\\":0,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":0},\\\"pending\\\":{\\\"timers\\\":0,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":0,\\\"spawn\\\":0,\\\"startup\\\":0,\\\"render\\\":0,\\\"encode\\\":0,\\\"write\\\":0,\\\"total\\\":293157},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[],\\\"error\\\":{\\\"name\\\":\\\"CaptureFailed\\\",\\\"ask\\\":\\\"/tmp/weaver-exp-astra/runs/C4/widget.tsx:36:18: class must resolve to at most 32 literal strings so weaver check can validate every utility\\\",\\\"remedy\\\":\\\"fix the named failure, then rerun the same capture command\\\"}}\\nweaver capture failed: CaptureFailed: /tmp/weaver-exp-astra/runs/C4/widget.tsx:36:18: class must resolve to at most 32 literal strings so weaver check can validate every utility\\nremedy: fix the named failure, then rerun the same capture command\\n\"}" + }, + { + "type": "input_text", + "text": "Script error:\nunable to locate image at `/tmp/weaver-exp-astra/runs/C4/captures/04-initial.png`: No such file or directory (os error 2)" + } + ] + }, + { + "timestamp": "2026-09-05T15:49:55.103Z", + "call_id": "call_4gOEnqwTnaHWzGMtKVFeW15G", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"29ae8e\",\"wall_time_seconds\":0.000004625,\"exit_code\":0,\"original_token_count\":406,\"output\":\"## `` \u2014 immediate mode (the ADR 0009 exception)\\n\\n```tsx\\n { \u2026 }} />\\n```\\n\\n```ts\\ninterface CanvasFrame { t: number; dt: number } // seconds\\ntype CanvasFrameRate = number | \\\"display\\\";\\ninterface CanvasCtx {\\n width: number; height: number; // logical px\\n clear(color?: string): void; // default: transparent\\n fillRect(x: number, y: number, w: number, h: number, color: string): void;\\n fillRoundRect(x: number, y: number, w: number, h: number, r: number, color: string): void;\\n fillCircle(cx: number, cy: number, r: number, color: string): void;\\n line(x1: number, y1: number, x2: number, y2: number, width: number, color: string): void;\\n polyline(points: number[], width: number, color: string): void; // flat x,y pairs\\n}\\n```\\n\\n- `fps=\\\"display\\\"` draws once per native surface frame, matching a 60 Hz or\\n high-refresh display without guessing its rate. This is the default choice\\n for fluid visualizers: `fps={active ? \\\"display\\\" : 0}`.\\n- A positive numeric `fps` requests a fixed lower cadence and remains capped\\n at 60 for compatibility. `fps={0}` pauses the frame clock entirely (0% cost)\\n while keeping the last frame on screen; omitted draws once per React render.\\n- `onFrame` runs on the selected native clock; commands batch into one\\n immediate-mode buffer per frame. Colors are `#rgb/#rrggbb/#rrggbbaa`.\\n- A canvas with `fps=\\\"display\\\"` or `fps > 0` is an *animated* widget and is\\n billed accordingly (ADR 0005); everything outside the canvas stays\\n retained/idle-zero.\\n\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:50:10.899Z", + "call_id": "call_6tijk9R4pYW9t6rXBZ6hvdGB", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.8 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"b435c0\",\"wall_time_seconds\":0.636075708,\"exit_code\":1,\"original_token_count\":86,\"output\":\"weaver failed (1 error)\\n- /tmp/weaver-exp-astra/runs/C4/widget.tsx:35:17: CanvasNeedsExplicitSize: has a percentage width. A canvas has no intrinsic size, so inside a content-sized container a percentage resolves against 0 and every draw silently no-ops (ctx.width === 0). Fix: give the canvas an explicit pixel width, e.g. w-[312px].\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:50:18.872Z", + "call_id": "call_ss3h9Hncll12auk0OTTel0sN", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.7 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"79fe69\",\"wall_time_seconds\":0.577850084,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:50:32.852Z", + "call_id": "call_PpiMlnpiVo3GdBXNTGijGhwc", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"d8bd05\",\"wall_time_seconds\":0.778904625,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"59e4796164108667c0507fe6b9209cd2d705b441af1a394bb148ee515c13f7b1\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/05-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/05-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":37,\\\"nodes\\\":39,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":361190,\\\"spawn\\\":60068,\\\"startup\\\":44435,\\\"render\\\":1614,\\\"encode\\\":519,\\\"write\\\":658,\\\"total\\\":476869},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"551863\",\"wall_time_seconds\":0.000003083,\"exit_code\":0,\"original_token_count\":2756,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=46554000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=25573 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=37 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=17 canvas_frame_encoder_commands=108 canvas_frame_encoder_cache_actions=71 canvas_frame_encoder_pipeline_binds=17 canvas_frame_encoder_draws=17 canvas_frame_pipelines=2 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=2 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=18 canvas_frame_uploads=0 canvas_frame_retains=18 canvas_frame_evicts=0 canvas_frame_effects=0 canvas_frame_shadows=0 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=0 canvas_frame_effect_evicts=0 canvas_frame_glyphs=32 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=32 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=18 canvas_frame_text_lines=18 canvas_frame_text_uploads=0 canvas_frame_text_retains=18 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=35 canvas_frame_gpu_packet_cache_actions=71 canvas_frame_gpu_packet_cached_resources=18 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=39/1024 widget_semantics=39/1024 context_menu_items=0/512 text_layout_plans=18/2048 text_layout_lines=18/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=376 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=39 widget_semantics=39 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#14521845296726044339 role=group name=\\\"\\\" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15091253999156092641 role=group name=\\\"\\\" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"Weekly goal\\\" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12445700919989132789 role=text name=\\\"0 / 20\\\" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12567209568093186446 role=group name=\\\"\\\" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"59e4796164108667c0507fe6b9209cd2d705b441af1a394bb148ee515c13f7b1\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/05-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/05-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 37,\\n \\\"nodes\\\": 39,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 361190,\\n \\\"spawn\\\": 60068,\\n \\\"startup\\\": 44435,\\n \\\"render\\\": 1614,\\n \\\"encode\\\": 519,\\n \\\"write\\\": 658,\\n \\\"total\\\": 476869\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:51:02.299Z", + "call_id": "call_ICXIH0EczujDd52wQqtGS7DU", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.8 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"8754cd\",\"wall_time_seconds\":0.668934666,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:51:13.509Z", + "call_id": "call_mfktqWEtRWGcxbxUge6cHSf2", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"65b4c8\",\"wall_time_seconds\":0.75760525,\"exit_code\":0,\"original_token_count\":301,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/06-initial.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/06-initial.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":2,\\\"retainedRevision\\\":1,\\\"commands\\\":44,\\\"nodes\\\":46,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":370200,\\\"spawn\\\":58432,\\\"startup\\\":42467,\\\"render\\\":1756,\\\"encode\\\":483,\\\"write\\\":258,\\\"total\\\":482087},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\"},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"6e395c\",\"wall_time_seconds\":0.000003667,\"exit_code\":0,\"original_token_count\":3039,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=44679000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=27525 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=138 canvas_frame_encoder_cache_actions=91 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=22 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=45 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=91 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=493 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#14521845296726044339 role=group name=\\\"\\\" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15091253999156092641 role=group name=\\\"\\\" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"Weekly goal\\\" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12445700919989132789 role=text name=\\\"0 / 20\\\" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12567209568093186446 role=group name=\\\"\\\" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,154.5 288x28) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#4860165038249741585 role=button name=\\\"Log session\\\" bounds=(16,154.5 172x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press]\\n widget @w1/widget-canvas#7217482369044429682 role=group name=\\\"\\\" bounds=(16,154.5 172x28) focused=false enabled=true parent=#4860165038249741585\\n widget @w1/widget-canvas#2165676007840600680 role=text name=\\\"Log session\\\" bounds=(16,159.75 172x17.5) focused=false enabled=true parent=#7217482369044429682\\n widget @w1/widget-canvas#2238034082661263458 role=button name=\\\"Reset week\\\" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press]\\n widget @w1/widget-canvas#11813601622197617951 role=group name=\\\"\\\" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2238034082661263458\\n widget @w1/widget-canvas#7032127835310027939 role=text name=\\\"Reset week\\\" bounds=(196,159.75 108x17.5) focused=false enabled=true parent=#11813601622197617951\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/06-initial.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/06-initial.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 2,\\n \\\"retainedRevision\\\": 1,\\n \\\"commands\\\": 44,\\n \\\"nodes\\\": 46,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 370200,\\n \\\"spawn\\\": 58432,\\n \\\"startup\\\": 42467,\\n \\\"render\\\": 1756,\\n \\\"encode\\\": 483,\\n \\\"write\\\": 258,\\n \\\"total\\\": 482087\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\"\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:51:19.523Z", + "call_id": "call_znSEYpmxYSbzxwphfB5Ounmq", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.6 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"e67829\",\"wall_time_seconds\":0.442419292,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:51:31.500Z", + "call_id": "call_dS0JdBwObRcjIjEJ5WcgYJCS", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"405e6e\",\"wall_time_seconds\":0.749310167,\"exit_code\":0,\"original_token_count\":343,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":5,\\\"retainedRevision\\\":4,\\\"commands\\\":45,\\\"nodes\\\":46,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":362570,\\\"spawn\\\":56986,\\\"startup\\\":33876,\\\"render\\\":1803,\\\"encode\\\":492,\\\"write\\\":221,\\\"total\\\":468644},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\",\\\"actionFileSha256\\\":\\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"},\\\"interactions\\\":{\\\"actions\\\":[\\\"click\\\",\\\"click\\\",\\\"click\\\"],\\\"mediaCommands\\\":[]},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"7ec0f6\",\"wall_time_seconds\":0.000003875,\"exit_code\":0,\"original_token_count\":3106,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=44983000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=27693 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623491423344000 gpu_input_latency_ns=2905000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=45 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=149 canvas_frame_encoder_cache_actions=102 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=22 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=47 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=50 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=102 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=520 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"3\\\" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#14521845296726044339 role=group name=\\\"\\\" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15091253999156092641 role=group name=\\\"\\\" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"Weekly goal\\\" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12445700919989132789 role=text name=\\\"3 / 20\\\" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12567209568093186446 role=group name=\\\"\\\" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,154.5 288x28) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#4860165038249741585 role=button name=\\\"Log session\\\" bounds=(16,154.5 172x28) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press]\\n widget @w1/widget-canvas#7217482369044429682 role=group name=\\\"\\\" bounds=(16,154.5 172x28) focused=false enabled=true parent=#4860165038249741585\\n widget @w1/widget-canvas#2165676007840600680 role=text name=\\\"Log session\\\" bounds=(16,159.75 172x17.5) focused=false enabled=true parent=#7217482369044429682\\n widget @w1/widget-canvas#2238034082661263458 role=button name=\\\"Reset week\\\" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press]\\n widget @w1/widget-canvas#11813601622197617951 role=group name=\\\"\\\" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2238034082661263458\\n widget @w1/widget-canvas#7032127835310027939 role=text name=\\\"Reset week\\\" bounds=(196,159.75 108x17.5) focused=false enabled=true parent=#11813601622197617951\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 5,\\n \\\"retainedRevision\\\": 4,\\n \\\"commands\\\": 45,\\n \\\"nodes\\\": 46,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 362570,\\n \\\"spawn\\\": 56986,\\n \\\"startup\\\": 33876,\\n \\\"render\\\": 1803,\\n \\\"encode\\\": 492,\\n \\\"write\\\": 221,\\n \\\"total\\\": 468644\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\",\\n \\\"actionFileSha256\\\": \\\"06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77\\\"\\n },\\n \\\"interactions\\\": {\\n \\\"actions\\\": [\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\"\\n ],\\n \\\"mediaCommands\\\": []\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:51:45.102Z", + "call_id": "call_xftdccrtHc0qzB3inRujyP6a", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.8 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"59c667\",\"wall_time_seconds\":0.666706875,\"exit_code\":0,\"original_token_count\":13,\"output\":\"weaver check passed: /tmp/weaver-exp-astra/runs/C4\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:52:05.774Z", + "call_id": "call_txsUDTUGj0hkvWrjGWhayEN0", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 1.0 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"6754cc\",\"wall_time_seconds\":0.764940166,\"exit_code\":0,\"original_token_count\":345,\"output\":\"{\\\"schema\\\":\\\"weaver.capture.v1\\\",\\\"status\\\":\\\"ok\\\",\\\"provenance\\\":{\\\"weaverCommit\\\":\\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\\"nativeSdkCommit\\\":\\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\\"bundleSha256\\\":\\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\\"platform\\\":\\\"darwin-headless-coretext\\\"},\\\"output\\\":{\\\"image\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.png\\\",\\\"snapshot\\\":\\\"/tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.snapshot.txt\\\",\\\"widthPx\\\":320,\\\"heightPx\\\":200,\\\"scale\\\":1,\\\"pngBytes\\\":256283},\\\"renderer\\\":{\\\"pixels\\\":\\\"reference\\\",\\\"textMeasurement\\\":\\\"coretext\\\",\\\"eventsDriven\\\":[\\\"app_start\\\",\\\"appearance_changed\\\",\\\"surface_resized\\\",\\\"window_frame_changed\\\",\\\"gpu_surface_resized\\\",\\\"gpu_surface_frame\\\",\\\"app_shutdown\\\"],\\\"framesDriven\\\":6,\\\"retainedRevision\\\":5,\\\"commands\\\":44,\\\"nodes\\\":46,\\\"images\\\":0,\\\"fonts\\\":0,\\\"pixelsDifferentFromClear\\\":63572},\\\"pending\\\":{\\\"timers\\\":1,\\\"fetches\\\":0,\\\"images\\\":0,\\\"providers\\\":[],\\\"frameRequests\\\":0},\\\"timingUs\\\":{\\\"bundle\\\":359461,\\\"spawn\\\":65615,\\\"startup\\\":38349,\\\"render\\\":1727,\\\"encode\\\":497,\\\"write\\\":310,\\\"total\\\":473359},\\\"inputs\\\":{\\\"clock\\\":\\\"2026-09-04T09:41:00.000Z\\\",\\\"storage\\\":\\\"isolated-empty\\\",\\\"actionFileSha256\\\":\\\"2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0\\\"},\\\"interactions\\\":{\\\"actions\\\":[\\\"click\\\",\\\"click\\\",\\\"click\\\",\\\"click\\\"],\\\"mediaCommands\\\":[]},\\\"warnings\\\":[\\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"]}\\n\"}" + }, + { + "type": "input_image", + "omitted": "Non-text tool artifact; agent capture files are archived separately." + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"f68298\",\"wall_time_seconds\":0.000001375,\"exit_code\":0,\"original_token_count\":3110,\"output\":\"ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=52205000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=29635 markup_watch=off\\nwindow @w1 \\\"Focus Week\\\" bounds=(0,0 320x200) focused=true frame=0 commands=0\\n view @w1/widget-canvas kind=gpu_surface role=\\\"Weaver widget canvas\\\" accessibility_label=\\\"Focus Week\\\" text=\\\"Weaver widget canvas\\\" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=6 gpu_timestamp_ns=84333335 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623525697816000 gpu_input_latency_ns=2767000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command=\\\"\\\" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=5 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=149 canvas_frame_encoder_cache_actions=102 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=22 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=50 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=102 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=515 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=10 widget_nodes=46 widget_semantics=46 widget_cursor=arrow\\n widget @w1/widget-canvas#6194227322212544528 role=group name=\\\"\\\" bounds=(0,0 320x200) focused=false enabled=true\\n widget @w1/widget-canvas#8989280229327462431 role=group name=\\\"\\\" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528\\n widget @w1/widget-canvas#17141410367181492475 role=group name=\\\"\\\" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#16282996836656487105 role=text name=\\\"Focus week\\\" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#7085508171825967427 role=text name=\\\"Fri, Sep 4\\\" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475\\n widget @w1/widget-canvas#10162277730996300551 role=group name=\\\"\\\" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15080105495274655534 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#14348414673741379304 role=group name=\\\"\\\" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534\\n widget @w1/widget-canvas#15095474804485896871 role=text name=\\\"M\\\" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#5036925338709116941 role=text name=\\\"0\\\" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304\\n widget @w1/widget-canvas#12556696334436056940 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#3815727781268906353 role=group name=\\\"\\\" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940\\n widget @w1/widget-canvas#16579326942085127115 role=text name=\\\"T\\\" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7946296496768470956 role=text name=\\\"0\\\" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353\\n widget @w1/widget-canvas#7597821939212968695 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9425647543182277583 role=group name=\\\"\\\" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695\\n widget @w1/widget-canvas#11248424745687431576 role=text name=\\\"W\\\" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#15686864919909977529 role=text name=\\\"0\\\" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583\\n widget @w1/widget-canvas#7296780229786415153 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#9271565681298391461 role=group name=\\\"\\\" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153\\n widget @w1/widget-canvas#7285692155281014087 role=text name=\\\"T\\\" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#802649812111143556 role=text name=\\\"0\\\" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461\\n widget @w1/widget-canvas#1102249205766815737 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#6754876511232257284 role=group name=\\\"\\\" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737\\n widget @w1/widget-canvas#1147135667572071714 role=text name=\\\"F\\\" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#1591004126705514636 role=text name=\\\"0\\\" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284\\n widget @w1/widget-canvas#9608914897307801018 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#2454825294539352308 role=group name=\\\"\\\" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018\\n widget @w1/widget-canvas#16294110544623668557 role=text name=\\\"S\\\" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#8022720664598915415 role=text name=\\\"0\\\" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308\\n widget @w1/widget-canvas#10997492118612647209 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551\\n widget @w1/widget-canvas#5379490745807977887 role=group name=\\\"\\\" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209\\n widget @w1/widget-canvas#13826355370529843847 role=text name=\\\"S\\\" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#17764601967149365852 role=text name=\\\"0\\\" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887\\n widget @w1/widget-canvas#14521845296726044339 role=group name=\\\"\\\" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#15091253999156092641 role=group name=\\\"\\\" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#15729049687520163901 role=text name=\\\"Weekly goal\\\" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12445700919989132789 role=text name=\\\"0 / 20\\\" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641\\n widget @w1/widget-canvas#12567209568093186446 role=group name=\\\"\\\" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339\\n widget @w1/widget-canvas#2479990500450380282 role=group name=\\\"\\\" bounds=(16,154.5 288x28) focused=false enabled=true parent=#8989280229327462431\\n widget @w1/widget-canvas#4860165038249741585 role=button name=\\\"Log session\\\" bounds=(16,154.5 172x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press]\\n widget @w1/widget-canvas#7217482369044429682 role=group name=\\\"\\\" bounds=(16,154.5 172x28) focused=false enabled=true parent=#4860165038249741585\\n widget @w1/widget-canvas#2165676007840600680 role=text name=\\\"Log session\\\" bounds=(16,159.75 172x17.5) focused=false enabled=true parent=#7217482369044429682\\n widget @w1/widget-canvas#2238034082661263458 role=button name=\\\"Reset week\\\" bounds=(196,154.5 108x28) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press]\\n widget @w1/widget-canvas#11813601622197617951 role=group name=\\\"\\\" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2238034082661263458\\n widget @w1/widget-canvas#7032127835310027939 role=text name=\\\"Reset week\\\" bounds=(196,159.75 108x17.5) focused=false enabled=true parent=#11813601622197617951\\n{\\n \\\"schema\\\": \\\"weaver.capture.v1\\\",\\n \\\"status\\\": \\\"ok\\\",\\n \\\"provenance\\\": {\\n \\\"weaverCommit\\\": \\\"ab20771762be56faff04173ab11a5525a8d89be5\\\",\\n \\\"nativeSdkCommit\\\": \\\"464ff65faa02d36179b34e2252fa2a1cf46f7541\\\",\\n \\\"bundleSha256\\\": \\\"b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0\\\",\\n \\\"platform\\\": \\\"darwin-headless-coretext\\\"\\n },\\n \\\"output\\\": {\\n \\\"image\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.png\\\",\\n \\\"snapshot\\\": \\\"/tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.snapshot.txt\\\",\\n \\\"widthPx\\\": 320,\\n \\\"heightPx\\\": 200,\\n \\\"scale\\\": 1,\\n \\\"pngBytes\\\": 256283\\n },\\n \\\"renderer\\\": {\\n \\\"pixels\\\": \\\"reference\\\",\\n \\\"textMeasurement\\\": \\\"coretext\\\",\\n \\\"eventsDriven\\\": [\\n \\\"app_start\\\",\\n \\\"appearance_changed\\\",\\n \\\"surface_resized\\\",\\n \\\"window_frame_changed\\\",\\n \\\"gpu_surface_resized\\\",\\n \\\"gpu_surface_frame\\\",\\n \\\"app_shutdown\\\"\\n ],\\n \\\"framesDriven\\\": 6,\\n \\\"retainedRevision\\\": 5,\\n \\\"commands\\\": 44,\\n \\\"nodes\\\": 46,\\n \\\"images\\\": 0,\\n \\\"fonts\\\": 0,\\n \\\"pixelsDifferentFromClear\\\": 63572\\n },\\n \\\"pending\\\": {\\n \\\"timers\\\": 1,\\n \\\"fetches\\\": 0,\\n \\\"images\\\": 0,\\n \\\"providers\\\": [],\\n \\\"frameRequests\\\": 0\\n },\\n \\\"timingUs\\\": {\\n \\\"bundle\\\": 359461,\\n \\\"spawn\\\": 65615,\\n \\\"startup\\\": 38349,\\n \\\"render\\\": 1727,\\n \\\"encode\\\": 497,\\n \\\"write\\\": 310,\\n \\\"total\\\": 473359\\n },\\n \\\"inputs\\\": {\\n \\\"clock\\\": \\\"2026-09-04T09:41:00.000Z\\\",\\n \\\"storage\\\": \\\"isolated-empty\\\",\\n \\\"actionFileSha256\\\": \\\"2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0\\\"\\n },\\n \\\"interactions\\\": {\\n \\\"actions\\\": [\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\",\\n \\\"click\\\"\\n ],\\n \\\"mediaCommands\\\": []\\n },\\n \\\"warnings\\\": [\\n \\\"Weaver working tree contains uncommitted changes; provenance names the checkout commit.\\\"\\n ]\\n}\\n\"}" + } + ] + }, + { + "timestamp": "2026-09-05T15:52:41.519Z", + "call_id": "call_YxtMUBTWvfiImGRK8RYukaJi", + "output": [ + { + "type": "input_text", + "text": "Script completed\nWall time 0.1 seconds\nOutput:\n" + }, + { + "type": "input_text", + "text": "{\"chunk_id\":\"274238\",\"wall_time_seconds\":0.000004875,\"exit_code\":0,\"original_token_count\":0,\"output\":\"\"}" + } + ] + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/C4-usage.json b/experiments/render-loop-cadence/astra/evidence/C4-usage.json new file mode 100644 index 00000000..c735d22d --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/C4-usage.json @@ -0,0 +1,604 @@ +{ + "run": "C4", + "thread": { + "id": "01a07240-fd9a-7030-9a5b-8faf50b49740", + "rollout_path": "/Users/dara/.codex/sessions/2026/09/05/rollout-2026-09-05T11-47-37-01a07240-fd9a-7030-9a5b-8faf50b49740.jsonl", + "created_at": 1788623256, + "agent_path": "/root/astra_c4", + "model": "gpt-6-astra", + "reasoning_effort": "high", + "tokens_used": 866114 + }, + "dispatch_utc": "2026-09-05T15:47:28.105174+00:00", + "harness_start_utc": "2026-09-05T15:47:37.100Z", + "completion_utc": "2026-09-05T15:52:53.110Z", + "usage_timestamp": "2026-09-05T15:52:53.105Z", + "total_token_usage": { + "input_tokens": 860944, + "cached_input_tokens": 813952, + "cache_write_input_tokens": 0, + "output_tokens": 5170, + "reasoning_output_tokens": 298, + "total_tokens": 866114 + }, + "tool_call_counts": { + "exec": 19 + }, + "tool_calls": [ + { + "timestamp": "2026-09-05T15:47:48.100Z", + "type": "custom_tool_call", + "call_id": "call_XXjBSmT734JmVunTe8nqWWBC", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/prompts/C4.md\",max_output_tokens:12000}));\n" + }, + { + "timestamp": "2026-09-05T15:47:58.318Z", + "type": "custom_tool_call", + "call_id": "call_6Hxo83QoAdfwyLHT7RuCfaWw", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat .agents/skills/conjure-widget/SKILL.md && rg -n '^#+ .*|Module shape|widget\\\\(config|useStorage|PR 11|Consolidated v0.4' sdk/CONTRACT.md\",max_output_tokens:18000}));\n" + }, + { + "timestamp": "2026-09-05T15:48:08.364Z", + "type": "custom_tool_call", + "call_id": "call_KtigcUemo92EfOoh52ZFhr3A", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"sed -n '20,114p' sdk/CONTRACT.md; sed -n '410,418p' sdk/CONTRACT.md; sed -n '459,523p' sdk/CONTRACT.md; sed -n '538,632p' sdk/CONTRACT.md; cat examples/pomodoro/widget.tsx examples/clock/widget.tsx docs/agent-widget-capture.md\",max_output_tokens:18000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver init /tmp/weaver-exp-astra/runs/C4\",yield_time_ms:10000,max_output_tokens:2000}));\n" + }, + { + "timestamp": "2026-09-05T15:48:30.377Z", + "type": "custom_tool_call", + "call_id": "call_EjeAywKOSGYPSfk950P2RfPT", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/widget.tsx\",max_output_tokens:2000}));\ntext(await tools.exec_command({cmd:\"mkdir -p /tmp/weaver-exp-astra/runs/C4/captures\\ncp /tmp/weaver-exp-astra/clicks.actions /tmp/weaver-exp-astra/runs/C4/clicks.actions\\ncat > /tmp/weaver-exp-astra/runs/C4/widget.tsx <<'EOF'\\nimport { useProvider, widget } from \\\"@weaver/sdk\\\";\\n\\nexport default widget({\\n name: \\\"Focus Week\\\",\\n size: [320, 200],\\n anchor: { corner: \\\"top-right\\\", offset: [24, 24] },\\n subscribe: [\\\"time\\\"],\\n}, () => {\\n const time = useProvider(\\\"time\\\");\\n return (\\n \\n \\n Focus week\\n {time.weekday}, {time.month} {time.day}\\n \\n \\n );\\n});\\nEOF\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:2000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/01-initial.png\",yield_time_ms:10000,max_output_tokens:2500}));\n" + }, + { + "timestamp": "2026-09-05T15:48:40.412Z", + "type": "custom_tool_call", + "call_id": "call_umhjfB9Mpti843ayigBQcsON", + "name": "exec", + "input": "image((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/01-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/01-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/01-initial.receipt.json\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:49:00.368Z", + "type": "custom_tool_call", + "call_id": "call_LOxD5Ox9V9ckx5ttBvkUu9Up", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\\ns=open(p).read().replace('text-[16px] font-semibold', 'text-[14px] font-semibold').replace('text-[12px] text-[#f5f6f8]/65','text-[14px] text-[#f5f6f8]/65')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/02-initial.png\",max_output_tokens:1500}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/02-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/02-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/02-initial.receipt.json\",max_output_tokens:3000}));\n" + }, + { + "timestamp": "2026-09-05T15:49:26.755Z", + "type": "custom_tool_call", + "call_id": "call_z4LTKnjN69dfSd4ShypMc0Ck", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\\ns=open(p).read().replace('\\\\nexport default', '\\\\nconst weekdays = [\\\"Mon\\\", \\\"Tue\\\", \\\"Wed\\\", \\\"Thu\\\", \\\"Fri\\\", \\\"Sat\\\", \\\"Sun\\\"];\\\\nconst letters = [\\\"M\\\", \\\"T\\\", \\\"W\\\", \\\"T\\\", \\\"F\\\", \\\"S\\\", \\\"S\\\"];\\\\n\\\\nexport default')\\ns=s.replace(' \\\\n ', ''' \\n \\n {weekdays.map((day, index) => (\\n \\n {letters[index]}\\n 0\\n \\n ))}\\n \\n ''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/03-initial.png\",max_output_tokens:1500}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/03-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/03-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/03-initial.receipt.json\",max_output_tokens:5000}));\n" + }, + { + "timestamp": "2026-09-05T15:49:48.624Z", + "type": "custom_tool_call", + "call_id": "call_tIt5RBe0oL6x5dY80hpS3fGE", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\\ns=open(p).read().replace(' const time = useProvider(\\\"time\\\");', ' const time = useProvider(\\\"time\\\");\\\\n const total = 0;')\\ns=s.replace(' \\\\n );', ''' \\n \\n Weekly goal\\n {total} / 20\\n \\n \\n \\n \\n \\n \\n );''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\ntext(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/04-initial.png\",max_output_tokens:1500}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/04-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/04-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/04-initial.receipt.json\",max_output_tokens:5500}));\n" + }, + { + "timestamp": "2026-09-05T15:49:55.030Z", + "type": "custom_tool_call", + "call_id": "call_4gOEnqwTnaHWzGMtKVFeW15G", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"sed -n '322,353p' sdk/CONTRACT.md\",max_output_tokens:2500}));\n" + }, + { + "timestamp": "2026-09-05T15:50:10.079Z", + "type": "custom_tool_call", + "call_id": "call_6tijk9R4pYW9t6rXBZ6hvdGB", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\\ns=open(p).read().replace(''' \\n \\n ''', ''' {\\n ctx.clear();\\n ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, \\\"#ffffff1a\\\");\\n if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, \\\"#5eead4\\\");\\n }} />''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:50:18.106Z", + "type": "custom_tool_call", + "call_id": "call_ss3h9Hncll12auk0OTTel0sN", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\np='/tmp/weaver-exp-astra/runs/C4/widget.tsx'\\ns=open(p).read().replace('>(\\\"sessions-by-weekday\\\", emptyWeek);\\\\n const total = weekdays.reduce((sum, day) => sum + counts[day], 0);')\\ns=s.replace('text-[#f5f6f8]\\\">0', 'text-[#f5f6f8]\\\">{counts[day]}')\\ns=s.replace(' \\\\n );', ''' \\n \\n \\n \\n \\n );''')\\nopen(p,'w').write(s)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:51:12.521Z", + "type": "custom_tool_call", + "call_id": "call_mfktqWEtRWGcxbxUge6cHSf2", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/06-initial.png\",max_output_tokens:1500}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/06-initial.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/06-initial.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/06-initial.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:51:18.898Z", + "type": "custom_tool_call", + "call_id": "call_znSEYpmxYSbzxwphfB5Ounmq", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:51:30.518Z", + "type": "custom_tool_call", + "call_id": "call_dS0JdBwObRcjIjEJ5WcgYJCS", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/clicks.actions --out /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.png\",max_output_tokens:1600}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/07-after-clicks.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:51:44.258Z", + "type": "custom_tool_call", + "call_id": "call_xftdccrtHc0qzB3inRujyP6a", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"python3 - <<'PY'\\nimport json\\np='/tmp/weaver-exp-astra/runs/C4/'\\na=json.load(open(p+'clicks.actions'))\\na['actions'].append({'action':'click','target':{'role':'button','name':'Reset week'}})\\njson.dump(a,open(p+'reset.actions','w'),indent=2)\\nPY\\nnpx --no-install weaver check /tmp/weaver-exp-astra/runs/C4\",max_output_tokens:1000}));\n" + }, + { + "timestamp": "2026-09-05T15:52:04.771Z", + "type": "custom_tool_call", + "call_id": "call_txsUDTUGj0hkvWrjGWhayEN0", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/reset.actions --out /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.png\",max_output_tokens:1600}));\nimage((await tools.view_image({path:\"/tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.png\"})).image_url);\ntext(await tools.exec_command({cmd:\"cat /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.snapshot.txt /tmp/weaver-exp-astra/runs/C4/captures/08-after-reset.receipt.json\",max_output_tokens:6500}));\n" + }, + { + "timestamp": "2026-09-05T15:52:41.415Z", + "type": "custom_tool_call", + "call_id": "call_YxtMUBTWvfiImGRK8RYukaJi", + "name": "exec", + "input": "text(await tools.exec_command({cmd:\"cat > /tmp/weaver-exp-astra/runs/C4/REPORT.md <<'EOF'\\n# Focus Week report\\n\\n- Condition: C (progressive capture).\\n- `weaver check` runs: 9 (7 passed, 2 failed with actionable authoring diagnostics; final check passed).\\n- `weaver capture` runs: 8 (7 successful, 1 failed before rendering).\\n- Confidence: 9 / 10.\\n\\n## Defects fixed because of pixels or snapshots\\n\\n- Slice 1: the original 16px title and 12px date had different vertical text metrics in capture 01. Changed both to 14px, retaining the title's semibold weight. Capture 02 confirms matching y=20.5 and height=17.5 text bounds and visually aligned text.\\n\\n## Evidence\\n\\n- Slice 1: captures 01 and 02, frame and header.\\n- Slice 2: capture 03, seven equal-width weekday cells (37.714287px each), Friday highlighted, all counts zero.\\n- Slice 3: capture 05, goal label above the bar with a clear gap. Capture attempt 04 failed static validation of a computed class and produced no artifacts. Replaced the computed class with the documented canvas drawing API, then fixed its width to the measured 288px content width after the checker rejected percentage canvas sizing.\\n- Slice 4: capture 06, full initial widget. Capture 07, three Log session clicks: Friday 3, all other days 0, label 3 / 20, bar 15% (43.2 / 288px).\\n- Additional interaction: capture 08, three Log session clicks followed by Reset week: all seven counts zero, label 0 / 20, empty bar.\\n- Opened and inspected every successful PNG at 320x200, read every semantic snapshot and receipt. All successful receipts have status `ok`. Both exact button names appear in semantics. Both buttons have native hover and pressed classes; post-action captures show their hover feedback.\\n- Counts use `useStorage` with a JSON object keyed Mon through Sun. Restart persistence relies on that documented SDK contract; capture deliberately uses fresh isolated storage each run.\\n- Receipts report the pre-existing dirty repository warning. No repository files were modified. One pending timer is consistent with the time subscription; no fetches, images, other providers, or pending frame requests appear.\\n- No live view was started, as the task explicitly forbids `weaver dev`.\\n\\n## Unmet spec items\\n\\nNone identified. No automatic calendar-week rollover was added; Reset week explicitly clears the stored weekday counts as requested.\\nEOF\",max_output_tokens:1000}));\n" + } + ], + "token_usage_events": [ + { + "timestamp": "2026-09-05T15:47:48.175Z", + "info": { + "total_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "last_token_usage": { + "input_tokens": 19203, + "cached_input_tokens": 18944, + "cache_write_input_tokens": 0, + "output_tokens": 39, + "reasoning_output_tokens": 0, + "total_tokens": 19242 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:47:58.393Z", + "info": { + "total_token_usage": { + "input_tokens": 39862, + "cached_input_tokens": 38016, + "cache_write_input_tokens": 0, + "output_tokens": 165, + "reasoning_output_tokens": 15, + "total_tokens": 40027 + }, + "last_token_usage": { + "input_tokens": 20659, + "cached_input_tokens": 19072, + "cache_write_input_tokens": 0, + "output_tokens": 126, + "reasoning_output_tokens": 15, + "total_tokens": 20785 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:48:08.895Z", + "info": { + "total_token_usage": { + "input_tokens": 62993, + "cached_input_tokens": 58496, + "cache_write_input_tokens": 0, + "output_tokens": 313, + "reasoning_output_tokens": 15, + "total_tokens": 63306 + }, + "last_token_usage": { + "input_tokens": 23131, + "cached_input_tokens": 20480, + "cache_write_input_tokens": 0, + "output_tokens": 148, + "reasoning_output_tokens": 0, + "total_tokens": 23279 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:48:31.927Z", + "info": { + "total_token_usage": { + "input_tokens": 94507, + "cached_input_tokens": 81408, + "cache_write_input_tokens": 0, + "output_tokens": 770, + "reasoning_output_tokens": 15, + "total_tokens": 95277 + }, + "last_token_usage": { + "input_tokens": 31514, + "cached_input_tokens": 22912, + "cache_write_input_tokens": 0, + "output_tokens": 457, + "reasoning_output_tokens": 0, + "total_tokens": 31971 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:48:40.476Z", + "info": { + "total_token_usage": { + "input_tokens": 127216, + "cached_input_tokens": 112768, + "cache_write_input_tokens": 0, + "output_tokens": 871, + "reasoning_output_tokens": 15, + "total_tokens": 128087 + }, + "last_token_usage": { + "input_tokens": 32709, + "cached_input_tokens": 31360, + "cache_write_input_tokens": 0, + "output_tokens": 101, + "reasoning_output_tokens": 0, + "total_tokens": 32810 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:49:01.961Z", + "info": { + "total_token_usage": { + "input_tokens": 161823, + "cached_input_tokens": 145280, + "cache_write_input_tokens": 0, + "output_tokens": 1258, + "reasoning_output_tokens": 95, + "total_tokens": 163081 + }, + "last_token_usage": { + "input_tokens": 34607, + "cached_input_tokens": 32512, + "cache_write_input_tokens": 0, + "output_tokens": 387, + "reasoning_output_tokens": 80, + "total_tokens": 34994 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:49:28.391Z", + "info": { + "total_token_usage": { + "input_tokens": 199013, + "cached_input_tokens": 179840, + "cache_write_input_tokens": 0, + "output_tokens": 1865, + "reasoning_output_tokens": 103, + "total_tokens": 200878 + }, + "last_token_usage": { + "input_tokens": 37190, + "cached_input_tokens": 34560, + "cache_write_input_tokens": 0, + "output_tokens": 607, + "reasoning_output_tokens": 8, + "total_tokens": 37797 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:49:50.014Z", + "info": { + "total_token_usage": { + "input_tokens": 240577, + "cached_input_tokens": 216960, + "cache_write_input_tokens": 0, + "output_tokens": 2338, + "reasoning_output_tokens": 103, + "total_tokens": 242915 + }, + "last_token_usage": { + "input_tokens": 41564, + "cached_input_tokens": 37120, + "cache_write_input_tokens": 0, + "output_tokens": 473, + "reasoning_output_tokens": 0, + "total_tokens": 42037 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:49:55.103Z", + "info": { + "total_token_usage": { + "input_tokens": 283214, + "cached_input_tokens": 258432, + "cache_write_input_tokens": 0, + "output_tokens": 2405, + "reasoning_output_tokens": 128, + "total_tokens": 285619 + }, + "last_token_usage": { + "input_tokens": 42637, + "cached_input_tokens": 41472, + "cache_write_input_tokens": 0, + "output_tokens": 67, + "reasoning_output_tokens": 25, + "total_tokens": 42704 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:50:10.899Z", + "info": { + "total_token_usage": { + "input_tokens": 326440, + "cached_input_tokens": 301056, + "cache_write_input_tokens": 0, + "output_tokens": 2727, + "reasoning_output_tokens": 140, + "total_tokens": 329167 + }, + "last_token_usage": { + "input_tokens": 43226, + "cached_input_tokens": 42624, + "cache_write_input_tokens": 0, + "output_tokens": 322, + "reasoning_output_tokens": 12, + "total_tokens": 43548 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:50:18.872Z", + "info": { + "total_token_usage": { + "input_tokens": 370138, + "cached_input_tokens": 344192, + "cache_write_input_tokens": 0, + "output_tokens": 2844, + "reasoning_output_tokens": 140, + "total_tokens": 372982 + }, + "last_token_usage": { + "input_tokens": 43698, + "cached_input_tokens": 43136, + "cache_write_input_tokens": 0, + "output_tokens": 117, + "reasoning_output_tokens": 0, + "total_tokens": 43815 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:50:32.853Z", + "info": { + "total_token_usage": { + "input_tokens": 414025, + "cached_input_tokens": 387840, + "cache_write_input_tokens": 0, + "output_tokens": 3019, + "reasoning_output_tokens": 140, + "total_tokens": 417044 + }, + "last_token_usage": { + "input_tokens": 43887, + "cached_input_tokens": 43648, + "cache_write_input_tokens": 0, + "output_tokens": 175, + "reasoning_output_tokens": 0, + "total_tokens": 44062 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:51:02.299Z", + "info": { + "total_token_usage": { + "input_tokens": 462097, + "cached_input_tokens": 431616, + "cache_write_input_tokens": 0, + "output_tokens": 3658, + "reasoning_output_tokens": 225, + "total_tokens": 465755 + }, + "last_token_usage": { + "input_tokens": 48072, + "cached_input_tokens": 43776, + "cache_write_input_tokens": 0, + "output_tokens": 639, + "reasoning_output_tokens": 85, + "total_tokens": 48711 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:51:13.510Z", + "info": { + "total_token_usage": { + "input_tokens": 510880, + "cached_input_tokens": 479616, + "cache_write_input_tokens": 0, + "output_tokens": 3833, + "reasoning_output_tokens": 225, + "total_tokens": 514713 + }, + "last_token_usage": { + "input_tokens": 48783, + "cached_input_tokens": 48000, + "cache_write_input_tokens": 0, + "output_tokens": 175, + "reasoning_output_tokens": 0, + "total_tokens": 48958 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:51:19.523Z", + "info": { + "total_token_usage": { + "input_tokens": 564161, + "cached_input_tokens": 528256, + "cache_write_input_tokens": 0, + "output_tokens": 3878, + "reasoning_output_tokens": 225, + "total_tokens": 568039 + }, + "last_token_usage": { + "input_tokens": 53281, + "cached_input_tokens": 48640, + "cache_write_input_tokens": 0, + "output_tokens": 45, + "reasoning_output_tokens": 0, + "total_tokens": 53326 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:51:31.501Z", + "info": { + "total_token_usage": { + "input_tokens": 617559, + "cached_input_tokens": 581504, + "cache_write_input_tokens": 0, + "output_tokens": 4075, + "reasoning_output_tokens": 225, + "total_tokens": 621634 + }, + "last_token_usage": { + "input_tokens": 53398, + "cached_input_tokens": 53248, + "cache_write_input_tokens": 0, + "output_tokens": 197, + "reasoning_output_tokens": 0, + "total_tokens": 53595 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:51:45.102Z", + "info": { + "total_token_usage": { + "input_tokens": 675650, + "cached_input_tokens": 634752, + "cache_write_input_tokens": 0, + "output_tokens": 4275, + "reasoning_output_tokens": 238, + "total_tokens": 679925 + }, + "last_token_usage": { + "input_tokens": 58091, + "cached_input_tokens": 53248, + "cache_write_input_tokens": 0, + "output_tokens": 200, + "reasoning_output_tokens": 13, + "total_tokens": 58291 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:52:05.775Z", + "info": { + "total_token_usage": { + "input_tokens": 734013, + "cached_input_tokens": 692736, + "cache_write_input_tokens": 0, + "output_tokens": 4466, + "reasoning_output_tokens": 238, + "total_tokens": 738479 + }, + "last_token_usage": { + "input_tokens": 58363, + "cached_input_tokens": 57984, + "cache_write_input_tokens": 0, + "output_tokens": 191, + "reasoning_output_tokens": 0, + "total_tokens": 58554 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:52:41.519Z", + "info": { + "total_token_usage": { + "input_tokens": 797125, + "cached_input_tokens": 750976, + "cache_write_input_tokens": 0, + "output_tokens": 5118, + "reasoning_output_tokens": 298, + "total_tokens": 802243 + }, + "last_token_usage": { + "input_tokens": 63112, + "cached_input_tokens": 58240, + "cache_write_input_tokens": 0, + "output_tokens": 652, + "reasoning_output_tokens": 60, + "total_tokens": 63764 + }, + "model_context_window": 258400 + } + }, + { + "timestamp": "2026-09-05T15:52:53.105Z", + "info": { + "total_token_usage": { + "input_tokens": 860944, + "cached_input_tokens": 813952, + "cache_write_input_tokens": 0, + "output_tokens": 5170, + "reasoning_output_tokens": 298, + "total_tokens": 866114 + }, + "last_token_usage": { + "input_tokens": 63819, + "cached_input_tokens": 62976, + "cache_write_input_tokens": 0, + "output_tokens": 52, + "reasoning_output_tokens": 0, + "total_tokens": 63871 + }, + "model_context_window": 258400 + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/evidence/artifact-sha256.json b/experiments/render-loop-cadence/astra/evidence/artifact-sha256.json new file mode 100644 index 00000000..5b706993 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/artifact-sha256.json @@ -0,0 +1,530 @@ +{ + "runs/A1/REPORT.md": "5357b84e0ddabef4db879e86f9a12504a449bfb9dc9fd7d23cf8974819321d43", + "runs/A1/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/A1/widget.tsx": "c6a87be53dfe29ab461036e1bbf369abc17c257306ebef14d6b618433927ce18", + "runs/A2/REPORT.md": "50a4a12f9f914f7222073e92d059233c1a4e1981410ff0408754a590b890ae5f", + "runs/A2/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/A2/widget.tsx": "114dee45fbaeb5f335ef5ed09071a1aea057d3d2edc57fa9677cc5140cbceb3c", + "runs/B1/REPORT.md": "fea48c0ed2486065574a96e39fdeb4e8676c9dfee3b8a78f9e1662c7a1f7bfbd", + "runs/B1/captures/01-initial.png": "c1eb2f9513c62d9b3b60e425a473486707ac6b1c3ad32d54002c0760fb4836ee", + "runs/B1/captures/01-initial.receipt.json": "c301883b0b6a59bd5581d2a017f401f0b30d79ec006fd86878431dafbf43dabf", + "runs/B1/captures/01-initial.snapshot.txt": "6947542f0db48cf33e773f77dd4274f8d85712f9d531256283a0f5a4e55210c6", + "runs/B1/captures/02-after-clicks.png": "7bdf1017823669fef1cb05e98d7af60c4adba57fe6f073dd1b98c94e226777cb", + "runs/B1/captures/02-after-clicks.receipt.json": "3673eda03af7ba72adfc5704f26e1ac2c4eec5711048cde2a26609c7a2149fe6", + "runs/B1/captures/02-after-clicks.snapshot.txt": "47473f4d92848783994103e62a0b6e0a488595fd375dce3a07fe2cfc9773cf32", + "runs/B1/captures/03-initial.png": "577a28b6c84ef2f978cde1f5c24ad398bbc194e327edce13b02574a69db6795b", + "runs/B1/captures/03-initial.receipt.json": "80d29c9a7aac84824ac797c71d2db5580970cb96df70027c1d0fd3e4b795966c", + "runs/B1/captures/03-initial.snapshot.txt": "8f602769b9eca21bf5e472c1dba0ab51c3babf78f6d91761deff10f55ec6dc34", + "runs/B1/captures/04-after-clicks.png": "1def36ef31771d7e8f4aec4029fc213108a5fd87650755c33c309189955ead8a", + "runs/B1/captures/04-after-clicks.receipt.json": "281502a364bff1e54878d9501db2a79378047c119815a1c524c8074dd239fb09", + "runs/B1/captures/04-after-clicks.snapshot.txt": "4dc2d13c9fcb4c5afca773a9c93163661b5770b6a2097a62af31d470684ae50c", + "runs/B1/captures/05-after-reset.png": "20d12c185c765fc4265d4d456688f2a79e6a5b14bb54f8e45838f25102d4fe5c", + "runs/B1/captures/05-after-reset.receipt.json": "2f7473bd870befda496919da11e1ad3484488197e623961bb33010ccae2cedcc", + "runs/B1/captures/05-after-reset.snapshot.txt": "425fbd283c587fe4d6dc5b1e8e9ae3da10cca7332c41cda0aa12fb4115ca7ae6", + "runs/B1/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B1/dist/bundle.js": "1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42", + "runs/B1/dist/captures/01-initial.png": "c1eb2f9513c62d9b3b60e425a473486707ac6b1c3ad32d54002c0760fb4836ee", + "runs/B1/dist/captures/01-initial.receipt.json": "c301883b0b6a59bd5581d2a017f401f0b30d79ec006fd86878431dafbf43dabf", + "runs/B1/dist/captures/01-initial.snapshot.txt": "6947542f0db48cf33e773f77dd4274f8d85712f9d531256283a0f5a4e55210c6", + "runs/B1/dist/captures/02-after-clicks.png": "7bdf1017823669fef1cb05e98d7af60c4adba57fe6f073dd1b98c94e226777cb", + "runs/B1/dist/captures/02-after-clicks.receipt.json": "3673eda03af7ba72adfc5704f26e1ac2c4eec5711048cde2a26609c7a2149fe6", + "runs/B1/dist/captures/02-after-clicks.snapshot.txt": "47473f4d92848783994103e62a0b6e0a488595fd375dce3a07fe2cfc9773cf32", + "runs/B1/dist/captures/03-initial.png": "577a28b6c84ef2f978cde1f5c24ad398bbc194e327edce13b02574a69db6795b", + "runs/B1/dist/captures/03-initial.receipt.json": "80d29c9a7aac84824ac797c71d2db5580970cb96df70027c1d0fd3e4b795966c", + "runs/B1/dist/captures/03-initial.snapshot.txt": "8f602769b9eca21bf5e472c1dba0ab51c3babf78f6d91761deff10f55ec6dc34", + "runs/B1/dist/captures/04-after-clicks.png": "1def36ef31771d7e8f4aec4029fc213108a5fd87650755c33c309189955ead8a", + "runs/B1/dist/captures/04-after-clicks.receipt.json": "281502a364bff1e54878d9501db2a79378047c119815a1c524c8074dd239fb09", + "runs/B1/dist/captures/04-after-clicks.snapshot.txt": "4dc2d13c9fcb4c5afca773a9c93163661b5770b6a2097a62af31d470684ae50c", + "runs/B1/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B1/dist/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/B1/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/B1/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/B1/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/B1/widget.tsx": "5dd994506d8345bf1ed89c1fcedfa2722e7ccf415f85ce95de54ac34a7baa619", + "runs/B2/REPORT.md": "a77c69993affc87f711e2e2efbd56489ac56651e5a6bb04879cd3bc4f3be62b3", + "runs/B2/captures/01-initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "runs/B2/captures/01-initial.receipt.json": "c2da1eefe9c56beed65eb436c29232d76483318315393e1fa140e0aac9d250c9", + "runs/B2/captures/01-initial.snapshot.txt": "c8dab0a3884914b400f1378cd91224ea7a95eb1abba10754e185ba266766168a", + "runs/B2/captures/02-after-clicks.png": "35f486f776cb3ee78b18aee2b18a10df91c89d5bdecdf28ad97d8359ec03bd17", + "runs/B2/captures/02-after-clicks.receipt.json": "c7fd1dd08c1fd44e51df5a64733d1dab6b2f1fc2c782be1ab04c8b3b2c5d624f", + "runs/B2/captures/02-after-clicks.snapshot.txt": "59d146a62b67596bb8813136c84f7ee6149efae5320ef03b46c395d6e4ea93c4", + "runs/B2/captures/03-initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "runs/B2/captures/03-initial.receipt.json": "5adf6782d6867c177ff28813f54f98ccb6942ec9c484f3adda4d85ea421e4ed9", + "runs/B2/captures/03-initial.snapshot.txt": "f76bfa7e94be6e630f6d409ac3413967787561265aec662a977938ed64367da1", + "runs/B2/captures/04-after-clicks.png": "be359e552a73260dbe41213da3a31879d1a6c243184108ffd5b5166303cb4f5a", + "runs/B2/captures/04-after-clicks.receipt.json": "306986d29ac65a45fb9939f4672cd8bbfc644a73353ebd3ac734e812de54b2d6", + "runs/B2/captures/04-after-clicks.snapshot.txt": "cb2bc2109ad6aa1ed8a1dcc7481b354ec201ea4c2fdcd1b8b3bb1a66eafd7557", + "runs/B2/captures/05-after-reset.png": "35f02a09d94050a170bca1eebc5721f696047f8b5a91dffb701a4714f92e4cf9", + "runs/B2/captures/05-after-reset.receipt.json": "7bb61071131a5384f826ad037328afe4ae267b80c788fe7dd554a61207b1c03d", + "runs/B2/captures/05-after-reset.snapshot.txt": "4641acfe7f4b8db832f74add70cbbf71dc417edeebd34aa51e609c4d4419fbba", + "runs/B2/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B2/dist/bundle.js": "4399f5d2d52aad432f7fc80fef4fe97494cf2eddd1e9b756f02e589df7b1bf66", + "runs/B2/dist/captures/01-initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "runs/B2/dist/captures/01-initial.receipt.json": "c2da1eefe9c56beed65eb436c29232d76483318315393e1fa140e0aac9d250c9", + "runs/B2/dist/captures/01-initial.snapshot.txt": "c8dab0a3884914b400f1378cd91224ea7a95eb1abba10754e185ba266766168a", + "runs/B2/dist/captures/02-after-clicks.png": "35f486f776cb3ee78b18aee2b18a10df91c89d5bdecdf28ad97d8359ec03bd17", + "runs/B2/dist/captures/02-after-clicks.receipt.json": "c7fd1dd08c1fd44e51df5a64733d1dab6b2f1fc2c782be1ab04c8b3b2c5d624f", + "runs/B2/dist/captures/02-after-clicks.snapshot.txt": "59d146a62b67596bb8813136c84f7ee6149efae5320ef03b46c395d6e4ea93c4", + "runs/B2/dist/captures/03-initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "runs/B2/dist/captures/03-initial.receipt.json": "5adf6782d6867c177ff28813f54f98ccb6942ec9c484f3adda4d85ea421e4ed9", + "runs/B2/dist/captures/03-initial.snapshot.txt": "f76bfa7e94be6e630f6d409ac3413967787561265aec662a977938ed64367da1", + "runs/B2/dist/captures/04-after-clicks.png": "be359e552a73260dbe41213da3a31879d1a6c243184108ffd5b5166303cb4f5a", + "runs/B2/dist/captures/04-after-clicks.receipt.json": "306986d29ac65a45fb9939f4672cd8bbfc644a73353ebd3ac734e812de54b2d6", + "runs/B2/dist/captures/04-after-clicks.snapshot.txt": "cb2bc2109ad6aa1ed8a1dcc7481b354ec201ea4c2fdcd1b8b3bb1a66eafd7557", + "runs/B2/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B2/dist/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/B2/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/B2/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/B2/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/B2/widget.tsx": "755a31cf203cffe571a784d725d34aab8e2c564db3c322fbf172eb0c0f91409b", + "runs/B3/REPORT.md": "89adbed7b0f245b0cfa2638781da254a7ff22ad9ae5937c076c9ef55204055fb", + "runs/B3/captures/01-initial.png": "c7dc8a96d669208626a8eaabdd312b0f6a45c85e1c8876483578097bbab8d674", + "runs/B3/captures/01-initial.receipt.json": "933c9895e3a888fc02c9cae228c3ec60c7953e2a769c69f753147befaeb09e1d", + "runs/B3/captures/01-initial.snapshot.txt": "e6531a50619903ff0b3e6e5d478b3f06b2e5f63fb6326159d115563476f60bbb", + "runs/B3/captures/02-after-clicks.png": "6b3c475d509c3a4c9b2f5893b5424348473a6375fcc7b1c219ae94ef85a861f9", + "runs/B3/captures/02-after-clicks.receipt.json": "e005468e8c8bfa85fdcefb5bd1ddba48533bfcd855dfd99a0326da1b301cae19", + "runs/B3/captures/02-after-clicks.snapshot.txt": "5dc92168469ebfe292da174cf76d116b3c225872e3279f2a6dcff0d71472b844", + "runs/B3/captures/03-initial.png": "156c5cdf4ed96faf13eeeb867b31748fcb628e53e433a5dd0b2a446d915e6aa6", + "runs/B3/captures/03-initial.receipt.json": "1224d76b32ce15cb0648f173a51048796fa2fe3e6710fb2189b25acaa870ca7c", + "runs/B3/captures/03-initial.snapshot.txt": "68585f5abf0064bba413f8720ab243fc2a511e43e7179f5b59649d949f335a1c", + "runs/B3/captures/04-after-clicks.png": "a8a24c3a4cb4c05a91fc763bd5942fb11acbb974132835c833f4bfa4dd5cf61a", + "runs/B3/captures/04-after-clicks.receipt.json": "d54dda017c55a3b9ff74a5ecbb04f40212288f96b5c71dfe88c922b48d68002d", + "runs/B3/captures/04-after-clicks.snapshot.txt": "14b2154168ba46209663de20e6dbb4267fec68ba2f47085873efc53c30348b40", + "runs/B3/captures/05-after-reset.png": "49c1ae5bba522a7d7a07569a6137ad6ea1a14138c56f3b7949b440cd984aaa7f", + "runs/B3/captures/05-after-reset.receipt.json": "22c7bf6f2f0f62e08050c171ba12db979b9f802bd0b1d6fd00a888eec21c8566", + "runs/B3/captures/05-after-reset.snapshot.txt": "e24b3f7de2adbee462f84d3da4fd1be36888ea055f70e261e12fbef18c66bef1", + "runs/B3/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B3/dist/bundle.js": "8c24c3be76034c61092ab24bbec5963b465bfa832497b3c3170659c38acdfef2", + "runs/B3/dist/captures/01-initial.png": "c7dc8a96d669208626a8eaabdd312b0f6a45c85e1c8876483578097bbab8d674", + "runs/B3/dist/captures/01-initial.receipt.json": "933c9895e3a888fc02c9cae228c3ec60c7953e2a769c69f753147befaeb09e1d", + "runs/B3/dist/captures/01-initial.snapshot.txt": "e6531a50619903ff0b3e6e5d478b3f06b2e5f63fb6326159d115563476f60bbb", + "runs/B3/dist/captures/02-after-clicks.png": "6b3c475d509c3a4c9b2f5893b5424348473a6375fcc7b1c219ae94ef85a861f9", + "runs/B3/dist/captures/02-after-clicks.receipt.json": "e005468e8c8bfa85fdcefb5bd1ddba48533bfcd855dfd99a0326da1b301cae19", + "runs/B3/dist/captures/02-after-clicks.snapshot.txt": "5dc92168469ebfe292da174cf76d116b3c225872e3279f2a6dcff0d71472b844", + "runs/B3/dist/captures/03-initial.png": "156c5cdf4ed96faf13eeeb867b31748fcb628e53e433a5dd0b2a446d915e6aa6", + "runs/B3/dist/captures/03-initial.receipt.json": "1224d76b32ce15cb0648f173a51048796fa2fe3e6710fb2189b25acaa870ca7c", + "runs/B3/dist/captures/03-initial.snapshot.txt": "68585f5abf0064bba413f8720ab243fc2a511e43e7179f5b59649d949f335a1c", + "runs/B3/dist/captures/04-after-clicks.png": "a8a24c3a4cb4c05a91fc763bd5942fb11acbb974132835c833f4bfa4dd5cf61a", + "runs/B3/dist/captures/04-after-clicks.receipt.json": "d54dda017c55a3b9ff74a5ecbb04f40212288f96b5c71dfe88c922b48d68002d", + "runs/B3/dist/captures/04-after-clicks.snapshot.txt": "14b2154168ba46209663de20e6dbb4267fec68ba2f47085873efc53c30348b40", + "runs/B3/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B3/dist/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/B3/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/B3/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/B3/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/B3/widget.tsx": "75ef381b47dacf6c02d6bdf2c52a7fa44ec08b415ccd0247c65a507d0d6d0cd7", + "runs/B4/REPORT.md": "ee956631dc68ddffa84c632471d28701833e5faa7e2a42fc6e7773e156db3f92", + "runs/B4/captures/01-initial.png": "9ab9a3a1efd063c33d415f5b176f47b9c32b2d020eba9709fd91bab83587d5c7", + "runs/B4/captures/01-initial.receipt.json": "68a98ffc88bc64bf46720a56653ea275c1add4c3d967b65ddbc9119b9d9159cc", + "runs/B4/captures/01-initial.snapshot.txt": "c0e011efcc251cebca6bbe5d9ce9f5656b1ec326465c6856ab7e19b83044ff70", + "runs/B4/captures/02-after-clicks.png": "e570d77e559d91d6675a0a278daa9598a1d2919b3d2ec817c37998b33e57d9d0", + "runs/B4/captures/02-after-clicks.receipt.json": "26422f241282a75835d6ad315859528a95aba3c506f14f7a309cb40811802895", + "runs/B4/captures/02-after-clicks.snapshot.txt": "7483e90a161c5241869710cccc51cf435591762b1eb7474675e71a01a9b0233b", + "runs/B4/captures/03-after-reset.png": "eae90cf06778b37939ef3576312e6ee176d01be97bd1c0ce59f5d0a509b4a109", + "runs/B4/captures/03-after-reset.receipt.json": "c4462e689345ccc308ca869fbf21bf3658309b46faca8ff85a8449d8e3192e84", + "runs/B4/captures/03-after-reset.snapshot.txt": "5bec29d7a48613864b1edd90f7436820b609e5014ef6fc3ed8d3447092dcba58", + "runs/B4/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B4/dist/bundle.js": "85f51bbf3a543213727ed127d8677c63d584f55479034b039192705a1bfa2b35", + "runs/B4/dist/captures/01-initial.png": "9ab9a3a1efd063c33d415f5b176f47b9c32b2d020eba9709fd91bab83587d5c7", + "runs/B4/dist/captures/01-initial.receipt.json": "68a98ffc88bc64bf46720a56653ea275c1add4c3d967b65ddbc9119b9d9159cc", + "runs/B4/dist/captures/01-initial.snapshot.txt": "c0e011efcc251cebca6bbe5d9ce9f5656b1ec326465c6856ab7e19b83044ff70", + "runs/B4/dist/captures/02-after-clicks.png": "e570d77e559d91d6675a0a278daa9598a1d2919b3d2ec817c37998b33e57d9d0", + "runs/B4/dist/captures/02-after-clicks.receipt.json": "26422f241282a75835d6ad315859528a95aba3c506f14f7a309cb40811802895", + "runs/B4/dist/captures/02-after-clicks.snapshot.txt": "7483e90a161c5241869710cccc51cf435591762b1eb7474675e71a01a9b0233b", + "runs/B4/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/B4/dist/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/B4/dist/widget.json": "c968a95a6291a70c21c987b99decfc4f7342192c5ed19a7cf031cf0bf572a8e7", + "runs/B4/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/B4/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/B4/widget.tsx": "6e02b5a6ceab77c4384fa4e74fa50073e7426590c79a5909eb20f363b19756d2", + "runs/C1/REPORT.md": "f4201b905804b5e55fc05a3832f3890211fbfac0e9f5ee67594ebf39de751412", + "runs/C1/captures/01-initial.png": "cb39561761579820af291888a57255a09ed28ca52964c16888b585d8a5f0f0f6", + "runs/C1/captures/01-initial.receipt.json": "992b2dde21ed12f0ccaa8355135770e40ae1dc700584e36e1597f70d45644558", + "runs/C1/captures/01-initial.snapshot.txt": "e5bfe1c0b2d1ae425322aef0aa65f607bb31cc052fe2762417da64ffc5b009f4", + "runs/C1/captures/03-initial.png": "a1039670868cea093d1754615c02ac70dfb5997d02d258685a15e773f172a350", + "runs/C1/captures/03-initial.receipt.json": "1bed83781e5ccfafdfab7ad2cf06bba7a1dda08a0f48f50cc42962c36a5ab1b1", + "runs/C1/captures/03-initial.snapshot.txt": "2bebb5a0b13f125aed5189c499ec6dd66361e65e1e272f8ed9f0732b10541bfb", + "runs/C1/captures/04-initial.png": "a951b88adf5502e437fa8503dbc4dab5d7e6977e6a903140db696d2e1dcb65a1", + "runs/C1/captures/04-initial.receipt.json": "d9ae9ff420d1557937700d2aa45acbe0951ddb99a3d87eee245ea10b19701fd9", + "runs/C1/captures/04-initial.snapshot.txt": "b994a9747f0409b1e2eb276edf2568d0720f3decf1ae004069011ecd45330c90", + "runs/C1/captures/05-initial.png": "15b621723b2165bb1e04a1ae317ae51254463be566d6db211aeeb1cc6ae7cc77", + "runs/C1/captures/05-initial.receipt.json": "9448868fabf32e4c145f2ea69f5f1ec61ece27598416c0061df5af0471b07b6a", + "runs/C1/captures/05-initial.snapshot.txt": "3711853c15d77eb05c8b0d5327eb044f2a54ab89bb27d5cc33dc83037e4e52a9", + "runs/C1/captures/06-initial.png": "54edb774e71592077df9d0d4d173faf2f4efef92386caafd9d3afeed869fa5b8", + "runs/C1/captures/06-initial.receipt.json": "48f7ca1d224587daf303e3375e207e39b04e735d6675259ea91cf8395dfe0444", + "runs/C1/captures/06-initial.snapshot.txt": "0b9ddb1c9a6856049c9144e8059a4eb7b694dda2c6bbb2881265c24197078a57", + "runs/C1/captures/07-after-clicks.png": "e23da14853880d95962edb9baa4da95ba289feada2eaf425abd7475f4cd14512", + "runs/C1/captures/07-after-clicks.receipt.json": "fdc7acd7e5599dca9baf5c057e34fe24836dbe00920c17fe72f518714fd53f39", + "runs/C1/captures/07-after-clicks.snapshot.txt": "5dc000af69159657e63a259e1a66401e0db3386716a968ed9ac2d28b7cab4c7b", + "runs/C1/captures/08-after-reset.png": "ba80a046df128a949336e34652fcbc58ac735fa1f02ef104bcd0f3373870339d", + "runs/C1/captures/08-after-reset.receipt.json": "269a45b327492f71713b010662eac77715aa808659955f0e87f5689eb4140e2c", + "runs/C1/captures/08-after-reset.snapshot.txt": "33af58cb2e398ad43a598434afe1e719c25c8386fb5f7dc8302761dcf39d6e70", + "runs/C1/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C1/dist/bundle.js": "d6d7ac89536a2251537e92e5c64321dd8f394cca75633f1250db9f231e8d48d1", + "runs/C1/dist/captures/01-initial.png": "cb39561761579820af291888a57255a09ed28ca52964c16888b585d8a5f0f0f6", + "runs/C1/dist/captures/01-initial.receipt.json": "992b2dde21ed12f0ccaa8355135770e40ae1dc700584e36e1597f70d45644558", + "runs/C1/dist/captures/01-initial.snapshot.txt": "e5bfe1c0b2d1ae425322aef0aa65f607bb31cc052fe2762417da64ffc5b009f4", + "runs/C1/dist/captures/03-initial.png": "a1039670868cea093d1754615c02ac70dfb5997d02d258685a15e773f172a350", + "runs/C1/dist/captures/03-initial.receipt.json": "1bed83781e5ccfafdfab7ad2cf06bba7a1dda08a0f48f50cc42962c36a5ab1b1", + "runs/C1/dist/captures/03-initial.snapshot.txt": "2bebb5a0b13f125aed5189c499ec6dd66361e65e1e272f8ed9f0732b10541bfb", + "runs/C1/dist/captures/04-initial.png": "a951b88adf5502e437fa8503dbc4dab5d7e6977e6a903140db696d2e1dcb65a1", + "runs/C1/dist/captures/04-initial.receipt.json": "d9ae9ff420d1557937700d2aa45acbe0951ddb99a3d87eee245ea10b19701fd9", + "runs/C1/dist/captures/04-initial.snapshot.txt": "b994a9747f0409b1e2eb276edf2568d0720f3decf1ae004069011ecd45330c90", + "runs/C1/dist/captures/05-initial.png": "15b621723b2165bb1e04a1ae317ae51254463be566d6db211aeeb1cc6ae7cc77", + "runs/C1/dist/captures/05-initial.receipt.json": "9448868fabf32e4c145f2ea69f5f1ec61ece27598416c0061df5af0471b07b6a", + "runs/C1/dist/captures/05-initial.snapshot.txt": "3711853c15d77eb05c8b0d5327eb044f2a54ab89bb27d5cc33dc83037e4e52a9", + "runs/C1/dist/captures/06-initial.png": "54edb774e71592077df9d0d4d173faf2f4efef92386caafd9d3afeed869fa5b8", + "runs/C1/dist/captures/06-initial.receipt.json": "48f7ca1d224587daf303e3375e207e39b04e735d6675259ea91cf8395dfe0444", + "runs/C1/dist/captures/06-initial.snapshot.txt": "0b9ddb1c9a6856049c9144e8059a4eb7b694dda2c6bbb2881265c24197078a57", + "runs/C1/dist/captures/07-after-clicks.png": "e23da14853880d95962edb9baa4da95ba289feada2eaf425abd7475f4cd14512", + "runs/C1/dist/captures/07-after-clicks.receipt.json": "fdc7acd7e5599dca9baf5c057e34fe24836dbe00920c17fe72f518714fd53f39", + "runs/C1/dist/captures/07-after-clicks.snapshot.txt": "5dc000af69159657e63a259e1a66401e0db3386716a968ed9ac2d28b7cab4c7b", + "runs/C1/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C1/dist/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C1/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/C1/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C1/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/C1/widget.tsx": "f53dc0b258f808fe8a7e041c3ac8768bdc58ac691bfcb5bda81e85e7b00dfbbf", + "runs/C2/REPORT.md": "300d928ecff444d2ad4b1143a0a01c6b45a90ab1a6e8a6c660a05767e7270290", + "runs/C2/captures/01-initial.png": "47f9648b71001e9d720b87befbe0da702df415376219632010e053a890e738f0", + "runs/C2/captures/01-initial.receipt.json": "0583197d791b438fdb4b1bb9e2f8c2c2212e87d5c2ec5fbec9c02a2daa980a01", + "runs/C2/captures/01-initial.snapshot.txt": "8f6217fa673a9c3b4cd80463dec79a88962009a8c346d053fc59baa6ef563d3f", + "runs/C2/captures/02-initial.png": "7d965de03bfb4a13ae747104dcfd55b791e5e1508a3f28593e181aeaff100ab3", + "runs/C2/captures/02-initial.receipt.json": "55d08447bb15eecce9fa463b6dec5aee46539f78b5b3f6cf4ba04cb8a2b29dd9", + "runs/C2/captures/02-initial.snapshot.txt": "ce7ea9a62c4e402a341930aa00bb96ea6618b62544a252c87dc1560085507e2b", + "runs/C2/captures/04-initial.png": "434a83b2e12dff8175549246bd391bd7cd01f6ce43c0f6d9ff078e00988abe74", + "runs/C2/captures/04-initial.receipt.json": "4539e17f4ba9511413a90b80b10343f69fd3e1e86ba61e6c0943be1bd4fb18ec", + "runs/C2/captures/04-initial.snapshot.txt": "54c932b27bfb719a5feed624b8608a19c7485f1d3784cc1ff87aa8d1cb9d86d8", + "runs/C2/captures/05-initial.png": "9ca1deabaae751ce84130c7339f690fbd08eb3284cad18d2a0ada3d5b4d9e388", + "runs/C2/captures/05-initial.receipt.json": "07908fb468d9d2b00c635eb64b0181fcd385a1dd7da1ce79677c3e4d7a68d34f", + "runs/C2/captures/05-initial.snapshot.txt": "9de12175230c8f7cd0ba3d9d8a915c45b73b80fdc9c20a857b004334a0c3f08e", + "runs/C2/captures/06-after-clicks.png": "5b0b17a527d0f94f0f173ee5b018f13a4e6ee0433e5c7fc61b62051d82302547", + "runs/C2/captures/06-after-clicks.receipt.json": "542ca199a06bf08d3122ee5080e01bd15b9f0af33c3a25386fd539e8fa50de72", + "runs/C2/captures/06-after-clicks.snapshot.txt": "585166f374f53c76627f0eac0f3b67fab4b835df25a90bc09c442ec96db74ed8", + "runs/C2/captures/07-after-reset.png": "c20f2f37cffb0084fd6d66aad1c9bb26daee6393a2101b9d90f51ef3479e757c", + "runs/C2/captures/07-after-reset.receipt.json": "868a336d53126c311e22daea19ecd478cee405a5f5222b21b2cde48ffaec9c33", + "runs/C2/captures/07-after-reset.snapshot.txt": "6c819a48405c4504cb7c4e35f79cc1709d8566080229aeda85a856033dee0ed3", + "runs/C2/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C2/dist/bundle.js": "0cebb86f890ee357dcf4de4aad6aff5b999f394d9740de20112ccd8d0baf7991", + "runs/C2/dist/captures/01-initial.png": "47f9648b71001e9d720b87befbe0da702df415376219632010e053a890e738f0", + "runs/C2/dist/captures/01-initial.receipt.json": "0583197d791b438fdb4b1bb9e2f8c2c2212e87d5c2ec5fbec9c02a2daa980a01", + "runs/C2/dist/captures/01-initial.snapshot.txt": "8f6217fa673a9c3b4cd80463dec79a88962009a8c346d053fc59baa6ef563d3f", + "runs/C2/dist/captures/02-initial.png": "7d965de03bfb4a13ae747104dcfd55b791e5e1508a3f28593e181aeaff100ab3", + "runs/C2/dist/captures/02-initial.receipt.json": "55d08447bb15eecce9fa463b6dec5aee46539f78b5b3f6cf4ba04cb8a2b29dd9", + "runs/C2/dist/captures/02-initial.snapshot.txt": "ce7ea9a62c4e402a341930aa00bb96ea6618b62544a252c87dc1560085507e2b", + "runs/C2/dist/captures/04-initial.png": "434a83b2e12dff8175549246bd391bd7cd01f6ce43c0f6d9ff078e00988abe74", + "runs/C2/dist/captures/04-initial.receipt.json": "4539e17f4ba9511413a90b80b10343f69fd3e1e86ba61e6c0943be1bd4fb18ec", + "runs/C2/dist/captures/04-initial.snapshot.txt": "54c932b27bfb719a5feed624b8608a19c7485f1d3784cc1ff87aa8d1cb9d86d8", + "runs/C2/dist/captures/05-initial.png": "9ca1deabaae751ce84130c7339f690fbd08eb3284cad18d2a0ada3d5b4d9e388", + "runs/C2/dist/captures/05-initial.receipt.json": "07908fb468d9d2b00c635eb64b0181fcd385a1dd7da1ce79677c3e4d7a68d34f", + "runs/C2/dist/captures/05-initial.snapshot.txt": "9de12175230c8f7cd0ba3d9d8a915c45b73b80fdc9c20a857b004334a0c3f08e", + "runs/C2/dist/captures/06-after-clicks.png": "5b0b17a527d0f94f0f173ee5b018f13a4e6ee0433e5c7fc61b62051d82302547", + "runs/C2/dist/captures/06-after-clicks.receipt.json": "542ca199a06bf08d3122ee5080e01bd15b9f0af33c3a25386fd539e8fa50de72", + "runs/C2/dist/captures/06-after-clicks.snapshot.txt": "585166f374f53c76627f0eac0f3b67fab4b835df25a90bc09c442ec96db74ed8", + "runs/C2/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C2/dist/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C2/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/C2/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C2/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/C2/widget.tsx": "7eedca57e692580b197beca8233409a1999530345101d462c5e420f8b4df14cb", + "runs/C3/REPORT.md": "570f30c4960fd374ef778955fee3918debf82086ab59c3fa4e1e2180907b8716", + "runs/C3/captures/01-initial.png": "013fe4993a3b85e5582d590d6c13f97d2bbc457063a82d83974eaf4d4a84ae8b", + "runs/C3/captures/01-initial.receipt.json": "3b6a114e159788f619f529c0d63ed8158d8509782552d51da4ad1514546eb9ee", + "runs/C3/captures/01-initial.snapshot.txt": "d1aca5ec76d344dfde640c95d6cf14baf138df4d6eca43e6eed0f57661e75c99", + "runs/C3/captures/02-initial.png": "e524b14ec0a23ae4234f2df7e6b3b05a7d3af4dab2ece4d4e7a2ec6945a16614", + "runs/C3/captures/02-initial.receipt.json": "f08e908c41db32ac7c472163b9fc85dfd9a86bdd7b3341a2927967df3fc3d651", + "runs/C3/captures/02-initial.snapshot.txt": "72231edafce593af211b7b2c713ba434d422d087a89f3447fb30d4c24c5a61d4", + "runs/C3/captures/04-initial.png": "61edbc38907cd2b7b094b61606e24399e0f58bccee89e4d7adc1054b4e1f735f", + "runs/C3/captures/04-initial.receipt.json": "73a0348c010102e6c274bc8341d30aea4e1a5bceb79318483bd71c43455c0de9", + "runs/C3/captures/04-initial.snapshot.txt": "09150e89b3e104ef1e3fce45f109f91204f2c1e9add61db1ae629e5a31176bdc", + "runs/C3/captures/05-initial.png": "8c70b8265c128052b4ceb3077c8f8117084a4ef121a7590cbba826469eb80a2e", + "runs/C3/captures/05-initial.receipt.json": "d1f0d5f8096f49e419687fe850f6faa7fb2326245192dd692b519bafd05a7f51", + "runs/C3/captures/05-initial.snapshot.txt": "f9be8f8f95c8f49266c33bb2351c44593dc1add5a03c1ba4d672347117d9c24d", + "runs/C3/captures/06-after-clicks.png": "ea77edfeff6b4b2408e49478e05d7b7a3ff5af9e819aa02ce234369ac926205d", + "runs/C3/captures/06-after-clicks.receipt.json": "6ee1f74d5a9ce1d9cb9b1a79ea1da70a8850050a6be0ddc5ade2a9f50a31aa8c", + "runs/C3/captures/06-after-clicks.snapshot.txt": "9be9d221898dea35a2ac361d229786455157fc6d6f6c8eb232d8680bcc4ee603", + "runs/C3/captures/07-after-reset.png": "4fabf2d9e85a250ece43c6d5bc52c4cdd6d8ed81ffac60d88ecbfddc9a9bece9", + "runs/C3/captures/07-after-reset.receipt.json": "61b9988990e1b152eae19c67c31f73ef09caf8e2c5c8fa273ba5a62519660fbd", + "runs/C3/captures/07-after-reset.snapshot.txt": "a0da566f64dc9193a75359038f06b7788616ce82a30646c83762fb25f34aa3d7", + "runs/C3/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C3/dist/bundle.js": "c14930d3ba22eecbd0010fb5a7f5ff43c44cd40d816c023e82e08c9ad817439b", + "runs/C3/dist/captures/01-initial.png": "013fe4993a3b85e5582d590d6c13f97d2bbc457063a82d83974eaf4d4a84ae8b", + "runs/C3/dist/captures/01-initial.receipt.json": "3b6a114e159788f619f529c0d63ed8158d8509782552d51da4ad1514546eb9ee", + "runs/C3/dist/captures/01-initial.snapshot.txt": "d1aca5ec76d344dfde640c95d6cf14baf138df4d6eca43e6eed0f57661e75c99", + "runs/C3/dist/captures/02-initial.png": "e524b14ec0a23ae4234f2df7e6b3b05a7d3af4dab2ece4d4e7a2ec6945a16614", + "runs/C3/dist/captures/02-initial.receipt.json": "f08e908c41db32ac7c472163b9fc85dfd9a86bdd7b3341a2927967df3fc3d651", + "runs/C3/dist/captures/02-initial.snapshot.txt": "72231edafce593af211b7b2c713ba434d422d087a89f3447fb30d4c24c5a61d4", + "runs/C3/dist/captures/04-initial.png": "61edbc38907cd2b7b094b61606e24399e0f58bccee89e4d7adc1054b4e1f735f", + "runs/C3/dist/captures/04-initial.receipt.json": "73a0348c010102e6c274bc8341d30aea4e1a5bceb79318483bd71c43455c0de9", + "runs/C3/dist/captures/04-initial.snapshot.txt": "09150e89b3e104ef1e3fce45f109f91204f2c1e9add61db1ae629e5a31176bdc", + "runs/C3/dist/captures/05-initial.png": "8c70b8265c128052b4ceb3077c8f8117084a4ef121a7590cbba826469eb80a2e", + "runs/C3/dist/captures/05-initial.receipt.json": "d1f0d5f8096f49e419687fe850f6faa7fb2326245192dd692b519bafd05a7f51", + "runs/C3/dist/captures/05-initial.snapshot.txt": "f9be8f8f95c8f49266c33bb2351c44593dc1add5a03c1ba4d672347117d9c24d", + "runs/C3/dist/captures/06-after-clicks.png": "ea77edfeff6b4b2408e49478e05d7b7a3ff5af9e819aa02ce234369ac926205d", + "runs/C3/dist/captures/06-after-clicks.receipt.json": "6ee1f74d5a9ce1d9cb9b1a79ea1da70a8850050a6be0ddc5ade2a9f50a31aa8c", + "runs/C3/dist/captures/06-after-clicks.snapshot.txt": "9be9d221898dea35a2ac361d229786455157fc6d6f6c8eb232d8680bcc4ee603", + "runs/C3/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C3/dist/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C3/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/C3/reset.actions": "547af5e62a5a22258cec6451097d2522e40a938e46a64f35e6107385fa81cc8a", + "runs/C3/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/C3/widget.tsx": "ce12b3d87d406972654b71ad9c82f3ae1e51cf31a81c73a1f27999854818dde7", + "runs/C4/REPORT.md": "9b9c24e57c4a67ce06e612787abd5418253d4ae894c90b3ee3d7a69ea62ff5de", + "runs/C4/captures/01-initial.png": "9b36d96fab28f85ea169e1db57d68ce1b3e2c185850f4f77b0e24e7ed80e55c1", + "runs/C4/captures/01-initial.receipt.json": "f3014335e17fbbc93c813ba7a7e1472c9f6a33a99ab9d0468c07e0d8af7954ab", + "runs/C4/captures/01-initial.snapshot.txt": "060497ab2b2f6f269ea73c9a4dce163820e593d7be8dfe3a2c1964a0babd05b5", + "runs/C4/captures/02-initial.png": "734777c821b1de9a972a1f22c82eaf34271b3f68e689f00f97fc966f092856be", + "runs/C4/captures/02-initial.receipt.json": "364be8c11a285d10936b2db629770bfc0b536891b7846c3180e3e02497ebaaa4", + "runs/C4/captures/02-initial.snapshot.txt": "b2bc4ab31fcd2c6d9ee7d42129c1068f435efaa257ad7b215700bc1a4c1bf948", + "runs/C4/captures/03-initial.png": "acd831624844aa5cf5c6d7fde33cca4fa78ee973203aadca1e4a2767e9ec5fef", + "runs/C4/captures/03-initial.receipt.json": "e1e83ba2d4004240a6d39edd15768d5a394686fa8c96516e83f8ab0b47439249", + "runs/C4/captures/03-initial.snapshot.txt": "9ae54a442bf4d18a2d6d79c0a54e45d143fb6bfe8c638911eec23decb483fb47", + "runs/C4/captures/05-initial.png": "87c1d9d2c11341f4a1abe5b8db8f295cfc3c775a85a4ebd579b5eb1f418a0bdc", + "runs/C4/captures/05-initial.receipt.json": "fa960eddfce49da9621f606137012958df1bc6c9c23b13391f7c38e737b864fe", + "runs/C4/captures/05-initial.snapshot.txt": "7e3740ed636ad28232e1edf9313422f52ec06c897a0c2ce723d3ab50072a4f95", + "runs/C4/captures/06-initial.png": "fca5c6cbfdee31ffe683f13c6fcdaee01bd47afc241a21e5c3f941cbd5b193c9", + "runs/C4/captures/06-initial.receipt.json": "6126787ba63b2ed2a1ece2b1bb0ac3fcfe23753167d45f508c2fbb6b3bd7d2a6", + "runs/C4/captures/06-initial.snapshot.txt": "d5df5a6e9a8744c35ddcd3024399cfa7b4032ab4a52d158807230d90e58e2624", + "runs/C4/captures/07-after-clicks.png": "2f5bd7e4ef88186894e926c6bc2ccdea9fd2106ce9a7390997adc6e6b2530dad", + "runs/C4/captures/07-after-clicks.receipt.json": "a69d8365616678ff9141f7a19ed4606792223c91d38006417b8672d3ea7bccbe", + "runs/C4/captures/07-after-clicks.snapshot.txt": "c206af093379bafaf53019997e490d65eff7957b688bc5431f82fb91c3f2ed69", + "runs/C4/captures/08-after-reset.png": "64f2c67c19f937edaab4851509174a239c56f152812c56d020a89f931c95b871", + "runs/C4/captures/08-after-reset.receipt.json": "d28ce1cbab28990fa078b29f6db895774c429ccd28692af1b5f2286a381acbb2", + "runs/C4/captures/08-after-reset.snapshot.txt": "1f14a82de5912c953d3c4fd8b9b9ff778a7dfb56190bc572ad42bbca751328e5", + "runs/C4/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C4/dist/bundle.js": "b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0", + "runs/C4/dist/captures/01-initial.png": "9b36d96fab28f85ea169e1db57d68ce1b3e2c185850f4f77b0e24e7ed80e55c1", + "runs/C4/dist/captures/01-initial.receipt.json": "f3014335e17fbbc93c813ba7a7e1472c9f6a33a99ab9d0468c07e0d8af7954ab", + "runs/C4/dist/captures/01-initial.snapshot.txt": "060497ab2b2f6f269ea73c9a4dce163820e593d7be8dfe3a2c1964a0babd05b5", + "runs/C4/dist/captures/02-initial.png": "734777c821b1de9a972a1f22c82eaf34271b3f68e689f00f97fc966f092856be", + "runs/C4/dist/captures/02-initial.receipt.json": "364be8c11a285d10936b2db629770bfc0b536891b7846c3180e3e02497ebaaa4", + "runs/C4/dist/captures/02-initial.snapshot.txt": "b2bc4ab31fcd2c6d9ee7d42129c1068f435efaa257ad7b215700bc1a4c1bf948", + "runs/C4/dist/captures/03-initial.png": "acd831624844aa5cf5c6d7fde33cca4fa78ee973203aadca1e4a2767e9ec5fef", + "runs/C4/dist/captures/03-initial.receipt.json": "e1e83ba2d4004240a6d39edd15768d5a394686fa8c96516e83f8ab0b47439249", + "runs/C4/dist/captures/03-initial.snapshot.txt": "9ae54a442bf4d18a2d6d79c0a54e45d143fb6bfe8c638911eec23decb483fb47", + "runs/C4/dist/captures/05-initial.png": "87c1d9d2c11341f4a1abe5b8db8f295cfc3c775a85a4ebd579b5eb1f418a0bdc", + "runs/C4/dist/captures/05-initial.receipt.json": "fa960eddfce49da9621f606137012958df1bc6c9c23b13391f7c38e737b864fe", + "runs/C4/dist/captures/05-initial.snapshot.txt": "7e3740ed636ad28232e1edf9313422f52ec06c897a0c2ce723d3ab50072a4f95", + "runs/C4/dist/captures/06-initial.png": "fca5c6cbfdee31ffe683f13c6fcdaee01bd47afc241a21e5c3f941cbd5b193c9", + "runs/C4/dist/captures/06-initial.receipt.json": "6126787ba63b2ed2a1ece2b1bb0ac3fcfe23753167d45f508c2fbb6b3bd7d2a6", + "runs/C4/dist/captures/06-initial.snapshot.txt": "d5df5a6e9a8744c35ddcd3024399cfa7b4032ab4a52d158807230d90e58e2624", + "runs/C4/dist/captures/07-after-clicks.png": "2f5bd7e4ef88186894e926c6bc2ccdea9fd2106ce9a7390997adc6e6b2530dad", + "runs/C4/dist/captures/07-after-clicks.receipt.json": "a69d8365616678ff9141f7a19ed4606792223c91d38006417b8672d3ea7bccbe", + "runs/C4/dist/captures/07-after-clicks.snapshot.txt": "c206af093379bafaf53019997e490d65eff7957b688bc5431f82fb91c3f2ed69", + "runs/C4/dist/clicks.actions": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77", + "runs/C4/dist/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/C4/dist/widget.json": "c40ca094d273ad1210a1e86aeb5a21ecf3ec067b1b8e891719ef456623749895", + "runs/C4/reset.actions": "2fc5e3e27040c5745f30fec7516cb2889023539d027a3cfcc6a647a4c9d536c0", + "runs/C4/tsconfig.json": "601f9278b19a229c1adb445b611039f130a483a54773e596af0d31a78f0a28e9", + "runs/C4/widget.tsx": "af0df9e06014d0c3e53bd0a0c34be53dae47a96c4037ff20622555bb8a9a50f0", + "final/A1/after-clicks.command.json": "cdaa4600b3e267d9ef06c2fd5207267b99b927f1e0e387db65a45e7d4a2f0a7a", + "final/A1/after-clicks.png": "15712590fa34780abe1834ef2da5db109c3bb59d0d090ed844b243820d9e3b79", + "final/A1/after-clicks.receipt.json": "3175088eb7380959964f55fb51bc273f17fdda7bf0663f571e3d4c2a476af0a9", + "final/A1/after-clicks.snapshot.txt": "3e7266215f989fa7a3f5aa02ea58a772a79c174dfb102c764a10620320949249", + "final/A1/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A1/after-clicks.stdout": "95156c64b3a9e3cffdc4a78672acbc0f6e141b6d7c52fb1c2c84f458ace53a3c", + "final/A1/check.command.json": "02044f348c53b17801b151c7b1506549da46da4687664a5d1d70e7eada31af36", + "final/A1/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A1/check.stdout": "f02a8b7acdc47f6334512e57fc47a6061139b563a437e2d22ffe601dfb873263", + "final/A1/initial.command.json": "34d54c0c681474dc349feaa0221a2b621adae5a312c56fa6580182c1ac079bd9", + "final/A1/initial.png": "9d64abdcdff72e1eab129ca7f95dffab74c1f3e54e9dbffe452f1eb0d8ebdad1", + "final/A1/initial.receipt.json": "d7ab999a5fee9d99750316b4ad994d7bba4473c9e81e616551e2fafb27f4cdf0", + "final/A1/initial.snapshot.txt": "ba37a58b624075d3c9c24ee84112997d8e5127e7c305ae08dcb4a5a775e1bf41", + "final/A1/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A1/initial.stdout": "ed3eacd9ba9a69e4595778a8bc79160de146755f0ed9af352f6ae54cc79cf9af", + "final/A2/after-clicks.command.json": "e2dc9ee826bba2c9c079ba5fb1b33fa8763fb2d6d1e7efdd0554e9a792ff7e3f", + "final/A2/after-clicks.png": "ac504e9443402e7387760512b076177790e18d6baacff1be4e4bcb05bdcf6be4", + "final/A2/after-clicks.receipt.json": "65b2d277d899051b1ee304dc880c3ca60ed7ec1519d2bb0075dc5f2bfb3ba6bb", + "final/A2/after-clicks.snapshot.txt": "d3426e4f179ed444cf3305ac40f6fa85fa99d8da35ec85f1c1d895aaac180aba", + "final/A2/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A2/after-clicks.stdout": "674ddb12b8838a6fdf98def25b1f3b9b6dabd5661324a7fd6ecd3a07f0df58cd", + "final/A2/check.command.json": "bbfb8bb9e6ea94801325b230dca4ac521925e625969217daa0ae92880be5908f", + "final/A2/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A2/check.stdout": "5a04db44c4349e30d01a88575d363b0cf63c6e62ca301dbb5aec8cd6ce9d6a60", + "final/A2/initial.command.json": "a45799b3bb63e352937a343ad113625322b34b85037d6e107dce53db08178c9d", + "final/A2/initial.png": "7e2c5fb64e9b88335eadf16452826bc3a016f036dca1242412b653636f445ba1", + "final/A2/initial.receipt.json": "ccc730033355a81e9311254901cd85e604de296d75180695c700da5d836a16be", + "final/A2/initial.snapshot.txt": "fb386c3386fb743db72e2e332ee0c6c3e53a2ff72f46d4023dd66d6493d2388c", + "final/A2/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/A2/initial.stdout": "e545f1f2273d6764131f2d9e78e157dc2e85be65d630f8e3bdbcf71c5d60fc70", + "final/B1/after-clicks.command.json": "90f83b7c921563f3669ebd46b581fca3832c28caf443e0c85c605d99ba1c3364", + "final/B1/after-clicks.png": "1def36ef31771d7e8f4aec4029fc213108a5fd87650755c33c309189955ead8a", + "final/B1/after-clicks.receipt.json": "b94124756d90df50069b5c01327420a579465f48f74292a08026dea34f34e70d", + "final/B1/after-clicks.snapshot.txt": "7e4737be94f698283d00036370496deea71b876ef2d0b4b004f1aa1a16dafc4b", + "final/B1/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B1/after-clicks.stdout": "04b34aa400d38ffff9f0f0d4d037f160bcdde6c3cd1001e2fc54da3d1e08c054", + "final/B1/check.command.json": "2f6e1fe474fd8ed7cdcff9749f94bef796d735eafc6ee92abea5288759533d03", + "final/B1/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B1/check.stdout": "1302c5fb3ad057455ff587141612a12da54d1594045d4c41aee3fa9acdb41ddb", + "final/B1/initial.command.json": "2797f7cb207d31599c1c41f11d7ec6470d82e5448cd0615c462cbaa06581b7ee", + "final/B1/initial.png": "577a28b6c84ef2f978cde1f5c24ad398bbc194e327edce13b02574a69db6795b", + "final/B1/initial.receipt.json": "8eea2ea898aef006ea94d27f3d03d9ec609276634541817988b497f6304481a2", + "final/B1/initial.snapshot.txt": "ece211031f7018000ad0d8a8eae62f4903376d574a2bcbac455a8e5e65f47123", + "final/B1/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B1/initial.stdout": "6e6159afe9fa0278087fce400314c04c3c57107ef34cec320dced5e99036026f", + "final/B2/after-clicks.command.json": "5e85e966874570992454157e8b26b956dd7e068e852322d25eaafbc02e12f49e", + "final/B2/after-clicks.png": "be359e552a73260dbe41213da3a31879d1a6c243184108ffd5b5166303cb4f5a", + "final/B2/after-clicks.receipt.json": "120e3e13537069dcb5b499b42b5d375e2478c20bd9785443833f0f814e695ac9", + "final/B2/after-clicks.snapshot.txt": "19ee29c5c35486b740b94f640f568097a3654ed2be28207e1e995ee842af7f21", + "final/B2/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B2/after-clicks.stdout": "21d7c4097bc83873ead3068dd399321259b18eef088ad26e538677334744da15", + "final/B2/check.command.json": "c043b8e5869b80758f6a7cdcce7a46d6a808c208f78429d2ab06bae484a10d1e", + "final/B2/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B2/check.stdout": "9928dae0183fd7bb072f15c57a879b634d9e07bc4656203abd01f51f8672f2d6", + "final/B2/initial.command.json": "fe90a4a432dd89c9c3981349301dbbe7a593a41714ccf2f2e46f0c71104f9110", + "final/B2/initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "final/B2/initial.receipt.json": "4dc0c13fa7e4459eb6c8e17d5245be5c13597223a7ba23e2b20259bbb0a7bfed", + "final/B2/initial.snapshot.txt": "4fd44b6d176a3be13ea2ca09316da563975a31ff0ef29ba14d4101f0bbee4ef8", + "final/B2/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B2/initial.stdout": "a2979bbd3652eef47112e190b00d3dfb7fe3f9314cd3f30aa770838c7642ca0d", + "final/B3/after-clicks.command.json": "51ce1d6e828b45e1c4c42d356cca2c441040801ffd438c1c3774c7d228af75d8", + "final/B3/after-clicks.png": "a8a24c3a4cb4c05a91fc763bd5942fb11acbb974132835c833f4bfa4dd5cf61a", + "final/B3/after-clicks.receipt.json": "5b594a9e78d5b8b25d521eef4dfdce1b3bdc5446deeaa072c258f6c394bc33ec", + "final/B3/after-clicks.snapshot.txt": "958e920a82f7c69d31d8719e84264d7379f8124c1b3c0cafa6046841dc7bfa31", + "final/B3/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B3/after-clicks.stdout": "7fcdd3ef95d3c0511b41cb3c7ec19ebc47427dfcdd8fd09a7e33833894b34531", + "final/B3/check.command.json": "a2167d4c907f6f2331859b70855eaa8f9d145e1184d533e1d5bd3507c103cf3c", + "final/B3/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B3/check.stdout": "946715d8e822be06ddd5d239216142e3b7bd20d89feffb4772f465c94c5d811a", + "final/B3/initial.command.json": "9e553a68d9472099b432928db13f5457832112e692cc257052c5165120d185cf", + "final/B3/initial.png": "156c5cdf4ed96faf13eeeb867b31748fcb628e53e433a5dd0b2a446d915e6aa6", + "final/B3/initial.receipt.json": "22eef61054936d9d415574b851eb99dfb5196b39ff4c751e4d95d1f2016ad087", + "final/B3/initial.snapshot.txt": "9211f41382c9c48affa44e2d9f5709b743424589d89ea397fe750c0e7ed862c0", + "final/B3/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B3/initial.stdout": "f83c1bc386acb8f62b6eb486a059b743bb8dfaa7e7ee83f5959ba5400a717e7c", + "final/B4/after-clicks.command.json": "946d7e9e315ec07ad5487f3f317484343c48b6c40f8d641db1843d5ec9620f33", + "final/B4/after-clicks.png": "e570d77e559d91d6675a0a278daa9598a1d2919b3d2ec817c37998b33e57d9d0", + "final/B4/after-clicks.receipt.json": "867caeea7e31b289daaf3d9f448a04726e1712114b243c20c24eef72d22b15f3", + "final/B4/after-clicks.snapshot.txt": "f837fb775513afcd2e431455f5206a35687229bd35ef7670b3a22d94df5c2a38", + "final/B4/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B4/after-clicks.stdout": "b7c544f6c837688ecf5df54dd5247f13819f8e0532d0a478a7b235b0366360e5", + "final/B4/check.command.json": "72b6298482323ebf308f9c2dba6fbac54a342092098d7ff9efb4cbae7f8c8fbd", + "final/B4/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B4/check.stdout": "542a61eac0af55a17641b5c438e8094d6575184f1125e1949ca18c3637bdf0be", + "final/B4/initial.command.json": "6687973b6fcd360ea97083e03329fd86ed72ac7f03ad155f7e2050abf8d61f02", + "final/B4/initial.png": "9ab9a3a1efd063c33d415f5b176f47b9c32b2d020eba9709fd91bab83587d5c7", + "final/B4/initial.receipt.json": "c4cb27cfccbf47751c64222ac8d5e4ae3eadb8b9898fbf16f8f37179d27d445d", + "final/B4/initial.snapshot.txt": "b7e3ca7e31322f7a08ba7b5757ae851df5b4de0e3488cb9ac0071ac593c201ac", + "final/B4/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/B4/initial.stdout": "1ce451fcaefb4e67ab406c5d80960016c907b3f66e06e9577b94832fba846d7c", + "final/C1/after-clicks.command.json": "7b98a09acd3465b1e2bfbcb01d4d8f839d4d21eb61b5e5a95bf9d64c1d0c9e5a", + "final/C1/after-clicks.png": "e23da14853880d95962edb9baa4da95ba289feada2eaf425abd7475f4cd14512", + "final/C1/after-clicks.receipt.json": "8c7a33b72e649ad7246b04d9279f06d30434e24046e8b9ad7b92213d07ce6d13", + "final/C1/after-clicks.snapshot.txt": "ea1535568455f67eef2f8e8bdeea5871580656218bd0a906bedf9bca2320931d", + "final/C1/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C1/after-clicks.stdout": "7c61ab9750d087713b6a5a38d4789c8dcd23975e1da87b312501b2470a1092f0", + "final/C1/check.command.json": "7adf3617d3619ae0bf9bfa4d84b0a392b388ac50ed001d87f6c72111cd84eced", + "final/C1/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C1/check.stdout": "c75f6fb66041f5772a941372553538725d8e2f2174bd5c18b7a8004a1b752378", + "final/C1/initial.command.json": "6eec562101813c7ab167323d9ec10baf49290bfd1c82c94814297f7e4235ce5e", + "final/C1/initial.png": "54edb774e71592077df9d0d4d173faf2f4efef92386caafd9d3afeed869fa5b8", + "final/C1/initial.receipt.json": "0fc39a4966e9ad226a57069126e9d68dffd5e8851fd13f18ca8b6ed45ef11d1a", + "final/C1/initial.snapshot.txt": "02f8bcb0a97ef996c62c5de5d3128a2d9c35a44708f0af1ead84d9de3ee18831", + "final/C1/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C1/initial.stdout": "1161ae08d301bb492b4859157d81c94eb3978fd19063b277289b7fb4f348049e", + "final/C2/after-clicks.command.json": "37e8ba4926a079fb2b516f83ceb94c7ccc74d597ea8f2b9a2683ffa0c4489347", + "final/C2/after-clicks.png": "5b0b17a527d0f94f0f173ee5b018f13a4e6ee0433e5c7fc61b62051d82302547", + "final/C2/after-clicks.receipt.json": "2aa245be28632a7572e3cab5b356a9f74a3a2e9255d57cc8e1d585f8b00c8c68", + "final/C2/after-clicks.snapshot.txt": "54599df1df88b87e7e874eebe71eac696cb94da6c2b71d26489adb14e480bb7e", + "final/C2/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C2/after-clicks.stdout": "07bb680cf6e6f00e93df468ca29273bd87a879504104fb274aa6bfcdc181a193", + "final/C2/check.command.json": "62965e6c31c32ec9c37eee60a22dd05f945aa12214065308df2dd27c505d9b85", + "final/C2/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C2/check.stdout": "934ba44e5a131d2edd233490c42961356c032327120049eaea9d5a23df5cbc4e", + "final/C2/initial.command.json": "7af40b8c7ecf864fa608df25045ee657d0faef156e9b57b2bafb623c78ea9210", + "final/C2/initial.png": "9ca1deabaae751ce84130c7339f690fbd08eb3284cad18d2a0ada3d5b4d9e388", + "final/C2/initial.receipt.json": "dbb7dbd1e15d257e0b22e3f2376398e0a6365fe99b5bc674fdb828ffc41152ba", + "final/C2/initial.snapshot.txt": "f6f97d121bd14d49dfa7e6a789a882d29abd8f7d15bc5df38f3e55fe372b36a7", + "final/C2/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C2/initial.stdout": "7a2f27cd7d9fbb543970d9da9d9b08e7e47f7735f408750b0397161715a45aad", + "final/C3/after-clicks.command.json": "b80aa29a231484ba8cca0a6b93a922fe5bbabcde766206e8e2c31cda1af0e0e4", + "final/C3/after-clicks.png": "ea77edfeff6b4b2408e49478e05d7b7a3ff5af9e819aa02ce234369ac926205d", + "final/C3/after-clicks.receipt.json": "a85c86e3db954153ebd1d78fc17e527251acc4851824091eca7365ae1604a906", + "final/C3/after-clicks.snapshot.txt": "8b29eab8edd572bc90235dab3c5cc710589c9f73a6f57c058f12779b78c4d591", + "final/C3/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C3/after-clicks.stdout": "012dba29def04f8a5b4abf03ab6a5d51d3035ed32babb7e5d09f3d94f4ea7b76", + "final/C3/check.command.json": "fe52d08f2d52db7ae7f7092805461e6db16d9696397e37608b988bff7e25cbdc", + "final/C3/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C3/check.stdout": "db4bbc98d2fb1cedae5d289376ec9bf9468e3539053dee1b755206b31df3d222", + "final/C3/initial.command.json": "9d5f324fc53835325e46ae8c151b33030d2c0bd23af92722a69000d2cac5c34c", + "final/C3/initial.png": "8c70b8265c128052b4ceb3077c8f8117084a4ef121a7590cbba826469eb80a2e", + "final/C3/initial.receipt.json": "cbc2500d2aa2e87a7c1b0f7dd35c4663c3e6cd2e97eb8c1ab7968cbf2cd40cb6", + "final/C3/initial.snapshot.txt": "3513840a12180eee051fa072d238a44148d80402eb6960745bcefb6afd9dc152", + "final/C3/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C3/initial.stdout": "137c9bb7a262b40a3e90113dd027d193b69ed6bb53017515299eeff7c0379003", + "final/C4/after-clicks.command.json": "6461affcc79068d5aa6678a0b9f379e07a2a7c3a0c216e9dbf4b44df56b878fe", + "final/C4/after-clicks.png": "2f5bd7e4ef88186894e926c6bc2ccdea9fd2106ce9a7390997adc6e6b2530dad", + "final/C4/after-clicks.receipt.json": "d35d5c6e3cb0b82e0bfcc51da7e4713475b922e0c8e1909e9afa5b1b677b100c", + "final/C4/after-clicks.snapshot.txt": "abb07fa3110144a5747c86cdd233e27e8b72b64859f22583ee4cdee3fdc29248", + "final/C4/after-clicks.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C4/after-clicks.stdout": "732ccf765cf9ea5cd65640f3065edb9026e8cf82580bf6aa294afea96a28e9fc", + "final/C4/check.command.json": "fbb061dbd4ad7dd2c1a901ac88b7d8053536c82260f057100a3cc192a95a0b9d", + "final/C4/check.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C4/check.stdout": "b769af25795429cf77055986aaa971b31c52b481032d184e0cef033f1d953bdc", + "final/C4/initial.command.json": "77fb774b99eff03d7bc6eef45f9eb54259202e898db5ed363b72ec5ee8c8f911", + "final/C4/initial.png": "fca5c6cbfdee31ffe683f13c6fcdaee01bd47afc241a21e5c3f941cbd5b193c9", + "final/C4/initial.receipt.json": "aed023bced81a9c556e6d82ac432e88b723f5fb8fcf0b4433a818f3587836c87", + "final/C4/initial.snapshot.txt": "8868019d647e240778728dfaa7773ba7b2589db23c12a5a493a89afc8f1ccc81", + "final/C4/initial.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "final/C4/initial.stdout": "4096fbc0b1cf768d1ef678c1424446b6cd33085a331d8609c2aa4bb17d1e871e", + "final-captures/A1-after.png": "15712590fa34780abe1834ef2da5db109c3bb59d0d090ed844b243820d9e3b79", + "final-captures/A1-after.receipt.json": "3175088eb7380959964f55fb51bc273f17fdda7bf0663f571e3d4c2a476af0a9", + "final-captures/A1-after.snapshot.txt": "3e7266215f989fa7a3f5aa02ea58a772a79c174dfb102c764a10620320949249", + "final-captures/A1-initial.png": "9d64abdcdff72e1eab129ca7f95dffab74c1f3e54e9dbffe452f1eb0d8ebdad1", + "final-captures/A1-initial.receipt.json": "d7ab999a5fee9d99750316b4ad994d7bba4473c9e81e616551e2fafb27f4cdf0", + "final-captures/A1-initial.snapshot.txt": "ba37a58b624075d3c9c24ee84112997d8e5127e7c305ae08dcb4a5a775e1bf41", + "final-captures/A2-after.png": "ac504e9443402e7387760512b076177790e18d6baacff1be4e4bcb05bdcf6be4", + "final-captures/A2-after.receipt.json": "65b2d277d899051b1ee304dc880c3ca60ed7ec1519d2bb0075dc5f2bfb3ba6bb", + "final-captures/A2-after.snapshot.txt": "d3426e4f179ed444cf3305ac40f6fa85fa99d8da35ec85f1c1d895aaac180aba", + "final-captures/A2-initial.png": "7e2c5fb64e9b88335eadf16452826bc3a016f036dca1242412b653636f445ba1", + "final-captures/A2-initial.receipt.json": "ccc730033355a81e9311254901cd85e604de296d75180695c700da5d836a16be", + "final-captures/A2-initial.snapshot.txt": "fb386c3386fb743db72e2e332ee0c6c3e53a2ff72f46d4023dd66d6493d2388c", + "final-captures/B1-after.png": "1def36ef31771d7e8f4aec4029fc213108a5fd87650755c33c309189955ead8a", + "final-captures/B1-after.receipt.json": "b94124756d90df50069b5c01327420a579465f48f74292a08026dea34f34e70d", + "final-captures/B1-after.snapshot.txt": "7e4737be94f698283d00036370496deea71b876ef2d0b4b004f1aa1a16dafc4b", + "final-captures/B1-initial.png": "577a28b6c84ef2f978cde1f5c24ad398bbc194e327edce13b02574a69db6795b", + "final-captures/B1-initial.receipt.json": "8eea2ea898aef006ea94d27f3d03d9ec609276634541817988b497f6304481a2", + "final-captures/B1-initial.snapshot.txt": "ece211031f7018000ad0d8a8eae62f4903376d574a2bcbac455a8e5e65f47123", + "final-captures/B2-after.png": "be359e552a73260dbe41213da3a31879d1a6c243184108ffd5b5166303cb4f5a", + "final-captures/B2-after.receipt.json": "120e3e13537069dcb5b499b42b5d375e2478c20bd9785443833f0f814e695ac9", + "final-captures/B2-after.snapshot.txt": "19ee29c5c35486b740b94f640f568097a3654ed2be28207e1e995ee842af7f21", + "final-captures/B2-initial.png": "56e52827209d52d4a555a4aff2e4472e172909463883b48b435a775e067b2cb6", + "final-captures/B2-initial.receipt.json": "4dc0c13fa7e4459eb6c8e17d5245be5c13597223a7ba23e2b20259bbb0a7bfed", + "final-captures/B2-initial.snapshot.txt": "4fd44b6d176a3be13ea2ca09316da563975a31ff0ef29ba14d4101f0bbee4ef8", + "final-captures/B3-after.png": "a8a24c3a4cb4c05a91fc763bd5942fb11acbb974132835c833f4bfa4dd5cf61a", + "final-captures/B3-after.receipt.json": "5b594a9e78d5b8b25d521eef4dfdce1b3bdc5446deeaa072c258f6c394bc33ec", + "final-captures/B3-after.snapshot.txt": "958e920a82f7c69d31d8719e84264d7379f8124c1b3c0cafa6046841dc7bfa31", + "final-captures/B3-initial.png": "156c5cdf4ed96faf13eeeb867b31748fcb628e53e433a5dd0b2a446d915e6aa6", + "final-captures/B3-initial.receipt.json": "22eef61054936d9d415574b851eb99dfb5196b39ff4c751e4d95d1f2016ad087", + "final-captures/B3-initial.snapshot.txt": "9211f41382c9c48affa44e2d9f5709b743424589d89ea397fe750c0e7ed862c0", + "final-captures/B4-after.png": "e570d77e559d91d6675a0a278daa9598a1d2919b3d2ec817c37998b33e57d9d0", + "final-captures/B4-after.receipt.json": "867caeea7e31b289daaf3d9f448a04726e1712114b243c20c24eef72d22b15f3", + "final-captures/B4-after.snapshot.txt": "f837fb775513afcd2e431455f5206a35687229bd35ef7670b3a22d94df5c2a38", + "final-captures/B4-initial.png": "9ab9a3a1efd063c33d415f5b176f47b9c32b2d020eba9709fd91bab83587d5c7", + "final-captures/B4-initial.receipt.json": "c4cb27cfccbf47751c64222ac8d5e4ae3eadb8b9898fbf16f8f37179d27d445d", + "final-captures/B4-initial.snapshot.txt": "b7e3ca7e31322f7a08ba7b5757ae851df5b4de0e3488cb9ac0071ac593c201ac", + "final-captures/C1-after.png": "e23da14853880d95962edb9baa4da95ba289feada2eaf425abd7475f4cd14512", + "final-captures/C1-after.receipt.json": "8c7a33b72e649ad7246b04d9279f06d30434e24046e8b9ad7b92213d07ce6d13", + "final-captures/C1-after.snapshot.txt": "ea1535568455f67eef2f8e8bdeea5871580656218bd0a906bedf9bca2320931d", + "final-captures/C1-initial.png": "54edb774e71592077df9d0d4d173faf2f4efef92386caafd9d3afeed869fa5b8", + "final-captures/C1-initial.receipt.json": "0fc39a4966e9ad226a57069126e9d68dffd5e8851fd13f18ca8b6ed45ef11d1a", + "final-captures/C1-initial.snapshot.txt": "02f8bcb0a97ef996c62c5de5d3128a2d9c35a44708f0af1ead84d9de3ee18831", + "final-captures/C2-after.png": "5b0b17a527d0f94f0f173ee5b018f13a4e6ee0433e5c7fc61b62051d82302547", + "final-captures/C2-after.receipt.json": "2aa245be28632a7572e3cab5b356a9f74a3a2e9255d57cc8e1d585f8b00c8c68", + "final-captures/C2-after.snapshot.txt": "54599df1df88b87e7e874eebe71eac696cb94da6c2b71d26489adb14e480bb7e", + "final-captures/C2-initial.png": "9ca1deabaae751ce84130c7339f690fbd08eb3284cad18d2a0ada3d5b4d9e388", + "final-captures/C2-initial.receipt.json": "dbb7dbd1e15d257e0b22e3f2376398e0a6365fe99b5bc674fdb828ffc41152ba", + "final-captures/C2-initial.snapshot.txt": "f6f97d121bd14d49dfa7e6a789a882d29abd8f7d15bc5df38f3e55fe372b36a7", + "final-captures/C3-after.png": "ea77edfeff6b4b2408e49478e05d7b7a3ff5af9e819aa02ce234369ac926205d", + "final-captures/C3-after.receipt.json": "a85c86e3db954153ebd1d78fc17e527251acc4851824091eca7365ae1604a906", + "final-captures/C3-after.snapshot.txt": "8b29eab8edd572bc90235dab3c5cc710589c9f73a6f57c058f12779b78c4d591", + "final-captures/C3-initial.png": "8c70b8265c128052b4ceb3077c8f8117084a4ef121a7590cbba826469eb80a2e", + "final-captures/C3-initial.receipt.json": "cbc2500d2aa2e87a7c1b0f7dd35c4663c3e6cd2e97eb8c1ab7968cbf2cd40cb6", + "final-captures/C3-initial.snapshot.txt": "3513840a12180eee051fa072d238a44148d80402eb6960745bcefb6afd9dc152", + "final-captures/C4-after.png": "2f5bd7e4ef88186894e926c6bc2ccdea9fd2106ce9a7390997adc6e6b2530dad", + "final-captures/C4-after.receipt.json": "d35d5c6e3cb0b82e0bfcc51da7e4713475b922e0c8e1909e9afa5b1b677b100c", + "final-captures/C4-after.snapshot.txt": "abb07fa3110144a5747c86cdd233e27e8b72b64859f22583ee4cdee3fdc29248", + "final-captures/C4-initial.png": "fca5c6cbfdee31ffe683f13c6fcdaee01bd47afc241a21e5c3f941cbd5b193c9", + "final-captures/C4-initial.receipt.json": "aed023bced81a9c556e6d82ac432e88b723f5fb8fcf0b4433a818f3587836c87", + "final-captures/C4-initial.snapshot.txt": "8868019d647e240778728dfaa7773ba7b2589db23c12a5a493a89afc8f1ccc81" +} diff --git a/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/clock/widget.tsx b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/clock/widget.tsx new file mode 100644 index 00000000..add6eae1 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/clock/widget.tsx @@ -0,0 +1,77 @@ +import { useProvider, widget, type CanvasCtx, type TimeData } from "@weaver/sdk"; + +// The first widget: one provider, one canvas, no timers of its own. +// The `time` provider ticks once per second while subscribed; each tick +// re-renders the text nodes and redraws the dial. Nothing else runs. + +const weekdays: Record = { + Sun: "Sunday", Mon: "Monday", Tue: "Tuesday", Wed: "Wednesday", + Thu: "Thursday", Fri: "Friday", Sat: "Saturday", +}; +const months: Record = { + Jan: "January", Feb: "February", Mar: "March", Apr: "April", May: "May", Jun: "June", + Jul: "July", Aug: "August", Sep: "September", Oct: "October", Nov: "November", Dec: "December", +}; + +function longDate(time: TimeData): string { + return `${weekdays[time.weekday] ?? time.weekday}, ${months[time.month] ?? time.month} ${time.day}`; +} + +// Draws a small analog dial. Runs once per render (no `fps`), so it costs +// nothing between provider ticks. +function drawDial(ctx: CanvasCtx, time: TimeData): void { + ctx.clear(); + const cx = ctx.width / 2; + const cy = ctx.height / 2; + const radius = Math.min(cx, cy) - 2; + const hours = Number(time.hh) % 12; + const minutes = Number(time.mm); + const seconds = Number(time.ss); + + for (let index = 0; index < 12; index += 1) { + const angle = (index / 12) * Math.PI * 2 - Math.PI / 2; + const outer = radius; + const inner = index % 3 === 0 ? radius - 7 : radius - 4; + ctx.line( + cx + Math.cos(angle) * inner, cy + Math.sin(angle) * inner, + cx + Math.cos(angle) * outer, cy + Math.sin(angle) * outer, + index % 3 === 0 ? 2 : 1, index % 3 === 0 ? "#ffffffb3" : "#ffffff4d", + ); + } + + const hand = (turns: number, length: number, width: number, color: string) => { + const angle = turns * Math.PI * 2 - Math.PI / 2; + ctx.line(cx, cy, cx + Math.cos(angle) * length, cy + Math.sin(angle) * length, width, color); + }; + hand((hours + minutes / 60) / 12, radius * 0.52, 3, "#f5f6f8"); + hand((minutes + seconds / 60) / 60, radius * 0.78, 2, "#f5f6f8"); + hand(seconds / 60, radius * 0.86, 1, "#f59e0b"); + ctx.fillCircle(cx, cy, 3, "#f59e0b"); +} + +export default widget({ + name: "Clock", + size: [320, 132], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + return ( + + + + {time.hh}:{time.mm} + {time.ss} + + {longDate(time)} + + drawDial(ctx, time)} /> + + ); +}); diff --git a/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/pomodoro/widget.tsx b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/pomodoro/widget.tsx new file mode 100644 index 00000000..5084a0ce --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/examples/pomodoro/widget.tsx @@ -0,0 +1,131 @@ +import { useInterval, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// A tiny app: persisted state, one timer, buttons with native hover and +// pressed states, and a canvas ring that redraws once per second. + +type Mode = "focus" | "short" | "long"; + +const minutes: Record = { focus: 25, short: 5, long: 15 }; +const headings: Record = { focus: "FOCUS", short: "SHORT BREAK", long: "LONG BREAK" }; +const focusColor = "#ff7a59"; +const breakColor = "#5eead4"; + +interface TimerState { + mode: Mode; + remaining: number; // seconds + running: boolean; +} + +function clock(seconds: number): string { + return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`; +} + +// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out. +function drawRing(ctx: CanvasCtx, fraction: number, color: string): void { + ctx.clear(); + const cx = ctx.width / 2; + const cy = ctx.height / 2; + const outer = Math.min(cx, cy) - 2; + const inner = outer - 11; + const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60); + for (let index = 0; index < 60; index += 1) { + const angle = (index / 60) * Math.PI * 2 - Math.PI / 2; + const cos = Math.cos(angle); + const sin = Math.sin(angle); + ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : "#ffffff1f"); + } +} + +export default widget({ + name: "Pomodoro", + size: [300, 344], + anchor: { corner: "top-right", offset: [24, 180] }, +}, () => { + const [timer, setTimer] = useStorage("timer", { mode: "focus", remaining: minutes.focus * 60, running: false }); + const total = minutes[timer.mode] * 60; + const focus = timer.mode === "focus"; + const color = focus ? focusColor : breakColor; + + // Ticks once per second while running. While paused the interval is + // stretched to an hour so the widget does not wake up for nothing. + useInterval(() => { + setTimer((current) => { + if (!current.running) return current; + if (current.remaining <= 1) return { ...current, remaining: 0, running: false }; + return { ...current, remaining: current.remaining - 1 }; + }); + }, timer.running ? 1000 : 3_600_000); + + const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false }); + const chip = (mode: Mode, label: string) => { + const selected = timer.mode === mode; + return ( + + ); + }; + + return ( + + + {headings[timer.mode]} + {minutes[timer.mode]} MIN + + + + drawRing(ctx, timer.remaining / total, color)} /> + + {clock(timer.remaining)} + + {timer.remaining === 0 ? "DONE" : timer.running ? "RUNNING" : "PAUSED"} + + + + + + {chip("focus", "Focus")} + {chip("short", "Short break")} + {chip("long", "Long break")} + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/evidence/authoring-inputs/sdk/CONTRACT.md b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/sdk/CONTRACT.md new file mode 100644 index 00000000..2d81a346 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/authoring-inputs/sdk/CONTRACT.md @@ -0,0 +1,835 @@ +# @weaver/sdk — public API contract (v0.2 — M1 surface + the M2 amendment at the end) + +This is the authoring contract for Weaver widgets. It is the product's face: +agents learn Weaver from this file. Implementation must match it exactly; +anything not implementable in M1 must fail at `weaver check` with a clear +"arrives in M2" message — never silently no-op. + +Design invariants (from ADRs 0001/0003/0005/0009): +- One TSX module per widget; `widget()` is the default export. +- Styling is Tailwind-shaped `class` strings; arbitrary values allowed; + unknown utilities are check-time errors with fix-its. +- Idle-zero: no state change → no ops → no repaint. The SDK never polls. +- The reconciler runs in JS and emits retained-tree ops (never full frames). +- `weaver check` estimates the exported widget's lowered Native tree through + local components and one level of relative imports, taking the maximum across + conditional JSX returns and counting statically evident implicit text nodes. + Dynamic collections and unresolved component output remain subject to the + authoritative Native runtime node/depth limits. + +## Module shape + +```tsx +import { widget, useProvider, useState } from "@weaver/sdk"; + +export default widget({ + name: "Clock", + size: [240, 110], + anchor: { corner: "top-right", offset: [24, 24] }, +}, () => { + const time = useProvider("time"); + return ( + + + {time.hh}:{time.mm} + {time.ss} + + {time.weekday}, {time.month} {time.day} + + ); +}); +``` + +## `widget(config, component)` + +```ts +export function widget(config: WidgetConfig, component: () => JSX.Element): WidgetModule; + +export interface WidgetConfig { + name: string; + size: [width: number, height: number]; // logical px + anchor?: { + monitor?: "primary"; // M1: primary only + corner: "top-left" | "top-right" | "bottom-left" | "bottom-right"; + offset?: [x: number, y: number]; // default [24, 24] + }; + layer?: "desktop" | "normal" | "topmost"; // default "desktop" + clickThrough?: boolean; // default false + subscribe?: ("time")[]; // M1: "time" only; full list M2 + origins?: string[]; // declared API hosts; M1: parsed+validated, fetch arrives M2 + capabilities?: never[]; // M1: must be empty; ladder arrives M2 +} +``` + +`weaver check` validates config statically (it is extracted from the default +export at bundle time; config must be a literal object — no computed values). + +`anchor` is the widget's placement until the user drags it. Every widget is +draggable by its whole surface (buttons and sliders keep their interactions); +the dragged position is user state stored outside the widget — it survives +restarts and reinstalls, outranks `anchor`, and falls back to `anchor` when it +goes stale (e.g. its monitor was unplugged). Widget code cannot read or write +it (ADR 0016). + +## Hooks + +```ts +export function useState(initial: T | (() => T)): [T, (next: T | ((prev: T) => T)) => void]; +export function useRef(initial: T): { current: T }; +export function useEffect(fn: () => void | (() => void), deps?: unknown[]): void; +export function useInterval(fn: () => void, ms: number): void; // native-clocked, auto-cleaned +export function useProvider(name: "time"): TimeData; // M1: "time" only +export function useProviderSignal(name: "time"): Signal; + +export interface Signal { + readonly value: T; + subscribe(listener: (value: T) => void): () => void; + map(project: (value: T) => U): Signal; +} + +export interface TimeData { // updates once per second while subscribed + hh: string; mm: string; ss: string; // zero-padded locale-agnostic + weekday: string; month: string; // short names ("Sun", "Jul") + day: number; year: number; + epochMs: number; +} +``` + +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 names the hook in its +error: `useProviderSignal("audio") requires subscribe: ["audio"] in the widget +config`. + +`useProvider` is the declarative path: each value schedules a component render. +`useProviderSignal` is the high-frequency retained path: it updates `.value` +without rendering the component. A canvas samples `.value` inside `onFrame`. +A `` may contain one mapped signal, which updates only that native text +node; format the whole label in `signal.map(...)`. `subscribe` is for edge +transitions such as waking a paused canvas, not for rebuilding the tree on each +provider frame. `map` memoizes by source signal and projector identity. Define a +projector once outside the component (`const label = signal.map(format)`) so +unrelated renders reuse the binding instead of unsubscribing and resubscribing. + +## Hot swap +`weaver dev` evaluates a valid changed bundle in a fresh JS context before replacing the running one. +Root hook slots are seeded by position when slot kind and value type all match; refs keep `current`, while effects restart. +Any slot-count, kind, or type mismatch remounts every root hook; non-serializable values alone initialize fresh. +Evaluation failure leaves the prior context, window, and state running; window-config changes restart the process. + +## Elements (JSX intrinsics) + +| Element | M1 renders | Props beyond `class`/`children` | +|---|---|---| +| `` | yes | — | +| `` | yes | — | +| `` | yes | — (a styled box; column layout) | +| `` | yes | — (children: strings/numbers, or one `Signal`) | +| `` | yes | exactly one of literal `name` or literal `d`; custom paths also accept `viewBox`/`stroke`; no children | +| `` | check-error "arrives in M2" | `src` | +| ` // pressable box + …} /> // horizontal, drag+click + // LOCAL widget assets only in M2; + // remote images arrive in M3 +``` + +Handlers run in the widget's JS context; events route through the retained +tree (node id → handler). No hover/focus styling in M2 (arrives with state +variants, unscheduled). + +## `weaver.fetch` — the declared-origins network (ADR 0002) + +```ts +// Global in widget context (also exported from @weaver/sdk for typing): +function wfetch(url: string, init?: { + method?: "GET" | "POST"; + headers?: Record; + body?: string; +}): Promise<{ status: number; ok: boolean; text(): Promise; json(): Promise }>; +``` + +- HTTPS only. The URL's host must exactly match an entry in `config.origins`; + otherwise the promise rejects with + `OriginNotDeclared: add "api.example.com" to origins in your widget config`. +- `weaver check` statically flags string-literal fetch URLs whose host is not + declared. Runtime enforcement is authoritative. +- Timeout 15s. No cookies; redirects are returned rather than followed; total + request and response caps are 5 MB each. + +## `useStorage` — scoped persistence (quiet standard surface) + +```ts +function useStorage(key: string, initial: T): [T, (next: T | ((prev: T) => T)) => void]; +``` + +JSON-serializable values only; persisted per widget (survives restarts and +`weaver dev` reloads); 64 KB total quota per widget, over-quota writes throw. + +## Providers: `cpu` and `memory` (host-fed) + +```ts +useProvider("cpu") // { percent: number, perCore: number[] } 1 Hz +useProvider("memory") // { usedMb: number, totalMb: number, percent: number } 1 Hz +``` + +Delivered by `weaverd` (the host). `time` remains SDK-local. Subscribing +without the host running is a runtime error that names the fix (`weaver up`); +`weaver dev` auto-starts the host. + +`cpu.percent` is whole-machine utilization from 0–100, not the sum of cores; +`perCore` reports the same 0–100 utilization for each logical core. Memory +`usedMb` is physical memory that is not currently free or reclaimable idle +cache, `totalMb` is installed physical memory, and `percent` is their ratio. +These meanings stay platform-neutral even though each host uses its public OS +counters to project them. + +## The host and its CLI verbs + +``` +weaver up | down start/stop weaverd (singleton, tray-less in M2) +weaver pack write portable source to .weave +weaver install validate, own, build, register, and run source +weaver uninstall stop + unregister +weaver status table: name · pid · private-MB · cpu% · uptime (ADR 0005 billing) +``` + +Portable install amendment: `weaver pack ` writes a deterministic +`.weave` containing source, assets, declared surface, provenance, and lineage. +`weaver install ` validates that artifact, builds a +Weaver-owned source copy, and registers the owned path. Only `weaver dev` +registers a developer workspace by reference (ADR 0011). + +weaverd supervises widget processes (crash → restart with backoff, 3 strikes +→ stopped + noted in status), fans out providers over local IPC, and samples +per-widget cost. Registrations persist across host restarts. + +--- + +# Styling breadth amendment (v0.4) + +Everything above stands. This section grows with the numbered styling stack; +utilities not yet listed here remain loud `weaver check` errors. + +## PR 01: spacing and sizing + +The scale remains 1 unit = 4 logical px. Bracketed pixel values are accepted +where shown. Utilities are applied left-to-right; a later utility wins on the +same side or axis. Negative margins are supported; padding and sizes are +non-negative. + +| Utility | Maps to | +|---|---| +| `p-N`, `p-[Npx]` | uniform padding | +| `px/py/pt/pr/pb/pl-N`, bracketed `Npx` forms | directional padding; side values override uniform padding | +| `m/mx/my/mt/mr/mb/ml-N`, bracketed `Npx` forms, optional leading `-` | external per-side margin | +| `w-N`, `h-N`, bracketed `Npx` forms | fixed width or height | +| `w-full`, `h-full`, `w-A/B`, `h-A/B` | percentage of the parent's content box | +| `w-auto`, `h-auto` | clear an earlier size on that axis | +| `size-N`, `size-[Npx]`, `size-full` | set both axes together | +| `min-w/max-w/min-h/max-h-N`, bracketed `Npx` forms | per-axis size bounds | +| `aspect-square`, `aspect-video`, `aspect-[W/H]`, `aspect-[N]` | derive the missing axis when exactly one axis is definite | +| `aspect-auto` | clear an earlier aspect ratio | + +Percentage sizes are calculated from the parent's content box before margins; +min/max bounds then clamp the laid-out frame. `aspect-*` does nothing when both +axes are definite or both are automatic. + +## PR 02: flex completeness + +| Utility | Maps to | +|---|---| +| `justify-around`, `justify-evenly` | Tailwind main-axis free-space distribution | +| `grow-N`, `grow-[N]` | numeric flex-grow factor (`grow` remains 1) | +| `shrink`, `shrink-0` | opt in/out of compression below the preferred size | +| `self-auto/start/center/end/stretch` | per-child cross-axis alignment | +| `flex-wrap`, `flex-nowrap` | enable/disable row or column line wrapping | + +Weaver elements default to `shrink: 1`, matching Tailwind. When preferred +sizes overflow a line, eligible children give up space in proportion to their +available shrink capacity (preferred size minus min-size floor); `shrink-0` +children never compress. If all floors still exceed the container, overflow +remains explicit and the Native debug diagnostic fires. Wrapped lines use the +container's `gap` on both axes. `items-baseline` remains an end-alignment +approximation; true font baseline layout is outside this styling slice. + +## PR 09: overlay stacks and bounded overflow + +`` is the overlay sibling of `` and ``. Every child starts +at the stack's content-box origin, paints in child order, and uses its own +width, height, margin, and alignment utilities. Overlay composition therefore +uses ordinary child utilities such as `w-full h-full`; there is no positioned +layout API. + +| Utility | Maps to | +|---|---| +| `overflow-hidden` | clip descendant painting to this element's resolved rounded bounds | + +The clip applies to canvases, images, text, panels, and nested content. +Per-corner `rounded-*` utilities shape the mask, including asymmetric corners. +This is the intended way to give a canvas-backed visual rounded edges. An +opacity ancestor remains unsupported for ``; apply that opacity while +drawing the canvas instead. + +## PR 10: image fitting, rounded masks, and tiling + +```ts + + +``` + +`fit` accepts `cover`, `contain`, or `stretch`; omitted `fit` preserves the +existing `stretch` behavior. Existing uniform and per-corner `rounded-*` +utilities are applied directly to the image mask. `tile` repeats the image at +its natural logical-pixel size from the image element's top-left and takes +precedence over fit geometry; rounding still masks the tiled result. Image +sources remain local widget assets. + +## PR 11: native interaction states and press events + +`hover:` and `pressed:` are supported only for the five native-swappable +visual channels below. Every other state-prefixed utility is a loud +`weaver check` error naming these supported forms. + +| Utility | Native override | +|---|---| +| `hover:bg-`, `pressed:bg-` | background color | +| `hover:text-`, `pressed:text-` | foreground/text color | +| `hover:opacity-N`, `pressed:opacity-N` | node opacity (`N` is 0–100) | +| `hover:border-`, `pressed:border-` | border color; border width remains the base style | +| `hover:shadow-*`, `pressed:shadow-*` | complete box-shadow replacement, including named shadows, arbitrary shadows, `shadow-inner`, and `shadow-none` | + +Named Tailwind v4 colors, bracketed hex colors, and `/NN` alpha use the same +forms and values as their unprefixed counterparts. Overrides inherit every +base channel they do not name. Pressed wins over hover when both native states +are active; disabled elements use the base style. Swaps use retained native +state and its existing invalidation path: no JS callback, timer, polling, or +per-frame work is introduced. The earlier M2 note that hover styling was +unscheduled is superseded by this bounded surface. + +On a non-pressable node, `hover:` and `pressed:` utilities resolve against +the nearest pressable ancestor (` +``` + +`onPress` remains required on ` +- +- ++ ++ + {media.artPath +- ? +- : } +- +- {media.title || "Nothing playing"} +- {media.artist || media.album || (media.title ? "Unknown artist" : "Open a media app to begin")} +- {media.sourceApp || "Unknown source"} ++ ? ++ : ( ++ ++ ++ ++ )} ++ ++ ++ ++ ++ {hasTrack ? media.title : "Nothing playing"} ++ {hasTrack ? (media.artist || media.album || "Unknown artist") : "Play something in any app"} ++ ++ ++ ++ ++ ++ drawProgress(ctx, progress)} /> ++ ++ ++ ++ ++ ++ ++ {media.durationMs > 0 ? `${timestamp(media.positionMs)} / ${timestamp(media.durationMs)}` : media.sourceApp} ++ ++ + +- +- +- {Array.from({ length: segmentCount }, (_, index) => ( +- index < filled +- ? +- : +- ))} +- +- ++ ++ + ); + }); +diff --git a/examples/pomodoro/widget.tsx b/examples/pomodoro/widget.tsx +index 58d3cf3..5084a0c 100644 +--- a/examples/pomodoro/widget.tsx ++++ b/examples/pomodoro/widget.tsx +@@ -1,71 +1,129 @@ +-import { useInterval, useStorage, widget } from "@weaver/sdk"; ++import { useInterval, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +-interface PomodoroState { +- minutes: number; +- remaining: number; ++// A tiny app: persisted state, one timer, buttons with native hover and ++// pressed states, and a canvas ring that redraws once per second. ++ ++type Mode = "focus" | "short" | "long"; ++ ++const minutes: Record = { focus: 25, short: 5, long: 15 }; ++const headings: Record = { focus: "FOCUS", short: "SHORT BREAK", long: "LONG BREAK" }; ++const focusColor = "#ff7a59"; ++const breakColor = "#5eead4"; ++ ++interface TimerState { ++ mode: Mode; ++ remaining: number; // seconds + running: boolean; + } + ++function clock(seconds: number): string { ++ return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`; ++} ++ ++// 60 ticks around the dial; the lit arc shrinks clockwise as time runs out. ++function drawRing(ctx: CanvasCtx, fraction: number, color: string): void { ++ ctx.clear(); ++ const cx = ctx.width / 2; ++ const cy = ctx.height / 2; ++ const outer = Math.min(cx, cy) - 2; ++ const inner = outer - 11; ++ const lit = Math.ceil(Math.max(0, Math.min(1, fraction)) * 60); ++ for (let index = 0; index < 60; index += 1) { ++ const angle = (index / 60) * Math.PI * 2 - Math.PI / 2; ++ const cos = Math.cos(angle); ++ const sin = Math.sin(angle); ++ ctx.line(cx + cos * inner, cy + sin * inner, cx + cos * outer, cy + sin * outer, 2.5, index < lit ? color : "#ffffff1f"); ++ } ++} ++ + export default widget({ + name: "Pomodoro", +- size: [320, 210], +- anchor: { corner: "top-right", offset: [24, 158] }, ++ size: [300, 344], ++ anchor: { corner: "top-right", offset: [24, 180] }, + }, () => { +- const [timer, setTimer] = useStorage("timer", { +- minutes: 25, +- remaining: 25 * 60, +- running: false, +- }); ++ const [timer, setTimer] = useStorage("timer", { mode: "focus", remaining: minutes.focus * 60, running: false }); ++ const total = minutes[timer.mode] * 60; ++ const focus = timer.mode === "focus"; ++ const color = focus ? focusColor : breakColor; + ++ // Ticks once per second while running. While paused the interval is ++ // stretched to an hour so the widget does not wake up for nothing. + useInterval(() => { +- if (!timer.running) return; + setTimer((current) => { ++ if (!current.running) return current; + if (current.remaining <= 1) return { ...current, remaining: 0, running: false }; + return { ...current, remaining: current.remaining - 1 }; + }); +- }, 1000); ++ }, timer.running ? 1000 : 3_600_000); + +- const shownMinutes = Math.floor(timer.remaining / 60); +- const shownSeconds = timer.remaining % 60; +- const clock = `${String(shownMinutes).padStart(2, "0")}:${String(shownSeconds).padStart(2, "0")}`; ++ const select = (mode: Mode) => setTimer({ mode, remaining: minutes[mode] * 60, running: false }); ++ const chip = (mode: Mode, label: string) => { ++ const selected = timer.mode === mode; ++ return ( ++ ++ ); ++ }; + + return ( +- +- +- +- FOCUS TIMER +- {clock} ++ ++ ++ {headings[timer.mode]} ++ {minutes[timer.mode]} MIN ++ ++ ++ ++ drawRing(ctx, timer.remaining / total, color)} /> ++ ++ {clock(timer.remaining)} ++ ++ {timer.remaining === 0 ? "DONE" : timer.running ? "RUNNING" : "PAUSED"} ++ + +- {timer.running ? "Focusing" : "Ready"} ++ ++ ++ ++ {chip("focus", "Focus")} ++ {chip("short", "Short break")} ++ {chip("long", "Long break")} + +- +- +- Session length +- {timer.minutes} min +- +- { +- const rounded = Math.max(5, Math.round(minutes)); +- setTimer((current) => ({ ...current, minutes: rounded, remaining: current.running ? current.remaining : rounded * 60 })); +- }} +- /> +- +- ++ ++ + + + + +diff --git a/examples/retro-player-shell/GeistPixel-Square.ttf b/examples/retro-player-shell/GeistPixel-Square.ttf +deleted file mode 100644 +index caa0a61..0000000 +Binary files a/examples/retro-player-shell/GeistPixel-Square.ttf and /dev/null differ +diff --git a/examples/retro-player-shell/OFL.txt b/examples/retro-player-shell/OFL.txt +deleted file mode 100644 +index 04e95fc..0000000 +--- a/examples/retro-player-shell/OFL.txt ++++ /dev/null +@@ -1,93 +0,0 @@ +-Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) +- +-This Font Software is licensed under the SIL Open Font License, Version 1.1. +-This license is copied below, and is also available with a FAQ at: +-https://openfontlicense.org +- +- +------------------------------------------------------------ +-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +------------------------------------------------------------ +- +-PREAMBLE +-The goals of the Open Font License (OFL) are to stimulate worldwide +-development of collaborative font projects, to support the font creation +-efforts of academic and linguistic communities, and to provide a free and +-open framework in which fonts may be shared and improved in partnership +-with others. +- +-The OFL allows the licensed fonts to be used, studied, modified and +-redistributed freely as long as they are not sold by themselves. The +-fonts, including any derivative works, can be bundled, embedded, +-redistributed and/or sold with any software provided that any reserved +-names are not used by derivative works. The fonts and derivatives, +-however, cannot be released under any other type of license. The +-requirement for fonts to remain under this license does not apply +-to any document created using the fonts or their derivatives. +- +-DEFINITIONS +-"Font Software" refers to the set of files released by the Copyright +-Holder(s) under this license and clearly marked as such. This may +-include source files, build scripts and documentation. +- +-"Reserved Font Name" refers to any names specified as such after the +-copyright statement(s). +- +-"Original Version" refers to the collection of Font Software components as +-distributed by the Copyright Holder(s). +- +-"Modified Version" refers to any derivative made by adding to, deleting, +-or substituting -- in part or in whole -- any of the components of the +-Original Version, by changing formats or by porting the Font Software to a +-new environment. +- +-"Author" refers to any designer, engineer, programmer, technical +-writer or other person who contributed to the Font Software. +- +-PERMISSION & CONDITIONS +-Permission is hereby granted, free of charge, to any person obtaining +-a copy of the Font Software, to use, study, copy, merge, embed, modify, +-redistribute, and sell modified and unmodified copies of the Font +-Software, subject to the following conditions: +- +-1) Neither the Font Software nor any of its individual components, +-in Original or Modified Versions, may be sold by itself. +- +-2) Original or Modified Versions of the Font Software may be bundled, +-redistributed and/or sold with any software, provided that each copy +-contains the above copyright notice and this license. These can be +-included either as stand-alone text files, human-readable headers or +-in the appropriate machine-readable metadata fields within text or +-binary files as long as those fields can be easily viewed by the user. +- +-3) No Modified Version of the Font Software may use the Reserved Font +-Name(s) unless explicit written permission is granted by the corresponding +-Copyright Holder. This restriction only applies to the primary font name as +-presented to the users. +- +-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +-Software shall not be used to promote, endorse or advertise any +-Modified Version, except to acknowledge the contribution(s) of the +-Copyright Holder(s) and the Author(s) or with their explicit written +-permission. +- +-5) The Font Software, modified or unmodified, in part or in whole, +-must be distributed entirely under this license, and must not be +-distributed under any other license. The requirement for fonts to +-remain under this license does not apply to any document created +-using the Font Software. +- +-TERMINATION +-This license becomes null and void if any of the above conditions are +-not met. +- +-DISCLAIMER +-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +-OTHER DEALINGS IN THE FONT SOFTWARE. +\ No newline at end of file +diff --git a/examples/retro-player-shell/assets/grille.png b/examples/retro-player-shell/assets/grille.png +deleted file mode 100644 +index b264f7d..0000000 +Binary files a/examples/retro-player-shell/assets/grille.png and /dev/null differ +diff --git a/examples/retro-player-shell/assets/night-bloom.jpg b/examples/retro-player-shell/assets/night-bloom.jpg +deleted file mode 100644 +index 1f9e46f..0000000 +Binary files a/examples/retro-player-shell/assets/night-bloom.jpg and /dev/null differ +diff --git a/examples/retro-player-shell/widget.tsx b/examples/retro-player-shell/widget.tsx +deleted file mode 100644 +index 9f19159..0000000 +--- a/examples/retro-player-shell/widget.tsx ++++ /dev/null +@@ -1,69 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-const noop = () => {}; +- +-export default widget({ +- name: "Retro Player Shell", +- size: [820, 580], +- anchor: { corner: "top-right", offset: [32, 32] }, +-}, () => ( +- +- +- +- +- WEAVER HI-FI SYSTEM +- MODEL WR-04 / STATIC SIGNAL +- +- +- 10:24 PM +- +- +- +- +- +- +- +- +- +- NIGHT BLOOM +- +- 03:18 / 05:42 +- +- +- SECOND NATURE +- CHANNEL SURFING / SIDE A +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-)); +diff --git a/examples/styling-fonts/GeistPixel-Square.ttf b/examples/styling-fonts/GeistPixel-Square.ttf +deleted file mode 100644 +index caa0a61..0000000 +Binary files a/examples/styling-fonts/GeistPixel-Square.ttf and /dev/null differ +diff --git a/examples/styling-fonts/OFL.txt b/examples/styling-fonts/OFL.txt +deleted file mode 100644 +index 04e95fc..0000000 +--- a/examples/styling-fonts/OFL.txt ++++ /dev/null +@@ -1,93 +0,0 @@ +-Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) +- +-This Font Software is licensed under the SIL Open Font License, Version 1.1. +-This license is copied below, and is also available with a FAQ at: +-https://openfontlicense.org +- +- +------------------------------------------------------------ +-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +------------------------------------------------------------ +- +-PREAMBLE +-The goals of the Open Font License (OFL) are to stimulate worldwide +-development of collaborative font projects, to support the font creation +-efforts of academic and linguistic communities, and to provide a free and +-open framework in which fonts may be shared and improved in partnership +-with others. +- +-The OFL allows the licensed fonts to be used, studied, modified and +-redistributed freely as long as they are not sold by themselves. The +-fonts, including any derivative works, can be bundled, embedded, +-redistributed and/or sold with any software provided that any reserved +-names are not used by derivative works. The fonts and derivatives, +-however, cannot be released under any other type of license. The +-requirement for fonts to remain under this license does not apply +-to any document created using the fonts or their derivatives. +- +-DEFINITIONS +-"Font Software" refers to the set of files released by the Copyright +-Holder(s) under this license and clearly marked as such. This may +-include source files, build scripts and documentation. +- +-"Reserved Font Name" refers to any names specified as such after the +-copyright statement(s). +- +-"Original Version" refers to the collection of Font Software components as +-distributed by the Copyright Holder(s). +- +-"Modified Version" refers to any derivative made by adding to, deleting, +-or substituting -- in part or in whole -- any of the components of the +-Original Version, by changing formats or by porting the Font Software to a +-new environment. +- +-"Author" refers to any designer, engineer, programmer, technical +-writer or other person who contributed to the Font Software. +- +-PERMISSION & CONDITIONS +-Permission is hereby granted, free of charge, to any person obtaining +-a copy of the Font Software, to use, study, copy, merge, embed, modify, +-redistribute, and sell modified and unmodified copies of the Font +-Software, subject to the following conditions: +- +-1) Neither the Font Software nor any of its individual components, +-in Original or Modified Versions, may be sold by itself. +- +-2) Original or Modified Versions of the Font Software may be bundled, +-redistributed and/or sold with any software, provided that each copy +-contains the above copyright notice and this license. These can be +-included either as stand-alone text files, human-readable headers or +-in the appropriate machine-readable metadata fields within text or +-binary files as long as those fields can be easily viewed by the user. +- +-3) No Modified Version of the Font Software may use the Reserved Font +-Name(s) unless explicit written permission is granted by the corresponding +-Copyright Holder. This restriction only applies to the primary font name as +-presented to the users. +- +-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +-Software shall not be used to promote, endorse or advertise any +-Modified Version, except to acknowledge the contribution(s) of the +-Copyright Holder(s) and the Author(s) or with their explicit written +-permission. +- +-5) The Font Software, modified or unmodified, in part or in whole, +-must be distributed entirely under this license, and must not be +-distributed under any other license. The requirement for fonts to +-remain under this license does not apply to any document created +-using the Font Software. +- +-TERMINATION +-This license becomes null and void if any of the above conditions are +-not met. +- +-DISCLAIMER +-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +-OTHER DEALINGS IN THE FONT SOFTWARE. +\ No newline at end of file +diff --git a/examples/styling-fonts/tsconfig.json b/examples/styling-fonts/tsconfig.json +deleted file mode 100644 +index 4248ebc..0000000 +--- a/examples/styling-fonts/tsconfig.json ++++ /dev/null +@@ -1,19 +0,0 @@ +-{ +- "compilerOptions": { +- "target": "ES2020", +- "module": "ESNext", +- "moduleResolution": "Bundler", +- "strict": true, +- "noEmit": true, +- "skipLibCheck": true, +- "jsx": "react-jsx", +- "jsxImportSource": "@weaver/sdk", +- "types": [], +- "baseUrl": ".", +- "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] +- } +- }, +- "include": ["widget.tsx"] +-} +diff --git a/examples/styling-fonts/widget.tsx b/examples/styling-fonts/widget.tsx +deleted file mode 100644 +index 2758b29..0000000 +--- a/examples/styling-fonts/widget.tsx ++++ /dev/null +@@ -1,17 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-export default widget({ +- name: "Styling Fonts", +- size: [420, 250], +- anchor: { corner: "top-right", offset: [24, 24] }, +-}, () => ( +- +- +- BUNDLED PIXEL FACE +- Built-in sans · weight ladder +- Built-in mono 02:47:19 +- +- A single custom face keeps its own outlines for every requested weight; add weight-suffixed files to select real variants. +- +- +-)); +diff --git a/examples/styling-icons/widget.tsx b/examples/styling-icons/widget.tsx +deleted file mode 100644 +index 85f14ba..0000000 +--- a/examples/styling-icons/widget.tsx ++++ /dev/null +@@ -1,44 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-export default widget({ +- name: "Styling Icons", +- size: [500, 350], +- anchor: { corner: "top-right", offset: [24, 24] }, +-}, () => ( +- +- +- +- +- +- Bundle-time vector icons +- Full Lucide catalog · tree-shaken M/L/C/Z paths +- +- +- +- +- +- +- +- +- +- +- +- +- named +- +- +- +- custom fill +- +- +- +- custom stroke +- +- +- +- currentColor +- +- +- +- +-)); +diff --git a/examples/styling-interaction/tsconfig.json b/examples/styling-interaction/tsconfig.json +deleted file mode 100644 +index fb8488e..0000000 +--- a/examples/styling-interaction/tsconfig.json ++++ /dev/null +@@ -1,17 +0,0 @@ +-{ +- "compilerOptions": { +- "target": "ES2020", +- "module": "ESNext", +- "moduleResolution": "Bundler", +- "strict": true, +- "noEmit": true, +- "jsx": "react-jsx", +- "jsxImportSource": "@weaver/sdk", +- "baseUrl": ".", +- "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] +- } +- }, +- "include": ["widget.tsx"] +-} +diff --git a/examples/styling-shadows/widget.tsx b/examples/styling-shadows/widget.tsx +deleted file mode 100644 +index b275803..0000000 +--- a/examples/styling-shadows/widget.tsx ++++ /dev/null +@@ -1,19 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-export default widget({ +- name: "Styling Shadows", +- size: [380, 250], +- anchor: { corner: "top-right", offset: [24, 24] }, +-}, () => ( +- +- +- Shadow breadth +- +- +- +- +- +- outset · inset · arbitrary +- +- +-)); +diff --git a/examples/styling-spacing/tsconfig.json b/examples/styling-spacing/tsconfig.json +deleted file mode 100644 +index 4248ebc..0000000 +--- a/examples/styling-spacing/tsconfig.json ++++ /dev/null +@@ -1,19 +0,0 @@ +-{ +- "compilerOptions": { +- "target": "ES2020", +- "module": "ESNext", +- "moduleResolution": "Bundler", +- "strict": true, +- "noEmit": true, +- "skipLibCheck": true, +- "jsx": "react-jsx", +- "jsxImportSource": "@weaver/sdk", +- "types": [], +- "baseUrl": ".", +- "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] +- } +- }, +- "include": ["widget.tsx"] +-} +diff --git a/examples/styling-spacing/widget.tsx b/examples/styling-spacing/widget.tsx +deleted file mode 100644 +index 145cc9b..0000000 +--- a/examples/styling-spacing/widget.tsx ++++ /dev/null +@@ -1,23 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-export default widget({ +- name: "Styling Spacing", +- size: [320, 200], +- anchor: { corner: "top-right", offset: [24, 24] }, +-}, () => ( +- +- Styling breadth +- +- +- +- +- +- +- +- Directional padding +- 02:47 · Fractions, bounds, aspect ratio, and clamped text +- +- +- +- +-)); +diff --git a/examples/styling-stack/tsconfig.json b/examples/styling-stack/tsconfig.json +deleted file mode 100644 +index fb8488e..0000000 +--- a/examples/styling-stack/tsconfig.json ++++ /dev/null +@@ -1,17 +0,0 @@ +-{ +- "compilerOptions": { +- "target": "ES2020", +- "module": "ESNext", +- "moduleResolution": "Bundler", +- "strict": true, +- "noEmit": true, +- "jsx": "react-jsx", +- "jsxImportSource": "@weaver/sdk", +- "baseUrl": ".", +- "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] +- } +- }, +- "include": ["widget.tsx"] +-} +diff --git a/examples/styling-stack/widget.tsx b/examples/styling-stack/widget.tsx +deleted file mode 100644 +index 8b17b03..0000000 +--- a/examples/styling-stack/widget.tsx ++++ /dev/null +@@ -1,24 +0,0 @@ +-import { widget } from "@weaver/sdk"; +- +-export default widget({ +- name: "Styling Stack", +- size: [420, 280], +- anchor: { corner: "top-right", offset: [24, 24] }, +-}, () => ( +- +- +- Overlay stack +- +- +- +- +- Children paint in order +- +- rounded clip +- +- +- +- +- +- +-)); +diff --git a/examples/styling-text/tsconfig.json b/examples/styling-text/tsconfig.json +deleted file mode 100644 +index 4248ebc..0000000 +--- a/examples/styling-text/tsconfig.json ++++ /dev/null +@@ -1,19 +0,0 @@ +-{ +- "compilerOptions": { +- "target": "ES2020", +- "module": "ESNext", +- "moduleResolution": "Bundler", +- "strict": true, +- "noEmit": true, +- "skipLibCheck": true, +- "jsx": "react-jsx", +- "jsxImportSource": "@weaver/sdk", +- "types": [], +- "baseUrl": ".", +- "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] +- } +- }, +- "include": ["widget.tsx"] +-} +diff --git a/examples/system/widget.tsx b/examples/system/widget.tsx +index 34f80c6..25932fe 100644 +--- a/examples/system/widget.tsx ++++ b/examples/system/widget.tsx +@@ -1,27 +1,102 @@ +-import { useProvider, widget } from "@weaver/sdk"; ++import { useEffect, useProvider, widget, type CanvasCtx, type CpuData } from "@weaver/sdk"; ++ ++// CPU and memory from the host at 1 Hz. The text nodes update in the retained ++// tree; the three canvases redraw once per provider frame (no `fps`, so no ++// frame clock of their own). ++ ++const historyLength = 60; ++const history: number[] = []; ++ ++const accent = "#2dd4bf"; ++const accentSoft = "#2dd4bf33"; ++const track = "#ffffff14"; ++ ++function gigabytes(mb: number): string { ++ return (mb / 1024).toFixed(1); ++} ++ ++function drawHistory(ctx: CanvasCtx): void { ++ ctx.clear(); ++ const step = ctx.width / (historyLength - 1); ++ const floor = ctx.height - 1; ++ const points: number[] = []; ++ const offset = historyLength - history.length; ++ for (let index = 0; index < history.length; index += 1) { ++ const x = (offset + index) * step; ++ const y = floor - (history[index] / 100) * (ctx.height - 4); ++ // Area under the line: one thin column per sample. ++ ctx.fillRect(x, y, Math.max(1, step), floor - y, accentSoft); ++ points.push(x, y); ++ } ++ ctx.line(0, floor, ctx.width, floor, 1, track); ++ if (points.length >= 4) ctx.polyline(points, 1.5, accent); ++} ++ ++function drawCores(ctx: CanvasCtx, cpu: CpuData): void { ++ ctx.clear(); ++ const count = Math.max(1, cpu.perCore.length); ++ const gap = 3; ++ const width = (ctx.width - gap * (count - 1)) / count; ++ for (let index = 0; index < count; index += 1) { ++ const x = index * (width + gap); ++ const load = Math.max(0, Math.min(1, (cpu.perCore[index] ?? 0) / 100)); ++ ctx.fillRoundRect(x, 0, width, ctx.height, 2, track); ++ const height = Math.max(2, load * ctx.height); ++ ctx.fillRoundRect(x, ctx.height - height, width, height, 2, load > 0.85 ? "#fb7185" : accent); ++ } ++} ++ ++function drawMemory(ctx: CanvasCtx, percent: number): void { ++ ctx.clear(); ++ ctx.fillRoundRect(0, 0, ctx.width, ctx.height, ctx.height / 2, track); ++ const width = Math.max(ctx.height, (Math.max(0, Math.min(100, percent)) / 100) * ctx.width); ++ ctx.fillRoundRect(0, 0, width, ctx.height, ctx.height / 2, "#f5f6f8"); ++} + + export default widget({ + name: "System Monitor", +- size: [300, 150], ++ size: [340, 196], + anchor: { corner: "top-left", offset: [24, 24] }, + subscribe: ["cpu", "memory"], + }, () => { + const cpu = useProvider("cpu"); + const memory = useProvider("memory"); ++ useEffect(() => { ++ history.push(cpu.percent); ++ if (history.length > historyLength) history.shift(); ++ }, [cpu]); ++ + return ( +- +- SYSTEM +- +- +- CPU +- {cpu.percent.toFixed(1)}% +- +- +- MEMORY +- {memory.usedMb} MB +- of {memory.totalMb} MB · {memory.percent.toFixed(1)}% ++ ++ ++ ++ CPU ++ ++ {cpu.percent.toFixed(0)} ++ % ++ + ++ + ++ ++ drawCores(ctx, cpu)} /> ++ ++ ++ ++ MEMORY ++ ++ {gigabytes(memory.usedMb)} ++ / {gigabytes(memory.totalMb)} GB ++ ++ ++ drawMemory(ctx, memory.percent)} /> ++ + + ); + }); +diff --git a/scripts/verify-dpi.ps1 b/scripts/verify-dpi.ps1 +index 05745ef..9645c96 100644 +--- a/scripts/verify-dpi.ps1 ++++ b/scripts/verify-dpi.ps1 +@@ -131,7 +131,7 @@ $RepoRoot = [IO.Path]::GetFullPath($RepoRoot) + $OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory) + [IO.Directory]::CreateDirectory($OutputDirectory) | Out-Null + $cli = Join-Path $RepoRoot "cli\dist\index.js" +-$fixture = Join-Path $RepoRoot "examples\dpi-diagnostic" ++$fixture = Join-Path $RepoRoot "test\fixtures\dpi-diagnostic" + $results = [ordered]@{ + startedUtc = [DateTime]::UtcNow.ToString("o") + repoRoot = $RepoRoot +diff --git a/scripts/verify-gradient-gpu.ps1 b/scripts/verify-gradient-gpu.ps1 +index 3038ae8..c3be1f2 100644 +--- a/scripts/verify-gradient-gpu.ps1 ++++ b/scripts/verify-gradient-gpu.ps1 +@@ -51,7 +51,7 @@ $OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory) + [IO.Directory]::CreateDirectory($OutputDirectory) | Out-Null + $NativeRoot = Join-Path $RepoRoot "runtime\native-sdk" + $Cli = Join-Path $RepoRoot "cli\dist\index.js" +-$Example = Join-Path $RepoRoot "examples\gradient-stack" ++$Example = Join-Path $RepoRoot "test\fixtures\gradient-stack" + $CaptureHelper = Join-Path $RepoRoot "renderer\zig-out\bin\weaver-window-capture.exe" + $StateRoot = Join-Path $OutputDirectory "state" + $ResultPath = Join-Path $OutputDirectory "results.json" +diff --git a/sdk/CONTRACT.md b/sdk/CONTRACT.md +index aaf8c6e..2d81a34 100644 +--- a/sdk/CONTRACT.md ++++ b/sdk/CONTRACT.md +@@ -304,7 +304,7 @@ actionable — the primary reader is an agent in a fix-it loop. + + ## The conjure skill + +-`skills/conjure-widget/SKILL.md` in this repo: teaches an agent to go from a ++`.agents/skills/conjure-widget/SKILL.md` in this repo: teaches an agent to go from a + user's description to `weaver init` → edit widget.tsx → `weaver check` → + `weaver dev`, including this contract inline or by reference, the class table, + and the M1 boundaries (no providers beyond time, no input elements yet). +diff --git a/test/capture-smoke.mjs b/test/capture-smoke.mjs +index b350e75..66b72cb 100644 +--- a/test/capture-smoke.mjs ++++ b/test/capture-smoke.mjs +@@ -12,17 +12,17 @@ const fixedClock = "2026-08-24T17:30:00.000Z"; + + try { + const clock = capture("clock", "examples/clock"); +- assert.deepEqual([clock.output.widthPx, clock.output.heightPx], [240, 110]); ++ assert.deepEqual([clock.output.widthPx, clock.output.heightPx], [320, 132]); + + const resizedClock = capture("clock-resized", "examples/clock", [ + "--action-file", join(root, "test", "capture", "resize.actions"), + ]); + assert.deepEqual([resizedClock.output.widthPx, resizedClock.output.heightPx], [962, 719]); + +- const text = capture("styling-text", "examples/styling-text"); ++ const text = capture("styling-text", "test/fixtures/styling-text"); + assert.ok(text.renderer.pixelsDifferentFromClear > 0); + +- const images = capture("styling-images", "examples/styling-images"); ++ const images = capture("styling-images", "test/fixtures/styling-images"); + assert.equal(images.renderer.images, 3); + assert.equal(images.pending.images, 0); + +@@ -34,16 +34,16 @@ try { + assert.match(snapshotText(pomodoroAfter), /role=button name="Pause"/); + assert.match(snapshotText(pomodoroAfter), /role=text name="24:59"/); + +- const interactionBefore = capture("interaction-before", "examples/styling-interaction"); +- const interactionAfter = capture("interaction-after", "examples/styling-interaction", [ ++ const interactionBefore = capture("interaction-before", "test/fixtures/styling-interaction"); ++ const interactionAfter = capture("interaction-after", "test/fixtures/styling-interaction", [ + "--action-file", join(root, "test", "capture", "styling-interaction.actions"), + ]); + assert.notEqual(imageHash(interactionBefore), imageHash(interactionAfter)); + assert.match(snapshotText(interactionAfter), /role=slider .* value=0\.9/); + assert.match(snapshotText(interactionAfter), /role=text name="90%"/); + +- const tideglassBefore = capture("tideglass-before", "examples/tideglass"); +- const tideglassAfter = capture("tideglass-after", "examples/tideglass", [ ++ const tideglassBefore = capture("tideglass-before", "test/fixtures/tideglass"); ++ const tideglassAfter = capture("tideglass-after", "test/fixtures/tideglass", [ + "--action-file", join(root, "test", "capture", "tideglass.actions"), + ]); + assert.notEqual(imageHash(tideglassBefore), imageHash(tideglassAfter)); +@@ -52,6 +52,24 @@ try { + assert.deepEqual(tideglassAfter.interactions.actions, ["click", "click"]); + assert.equal(tideglassAfter.pending.timers, 0); + ++ const system = capture("system", "examples/system", [ ++ "--provider-fixture", join(root, "test", "capture", "system.provider.json"), ++ ]); ++ assert.match(snapshotText(system), /role=text name="MEMORY"/); ++ assert.match(snapshotText(system), /role=text name="9\.6"/); ++ ++ const nowPlaying = capture("now-playing", "examples/now-playing", [ ++ "--provider-fixture", join(root, "test", "capture", "noro.provider.json"), ++ ]); ++ assert.match(snapshotText(nowPlaying), /role=button name="Pause"/); ++ assert.match(snapshotText(nowPlaying), /role=button name="Seek"/); ++ assert.match(snapshotText(nowPlaying), /name="0:42 \/ 3:00"/); ++ ++ // The forecast fetch is real network and may or may not land inside the ++ // capture window, so only the static frame is asserted. ++ const weather = capture("weather", "examples/weather"); ++ assert.match(snapshotText(weather), /role=text name="San Francisco"/); ++ + const noro = capture("noro", "examples/noro-shell", [ + "--provider-fixture", join(root, "test", "capture", "noro.provider.json"), + ]); +@@ -158,6 +176,9 @@ try { + ]); + assert.equal(ambiguous.error?.name, "CaptureTargetAmbiguous"); + assert.deepEqual(ambiguous.error?.candidates?.map(({ role, name }) => ({ role, name })), [ ++ { role: "button", name: "Focus" }, ++ { role: "button", name: "Short break" }, ++ { role: "button", name: "Long break" }, + { role: "button", name: "Start" }, + { role: "button", name: "Reset" }, + ]); +diff --git a/examples/m4b-parity/tsconfig.json b/test/fixtures/dpi-diagnostic/tsconfig.json +similarity index 73% +rename from examples/m4b-parity/tsconfig.json +rename to test/fixtures/dpi-diagnostic/tsconfig.json +index daa9010..47cf729 100644 +--- a/examples/m4b-parity/tsconfig.json ++++ b/test/fixtures/dpi-diagnostic/tsconfig.json +@@ -1,5 +1,5 @@ + { +- "extends": "../../sdk/tsconfig.json", ++ "extends": "../../../sdk/tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk" +diff --git a/examples/dpi-diagnostic/widget.tsx b/test/fixtures/dpi-diagnostic/widget.tsx +similarity index 100% +rename from examples/dpi-diagnostic/widget.tsx +rename to test/fixtures/dpi-diagnostic/widget.tsx +diff --git a/examples/retro-player-shell/tsconfig.json b/test/fixtures/gradient-stack/tsconfig.json +similarity index 70% +rename from examples/retro-player-shell/tsconfig.json +rename to test/fixtures/gradient-stack/tsconfig.json +index fb8488e..3baf8db 100644 +--- a/examples/retro-player-shell/tsconfig.json ++++ b/test/fixtures/gradient-stack/tsconfig.json +@@ -9,8 +9,8 @@ + "jsxImportSource": "@weaver/sdk", + "baseUrl": ".", + "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] ++ "@weaver/sdk": ["../../../sdk/index.d.ts"], ++ "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] + } + }, + "include": ["widget.tsx"] +diff --git a/examples/gradient-stack/widget.tsx b/test/fixtures/gradient-stack/widget.tsx +similarity index 100% +rename from examples/gradient-stack/widget.tsx +rename to test/fixtures/gradient-stack/widget.tsx +diff --git a/examples/dpi-diagnostic/tsconfig.json b/test/fixtures/m4b-parity/tsconfig.json +similarity index 73% +rename from examples/dpi-diagnostic/tsconfig.json +rename to test/fixtures/m4b-parity/tsconfig.json +index daa9010..47cf729 100644 +--- a/examples/dpi-diagnostic/tsconfig.json ++++ b/test/fixtures/m4b-parity/tsconfig.json +@@ -1,5 +1,5 @@ + { +- "extends": "../../sdk/tsconfig.json", ++ "extends": "../../../sdk/tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk" +diff --git a/examples/m4b-parity/widget.tsx b/test/fixtures/m4b-parity/widget.tsx +similarity index 100% +rename from examples/m4b-parity/widget.tsx +rename to test/fixtures/m4b-parity/widget.tsx +diff --git a/examples/m4b-synthetic/tsconfig.json b/test/fixtures/m4b-synthetic/tsconfig.json +similarity index 100% +rename from examples/m4b-synthetic/tsconfig.json +rename to test/fixtures/m4b-synthetic/tsconfig.json +diff --git a/examples/m4b-synthetic/widget.tsx b/test/fixtures/m4b-synthetic/widget.tsx +similarity index 100% +rename from examples/m4b-synthetic/widget.tsx +rename to test/fixtures/m4b-synthetic/widget.tsx +diff --git a/examples/styling-images/assets/weaver.png b/test/fixtures/styling-images/assets/weaver.png +similarity index 100% +rename from examples/styling-images/assets/weaver.png +rename to test/fixtures/styling-images/assets/weaver.png +diff --git a/examples/styling-icons/tsconfig.json b/test/fixtures/styling-images/tsconfig.json +similarity index 70% +rename from examples/styling-icons/tsconfig.json +rename to test/fixtures/styling-images/tsconfig.json +index fb8488e..3baf8db 100644 +--- a/examples/styling-icons/tsconfig.json ++++ b/test/fixtures/styling-images/tsconfig.json +@@ -9,8 +9,8 @@ + "jsxImportSource": "@weaver/sdk", + "baseUrl": ".", + "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] ++ "@weaver/sdk": ["../../../sdk/index.d.ts"], ++ "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] + } + }, + "include": ["widget.tsx"] +diff --git a/examples/styling-images/widget.tsx b/test/fixtures/styling-images/widget.tsx +similarity index 100% +rename from examples/styling-images/widget.tsx +rename to test/fixtures/styling-images/widget.tsx +diff --git a/examples/styling-images/tsconfig.json b/test/fixtures/styling-interaction/tsconfig.json +similarity index 70% +rename from examples/styling-images/tsconfig.json +rename to test/fixtures/styling-interaction/tsconfig.json +index fb8488e..3baf8db 100644 +--- a/examples/styling-images/tsconfig.json ++++ b/test/fixtures/styling-interaction/tsconfig.json +@@ -9,8 +9,8 @@ + "jsxImportSource": "@weaver/sdk", + "baseUrl": ".", + "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] ++ "@weaver/sdk": ["../../../sdk/index.d.ts"], ++ "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] + } + }, + "include": ["widget.tsx"] +diff --git a/examples/styling-interaction/widget.tsx b/test/fixtures/styling-interaction/widget.tsx +similarity index 100% +rename from examples/styling-interaction/widget.tsx +rename to test/fixtures/styling-interaction/widget.tsx +diff --git a/examples/styling-shadows/tsconfig.json b/test/fixtures/styling-text/tsconfig.json +similarity index 73% +rename from examples/styling-shadows/tsconfig.json +rename to test/fixtures/styling-text/tsconfig.json +index 4248ebc..318a70a 100644 +--- a/examples/styling-shadows/tsconfig.json ++++ b/test/fixtures/styling-text/tsconfig.json +@@ -11,8 +11,8 @@ + "types": [], + "baseUrl": ".", + "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] ++ "@weaver/sdk": ["../../../sdk/index.d.ts"], ++ "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] + } + }, + "include": ["widget.tsx"] +diff --git a/examples/styling-text/widget.tsx b/test/fixtures/styling-text/widget.tsx +similarity index 100% +rename from examples/styling-text/widget.tsx +rename to test/fixtures/styling-text/widget.tsx +diff --git a/examples/tideglass/tsconfig.json b/test/fixtures/tideglass/tsconfig.json +similarity index 74% +rename from examples/tideglass/tsconfig.json +rename to test/fixtures/tideglass/tsconfig.json +index 8c42381..e02d05f 100644 +--- a/examples/tideglass/tsconfig.json ++++ b/test/fixtures/tideglass/tsconfig.json +@@ -11,8 +11,8 @@ + "types": [], + "baseUrl": ".", + "paths": { +- "@weaver/sdk": ["../../sdk/index.d.ts"], +- "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] ++ "@weaver/sdk": ["../../../sdk/index.d.ts"], ++ "@weaver/sdk/jsx-runtime": ["../../../sdk/jsx-runtime.d.ts"] + } + }, + "include": [ +diff --git a/examples/tideglass/widget.tsx b/test/fixtures/tideglass/widget.tsx +similarity index 100% +rename from examples/tideglass/widget.tsx +rename to test/fixtures/tideglass/widget.tsx diff --git a/experiments/render-loop-cadence/astra/evidence/git-status-after.txt b/experiments/render-loop-cadence/astra/evidence/git-status-after.txt new file mode 100644 index 00000000..e7fa7c87 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/git-status-after.txt @@ -0,0 +1,79 @@ +A .agents/skills/conjure-widget/SKILL.md +A .agents/skills/conjure-widget/agents/openai.yaml + M README.md + M cli/test/example-surface-smoke.mjs + M docs/agent-widget-capture.md + M docs/dpi-scaling.md + M docs/media-v2-results.md + D examples/clock/bundle.js + D examples/clock/widget.json + M examples/clock/widget.tsx + D examples/dpi-diagnostic/tsconfig.json + D examples/dpi-diagnostic/widget.tsx + D examples/gradient-stack/tsconfig.json + D examples/gradient-stack/widget.tsx + D examples/m4b-parity/tsconfig.json + D examples/m4b-parity/widget.tsx + D examples/m4b-synthetic/tsconfig.json + D examples/m4b-synthetic/widget.tsx + D examples/myclock/tsconfig.json + D examples/myclock/widget.tsx + M examples/now-playing/widget.tsx + M examples/pomodoro/widget.tsx + D examples/retro-player-shell/GeistPixel-Square.ttf + D examples/retro-player-shell/OFL.txt + D examples/retro-player-shell/assets/grille.png + D examples/retro-player-shell/assets/night-bloom.jpg + D examples/retro-player-shell/tsconfig.json + D examples/retro-player-shell/widget.tsx + D examples/styling-fonts/GeistPixel-Square.ttf + D examples/styling-fonts/OFL.txt + D examples/styling-fonts/tsconfig.json + D examples/styling-fonts/widget.tsx + D examples/styling-icons/tsconfig.json + D examples/styling-icons/widget.tsx + D examples/styling-images/assets/weaver.png + D examples/styling-images/tsconfig.json + D examples/styling-images/widget.tsx + D examples/styling-interaction/tsconfig.json + D examples/styling-interaction/widget.tsx + D examples/styling-shadows/tsconfig.json + D examples/styling-shadows/widget.tsx + D examples/styling-spacing/tsconfig.json + D examples/styling-spacing/widget.tsx + D examples/styling-stack/tsconfig.json + D examples/styling-stack/widget.tsx + D examples/styling-text/tsconfig.json + D examples/styling-text/widget.tsx + M examples/system/widget.tsx + D examples/tideglass/tsconfig.json + D examples/tideglass/widget.tsx + M scripts/verify-dpi.ps1 + M scripts/verify-gradient-gpu.ps1 + M sdk/CONTRACT.md + D skills/conjure-widget/SKILL.md + D skills/conjure-widget/agents/openai.yaml + M test/capture-smoke.mjs +A test/fixtures/dpi-diagnostic/tsconfig.json +A test/fixtures/dpi-diagnostic/widget.tsx +A test/fixtures/gradient-stack/tsconfig.json +A test/fixtures/gradient-stack/widget.tsx +A test/fixtures/m4b-parity/tsconfig.json +A test/fixtures/m4b-parity/widget.tsx +A test/fixtures/m4b-synthetic/tsconfig.json +A test/fixtures/m4b-synthetic/widget.tsx +A test/fixtures/styling-images/assets/weaver.png +A test/fixtures/styling-images/tsconfig.json +A test/fixtures/styling-images/widget.tsx +A test/fixtures/styling-interaction/tsconfig.json +A test/fixtures/styling-interaction/widget.tsx +A test/fixtures/styling-text/tsconfig.json +A test/fixtures/styling-text/widget.tsx +A test/fixtures/tideglass/tsconfig.json +A test/fixtures/tideglass/widget.tsx +?? .claude/skills/conjure-widget/ +?? .claude/worktrees/ +?? examples/weather/ +?? experiments/ +?? test/capture/media-stopped.provider.json +?? test/capture/system.provider.json diff --git a/experiments/render-loop-cadence/astra/evidence/git-status-before.txt b/experiments/render-loop-cadence/astra/evidence/git-status-before.txt new file mode 100644 index 00000000..e7fa7c87 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/git-status-before.txt @@ -0,0 +1,79 @@ +A .agents/skills/conjure-widget/SKILL.md +A .agents/skills/conjure-widget/agents/openai.yaml + M README.md + M cli/test/example-surface-smoke.mjs + M docs/agent-widget-capture.md + M docs/dpi-scaling.md + M docs/media-v2-results.md + D examples/clock/bundle.js + D examples/clock/widget.json + M examples/clock/widget.tsx + D examples/dpi-diagnostic/tsconfig.json + D examples/dpi-diagnostic/widget.tsx + D examples/gradient-stack/tsconfig.json + D examples/gradient-stack/widget.tsx + D examples/m4b-parity/tsconfig.json + D examples/m4b-parity/widget.tsx + D examples/m4b-synthetic/tsconfig.json + D examples/m4b-synthetic/widget.tsx + D examples/myclock/tsconfig.json + D examples/myclock/widget.tsx + M examples/now-playing/widget.tsx + M examples/pomodoro/widget.tsx + D examples/retro-player-shell/GeistPixel-Square.ttf + D examples/retro-player-shell/OFL.txt + D examples/retro-player-shell/assets/grille.png + D examples/retro-player-shell/assets/night-bloom.jpg + D examples/retro-player-shell/tsconfig.json + D examples/retro-player-shell/widget.tsx + D examples/styling-fonts/GeistPixel-Square.ttf + D examples/styling-fonts/OFL.txt + D examples/styling-fonts/tsconfig.json + D examples/styling-fonts/widget.tsx + D examples/styling-icons/tsconfig.json + D examples/styling-icons/widget.tsx + D examples/styling-images/assets/weaver.png + D examples/styling-images/tsconfig.json + D examples/styling-images/widget.tsx + D examples/styling-interaction/tsconfig.json + D examples/styling-interaction/widget.tsx + D examples/styling-shadows/tsconfig.json + D examples/styling-shadows/widget.tsx + D examples/styling-spacing/tsconfig.json + D examples/styling-spacing/widget.tsx + D examples/styling-stack/tsconfig.json + D examples/styling-stack/widget.tsx + D examples/styling-text/tsconfig.json + D examples/styling-text/widget.tsx + M examples/system/widget.tsx + D examples/tideglass/tsconfig.json + D examples/tideglass/widget.tsx + M scripts/verify-dpi.ps1 + M scripts/verify-gradient-gpu.ps1 + M sdk/CONTRACT.md + D skills/conjure-widget/SKILL.md + D skills/conjure-widget/agents/openai.yaml + M test/capture-smoke.mjs +A test/fixtures/dpi-diagnostic/tsconfig.json +A test/fixtures/dpi-diagnostic/widget.tsx +A test/fixtures/gradient-stack/tsconfig.json +A test/fixtures/gradient-stack/widget.tsx +A test/fixtures/m4b-parity/tsconfig.json +A test/fixtures/m4b-parity/widget.tsx +A test/fixtures/m4b-synthetic/tsconfig.json +A test/fixtures/m4b-synthetic/widget.tsx +A test/fixtures/styling-images/assets/weaver.png +A test/fixtures/styling-images/tsconfig.json +A test/fixtures/styling-images/widget.tsx +A test/fixtures/styling-interaction/tsconfig.json +A test/fixtures/styling-interaction/widget.tsx +A test/fixtures/styling-text/tsconfig.json +A test/fixtures/styling-text/widget.tsx +A test/fixtures/tideglass/tsconfig.json +A test/fixtures/tideglass/widget.tsx +?? .claude/skills/conjure-widget/ +?? .claude/worktrees/ +?? examples/weather/ +?? experiments/ +?? test/capture/media-stopped.provider.json +?? test/capture/system.provider.json diff --git a/experiments/render-loop-cadence/astra/evidence/prompt-verification.json b/experiments/render-loop-cadence/astra/evidence/prompt-verification.json new file mode 100644 index 00000000..4b4e5d4a --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/prompt-verification.json @@ -0,0 +1,62 @@ +[ + { + "run": "A1", + "batch": 1, + "exact_after_path_substitution": true, + "sha256": "08ac179928e0f21507cf738023be64b1b94c0183da9355ff2dee279542acbaca" + }, + { + "run": "B1", + "batch": 1, + "exact_after_path_substitution": true, + "sha256": "d32cd49ca837057ee7b70a820d26445beb6c51bc5d6492e4bee18d55b84289d6" + }, + { + "run": "C1", + "batch": 1, + "exact_after_path_substitution": true, + "sha256": "12d1d80731671d12732f5b16a2b2b93c9a6779195d554843b0bd1b05132843ab" + }, + { + "run": "A2", + "batch": 2, + "exact_after_path_substitution": true, + "sha256": "d953f2f647b7e8c7623e97929f7e0cefa49a3518bdb4d92e97de02fde764c34c" + }, + { + "run": "B2", + "batch": 2, + "exact_after_path_substitution": true, + "sha256": "cfb51ed98891273de72f3cc91b7568ffb9be5c28f9c0a893a0c3430bca8ff18c" + }, + { + "run": "C2", + "batch": 2, + "exact_after_path_substitution": true, + "sha256": "5782e1770ef01c0f4b7d90c6aa74855bf8211170818cc2a2b048c426aa275bc8" + }, + { + "run": "B3", + "batch": 3, + "exact_after_path_substitution": true, + "sha256": "df847cb14e05fc3625f5707cc9a9f518a3ce6f75546dc1d9cd8c9a2f80667438" + }, + { + "run": "C3", + "batch": 3, + "exact_after_path_substitution": true, + "sha256": "774ca846ae17446fa01a0916ba7b2fccfff57923adfc19ef5b8164b054d52704" + }, + { + "run": "B4", + "batch": 3, + "exact_after_path_substitution": true, + "sha256": "434320fbf9f1cd3fa8202558d1e897ce6d7f77f435c8fa646e358d34555a054e" + }, + { + "run": "C4", + "batch": 4, + "exact_after_path_substitution": true, + "sha256": "3d079fcd3b4f9bfa5330ed09affafe75390b881c45f3795375e559c26862efc4" + } +] diff --git a/experiments/render-loop-cadence/astra/evidence/toolchain-after.json b/experiments/render-loop-cadence/astra/evidence/toolchain-after.json new file mode 100644 index 00000000..c09a3334 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/toolchain-after.json @@ -0,0 +1,12 @@ +{ + "recorded_at": "2026-09-05T15:55:16.008147+00:00", + "head": "ab20771762be56faff04173ab11a5525a8d89be5", + "submodule": "464ff65faa02d36179b34e2252fa2a1cf46f7541 runtime/native-sdk (v0.4.4-169-g464ff65f)", + "sha256": { + "sdk/CONTRACT.md": "f4a7a8bf158b84bef91f9e2dc14620eee86f514a4bebe692b5051622e53551b4", + "examples/clock/widget.tsx": "0f5fc380d2cda74b1adfb969fb77f9c672aec61d86427634ad5b2d0d182d803b", + "examples/pomodoro/widget.tsx": "e77265ae15bacca60c407a59a87439a093d88915464cbde6a85dd6aebc955a85", + "package-lock.json": "65768ada60c9bc56ee269d91a961da0514a10a2fc6c8db330344ce10a3474d8b", + "cli/dist/index.js": "6a2e8d44a230f05731aabd0f32f6c065acba93ff1f8358ad1dacd51b485a8af3" + } +} diff --git a/experiments/render-loop-cadence/astra/evidence/toolchain-before.json b/experiments/render-loop-cadence/astra/evidence/toolchain-before.json new file mode 100644 index 00000000..6c4a0d40 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/toolchain-before.json @@ -0,0 +1,12 @@ +{ + "recorded_at": "2026-09-05T15:29:18.496303+00:00", + "head": "ab20771762be56faff04173ab11a5525a8d89be5", + "submodule": "464ff65faa02d36179b34e2252fa2a1cf46f7541 runtime/native-sdk (v0.4.4-169-g464ff65f)", + "sha256": { + "sdk/CONTRACT.md": "f4a7a8bf158b84bef91f9e2dc14620eee86f514a4bebe692b5051622e53551b4", + "examples/clock/widget.tsx": "0f5fc380d2cda74b1adfb969fb77f9c672aec61d86427634ad5b2d0d182d803b", + "examples/pomodoro/widget.tsx": "e77265ae15bacca60c407a59a87439a093d88915464cbde6a85dd6aebc955a85", + "package-lock.json": "65768ada60c9bc56ee269d91a961da0514a10a2fc6c8db330344ce10a3474d8b", + "cli/dist/index.js": "6a2e8d44a230f05731aabd0f32f6c065acba93ff1f8358ad1dacd51b485a8af3" + } +} diff --git a/experiments/render-loop-cadence/astra/evidence/verification.json b/experiments/render-loop-cadence/astra/evidence/verification.json new file mode 100644 index 00000000..af22ac70 --- /dev/null +++ b/experiments/render-loop-cadence/astra/evidence/verification.json @@ -0,0 +1,26 @@ +{ + "verified_at": "2026-09-05T15:55:16.091384+00:00", + "runs": 10, + "all_objective_gates_passed": 10, + "final_captures": 20, + "all_final_images_320x200": true, + "fixed_clock_and_isolated_storage": true, + "pinned_provenance_matches": true, + "authoring_inputs_unchanged": true, + "tracked_diff_unchanged": true, + "all_artifact_hashes_match": true, + "agent_check_commands": 47, + "agent_capture_attempts": 48, + "agent_published_captures": 44, + "observed_saves": 50, + "model_tool_calls": 147, + "total_tokens": 6242390, + "cached_input_tokens": 5733376, + "archive_finalized_at": "2026-09-05T16:00:05.314616+00:00", + "flat_grading_copies_verified": 60, + "failed_capture_receipts_preserved": 4, + "agent_reports_unchanged": true, + "save_log_copy_verified": true, + "watcher_stopped": true, + "manifest_files": 528 +} diff --git a/experiments/render-loop-cadence/astra/final-captures/A1-after.png b/experiments/render-loop-cadence/astra/final-captures/A1-after.png new file mode 100644 index 0000000000000000000000000000000000000000..e21fd446c4657d77dc058b7657c6b5d754fd165a GIT binary patch literal 256283 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%0D1j1Hd3HI3!#i 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⋙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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/B1-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B1-after.receipt.json new file mode 100644 index 00000000..74d3574d --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B1-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "1d979fb051f3d133eae73a24f114bf7b543e676e262d62cf101b9938d7a23a42", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B1/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B1/after-clicks.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 5, + "retainedRevision": 4, + "commands": 44, + "nodes": 44, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 335617, + "spawn": 56529, + "startup": 32826, + "render": 1828, + "encode": 510, + "write": 294, + "total": 431365 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty", + "actionFileSha256": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77" + }, + "interactions": { + "actions": [ + "click", + "click", + "click" + ], + "mediaCommands": [] + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/B1-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B1-after.snapshot.txt new file mode 100644 index 00000000..667beba8 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B1-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=43629000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32322 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623605193905000 gpu_input_latency_ns=2774000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=147 canvas_frame_encoder_cache_actions=98 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=48 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=25 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=98 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=509 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=44 widget_semantics=44 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,18.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(242.19629,18.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,52 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,71.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,52 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,71.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,52 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,71.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,52 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,71.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,52 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,71.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,52 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,71.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,52 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,71.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,110 288x26) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,120 224x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 20" bounds=(252,114.25 52x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,146 170x34) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,146 170x34) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,154.25 170x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(194,146 110x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(194,146 110x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(194,154.25 110x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/B1-initial.png b/experiments/render-loop-cadence/astra/final-captures/B1-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..c34ac4799bba61e3c1806f20e741529bd10d6eb0 GIT binary patch literal 256283 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 cwYCJb|i1i|^w9?vYKh6DpFeIcb=ho}Bo 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/B2-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B2-after.receipt.json new file mode 100644 index 00000000..1b0f8cda --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B2-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "4399f5d2d52aad432f7fc80fef4fe97494cf2eddd1e9b756f02e589df7b1bf66", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B2/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B2/after-clicks.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 5, + "retainedRevision": 4, + "commands": 50, + "nodes": 48, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 321128, + "spawn": 53109, + "startup": 29619, + "render": 1853, + "encode": 495, + "write": 229, + "total": 410049 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty", + "actionFileSha256": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77" + }, + "interactions": { + "actions": [ + "click", + "click", + "click" + ], + "mediaCommands": [] + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/B2-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B2-after.snapshot.txt new file mode 100644 index 00000000..1a367840 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B2-after.snapshot.txt @@ -0,0 +1,51 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40546000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32599 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623607153135000 gpu_input_latency_ns=2812000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=50 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=160 canvas_frame_encoder_cache_actions=112 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=55 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=59 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=112 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=48/1024 widget_semantics=48/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=563 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=48 widget_semantics=48 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,17.25 85.91675x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,18.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,46 288x54) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,46 37.714287x54) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,51.5 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,72 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,46 37.714287x54) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,51.5 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,72 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,46 37.714287x54) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,51.5 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,72 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,46 37.714287x54) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,51.5 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,72 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,46 37.714287x54) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,51.5 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,72 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,46 37.714287x54) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,51.5 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,72 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,46 37.714287x54) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,51.5 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,72 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,110 288x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,110 288x16) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY SESSIONS" bounds=(16,110 101.674805x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(269.9273,110 34.0727x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(16,132 288x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#7843502307405687036 role=group name="" bounds=(16,132 288x6) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#13195408868291225394 role=group name="" bounds=(16,132 288x6) focused=false enabled=true parent=#7843502307405687036 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(16,148 288x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(16,148 140x34) focused=true enabled=true parent=#5802963363624800140 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(16,148 140x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(16,156.25 140x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(164,148 140x34) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(164,148 140x34) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(164,156.25 140x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/astra/final-captures/B2-initial.png b/experiments/render-loop-cadence/astra/final-captures/B2-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..75c6301a98cc612c9754db28128255f212720588 GIT binary patch literal 256283 zcmeI51#}e2{_k_od*_|^?!CKR(rV>(jqqRi}GR*UoKU_-DC)1_cGZ zkl3zux1gYZv=G;C{@?#2{=fTwH+UoHfBp4KV(a)Gv;Pq!2;x31{#6T!2(BI)F(4!~ za$`tX)8CDpr+%N1!9nlLklw1+4)95ex#0z$A}*g`&qd z7bh!QzH-WoMM}6u^@6S}Iv;gV(tv+z04xHNz$P$CtyAYPzZi4J!rg@H30IVa9FtgF1u1b_Tkxz|=OF2DaH7_6rhY<++$fCXocDNT}VZ-Theu(qE9+dQK2eQNvB7 zaX;z={@e-Z+5%VKU>g{x_!lGiQxZH)O#%sAfl%91+xxo)z&NljUnndRu>{CSf8ItN zz~4InU0+~p9E^MF1wMO$0-lq>9~F~00$Uu^{?z_~paHNh-?M?39l@Iw0^#E68mW_$ z1_E0HV4ZbF7z2WMw-$*auth=bPwgK_8UXX8$q@Y22R-^i;twS8)3uV`^B##2|2hOS zB6!OxiGoBy8Xye>iUz9|=EDgiqH=T89RnjsuDOO82Zrz&-%b?MGmo0U%yUbNJ}1nZNz<*JHCKQ@H)< zy_{~{`=s%W47c>)p`#hU{`RMo=i>{Pv->9xNoRTD>Ne8jSaIgsYIBojEmN_tJog~? zh*9IxKfQZD2m3$&;;Y;Rij#Sb;e z0a&G4nC`1@zRNv%>cgxe#pt^$d|lGIHX!KUvu_&u6aTASr@mgPew#FFm0CNdo?@Cj zf3p^?Q^$^*WE?$af-x#O)~RFUWvJP1m)P0Rpi%RD{Y}mBEHBtsU;sRN>_p}dKmPQ1 z@{}3I=J5%s$6kFsGewvBga^m|gGVy{^FKd7o;rP&v3|p*sT((Mvmj5kkZ=ij&HymD zN~lhsn)YP+j5(&5*arGhqsONMUP;}1=YuV)g!exB%WY+s+g$!REq z{jKzg*WS#$cmH9|;GrYa8#HW|3K;&+Prp1CpDvf|jIJH0|Krd9KH0bbP)2<*edzGf z>0f^JP42GU`>Y`^4?qAGH-t-i8T2i-OX1U7;5%H9JRAD%s*g=0`IuBE%! z;H(V1YwW*&r#zWBX_{pF@|A1MUw`v`?u$iATEC$%aq@H{z|6cm20(bm=RUfSedq3j zoU$}wWUVh&x3qi)Fn8+$0K_Ze<>g>TG(4h~u5#5dU9G2HpZJilu0kcpug04*Z;`2M zQcr7NKy@Ow6D2bg1{kE?N#pv2~t=?ggVx=F!TdY($LtVB`A>JCi`ikzxw*y+->6BsB_mI278k{2t5H_xbg755E8>fg}2&oz+kCizx)2j+{sgC zN^nDC!On}9uI8KdMwrWh|G~*KS?~z?8v+Z58#c~!-5CI1f8*^;l!x>4*GlW!b$qJJ zyt=dnz_9RW-KNdkEgLs&v-E$e`7vWB8oO{{vsH%}Zd$ZtxfyU$$}@WG1S29jI3e41 z?6R<7FGOl^EZ{LBbl$RUr)AON+Zb=Ir15CY_mHo>g!R8{>hhLeVYsK^755y*^cgjyv?+pzYVEA9M=Z`xN6OM^U~$3 ztiKwf=LY~DJN{ZGKm6h>0O83E8!;vw{RMrZZDJ>@!y!IntV17SpVxo`bVQs7fX)Fx zgtD=98(O`>UAy;YG-}*J(Gfrd#~vH=IRFM%36a9aVd7XAFI0GHxC>xk`HEFi02+g>tOukH7cigF|j-0O}0I+qN_J+86jr8n?i9pE% z+_K%m*QK)n`6ZPsdAYZ>i z`3)L1OWnR>x20t1yhrMM4uH4_bog(+{UI0QfHiBy>Tzelm{@$PwpQX}GT}QB3V>h@ z@vgLb?FKW()+$x5ZXHkf=={a(*F-2*7Avr2>vpNPZr_z=S{VStBWvj}VX&|y@ zsw?|-(5yLP7)_I5t;GFBGLi08Z~K=x>XEq8En}SeG33Yf9L-U7k^OEiF0mP zncx7N7zR?n@a0{5Gtg&P9#@u{PJ*CA+cTm>sd6cBc~cGP(xW3^h_j+>yn!8u!C1`5 z0zB}tE?xN~TRx)%FAC#^NdM{Q-yRPgHYy$K41g$Wg!ov?O)<2_en15wDeiLYJW5M= zqnP+$Grh=j`onWsC<8On{4r?2H{N_F6QD)$)J>y9T{8bYh14JZ;r#T{`YU`k5 zJpL6EoA;;PLP3xC%fxDj2U%v&{p$&vB0$J3N-WfO%;X>9D9r2&9D zckPjerPw41ODm{lp?QD>b%Asqf(mKCeGOoY9OK$r)@8X0RZ?cmoSSd5Qp@t4DT@Fo zhT6_l6y>3MA`SST1_*!zK)L~t1_D+C1V9phz>1$dI{)+N)V3)BkN`*kBn7X8VNj0g%KWu;M3=&i_0*wQcHA0OAX1c)b<=kQ%R#((;Eg zQ8xdTHMJMd@_WioU$7Bv5{Pyd5x+lEGAvwIrdDlz+1OZ3e<%}W;~Y$5t}aQN+Vyj# zHt+}l(P*B4o-KglT&{qyAno)88yO6}y)NCc6HxL5^lU*C=W+#vq|N6YCRh8A68P9Y z%>jtl+Sme>r}wLQrA}el=?gZZo&3?x;?+WQwm{|S{Wv%4bdHv!&FA6AvqOzG9o4m_ z04%JAQ(HNOZKpF0SlBi?3qfD8voPVu;OYzn3%fr3Nt=$~hjh&V2$!7)QDLsz3*o%Q zPG7JQZRihnA_Qd+D(t1baG11d-}93*#hx~ufuE)TEXXlGc|~yBL4ptzB+a(KAX~NI zCB{m#58iGgD%Th4(vh77Iq>I*varS5+ua}9+*TdS_iN$?dduyLqoJbv;%#;+-NwAl zM%1Y<+v!a%AcLclE9hrJ*XTYSMr*y^ixGU#~Q(iiH}7i?70rrd6O+XO(db2Atf z#!}umg<*p;=k!%Oy$yWK9$%yfQv zKg;9FQf{Xf;A_5nLq_L|Z|Cs8YMnb6+$mdbrz_XWA5)=HHQlH&6O8LNY_`mvv%u7@ zeP;uo?#jB>Ho}Hx&0D9=U$DfqcKs&Hu;HWAYeYo5q(}aG@Y>&APlI)EsLsZ}%R3((tpF$JsQkY%Eo#V#>Ppn=O^AhDm}- zXxqVn`fHugUg`){s)gy$Igrm;+xUE1*~yp5);Dh2W?}2@F6DN*11WZF$Fr|xM-1wh z&bGB!%I$Rbx(5s#nm%gucq2d<9$8yIcm85iy#`HO?mMtYYa1&DSJ!RYvfY9&t(Prd zIi*9VB*RS6p>X%w<#wvs_6h*bTd>%)Y{hCbUlGfeuQp>p0nqs|%JCDX7@Nnpkwiay zD}o& zXfv(bJSw`59{rlX33pBEl?E_6(ulouxt(gZy#j!6-RFsStk}8@rEs@STthv!vEQ9W zlvjkkN>r2PjUFKEZ{M-2VbG8f67V3jnArOIrOQ@HHJsPh1pwAx zHpd(}EIFP1-1P#ruFu%Ijr42RZM2}zG!?^4zU^FH*V;yaZ`}CF#wE*En!AY+RMqO? zZh?s`ELg&Coy zy?S?)=BYLpb*SsvtA84796WTS)aM=9VlQ28rIP~F;fn=BZ^SR>xauuT9| z2SA8q#mcp2jI9h6Zz9-62#js)ww6H%C9Ef7Xaw(V}NL5Onk9=Z`inb>eT78 z-5Ouhy3HeN*3l<$VLE_4YxaC=M;uX_|4Yc=y5*+XO)M030!D zZ2F2-Yt8Yk+DhSW%hrhoY-7J#Ve$FpqT4HT|HJ_}J+ih>#s{q)%MS?UVj3qi10Z=^vTZyy2+js1?&IVVh zRzru`VC;7XRB{oyQ>!P&SFRutK%GA0HU$7C^?5lRVJ67kZ z<2_ZMfC>NXr#pJ}l#Q?{)Wzpfm99r_rINVem0ExnRDQXg?t;ow$II<3sQOWJ9$&B#*CV%6%{Bp$ z07wAT_}iGyKvUjH)qts>^7?{}1VB3g^MwZV1sjz_R#2T#?Rn(&=?shtBahrpwbxk? z`F+7g)PvkkHQVF?+5squ?AiFJTvP>7H?EvRZf9Y@&6#t`?R4c@J$;NX*oZoi+o@)o z07w9&5ST(>MGeS7;%VTzTE5&)HQNM00-&P!u=a)HZ5B~SO3ZMmI=;oUiN zPPv`lQh&T1zF;HlmD{Oin*c}vBmj~JsHg!sNO(AU)4JSFHQQbTz>%ZIrN8mkyP1zt z^iRJ1?#J9$_8!P+*}9!q{rxIlGKs%qeDLs#T$4FNICbV+){L2RO?ZQitAda>maFCP z$N55C!rp?g(;08fUY?50o2E8cIp5s*(mOc=|NcVgdi`WhqqU1H!7bxc?H%VRP3v|i zZ5DeZuTy8Xy#jzUX3aI3Et$f-2cP8vFb57E$@uB#-yQ>o^&2*G`Q?uC3g983b{#Jj z_~zU1bN~By%9B@LdovTS?7DdQYBubKy=u#2`L(nWW%@#07NnhyK;$UBgZMi9 z533|zw>_9AAkP$Nxb-KdEU+i3ztgp9y9LQ z2Z{J}N9$VJ=qq(ukapSvkTd%mZ&+#p{Ay1gW90MK95d87;P(eYi#;1N`2A|uwQP6N zrVj(~z4uRL{ryPy1Rw2@!vb%HhKDtF{3MsYWucYGTC{AF3OiP>-JtkV(FY==;T_8D zcV=5F8*wgQsLO)3Qw@~(yyfcE(*tseCy!?H``LQJYkRT~5?5^2)TK~Zt9B=C`uHTs z*WY}Xi;z+Y7Wi@$Le4GQcDnS{Fs(#}7fk|yb?YmCWoz-$6=tK!BH%67O4ng;pH?>F z9KKMO1#Kq-mfB@Vw=QV_T+Gz5CZ%JeMh-S2-PJcmYt`lEB-hlLai)WdY(jD#7s@+MOJ`6zdwe3=9iSGg^fd%_6T)dL~&9^@k zYIynn2dA@s`~A>$NTmlviTUvFTefqc#rr@AP*d8*R>MaH1X?N09-^= zjN&&IW{6+6M|zEj=t3O>^o6=C=r&h^k2Cvf^zS8&0oEKdEZ+<;J2pJIPdYrnnxlp& zrn7vumZZ&RZyJIowCv~dy0y1m=#RmiJAWbj$N&8FxJCYA#Z?X+Kf3iLu7j} zlwY{Ly!O(V9kxC*_|f@`*+2jCo6Qi}UfEjNh;#TtT^6*RwgBX4e}%@4Qj`DsTxfN8 zN2XHV<}a_y001kuX{8tk{)2iJ`n?CLVjvPH+nqi$edtN@sm8(!i>d?Ra{@3H^ z+I1B@FMD7?npPsiUwYgZAJYEn>u+=UZ?EDUUAy&4!(WAL+PvN7M2wXzZC@P)c8 zXghi6s9kUS*8Z&iKi_#0(yep8Ft}RBL_^;nZ$808(rU|O`L$|y(&qF1Twb^KwhP?@ zM2Fb7|8NF8y*>L5X7n2{IDMk{UEoWXKgkAIdiL(GdR&bGM}FaKzbngn4VtF@{Yd}h z;pboGV$ufVeOttDoa$54o?whp$%A#~JX+d_^Z7zu7NngFIIb))(b40<$GLrfy!E8f zx+Rv#Vae%@)-1C0`S#l5-d|mP9Ne;nOV0qp7A@PIwCTeSLZdU_F1GuXeHjRa0Ydyf zy>mZ@|Io8DFp=lcQe-H*TaP|z2s4?Dzl(nv^6H5VSRh#^9uQ6oLSep-AS9SLC`BaKpqm!;}cRN zYu0fovaHxP4Wx(HamU6MhMfF?JOA++uIB(-&+6{QSXAZwiBz!e7=wNt^1RXiuB0P8}^Z1E4o~SN84- z-eRXO*l5f9W1{kwx^!fxH+g|d-k-PCr$1Xcu46oCARXkFbC>QrA;U!(!gYk&YKy1^tg zssqwMU}}H>=)C|85`>^2qO*kh~evK)`B% z07&8wSn-qhsREKY35?c~AaOe*{1RAOVmx5U?5`0Fw9vR{Z|p!O%6h=fx5L34jDZ(m=p!fB;D1 z4_NV&_vD`UZ8HR{GKDGv~63mn@g>6L}RXRZHnNU~t-ojaw~a$4@erDpMg}dSuNQ{lv-BjmuW7 zHh1ilWN>sIXVNtRU}ViY`X0UdrLhx6MAgHj&h=uEl8+`#nrg%w9&1EI z>n2Z~VdQ@uo?c9su00I=eympyjg&s7FmC*0BP$;jIBdk|^zg`9Qd+Ox{nM&ctC8=c z3pnSfF%ygxgR5C9u}ry2DPzTQii*dxvaqZZ+dw~K)?Cx7)$7dz2MtT-%R)o&Hcgl~ z)oMplx87-smMk|fShUpCC8?)@f3J9Ahc1Q%3zwRZ-lJ#VG}hSVD^^YEpFAX;oga15 ztIvS6dGi;WmMmRq9yDY`dbtW!tTwkz>|_`>VTuvg%#Mkz+fbj-rh_Daf4^8k0l^6a`brXxdsj%p5Cc*ck6M;1F)=J zzsVdGT}KaSwrJTVb;hiDlC4Nzy>^53y7;o|H*A_ZYtDQVV1>pT#FbsMR;+&E;$ z(Mpx6n9{p%a$0Y(QE`0bs$n|5{E=c^j1p}`Lm+>jego5H&s|``YnqY2zj#LkNIQ!+ z2X_7z@oiF3CbnVkl&Ld~fO~n-7SwI)Htnr>*)g;v5NfRf^u@CueVpAYA<^pfHEPl# z_0r`}vWpgfcEgsR7w`iF`TgU?oBYaE>#R`3YrwC5ay`3h^}H|1?>}%jW9YC^*1n9s za_z>g95_^bIcnE60U%B~XYN8%_0R~(7<9<-6Q>y4i(U}YI(F`6=-#7`)M4EPV6y0; z4d6T|ly3`w@IYtJSzwB;9j6bgQBwy`P3|3446dHCblEC1^Hxz_o35W!J7#U(u04UWC7V zM5AOQ`sJOOz1I=M5JV1bg?Z=YA0UltI*x51Gz&uTMakc=6 z^oXb!-JE#~P19z~HretnhYTH=zHrep$;;xyPaF>bM%S)uwUym*%9gL3f-w(V8-T;? z#4-3F$gJ7(O;e`LGKzOc1M}vP#sjc%)0V05X0f0Dp;3E^VLkQ%fK8gUOa=7d!D1f| zz)F=vQWh^+VMbWcyhTDP4|2XtTF+m{R3GlwN1JvX4aZ)6JyTwnd-om8z>QhHAKQpz zmakl6_4JhT;Mj8?UC16jVvMBsu<)9?%U3?hmTMbM!6b1^P^k=O_h|+|j7uS$L-;p# z+$3?#Di4G&6)pJ)t}V7<6aa{^DvX)2A3%pR0C4E=QR!?ymhA3=fzipLX9<|qt=Bl; zoxmOdQSK1Ybsi(yWUo@-31aL5wqYEQ)U^jG`|1ysO2x%nM_g2Z(auiQN6ocXNWPJpUzl3@e>Fb2bZM zGRx1FaCF{!=lv}76Xx`=G%Qb@KAXjy2yCOzod5VzcC!|(t$mlz@9er}0K^HWiXk6n zGDE_mqzVBHvCYp4xe7ow34-$=)SEhemUWid9RLDK>o;z(z*}RLHf{QBBRpDc+X7${ zF?@wL${GuyGiH$iz&dda^q9?JAn-_GFPnkJ4FZn|$f3%vjh60pdaA$t^|yM>1~a@m=nl|Zvv#9- zi|Cmt)f1kEShRS#b%K%41E&KM9sE9i9Z}`MLq{`eiB15V4QT$v>u+W9!%KXAXV*0a zAi~5|Yt~ykA7)nbW`m!>1pvf8{)ZVL7>p2@-;Z^8I7s6Gh;4+m-MaUdygC3-ejFwP zSS8r=0Feie!C)49-h#y@01p!_Y)lW^^0FE9lEm|G-m=3YjxQS5iPQ7^Gf;R8X5*%< zV%i)NmMnDUJwTir6C3c5F*CM&#Tqjvlh`;T(&YfGTs2gO@)!UCI?Nnz+PvK|edZh! z>Zx9XCRWds)d4N@cU-CuZR!JkVe7V+EqD|L6BWC5@67<9las2M&sSmT<9h$-M7`D=?E(w5Q<7icxR1Vc8X+T*6 zWyMGbkE3~8{SW{NfOG>O4Fs$P2!JI1fEB;Dc_UNj0g%KW zu;TZmXF+8byf^1cof7~FfCNC&K)`B%07&8wSn<2!G0-u-;n_LcPMQG_f0~AO_n|=g zQ5}#5NCTeK09eESIjpn5ljnntLHJLepk^C}c=BSYZ0by;0n&hy2Hb@p%5)omg0DEJ+8i$R~O8}&horWw(13s$(uK*y0z;vhg^qro{Cygm-z$-#vxRfx2 zLSYiAl1OPE=|XD_fHm&I58Q%XZjS--F*U9G*JA?Ip46WHtN{WbJqJk70g?s+Rs#e; z5`Vyo-=94jx;E!LcLE>*kN`*;2v`je07?7-D}M5lob!_Wxt<7s1V92HX&_)VKma81 z2dw!0*|VW*bI!XZ01^NRfTV$d)c^sI#2>KYCojo4FUgy2G*oXqO`pIeWU|NFTx@b53^=f`z`Hbz^c&C&K+dk**rcUkfKvK51?r{LSLmFef# zb$~WTTcgd<_FC%+<#_~v5I;Hs0WYwD4-IGmLWmz7fq)m-(1!-J2BGEvY=7=V27xcI z!6$EjXu{RIcj>Z~2z=z}=JRx+30L(bKTcBs68s2!a`>@rS0G663v7?ip2x2h1T_O7 zLLDY{S`rAAG@vFNMyO-215g^lQHyX`GXT<{)NJ(*tPw*N>-v)wVmd;z*q20uuZj!H=c8>k4WBz@jPQ zvk%#7I|AhoOt%qQ`PU0Y?cTZZ>;n@xEeVG9GyttQx}n-jcN>8J{CCk5ih%y^^%4P)COK41bU`!r zgeey|Z4>nDX~3SA9HqGnz!U-?d39<%`=?AN1b-!yq=^q1|}xQ6-(6Q>$| z;d<-=&QY3Q0OBRDHETCo+O+Lp@KpJ>%EdX)eE3n8t#ohN?+9}C(gPBJU9P+*G+ez`3tb)nv( znL^?RN1scx9(VI}zO>}OJ`)m-?-rVFT_yDX`l>ap-%pVC5I)(jMR(r3D-STs5xesP&PJBsM0n;81VZ82@**+P6Jot9G{H{!x-q4!cfZD0k zXC)7A?!1Mji_ivHl5uV&vh?_IT3YuEu zN7w`)z}Df+t5RNgS!|51?+-VH7fX~8dViJY!S(t6hVVl1(n7DVu1I;y)`=C`pFW;< z+`W$^FAh*bI-tg2ocP{hE4btUEEyIqw0(2G)z08n@sihwasWU;e8BJbrF4vkh9~#2 z<|P2SK8YX?fp@>MFGGY{R!p7xlBf6fJMU)=A2BAK0Rd@a#!i%ga`V=moMz2iOR#DY z-^ReaMvSu^JN{ZGI|ln-f8%ZI_8V`$li96%?|fbx%lpcn0~zDSPnOExv-f}mviS=Z zOOQh7ykOx{b7WME{E3nYum1q;nO?! za!@`4U}#vR4mJRu?7ZH#vjTj`fI=sUgh9D0oePSYr+d6VEND;p*Flh2EeL`ZLP<)KY3KB6tC>X78VSB z*#qRq01q8LCV6>vV(aS>No;t%02s4o&o^DTcqMz|rmdF# z0|uufM8*CsTX$OEov~xy|KN1iox2Yt2qE1b0EZ46mA?PLkqm^TH*Vg}>C&}F8qSa7 z&VPIuJ6u)na5HYx)6iyEmJxss~;VZ`e_#Z!}Cmknxoe_ik3-Ac}zohB)VYg+qL#|VH=I|}PC zt}fvL%Etg--nA!V%G8;X*M;yG9vQ~o*spnu1nZa{LdlV%#u@kSJD35G!j2Uy*P8e3 zKa|1pvn8|99suFp-MW1@r*oGcX(wKLGZPSoN0-p1gW<~6YuPBHRqJ+!J9qEruyWZF zUhA;oqtj2HIh)1yu_eY60YHS*+qS=K*}83~W&MWD63Cfd-n6s_I7ev#1wcTne1ir; z-TBi5OgMD8`o2&sxT?_cqt_*109YkLYY250Oc!FNj1|g6*HQ!^jxAF=Mrix?0qHn| zuSLYry5G-tgycUS3dO5bm%KupuiNbpg{mFeNn><44jvv0UlArt$BB~|-NkSiw!p)~ zaV-yS6RNapBdzlQL|Wy9R?@g4!sTw_1WbwQVM4oi4oZ0mfUbwQjykmx05LX)a1+PA zylZd9rp?B21uby}#6OhDlNZY#YWec{~t=}Zsgzy&U8a!l#R7T?_@u@flV~_Ck;0?l4 z#IfCb^hpEIu?_&jF4%|(mrIvF$?n}JSuqrs+f>lojv!|*-ERRXUbMjfFfjpm05pIg z#>wERHQBga+K)8+I-P%0s5Nnv5I1*f9)uF}AjHzy5@U1-nM;L73dO62h+}|DtmSn2 z_$?{S1qe$;))ZQap|15fF+?t3pB-0S90OczO~b5h$r=$-nE)&sE0hBe-XA7Da1BMu zRTLVmm~SnE09dd996N5J5#w*@^ziVGzxsM6Jg%F!KFwLRdcAerY(Vmm^m89w$i}1w zyfjQ&Fi>Cy_TK%6(lLM+8?Qq;Le)!`uV&wW@OduF&o2?i!c%L~w58-}4oDuFj%_@% z$ns%g1mQPqLRk!kNFO+8SUNmcqm-mDFGMBiISX-U#SsAMg{TBTXQ5u`FGPiy>6Q2dKxY96tvm(bBU|AK zy%L`Q=qvyW|CRXS%PpI{LLWtP765^s4_a~bLR9)F5&_Uz0BZG7B%AMMvvrqd`|)~n z+|elvCNIzt+*$bR=#}`;7KOnCK}QgDH~fXp#7U5pAaQ#9*MGlQ+-69^V5hXi2W|jB z@&XBfjsOUaKr4_%I3;01}U>?{PB>wH_`=8gMu4~SIs!c`?f*bT8>6k!=30V}X$#B) z`+};4LB?A4C>@j9Y)0+**W@O1p|f&@SOS3NXxa)pXj-3x>B-EGB? z7#^YcoS-~3CO|v`gum4V+FELJ$>S@kp`Hi^o`OLjmJ8N_c~$_5uAulX(5RFbiiy+Se#jvx#>I2pek6umbqd!=1Ec{j z)Ii>&FOhTQ+{?F(8R1f8D$)S97d9Z>`CYs7Q@v5WfoWh{KG-R3hz|$G!c8n%ybRsN z2!f;m(tyuv04xL3z&0i3J+}`}NaK@wG#*HIPV$~e1HP;QFbph{{_5j7(%IR8=VYpg zU!5liQU~zm4nVdCu71HTFf89Qe|DJnToMihJt-UxToDmKsO^1G17KF3=f^$p{2bw& z*a6oO@iR?~P)G2^jzBgCo^HXar(=EtoIsr8EEqh*3<{=^DI^X&K@mi#&3!=wU=tVx zR)JZL$)+*~o)ZLF@ieuE|7_0ZXP$gPFk~Zv%^x%X7J*55UY~>K{8TdUx$O9h5&S6$ zPKG}!*6J-X{?HI~4FnX@K*4DM>;Z$oA}|STdJb5g+JQeN#w3a4Zi?^Lg6oO5timX` zqON{ui3C(|0;0O6y7mPPfF)oG*aF5#f6*Z_Coj|$Cu-#{Ht-bmY?TZ0VzLAj7L7WI zkB#7qOCYoO)6tLWfHXiFa8Uy(UN+9%v z&=N{WA$=3lwk6rkW_ObfmfR${fTVB!W3CuqMx&85Dq}sIGfcTy7i)mM%9bi992K&ji~yu_v+P;{i$Aq*eqc)&_-oI8XygLsDUi71WXaxA}|K5 z0durqm&bVs22`wDFJ`J>)UCQv(T1Agky(|i*2;ROV%4mt%U8Pp`==`0|J@&+p^eIb zG(Z~gN&{dCm;$zdF<=dtBeF+e5Lo0f$lOf`^1{;-Xr5K0W*rfD1UdpeX@E4~Zw&y5 zU=UaYCi&be6gcoSJ5k~`@68{e$+ro17%YKU=f%EHi1#@I(07N3w`bc zxSMc2;fj)w%BGO0Ua4O7tO2kIj4J6GM<=)ho0~8*`xu|fNnGZW`SK`m{Y(h1t4KWWCH_rc|+r^ zN!}6Fb6L{>*ae2U4MB08jX+O=A2o`y)+p$CLQB(NScxa7vOA0k5A>g@+Z$R!Auv#V zmsJgbWsk-LT~CZ)28AX(s4Iw@)tOzpFpSMv1DC-S?o-edD4#qw50v~@s0qbP&N5v$L&=v>PKh=LIXaKA$wKfp5 zBlxmHC_FqpBQ zJuB(GWJ!$h*CCh@!B(IcXalkji z@M9yi_?bjOU?2^Ik_Ny$urCb1xa92*7{xYDFsAhEog=q3O-M3^Qo(xqtf&K&U+p^e zX+ny=yQiD)?s=;BK&L}{1N*|TD9~GDHf+kYm@S2Nx$V&5qXpjP9}4OJ@N~udD8J#) zkIoB)=cQ*Pk2BC30Q&$yuRRU`@au2>^f1s5r04q+00{_s)~_CI2mAaEz|^#UIU6@^ zwQSq5+tM#%aIV~U2kSLxWEl72r2IX54-`z8I5j^avUInwS6bhkDbr@7#45C#x0i5KEL;XonsHUAPqpst{)V--#NMY_N&+4D*EW- z&&2z!S-Y_mxLDkp;dQg}^3C>_CQfmHwOLYYBl7&>-q)qP+sjw37r{1`7EmjR_tnD> zKl)U>&(>|bEG!)R`3skt5C@*}d+&cJ#yRrxamVn08~|s`nwyU_BSwv-ZZVAuI$oAi zUAc1%hhxaFk$KWBE?$0&zD>K%*>QqXpeFxz9lB({G+|2qc)@AGe1MuX-o)vil9tn= zRr_pj@<3Wm0SHjZO@f3+)DwX;__^V^Xv`BQPjdh!W8e_++LUQC9oKH%ey8}}m)|^W z7!&6J+4+l?M1ZjeRs%qIjoCSQw&zE_;DE=>+4D_Vh8&x)_}h^;%M<&Xx9=36Id{?>BTE#;-vu2atd zxK^xGP3#7$0brGC;aUIvHOrPMbbs0XF!jxMky#k_v*#`_{rt@4S1r_{`Z04)2OR9LB@`^yj~d0BPSbS@e`TC#NXBdDH+9`Olm^ z&x9`UFaN!7d-e3WLX0PdM?}ebe~2H`C|>OHqC1V1;z$b^?LT;=;Noj<6d?}YaG!ko zxug4i?fQ)(Iq>5e!jR_lne&Ct;@th6FM9{roZbJ0aTD?|P7XN9#Toz7r2Ng9+btu6p4j%C zdn|qX4HEN2&k!$vv?p|(;b<&by3!;!c8+`j$JJ}ro8f5=62|0p2fzzLH}>uaA34Cm z3JYMtm>AB{?FA@MSS(y_4*;T@EDh_KTGFMIjsYSZz(aR(x8Q;P?YkeW|M>AIYojL4 z$0^{IVVn>X9{>^FRG6?}$6tQ+?ZZ{8*Eu{hjA6oymFxbuY1c^v*sk6CEg097i-Ybl z>|_AM^KaX}+j8#wYlYwb=`Rmy@`K0ke`9zFI-DNhk@ zHoB(OAAPeB1&#>|>EAH3wTKLW@ZvC@7#-WxQNVEZ(Y2g4XTDgFa$9#o#c zaEXb{Ff#x`Ajk*h1Xv$Fa?CMN!t$p*LD3Tp0Dx#0iOpLX*@hRa=m827l+rxa0#KSJ zsb#xt3?spt1O#!f148df3f$u-P8Gt@0RV+|ULfuEPMJD0AI^p}PaL;s)h>I-&b^jr zE0+LTmjFZ||M2%8tsj5#*@Kaz$K_#=_3bmJD`w(CSyb%Wj$CylEwlDxn7eeePns6X$pEcZZ8~Ic6S}qxwrmgR0)VfaI#VchViql4Zc3G`_F#Fg zUBAhU?lS`^V7PnFfdWjTvN)dXHJt=;H3kR+lUlaT#+VlxHMUPa`}{%o9%+u{E$ksy zui0P*ED;A?M=U9ky61?8Nr}G*;6WUWAr2Z`GRw>Wh&Y%oKYRXSAwYw8faEM;CYasF z+5Y<<{$a%otkkQ+tS|DAdaEpbd}0gZyYGEajBsp#u5{TB;t8Ip;l|Ck9dS?&{U6N| zBU}!ExQ=eYe}4Y2t$xEs4iA&vm-YlgcQoKB00ArM1cvmUSfaH`7@K1~JG|@<3B8u+ z*f;~=hNWIjAN@IOlcvp#=rO@NWL;n^$w7XY5IHQw#TsB~{v~1Y4v!TO#Y&P{LO#M* zou7!yr&T)F41h{Ekqbk?umY0{XV>60vSVj^=4Ckx$8{9An!J?qP!m@2W|JQbX6Z2= z5*gLd<#Vz4v?s`Er2$U?h=~zQR>;|bo)*>sVmuEo>yv_4C-uy*UJqm7nDE#lbh8ti zw-&uc01)GbihJ0D4~&Cp})j>#Sbk zQ8^34c)v6Z0L0QbTw{|Y(r|wq2h0QX$HUP*%0}a(dJKF$;;%(8%%f#pU>sk~aFmw! zgftKu8Xy1?0OteIAOVm7NE!%P z4G;iH{2?oTCC`AuLc=>G01^NRfTV$t)c^sI#2>QaCoeBFyga3PCIAuu34o-5kktSI zki;Ld;#cwvC@eI*LjoWHkN`*;2w4pf07?8ID}M6wLc_~bs%HWq0gwPl8VFep5CBR1 zAuE0*&w#>0!#ngT0P$IPe1aaI(!qD~wA_#<^2R;96|1l8)Ps$vlTfs?T=np*XX`gK zRA~}tteTLZ>4rR!H|{~&^se1&sZF`M@Cg6`6d0~0@Rahxy&i!u%x(`0bBl=nG*)70 z(Avm|_^3e3q@5s>FUaSNq_~$SG$d_4Nl#DPkR1KkHO(oAuNx{6%a>v9d|5G2cIv@K z)KOWqvqEH)!5OH0eI55^jn37cwD~0bq}*^vo36@QQve34;@mBqK-;ON0t0QMS_taJ z&OpMC!Bq_e16`hFNt>?Vhj7gR2$x+7qCg%ib>V`=PCeL&IxGuzq6^9(6zIKDcbK%P z?D_FbQPQRw_-P72e-8Zd1;L-g7H0(zEOzR_MwDw=u+yJoey#uuTS%MkfsSwA>|9Bk z&dQj-u89X2EN?DWFxbnz9fHkHJ=mz1vUFx=FnNCrj&fcgY11<(%C#XLa!Ti#01#_Z zr0@xbW7xz$c(B>22OCkBdbSg5QW$uGWe=N3o1OuWXN#OR`Lb0y*93sU(yf#hj+}cO zYwF9Wb#H<+~P84%^PsRTSeOcMY~!4pi!{KE#5ZOj%u*a%zoYA1tE zuZ=91!B)vP9SVhb5Fh68EoKV_UNHJ^S(oU`j{_FCDAd-%B_=f$v#kb{$5(yShafXtUY@V76^8U<=D61pxh%bA1`R%v1>N&86DfyxFvJDg}=YrbFJ*; z@26#1B5&SKDRewJ9`fU-Hc!&IO2ga9my0{+Xgj-h?-%MiS*+{iZas50Y|OM&u3F2{ zrrgPo#nsYAE#KE2|qoRq?A)s8ak-g}^+T8#(? z@KE3N8Z`3iC9QRx`^!$=Zl&{}03f=+lc&yfG|n~aHkxsb0O%e72Mr#UJM8(<;;;e0 zg6_tORcp;?JX3`7?bKzPYZvJ2l~2m*<$V zFXe5?++i6pYHVKphK;=fAFDsDZA8BQu#>l2={zU^h%WEWU3)DxYDF62nl?ACTff=d zyhWRA0-$>UOh{~LT(Wef8RLH|R+fMdfI+!#*}B70r)~p}8wM{T)=0eF2Ri_V{pX%t zItJK&@1_DZfO8ec7v)*6eypKi#^BsFYd4yw&zxhbQcd{omjE44H(%HYTYPONZ@1EU zPyi6)R@0`>&hOEyPtNEUUd$UXXlO10(0$=zjAgq3JTwA$0ubBunR89O(=&46ReRbH zkd7CTH+f0Z20H-tFa{VUfG@q@z)};50AO;rULJe=zNmA5*~x2F={#rv*tUHaVU~5J zdF%FFmb&#~3k1#hoSyUya6D&U9nF~W;Q3LbZlc@epr-dTJCp!Z{d z;sls5`^(0EQPy+jEi|R{>>X49^p~ByR+Y|!27s8cLSw+dJt~j@=otX}^c|3U@X*VS z+2EK)@y3$b;F1|aXCQKQofna-_-exmfZhWTWsUJ(c>fzWZME#&wa)?%(A$*?zNmA5 z*vZ?ibRKX3s%J(arRB`3uv$uWUsAzO<9K zTj`ttC{zZk@IdVO$_a!GYVN65I|BtcSNGLJdFsJNXqUIsopS;p0Z`QofESe-Xa*t< zZ>K8|1uC4kGZ1Cv>YjSA5zoNe>CQO;kN`*k)cB|2)IgPQq^@8Th;TjFNB~p-m>w!n z4>rn)ED#M+%{}?@R0E?x#Nq8!^KAZ(qX!#NCcK^QoRbHr08oDjj;}0#+|!eL=+(|Z zz)j6P^-!LAu#o_$05CmNpdM_L6PYIv^+y`MJk`J`5OH`r{ZTgV-a`*I;+c3m-8m-@ zPywLs3dWQ8d}Vo(hdPeo{O1U?c41?R4jy07w8N0FnnN zs{tM)QaA?FF>j|k=RpC$v_AcFj~qQw@Q)vVvi|GeKU+_{a=LKvkmpN%-NKUs=L^D< zJfvxSVW-wM!d^Yt=?fe2?0k88i(j^-+f>k^w+!AM!Ck|4Wtt1Pd5$!^=o_jhgTkUJeXP7 z>E-Q({lB>R5Z5~F+w9eM0ky1mUzMjGY?P~W-fpGyfC8{VbYsI0fB(_??t6EOBO)Jv ztg~i#UBk8OH;R7#>`ObfvJuat2RnUfBg%j;&rT}vGB{UzI`aIQ0ehI@7^uGdFxKG^qM=z{DZrbRvOorc4}oK?A3#vzO)f#z?Y{p z0C{@7dW#lDj0N`n_}W8H^FTV@PO0A9Ire3F>cK|2I_K?HIu9rS?|t>n!>iZcDsoog zubezx_|KpIZFLsz>N@}6uHrij_oba$*$CV9V5cu_L>chq=?$b<+8V7}Ww+h7x*+A! z@#5$H{;{pkdzT*6AK1^UA4lTtbf!I5*L_)@dazNh&Uw3)&I1NOe6%qqH{X8j#Hm7O zm5i?iql=7B-+9+4&yxmIY0R`aYtJjM@{OHpMe1WlZVJ5iv?gt+`4QKJ3?fD0H z7SGjnU)rgajd%t<*y&3fQ3iZ@@(|PFJZbqnGrYkjlgH(InjdecD-Aje_hotN!A7|{ z=j~QH4=4b)WNx?Q<(uts@y(xD>JlY%dkw}M8-CEoS>?OB&Of-T_|C$8X{S~;!gf8_ z=}Q|?27GyX3aH55J#*q`Pd3$P)$)n1ZbVAA8~_k&13k^3x6_&STwV8NdFsJNxjN_V zRyq$T06TQ*nr+O^wH-Tt@`-UkEQkgiQ+xOG_%A~E2X`eVXW_oIQ!5)`yB_THrHyip z!BapbEuSlTd961tv+#Me+p(?y0BpW&u9**0d#+Wz`?5UsV53}}^L8tp2NZxXeyZ?; z=$Pnu?e)t=W5-R%A2nut-sv;v3vq4viZwy=W8S{9ldl|>GfczFKm>nbG1N{ zi&r;2HMi5@ZH0gxJU+HzIZR|~504i?<6c_VyD!R94>roxId8Ypxh4RtSgE>KUJGmV z3C&s=lUlaRX6N4QVH5x0!Dgo~ZA95=Ri3`IQ!5+symEF{X%gr0pQ}ls7}Yl|7k?R2 zy=4oJy*`#7Yzk#<`nt~fvQ;|Q1c1*}tf~nBy#XGd7B=w@9&C2%!A6v;p6z_LenSHT zPq6G^6KT`Cp&r)W<+RC{tqDM%7UF*b%PneyxGfje@UC3 z!B9z?tV~_)H3MKUc~?qrgmgU{+OtOr7T_98BAWFoc9-Ov z%bpEAn>x>(07w8N0FnkmRs#e;5`V~wpS&b>UQ$^uCjuY=kN`*;2w4pf07?8IEB>QaFUy_{ zJ)1i3mH zsq=0LfCNASAZZ|EH9!C)@rSJV$xBk_C6(oJA^;Kq34o-5kktSIki;Ld;xEgd4LzGW z@0I{a03-mC2E5Wh`3jZqckSLQXa0gErpZ%hiWxBsBrS##!_r1^(O)HA$s`C8HJISWkb{RZZ4+rG=P zann`{ixV$^_4->kix(_fY8wCIr2NZQuNMs*JS>-md$QLAfPkOBp(l60ZpU_-N&Eyr z(!gU4_ydANhmXpOjB03L0Gc#;dj9m8bMo1_+LU5#3i zS#RCAU5wvvMIJ97d!?XvdPWY*uYSWuhU;(MEJi$b&E35w01TAp$3rmV-mM2D{>S2{ zvY@hnC+IE|yon#zw7K!{%f}14rKCDQ#phSOW<=JhSI-vy{;3M3y1#t9xcDUFwd*&E zo+|h3eL(Q$tvki=5~cA@pE+OHu0xknAeDx@Iwk;8x0!|w%CH9f3BY5=PZr*~{Z8?m zc?(N*ZFvZx+d6gnEJY7-z@VYIuV1=Sgsw2sCnUBso)N|j`Mg%HUS}RUY-ApPUG2Fh z0HiK3c^c$x2B!x6(FK;mreRE+Vcq&o=Bd-118&F8J(l=H`H7N<$OeXOJ9b+R9XVFe zG$F|`j##%|i~-(Yxo0Ys@)~#T-fv0k-QTIVDYZ@RSQ7vuW10jB&IUkW3e9@)*Ca@V zXRBrVEt6Q>HX42Ic`n=vzd`O5VoEWHV@9aU;lM4F$PV*(%nkX`_!0ZlX@ zj5iwih0Rh3VX4efVJVCBnkUEQo~eAldW{H=m%d2vNdP4AYa)KBsOY$~heYL3QXbW7 z*2!uR-NY-8P3y8G01^NRfTV$t)c^sI#2>Qa*V>z){PgGf5&#K+1VGY2$ZCK9Na7D! z@sr134jDZ(m=>+fB;D14_Wb( z$EH7zP3t-%01^NRfTV$t)c^sI#2>Qa*V>z){PgEh5&#K+1VGY2$ZCK9Na7D!@sr1< zKaWl8IwJrQ011GkfsoYz0g%KWvf|g;o1pyk=TQ;>34jDZ(m=>+fB;D14_Wb($EH7z zP3t-%01^NRfTV$t)qqa{SiWZMtVZKT=65`_wXpY{iw`osdfPhSn|ElVGVodh&=NES zZ9!wun%3R{KJQ+!QuVBA!VmD&46mDo-?^wwn_tQRWsNdN*`p4WKDF;nz55J+iSwqJ z2zUg0f4%UaHE7P8#vn~wsY*=(UJ$_^Kt!EL>qv`Z%>h^?uBoy6g(Jm}g?~qQ+tWs6 z;A;((ylkL7XwcKffuC5cA^dg)d3wR=?V@hH`58=J7n%YP!b7*D1b)62Jms$=sQ%`Y zUlJ?(@lE)S*gy7!glJvpdl3PHlYp#VP)AykP*Vz)xPL?^9nr~;VDhgnphfRg@^tWHQkFKs#XKgCN!$l5NPICpYQ_=QFlsp>ncnG z0G1QR|8AGr*+jJsjp79-l%dVv{=S^zI3SJx=@)>gJ6DiX3ilp>zbj{;#vh!GpX#Ng zUVbZRRH+g0-6}fQ7Z8=|)>Rk*kp5Jq%zN(yKz#wt-4~E6$SH*r03`rywQ-qE7&9s} zKMQh8oi*2Fq2?iQ~X}$aB&YQp3#J2Rl19IJMaBCu)`ADwe$NJ5`UjV-DX$+Z6)yF{QeHc1OLz%YLo0i-9yno4&uHR>GTDxC7;y8y5J+Gd$wp_Ew*70Db z4dKkL^bfCCdtN(b1vFc%oNr6Lb=DEa;^=iBXb%toT)1eNN!s}L>^)fU!q}G_o>HsU z9kSs$4H-HjFSb#9DKMt=NXwZrb!L8xmhG~oc|^xFF+Mls`Me1er{=e5+sP5uzC&{M zx%00TO`SF?zh|#Lr636C_UQTeTEplj#?-Waxe;~hi{HA6suyEOP3!CMP`h>Sl{0(J z0#jP=evWIf0rAuO4$Pe~bFQgNau3HncmOtTk|^e1C$fRhzNMuEI9Fi=K$QS&w`;wv zQgp1n@q`y_wK}x7)$NmN>woX22nm3ra%>}e%*dg(215qe!aH@a)#=e)*7Hi3J=qq~ zE!mbhf10g&ix&14s~0-r0em%Dx3b3zacZ_}Yi~Mpq9ZI}?i5??u3dz5(@W9`AZ9>{ zNa<>8IDD`zZpt`Y<;G3yDVIv%n{w&6wN}UWj(EZc^lX(H#@HLZILcN#xw8%F`v37Q z@fkY5yhFTJe_%gb!rZC0YR#J20eW^1J@11NfZMk3w#=M0PlRIkl(ZapgzMICw(Q$~ zxZw1e^M%YiT)$zn<@kwHg^Lz1Grx7?cJatjWAgwYgr7Nkp%C8W+I5@6Fyw=)UT&F5roLVBeLi z*NYY{UT%K<(v_lR%U79k9oyDzyDVqVT`XL>Y?b-?n>UL`k9kqFOA0^$`ohIaMboCw zE@cDDL#w?j$SH*r0M!8S>pRxUjT+m#oqgOrMt8aW?)4%d(9KMkH`M`)CX>fG1t7rI z^~?bgI;l6$I>zYwetgwhv0ei^^Wfl-NzZGwZ)fXzdVfhe!P|rv2PpMhoYu_b%?6?V{*9dR%(BY#63?jIG z^w=wf?EKjAlZCzeWR&vSSlIR*do1I|PZaanv2%|FAcdEQaCDvL&Rb-Pj)^mV_|Yd1 zn#L!IHo_~#d3-{Wv3p8t&YN%DDvqq%P=sM}*B&`{-g&dnLfR z3L^lj03bjGI7rt!!aHj^V}b|>czgg4gG7h@Tbu$A-DG%qjmD3%b=bGb(G5*Lxz`F0 zGcv8Gjct{pW9$GE@bZ@4S0ggb>1& z066^l(RsV~>@PsK^yaNQ#l2F~b8vs8yY$A@qE4N=<)9n<-uoXuVEJQ@^Naz{<-Rmw zNdBwnzbpdsd99Z}0u?YmPLC7e8x~ z7#E<8>et)x3|(K{PXH8vz#5r1d$}>d%&j{ulO|6Wy)blt;gMl1j%{t*b#{#DVVrK{ zsBw8ackL|zNMXy8r7O)lckL@+@!6i)sRTfHcW>W$PXynQmyZ_$!tm$-FLa%eN5@WG za{yG9FWbXweSXB4Jam)UHMWPH$OB#Kjhiwp8#ZQIRJtD&7(C0SGbY+H?%lFt0;XDGqP@$B-C{Zdpf<2$0Fv(I0En?UbT<(XFkH8OlLg~* z*!J!_SkSpk_Z)b8824l2bLa}AOAKIPtPUO^8_SzKWkx={MRwmkdk+*~LWQ04djWg} zfF#l(48X$q%2n$`o6x<5mp63SNHLF=t=eZFK60#}euG#eJUw`W@D!1@PkKgf=GGk+ z90P!`3pO@r*w}dW+FM2aGX~3c#d(`NJy-JZT!oPbD1ZTQzy<(56A@{bZkU)r7(f#) zKoDJFcxtWIFL8KF2*+$|+|=KPt)7%*M;HLx^>oP?qtpXL zJa~T*-MfmAI7Ay0HwuU>nz=>5ANJ&*&-go#t~;i+Nv8R57O&aq~Z z#RquN{YL(P8iOIi0atjg2t${*Yqy>v3;{stGME%$1{?9v-Dmk~y>|sUrEmh^BLFZE zxZ3ysykyo?8n4y*rM9U4eQasB&s%#5OH>*R&ak!Jw%P#~XEu9JYdmV72c9A(L$JIg zY581R|1V0G$f!+E@g95PT9yU0=?Z}KF$CXvzYJ2o+6TqQ5a@GQzG=K#f*@4$5^ zPd|u60CY?y`5SUd_k%WF0gyh4uU`Oa@JalvFkz7Mr{6zS;l8T@L%DE#Z1U;qHM40P zkh;N2APPhnGzo3G`XDO(D3U$_i19yfeiRAJ1N*|F>c`%Dx_l)M0a!lke}DJ1F@Ek8 zOCUr}_ayK-(*QIHZMym-K3?pV=w~rCS@i9z$qu=EQD<^anc8b$9@r-UFy@VCDpvI@ zGvW6Z{`Ys~j1XG43x|uHiIJ`osQjq`Xc3x(HeLNF5^FH@!|3|)1hx2KbTAL>3lmnH zZ?0UmmS+GI-k#`UKx~y7H_oLQVFH~$K__=FXb@T~@&1%QhtJ@L{Zr+hy-zd3!4E;y z5$Z}>cb*)Bd0<~y-FneOYlcU93_!eLG0@B)NS+`;P!3G~xCZSx;D_ZeE`AY?Z#ZaJ z^Az5D5JNJ=_CYV`F|y zhibX6SYi5d8;4lr_p6Wsf@WX115rr*!{l z{O^_sKm1p>Ud&W21{NVa)*Y4#l8#F}V=4#VmIJh>1^lFqg^o)coU&97U>%s}0HELs z3LhYj75di|y&hZ?#{|WRk&@YAYV^Ks^i;km-*ST2=l+;qS!&euEb2fF#({NUo&$h5 zz>G*$!R6GfAmI&)oA6e~o0&E$1Fbb6Ku`4e1f6N7+ebq>l%G1F=&hW;Z$6J z>xlj{O^i?j&{G2-TSHf`VAZ2Bzo9A+=Q;`o4>5y+X=LgWhpw;)DpdEutO2kIi~_5` zEZ1anGX~ZPf~;6gt;wIw(RwGEX(tVk2E5b&SOg}OczrI``MJrwC!*soM)0R3xEcPa z*xRqj1oIn(Y$K0{G!VQR0DHh7un0^7o1OrcuP)$^i7`ncx|_ncwcvWkgK z7neY0VKdN1Wk4Dr4S1-5EU*Mj5!oUz2CUJ_+lzSCRAJ}cMPGt#DamPF&UYHI{QmU{y(K^(A=Cf? zLPC17>6^Nn&1O^ZxQ@q#qE~;JtH`oOGn$cRMx%#w29l)K1B;+sc`So}I=l}8l@A<#YPlx=U-~JsJ)1lv-zl3lczfX^UHA5q- z)(VRp8X8t-Q)qad3!&k4KMf17`*T?Bx+(n6Mn9?p(g10|Lk*;WC18rc7M?L+4Va?` zyF4y~H=tClusTzCqu!_$8fmLswPs4$@>Nnwlq#R{bn!Cx{`OSKdw+eh1pTNENCTt+ zuQULbfGJ=L7z5UTIRbll27yH$gG}pzATK;Up5`f)D%TKzN1!9nlLklwzSaPM2nK;g zV3OfpA@A|c!^z55td{aru~J@9-Pe^x=c5iv8VF7efJI;u*aSvtb?RK^=VR_@xSMc2 z;fj)wf>TJ;uGFq()&ST9Miqp{k=7rN!}5) zbFgUu>;l6yLr{3mhNmaNk2*!Lbqcy3YiSw`EARx}42Ln{f%uuiUTX=3z(DOCtQr8z z9*+sSo*2Ol3Qc%WX9(8LK-XnWZG&lGo7%8n2p=oY!!$C9#F`?ZcBgg^W(^2`LE`K= zK|DnbH<8Bus1pQpC!lMyuD-!GFi!C=M)0R3c$%67VqJky+f&;Iy9U5Gu&z)j%oDK` z$Vh+QMjas7I{;muwKWdLJ@x|se1QUdia?{ zL0}*aSV;q59@rOxFD`le0i(M0qf_I$_exj#HHvPQYNd+x^jgsdsK078!f8T^-n(a- z_wISBcYhy;{s#7i;GsZojak1j*^%wY<&=I04j#$zwtOob|K!u9?xFsMJu@oP3fD{5 zNFJxZH30SjfL?nX0N@v2e*M7T7i8x1695SaX4bD6Z3p{&4#1xAebYB=+~U}}eV3ze z|3Mi_?;Q-QUC;L1^Aodn?|C6-{Ddi4)oT_G3wy-(NuNA*W|p+lYe&|%tz5M(yMpZR zncH{loVI1_4#%?PtFxn`n>!818#HQ~isSJHS!ub8m#)YjI4CJYx(}i1(q*f%rTbvh z#!XutTej_V^y!zFp){-z)45yv+Vz{VckJBj7?3zLqgaWuVyNQ`fX|Jckhx^p%Iwl* zD|zjyOYNm~0bZ`m${%K!N0`v)KY{j>WB`Hr7>DOcJM{M5AVyYK(`5NX%0 z-^~C1hkps{01V5we#2(RN1uFppKW6axZoIoknP{khu`TLS={9-*Ye(b|0CgitJiEO z1TL1ha@ATXnOWJ~xCxU*ur_JdDivk^{nIZBdAAoYUCo1S>{vjpAm8T?-hJ;w;XGTm z?sTwpEaxp)Vn-f$%5S~>u8`-@;bY?PfD!OsjjrF!{Hc` zG$K>_YZ#?GM&G(^r?iH=Q{YbdZQIABjT=8XYb@`yU_QW|W4y`JH7-8AdCPWb-jso3 zbp;?mr8EgrwR)HUq(Os+WuP-pm^4)cO#gvHgng5z&Jg##ar4dmPe1$eK}4N~BFN6Z z@|plJcERod5MEE0hq*(1=_Q7xT(`;iN{E7rFHV)v}$1Yp8Yvv#*TLjfc*yy z&gj^wt4qklcJ7|OXWxMwL_G<824oao--ZYCi!YtY9X)28*x%eeR-R8+ z0HT8{{Qv`;c<1hYIsf_P*N5onQbRud?289y9zzFk$;h;G%U7%^f0 zgn{k=uv~?zDZl@b@+g@Pf7$sk^(_yPSsIqJ=FGSM`r99mo+?&aun}G!LfRjG{ORGO z$MEWvPyoD$$3Wb$X^Z2t&%Z3>A>tap{qBc{2=!6!!o|z&xIq--&o4b6yx6@j92C4j zDFET^0^SJQrTJ-{py!PS06_T=56Z(canLiKK)_HC_VIrvW~)@i^~;gx@=ikUg#IG% z;9TtEHC>AD%golsO5({)}03?FfN? z`~BXdmrlK$i}A#&)k77%Kjg1dFG>h`5l-VtaU2U6?c0AS=apA4Ee?sUCM`Q7l6?UbubCe4>u3Eh=8=ht&KPGQF0G{K+*t_q%CxU}j7Qlir zF>E931t?HiEL~{{03uA5rgiUG5K>CV0Fe&hA)MUBd!XNa|Kr1d{q*z0dJUY9Q@|_3 zI3XrJ03zI}Fk!*gKl}Wv2P;>t6+JVIVZw`53jbTT?I-|j=dOJYjB6_8L3j*1831wp zTet0UynOc6+^@d=<^fH95d5S%_huacT)lQf_OcbL#UF-t06^%tRGEsR*XAw&(LY8# z`+O$6zIFV~yGvZpbOtg0ugq-w4;;>66P-2qFHIgjb}|<*0{{`qMmK38dWD$uY}u;4 z;!S@9KMp=;?m}VM$&>)ZT_Vfw;G}m7R35;xW7l3WO#S&k|9yDm=!rs}BHV0*rWGH* zvk(=I2@C1pFtcY7835tMVLUOiZX>aR;p!u_oH=`*P?1VvfnNW-L>|gs0NG!0b5-?0^(zaND$tNkc;biU269mP8aJB)ESK!yPj75n8^|9Eio)}8!5{1`*i=B-mvHpUq1H*73Ik(J4oZQ6B8 z1E~M~^Dhsd=V!Lqe#|5TNbn-rJ}mLg(Qm)|;lZujZ{@>tZPlhj+A;oa`rlvwc*Osy zjR3`pm8++G{>4`h09L>oc`$H{$rNS_1EBOl=-&LGGOlSTKXWHNC#@3zJ<))x5LjBK zy8y)FXc*&@9*f7x0Iim-+ox^iLt6%0wghwmz!NW?&Xqbb3l}Z3_mn*C!OC2-ZeupW zX9iNhaM$h^axjU?@_4e;brQtY7$6L6)}l=s#=Ov}@%!MTPwsc^7B4>D!Y*Rf>h;-x zCGsG2#3LnA_Z;~!De(;t9^}CoV&b5JS!M=6x(j^-YPpjs&VtwJ8!*{k97P1UFl;x$j5u4w(B=;iFr^D{T|N}BV7rA z*pIN_zrX(eC_JK`=wY(+(vm=^MFXA!5U`R?U`Wr2N3>S*V{rMtkeZ

uYL|S+T5aW5cS)b&+I;m%d=k+iKjtP&=e3;$1X)D27 z1OPE^xNz|@JAnBDKUNsuyI&D!Na>sb7Xm98N&Bedk_Li91BkvRO#JitU1#kIkIGpZ z#`~pd03aTX!#*}iB2D+jy5BrNUtAoWBRD!AwWI&r5q~X$VIDo(0^|7Z3`gmCPI*}b zK>qF{uN2y*Iw1{MLjwdr0wCQ0NCTGD00EH1Z&~q^muC$xPpzE^fCNASAZfs|8Xy3Y z_$@1bHP3+3tl=FJ011EuK+=F^H9!C)@mp5>I>2+J}_r$M)$?LA>2ijaWveX?e4vzw9)FjcB7_w6kQ* zP@6MQ8NDCpW}VK}lC)VAeo}5|(Wa}q))j#MYB;Tx<8M3NX+VG5=q?1!Vy8dh$KdJ? z1pQr~!K6)B@I$(80EEjf1(843)k3&HvC|ATq78$=PK2NgLjGQ=g~Oyxb=*xjWc}2*#VT-d02oyWbU?b`^80_@rn4c@a!WPn|HqgoYH``Xzrn5Sh@7Kix z43s+;s~9Ym?hb)wrx|QCOIJjWhS-Z=Mx@ z-7Xx<_p~hOadJD|X#=%9O`5e%Te^Hz_U^s=b0$rmo`o-&tL1kmO>Y}UxU+m(_ix?4%Tcj%4Ua$~ zKbKxMmakYXW%r)_IlNs$J@)CFm~rUvv7B}tI;Y{Bk#!rTZcg6jke}b(ZN2Q2pHI)a zMA>pXrO@$YeaKHAKJw%^SI5Zhl-G-vZSo+7j%9gJp_9-pp zvAlZPh%$X;r`&F}?SKH_idAc~TeayRG#)Cd|G*&`*hc`=7M?FyxYW+-ar(@;_IV2y z+ebe3qI>r0n?8Qx6wyOuB6oKw7m>TixynZXEO_;bt9nvPuTm}4wrkG|ITb2Z7lDWN z4y#?ytDCgmZSE^O<#wxW2Lu2S0#BMUL+qTZ*KWwhJ_4XN045Gf%1C-2bI&7m-?r)RGqP0Q~u*M|DOeWwKw`fIb*g)n9W`pz_PArnMZ`LZx642WVA6j-<)mYP z?e=WUaR+d&@)%K{Vc~Uceftl}SiNRL_OuzZ?d2-)@BQMT(05>=i9`S}wo4C>J$@tF+*fwWwW_uqFaT`RE{30FU6H+I z+fGNVusSvZpmqR4v@`fw^<>`LYu&b!Fs2IlVS6-xW08VK>$+S-T90>@p8)9n7@#l# z#?St;@n6*S?70i12us9oB zr(RTQ!EA8B452d+x!Nxmk*oafrV{|Y2O#PiCIAuu-MRtDMdc1O{gFp* zrz;ToD_w4Ea0Z;{CW@tb& z*r+5je{@K9&MB`?cVOg?JaRkTxi(+tF@ue$6SWgFK_2~|b{Ep9F|Bd$qqrdIXY!d(pfCNDD z02MVL2Z>rsac^Gzaig=m zEmv-*RA-*78&RKTuu-Ya<#wxW`yGJYdnTl3WZJoJzWw3BuH7%>Z0BE*|JB#uJjizB zazm0v1k4*ujIvYSIG%`KdW;$DG|EP$&fpEGBA*$Yne^+YT>sB+J?yYQIk)}ZO*#Gk ze&fNgKfd7VPk7cV2h-)|fBWMRUh*mJ;9Az@7p~=4Xr*S3SpHUK?DMZ4NE=kT{^p&#`8VFUoiE*|WnF&ZT8@?GHPTMKY=pgLu+vBzQ3vw+ z)Cwk+zsuQ!d3`^+_JD26m+`mG-S2t*w8x*wl-nuQo0fGW>(dN2Dz&-XZnbT{0`Sw% zzkG1{%C$Ua4SwR}soa16{L4dU>8|$6FWgmrXX!@Tsh5qg-3)dbX(Q@DUY~Msxx3x> zqt_pFzkJdu;5xswFE8=iyARzhPo7V1r!(!j+HYiin!!e;HkaG2w(U0n;-!u08Cl%X z<1gkqYh=7F7$GuVk?$;z+J55cr@mZd$vc?kEW{$LY^kSaCy4B+eX@{myNg{8eKO!^T@Lu-_QSaI zN1b|rF~@f03Li}3VX3ujG{R+T~m#^l%``(B5<&Da= z`I+GSyYIa3G@a#hwv=DEvwW`h8)>IrHsTu0V5gBbq7LNs=?R>0Ot(uX@_WC1;l8uu zF%#VD&UvTl&W>aI<#xK#ptE!%>(dN2Dz&-XZnbT{0&sKkHb-VwHrFt!X^}@=Liw=Q zmYV(uAM|n7_^$TLFWgmrXX!@Tsh5qg-3)dbX(Q@DUY`s&T9<8iuFFaK?K7@=T<0Q> zx>RZ3Hf_kyA3uT@sI^>{Uv8%}?YY`-WPO^!Mx{2F+pV_kR{*x}*f}jVE#uMAV<(G@ z1LA>bz_Dkqz8?QYi2TA`iOE^Ik#_23BWyQ=okrTI)EO9Xv@XL2^vM|dpHCjeo+vsF zhzFtp$H);wGPRb=^6S;^M%JepY*cD3zB*t&=53Un^2R}(c=I!ZokrQH)EO9XJXtnbI3pVq9T*FYnmN(lXxcb? zmoo?Qu&?EYr4CQZWXI^)?nc$88EjN)bGhAW+kOWiE@08(<=J>15YWR9e+svL!)Av! zAW*6pZ_6{nPI=>aYa@;~gPlg$sMO{RIG!$BtXbs1^MHUJe)vDiPVaU% zqCU-Fqf(p8?N-~?1%Rc>RP@SgVVyp@Nz2q`E!w8BZEu#aNq*shW~Y%hqVDvnPb2Nr z%SK$UlAYxmH1ueemVt^bYw&;lQL|U~BIAK9UCR^;fo8%WBXm*;xM%1gB?JON0VbcO9U*v^Nq)qRJdRTu~(x$v_)wXp3;M2v+++zj> z$`UroFFerfG=q(3Pcz$DtYXy^UqDUEIbaiMQy%~-X;WUeYTLR15GT+pywn4rN}&*| zgg~*=3^t-Ig27I`!eA|sbCy>r{3UIA217M%vO0CO)D3`ve|bX@_60{saWEtTRgJI!FDyYOQI^H*JJwbP#vbO(O^uFqi9 zCaY6tOWgs86TyY{oYkpxX(#}tC!+NdF2^QibriyJAt721qWt`AT~?8_O?9HG0iqxYL{%UJ z6oP6nYk&Yq03-mC1}v)q0w9Usvf>YB&xWqeJxlqJ03-mC1}v)q0w9Usvf>YB&xWqeJ@1wPNB|@Nk_IfR0RkY2-?HK-FUdVGDVXbt z07w8N0FnkQs{sNaiQlr~4`$DXuFXB~mHxlqJ z03-mC1}v)q0w9Usvf>YB&xWqeJ@1wPNB|@Nk_NoiK&#dr(q_$>Z=W`Oc2;!b7OAcP zT(*3blv8KUDHrn`jxBK^CnK3 zmNjekeEYTQH}hM!>8J{)KK&9iX3m~xm!7L?^)TCoi&yecMnd0#8C$pQbZpqT#liAK zMK@2qdhJI3{Dn*GW1pXxb@B4myn%y~GFZANOI-kniYCGPSMXH-RR2mEFdBmRKJBH; zujfTIZZ3L#F`c`mzkK%9Ts0tVPTuBd)}l=zNKT(ICu=J2L9*j2RjHW*nBx1b*mwBo ziJV>u{nJ@`ctkzh)z@$2BOlwRb*T#g$@8Pmr_}jqpZ|4%zNr-oTJpmyd+p-oJZUHk zU|qj)E5BNeaK&?1tXw_i#h1?H{_Uxfg~DI?c^gJGOND3oRI$?cQ09#{Zs)^Gl;%5i z`fP67_A!M(DouB_P5`8korWxeSOZ1_uy?|MjLloNi(x7Q&Y{D{a@w_zRRj~l)+y6w zik==jM!Fo3I5gw@YnSp63S&RU6;JbHhSEG(U$JU!_RypenezSaZtDU-3W5E9rzdZV z+CWJIMu)&1W4fjtK5{%q3LJQLub#h{*NFGvr2EDyEmxtcI1U$4r=blYaEVfdXK;}pv%JSoo+{$WAq{1~%fl>hvEqe62dHAK zu}QO5B2@Vq;(Hhatkz{n%k7wqfCsmJ zL$YJRqNRmqc$xh}hmFh}KVgbu_&a0PT>F}J8?#wn`Eu&CSy{)Og!td@e= z;vKv8Ixt2k&+G0s0Z`)|!`+Idd;~44XaJtu7XFcy%U7=DUAu8JfAyLT*_a(xy8bN#kzuSNSNB|@Nk_IfR0RkY2-?HNO zxA#Hk_rC{903-ks07(Ou)c^sI#BW*glLzL156s_fKma5F5&%g9mel|Oki>6U@%!8R zp!56R10?_w011Gk0n2KD07&AutoX?T^S=k??=~K<(%{qVY;?Q9qTyS#QJn}A2K_tgy#T7%~F>KtXtRVLsC5bOa&w25Br%gWImfDz+I zr1t;v_I+OopUy*&m1+Rmg9e$vwJ!0A#Y+6QE6CFeOm7!$yd zE&#+d9L;(VptJ(Y=={*6J5$7%W~6D}zz3fEri3>0c8XXR0JcB2Bim>(Q~3l~Pc#5+ zy7B_?tcARD(Y85&h_-XpzG~^-1MqLfQxe|4obQP^=@^2V(Hej@|H^ArtrOsZGXkDD zfG2M!w4GYpx=QmJfKU9bn2n}?31mit%+vCrO=wiDBhbvRIpGHwqV3e$)>WGK0Q_q) z8vmm|@9^nkE?QuSalj{djjDA78vipd0MT}8ZR;vc4*;fW5hUd$Z_(Ep-~p)mbhJFI zqHS{l(G}#>(!B=Y|NraL1VHit1J(lsY@t!LPC&pj7x3imrPj8t(!2#=N-zPib@EEC z|7SM?x-)C>p89`&i)*!ESQD3-5SlN}Qqmu^(~&dTi+6PJGW-1$6b=|=2V z1DvZg0-y!}_ImSGuEm-~TsuI2`QeMd|i z{I3tVo;S{j+pwYc+ZVW&>z8sd$9Ho`XLcoidzVYNdyxY)TdZEl;d)q_*_VL;zy%AJ z+NGU;_n!SZ&yE=MSRtFO2ZHXwgOpMe?EXUwt3#C8+UAqQan291UCYt*c5 z*t@h`K~6250O%$FJM2&9o-S93tM~jUu6%T3u6mbPZs;$67a)=F&PA?R#VTCH&_ph* zUjkR5NfWM0`*w-|iJmo?tK7O3*LeOku1sVduI1XrV!ozJW^-lh)#svSP2$QmYQ!~~ zK3+_Vo->83)C$K<7mfpn8JH@!ZNr5p_Tw5%9K#i_T#bvrRRG^!w_o8ZG;S>Bi#@rA zd%A2zuI`xOT%{H*I2rE`Xk$!_3P-1mM$T67!5YkVd zIhPA>a?RR}LK@0JTGFtQnOCk}&)=N9-7$04yh7lu6&h)K>+N^$H)+~R0OqLCV>3Vc z`0w`_#QO9dm;rdA9N2g1^3}YBi<^1X|oF1z{=2TsRlS#X#_xb0LVW|QM^)BuDc{WM!4MJz!m`> z5lMr%#&f5NplLASS*HL5*t%anDddHh#m49ceg7`^RH<^@z^@8CxWw_2k!L@wJtdhBFwuipI&d2K9h+xFd#=f+MD z%GthSw*w%BmxpwO&U5B2v`5xynELK}AKY&g)l9GvUMaStqMN05jq92I`n5OmYu1Vo zU>MuETl(!c-_FPJ41n+?VFTdF&TG`t739>?34m?@uvUv?7>353KgvB_z7kh0rjz)C#|bb2J_v8c z;|^~Zk3(9Wkx5+nMp3-SIDzYS;kamr6o3Q&@izA)4_ImFj!+xkAOm2HxGv(c-7XyC zs&r8HV$BA_K=1&iV}N`19^k#abGeP8nx-O@y!+1k_fNifIv3!>@9OK<^H;52FMwm( z^x5`{m#*fmUb7*4U}91Rzygr0->}(n>GJD&>=<~BZ{E2pKnUq-037zrsLWlv_vIig zz46BF{2o0M(s6zq_u7Tac^x}-NkXN(&^ISa>0(?0m{llx7Z zwN3*7;q{^Xo44-dhlSTQEc9hSRRf%>GyW(XFeP*6reP z0w50r*2%nC!UL3#0VZ$R;g~pSn&5>Y{Dnt`u{ic?)3%d1riXF55hI_=+_7^{4nPW9 z7B5+my<_Lz9G0IgnVo6?gm-uA_FDq@4jn$03kbub1H2GAql^w6JEsGvtX#H)*ZR!x z(U}O7**>;}ohSn#^@fefj`bUo9jjKaBM;Cl9)sE}aK+}$xh4yybC_`Gb>}=+qG}DU z$F)-eFaWGlVYRs?3ukbRrjFyv)o-8(Kpb1HVI!`~*@MDy2w#iwq4nUOKID@A`zcql zdM&{#M1A#n{|Z;5dsktM4#&a6W8o{pWZ^h|5~D944#O6BcsQ=(p>16CuAPN-DFBgH zEw+;|u845C4?h7@s#ZAH_1qyLF9A>=*f9V}mr4M{*c`%5^ii<>jfRlLyFyfdLu-MAc3drf3~-5%0Nm1Lt3g6l1=e>RRz57aF89!li7Cbe~J|i9H!8V>*WcdMJgx@G1P-8GeI^YV=6=?{0 zJ9p_Wzz_hGJ_ZxV&tM}T!hKe*-b*#Wxk@7dN&v`UqqbzTrqVnJJ!|xctai)*)gg9sOCUbZeBi(~uP(ug!xHkL})AWaXpb$^cmy4&H^#>+fSbNAe8`TTiq zHM>}vE6Ay(>jFUOSX8ie9(S(?o+3OuJYLd##e8n)e+p((-94W2{ppG8Sr^czD*)2V z5RCJF8KjI_`uk-F!k@y?>#&UJyn2Gbs%1f&t^i1{!!j=b{r);Eh>Ko`N&pO0z(Sjk z0eH_@C`2zrH7@}5dLgRQKNNQ+8nz#=8ft%RJG~NL<5*�wdV$f;L^f4vSuiZ(acE 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/B4-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B4-initial.receipt.json new file mode 100644 index 00000000..2b86f921 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B4-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "85f51bbf3a543213727ed127d8677c63d584f55479034b039192705a1bfa2b35", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B4/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B4/initial.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 2, + "retainedRevision": 1, + "commands": 44, + "nodes": 45, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 304659, + "spawn": 44886, + "startup": 30406, + "render": 1579, + "encode": 481, + "write": 258, + "total": 385959 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty" + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/B4-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B4-initial.snapshot.txt new file mode 100644 index 00000000..528b61ee --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B4-initial.snapshot.txt @@ -0,0 +1,48 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=32455000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33047 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=131 canvas_frame_encoder_cache_actions=82 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=39 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=39 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=19 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=82 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=45/1024 widget_semantics=45/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=462 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=45 widget_semantics=45 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,18 284x164) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,18 284x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,18 80.87256x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(240.19629,18 61.80371x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,50 284x54) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(18,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(18,50 37.142857x54) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(31.732073,55.25 9.678711x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(30.871801,76.75 11.399255x22) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(59.142857,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(59.142857,50 37.142857x54) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.19622,55.25 7.036133x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(72.014656,76.75 11.399255x22) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100.28571,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100.28571,50 37.142857x54) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.50216,55.25 10.709961x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(113.15752,76.75 11.399255x22) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.42857,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.42857,50 37.142857x54) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.48193,55.25 7.036133x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.30037,76.75 11.399255x22) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.57143,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.57143,50 37.142857x54) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.91245,55.25 6.4608083x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(195.13634,76.75 12.013037x22) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(223.71428,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(223.71428,50 37.142857x54) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.74884,55.25 7.0737305x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(236.58607,76.75 11.399255x22) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(264.85715,50 37.142857x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(264.85715,50 37.142857x54) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(279.89172,55.25 7.0737305x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(277.72894,76.75 11.399255x22) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(18,116 284x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#17475671269766583825 role=group name="" bounds=(18,123 212x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15731116241903212993 role=group name="" bounds=(18,123 212x6) focused=false enabled=true parent=#17475671269766583825 + widget @w1/widget-canvas#15729049687520163901 role=text name="0 / 20" bounds=(242,117.25 60x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(18,148 284x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(18,148 172x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(18,148 172x34) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(18,156.25 172x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(198,148 104x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(198,148 104x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(198,156.25 104x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/C1-after.png b/experiments/render-loop-cadence/astra/final-captures/C1-after.png new file mode 100644 index 0000000000000000000000000000000000000000..65009d6a6a0c0e358d9c81de293342a1b73e3444 GIT binary patch literal 256283 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�`h}>%>##cRj?L5B1wi)r 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 G`2Pda;#Qvk literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C1-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C1-initial.receipt.json new file mode 100644 index 00000000..d49c1224 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C1-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "d6d7ac89536a2251537e92e5c64321dd8f394cca75633f1250db9f231e8d48d1", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C1/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C1/initial.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 2, + "retainedRevision": 1, + "commands": 44, + "nodes": 44, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 344110, + "spawn": 54148, + "startup": 37905, + "render": 1782, + "encode": 480, + "write": 374, + "total": 437417 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty" + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C1-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C1-initial.snapshot.txt new file mode 100644 index 00000000..f2be143b --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C1-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40154000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33331 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=132 canvas_frame_encoder_cache_actions=83 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=39 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=39 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=19 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=41 canvas_frame_gpu_packet_cache_actions=83 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=466 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=44 widget_semantics=44 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,16 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,18.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,48 288x54) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,48 37.714287x54) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.9523,53 9.809688x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(28.850624,74.5 12.013037x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,48 37.714287x54) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(73.00018,53 7.14249x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.56491,74.5 12.013037x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,48 37.714287x54) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.84703,53 10.877375x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.2792,74.5 12.013037x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,48 37.714287x54) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.42876,53 7.14249x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(153.99348,74.5 12.013037x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,48 37.714287x54) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.48389,53 6.4608083x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(195.70778,74.5 12.013037x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,48 37.714287x54) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(239.8154,53 7.2263727x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.42207,74.5 12.013037x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,48 37.714287x54) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,48 37.714287x54) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(281.5297,53 7.2263727x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(279.13635,74.5 12.013037x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,114 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,121 224x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="0 / 20" bounds=(252,115.25 52x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,146 288x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,146 166x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,146 166x34) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,154.25 166x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(190,146 114x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(190,146 114x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(190,154.25 114x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/C2-after.png b/experiments/render-loop-cadence/astra/final-captures/C2-after.png new file mode 100644 index 0000000000000000000000000000000000000000..85a212ad675e4db74e75dd8f0d289a5ca91771e6 GIT binary patch literal 256283 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 T_;ru+U|Yww$%!Xh4_WfRT(B6t literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C2-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C2-after.receipt.json new file mode 100644 index 00000000..140529af --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C2-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "0cebb86f890ee357dcf4de4aad6aff5b999f394d9740de20112ccd8d0baf7991", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C2/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C2/after-clicks.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 5, + "retainedRevision": 4, + "commands": 46, + "nodes": 44, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 321957, + "spawn": 54928, + "startup": 31288, + "render": 1862, + "encode": 519, + "write": 286, + "total": 411573 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty", + "actionFileSha256": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77" + }, + "interactions": { + "actions": [ + "click", + "click", + "click" + ], + "mediaCommands": [] + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C2-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C2-after.snapshot.txt new file mode 100644 index 00000000..3212b1de --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C2-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=42187000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33731 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623615157736000 gpu_input_latency_ns=2768000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=46 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=148 canvas_frame_encoder_cache_actions=99 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=48 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=25 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=99 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=514 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=44 widget_semantics=44 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,16 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,18.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,46 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,52 37.714287x40) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,52 37.714287x17.161291) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,71.16129 37.714287x20.838709) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,52 37.714287x40) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,52 37.714287x17.161291) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,71.16129 37.714287x20.838709) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,52 37.714287x40) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,52 37.714287x17.161291) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,71.16129 37.714287x20.838709) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,52 37.714287x40) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,52 37.714287x17.161291) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,71.16129 37.714287x20.838709) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,52 37.714287x40) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,52 37.714287x17.161291) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,71.16129 37.714287x20.838709) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,52 37.714287x40) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,52 37.714287x17.161291) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,71.16129 37.714287x20.838709) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,46 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,52 37.714287x40) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,52 37.714287x17.161291) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,71.16129 37.714287x20.838709) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,108 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,117 224x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 20" bounds=(250,111.25 54x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,142 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,142 164x36) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,142 164x36) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,151.25 164x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(188,142 116x36) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(188,142 116x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(188,151.25 116x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/C2-initial.png b/experiments/render-loop-cadence/astra/final-captures/C2-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..e12739bd1bdc9cd194c3993d325462a298903cee GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C3-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C3-after.receipt.json new file mode 100644 index 00000000..2e5b81c6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C3-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "c14930d3ba22eecbd0010fb5a7f5ff43c44cd40d816c023e82e08c9ad817439b", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C3/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C3/after-clicks.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 5, + "retainedRevision": 4, + "commands": 46, + "nodes": 44, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 317662, + "spawn": 50254, + "startup": 28034, + "render": 1724, + "encode": 481, + "write": 258, + "total": 402855 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty", + "actionFileSha256": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77" + }, + "interactions": { + "actions": [ + "click", + "click", + "click" + ], + "mediaCommands": [] + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C3-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C3-after.snapshot.txt new file mode 100644 index 00000000..fddff902 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C3-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=38380000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=34020 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623617110003000 gpu_input_latency_ns=2640000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=46 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=146 canvas_frame_encoder_cache_actions=97 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=43 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=46 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=25 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=97 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=506 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=44 widget_semantics=44 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,16 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,18.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,48 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,48 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,53.125 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,73.625 37.714287x21.25) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,48 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,53.125 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,73.625 37.714287x21.25) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,48 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,53.125 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,73.625 37.714287x21.25) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,48 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,53.125 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,73.625 37.714287x21.25) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,48 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,53.125 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,73.625 37.714287x21.25) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,48 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,53.125 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,73.625 37.714287x21.25) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,48 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,53.125 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,73.625 37.714287x21.25) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,112 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,121 232x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 20" bounds=(260,115.25 44x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,148 288x32) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,148 168x32) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 168x32) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,155.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,148 112x32) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,148 112x32) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,155.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/C3-initial.png b/experiments/render-loop-cadence/astra/final-captures/C3-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..0eac1deae2604b192e6160b75948517d339de8ed GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C3-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C3-initial.receipt.json new file mode 100644 index 00000000..96b1e35f --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C3-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "c14930d3ba22eecbd0010fb5a7f5ff43c44cd40d816c023e82e08c9ad817439b", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C3/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C3/initial.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 2, + "retainedRevision": 1, + "commands": 43, + "nodes": 44, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 346384, + "spawn": 42757, + "startup": 28553, + "render": 1790, + "encode": 492, + "write": 261, + "total": 423147 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty" + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C3-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C3-initial.snapshot.txt new file mode 100644 index 00000000..1aee6408 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C3-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=30825000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33897 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=43 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=134 canvas_frame_encoder_cache_actions=85 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=20 canvas_frame_uploads=0 canvas_frame_retains=20 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=41 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=41 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=19 canvas_frame_text_lines=19 canvas_frame_text_uploads=0 canvas_frame_text_retains=19 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=41 canvas_frame_gpu_packet_cache_actions=85 canvas_frame_gpu_packet_cached_resources=20 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=44/1024 widget_semantics=44/1024 context_menu_items=0/512 text_layout_plans=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=474 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=44 widget_semantics=44 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x20) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,16 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,18.5 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,48 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,48 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,53.125 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,73.625 37.714287x21.25) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,48 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,53.125 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,73.625 37.714287x21.25) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,48 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,53.125 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,73.625 37.714287x21.25) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,48 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,53.125 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,73.625 37.714287x21.25) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,48 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,53.125 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(182.85715,73.625 37.714287x21.25) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,48 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,53.125 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,73.625 37.714287x21.25) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,48 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,48 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,53.125 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,73.625 37.714287x21.25) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,112 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,121 232x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="0 / 20" bounds=(260,115.25 44x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,148 288x32) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,148 168x32) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 168x32) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,155.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,148 112x32) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,148 112x32) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,155.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-after.png b/experiments/render-loop-cadence/astra/final-captures/C4-after.png new file mode 100644 index 0000000000000000000000000000000000000000..95e07379b73b2d9644d4164d3d6d51583aac053a GIT binary patch literal 256283 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 LHZQdrw&?!@zl0l{ literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C4-after.receipt.json new file mode 100644 index 00000000..3cba4a78 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C4-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C4/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C4/after-clicks.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 5, + "retainedRevision": 4, + "commands": 45, + "nodes": 46, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 322020, + "spawn": 53895, + "startup": 29944, + "render": 1797, + "encode": 499, + "write": 235, + "total": 409791 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty", + "actionFileSha256": "06da27fdf07d9f79ac341bbb70d5593e056b492fca31e4504b7c7b120d7e1c77" + }, + "interactions": { + "actions": [ + "click", + "click", + "click" + ], + "mediaCommands": [] + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C4-after.snapshot.txt new file mode 100644 index 00000000..a0007315 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C4-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=41479000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=34302 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788623619070140000 gpu_input_latency_ns=3049000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=45 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=149 canvas_frame_encoder_cache_actions=102 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=22 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=47 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=50 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=102 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=520 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Weekly goal" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,154.5 288x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,154.5 172x28) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,154.5 172x28) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,159.75 172x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(196,159.75 108x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-initial.png b/experiments/render-loop-cadence/astra/final-captures/C4-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..22fed57c09be5ad6ecef5f8c1ebc9c232519579a GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C4-initial.receipt.json new file mode 100644 index 00000000..2af59daa --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C4-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "b0b50cfb5e0fffb4cb47323a356cc8877790fa63e3339a6172a3ae6a84fcd4c0", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C4/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C4/initial.snapshot.txt", + "widthPx": 320, + "heightPx": 200, + "scale": 1, + "pngBytes": 256283 + }, + "renderer": { + "pixels": "reference", + "textMeasurement": "coretext", + "eventsDriven": [ + "app_start", + "appearance_changed", + "surface_resized", + "window_frame_changed", + "gpu_surface_resized", + "gpu_surface_frame", + "app_shutdown" + ], + "framesDriven": 2, + "retainedRevision": 1, + "commands": 44, + "nodes": 46, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 343311, + "spawn": 48936, + "startup": 34623, + "render": 1817, + "encode": 480, + "write": 279, + "total": 424976 + }, + "inputs": { + "clock": "2026-09-04T09:41:00.000Z", + "storage": "isolated-empty" + }, + "warnings": [ + "Weaver working tree contains uncommitted changes; provenance names the checkout commit." + ] +} diff --git a/experiments/render-loop-cadence/astra/final-captures/C4-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C4-initial.snapshot.txt new file mode 100644 index 00000000..472e4efc --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C4-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=36909000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=34177 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=44 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=138 canvas_frame_encoder_cache_actions=91 canvas_frame_encoder_pipeline_binds=22 canvas_frame_encoder_draws=22 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=21 canvas_frame_uploads=0 canvas_frame_retains=21 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=45 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=45 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=91 canvas_frame_gpu_packet_cached_resources=21 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=493 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,20.5 80.87256x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(242.19629,20.5 61.80371x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,50 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,50 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.613003,55 10.488281x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(29.157516,74.5 11.399255x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,50 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(72.76869,55 7.6054688x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.8718,74.5 11.399255x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,50 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.47908,55 11.613281x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.58609,74.5 11.399255x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,50 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.19727,55 7.6054688x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.30037,74.5 11.399255x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,50 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.2807,55 6.8671875x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(196.01466,74.5 11.399255x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,50 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(239.60535,55 7.6464844x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.72896,74.5 11.399255x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,50 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(281.31964,55 7.6464844x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(279.44324,74.5 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,114 288x28.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,114 288x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Weekly goal" bounds=(16,114 68.23828x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(270.42578,114 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,136.5 288x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,154.5 288x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,154.5 172x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,154.5 172x28) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,159.75 172x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(196,154.5 108x28) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(196,159.75 108x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/astra/harness/collect-usage.py b/experiments/render-loop-cadence/astra/harness/collect-usage.py new file mode 100644 index 00000000..3038b023 --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/collect-usage.py @@ -0,0 +1,89 @@ +"""Extract only this experiment's usage and tool receipts from local harness logs.""" +from pathlib import Path +from datetime import datetime +import collections +import csv +import json +import sqlite3 + +OUT = Path(__file__).resolve().parents[1] +SCHEDULE = json.loads((OUT / "harness/schedule.json").read_text()) +EVENTS = [json.loads(line) for line in (OUT / "harness/events.jsonl").read_text().splitlines()] +DB = sqlite3.connect("file:/Users/dara/.codex/state_5.sqlite?mode=ro", uri=True) +DB.row_factory = sqlite3.Row + + +def instant(value): + return datetime.fromisoformat(value.replace("Z", "+00:00")) + + +rows = [] +for run, batch in SCHEDULE: + dispatched = next((e["timestamp"] for e in EVENTS if e["run"] == run and e["event"] == "dispatch_requested"), None) + if dispatched is None: + continue + thread = DB.execute( + "SELECT id, rollout_path, created_at, agent_path, model, reasoning_effort, tokens_used " + "FROM threads WHERE agent_path = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 1", + ("/root/astra_" + run.lower(), int(instant(dispatched).timestamp()) - 1), + ).fetchone() + if thread is None: + raise RuntimeError(f"No harness thread for dispatched run {run}") + usage = None + usage_at = None + completed = None + started = None + calls = [] + results = [] + token_records = [] + for line in Path(thread["rollout_path"]).read_text().splitlines(): + try: + event = json.loads(line) + except json.JSONDecodeError: + continue # The active writer can leave the last line incomplete. + payload = event.get("payload", {}) + kind = payload.get("type") + if event.get("type") == "event_msg": + if kind == "token_count" and payload.get("info"): + usage = payload["info"]["total_token_usage"] + usage_at = event["timestamp"] + token_records.append({"timestamp": usage_at, "info": payload["info"]}) + elif kind == "task_started": + started = event["timestamp"] + elif kind in ("task_complete", "task_completed"): + completed = event["timestamp"] + elif event.get("type") == "response_item" and kind in ("function_call", "custom_tool_call"): + calls.append({"timestamp": event["timestamp"], **{key: payload[key] for key in ("type", "call_id", "name", "arguments", "input") if key in payload}}) + elif event.get("type") == "response_item" and kind in ("function_call_output", "custom_tool_call_output"): + output = payload.get("output") + if isinstance(output, list): + output = [item if item.get("type") in ("input_text", "text") else {"type": item.get("type"), "omitted": "Non-text tool artifact; agent capture files are archived separately."} for item in output] + results.append({"timestamp": event["timestamp"], "call_id": payload.get("call_id"), "output": output}) + names = collections.Counter(call["name"] for call in calls) + row = { + "run": run, "condition": run[0], "batch": batch, + "model": thread["model"], "effort": thread["reasoning_effort"], + "dispatch_utc": dispatched, "harness_start_utc": started or "NA", + "completion_utc": completed or "NA", + "wall_seconds": round((instant(completed) - instant(dispatched)).total_seconds(), 3) if completed else "NA", + "status": "complete" if completed else "running", + **{key: usage.get(key, "NA") if usage else "NA" for key in ( + "input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens")}, + "model_tool_calls": len(calls), "harness_tokens_used": thread["tokens_used"], + "usage_receipt": f"evidence/{run}-usage.json", + } + evidence = {"run": run, "thread": dict(thread), "dispatch_utc": dispatched, + "harness_start_utc": started, "completion_utc": completed, + "usage_timestamp": usage_at, "total_token_usage": usage, + "tool_call_counts": dict(names), "tool_calls": calls, + "token_usage_events": token_records} + (OUT / "evidence" / f"{run}-usage.json").write_text(json.dumps(evidence, indent=2) + "\n") + (OUT / "evidence" / f"{run}-tool-results.json").write_text(json.dumps(results, indent=2) + "\n") + rows.append(row) + +if rows: + with (OUT / "usage.tsv").open("w") as f: + writer = csv.DictWriter(f, fieldnames=list(rows[0]), delimiter="\t", lineterminator="\n") + writer.writeheader() + writer.writerows(rows) +print(json.dumps([{k: row[k] for k in ("run", "status", "wall_seconds", "total_tokens", "model_tool_calls")} for row in rows])) diff --git a/experiments/render-loop-cadence/astra/harness/events.jsonl b/experiments/render-loop-cadence/astra/harness/events.jsonl new file mode 100644 index 00000000..9df5b5f6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/events.jsonl @@ -0,0 +1,31 @@ +{"event": "dispatch_requested", "run": "A1", "batch": 1, "timestamp": "2026-09-05T15:29:35.964481+00:00"} +{"event": "dispatch_returned", "run": "A1", "batch": 1, "timestamp": "2026-09-05T15:29:54.830566+00:00"} +{"event": "dispatch_requested", "run": "B1", "batch": 1, "timestamp": "2026-09-05T15:29:54.830782+00:00"} +{"event": "dispatch_returned", "run": "B1", "batch": 1, "timestamp": "2026-09-05T15:30:10.491370+00:00"} +{"event": "dispatch_requested", "run": "C1", "batch": 1, "timestamp": "2026-09-05T15:30:10.491607+00:00"} +{"event": "dispatch_returned", "run": "C1", "batch": 1, "timestamp": "2026-09-05T15:30:32.096306+00:00"} +{"event": "dispatch_requested", "run": "A2", "batch": 2, "timestamp": "2026-09-05T15:36:26.825993+00:00"} +{"event": "dispatch_returned", "run": "A2", "batch": 2, "timestamp": "2026-09-05T15:36:44.149819+00:00"} +{"event": "dispatch_requested", "run": "B2", "batch": 2, "timestamp": "2026-09-05T15:36:44.150022+00:00"} +{"event": "dispatch_returned", "run": "B2", "batch": 2, "timestamp": "2026-09-05T15:37:02.573843+00:00"} +{"event": "dispatch_requested", "run": "C2", "batch": 2, "timestamp": "2026-09-05T15:37:02.574068+00:00"} +{"event": "dispatch_returned", "run": "C2", "batch": 2, "timestamp": "2026-09-05T15:37:29.861569+00:00"} +{"event": "dispatch_requested", "run": "B3", "batch": 3, "timestamp": "2026-09-05T15:42:04.137924+00:00"} +{"event": "dispatch_returned", "run": "B3", "batch": 3, "timestamp": "2026-09-05T15:42:21.872053+00:00"} +{"event": "dispatch_requested", "run": "C3", "batch": 3, "timestamp": "2026-09-05T15:42:21.872287+00:00"} +{"event": "dispatch_returned", "run": "C3", "batch": 3, "timestamp": "2026-09-05T15:42:38.033053+00:00"} +{"event": "dispatch_requested", "run": "B4", "batch": 3, "timestamp": "2026-09-05T15:42:38.033291+00:00"} +{"event": "dispatch_returned", "run": "B4", "batch": 3, "timestamp": "2026-09-05T15:42:58.032359+00:00"} +{"event": "dispatch_requested", "run": "C4", "batch": 4, "timestamp": "2026-09-05T15:47:28.105174+00:00"} +{"event": "dispatch_returned", "run": "C4", "batch": 4, "timestamp": "2026-09-05T15:47:51.217062+00:00"} +{"event": "completed", "run": "A1", "batch": 1, "timestamp": "2026-09-05T15:32:36.148Z", "source": "harness task_complete event"} +{"event": "completed", "run": "B1", "batch": 1, "timestamp": "2026-09-05T15:33:36.886Z", "source": "harness task_complete event"} +{"event": "completed", "run": "C1", "batch": 1, "timestamp": "2026-09-05T15:36:16.427Z", "source": "harness task_complete event"} +{"event": "completed", "run": "A2", "batch": 2, "timestamp": "2026-09-05T15:39:27.604Z", "source": "harness task_complete event"} +{"event": "completed", "run": "B2", "batch": 2, "timestamp": "2026-09-05T15:40:56.691Z", "source": "harness task_complete event"} +{"event": "completed", "run": "C2", "batch": 2, "timestamp": "2026-09-05T15:41:56.116Z", "source": "harness task_complete event"} +{"event": "completed", "run": "B3", "batch": 3, "timestamp": "2026-09-05T15:46:21.261Z", "source": "harness task_complete event"} +{"event": "completed", "run": "C3", "batch": 3, "timestamp": "2026-09-05T15:47:18.294Z", "source": "harness task_complete event"} +{"event": "completed", "run": "B4", "batch": 3, "timestamp": "2026-09-05T15:46:05.408Z", "source": "harness task_complete event"} +{"event": "completed", "run": "C4", "batch": 4, "timestamp": "2026-09-05T15:52:53.110Z", "source": "harness task_complete event"} +{"event": "watcher_stopped", "timestamp": "2026-09-05T15:53:06.693170+00:00", "pid": 75990} diff --git a/experiments/render-loop-cadence/astra/harness/extract-commands.cjs b/experiments/render-loop-cadence/astra/harness/extract-commands.cjs new file mode 100644 index 00000000..ad63f5ca --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/extract-commands.cjs @@ -0,0 +1,48 @@ +// Preserve command strings for auditing reported counts and protocol compliance. +// This does not execute agent JavaScript, infer loop execution, or count prose. +const fs = require('node:fs'); +const path = require('node:path'); +const out = path.resolve(__dirname, '..'); +const repo = path.resolve(out, '../../..'); +const ts = require(path.join(repo, 'node_modules/typescript')); +const schedule = JSON.parse(fs.readFileSync(path.join(__dirname, 'schedule.json'), 'utf8')); +const rows = []; +for (const [run] of schedule) { + const file = path.join(out, 'evidence', `${run}-usage.json`); + if (!fs.existsSync(file)) continue; + const data = JSON.parse(fs.readFileSync(file, 'utf8')); + const commands = []; + for (const call of data.tool_calls) { + if (call.name === 'exec_command' || call.name.endsWith('__exec_command')) { + const args = JSON.parse(call.arguments); + commands.push({timestamp: call.timestamp, call_id: call.call_id, command: args.cmd, literal: true}); + continue; + } + if (call.name !== 'exec') continue; + const ast = ts.createSourceFile('call.js', call.input || call.arguments || '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS); + function visit(node) { + if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === 'exec_command') { + const args = node.arguments[0]; + if (args && ts.isObjectLiteralExpression(args)) { + const prop = args.properties.find(p => ts.isPropertyAssignment(p) && (p.name.text || p.name.getText(ast)) === 'cmd'); + if (prop) { + const value = prop.initializer; + const literal = ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value); + commands.push({timestamp: call.timestamp, call_id: call.call_id, command: literal ? value.text : value.getText(ast), literal}); + } + } + } + ts.forEachChild(node, visit); + } + visit(ast); + } + fs.writeFileSync(path.join(out, 'evidence', `${run}-commands.json`), JSON.stringify(commands, null, 2) + '\n'); + const row = {run, extracted_exec_command_calls: commands.length, nonliteral_commands: commands.filter(c => !c.literal).length}; + for (const action of ['check', 'capture', 'dev']) { + const regex = new RegExp('(?:^|\\n)\\s*npx\\s+--no-install\\s+weaver\\s+' + action + '\\b', 'g'); + row[`${action}_literal_command_lines`] = commands.filter(c => c.literal).reduce((n, c) => n + [...c.command.matchAll(regex)].length, 0); + } + rows.push(row); +} +fs.writeFileSync(path.join(out, 'evidence', 'command-audit.json'), JSON.stringify(rows, null, 2) + '\n'); +console.log(JSON.stringify(rows)); diff --git a/experiments/render-loop-cadence/astra/harness/final-recapture.py b/experiments/render-loop-cadence/astra/harness/final-recapture.py new file mode 100644 index 00000000..5cb2a61e --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/final-recapture.py @@ -0,0 +1,122 @@ +"""Uniform grader inputs and objective gates; no subjective scoring or widget edits.""" +from pathlib import Path +from datetime import datetime, timezone +import csv +import hashlib +import json +import shutil +import subprocess + +OUT = Path(__file__).resolve().parents[1] +REPO = OUT.parents[2] +TMP = Path("/tmp/weaver-exp-astra") +RUNS = ["A1", "A2", "B1", "B2", "B3", "B4", "C1", "C2", "C3", "C4"] +CLOCK = "2026-09-04T09:41:00.000Z" + + +def now(): + return datetime.now(timezone.utc).isoformat() + + +def execute(args, basename): + start = now() + result = subprocess.run(args, cwd=REPO, capture_output=True) + basename.with_suffix(".stdout").write_bytes(result.stdout) + basename.with_suffix(".stderr").write_bytes(result.stderr) + basename.with_suffix(".command.json").write_text(json.dumps({ + "argv": args, "cwd": str(REPO), "started_at": start, + "completed_at": now(), "exit_code": result.returncode, + }, indent=2) + "\n") + return result + + +def receipt(basename, result): + published = basename.with_suffix(".receipt.json") + if published.exists(): + return json.loads(published.read_text()) + try: + return json.loads(result.stdout) + except json.JSONDecodeError: + return {"status": "missing", "error": {"code": "NoParseableReceipt"}} + + +usage = list(csv.DictReader((OUT / "usage.tsv").open(), delimiter="\t")) +if len(usage) != 10 or any(row["status"] != "complete" for row in usage): + raise RuntimeError("Uniform recapture must wait until all ten agents finish") +if (OUT / "final").exists() or (OUT / "runs").exists(): + raise RuntimeError("Refusing to overwrite archived runs or final evidence") +(OUT / "final").mkdir() +(OUT / "runs").mkdir() +shutil.copy2(TMP / "saves.log", OUT / "saves.log") +saves = (OUT / "saves.log").read_text().splitlines() +rows = [] +for run in RUNS: + source = TMP / "runs" / run + archived = OUT / "runs" / run + shutil.copytree(source, archived) + (archived / "captures").mkdir(exist_ok=True) + final = OUT / "final" / run + final.mkdir() + original_sha = hashlib.sha256((source / "widget.tsx").read_bytes()).hexdigest() + check = execute(["npx", "--no-install", "weaver", "check", str(source)], final / "check") + receipts = {} + exits = {} + snapshots = {} + for state in ("initial", "after-clicks"): + base = final / state + args = ["npx", "--no-install", "weaver", "capture", str(source), "--clock", CLOCK] + if state == "after-clicks": + args += ["--action-file", str(TMP / "clicks.actions")] + args += ["--out", str(base.with_suffix(".png"))] + result = execute(args, base) + receipts[state] = receipt(base, result) + exits[state] = result.returncode + snapshot = base.with_suffix(".snapshot.txt") + snapshots[state] = snapshot.read_text() if snapshot.exists() else "" + save_lines = [line.split("\t") for line in saves if line.split("\t")[1] == run] + initial_buttons = all(f'role=button name="{name}"' in snapshots["initial"] for name in ("Log session", "Reset week")) + after_buttons = all(f'role=button name="{name}"' in snapshots["after-clicks"] for name in ("Log session", "Reset week")) + row = { + "run": run, "condition": run[0], "check_pass": check.returncode == 0, + "check_exit": check.returncode, + "initial_status": receipts["initial"].get("status", "missing"), + "initial_exit": exits["initial"], + "initial_error": (receipts["initial"].get("error") or {}).get("code") or (receipts["initial"].get("error") or {}).get("name", ""), + "after_clicks_status": receipts["after-clicks"].get("status", "missing"), + "after_clicks_exit": exits["after-clicks"], + "after_clicks_error": (receipts["after-clicks"].get("error") or {}).get("code") or (receipts["after-clicks"].get("error") or {}).get("name", ""), + "initial_both_named_buttons": initial_buttons, + "after_clicks_both_named_buttons": after_buttons, + "after_clicks_3_of_20": "3 / 20" in snapshots["after-clicks"], + "agent_published_pngs": len(list((archived / "captures").glob("*.png"))), + "observed_saves": len(save_lines), + "first_observed_save_utc": save_lines[0][0] if save_lines else "NA", + "last_observed_save_utc": save_lines[-1][0] if save_lines else "NA", + "widget_sha256": original_sha, + "source_unchanged_by_recheck": original_sha == hashlib.sha256((source / "widget.tsx").read_bytes()).hexdigest(), + } + row["all_objective_gates"] = ( + row["check_pass"] and row["initial_status"] == "ok" + and row["after_clicks_status"] == "ok" and initial_buttons and after_buttons + and row["after_clicks_3_of_20"] + ) + rows.append(row) + with (OUT / "GATES.tsv").open("w") as f: + writer = csv.DictWriter(f, fieldnames=list(row), delimiter="\t", lineterminator="\n") + writer.writeheader() + writer.writerows(rows) + print(json.dumps({k: row[k] for k in ("run", "all_objective_gates", "initial_status", "after_clicks_status", "after_clicks_error")}), flush=True) + +flat = OUT / "final-captures" +flat.mkdir() +for run in RUNS: + for state, alias in (("initial", "initial"), ("after-clicks", "after")): + for suffix in (".png", ".snapshot.txt", ".receipt.json"): + source = OUT / "final" / run / (state + suffix) + if source.exists(): + shutil.copy2(source, flat / (run + "-" + alias + suffix)) + +manifest = {str(path.relative_to(OUT)): hashlib.sha256(path.read_bytes()).hexdigest() + for folder in (OUT / "runs", OUT / "final", flat) + for path in sorted(folder.rglob("*")) if path.is_file()} +(OUT / "evidence/artifact-sha256.json").write_text(json.dumps(manifest, indent=2) + "\n") diff --git a/experiments/render-loop-cadence/astra/harness/schedule.json b/experiments/render-loop-cadence/astra/harness/schedule.json new file mode 100644 index 00000000..67d98722 --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/schedule.json @@ -0,0 +1,42 @@ +[ + [ + "A1", + 1 + ], + [ + "B1", + 1 + ], + [ + "C1", + 1 + ], + [ + "A2", + 2 + ], + [ + "B2", + 2 + ], + [ + "C2", + 2 + ], + [ + "B3", + 3 + ], + [ + "C3", + 3 + ], + [ + "B4", + 3 + ], + [ + "C4", + 4 + ] +] diff --git a/experiments/render-loop-cadence/astra/harness/watch-saves.mjs b/experiments/render-loop-cadence/astra/harness/watch-saves.mjs new file mode 100644 index 00000000..452983e8 --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/watch-saves.mjs @@ -0,0 +1,15 @@ +import { statSync, appendFileSync, readdirSync, existsSync } from "node:fs"; +const root = "/tmp/weaver-exp-astra/runs"; +const seen = new Map(); +setInterval(() => { + if (!existsSync(root)) return; + for (const run of readdirSync(root)) { + const f = `${root}/${run}/widget.tsx`; + let st; try { st = statSync(f); } catch { continue; } + const key = `${st.mtimeMs}:${st.size}`; + if (seen.get(run) !== key) { + seen.set(run, key); + appendFileSync("/tmp/weaver-exp-astra/saves.log", `${new Date().toISOString()}\t${run}\t${st.size}\n`); + } + } +}, 500); diff --git a/experiments/render-loop-cadence/astra/harness/watcher-process.json b/experiments/render-loop-cadence/astra/harness/watcher-process.json new file mode 100644 index 00000000..34e0a88e --- /dev/null +++ b/experiments/render-loop-cadence/astra/harness/watcher-process.json @@ -0,0 +1,5 @@ +{ + "pid": 75990, + "command": "node /tmp/weaver-exp-astra/watch-saves.mjs", + "session_id": 20610 +} diff --git a/experiments/render-loop-cadence/astra/prompts/A1.md b/experiments/render-loop-cadence/astra/prompts/A1.md new file mode 100644 index 00000000..2f5beedd --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/A1.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/A1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/A1`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/A1` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/A1/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/A1/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/A1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/A1/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/A1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/A1/clicks.actions --out /tmp/weaver-exp-astra/runs/A1/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/A1/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: A (check-only) +You may run `weaver check` as often as you like. You must NEVER run `weaver capture`, and you never see pixels or a snapshot. Build from the contract, the examples and your own reasoning. Stop when you believe the widget matches the spec. Leave /tmp/weaver-exp-astra/runs/A1/captures absent. diff --git a/experiments/render-loop-cadence/astra/prompts/A2.md b/experiments/render-loop-cadence/astra/prompts/A2.md new file mode 100644 index 00000000..9016bf27 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/A2.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/A2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/A2`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/A2` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/A2/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/A2/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/A2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/A2/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/A2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/A2/clicks.actions --out /tmp/weaver-exp-astra/runs/A2/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/A2/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: A (check-only) +You may run `weaver check` as often as you like. You must NEVER run `weaver capture`, and you never see pixels or a snapshot. Build from the contract, the examples and your own reasoning. Stop when you believe the widget matches the spec. Leave /tmp/weaver-exp-astra/runs/A2/captures absent. diff --git a/experiments/render-loop-cadence/astra/prompts/B1.md b/experiments/render-loop-cadence/astra/prompts/B1.md new file mode 100644 index 00000000..15f9834c --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/B1.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/B1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B1`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B1` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B1/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/B1/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B1/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B1/clicks.actions --out /tmp/weaver-exp-astra/runs/B1/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/B1/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: B (final capture) +Write the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds. diff --git a/experiments/render-loop-cadence/astra/prompts/B2.md b/experiments/render-loop-cadence/astra/prompts/B2.md new file mode 100644 index 00000000..26c63d8d --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/B2.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/B2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B2`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B2` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B2/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/B2/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B2/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B2/clicks.actions --out /tmp/weaver-exp-astra/runs/B2/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/B2/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: B (final capture) +Write the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds. diff --git a/experiments/render-loop-cadence/astra/prompts/B3.md b/experiments/render-loop-cadence/astra/prompts/B3.md new file mode 100644 index 00000000..070e1196 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/B3.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/B3 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B3`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B3` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B3/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/B3/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B3/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B3/clicks.actions --out /tmp/weaver-exp-astra/runs/B3/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/B3/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: B (final capture) +Write the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds. diff --git a/experiments/render-loop-cadence/astra/prompts/B4.md b/experiments/render-loop-cadence/astra/prompts/B4.md new file mode 100644 index 00000000..c62491f6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/B4.md @@ -0,0 +1,43 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/B4 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/B4`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/B4` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/B4/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/B4/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/B4/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/B4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/B4/clicks.actions --out /tmp/weaver-exp-astra/runs/B4/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/B4/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: B (final capture) +Write the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds. diff --git a/experiments/render-loop-cadence/astra/prompts/C1.md b/experiments/render-loop-cadence/astra/prompts/C1.md new file mode 100644 index 00000000..4b143c26 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/C1.md @@ -0,0 +1,48 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/C1 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C1`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C1` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C1/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/C1/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C1/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C1 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C1/clicks.actions --out /tmp/weaver-exp-astra/runs/C1/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/C1/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: C (progressive capture) +Build in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next: +1. Frame and header row only (capture initial state). +2. Add the seven day cells (capture initial state). +3. Add the progress bar (capture initial state). +4. Add the buttons and storage (capture initial state AND after-clicks state). +Fix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied. diff --git a/experiments/render-loop-cadence/astra/prompts/C2.md b/experiments/render-loop-cadence/astra/prompts/C2.md new file mode 100644 index 00000000..2f9f2ef8 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/C2.md @@ -0,0 +1,48 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/C2 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C2`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C2` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C2/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/C2/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C2/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C2 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C2/clicks.actions --out /tmp/weaver-exp-astra/runs/C2/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/C2/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: C (progressive capture) +Build in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next: +1. Frame and header row only (capture initial state). +2. Add the seven day cells (capture initial state). +3. Add the progress bar (capture initial state). +4. Add the buttons and storage (capture initial state AND after-clicks state). +Fix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied. diff --git a/experiments/render-loop-cadence/astra/prompts/C3.md b/experiments/render-loop-cadence/astra/prompts/C3.md new file mode 100644 index 00000000..dcc611e3 --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/C3.md @@ -0,0 +1,48 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/C3 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C3`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C3` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C3/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/C3/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C3/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C3 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C3/clicks.actions --out /tmp/weaver-exp-astra/runs/C3/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/C3/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: C (progressive capture) +Build in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next: +1. Frame and header row only (capture initial state). +2. Add the seven day cells (capture initial state). +3. Add the progress bar (capture initial state). +4. Add the buttons and storage (capture initial state AND after-clicks state). +Fix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied. diff --git a/experiments/render-loop-cadence/astra/prompts/C4.md b/experiments/render-loop-cadence/astra/prompts/C4.md new file mode 100644 index 00000000..48392abf --- /dev/null +++ b/experiments/render-loop-cadence/astra/prompts/C4.md @@ -0,0 +1,48 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory +/tmp/weaver-exp-astra/runs/C4 (create it with `npx --no-install weaver init /tmp/weaver-exp-astra/runs/C4`; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp-astra other than your own and the file /tmp/weaver-exp-astra/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check /tmp/weaver-exp-astra/runs/C4` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp-astra/clicks.actions to /tmp/weaver-exp-astra/runs/C4/clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /tmp/weaver-exp-astra/runs/C4/captures +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --out /tmp/weaver-exp-astra/runs/C4/captures/NN-initial.png +npx --no-install weaver capture /tmp/weaver-exp-astra/runs/C4 --clock 2026-09-04T09:41:00.000Z --action-file /tmp/weaver-exp-astra/runs/C4/clicks.actions --out /tmp/weaver-exp-astra/runs/C4/captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /tmp/weaver-exp-astra/runs/C4/REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. + +## Your condition: C (progressive capture) +Build in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next: +1. Frame and header row only (capture initial state). +2. Add the seven day cells (capture initial state). +3. Add the progress bar (capture initial state). +4. Add the buttons and storage (capture initial state AND after-clicks state). +Fix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied. diff --git a/experiments/render-loop-cadence/astra/runs/A1/REPORT.md b/experiments/render-loop-cadence/astra/runs/A1/REPORT.md new file mode 100644 index 00000000..8ac4beff --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A1/REPORT.md @@ -0,0 +1,9 @@ +# Focus Week report + +- Condition: A (check-only). +- `weaver check` runs: 2. Final check passed. +- `weaver capture` runs: 0. No captures directory created. +- Defects fixed because of pixels or a snapshot: none. +- Check-driven fixes: removed unsupported JSX `key`; gave the canvas an explicit 286 px width, calculated from the 320 px widget minus 32 px horizontal padding and 2 px border. +- Spec items not met: none known. Visual layout, click results, native state feedback, and restart persistence were not observed because this condition permits only static checks. The implementation uses weekday-keyed persistent counts, native hover and pressed styles, and the time provider only. +- Confidence: 8 / 10. The final source passes the authoritative static check, but visual and interaction behavior remain unverified. diff --git a/experiments/render-loop-cadence/astra/runs/A1/tsconfig.json b/experiments/render-loop-cadence/astra/runs/A1/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A1/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/A1/widget.tsx b/experiments/render-loop-cadence/astra/runs/A1/widget.tsx new file mode 100644 index 00000000..25ba5cdc --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A1/widget.tsx @@ -0,0 +1,74 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +type Weekday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"; +type Counts = Record; +const days: Weekday[] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const emptyWeek: Counts = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; +const goal = 20; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage("sessions-by-weekday", emptyWeek); + const today = time.weekday as Weekday; + const total = days.reduce((sum, day) => sum + counts[day], 0); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => ( + + {day[0]} + {counts[day]} + + ))} + + + + + WEEKLY SESSIONS + {total} / {goal} + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff14"); + if (total > 0) { + ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / goal, 1), ctx.height, 3, "#5eead4"); + } + }} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/A2/REPORT.md b/experiments/render-loop-cadence/astra/runs/A2/REPORT.md new file mode 100644 index 00000000..67c78eb2 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A2/REPORT.md @@ -0,0 +1,10 @@ +# Focus Week report + +- Condition: A (check-only). +- `weaver check` runs: 2; final run passed. +- `weaver capture` runs: 0. The captures directory was not created. +- Defects fixed because of pixels or a snapshot: none. +- Spec items not met: none known from contract review and static checking. Visual layout, interaction execution, and restart persistence were not empirically verified because this condition prohibits captures and development sessions. +- Confidence: 8 / 10. + +The check identified an unsupported JSX key prop and a computed class string; both were corrected. The progress bar uses a canvas drawing on render, without an animation timer. Storage contains weekday-keyed counts. Layout reserves separate space for the progress label, uses seven equal flex widths, and budgets the four rows plus gaps within the 168px inner height. diff --git a/experiments/render-loop-cadence/astra/runs/A2/tsconfig.json b/experiments/render-loop-cadence/astra/runs/A2/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A2/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/A2/widget.tsx b/experiments/render-loop-cadence/astra/runs/A2/widget.tsx new file mode 100644 index 00000000..2c636bd7 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/A2/widget.tsx @@ -0,0 +1,83 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; +const emptyWeek: Record = { + Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0, +}; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + counts[day.key], 0); + const fraction = Math.min(1, total / 20); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => ( + + {day.letter} + {counts[day.key]} + + ))} + + + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff1f"); + if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, "#5eead4"); + }} + /> + {total} / 20 + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/B1/REPORT.md b/experiments/render-loop-cadence/astra/runs/B1/REPORT.md new file mode 100644 index 00000000..788d8ff3 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B1/REPORT.md @@ -0,0 +1,18 @@ +# Focus Week report + +- Condition: B (final capture). +- `weaver check` runs: 3. First failed on unsupported JSX `key` and a dynamic class; both subsequent runs passed, including the final source. +- `weaver capture` runs: 5. Every receipt has `status: "ok"`. +- Defects fixed because of pixels or snapshots: the progress bar was invisible in captures 01 and 02 even though its semantic canvas bounds were 224×6. Replacing `w-0 grow` on the canvas with explicit `w-[224px]` made both track and fill visible in captures 03 and 04. The width comes from the measured 288px content row minus its 12px gap and 52px label. +- Spec items not met: none known. Persistence uses `useStorage` with a weekday-keyed record; restart persistence was not independently exercised because captures use isolated empty storage. +- Confidence: 9/10. + +Final visual and semantic evidence: + +- `captures/03-initial.png`: Friday highlighted, all seven counts zero, `0 / 20`, visible empty track. +- `captures/04-after-clicks.png`: Friday 3, other days zero, `3 / 20`, fill at 15% of the 224px track. +- `captures/05-after-reset.png`: three logs followed by Reset week returns every count to zero and empties the track. + +All five PNGs were opened and inspected at their 320×200, scale-1 dimensions; all snapshots and receipts were read. The final captures show aligned header text, equal day cells, legible text, distinct controls, and no clipping or overlap. Both button names match exactly. Native hover feedback is visible after clicks; both controls also declare native pressed styles. + +The single pending timer is the subscribed time provider. No fetches, external providers, unresolved images, or frame requests remain. Receipts warn that the repository already contains uncommitted changes; no repository files were edited. No live development window was started, as requested. diff --git a/experiments/render-loop-cadence/astra/runs/B1/clicks.actions b/experiments/render-loop-cadence/astra/runs/B1/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B1/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B1/reset.actions b/experiments/render-loop-cadence/astra/runs/B1/reset.actions new file mode 100644 index 00000000..6713b5fa --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B1/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B1/tsconfig.json b/experiments/render-loop-cadence/astra/runs/B1/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B1/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B1/widget.tsx b/experiments/render-loop-cadence/astra/runs/B1/widget.tsx new file mode 100644 index 00000000..55b62652 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B1/widget.tsx @@ -0,0 +1,66 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +type Weekday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"; +const days: Weekday[] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const emptyWeek: Record = { + Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0, +}; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const today = time.weekday as Weekday; + const total = days.reduce((sum, day) => sum + counts[day], 0); + const progress = Math.min(total / 20, 1); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => ( + + {day[0]} + {counts[day]} + + ))} + + + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff1a"); + if (progress > 0) ctx.fillRoundRect(0, 0, ctx.width * progress, ctx.height, 3, "#5eead4"); + }} /> + {total} / 20 + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/B2/REPORT.md b/experiments/render-loop-cadence/astra/runs/B2/REPORT.md new file mode 100644 index 00000000..87c6a7af --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B2/REPORT.md @@ -0,0 +1,17 @@ +# Focus Week report + +- Condition: B (final capture). +- Explicit `weaver check` runs: 4. The final check passed. +- `weaver capture` runs: 5. Every receipt has status `ok`. +- Defects fixed because pixels or a snapshot exposed them: + - The progress canvas was 286 px wide inside a 288 px track. The first snapshots exposed the mismatch; corrected the canvas to 288 px, so three sessions fill exactly 15% of the track. +- Spec items not met: none known. +- Confidence: 9 / 10. + +The complete widget was written before the first capture. Static diagnostics first corrected an unsupported JSX `key`, a computed utility string, and a percentage-sized canvas; those fixes were not discovered through pixels or snapshots. + +Opened and inspected all five PNGs at their real 320×200 dimensions. Final evidence is `captures/03-initial.png`, `captures/04-after-clicks.png`, and `captures/05-after-reset.png`, with their matching snapshots and receipts. Friday is highlighted, all seven initial counts are visible zeros, three Log session clicks produce Friday 3 and `3 / 20`, and Reset week restores every count to zero. Text and controls are legible without overlap or clipping, and the progress label stays above the bar. The snapshots confirm seven equal-width cells and both exact accessible button names. + +Both buttons declare native hover and pressed styles. Hover feedback is visible in the corresponding interaction captures. Storage uses the documented persistent `useStorage` hook with a weekday-keyed object; cross-process persistence was not separately exercised because capture creates isolated empty storage each run. + +The single pending timer is the subscribed time provider. There are no pending fetches, images, external providers, or frame requests. Receipts warn that the shared Weaver checkout already contains uncommitted changes; this task modified no repository files. No live view was started, as instructed. diff --git a/experiments/render-loop-cadence/astra/runs/B2/clicks.actions b/experiments/render-loop-cadence/astra/runs/B2/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B2/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B2/reset.actions b/experiments/render-loop-cadence/astra/runs/B2/reset.actions new file mode 100644 index 00000000..07cd3440 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B2/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} \ No newline at end of file diff --git a/experiments/render-loop-cadence/astra/runs/B2/tsconfig.json b/experiments/render-loop-cadence/astra/runs/B2/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B2/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B2/widget.tsx b/experiments/render-loop-cadence/astra/runs/B2/widget.tsx new file mode 100644 index 00000000..6dc44164 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B2/widget.tsx @@ -0,0 +1,80 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; +const emptyWeek: Record = { + Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0, +}; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [sessions, setSessions] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + sessions[day.key], 0); + const fraction = Math.min(1, total / 20); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => ( + + {day.letter} + {sessions[day.key]} + + ))} + + + + + WEEKLY SESSIONS + {total} / 20 + + + { + ctx.clear(); + if (fraction > 0) ctx.fillRoundRect(0, 0, ctx.width * fraction, ctx.height, 3, "#5eead4"); + }} /> + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/B3/REPORT.md b/experiments/render-loop-cadence/astra/runs/B3/REPORT.md new file mode 100644 index 00000000..64aac413 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B3/REPORT.md @@ -0,0 +1,13 @@ +# Focus Week + +- Condition: B (final capture). +- `weaver check` runs: 3. First failed because `column` does not accept a `key` prop; the following two passed. +- `weaver capture` runs: 5. All receipts have status `ok`; every PNG was opened at its native 320×200 dimensions and every snapshot was read. +- Defects fixed because pixels or snapshots exposed them: + - The progress canvas had `w-[0px] grow`: its semantic bounds grew, but its drawing remained invisible. Changed it to an explicit 232 px drawing width, following the examples' explicit canvas dimensions, and reserved a separate 44 px label region with a 12 px gap. Captures 03 and 04 show the empty track and 15% fill respectively. +- Spec items not met: none identified. Persistence uses `useStorage` with a weekday-keyed object; capture isolates storage, so restart persistence was not separately exercised. No live dev session was run, as instructed. +- Confidence: 9/10. + +Final evidence: `captures/03-initial.png` shows Friday highlighted and seven zeros; `captures/04-after-clicks.png` shows Friday 3, six zeros, `3 / 20`, and 15% fill. `captures/05-after-reset.png` verifies three logs followed by Reset week returns all seven days and the total to zero. The semantic trees expose exactly `Log session` and `Reset week` as button names. Both buttons use native hover and pressed styles. No clipping or overlap was observed at 1× scale. + +The receipts' sole warning reports pre-existing uncommitted repository changes; this task modified no repository files. The one pending timer is the subscribed time provider; there are no fetches, unresolved images, external providers, or queued frames. diff --git a/experiments/render-loop-cadence/astra/runs/B3/clicks.actions b/experiments/render-loop-cadence/astra/runs/B3/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B3/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B3/reset.actions b/experiments/render-loop-cadence/astra/runs/B3/reset.actions new file mode 100644 index 00000000..6713b5fa --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B3/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B3/tsconfig.json b/experiments/render-loop-cadence/astra/runs/B3/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B3/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B3/widget.tsx b/experiments/render-loop-cadence/astra/runs/B3/widget.tsx new file mode 100644 index 00000000..34a22876 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B3/widget.tsx @@ -0,0 +1,85 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +const days = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; +const emptyWeek: Record = { + Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0, +}; + +function drawProgress(ctx: CanvasCtx, total: number): void { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff20"); + if (total > 0) { + ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, "#5eead4"); + } +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + counts[day.key], 0); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => ( + + {day.letter} + {counts[day.key]} + + ))} + + + + drawProgress(ctx, total)} /> + {total} / 20 + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/B4/REPORT.md b/experiments/render-loop-cadence/astra/runs/B4/REPORT.md new file mode 100644 index 00000000..4bf6478b --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B4/REPORT.md @@ -0,0 +1,18 @@ +# Focus Week — B4 + +- Condition: B (final capture). The complete widget was authored before the first capture. +- `weaver check` runs: 3 (first failed on an unbounded dynamic class; two subsequent runs passed). +- `weaver capture` runs: 3, all with status `ok`. +- Defects fixed because of pixels or snapshots: none. +- Spec items not met: none identified. Persistence uses `useStorage` with a record keyed by weekday; restarting a live widget was not exercised because live execution was prohibited. Reset is manual, as specified. +- Confidence: 9/10. + +Opened and inspected every PNG at its native 320×200 dimensions and read every snapshot and receipt: + +- `captures/01-initial.png`: Friday highlighted, seven zero counts, `0 / 20`, empty bar, equal day cells and aligned header. Text, spacing, contrast, and button bounds are clean. +- `captures/02-after-clicks.png`: Friday 3, every other day 0, `3 / 20`; semantic fill width 31.800001 against track width 212 confirms 15%. Primary native hover color is visible. +- `captures/03-after-reset.png`: three logs followed by Reset week returns every count and the total to zero and empties the bar. Secondary native hover color is visible. + +Accessible button names are exactly `Log session` and `Reset week`. Both declare native hover and pressed styles. The widget subscribes only to time and makes no network calls. All receipts report no pending fetches, images, providers, or frame requests; the time subscription accounts for the pending timer. Their sole warning records pre-existing uncommitted checkout changes; no repository files were modified. `weaver dev` was not run. + +The static-check fix replaced an arbitrary interpolated progress class with an explicit set of validated width classes for the 20-session goal. It happened before the first capture and was not a pixel-driven repair. diff --git a/experiments/render-loop-cadence/astra/runs/B4/clicks.actions b/experiments/render-loop-cadence/astra/runs/B4/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B4/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B4/reset.actions b/experiments/render-loop-cadence/astra/runs/B4/reset.actions new file mode 100644 index 00000000..07cd3440 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B4/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} \ No newline at end of file diff --git a/experiments/render-loop-cadence/astra/runs/B4/tsconfig.json b/experiments/render-loop-cadence/astra/runs/B4/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B4/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/B4/widget.tsx b/experiments/render-loop-cadence/astra/runs/B4/widget.tsx new file mode 100644 index 00000000..6c64a22e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/B4/widget.tsx @@ -0,0 +1,78 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const letters = ["M", "T", "W", "T", "F", "S", "S"]; +const emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [sessions, setSessions] = useStorage>("sessions", emptyWeek); + const total = days.reduce((sum, day) => sum + sessions[day], 0); + const progress = Math.min(total, 20); + const progressClass = + progress === 1 ? "w-1/20 h-full bg-[#5eead4] rounded-full" : + progress === 2 ? "w-2/20 h-full bg-[#5eead4] rounded-full" : + progress === 3 ? "w-3/20 h-full bg-[#5eead4] rounded-full" : + progress === 4 ? "w-4/20 h-full bg-[#5eead4] rounded-full" : + progress === 5 ? "w-5/20 h-full bg-[#5eead4] rounded-full" : + progress === 6 ? "w-6/20 h-full bg-[#5eead4] rounded-full" : + progress === 7 ? "w-7/20 h-full bg-[#5eead4] rounded-full" : + progress === 8 ? "w-8/20 h-full bg-[#5eead4] rounded-full" : + progress === 9 ? "w-9/20 h-full bg-[#5eead4] rounded-full" : + progress === 10 ? "w-10/20 h-full bg-[#5eead4] rounded-full" : + progress === 11 ? "w-11/20 h-full bg-[#5eead4] rounded-full" : + progress === 12 ? "w-12/20 h-full bg-[#5eead4] rounded-full" : + progress === 13 ? "w-13/20 h-full bg-[#5eead4] rounded-full" : + progress === 14 ? "w-14/20 h-full bg-[#5eead4] rounded-full" : + progress === 15 ? "w-15/20 h-full bg-[#5eead4] rounded-full" : + progress === 16 ? "w-16/20 h-full bg-[#5eead4] rounded-full" : + progress === 17 ? "w-17/20 h-full bg-[#5eead4] rounded-full" : + progress === 18 ? "w-18/20 h-full bg-[#5eead4] rounded-full" : + progress === 19 ? "w-19/20 h-full bg-[#5eead4] rounded-full" : + "w-full h-full bg-[#5eead4] rounded-full"; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day, index) => ( + + {letters[index]} + {sessions[day]} + + ))} + + + + + {progress > 0 ? : null} + + {total} / 20 + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/C1/REPORT.md b/experiments/render-loop-cadence/astra/runs/C1/REPORT.md new file mode 100644 index 00000000..f0c65dd9 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C1/REPORT.md @@ -0,0 +1,24 @@ +# Focus Week report + +- Condition: C (progressive capture). +- `weaver check` runs: 8 (6 passed, 2 failed while authoring). Final source passed. +- `weaver capture` runs: 8 (7 succeeded, 1 failed at static validation). Capture 02 produced no artifacts because an unsupported `key` prop remained; numbering was preserved. +- Confidence: 9 / 10. + +## Defects fixed because of pixels or snapshots + +- Capture 04 showed no progress track despite a 224×6 semantic canvas bound. The canvas had `w-0 grow`, so its drawing width was zero. Changed it to explicit `w-[224px]`, consistent with the shipped canvas examples. Capture 05 visibly confirmed the track; capture 07 confirmed the filled portion at 15%. + +## Verification + +Built and inspected each slice before starting the next: frame/header (01), day cells (03), progress (04 then 05), buttons/storage (06 initial, 07 after three clicks). Also captured reset after three clicks (08). + +Opened every successful PNG at its actual 320×200 size, read its semantic snapshot and receipt, and confirmed `status: "ok"`. Captures show equal-width Monday–Sunday cells, Friday highlighted, visible zero counts, separated bar and total, readable button labels, and no clipping or overlap. Capture 07 shows Friday 3, six zeros, `3 / 20`, and a 15% fill. Capture 08 shows seven zeros and `0 / 20`. Exact accessible names are `Log session` and `Reset week`. + +Storage uses `useStorage` with a record keyed by weekday. Persistence across restarts follows that SDK contract; captures intentionally use isolated empty storage and do not independently prove a live restart. Native hover and pressed classes are defined on both buttons; the post-action snapshots and pixels show each button's hover state. + +The one pending timer is the subscribed time provider. There are no fetches, other providers, unresolved images, or queued frame requests. The only successful-receipt warning is that the existing Weaver checkout has uncommitted changes. No repository file was edited and `weaver dev` was not run, as instructed. + +## Unmet spec items + +None identified. The week is reset through the specified Reset week button; no automatic rollover was requested. diff --git a/experiments/render-loop-cadence/astra/runs/C1/clicks.actions b/experiments/render-loop-cadence/astra/runs/C1/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C1/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C1/reset.actions b/experiments/render-loop-cadence/astra/runs/C1/reset.actions new file mode 100644 index 00000000..6713b5fa --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C1/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C1/tsconfig.json b/experiments/render-loop-cadence/astra/runs/C1/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C1/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C1/widget.tsx b/experiments/render-loop-cadence/astra/runs/C1/widget.tsx new file mode 100644 index 00000000..609955c6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C1/widget.tsx @@ -0,0 +1,58 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; +const letters = ["M", "T", "W", "T", "F", "S", "S"]; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + counts[day], 0); + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + {days.map((day, index) => ( + + {letters[index]} + {counts[day]} + + ))} + + + { + ctx.clear(); + ctx.fillRect(0, 0, ctx.width, ctx.height, "#ffffff1a"); + ctx.fillRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, "#5eead4"); + }} /> + {total} / 20 + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/C2/REPORT.md b/experiments/render-loop-cadence/astra/runs/C2/REPORT.md new file mode 100644 index 00000000..70fbeadb --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C2/REPORT.md @@ -0,0 +1,15 @@ +# Focus Week report + +- Condition: C (progressive capture). +- `weaver check` runs: 6 (5 passed, 1 rejected a computed class string). +- `weaver capture` runs: 7 (6 successful; attempt 03 failed static validation and published no PNG). +- Defects fixed because of pixels or a snapshot: none. +- Static diagnostic fix: replaced the computed bar-width class with a documented canvas drawing. No framework files changed. +- Unmet spec items: none identified. Persistence uses `useStorage` with a record keyed Mon through Sun; capture isolation does not exercise an actual desktop restart. +- Confidence: 9/10. + +The four slices were inspected at 320×200: frame/header in 01, seven cells in 02, progress in 04, and complete initial/three-click states in 05 and 06. Each successful PNG was opened and its snapshot and receipt read. The failed 03 attempt was mistakenly invoked immediately after the failed check; the diagnostic was then fixed and check passed before capture 04 and before proceeding to the next slice. + +Capture 06 shows Friday at 3, every other day at 0, the label `3 / 20`, and a 15% bar. Capture 07 additionally proves Reset week restores every count to 0 and empties the bar. Semantic snapshots expose exactly named `Log session` and `Reset week` buttons. Native hover and pressed classes are present on both controls; post-click hover appearance was visible in the captures. + +All successful receipts have status `ok`, no fetches, unresolved images, or queued frame requests. The single pending timer is associated with the subscribed time provider. The checkout provenance warning reports pre-existing uncommitted changes; this task did not modify repository files. `weaver dev` was not run, as instructed. diff --git a/experiments/render-loop-cadence/astra/runs/C2/clicks.actions b/experiments/render-loop-cadence/astra/runs/C2/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C2/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C2/reset.actions b/experiments/render-loop-cadence/astra/runs/C2/reset.actions new file mode 100644 index 00000000..6713b5fa --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C2/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C2/tsconfig.json b/experiments/render-loop-cadence/astra/runs/C2/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C2/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C2/widget.tsx b/experiments/render-loop-cadence/astra/runs/C2/widget.tsx new file mode 100644 index 00000000..d1e517a2 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C2/widget.tsx @@ -0,0 +1,54 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const letters = ["M", "T", "W", "T", "F", "S", "S"]; +const emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + counts[day], 0); + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + {days.map((day, index) => ( + + {letters[index]} + {counts[day]} + + ))} + + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff1a"); + if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, "#5eead4"); + }} /> + {total} / 20 + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/C3/REPORT.md b/experiments/render-loop-cadence/astra/runs/C3/REPORT.md new file mode 100644 index 00000000..c55c67c2 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C3/REPORT.md @@ -0,0 +1,14 @@ +# Focus Week report + +- Condition: C (progressive capture). +- `weaver check` runs: 7 (6 passed, 1 failed; final run passed). +- `weaver capture` runs: 7 (6 successful, 1 failed before rendering). +- Defects fixed because of pixels or a snapshot: none. Each rendered slice was inspected at its actual 320×200 dimensions and had no observed clipping, overlap, or alignment defect. +- Spec items not met: none known. Persistence uses `useStorage` with a record keyed Mon through Sun; restart persistence relies on the documented hook contract and was not separately exercised by the isolated captures. Reset is manual through Reset week. +- Confidence: 9/10. + +The four slices were captured in order: frame/header (01), days (02), progress (04), and buttons/storage (05 initial, 06 after three clicks). Capture 07 additionally verifies Reset week after three clicks. Every published PNG was opened, its semantic snapshot read, and its receipt confirmed `status: "ok"`. Capture 06 shows Friday 3, six zero counts, `3 / 20`, and the 15% bar. Capture 07 returns all counts to zero and clears the bar. Both accessible button names match exactly. The successful receipts report only the expected time-provider timer, no fetches or pending frame requests, and the existing dirty-checkout provenance warning. + +One authoring error was fixed from checker diagnostics: a computed width class was not statically enumerable. The progress bar now uses the documented canvas drawing API. Capture attempt 03 was inadvertently invoked after that failed check and also failed with the same actionable diagnostic; it published no PNG or snapshot. The next check passed before capture 04. Capture counters were not reused. + +No `weaver dev` was run, as instructed. No repository file was edited. diff --git a/experiments/render-loop-cadence/astra/runs/C3/clicks.actions b/experiments/render-loop-cadence/astra/runs/C3/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C3/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C3/reset.actions b/experiments/render-loop-cadence/astra/runs/C3/reset.actions new file mode 100644 index 00000000..6713b5fa --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C3/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C3/tsconfig.json b/experiments/render-loop-cadence/astra/runs/C3/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C3/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C3/widget.tsx b/experiments/render-loop-cadence/astra/runs/C3/widget.tsx new file mode 100644 index 00000000..997525a7 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C3/widget.tsx @@ -0,0 +1,63 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] as const; +const letters = ["M", "T", "W", "T", "F", "S", "S"]; +type Day = typeof days[number]; +const emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = days.reduce((sum, day) => sum + counts[day], 0); + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + {days.map((day, index) => ( + + {letters[index]} + {counts[day]} + + ))} + + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff1a"); + if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, "#5eead4"); + }} /> + {total} / 20 + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/runs/C4/REPORT.md b/experiments/render-loop-cadence/astra/runs/C4/REPORT.md new file mode 100644 index 00000000..a0d30f5f --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C4/REPORT.md @@ -0,0 +1,26 @@ +# Focus Week report + +- Condition: C (progressive capture). +- `weaver check` runs: 9 (7 passed, 2 failed with actionable authoring diagnostics; final check passed). +- `weaver capture` runs: 8 (7 successful, 1 failed before rendering). +- Confidence: 9 / 10. + +## Defects fixed because of pixels or snapshots + +- Slice 1: the original 16px title and 12px date had different vertical text metrics in capture 01. Changed both to 14px, retaining the title's semibold weight. Capture 02 confirms matching y=20.5 and height=17.5 text bounds and visually aligned text. + +## Evidence + +- Slice 1: captures 01 and 02, frame and header. +- Slice 2: capture 03, seven equal-width weekday cells (37.714287px each), Friday highlighted, all counts zero. +- Slice 3: capture 05, goal label above the bar with a clear gap. Capture attempt 04 failed static validation of a computed class and produced no artifacts. Replaced the computed class with the documented canvas drawing API, then fixed its width to the measured 288px content width after the checker rejected percentage canvas sizing. +- Slice 4: capture 06, full initial widget. Capture 07, three Log session clicks: Friday 3, all other days 0, label 3 / 20, bar 15% (43.2 / 288px). +- Additional interaction: capture 08, three Log session clicks followed by Reset week: all seven counts zero, label 0 / 20, empty bar. +- Opened and inspected every successful PNG at 320x200, read every semantic snapshot and receipt. All successful receipts have status `ok`. Both exact button names appear in semantics. Both buttons have native hover and pressed classes; post-action captures show their hover feedback. +- Counts use `useStorage` with a JSON object keyed Mon through Sun. Restart persistence relies on that documented SDK contract; capture deliberately uses fresh isolated storage each run. +- Receipts report the pre-existing dirty repository warning. No repository files were modified. One pending timer is consistent with the time subscription; no fetches, images, other providers, or pending frame requests appear. +- No live view was started, as the task explicitly forbids `weaver dev`. + +## Unmet spec items + +None identified. No automatic calendar-week rollover was added; Reset week explicitly clears the stored weekday counts as requested. diff --git a/experiments/render-loop-cadence/astra/runs/C4/clicks.actions b/experiments/render-loop-cadence/astra/runs/C4/clicks.actions new file mode 100644 index 00000000..874ba609 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C4/clicks.actions @@ -0,0 +1,26 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + } + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C4/reset.actions b/experiments/render-loop-cadence/astra/runs/C4/reset.actions new file mode 100644 index 00000000..07cd3440 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C4/reset.actions @@ -0,0 +1,33 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Log session" + } + }, + { + "action": "click", + "target": { + "role": "button", + "name": "Reset week" + } + } + ] +} \ No newline at end of file diff --git a/experiments/render-loop-cadence/astra/runs/C4/tsconfig.json b/experiments/render-loop-cadence/astra/runs/C4/tsconfig.json new file mode 100644 index 00000000..ca0e342e --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C4/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "@weaver/sdk", + "types": [], + "baseUrl": ".", + "paths": { + "@weaver/sdk": [ + "/Users/dara/Dev/Projects/weaver/sdk/index.d.ts" + ], + "@weaver/sdk/jsx-runtime": [ + "/Users/dara/Dev/Projects/weaver/sdk/jsx-runtime.d.ts" + ] + } + }, + "include": [ + "widget.tsx" + ] +} diff --git a/experiments/render-loop-cadence/astra/runs/C4/widget.tsx b/experiments/render-loop-cadence/astra/runs/C4/widget.tsx new file mode 100644 index 00000000..df4fdab6 --- /dev/null +++ b/experiments/render-loop-cadence/astra/runs/C4/widget.tsx @@ -0,0 +1,59 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +const weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const emptyWeek = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; +const letters = ["M", "T", "W", "T", "F", "S", "S"]; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage>("sessions-by-weekday", emptyWeek); + const total = weekdays.reduce((sum, day) => sum + counts[day], 0); + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + {weekdays.map((day, index) => ( + + {letters[index]} + {counts[day]} + + ))} + + + + Weekly goal + {total} / 20 + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#ffffff1a"); + if (total > 0) ctx.fillRoundRect(0, 0, ctx.width * Math.min(total / 20, 1), ctx.height, 3, "#5eead4"); + }} /> + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/astra/usage.tsv b/experiments/render-loop-cadence/astra/usage.tsv new file mode 100644 index 00000000..47253729 --- /dev/null +++ b/experiments/render-loop-cadence/astra/usage.tsv @@ -0,0 +1,11 @@ +run condition batch model effort dispatch_utc harness_start_utc completion_utc wall_seconds status input_tokens cached_input_tokens cache_write_input_tokens output_tokens reasoning_output_tokens total_tokens model_tool_calls harness_tokens_used usage_receipt +A1 A 1 gpt-6-astra high 2026-09-05T15:29:35.964481+00:00 2026-09-05T15:29:46.439Z 2026-09-05T15:32:36.148Z 180.184 complete 262911 215680 0 2735 634 265646 8 265646 evidence/A1-usage.json +B1 B 1 gpt-6-astra high 2026-09-05T15:29:54.830782+00:00 2026-09-05T15:30:01.072Z 2026-09-05T15:33:36.886Z 222.055 complete 421619 380160 0 4249 435 425868 10 425868 evidence/B1-usage.json +C1 C 1 gpt-6-astra high 2026-09-05T15:30:10.491607+00:00 2026-09-05T15:30:20.118Z 2026-09-05T15:36:16.427Z 365.935 complete 1240717 1190912 0 5418 608 1246135 27 1246135 evidence/C1-usage.json +A2 A 2 gpt-6-astra high 2026-09-05T15:36:26.825993+00:00 2026-09-05T15:36:34.797Z 2026-09-05T15:39:27.604Z 180.778 complete 337510 303744 0 2628 371 340138 10 340138 evidence/A2-usage.json +B2 B 2 gpt-6-astra high 2026-09-05T15:36:44.150022+00:00 2026-09-05T15:36:51.630Z 2026-09-05T15:40:56.691Z 252.541 complete 553963 502016 0 4192 478 558155 14 558155 evidence/B2-usage.json +C2 C 2 gpt-6-astra high 2026-09-05T15:37:02.574068+00:00 2026-09-05T15:37:09.967Z 2026-09-05T15:41:56.116Z 293.542 complete 691977 647552 0 4955 610 696932 16 696932 evidence/C2-usage.json +B3 B 3 gpt-6-astra high 2026-09-05T15:42:04.137924+00:00 2026-09-05T15:42:12.246Z 2026-09-05T15:46:21.261Z 257.123 complete 660833 603520 0 4239 558 665072 16 665072 evidence/B3-usage.json +C3 C 3 gpt-6-astra high 2026-09-05T15:42:21.872287+00:00 2026-09-05T15:42:29.070Z 2026-09-05T15:47:18.294Z 296.422 complete 784341 714880 0 5011 555 789352 17 789352 evidence/C3-usage.json +B4 B 3 gpt-6-astra high 2026-09-05T15:42:38.033291+00:00 2026-09-05T15:42:44.660Z 2026-09-05T15:46:05.408Z 207.375 complete 385415 360960 0 3563 419 388978 10 388978 evidence/B4-usage.json +C4 C 4 gpt-6-astra high 2026-09-05T15:47:28.105174+00:00 2026-09-05T15:47:37.100Z 2026-09-05T15:52:53.110Z 325.005 complete 860944 813952 0 5170 298 866114 19 866114 evidence/C4-usage.json diff --git a/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.png b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.png new file mode 100644 index 0000000000000000000000000000000000000000..6090da9995dda1675ea8bf7bf8a61fdbdbc92187 GIT binary patch literal 76953 zcmeI2S!`5Q7{@O>5JChBR10k_Yle6%s`eBS9bvLZy^aECybH2csb=FFqL`Y(CF-?bInL?M#u}^UeGwIdkva?aZA2 z|M&gxoS6-?X58JoS8lH$2ztlL%jUS{AFj>n*~2}LjQzDd=vG`AD=V4%O1D77ZR_aK zFFU``wO3s`;MyhE{&r1hi~%0FZXQs^lr?2e*(>ab(RTOgNv>792CR$$9*Eup%3^XL zy8{=wM$$$v8sMNoq6d`8MeQbTd}CI2UX?p2@g&w64?N(J2b9q`uWgoD1M;2(UWykU z@ZST2Y9E;S|v(()CnrT$cd z?Ay0rX3m)(p7Y%EFUf_A7v;#2qq2GHo8h*qm20HF{*-*RXRpkdH80%uz(bXC_Ut*S zJy9pspY4)C`NQRtPyb8)M;}`(M~~G=ZEc;r`0}!(-p`eAr<}l;AM>Y!2a*AJ!sJpp z>>$m~87yOOnsGw_gq5WmT(W?YfPv*UY}DpmjYCe=^II0cH{lfYSls zWGAtP7v3sQJ+m}S*u#f^l)=MBg`gz@TsHk)`N8d5w|YSGoiAU$EILcAtgKzXQJz@5BwSCtg`PQkeh7WR(4ugk76jea5v=X)>k`22U5IVb z{v(I+zdqx?{lkx??qt3Ebi7vH|KOumz~(==P-<$9hm%-38?Ed6zdIPVO`EsLyYFoe zkDcni>*_w8#7YEM^?GgfS~-9If}C)ZTwAxj-Fod*v;<%`kf{t9$7beu=|om%+9z{N zd)LU$>Du>Sy%qoiaHqy>&vb0_qmThG00XdL4*;-X@kl{GQZPy#02qKtV8b2&V8h}? zS^4SPkMsv%049MAdjNn9i$@Cjk%Cd`0KfoD0vq-K02>xB%F0jQexyGD1273}*aHA; zSUghDj}(kj2LJ|O64rm0DujPM+*9p zf>G)KzyM4F8}-8Ap)9t1=M6))g;iy?&7-G#)e5m& z4?)(*b{Eh;d+0y5Nam{yGC)!A{wEJ8V@=AOvUdfz@$bFLYWP_8&bZ^3{#;X~FJjYX KlTGx$w$}# literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.snapshot.txt new file mode 100644 index 00000000..a127fc75 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.snapshot.txt @@ -0,0 +1,8 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=48292000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=17000 markup_watch=off +window @w1 "CP display plain" bounds=(0,0 240x80) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP display plain" text="Weaver widget canvas" bounds=(0,0 240x80) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x80 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=2 canvas_commands=7 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=4 canvas_frame_encoder_commands=23 canvas_frame_encoder_cache_actions=13 canvas_frame_encoder_pipeline_binds=3 canvas_frame_encoder_draws=4 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=2 canvas_frame_uploads=0 canvas_frame_retains=2 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=5 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=5 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=1 canvas_frame_text_lines=1 canvas_frame_text_uploads=0 canvas_frame_text_retains=1 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=5 canvas_frame_gpu_packet_cache_actions=13 canvas_frame_gpu_packet_cached_resources=2 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=5/1024 widget_semantics=5/1024 context_menu_items=0/512 text_layout_plans=1/2048 text_layout_lines=1/8192 canvas_frame_dirty=(0,0 240x80) canvas_frame_profile_work_units=109 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=19200 canvas_frame_profile_dirty_area=19200 canvas_frame_profile_dirty_ratio=1 widget_revision=3 widget_nodes=5 widget_semantics=5 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x80) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x56) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 178.97461x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="static" bounds=(198.97461,12 29.02539x17.5) focused=false enabled=true parent=#17141410367181492475 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-display-plain/widget.tsx b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/widget.tsx new file mode 100644 index 00000000..19769491 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/widget.tsx @@ -0,0 +1,10 @@ +import { widget } from "@weaver/sdk"; +// Positive control: display-rate grow canvas, nothing ever re-renders the component. +export default widget({ name: "CP display plain", size: [240, 80], anchor: { corner: "top-right", offset: [24, 24] } }, () => ( + + + { ctx.clear(); ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#5eead4"); }} /> + static + + +)); diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/none.png b/experiments/render-loop-cadence/canvas-probe/cp-one/none.png new file mode 100644 index 0000000000000000000000000000000000000000..39465cd93b2776bbcb30af0a2a6a97ebdd38811e GIT binary patch literal 67343 zcmeI5YfKbZ7=~AW5M!z$s33?S;tFb2ELHJ_A_`aqYE|kTtEGvy)|fVe3ZfPT1gq9) zMM1nq6K@Dg5pC60uy{eR-qOVWYHIga(|>JBzMk*EuDgV_yQrNx%)7~9X3m+No%z1^ znfL50IVU$MA+}3rzs@F;sY`rZ%uKQTLzJnVJjCBWt9$=#>frG(K4#Lav<@aBQTL)( z_a1%BqO29AN|fJ3`9~B&K@6aQ*QNnxj9Fvmm_7507;UwU-z3U$Q2;Aq01arb0cO!P zkj0LvqQGgjPa42M4(v6+Os2N#xYkO~9{w3(C;K;H9r1t$bff`h)XJ;F($m|2IpD?3 z3mVYB2AEX`c)NM|4H1cJMDp~XJmd&DVpf@1E5scI(WfB{2m=~WM+3~P0Jx*6tEbNh zBu<^gAy>$iRRhef$S5 zH2{DWPM#hd0Oz1>PXqu1U^uYC8UVlwClBtYt^4UA{s0&N!+~Fu2HqMuo{k5wF|Fr>g1-%@OtXb*`)fU;ym4Xj~Ci zd)g;*Tr^#~{sZ;!38WDbW9eRf1NH3}N)e)qd{F>xUy6zk$#|~M*ho3K1rD*@vUM9} zW_>{!8#dFHoNW$mTXXU$L);|XjT-<4z;27iU6HB2e{jeUdidxOeY|ot4GkadQoO#% z&Xu6rU;DcCSrXjrt$DCZ_gW-{1Tut@va$m7XuB zYuCP~z~Dg?I(P(a*qH55R<8P7#&hA~WmH;P?hxCv=gw2g2OrVmC8@;g_VGGbT1Jaf zK6I$FZ+Es1fB~@EqH!js_F6w?{A4Q4FY6oblR0d-EZjCdaaL1XQgd7AaNB3N8cP5SfZZ02tKw=;`yD7Mppz!T)4m3rI^iNFzfGA!~LJALBMPO@GJ4%WC=94G1v)7b6h%R%a{US0Nf_wv=ow2 zw)sJpyVn|G9_sWxFKTn;a{w>^b}BAc1cZIG{S6xc17HBGum%9I!pVdCY3qJ^h(7=Z zz;IxNH2{DWPM#hd0Oz1>F8}}oU^uYC8UVlwClBtYt^4UA{s0&N!+{mn0034vd3taF zoP)N#000bt;lK)O001kTJh-2>?x%A?YT4%+qt05AZC11qcn z0IYEG;C|Y=pB~~5fB`TZSYZtSV1<*X2M548Xxj?_zyKHytgr@N8sN=h_{`+Fiy;Dq zMF1Do)W5!LUUcNzM4wxt#(C^KjPZK7_+O{W8d564u zHU%tP43Zr>C|tJjv=TgkHebxN=`-6r$k)pR1MgK=$VSbb+W`Cc1&b*ozNNwg2Wekn z5j}YD(B{C`#pw09dE05;f+Ygd0Q&Cgbvgd+p1p;%XYYOq=b5vm#GrG)FI8QpUAyC$E4GmK>q{?K|ah%E~Xwwq>a+LF~SYrt)Q7c5#z1z+y6LG_hzQ0sT#+S=Q;dhcF+rMp&q zbBVU)@1VzzpU9cn28M-8=;tq7N^8GrRZfBOW|EzhEcz>fO(F zOrs|Y*N+=kOAWXU@W{w0s;#{xzzU+CzJXMG>vpREPl-*SBH^n1fguBj(z9p3OMrR1 zva(9fjmpR3=_E=H9igxH9T3M0l3i$D(M{+5*xe(?M$3`xd35}iCy#9i+UOc^8(

0KB12eSULhboN}o2*8TV&JkA>eHn;{F8DNXS zgMcn1dLgQ6z+&?B_OAxOa588>Jq<9srfy!ncOZG{B@a16&X`?O=Qq6KAqI#68c^sPo7pvW6)Q|~7#?V;lSBY#%v{L_S55FTv&^okqbNS2Fws^gMt2(B zX`^*Z^?tpLcFxPJGPBICe0hk!vMVi?Vcfsg|AVa#H6Ek?GUja<_G`SnGmy<+e5KPi z1Iyq#ygG?38_8l_(#*as4#5BM!T+`edxkyh-L6zWKW5Cr%rSc{z_ot)Wme_uvnLmR T%^LP|0&m1mNr*WUowDg)1vtw0 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/none.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-one/none.snapshot.txt new file mode 100644 index 00000000..61b5eec9 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-one/none.snapshot.txt @@ -0,0 +1,9 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=36832000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=21876 markup_watch=off +window @w1 "CP one" bounds=(0,0 240x70) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP one" text="Weaver widget canvas" bounds=(0,0 240x70) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x70 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=8 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=3 canvas_frame_encoder_commands=28 canvas_frame_encoder_cache_actions=19 canvas_frame_encoder_pipeline_binds=3 canvas_frame_encoder_draws=3 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=10 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=10 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=5 canvas_frame_gpu_packet_cache_actions=19 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=6/1024 widget_semantics=6/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x70) canvas_frame_profile_work_units=127 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=16800 canvas_frame_profile_dirty_area=16800 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=6 widget_semantics=6 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x70) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x46) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 181.19824x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="s=00" bounds=(201.19824,12 26.801758x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#1952158521899574484 role=text name="draws:" bounds=(12,37.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/tick.png b/experiments/render-loop-cadence/canvas-probe/cp-one/tick.png new file mode 100644 index 0000000000000000000000000000000000000000..7cb486f6a746164f12f9195669617c0877dc174d GIT binary patch literal 67343 zcmeI5X;4;G7{_1z;51Gesi}Z0BD_MHC6yyBE{KBWmT9JFYKu-{rT6i;D3A#8eQm{)N|;x20jthcB{|5 zE!y~1c~_M@Ren|FUsZ&KHlPOXmcnzq7nuks#yd1o! z0q<)7tOme)PqUDY%5kN1p7)(cAJIo(70g-?H&jG_MPX1F)POk}0J93Wo8 za~wxs(N~rRz^*T-c}RxUz?$Nq2F%d_*i`_B9;MUFaT1ir%>c(}`xvU$rkxqSH- z*|POBd9-V{0Gm&F;~hy%>KD*f*};JT-(lxf))DMiH=}7tShO5HdR(Txn=WmmJLoz; z|3?W8_sc`^39@!ww*36_Wf?Mb1OX-lbrS+F`E^G62Xg9kq2%W7mq9~@R|ws(;iDz* z;5PyN_8&MX&y5@-k?lH2O25I9le3Qid&$Xsmby8RBs`HQhYtTBEm}oL{3DOcnWD22 z-ZoYqQB&l73TS6pw|=9Bc1GI!GCw0L0N{BaW=i_3Id)t2#?1tn(9}(6yyVxY=#FyX z;zfCN@|)7Bb5|R{TRr2Pxfzl+b9O-A_h!tJdGj;vHUi9btSyFHiHYA;e~@eEe?TU^ z_NMIGog;@19g&Er`z5wRyv%%mZa|ql%6>gql_IIlCH5L6G{2iF^yDqAVM91&l8%PK+0Vco(Yk&Y7 z>^w#?_ad38wj{s=m=V}u4G>_1oo8y);B&h-b0EM3m=V}u4G>_1oySP#UL-TsmIRmp zGXfi|0Rn8W^GuBzd~Ww<4g{D0GXfi|0Rn8W^BBq8i)5zSk^mE6Mqql>Mm>M<4(q$`kexXB$kI3G=xdJdPNUa)~ z0`v0=?DpQt1NHfqt=n|%eCDW_j&kbMX=!#}nBCvH4{P_L1#RiREpH28Yzr|Wb*v;M z4-hB7k3G>#TDFc8$;-!82Dnv7l-erdTUot!gREM;PKt{!*b(@!%37bX zV3CX*HBQ6u-S>wDIdGS+Sgpz$ZJg~pb_qa-Q4ZuClqE}7=;JZt#>@N#Spv`&E?TVb zvqx*Fp7J*2R( zNJq_ylcvbj>1h(F5@KV2neSC{YzSoihK)L+BUv_b?V_!_%B_ot?i3L6@&a0`Exc`< zn*J8r=TM1w!?BW{iGqZI0 zDnZihg;|ULx4vDF`H{S;GUHp0Ojcm-*s2LO~EI_qC3Yf)gjp1sE@l)~Top0Yta&B)|Rky9OBN`}gOm zeNwjx?)CiGmnD1SCRw>^t-4>NoMZtHx1tSeW6S`ssTBI-y0_k* zu8$FAo%wn#fH5!}JDx9ibB%ihw`r%7bBCx|0?ttgu(yS3`H6L)pQ;Qn3^+^e1A~YP zK)(EHXSo0a4s5Fk2y=3B6{MTx^|Jk9roT5+M?l;QTP&88l*rI$M`@6-rwrEEnCh<2 z{#3U)*TA?2JG&KMxG3j~i*ieR`{x)d0 z3IV=u3(F>~y>FA-0@w?VMO3}<_gqY`D|$ApnJenU@4YWv`skXEj0Lzn2jb_a^4i%( zAnU3I>J-3r)k*w!aR9oR1_-cY9egt*v7G>URRaW=0CU-4um%XQ!Ort)RN!;f+>8YP zm(t)hXK>n@wsuhir2x3Z#T#-u#)wW0)SL!Nd_m1aj}c%-1!}-N4S-$WJ!;KadBG}}1-tswNd2j&(yETb{M!33 zwi+C7)b;QBISe!W)<3@k$g+j6jC)mqaMHK;z@+VoV?X#0Z!#_s literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/tick.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-one/tick.snapshot.txt new file mode 100644 index 00000000..e8096aa4 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-one/tick.snapshot.txt @@ -0,0 +1,9 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=43812000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=23390 markup_watch=off +window @w1 "CP one" bounds=(0,0 240x70) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP one" text="Weaver widget canvas" bounds=(0,0 240x70) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x70 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=3 gpu_timestamp_ns=1034333334 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=2 canvas_commands=8 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=3 canvas_frame_encoder_commands=35 canvas_frame_encoder_cache_actions=26 canvas_frame_encoder_pipeline_binds=3 canvas_frame_encoder_draws=3 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=14 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=15 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=4 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=5 canvas_frame_gpu_packet_cache_actions=26 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=6/1024 widget_semantics=6/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x70) canvas_frame_profile_work_units=149 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=16800 canvas_frame_profile_dirty_area=16800 canvas_frame_profile_dirty_ratio=1 widget_revision=3 widget_nodes=6 widget_semantics=6 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x70) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x46) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 183.02441x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="s=01" bounds=(203.02441,12 24.975586x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#1952158521899574484 role=text name="draws:0,181" bounds=(12,37.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.png b/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.png new file mode 100644 index 0000000000000000000000000000000000000000..60abb92c3a1c5589dd1144635391100403b38174 GIT binary patch literal 67343 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 Oy?Z9~IMi*-y#E0Qq}YG} literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.snapshot.txt new file mode 100644 index 00000000..73d586ca --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.snapshot.txt @@ -0,0 +1,9 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=31668000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=23511 markup_watch=off +window @w1 "CP one" bounds=(0,0 240x70) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP one" text="Weaver widget canvas" bounds=(0,0 240x70) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x70 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=4 gpu_timestamp_ns=2051000001 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=3 canvas_commands=8 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=3 canvas_frame_encoder_commands=39 canvas_frame_encoder_cache_actions=30 canvas_frame_encoder_pipeline_binds=3 canvas_frame_encoder_draws=3 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=15 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=17 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=6 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=5 canvas_frame_gpu_packet_cache_actions=30 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=6/1024 widget_semantics=6/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x70) canvas_frame_profile_work_units=159 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=16800 canvas_frame_profile_dirty_area=16800 canvas_frame_profile_dirty_ratio=1 widget_revision=4 widget_nodes=6 widget_semantics=6 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x70) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x46) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 181.48828x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="s=02" bounds=(201.48828,12 26.511719x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#1952158521899574484 role=text name="draws:0,181,0,183" bounds=(12,37.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-one/widget.tsx b/experiments/render-loop-cadence/canvas-probe/cp-one/widget.tsx new file mode 100644 index 00000000..756a22ec --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-one/widget.tsx @@ -0,0 +1,15 @@ +import { useProvider, widget } from "@weaver/sdk"; +let drawLog: string[] = []; +export default widget({ name: "CP one", size: [240, 70], anchor: { corner: "top-right", offset: [24, 24] }, subscribe: ["time"] }, () => { + const time = useProvider("time"); + const history = drawLog.join(","); + return ( + + + { drawLog.push(String(Math.round(ctx.width))); ctx.clear(); ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#5eead4"); }} /> + s={time.ss} + + draws:{history} + + ); +}); diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/none.png b/experiments/render-loop-cadence/canvas-probe/cp-pair/none.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb9c9fadb83392573009a8d08c30a1854cb803a GIT binary patch literal 86563 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 VcJ9}Rxe>e*^HKlk!%<_B{ttA8JwX5f literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/none.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-pair/none.snapshot.txt new file mode 100644 index 00000000..4875dc06 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-pair/none.snapshot.txt @@ -0,0 +1,11 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=39887000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=19022 markup_watch=off +window @w1 "CP pair" bounds=(0,0 240x90) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP pair" text="Weaver widget canvas" bounds=(0,0 240x90) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x90 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=2 canvas_commands=11 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=6 canvas_frame_encoder_commands=42 canvas_frame_encoder_cache_actions=28 canvas_frame_encoder_pipeline_binds=5 canvas_frame_encoder_draws=6 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=17 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=17 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=7 canvas_frame_gpu_packet_cache_actions=28 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=8/1024 widget_semantics=8/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x90) canvas_frame_profile_work_units=178 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=21600 canvas_frame_profile_dirty_area=21600 canvas_frame_profile_dirty_ratio=1 widget_revision=3 widget_nodes=8 widget_semantics=8 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x90) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x66) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 159.77295x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="one w=-1" bounds=(179.77295,12 48.22705x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(12,41.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10954899810383814503 role=group name="" bounds=(12,46.25 127.00391x8) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#15095474804485896871 role=text name="disp w=-1 s=00" bounds=(147.0039,41.5 80.99609x17.5) focused=false enabled=true parent=#10162277730996300551 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.png b/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a287ddad70323cc02537811a5701d5bce7a162 GIT binary patch literal 86563 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.snapshot.txt new file mode 100644 index 00000000..dd23898b --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.snapshot.txt @@ -0,0 +1,11 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=36974000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=20838 markup_watch=off +window @w1 "CP pair" bounds=(0,0 240x90) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP pair" text="Weaver widget canvas" bounds=(0,0 240x90) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x90 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=3 gpu_timestamp_ns=1034333334 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=11 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=6 canvas_frame_encoder_commands=48 canvas_frame_encoder_cache_actions=34 canvas_frame_encoder_pipeline_binds=5 canvas_frame_encoder_draws=6 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=19 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=21 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=4 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=7 canvas_frame_gpu_packet_cache_actions=34 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=8/1024 widget_semantics=8/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x90) canvas_frame_profile_work_units=194 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=21600 canvas_frame_profile_dirty_area=21600 canvas_frame_profile_dirty_ratio=1 widget_revision=5 widget_nodes=8 widget_semantics=8 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x90) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x66) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 150.96436x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="one w=160" bounds=(170.96436,12 57.035645x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(12,41.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10954899810383814503 role=group name="" bounds=(12,46.25 121.052734x8) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#15095474804485896871 role=text name="disp w=127 s=01" bounds=(141.05273,41.5 86.947266x17.5) focused=false enabled=true parent=#10162277730996300551 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.png b/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd7bfd68716ce7abfd92264253f3481eb254ad48 GIT binary patch literal 86563 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 RI};yL9_p2xn>2Lh{{cib^Mn8Z literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.snapshot.txt new file mode 100644 index 00000000..9171b58e --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.snapshot.txt @@ -0,0 +1,11 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=29665000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=20960 markup_watch=off +window @w1 "CP pair" bounds=(0,0 240x90) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="CP pair" text="Weaver widget canvas" bounds=(0,0 240x90) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x90 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=4 gpu_timestamp_ns=2051000001 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=6 canvas_commands=11 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=6 canvas_frame_encoder_commands=51 canvas_frame_encoder_cache_actions=37 canvas_frame_encoder_pipeline_binds=5 canvas_frame_encoder_draws=6 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=17 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=22 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=6 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=7 canvas_frame_gpu_packet_cache_actions=37 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=8/1024 widget_semantics=8/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x90) canvas_frame_profile_work_units=196 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=21600 canvas_frame_profile_dirty_area=21600 canvas_frame_profile_dirty_ratio=1 widget_revision=7 widget_nodes=8 widget_semantics=8 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x90) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x66) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 152.99463x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="one w=151" bounds=(172.99463,12 55.00537x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(12,41.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10954899810383814503 role=group name="" bounds=(12,46.25 120.67676x8) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#15095474804485896871 role=text name="disp w=121 s=02" bounds=(140.67676,41.5 87.32324x17.5) focused=false enabled=true parent=#10162277730996300551 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-pair/widget.tsx b/experiments/render-loop-cadence/canvas-probe/cp-pair/widget.tsx new file mode 100644 index 00000000..2d023d2b --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-pair/widget.tsx @@ -0,0 +1,19 @@ +import { useProvider, widget } from "@weaver/sdk"; +// Module-level probes: onFrame records the width it saw; the labels re-render only on time ticks. +let oneShotWidth = -1; +let displayWidth = -1; +export default widget({ name: "CP pair", size: [240, 90], anchor: { corner: "top-right", offset: [24, 24] }, subscribe: ["time"] }, () => { + const time = useProvider("time"); + return ( + + + { oneShotWidth = Math.round(ctx.width); ctx.clear(); ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#5eead4"); }} /> + one w={oneShotWidth} + + + { displayWidth = Math.round(ctx.width); ctx.clear(); ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#fb7185"); }} /> + disp w={displayWidth} s={time.ss} + + + ); +}); diff --git a/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.png b/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.png new file mode 100644 index 0000000000000000000000000000000000000000..e2fb1462982f1ad44282b5552ab8298e5cb075e5 GIT binary patch literal 76953 zcmeI2YfMx}7=~AW7-Om;pvc8b6&6qgL=kPIQiB(~0$T4NUO;2D)EbpowAP9Z*eC|u zYBieL)S6IH(W+>hS`|bT5f!`@D)GV8s|f1IBBBS!^E2 z;=~k@;IzgE4d5UK_8MR&QyO(#bYELIh2ppdnU>mC^vSYY~MybpScU0S#!S zfjR~lyU!+i&j*0C0?6oh(&;S4iz;Hi}H2{D$ z4xSkt0DUlaB?5o}FdSH84YUg2DFw%9(O+ehSa%NzW6&ZEz_Fd{*ewQ_;RU#uxLT`$ z*9~yM&@ei1@Gw1k^q9__zd#EUmO893w(rQKvfJfUSa^+6R<5ztx%Tcy89TD*wy3*W zSVYMyR@>^@+Glr<{*;-ui|*XHOINNGQqs~D4)-1z5lNf3Y;!o)+%{VbFq{|gwiaH# zuDQZ&?RnoGI7FX*mLc02IVzGWDl4h~zyMj^l)jbn^M9rh;&{x|IJ#DRo#JONkag(- zpi}v0C@g#|O_>%?#l-CZw z^xcskTGdvI0d7n1a4q0}6_^{-HdAc;JSk>tKq#F(S3rINA+kI(ZZ4&5+R|*HyY=Z$ zWo6~W4#(|2eE5hW#zfh!U$Sf^oji3~mLEU|VXcK-@_u%8a49?oQn|`}=nXG}K6cil(0+55P!z9$h1jyW`{r!CXgQ=>j%HbH- zvvYp4?;wqzF!hBx`|H*B@Q8QmX6Y@5b7fz|#G%e=5HoOy|ImB7nrex~KR)Q{HN`l9;88*1(z1E{vPmUu!?_ux&e z6DRX+<#q*_JAv0ofVi~~D-pjeUz56ya(~JrUY7ECoag4|QR>?DvOFSuEb+6beHs!p zLV{R)y@VKcb^n43ztE(ZnX+T zce&dgVEZ41@6LU%hw=2GKmp^kXU`~Mak2y;F)3M=?H#hIahef3NA4hB`u(zeZNtE- zbG`cc%I8*o#q{*)Q`(dBwOyT`+_X}4_SdQFIp>Y98#ha(JM%7fsCZVkuW#%-gUlOW z4<0;}?e6?C+u<4jEC#l*fy1$mJ1)Fw)l~ck4jw|i`wnchp6hto+tjt{cyrEC=c;^= zUl8%mxGFm%Z}Dp+XEcg?bX>3yd*{X;0K>hV>IeYTxq!ZEJOMBO2EZC?003(oyjRW6 zsBd34G-A8~FaU-FYpekPta0#+nDNo3xm+Cp17J9?#u@;?8V3(mm3-p4*(2+;lLVe003(oJR@d&v}rEa z2fzRr4y>^T0Is8G?(iGU;qpU)>s1oSmWTq z4bA0-M#KXE17J9?#u@;?8VApa86Rz$%k=>;0EPo=tN{S5aq!@V=5j+L;sJmGFdSH8 z4FF(`gJ;Byk2cNa`T!UJ!+|x{007oFcyL2=xuFs90Kfnk4y>^T0I^dU;qpU)>s1oSmWRsG2^36bGbeM2EcG&jWqy(H4Yx! z&|Ge4L_7d60EPo=tN{S5aqx_o@zJKaTps`fU^uYG8UVl=2M=y&E;lqH9sn2s!+|x{ z00Ufa#LUt5Hao=y<=w>;-1dRQ7-~L-^-OV{=05^9qOpxYdu^IT>ntvA-bEP1HVq;s z5KJJ3Xn@(Z^mO&i2EYIq8qiMz%&w)|Tdpw(o_@hY%n&nX*CIZF!irBr5D)}3ppOQa zS!S03wl=u1rd!hb3_1Wotem8Q`Udy4GQd6}1@`FGcZ-v5ZpZ^Y`VKfciUycfX10M{ zOAqmdNe;w@79i*-5a{|l<;K<0h< literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.snapshot.txt new file mode 100644 index 00000000..a5ac3839 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.snapshot.txt @@ -0,0 +1,8 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=36395000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=6684 markup_watch=off +window @w1 "Canvas Probe" bounds=(0,0 240x80) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Canvas Probe" text="Weaver widget canvas" bounds=(0,0 240x80) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x80 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=3 gpu_timestamp_ns=1034333334 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=2 canvas_commands=7 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=4 canvas_frame_encoder_commands=26 canvas_frame_encoder_cache_actions=16 canvas_frame_encoder_pipeline_binds=3 canvas_frame_encoder_draws=4 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=2 canvas_frame_uploads=0 canvas_frame_retains=2 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=7 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=7 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=1 canvas_frame_text_lines=1 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=5 canvas_frame_gpu_packet_cache_actions=16 canvas_frame_gpu_packet_cached_resources=2 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=5/1024 widget_semantics=5/1024 context_menu_items=0/512 text_layout_plans=1/2048 text_layout_lines=1/8192 canvas_frame_dirty=(0,0 240x80) canvas_frame_profile_work_units=119 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=19200 canvas_frame_profile_dirty_area=19200 canvas_frame_profile_dirty_ratio=1 widget_revision=3 widget_nodes=5 widget_semantics=5 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x80) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x56) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 143.66504x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="w=300 s=01" bounds=(163.66504,12 64.33496x17.5) focused=false enabled=true parent=#17141410367181492475 diff --git a/experiments/render-loop-cadence/canvas-probe/cp-shrink/widget.tsx b/experiments/render-loop-cadence/canvas-probe/cp-shrink/widget.tsx new file mode 100644 index 00000000..68765ced --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/cp-shrink/widget.tsx @@ -0,0 +1,24 @@ +import { useProvider, useState, widget } from "@weaver/sdk"; + +export default widget({ + name: "Canvas Probe", + size: [240, 80], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [seen, setSeen] = useState("none"); + return ( + + + { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#5eead4"); + const label = `w=${Math.round(ctx.width)}`; + if (label !== seen) setSeen(label); + }} /> + {seen} s={time.ss} + + + ); +}); diff --git a/experiments/render-loop-cadence/canvas-probe/probe1/capture.png b/experiments/render-loop-cadence/canvas-probe/probe1/capture.png new file mode 100644 index 0000000000000000000000000000000000000000..cae4af856ee3895ed549f28578dbbf5cdc9de60f GIT binary patch literal 76953 zcmeI5YfKbZ6vtOT7-Om;XhA?!#04y^uNogUwkoKL?^lzmRkQ}J)>^Gbe1U>mK?M=; zU29t(Ac7j(SOt-nrhpX{d_|hr4^0z3^@Ja%Sw=A8fU z{_o6^J;}3XOzzsnzl+6U>1vx2IY&(Y6m3@LPU3HyI#`Iry4GGj zdInlW+ag+lXn%4KTYFFCYJ8`wC1U4ro9f4KTX`;DFmmnmS2Cu8=Fc2AExoSg5zJz!c(u z29(l3Jp+uV&mQzW9{^GcAa{R9-oOC6`y}xB$N@Cqq6Pr4i-AMOhmPM9Gys4BFx*dJ z4FF(;ljjKzfOBx~NCW@_U^uYC8UVlwClBuDUib5a_yb@73%QDX8JS09>?Yf0(x$j=lyf1EVwSCt>!w7{qJqLA zs(tjB($X`@=glA*I(!TrK5|@(_wGF@w0g~Yx$NDm59MCWr+}b=+WUGsM*yrdd3u70 zZQScdM#g`D^=*3oypASBO{L(05p?!kHWl3}k+6NVFoqrpP)ENvK`svr8%$51J|l*h z_v3B1$0tgNpFDX=eS^cPr*B`Xt$jqr#ieqevF}Gw;muo4!OPbRfB~@6qA?N_Pd)a$ z4;Rvf+$V*fwMz6Tcw4GnT z0Q$M2k`i|8B8K;t82UOoup_{OhmMj%=+Hq!Wo%Q^GAQ+6hMeymIDqc{a*v8jN+~!b zg2qpbru<7+sG_3Er91#&0PK=*%mk<2YvG|TJ7<=75Vc^@GP?HD4H-KgGCKmy$BSLL zhU)5mr3Vjd=<=1T;^CB4i*t5PE)_Hmsrlg+-&^lZIiS6-_k4Ie01SX#5{@$>GsCuh z`h`+OWfjexzmRxH%=f&jK3n&{vEzqTMqWPv2Ec|2%t-OJ^|42e{(uf1%A)hxxzb^I zINa9f@bc#YU;ylP5xy)+EbIR|4gdpS0IaYE0I31r##tHxfU^uYC8UVlwC(o>|g6q;hvH-vU7!Itk1^}?a$%9krcPg{S z3IGFOIIzMR0Kf_-&#bP3>(W260Kfnk4y>>STmm@ydNwWky_y!+*Po0?UpT-;$7Kc$m;qv^0fzGeUNgYU*T7oV}m<7uYWK-78M5VkY{8al~68@iKV>!%X0nNbsOo-*=$*baLm|=vhqSuzc7lP zHb=rcLexMSGHf*6yI0-z0OKJR05%K2dLLr71~A_fmzUp>FmhQ@2K!>(C3(-BuyZ$Y zdnn4QOr1WL5=9}i#9eze_>;tZn-8J+1o^_@!~j`UkXgHW;bpzI1~3;rD=oWCm6dm? zf5=-B&L4ifMxTGNQPv0MGNjzB;X^1nC6(efZ`T0cEbgt{03lh$qiF+th46Qlm4EXnF&XYB4h%AW46%B*>hf!c(t1MRvfJKl1 z2V!8P23i7m?)(K*SXe|{VURzcA8xG>RSEq9f+fr~;vp70^ZE^Onnp9Tj?s%3zsd5W z$4{Js0~?t*92*_Ot7xF5%7iVgcjdF3{u;@Z55YbF0U9ty0{|F9aBX-8$c%x^$hZPv z01SW?)&KxjIC)0)>^Qa>ZVZ3{FdSH64FF(;lLwbn!zGQ(695LlaA1Ws0Du)vo{>E} zj;)5f17H9Q2Ub`E09fJV!6nsjNh9+FfB`TZSYZt?zzs(B5XK$5!|aIs8g#+N1sJha zB(@DqalIlZ3%gL*E}$_(I>ma6mruYQ1lN$@qQgOlW2gq0T}yZG-Uk6N0EPzC(*Uz; z>GFoR4ark4dB_=Z#_U?eD_mIdRR{utfCkjj05i+%GQieG7gqF`K+(dx_3(>-O$Rsh#vSJf2->>_m{n%BkzGqSF~cN>3XKA3p!FicgW|rBNuTJ8x97>C6IFGOKU<+>S>2B0s z&W~AayyulB+sG<2+vL?*ENKvnc?mLGwm1O)vj_jj7M$6$dS$qz`SQVx)iZO<-b>)x c?|Ye5`3f(1aHQ^8c@i(!qGm+qPl!qU2b!Jc1poj5 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/canvas-probe/probe1/capture.snapshot.txt b/experiments/render-loop-cadence/canvas-probe/probe1/capture.snapshot.txt new file mode 100644 index 00000000..7f0a70db --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/probe1/capture.snapshot.txt @@ -0,0 +1,11 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=31400000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=72129 markup_watch=off +window @w1 "Canvas Probe" bounds=(0,0 240x80) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Canvas Probe" text="Weaver widget canvas" bounds=(0,0 240x80) layer=0 visible=true enabled=true focused=false open=true gpu_size=240x80 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=11 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=5 canvas_frame_encoder_commands=32 canvas_frame_encoder_cache_actions=19 canvas_frame_encoder_pipeline_binds=5 canvas_frame_encoder_draws=5 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=1 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=1 canvas_frame_layer_evicts=0 canvas_frame_resources=3 canvas_frame_uploads=0 canvas_frame_retains=3 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=9 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=9 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=2 canvas_frame_text_lines=2 canvas_frame_text_uploads=0 canvas_frame_text_retains=2 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=6 canvas_frame_gpu_packet_cache_actions=19 canvas_frame_gpu_packet_cached_resources=3 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=8/1024 widget_semantics=8/1024 context_menu_items=0/512 text_layout_plans=2/2048 text_layout_lines=2/8192 canvas_frame_dirty=(0,0 240x80) canvas_frame_profile_work_units=137 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=19200 canvas_frame_profile_dirty_area=19200 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=8 widget_semantics=8 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 240x80) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(12,12 216x56) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(12,12 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10908610489528790432 role=group name="" bounds=(12,16.75 182.20801x8) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="grow" bounds=(202.20801,12 25.791992x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(12,41.5 216x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#10954899810383814503 role=group name="" bounds=(12,46.25 180x8) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#15095474804485896871 role=text name="fixed" bounds=(200,41.5 25.561035x17.5) focused=false enabled=true parent=#10162277730996300551 diff --git a/experiments/render-loop-cadence/canvas-probe/probe1/widget.tsx b/experiments/render-loop-cadence/canvas-probe/probe1/widget.tsx new file mode 100644 index 00000000..3ab8e709 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/probe1/widget.tsx @@ -0,0 +1,23 @@ +import { widget } from "@weaver/sdk"; + +const draw = (ctx: any) => { + ctx.clear(); + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, 3, "#5eead4"); +}; + +export default widget({ + name: "Canvas Probe", + size: [200, 80], + anchor: { corner: "top-right", offset: [24, 24] }, +}, () => ( + + + + grow + + + + fixed + + +)); diff --git a/experiments/render-loop-cadence/canvas-probe/tick.actions b/experiments/render-loop-cadence/canvas-probe/tick.actions new file mode 100644 index 00000000..be9b05e8 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/tick.actions @@ -0,0 +1 @@ +{ "schema": "weaver.capture.actions.v1", "actions": [ { "action": "advance-clock", "milliseconds": 1000 } ] } diff --git a/experiments/render-loop-cadence/canvas-probe/ticks2.actions b/experiments/render-loop-cadence/canvas-probe/ticks2.actions new file mode 100644 index 00000000..9afae791 --- /dev/null +++ b/experiments/render-loop-cadence/canvas-probe/ticks2.actions @@ -0,0 +1 @@ +{ "schema": "weaver.capture.actions.v1", "actions": [ { "action": "advance-clock", "milliseconds": 1000 }, { "action": "advance-clock", "milliseconds": 1000 } ] } diff --git a/experiments/render-loop-cadence/clicks.actions b/experiments/render-loop-cadence/clicks.actions new file mode 100644 index 00000000..d510ea73 --- /dev/null +++ b/experiments/render-loop-cadence/clicks.actions @@ -0,0 +1,8 @@ +{ + "schema": "weaver.capture.actions.v1", + "actions": [ + { "action": "click", "target": { "role": "button", "name": "Log session" } }, + { "action": "click", "target": { "role": "button", "name": "Log session" } }, + { "action": "click", "target": { "role": "button", "name": "Log session" } } + ] +} diff --git a/experiments/render-loop-cadence/common-prompt.md b/experiments/render-loop-cadence/common-prompt.md new file mode 100644 index 00000000..d99a3d2e --- /dev/null +++ b/experiments/render-loop-cadence/common-prompt.md @@ -0,0 +1,40 @@ +You are building one Weaver desktop widget. Weaver is a desktop widget platform authored in TSX; the repository is at /Users/dara/Dev/Projects/weaver and you run all commands from that directory. You have no other context, so read what you need from the files named below. + +## Your widget directory + (create it with `npx --no-install weaver init `; it will not exist yet) + +## Rules +- Do NOT run `weaver dev`. Do NOT modify any file inside the repository. Do NOT read or touch any directory under /tmp/weaver-exp other than your own and the file /tmp/weaver-exp/clicks.actions. Do NOT read /Users/dara/Dev/Projects/weaver/experiments. +- Import Weaver APIs only from "@weaver/sdk". Keep one literal default export: `export default widget({ ... }, () => <... />);` +- Before writing elements, read these parts of /Users/dara/Dev/Projects/weaver/sdk/CONTRACT.md: "Module shape", "widget(config, component)", "Hooks", "Consolidated v0.4 authoring tables", "useStorage", and "PR 11: native interaction states and press events". Read /Users/dara/Dev/Projects/weaver/examples/pomodoro/widget.tsx and /Users/dara/Dev/Projects/weaver/examples/clock/widget.tsx as the house style. Do not infer browser DOM or CSS behavior the contract does not provide. +- `npx --no-install weaver check ` is the authority for statically knowable widget errors. It must pass before you finish. + +## Widget spec +Name: "Focus Week". Size 320×200. Anchor top-right, offset [24, 24]. Subscribe to the `time` provider only. No network, no other providers. + +1. Header row. Left: the title "Focus week". Right, aligned to the same baseline: the current weekday and date, for example "Fri, Sep 4" (from time.weekday, time.month, time.day). +2. Seven day cells in one row, Monday through Sunday, equal width, filling the available width. Each cell shows the weekday letter (M T W T F S S) above that day's session count. Today's cell is visibly highlighted. Days with zero sessions still show "0". +3. A progress bar showing sessions logged this week against a goal of 20, with a label of the form "12 / 20" placed so that it never overlaps the bar. +4. Two buttons in one row. Primary: "Log session" adds one session to today. Secondary: "Reset week" sets every day to zero. Both have native `hover:` and `pressed:` styles. Counts persist across restarts with `useStorage`, keyed by weekday. +5. Visual bar: the shipped examples' house style. Dark translucent surface, rounded corners, restrained palette, clear hierarchy, nothing clipped or overlapping, text legible at 1× scale. + +The buttons' accessible names must be exactly "Log session" and "Reset week". + +## Capture commands (only if your condition below allows capture) +Fixed clock for every capture: 2026-09-04T09:41:00.000Z (a Friday). Copy /tmp/weaver-exp/clicks.actions to /clicks.actions first. It clicks "Log session" three times; the expected result is Friday showing 3, every other day 0, label "3 / 20", bar at 15%. + +``` +mkdir -p /captures +npx --no-install weaver capture --clock 2026-09-04T09:41:00.000Z --out /captures/NN-initial.png +npx --no-install weaver capture --clock 2026-09-04T09:41:00.000Z --action-file /clicks.actions --out /captures/NN-after-clicks.png +``` +NN is a zero-padded counter (01, 02, ...) that increases on every capture you run; never overwrite an earlier capture. Each capture publishes a .png, a .snapshot.txt (semantic tree) and a .receipt.json. When you capture, open the PNG with your image-viewing tool and actually look at it at the widget's real dimensions; check layout, overlap, clipping, alignment, contrast and the requested state. Read the snapshot and confirm the receipt has status "ok". A capture whose receipt says CaptureWidgetFailed prints a `diagnostic:` line naming the widget error. + +## When you are done +Write /REPORT.md containing: +- Condition letter. +- Number of `weaver check` runs and number of `weaver capture` runs you made. +- A list of every defect you fixed BECAUSE you saw pixels or a snapshot (write "none" if you never captured or found nothing). +- Any spec item you could not meet and why. +- Your confidence (0 to 10) that the widget matches the spec. +Then reply with a two-line summary. Do not paste code into your reply. diff --git a/experiments/render-loop-cadence/cond-A.md b/experiments/render-loop-cadence/cond-A.md new file mode 100644 index 00000000..edceda16 --- /dev/null +++ b/experiments/render-loop-cadence/cond-A.md @@ -0,0 +1,2 @@ +## Your condition: A (check-only) +You may run `weaver check` as often as you like. You must NEVER run `weaver capture`, and you never see pixels or a snapshot. Build from the contract, the examples and your own reasoning. Stop when you believe the widget matches the spec. Leave /captures absent. diff --git a/experiments/render-loop-cadence/cond-B.md b/experiments/render-loop-cadence/cond-B.md new file mode 100644 index 00000000..fcfbfa14 --- /dev/null +++ b/experiments/render-loop-cadence/cond-B.md @@ -0,0 +1,2 @@ +## Your condition: B (final capture) +Write the whole widget first, without capturing. Only when you believe the widget is complete, run the Render loop: check, capture the initial state, capture the after-clicks state, open both PNGs, read both snapshots and receipts. Then fix whatever you find and re-capture. Repeat until you are satisfied. There is no cap on rounds. diff --git a/experiments/render-loop-cadence/cond-C.md b/experiments/render-loop-cadence/cond-C.md new file mode 100644 index 00000000..e69b4c2b --- /dev/null +++ b/experiments/render-loop-cadence/cond-C.md @@ -0,0 +1,7 @@ +## Your condition: C (progressive capture) +Build in four visual slices and run the Render loop (check, capture, open the PNG, read the snapshot and receipt) at the end of each slice before starting the next: +1. Frame and header row only (capture initial state). +2. Add the seven day cells (capture initial state). +3. Add the progress bar (capture initial state). +4. Add the buttons and storage (capture initial state AND after-clicks state). +Fix what you see at each slice before moving on. You may re-capture within a slice as often as you like. After slice 4, keep iterating until you are satisfied. diff --git a/experiments/render-loop-cadence/final-captures/A1-after.png b/experiments/render-loop-cadence/final-captures/A1-after.png new file mode 100644 index 0000000000000000000000000000000000000000..ecee70a6c5d9e9239a6b403120c03fa86a691926 GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/A1-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/A1-after.snapshot.txt new file mode 100644 index 00000000..c35ee98a --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/A1-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=104984000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11173 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571601266913000 gpu_input_latency_ns=14727000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=24 canvas_frame_encoder_commands=163 canvas_frame_encoder_cache_actions=112 canvas_frame_encoder_pipeline_binds=24 canvas_frame_encoder_draws=24 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=24 canvas_frame_uploads=0 canvas_frame_retains=24 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=51 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=55 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=112 canvas_frame_gpu_packet_cached_resources=24 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=560 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,14 284x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,14 284x15) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,14 82.75566x15) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,17 54.26367x12) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,41 284x55) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#5743744725605747535 role=group name="" bounds=(18,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#4424186537103983558 role=group name="" bounds=(20,41 36.571426x55) focused=false enabled=true parent=#5743744725605747535 + widget @w1/widget-canvas#5036925338709116941 role=text name="M" bounds=(20,41 36.571426x55) focused=false enabled=true parent=#4424186537103983558 + widget @w1/widget-canvas#7445899412393006508 role=text name="0" bounds=(20,41 36.571426x55) focused=false enabled=true parent=#4424186537103983558 + widget @w1/widget-canvas#12392041750931625881 role=group name="" bounds=(58.571426,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9042723113057631623 role=group name="" bounds=(60.571426,41 36.571426x55) focused=false enabled=true parent=#12392041750931625881 + widget @w1/widget-canvas#13495370015047273503 role=text name="T" bounds=(60.571426,41 36.571426x55) focused=false enabled=true parent=#9042723113057631623 + widget @w1/widget-canvas#11248424745687431576 role=text name="0" bounds=(60.571426,41 36.571426x55) focused=false enabled=true parent=#9042723113057631623 + widget @w1/widget-canvas#2798845554877152242 role=group name="" bounds=(99.14285,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(101.14285,41 36.571426x55) focused=false enabled=true parent=#2798845554877152242 + widget @w1/widget-canvas#7285692155281014087 role=text name="W" bounds=(101.14285,41 36.571426x55) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(101.14285,41 36.571426x55) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#10547606456136237439 role=group name="" bounds=(139.71428,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3755191306193106791 role=group name="" bounds=(141.71428,41 36.571426x55) focused=false enabled=true parent=#10547606456136237439 + widget @w1/widget-canvas#1591004126705514636 role=text name="T" bounds=(141.71428,41 36.571426x55) focused=false enabled=true parent=#3755191306193106791 + widget @w1/widget-canvas#423660634609421494 role=text name="0" bounds=(141.71428,41 36.571426x55) focused=false enabled=true parent=#3755191306193106791 + widget @w1/widget-canvas#15015154310066103275 role=group name="" bounds=(180.2857,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#16896545707069005182 role=group name="" bounds=(182.2857,41 36.571426x55) focused=false enabled=true parent=#15015154310066103275 + widget @w1/widget-canvas#13786191748898983725 role=text name="F" bounds=(182.2857,41 36.571426x55) focused=false enabled=true parent=#16896545707069005182 + widget @w1/widget-canvas#13826355370529843847 role=text name="3" bounds=(182.2857,41 36.571426x55) focused=false enabled=true parent=#16896545707069005182 + widget @w1/widget-canvas#134348505103821528 role=group name="" bounds=(220.85713,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2340136145418704815 role=group name="" bounds=(222.85713,41 36.571426x55) focused=false enabled=true parent=#134348505103821528 + widget @w1/widget-canvas#6733426896005681708 role=text name="S" bounds=(222.85713,41 36.571426x55) focused=false enabled=true parent=#2340136145418704815 + widget @w1/widget-canvas#15729049687520163901 role=text name="0" bounds=(222.85713,41 36.571426x55) focused=false enabled=true parent=#2340136145418704815 + widget @w1/widget-canvas#17833843196129393581 role=group name="" bounds=(261.42856,41 40.571426x55) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(263.42856,41 36.571426x55) focused=false enabled=true parent=#17833843196129393581 + widget @w1/widget-canvas#9181518193224604988 role=text name="S" bounds=(263.42856,41 36.571426x55) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="0" bounds=(263.42856,41 36.571426x55) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#11042477908510433656 role=group name="" bounds=(18,108 284x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,108 284x12) focused=false enabled=true parent=#11042477908510433656 + widget @w1/widget-canvas#10422795391015277995 role=text name="THIS WEEK" bounds=(18,109 68.75879x11) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#3469744615432886383 role=text name="3 / 20" bounds=(268.42578,108 33.57422x12) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#2395557358945257688 role=group name="" bounds=(18,128 284x8) focused=false enabled=true parent=#11042477908510433656 + widget @w1/widget-canvas#3105235776718550580 role=group name="" bounds=(18,148 284x38) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#6570805353255671499 role=button name="Log session" bounds=(18,148 162x38) focused=true enabled=true parent=#3105235776718550580 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#5371891027109061295 role=group name="" bounds=(18,148 162x38) focused=false enabled=true parent=#6570805353255671499 + widget @w1/widget-canvas#7862890408880023745 role=text name="Log session" bounds=(18,158.25 162x17.5) focused=false enabled=true parent=#5371891027109061295 + widget @w1/widget-canvas#13635469530840347363 role=button name="Reset week" bounds=(190,148 112x38) focused=false enabled=true parent=#3105235776718550580 actions=[focus,press] + widget @w1/widget-canvas#14526227502695209855 role=group name="" bounds=(190,148 112x38) focused=false enabled=true parent=#13635469530840347363 + widget @w1/widget-canvas#2713457422206060559 role=text name="Reset week" bounds=(190,158.25 112x17.5) focused=false enabled=true parent=#14526227502695209855 diff --git a/experiments/render-loop-cadence/final-captures/A1-initial.png b/experiments/render-loop-cadence/final-captures/A1-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..5d51ae236db2675609490bf60e6cc4750f02e69f GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/A2-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/A2-after.snapshot.txt new file mode 100644 index 00000000..d4ff8eb6 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/A2-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=109320000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=12276 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571607566292000 gpu_input_latency_ns=15427000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=161 canvas_frame_encoder_cache_actions=112 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=51 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=56 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=112 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=556 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,14 288x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,14 288x18) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,14 72.9911x18) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(245.97607,14 58.023926x18) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,42 288x60) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,42 36x60) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54 36x12.000001) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,70 36x20) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(58,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(58,42 36x60) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(58,54 36x12.000001) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(58,70 36x20) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,42 36x60) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(100,54 36x12.000001) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(100,70 36x20) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,42 36x60) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(142,54 36x12.000001) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(142,70 36x20) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184,42 36x60) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(184,54 36x12.000001) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(184,70 36x20) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226,42 36x60) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(226,54 36x12.000001) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(226,70 36x20) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268,42 36x60) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(268,54 36x12.000001) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(268,70 36x20) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,112 288x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,112 288x14) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions this week" bounds=(16,112 99.23096x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(272.37997,112 31.62003x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,132 288x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,150 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,150 186x36) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,150 186x36) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,159.25 186x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(210,150 94x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(210,150 94x36) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(210,159.25 94x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/A2-initial.png b/experiments/render-loop-cadence/final-captures/A2-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..0829cbab22efe4811b8211380698ab6650ca89a1 GIT binary patch literal 256283 zcmeI52b2|6*6;gU@2$7qoA4QsoEkdPIp;|31{#{2bIy{JWJL!D6?4uJK|oLpIF6V` zN1gOJQAZu6`-aXL!Ta{Vx=(Ys+`6G|-OznEYaQy;iMw{~^Q(Q%sjhq5xRMdS{8_J` z1qB8DvS{Sc@j*fVRY38N|L^~y{~!F{8ApQtSNV5ELklNv`L7_0h0^r+mzV*0U<()n)_^&BuuF3rNhuj! zNs#ra={fJDre_)B6H<(WqT>x=5z&SLAra;M2ZWXP3l8PLI$#@M8*s}8z!ES8Yyo4y z8ZZa!0fWFI%^-8NVseV&?cJH4kzydZ1GWLS0bkkxSOg}4O<DlkZk?T2NU<5;t!Ou3pHsE(Q05*Y9U=^6<4BH%*Nlwk24YEcIiZl3<^4vFj8EgY= z1J2k0SOsQ*T@C?fuK+c$o_1S|Az_0Eej!AB4y*&V0k#4Ew*fE<>;l8=F-|oP6_ZlZ zY08VWKL5X9mXYrf+W^~uYy)5y80InriJY@(N5wb*8y)>fsT^1bYy)fq9nc2AFt7|v zQ}y=bjHF~`!^1EzbdaGBT`&jM0owrEKu5L#u#7fF3}BngI-7BN)B2t8$XJFS!=E31 zYy+Lf2Ea71%_j6jVsc96j@bBQV@IYv%g){k+W^~uEgJyaz&OFXD~^fD>B02pC5B*{ zGux`nX>3$%18f5w*#^KiFb=G{0)9B5osv87cXoaH4I}_^U>&dxunlxR8vx_Lx+?&f zkd)RHWW>h{_@;Nho6h%??%s(4#A|9%ylubiH1IXsSpR&0owrEKqs~V zunx>?2Vin));riL?oAiXfpx$(z&6mCZ2+tT^ArG*D;P{PGznoxFmRgWm-e==u-3KDKjhNFlow+3a#yR#Co*2T3#}4qPZi=&N6GaeSg*+ zjct4sz-S%RWR6cvGtm2Tm<2k;0s@F($gm<)Y*wE zJg_f_J{xmKcw`JUHh?Z#TloBoKVJCrU%veDz4t$CX%FWWE7nwrux!QZDmA&0H*CZxlUlxGfGC&oM0~=;sY<`ZEw}mt^T56!dNJ_Sz);XsyAc3@3l}d_RjfO0ca*ve zK<)O^QSNa^lM?{U%^OV1Tl(Ich(WRCdkKE@VsSf!0K`R$mwS`}8CiM8n|AH3*|~dP zjk^E@^T0m5|M!Rf!J%cn`;d|}1_gkN2!JZ}*R0)8{l`E3<;RA`X3KBhJ=an=c!Wum zrCsN;#~y#G;hS&&bMd?X{BY^%XP$3}iKQtywKZ$@{K_x>@TUu+ERHp`^%nYZ6eHq; zhm176dg}G2s_NRGKKb;yCHbMcZD%D7pw zbY&IBlq22J-_#m*?%G#FKZDWEjDa*I9alQZ+&?%>NsEe3FrdA?`wrCJxNcK*LE*6W zb}_C|7TzPg$Q3KsRwX8-D`Q@*@9>D|@@?C9)#T+5HErFtvj#G#m31Z^%me!ffLY&Q zj@*lsq&0j750C(8t3K8O%MGSW>o;tvrtkI}A9(PQ`metJ_TnH?5Xv9E`~G?Wbn?`h z6`9%j#@Elh)qLLr57#4aCMoK30-)S307!q>Y((10S6^#-@ZrbmL&BoU=gwbTX);&- zl$zF>C)auAxfdJnr+$%!wF8thnks(6r?ipwz(bGL6U-XvE%&l7{_y7uj}nlveu6e3 z`((NXl)Lx72kSrm{pS~8Bn5+qn?C*Qiwk$(`+(B!xHbTyTvkqj5kSQ?XF4IW~>{^`TYoj z8#ZpO9#7L%+HozjfPhyw{qtX6UtG0jT{|e!GxLmiav{$V0N;7{y%qsBlpk4CVy5f4>V^YkfBN&6KcdX^ znR6>Y{@te+KK=a{7p6>WRp?*-=dVA`owukGo+)GlP*D~E9^b={Jl=r#zrOnB;>5|* zm79R`c?*_Q{`GJFP}&s$j89B8{QV#Qy0~}$t+k>JJ~9A(VFLglrmAvSPTm$|0RS-; zWVxILAnE{eg+oS|<}X}YiS{v`Vf)A<&&s%o;EJ&>+Q;}BJ8qI0=NQ-U{zM*Nw0+0! zn(SQLupUd^;;J?4tFZxsI(h&Q?SOqjH09F;fNCD#d*?oE*+v&9E*8f(Xo|V-=38s& ztF7gLW@c9YRnS5?M*u7yJ}X92M^W# z`q1Gzc$#S$xklun3=BYqxQPGuz4u!HMR6`4>l>OZs0#po^X>PS@Gz*Tto~{CoCQ}H zm$giM&QSEU4LI@u0Tx*XR{$v23#Q-Vz#9;lq5@JwhZmb<=!!TT2Gqm2hSw*zv52PO zqv&lCISp~l_5jDoL2>O)iCzE%`#cUnOf8>%{-t&g5Eu3Bci&%H&^BfMH?93a@#4ba z0q)$rUjZhj&tHB0%|($Hmyl`zaG(@Cfsl_WZ8W{vjVIAR{`vLA_2hbs^78Q%0dm8p zZPi%U8&NdI3}yd`cCI&X-BE*eM3jX~ZZuUYFqG?xIOLu-efAYMPUHcA03)WvxWWJV zzU-24`9&E%GW5J@1D*n4KCS0%p=qe_$iy{aCpaso5Wm-JM84Y68pek_=20KzvA!qT z5=VHd0-)AMOy5O0Eyp$hW|9XOOs=K&aCr^z>Ne)l^z%QoVK8&nyh{AIF)pI4+;|B) zNa*v4C!cBf@T1?gVBHK`(^%KLUs(eTruDiAWxZ}>@fdnC1eYDU<8U1yLx0Oh9%FFX zxeq>Sx$pjmXbrBl-w!|jqy;xYoXf|x>o!*Zp4RNJ*@ATJjD1JzbVyr!<3^Hqq-fBv|7?Rq628#Hg9eYd$4z@cR?z5Gh!(PJkFp220~#!n(xf2*{O zb4>l;I{TYuSq6?@Z6B-?&*=nqo0C_lj1_A=Pn$8jVr=O|Wn788#YG-7OHhd7u%MUOQ-%+Tl)^<_wdqk%Pkl$|+y zUL|&NQHTCUxvXf^So4mZdulM|ge>-sc(*~p@&Q9kkwqQ=IEU5@w{G8AgZdjcZ>!EG2T0^QI_e5QdKbpf zvv+WrHv;`!UAbC6STMypo2`88)*{%-LmGCH)bg~Z+iTOFtXliydfu@?*0XbZ#`G1- zRF3q8afvrN)XLc!w=-xqIBHC(8FlcDKDD}@P6zw&BDAXTo)&=Hcg`4DPpl_z+W`LD zY}oKoCQtM$1JD!gJKH7$&`X}Lvp0mxG3eL^yk`RpKn9>!mOgk;dv8#)uASF)8vrwC z3f!Lt0teOs+W^}@;Mf5DUNF`G8Gvl`fn)T1ulZgJ8@LR>UZfNbtOK?Iwt)b$0R@2g ztV|EOXb!9cwgI+*K(Ya_4jf?2pk(oN=c_RK>DgekDheV99Rcz18f5UWCLIyeiqZv zoi3UK>ws;5Z6J_r0POQ90P$xz^x@KSd@(sJJh~j;`@>gOTnjNuU9^F=(5BuuiRILH z;CB>##)X6$XQm}o?ii9$bH}Khx(CPR*FQAQwSYRPi#E^}+GP9m@9{3~kH-Lr0f2Ak zxduAt!HBl?03plSs`Eh8Cm?lWerna-V{+>@6r@(qNR6*7j*B)IMn#$mTnwm#x@ZG! zp-r@{2MF0d^|em{K5_I20O>Q?8a+Md0oV%Gm~!+bF2>a(%W19ez|d!DVr&Jxwv{=_ zRa$`O2#{zKZKDtL<*HqZ@@${_+NaQ~d~5??8m$5LrD>)6fxgDv20u)7y%W%i4EI>vLvWeC6%M*>w|=Vk!!vBFNkGTtFY_3w^SEs@t2ZoX}#QYWh!1PQx0YJ^-X| z|9cI3)=ER)Y8Ppp&T=|7#?GkE(!^FE6~{%HJqbR!ZS(~QqHk+ER6A$;)Ym@M^o(=` zfcWLIZaw;zxfAflc^Lh2dsqZ*SokDFmqP|e*T8Z*dw)8YK4S-l7#|p$S3jOWls_oK zB>&wyo>P-4vo0n3x zA}6WJo8XiCLf?>q?bCVt)5AU;>01{7wt7|iU6`W_x0i3v3uHN6zek-xpYXiy9-UiP z;APKG1|a%|4EDT0woiTS(-HiTuL}UNTV)SQ-pqq6Y8TFOx^7^dL7#X%Wqp2XwG1R* z#32J@Vf%F54%HZ9&py@kET`)NzyTqV{sO=tizO(i90JK#DaZXtSe8@g#bSH+efyB~ zn(3)=mA)XK+$Us!EV50?akfv_>1gl1%eqyIw^1;ac0&5lE`qiYO1}c$x(kAx5Z?yK zqIMlDr|b8oGw2h4s!gR4wh5P{ptAne4r$+z95pee|;Pv17uS)ou_E1bqhr15jUmb`<+m8((rd1JFnCV-HZ~)2B1(@rfx|17raD!uZr~kS}Dh*JnqU zlL4qNSnSz~FY?sv)0uPyfN=>ah8w!|F4G!9!lKIkDX3kCKgkGLSWbQIMopi1^&~eU z+~f}dvZ%?ahkZuJCK=K)a*cYl)zRftlV45;`+|H4zH8<&u3ShIFRH3DQ4aim+9b@p7AO^!QT-@4q=<*Tc5@`jj@j^F${aO>^0 z`069hbMuFokZ)bbnR8h-IqpndwKCq+r@H`rVbb8nZ&#IG{Nv&=7Z5(4U)-VLtIp0H>=p>+do9P+?y0ls-jY+6SuO5!0Pfy%bM3~>+p1;d z;pQP-PID!$cCoIsVXy4g?YnC1&n z%FGJnJ1d)9PH#Eowh{NVKJ@_Lo}n4FTA?S`^CSRw+_a}=P;`Rwz=IdKnjY5Hx_0H< zQ}^9la;nKMr~4d$F#c6*)>o%z<|$7r+&G-OGbrQ>l;f`4e0ycxkxgz_mQ9Y!Wn77; zq-H6)L!AYSmQ?|U^A|3y#QAE{De_%uPn4Bqlj9=a-J_@V87Kg}aowis((zL&V&alD z&r0NbDc@^3E|<{~_m-Tp%xZDJ0ANw^So6%;^Ob=*W7fP%oVzn9)Gk)b&9YU;9ogje zJR#@S?K^Am`Han5cPQQfrbIY*M`lmRDeJ)<+2nTA$L*V_BfMu;%XdYCo?;rJp9(Nn4Xbi+^}hD zHFjl1nyW`o+;?xvsV2Xit^hDLKE=?bYp*h`0YBQSHEi9svj%l(s#Z07?!rnOaW2xe zw5xU>}qP-XQDRm3T*&Q%!z39qbG8 z2LNK1@|If<*5Zhp%S zyV{m0FUuy!MZUX7PwO)f0El~#l~Z8cxqDyj+8Z}k1BPQuCo2y@t@lU1*K%BId!nAV z08#J9M`LT zz1opwb2ZKYWB@vR0H_(2UIwgJJ8E(=0JS~j)%2;?{nD!)H94J0Zv$X5ZG!ZqO%QEi zU}z)_BL4|$*WphxLKc=&Uz<_W=L03VvSwoh&Lpr%h}(qrS3X%mEA zoa}M~!B1ltNIyj6PeJWE{7FX0!gA_sH){G+02og2^MjxOP-UF4eQL7@wfpW&I@lM4 zH^;B1o1!(~mzn%2s9lFY$p~3kPJQi0O`rFZ*Og81^M?Rg)Z}FQ)MgKA`gA58?DGo% z77iX^TDN|4HU5x0o&Fro9b-_taCh1iby?2K4@#jEcaGlBryc-YI(16*BZm(++_G(3 zT}gIkg;tn)8i3x=r#tss)b)m(Y8;T$eGWkUnbuQJKi6>XgO6ICd;X=y<0novA--$( z{#v0dSC8@q%5hiQk;}83m%%4=D(lD9xHt9b4gg0aCz-$g>g$UQjm?(NKl${>AHM(L z65@C4->=E5^b`QSsZUq$wOn3R&OQ2%cVVaYjy?w<)#?Sfrt!@4ZXsV@M%sZVzR_|BO(TK@LsUoVc$$!_=h4j(vBUsGFWSv+}C zm8+hhrvT_peOiwVSI)gDry2+3be{qcUw(nNH+TNxt3Y?#!9#T?PM&UZMY*D^e1URY zbZ*RrS8P(RH`{aWUFMRUBM;ENq9i4jufZo=p zxR0(Ly)CCa_SNET08FAykRG%NqAd&viJ(mo*8@J+^xJbEw9p?&8?5V(EuC0#?){Hi zV&W37%CjzOeXe#L*5#Z%XE|-#g|qszF6V81-d~bK)722#1aU3gNz>f#zWwf!t$Mfa z*j{Han0~UAXDI`)0ykK^eEFBf(J&FYYEu&c$KEVw(8Q~ zvYG(Ek@RUSTlx0V)ULx`9ea5!r)}G?r!#wb-qz>+V+ep@1V0zU@fTif`s{a~T(DK| z#`*IU?{Hi$O^sb>7qYN@Ud;(A)ad3c&Zyo^AQ~-1{~GxMIe11%L}DjIZ)F0KKhGXU2@J zGTxR`9{Xx>p8^oSQ31%sC#D&!6$bDjFRx&j$vV%`x!T1#s;8FEa_S2}Z|hSl0H1y2 z(MGeW;-_5tIZbQG-TSLw)z>#PS%xRZo2~QgoqNIq^tL|L#)+eJZ_BC10Xf~L030=@ z)C|Z?nL4Y&T6w$o-dy|cZ{Kghcg?Kx9G%M-D90VuQ_E*L^#$N%ea`gCeb)-W{aZHI zVH0HDxRR^9ym#MvyXD_s{rjRl*xAbS1OUCQPqlI4DBas~%41(G?o$9p#UvWuc7^sb8XtM|i3T~{*|^%pI$Phm9LuRM0KKhGtpJ=ld}w7&O`YYQ+itsJ z4RJ_ZjM-3b{OQC?N1ALw&R&`)0O)OfT8|HB&%G_D8VBU`HUK8lCP;VM1ko0P2ZocE zrY%gEG*#K{UB7Wlb$-E6Q}O7r=EL{gUw`J!x0_SbvyEEXRl5!?ZHYQ8=he0$bfe|y zO?_$wAV79#?_PT6uikR|?%j2>Mip1CqE}Mue1@N7p+Hc=@Zb&3Jo!74UgS(Ps2A~f1~^b2&TmEoqeZe z)~HccTH1pwY@gm4?`nFM)4@Ig!1I)$DbN5Y(<5YLvpKd z7kl=pre`@lIwrvo6h;4CLjcqodi5FL7x06UAdA{{u$-O8yApL2{c{M_NI~}s9T`bG#x`A~DeTMhxYq+y0i{1tF zod<}%Ap>M#`*ht7)i`3$KGpOrr|SYhG}yCuu+P0f$RJ;wtvJi+yzzA=eXh((s9KU9 z?=vqDeM1IYHYumEed=qUvTkj~bps$s+|P#_A?Vwgrvc09oPl*VeZup?4(#Zd2(!1R z!sruy+w=a!;AH#M*FJ?_)sAfdj3>9eD@`5U3thYSCNB^>!rl+)+gbTpPRIABGwO3x zbh!D};pw$QB127?Ap>Yb#Pb1tp-=S9_UYK}oMneA_GwS=Q8Dp`ph3~`hX1~{>v=sw zx9)w)ur=+?fIeN7o#j-&N1a)plM)718~~7F!p#{3Ku-qrfxgfu+o!s{xylMH_Nk_S zuuoS2qN5wS^)Bn{1qh-K^rd!jj?!7qD~&Qx^jRDgZoYR^cHQFixT?%h{UL}p(Kh-( zUykfhEuZaEU;DJBXO9379pR1a9=-Z|%o9Z0=)=}Uxst|mwi;QW=`*}{AH#~wgsMAe zXLfaVLe<3hK^22BHP!$`)InXefws^l+D0F)*rKhnY@hntr?rkf20+mfZXjG%>~8hx z7oy2CglB@fXajBO0X`w0II^7jEP-@1eF9RLqHfMhu0A*-qYhr%eWP6qsDrv_18wO6 zKA}f(Wc$?DK80RA4nWZnA6>qIK^99;klQXUE8bwHtWB@V%*#-jE1{i>B`~hqH>=~(hMuDOm1|S2F0mwEGur{CoFg!BG@bh0@f1U&D zfNg+nz*{zuk(FokR$prUfPF!F01$0VpE0L$>GIW8MWe===}V^NYMp9H?@C`oEgn72 ztfj6ib@~qoE62}Bp$>hCwY+ff2$QY)gNKeZ^$XVb8g2DsFRgUKlnQ(KoX0TpmJQ&u z;hZ? z&b&pHa{iKKE31wjKiPEjl@m>im#nCg^R&iw0U*BHwQR+js<4O{<$c10q;%t~+4HXu zUaNqj9{LC#7@;dvMceXm>h#%_z55PS`WX-sSw4Q^RGW|i{OETK%jCM=jxSlZN*5#W zw%pub=L7TI_dHO)YtQ~#I1Q5~Pp>%j+L>ldFV*h##!cI5tRLXpZ`xh6b=%Gwz!cx< zd-JV#niG@L6)$o6%(<0MKK)!nN@|udEhESH^s_HCVyvpQ?`*m*0PNPIZ`mRuGXA_o zbexu+V}#d+^WcHuX3z!W z36PQ5>L%aNtyfu5@z{0`5Q>;RXMs{CJu|o6l^!-?lsP#y(>QzX!b&Juc%lF(JX7>l zGHzmfx{w#g?A$`rvK6bVpzOjSBTSHQ(v%q$qf5q{=Pg)LRWNvX`%?{`A#OJ6B_?MW zXOS!jfWO=(;z+|24{_)S20}l+tJKAD=hDAh|zx&?%E%Nx^xocnT+8Z}ktI7ECu@g=BuZVY0zh;OH~|uQ1w&2U zd-iL;Fia;GE?!1hG*;E91Y@l*f=5l1R$@!p=a5GMN6x2ZGiOL`HL!h^%>B9{g4CYaIJ_#c6iIs z6V7wDsHT4|$+?puiaV4+t;Eg8)y(Zaw;x!Ltqxk5b?%0GLRC1+*ap z+T_4G@TLunEGjWS_|T(QOlM2SPp-J@@V!^037O#3{QA)0I&p662q)pS*WYZ$cmqSu zz5h{*3`{s(=idLY1>@3IeP`2j10XuYAkE4yFv0r*cmOs4Zo$H(%7Dk9A3bKg85f80 z#iPcVagM38EHFS*Kpqwbzetw>2u}>)5P4Wk70?5~;Bg`kzn~0IB91=bF(xFX837ql z*ZOD;z$sH_w!7I__XDI+M*#4b*K|1#uPr;Lu-zlHZWDS~Kv2J~OZPH(mYJj@te2wP zG&21(J9gEK8dKUnn-l3cVwvl~haYQr?1`rvFcU-?!1vp8AGC(9g#sKeeK0z`j zE=jpyc!BYWsRlp+>6j+U031s0ue^hVDX;MEWPm|Q@JfYTkQ3e(yr?lHt**7m6Gyqe zn4*h3EbOMHXI}w8S z@s!KUA8Nw2$?0N^5&%Sd6DCco5L0Z?A0HWh-m(FVTddc~{b7x7)0Q1IavI_o+t}d1 z*tE{W_;~B>-!x;!Xq|WB0$ zin#Sr?Ebo&F4tFUQ!XRNT`e!ybrjd5ZF_Cl%X1_f=Q9YsVFTjL2wQytSjUdP+9a># z*(zr*4YM74Yxwr++RD=%fVMi}G#-3x18f5Tm#x>td}$jDK$?E~@&<6z}Fb1q~XE#}Rpt=AMf-v~l*gawF+$P(Vnhk(C?m|!(0D{J9LUKAAFxvpz zfTwH#>=E9amZL5JWbcm++*1b5?XqpzvjMP23;0AG1|Y9j@_H@XK!>#fzW^Xlf%z$I z?#2cvT%quM9v2AOnzXAYg5P0m#N5u*Tn!JQbGJGu|o#kO9a5WE%)r8(;vk z@dvE&vsdLAuc{;Il>x{AWB{@a1gs4(0NMBh*7!S;r^2#&##{9`0N15P8qZEEto?RH zNpr)-Ntb@wI?ZC)#({O#O>O>Pg$=%1IqdZhj!Snujuio zY|gX+9YI&nnI1oYu6AEN20$3omy3%Vd7%4#pz}R&{vN<)^#maXZ_nQS`Gdi3esT;t z^aKb!0>ESAbE?_XbAHe6bwWR4vL3(u7_`!(l zkb{l&=ATav*tDwyi`_rZfKP^`Uhbf70Hnne6VHA9a}YCJwci)mG;G^h2x75H9;h7m z91QhX7}O1bUoI+c;(?}ppt0`!S9h>&X938&9-af9^}__ZcJ{ugmD2@)H>O0IcmVtF z0Oot+{=I>Xs|_NN&fcH*;3r_{t{12a0BNzfo(GxxgN$|PzdD4C3(%<@dE>+T0Caal z#BBin>=)OSeY2vZg$J+y4qm=D?%x~OIBZ=Fen`jLyTUW!qjz8ko!h%7j`DN>;I-v= zrJe_w`-6;i=)XFIjsNTy*V_FhZvHb5??6v}xIpKQAZIV%eE|OaS_AL?`tQJHsOocX zVB-!CZc)Gt_nG_S}~vtd%FzD9Q+Fl_)-U2~ELrL*yZ!NW}>i%ZNR z3@~LMV?!EuP`p2Jmy5Z!juQlzz<+j?0L9qt40k2p3ij`}tW8#uL-jABR zLx&fepL^j*qguYR>GlBUD31Zi0A%PnVFLiWrvNx%($oqu*b|e}jSoKjSi{`;iz-E$ zr;aC1o^Hy_&NF(deMjvw0G%{EUwajfJiw++Q!EQoVl4f-cDID~=xMnzJHaAv41K$5 zoMlW@n1!B3mW%=YE%%PfvJ43yXcIhWYk5YTWnlN7mY6<$EV~O+t|<5U!cj_Hw3QPQ zZ28UX;qCb?o2OV-X2vNpMECA(xv3!e3OVi=nPExn*VodQYcZ^y&|WvZXD`cV z3olRe&(0if$qOBz$XpmU(DK3Dk?mzaBu^1(zZ#xy=|gR04GgxNo;IXC-`DrcQ~i4b zfPluL#mlSiz3;(#0g&l4=TtuN)H4llym_|y@ZI;-r=(@ILul$|*42bMFK7Z@zW58Q$giiI+k9>Z#Y8kdE;B8*ep>zHr1e{N_pQ*Dhp`eap&E2uf6_e^V82f-zdWyZQZnUPYv2T z_R7ho-Fx=e4h)S{ruo(Y%qtjT0+c6Cp4R?A5dGOZI`Z=D<+BIq1cV&{a9(n>rD#y7 zBs7!jes3+ClKaK)kedswJs^U(2e@c+2@U<1H^wDzropY}5ewNJ)-mL}ZBN z2P*rwr6rd5zI`o6CKf7f8P<-s1b6RYxu-bGVy1P;$HwMbdUok%`Om6SCI88Bc}lzA zuP(LxeOZYmxqm;)bK~=syuU6Tqk!)(OGYbl%uI~3tjUU3@*t-Sz`s#lw2OXzptcSX zID6gD&GOC4aY}gru-o-rEjJHMvovm+Y&k;L1n|qy_Y{PD*{(MLh^a5&w|?W68Vvg3 zBS)K$pEyNOm|hVZpKRE&?WUTio_?+Y5W)2I#H**9uznaFn`qd+V|UFRcip2v3hQex zy!dkC>b2{uW2xM<8M7--o_eh*JGamzU}Db$+(n?;ymf~nLs&#qIi}_aq2W;qyf$yy zUbB1e&9wmBV~;=8u;ZrPH3>;+#&M;SDj;vssIdw>H*DHk^T?x5G~`gfSvmQphaY{s zVdJK4O1m-uQ`57JfaL7C3taYm?E%hF9s|%#0AAQK#d7_%H&{NLciBS%up)c)R$%cZ zf#;fQx>%~$U*2HYl$)puz+aEZu#AihwN$O2sMH5^{%6S;C4OXLf#P||5Ex9J^D_S9j_GOu60K!v5J90mn1N&PZ8k3`> z0f5~JfPf#$0P?+W=&n2fm1iY==cPhXD zxBy6i2p~&N%`~1meWtl^$Z!Q}7|ehn;5epaycyn@ys2`CytJjuR#iCzz_A3fCkeDD zJ8Dd+`5~H?Km5q!4WmYnQ@{q9OUF;H$jZ()y>k53CiE@Z-9aATw(YwVnV+XMz9N!I zZvprU>3 z;;tr76H{?`n1=|akU{i)>##HnrpDONK^@2`@?-!mPK&kd$Zz#vMgCgy7T3|#9_IjH zEKScv9**!-- z=geDJNgiP%0D`GzZvGGjhKrZ3s1jx6`|0f;p_01#_)VxYe|b%-UTM^EJ(uh9I0fF-;*lo=lzp$b5>Q%+OepQs$B(_^B; zESO@W-m^5F#k!y9$NKmMO~EnEMmp-2#za_VBo0!}zgjU?nHD1tQ}u26Ny@Yr{UA*S z;BCXwEu(48Qf?n>eptIi8UxVwuk^SwXhm5Jet8oF=}VWds)84YIJ_wYQC>a*M0o{6 z72sjL5A{yHcBUEAUwB&2z3`IV9aeh)L_fbec&JVR>@&|b77QL{Dx_C-F#SfFkPpDc z)EXd>WfSq2UOv_+uO*6f905Rp5mVyP$syez|xp-%k+dn%DUaZY05gBJhxS}86n!iW(3ymw&W$z`d+9du5TYz03M)qwPIRN z6jSE?5XoD}N&*;0dZTbw5K`zK~Zq7(ce|pvBYXTw8 ze=~aoP1Ad|d#*A70b#81VZ9P%0p6~3j&($wGXOmcz)4ePRA8+PgT7?!gozUHC?c1X%(i#>6y7kY+At6 z6fnUQ8Pi*FZhgcC3)b(bzor2pmp4a{Hgono#Y08g0PT(IHdSMKj_K?(&%V%zx@d3b zu6?z4(Z&s?>nOYb=38qI+_B5^8p}eg=F^!#* z9A)W2n-J&|JF)+uX|^c)){J4aJKS5zi=yc)Hcdnxrn_?qme{~R-CXh(zieASM46og zVr;-5FPQ8dQ<;!BsofaxrDP~j~- z{^TC!T6RKag`1ZIFoaG?gyDnRch&pu970zTJE~ z?IZ)<$QNsXqAXwpDC3$$nlneTQO&>a$^fLnE&$^0v4H^eqqG)?_Ao_GqE}DE27>Sq zUzkwfu-{rcf0g8^q1F*Bd{$LFSSI_@UJF%G7!kdEEwmv7p(n7n(uC~MFFT=>&x`2)Q8i4M=sWaF0 zIRN={SiT#W-UdOS_6Hkx1VH{AmiIq~px5WHw0=`d`4|F!5S0Pg*}(`KcLYHGAgcEP zsKW;jNJ6HZS?wrc)A$d2L0od6f2%Cm&w*t`qk0Jqp>;-xcfbMvIxL05v*cTKQ9zDHpf9*dm zf~f%vyq~;LlEm!yfNZF2%$rF z*Zk!B0@i_f?Enl3i@Jffgv;IQmO^=CuQ`%?mu(t9P*Gr(N3( zFT?8sFdz=BgN|wgZLhqzI~Fv(TPuT;<5vUBU7dh&%I@zK^rI6j2!f1SUy7Cm!=kY~ zCGMyLf#nV?h{I-G-SCj@p5yuhOHZA)z5IN6^TQf~M8+-dyb@zAtO7#v2-{$Y*JU`c z4*bdnTA@ca>f%nXwXO5Hf5Q*=M|t&y7-!ABE6%Ya+^t7nPr3hSmjmm-Uu=Mk;+;P` z%)2TJ6+us)4)Z_?-h0k8;60-L}nTkO&;jmX-MIys2W@JGe&d_~3+%HTG6kg*K} zh7Eu{U{D+Q4uVa(fzDAw_+w&hlC-&-<#0Xml~o7@S5)f{EwS+ihVk-!=KJid4S*$J z3fKb1fHed=WvUAXUG-rDNAS`+U-1fQvqbR>={x&Ga(}HaGP0_D-+($9sAA{izg8EE-la^w{9Jd;dS-mGe9R literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/A2-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/A2-initial.snapshot.txt new file mode 100644 index 00000000..f8b71f4a --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/A2-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=61863000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=12082 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=150 canvas_frame_encoder_cache_actions=101 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=51 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=51 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=101 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=533 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,14 288x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,14 288x18) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,14 72.9911x18) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(245.97607,14 58.023926x18) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,42 288x60) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,42 36x60) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54 36x12.000001) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,70 36x20) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(58,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(58,42 36x60) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(58,54 36x12.000001) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(58,70 36x20) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,42 36x60) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(100,54 36x12.000001) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(100,70 36x20) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,42 36x60) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(142,54 36x12.000001) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(142,70 36x20) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184,42 36x60) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(184,54 36x12.000001) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(184,70 36x20) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226,42 36x60) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(226,54 36x12.000001) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(226,70 36x20) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268,42 36x60) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268,42 36x60) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(268,54 36x12.000001) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(268,70 36x20) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,112 288x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,112 288x14) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions this week" bounds=(16,112 99.23096x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(272.37997,112 31.62003x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,132 288x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,150 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,150 186x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,150 186x36) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,159.25 186x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(210,150 94x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(210,150 94x36) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(210,159.25 94x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/B1-after.png b/experiments/render-loop-cadence/final-captures/B1-after.png new file mode 100644 index 0000000000000000000000000000000000000000..f0f8eb76ba0dc0cf1b971bce05f12a5294aba73a GIT binary patch literal 256283 zcmeI52Xqz3{qL3Y-g)P}R5xsTl~6CJR|E(lBqY&$2h)4+z1d(JT(RR4J1*E@Fc=I5 zW87mWj^h?PPU0l~+cCOV^{NZ7uHNsv(umRJ?yY;9?vHbZ-JRK)o&C*sKKq-Q)!w^D z6z2Tu=be8Z5D@UI+@XU<1qA$T0PTPDfBz5t|JeUdJ{Iu5bl>L=9yn(G&jOm7C{Bxi zaS6#i;}cV-#V4j6N=!;SlbD?TSyD>+cNFv#iaD?iSOcs92Q>hOd*$fU=G*=27yHmgUsHHaq)_`cPJ@2T^|({rw{5IuJ7K1K*xb?z#3o;xKRUO z4;Ta%5eN@~P4@E4uJhv)Q?`&Rst=3kr|;3LudW;2EC;p$Yk)Q2NezHSU=r8_M%e{5 zTTUhyGa(@_ax={ z+U#Yp23P~OXaKANv%oH^fU|T06|jm{TZ;Pxg%bSw5b-&%4Oj!L0q@rUm<4u$VU`%D znud(A@kun~#ay5F-!Rva+lV#58jv*rc7b7bLy*WhjaF2OdtsrYI~kP&+kiE|8t_34 zfMH-6n5OFO$qBJ>%7TZ!cVMW#E8Q>$wgGE^HQ>t{0Ly4$L=U#ftTVe$Z(3jK8xqOz zWBBvKk2TP4GytZ7ZDye-BIDvyHb+Ls75g&nx$f+(um)HI<}?7dfpLO&ZMOa5l6umg zm*{)anAu!rj$=`=23P~WtO2kMj05Z1zz+wsQgRS~XVd*^#@|KMmZZ4BmteR%)x zvmQMIi@J2B#&as|Q}4_7z;$=LFL<-< zhUJea9Wiojn?MlIo2zqr#z6elgxNIH^V2g16;GNxy==n7sb&3QlWfXkT82HxS>#}( zr1meiCy(j5U>?{<08IT3WB$$rKSu)qIA`9X3P4;``s%wwe?M3eEHS2Uxc5-? zKfnF=PbH=0##hgrtEXS2(us5F%M!&G-ni6ISyf~F>g#W=tzNsK^?pnNxM1PZ3Vm^@ zF>7$HRWXV3dD}jK<8AE-0McJVwCY&YkA735D2ntS5*CelF@*>Cjg6q-h#SrodBk@1 zoCOs*xrMF3L%xlhwpI3|&(n)@&|lC``^7bvjd=R9b5RU=i}dwoU2fj+Qh<&A%+8_{ z791L>+puYCC0(=JSpcFAU|&GIivb9ue*5q5etPV;Pu0*bHx;j3z22bHmo$!_FjXNq zonKl;s&O8^kVfg)XTN5;W7GcJ9bwBW&j|Dvh;~6rJo~x9n~)-EwlAlw#(=-6U%1ZIbZ2Z8Uqk> z06nRKj)&$U@Is>Zjb#8%Z(Mw{;~iBahX*bo6+goG$M-1Moot zQ*+r<2q?`%;O678<0qB9aq&{aa08Gl`mbk%5dhj z*Xw7@np6JHyB}P^%GM7*7BvnTnoq;jo<;xj{eK%}n2UX^?k-rgv_c%q+e>e~quk?` zZ96OBU4HjJKl}vmFEt$vdZS%9j&0&@4Xod=xpKgu>=HN^BH**}kd z=Pz7R@!ubHjm`6bHyY>e{r6Ts{rl%?Up{`aZVk=b1qOxc;0dA(4AaFm-v8jED}b~( zmbY-hF{dXQLr%j!0Eqd>1ymPY?~fmUa+Ur7yY=2p&*$SC+lg)B8k+!s&2xZl%WnoC z=H;))+X_I8@aW?LZ65NAmMpITv{KUg7h`BEU@Nx0`UL9$KsZNu9YtJs&b);c*)9EE z#9_N+*-8WYtAHq&v5xL#Siy)JU@7ObwyyvXb8wxy^el2FzyrKlSWC?&s$HeO2zWK*B z3>h!eychr@S8y5u>!08L=O?5CXqfC2>6kx&$A;C|?|-=5c=v((ss#XX4uAJoQX%c}1lWX;?f-O&_2%BF@PikX`cm7k^dm z=f5;`e(>Q(YeZfE5bptsV*nmrCWIp5c<$b({A|IRXizkq2ytBua%C(f{>~%T6;~kxCr>*TU z>X}Ghmo>YZ^WH=rES89UYyrTv>o-+m-!x4=&z1Xb2cRo&hRfDg^lVSIr_cc24Wzdy zT1P-4-kB|i%F}1gu?kgZu3;^23ji?})`RHGfo;GVU=8?>2I%*KF$c&1WYPPN=((-A zt%U}z1F$n0g#+7wHNYD1BMm43#Q44=-82Wb0c(IY;7=L=`|v?j1|UBG_yNco@H-7K z09o{YCwhPKaQI#=d-M!I1|S2FHQ=`zXaQgn4S~Cp5je07SOcs9|It8fd=kw8(%_j)sfo;GVU=8?@2Eac2ET;Yrx@it<1J(d*z@Ib#_Avk%{`~M`4fv%77=SE%zZAYd zc{zNq>RvqqkO9a5WDWSO23i1^NOOSQ$Os(R2CM&^9S+dlqc&w}Xi(t8M0TL&js z&Pa+W9~Ko>Iv^~#Bs0{xfHF`P%0$_?2Cl{WY^yUznc%EG&9wvA7oa5o={GQ33O#ei z!!^y_oTWIfr@AQHvpwgh##Y=lG_`76Tx6NEz_XSg*TA)KO-oudm&W?kR-fi)t>DM5WzFk!rQY3Kaq}W;hOe9koBppKGoo-DF88?6rIOYTU&<1 zTuw&PjpPRE!82QsVN}9>Uh{o zD$DiMaFQ5pYEA8!lyk?}SCG$ii)*6}*6PXnw4H*sw7WHXw~T`mXeFd8ttdDa@C(FP zvhjw1x~Sa;*VFzsY7h1-hz={oSkx3s?mk8xP#4yx{W?@*izR)k*;$T{iA|uDkbVTf zI|zObhHhB>z|yZ51k^?CKDeItw^4hr=jzOO!;Hk3^2`ug>h)ki9Z(n6r~NuqV~Zty zs@YkN2m1n|>AwyHKSu-odbtkns5b=EMeRPgp7ys#Vl#aRBbW=U{bu|LadJ zfDdur20+o+%a*S;^ovbWAS2=&-KsT;qvcJWIKW)iYVMc4H;t7=ZQ<4>K~eO6DzCqS$if>UD zo-(5x!r!uOXI0;jNQXLvEEsv;-VSB%dG*bOqn*beDILm(it=7R1D24 zC>=j>O8E$yyBITWA^~tD&0#oJuG)P#TArM5+45C11jbX=vAW6mTv1PWemS}MrE}-Q zs}9s{-m<+ici8aK$y4D8I#y>_)Kk>O9rkP<0te9|h+_eBfGaZMXb9|BemP(B5ZHV_ z6E<;Vo0O7KjNhF=-r&$kdf;uTq|WV>PF>ON?yRR;{pENCfbhI-?a;Z%(a^0&pw5v1 zcQ`9Mw=^L!t#}1Jxx_GS^w^1IG?!K8NSVl^b{~$GC+AyA0Hjao6w7gr?z^I%@SeA9 z-B|_bpKiN>0priTae5i{n+I{}QrG{YzqgwmS z!o|xCnEw@ac4X`8^;E0B91r#dcp89coXuNz&#nq%{p9aWnsELgP6fT<8? z%9Pt$-gl-+?% zd~;e(gS};m^A!N9^fOC!czz*0cjX@Zcjg z@Cr@iZ9SH6P~NvSzv+2gPi+C{ZhJZkKyzTj3(@$CkO{F7<>u0@#km52?zX3C|FHGg z-Sw3FzS_RW0EjQZeDUR1*H)}rS7~ZM{B7{p-~8iRF#YYSX__s^YBy_3Uej~9o_%z_ zZck?cm>CjOvMfE;@Hl-vNKO zWaLky9UT4widqBE6ZSOMuGZo_QBS$=tL=LXfcSewczO6!EmPx-9Y47o0E|mWX`LH1 zJ;&0q+Ra+Zqn5_?)E0oAu&1*C6yDr)S`mI_LRMYz5EGbzzrV*>cj+BSGus+?>-_`6a$45lP z(jo}`-RRA?b}Vu-{?>3LjF z^V%@AldZ?@w&&pj0$>oq&(3gR%8-Wp^U|v2d;{oRKK+W(ji)AL)ywg=?xQZO&$hg9 zRex8rvm6ihc?^K~s>(-y{PWfO4nA0uoYKD}At}8CufKfq>E~AylQT+e?NFxY$u}tP zo1SOuG1pUD0J__rj}Uay;r-bOz(WMTT6zy~=isEO0-6V$mmFPjX5!#_%m=Q_h&9+- z9_oO)$eNV*ZPlacdG5BS>Gf?rc6U8x+p6tr0>I8)dpYC*!f-?Bw<=DbIoE(WKZMuL zU1%6NdVHC!Mm0STby2%nu4mgPuc__K9k&O2?$1f78XDHO)Lvi>3<)ZIgPx`qrlQSAL^oZvs_R61=b$ynHLdUx_MwirMR|02xSqDRPkXZG{+#5hQS=c5t)XUXdAK&} z!1}aZf7V!Hi$1N{J0h~5J|H}zpZ=y>?kI95;D<&qU*ySvI#|00uBYv7)Sm2_8{W5c zPj<30cb6L2r^KBBki@l72iB+U`m@FoTl8to-e8{q;AJ}5sc?J8Zh)Xi0Qz)&@F-BSBz`o+N@9Oy0euZ_UO}+-8BUuF60TgIARR0r@9#1 zvpoSKcw?iYLQ7o@L0kjZvIl;mv$8(5)u*tl=~i<9;sWHFUhdSTr^`J-Tm#oKy(wFd zxt?uB<}dcdP!#iV@XTm+w=5^DFWwP!+9O06C<|qxY+R#d*z1r+S)bbK(;OFE0zh#g zG~gYbx)*5)LzIOwodKVypV)Fe{nMU+({g$(1)zF3KfU^JL55QSWuPpS=?wUUF2$Dh zsjWVRU9oj30ObquzH{@dY(KUiYe0Jqv;Z(hf78vkU*^CzU=6Sa{7D1h^qWKh_`#pw z5CA!_4Oj!L0e{i}*v9~5`18Y$HQ<*TU;wi4{Zjb;=~(hM*d=(763-mB1i}72prf3tO3@5|7ajAB3d618Xm3x^-Ucvb6^{=23Q0B zqyeyx0m$&@haYReFEzjbWa0az@cqfl;d@p0>KT9xKn5Udz;89c0Q6q*2Q)PW1o*8o z*=h*@D%T^hZQZkCI z+4Gj$I$eJ5`IqYGbJs=kxm~;W(TyHEv26Q}JykPj&nw4|qsZx@;W7F-^A=UC+pwi_ z$k6;!InB|1%>X!I;?%O4v*(t}Ve*t2<)UJJg2Hq;xdm-19Tk(H&&bRw5$E*i6{O2A z9M$HW0fTZ%7A;w!7&mX&h*DFdiM-ebheql1@<+7h?;8@Sn?7?+IT{J+_}b&N8Fwl_ z(S_rn;0T>uU+kkXMVZ+-!%9uldk2Q-MEcZevs&+uesTHoxCv9ra7~fUTgN*V+s-#^ zH*)m&vPT|$yk^X}NoA8JPcMJw_b=3@rVp?P!L01Ok}cbIR?2PMsY{QdqsLCvty#OV za`?!xWqbD>sCwYR!!_cZkg#a|iC12&-?n{s)eP#>I2Vu<>5gtS1E8qDKmu0wkYTM5 z67k{mE5wr|AR;~`Ewfk#USQvF-HcgtTW>0qZhFbGm4>d}dl%tpfOF;ZMcHDDb5^g} zV8E*ah{IE2^OhZzeM2G?C;^aj=?NmvkBpAj1Ki@+bc-~cV;V1x*RI>7G$O8td(-Nv zB+BQlZ$QAG+X)^UzA7MWFm?Lu@{OCfwSk*R6I;M9D?7K<(Lns{JLgwy+;lx3`tmC$ zPuB~FW?(-=9`) zK)Oy!YX9Q=f|0G~29lQux{JJtN$JG|q1NMDZtYk!C@ZH#q?_B$U$D5McOUZ7=sGhA zrqifF0A(C!k$0DySJ-;J$f&qx07`X|%TxeJ=g4vLz5+nXJ95;xvJoT4mC0$muZ^DA zj=p2Zh{#y|q5B`I9z|ZETD#rWp>xr5&%anlec2*!g2)+ql>m1Kf$%rvU;u`ZQL%0M z;$iYU^M(y??ayl0v=kpg>tZ7~GKuo}bOm8;en@XIGtrp;8!#E=!9sK^^Z zaD&H*cY#E}uQQAE@#Fylo+1rflq=HLkOw#LvssD*V7!HrE@UVb>zikb(liKc|pP9y5lEK)x)!s^R1$J$2oHsR>*Po z?t^_^3qWx*m_IBSKDuURO>Y3Wa>STkdyPv`$)q%a-6)scKzl`0I_?|K;5zxYYh0|VmY1no$pj^L+`aAoQdSr zOl84Cv=ip-u|R=&aS(u~^pfUf_<*N-H?&zu*1V&o5X1$?<1pwma;gum@pTJNZjsZg) zV}(~Xj@aZx0tFrbpOLOU;;oopRRNGu_tQe5t(ToTaLXNfVhDH1BaAs z*toS42EsPI|DZMyGk24igQO>kvJ!=K+~lS$+bc1bAfFEaB3=$tXr54<0}oJ6!+vah za_bXE1|afaMGUX{i2S^DtW&Ywe8+CFammFGKJ;kKk(XYs!)q$L_uO5Dp|H6&+*zt|;4?GQqw81|W;x84+<_){n1hfC0#!FMIy10l(D%1CYh< zx8nCzuZ8QaoyW}pWB@V%Sp$Bn0R|w8-*3gwo|JZ;l&{*70muMk0I~-BRs#$`7Qf$$ z-&egBuD5oct7ZV)kr7?`?ZU!_YwIT%n>J2t@|J-5e7k5w!|t4nvT*ub4+pjZYrwZP zfG#p!TYx0x&65PWDURzWB}SY=g0u$&Lejo-uHby zcm)7?2<-bpVi<56`l1HBVhGHOAl!L;vGZ`9eOtF)vj~DQIKKwt+hSrEaQpd+1^_;< zdJV>zNl4DC-AkQpOSUCzz&;IVvI@*bx6kNoFSZwJz&kX+0OUV~<3ELC4fw4F7=SE( zzZE}wVcy||d9ocCfDAweAZx&HHNXI5@%yd#J?VMywY|gpWB@V%8Gx(-ztsQ(kj3w} z;%6_+JG?MYwgUr@0muMk4fw4F7=SE(zZJhHJrBONcX*!+Kn5TKkTu}98ejmj`2AM= z?1g!U7v{-!a5(^@yLHoV%#5u(HGWXtSMv(4US2lpC;jr#jU3npj%olJf|j5uXbT#1 zRVVuOO&u8k`K8j%1 z9CWnhz&6lI1438WLTg%r5S^}5mmWn7JnsNL+QJnebO`|GCq`B@dwSg2wd(9#j%6(Y zg3uha=d8DIYlqGZJ~w!Ijyzn@HqN%MoL_SQVn_lpa))IbctQiv9yBP6+@5_5xg6=3 zoX35hBHGBFHnnuFrU0Cu7-3-eG59oPA(u9-z+xlYG%-UDN3^XI?3$zmswI~4Ex9t^EP&QiMb z0Q|*GdhYPv)8V--ZfuL6lSVCd0*0RNK~HWoOKoc{%~=2zL0rDv>He{>u<@;_L)x_m zdtpj;ET#KB08fk?Xw2%{+i0l+`FdJx_ijxWCTBAMRla|w*0G$8f9{2s>Rvi}yza@T zo~b?Z;<36nF22>U|DJ=@Az@K^XUn#hfBA|vhREnRmtRM%9yz)BrLUYkU9Xm|WxOT8 zSxaL8`T+oa9pKK^-%}nS061>KlrquTW8;&HpLzEA+B@eis1R|k+Fp3$QbTI`fD%`g zZ>?MgppSeN!I}s7KTAe5E=Yhu_6(X#9FOrOpf);K;o#MtYOj!oIY zeT?_#rWgyu`|Q3r1kFEv~@sSn|j=nlVlta)T=3`TeqeqDN)9+=NGi*P3qO7=`AW-faKK) zgBtUweAGEVEXa6%^5E7qc!~v7hr6;9jr8|qO*tWbjK{_fXj4y7j<0OJ1%QCYf<;R! zo_O-Kk>WT_ul{T3cSm4<0rR*_9C5+c!YP}{osly4_gewUpsrgVfctKt>-`d$YV7R zJ^W~mIInQ{=(4ltE;RHG4ABAFj~xDO&0FuhcjegeSL$VWqpV%K_f?%a`+CFK*Do~e z-M7CAc~Fii00#`pE&-IsPn=pVuA|k~nwMuOojpJ+9^l->2;-QjVB_BE7AFL^9oDPUwE@&0zn}vCSJdF+s>+^ z$4=A%A{f42xOk}n^M?^pvHBf5_f#Ez^l=4Jm|r{f>TC6@)~r{Cxl^alD!=&VTMZeR zS*;$QB@b{9focm~3v~zz4%cC5ju6;4Oo7+ttvf3B-F2WEfP3M{(YhVG_Ez}>nc)peZ zXDy8ZXaRu#C9f;EQ|G4h()<~KkkY$H6FS<5Glwp;4 z=*VE>KWX6w`2n3jP#M@qx$wN?4h-NuLEuB&!J)~<5fOcjShT_MXOtJf!~R8DBHZen;@bIe>f=d4liK13=E>OZ%P#pqK;1 zJm9tiGAUQWi9MTPDAFIw zOH~CR;DuoRe3vk>I@})_MG_@M_)cs2Y_IxnK>|9f#IUX z%MJ4RV*l;~_f-q1SOOqGqvzIm+-B z@yI(VCe%2KhPpWZ^XxojSd4vmYMV0Si~zG3w#op++}_xzkT%!BJRpX|$PW*Y0jSM; zai)tP==e*Pt~5OG&?CxFcIU2rRq&|H0U<6SrFg)gAqwy?--mpc$Ri95kJiJ}vbMr% z34plX{SQ1`1Hh6eSvP2KP6<3sc!jg)EU0+k!RGn_xNp$V8jvto$J1xd)ys2<@;Lw? zpok&yaPn9&rx+8P*gC%{pX=9NAbt6-i$fX$79%is z2d`@s4R160^irJz+)G{><`cybco%tnb6Nn1xjxLjiFv&bXm|@x@ofShuCt#!K3rQ2 zf%g%}P%osNBOvyZhQL@nNujw&;kn8H1cY%N%vT~Wz#B@(7|!FE0jLf9(5cMG1(5S^yxD-cK?Dp< z=Pg)Vfgv%@J$vrFGG8cQf*~@7x8m4zJB=1to_qeqI`Yz#p)`imSj<4&jG1#3542BE zs1BfAyM9w8<}aiBCFoy1ezG2UQQq!7cUQrS#c&R*fI4BD%u~^U$=bRirNEyZ=EtOV!59g<~mV@CgyhSXGARXSK z?0Ie-7-t0NkcJ_v036De0f^(LM`VzP*j+gni#A6_XSQC40q9x)=H(A>0|pFd&%OSJ zvTFO{OE1?UT|i;s;$;TRslk&vb^5h>tRRatKoc-R+N)>I)-PGMvdtXZ%vp0QPQ7}j z-gFgMKXdSMDdT!pbLs{fN9t@@Lx%W^t z(%yaV4_6+fm1LBQG%*J#$_8k#ii~>_aawJyLC#XT-vdy<$J!Qibw8T?%`=9`SOpdf z2!Cnu5CIr#5YUewerdFOK@s{cUFEk|V z`a+2#i$-?XdASFnjuQSjxu`=%bSj zzS=>!-t8OS(5AH^FnoFS3v@uc8+8fLR`vAaCeslBf4g(Mc3NH}C!_$|C!wf=qLl&A7o*#5*ZSg~N1k){h zg5C>3tvo-pIhY6b1@sM$IC;x$ot$+ki)095{)HDt7=rGCAhgyp=LgSEz|Ub#V}6Mj zM!W}vXbUao{N#rnmuA)xT8~dhsAQe(3{&p5JH3~F(knYsdy`&Jwt|~vrvSF zpe1Mu+LFO{9e&mqKCbKb7S+)YIvs{wc;S}+V#Iwwgsow7*j{V!iFOC`z`lT>zTuO) z^>FSN)6wH=AAza%)228 z89`4T4!gFYxFfKASp(W?0L)T6Klz2{8wh7Z1YAdqpLtzDgPyr~ye9~65N}iSpUpYf zSS)t7A8SAx4S+>p64(SrnPZn`aYWYcbddwN82+f(6$TTNGa5-V%79^BeJ#~c8m1@o^aN=x=M>#tRb5?u>#JYis%rJzH>4!* zx4-K0D?dNK-{ub*FwD>IfBLfhKm6bS!~TE#f2SPv`(Nch<`3vMV)g&{8I3GXjeqfp zDgFsbX%iEY()TANr=Lkm$@n}uHRA^sG%RQ-kPS!!qydE*07HHNQ@|E52CM;d)L@t5 zGU5_aIdIuBq2>hf0(ty`#0Bi!Iz$!4y9=6%c6Q7tm5o8Sxjna6M@^o$T zGDriY0edt6R)JYymrcM~%fJd)##URjeF8%n{Q5BBQy?3V21o;l8AF-|rO zC&nctvmr0$`n>;!sgBe}qyf@^r~$AG409NQjGPnMii)-u7CL$`qf#InkOoKtZBPSX z7+40T$$EQYLR`GG;GyXq5UT0MZkPhufHXiFXv-P^%hsQ2 z3V<sNn=9wTEmyo(NA~IIftvky^fown;APux* z4S;oEo(X{QiD?(HRNR%_GzGE&X@E4)o;3j0fq4=DnJeheXsB(^H%#|N9hx*i8W1%A z=7D{FY(->ZL{uESzcLDB1JVF#z!x+C=7D{F?6WcZf~H503WI#$X=Uhxh+J z@97^<*0mdJJcZ%Ump;Gx#g|`Sd;f!vuZTfud2RW;jhnU^PMkc`*p}~s>aM&mc(d&a zi-zci3?11jFbHTY)j1=xAO32>Vw!pWjLiPpvEwFHjwzi`85@^u*E!~8IC7lB9E{Yo zEUhEwnCAuaz&-}Rv>!0$@511xGys4zX3eWsdVYI4Z$k?J+tWSKy(sS+-ekMgYc?20 zjTv7#m_d*SK+aMf3yX&8vic6Fu#_go_3b~fV$Ir(hWx_8x6n+wWo&1?cMiq?Z1Ec@fUs^8J(c1t!pr{FUe{Vx95TVwg3F? z`(G+_RX0wZIp4^Bk*b{MWnY%izWLV0CPPi#jjz7`_S*85YfSfJ4!}8c7glSux*ItI z@@VyS{ zMwYKxx6#0^S>-GMQ3tTkFTuqCgi*iy{)b;4f8v=s_RCG$rOQ|A%QY3(M~|5x5gbpT zpD&kR-*f-|+6eXwPqXJNsMc0g-iVG(k{ZGm06+P|pRV4wdv9$I|G=^(%U0@tzO1>9 zYjWfBEuK;sp7Y~BefpQHHMRA|oZMzG&0n~*`Y)gTO#D1|SjW`z#_t(FDb?wQge_xLVoHA`z74B#F$WrNkL;#kKomh#q!9zxx1j4UR zTY{XsH6RB-_K^V1(q*gkOPFH<&k*$*!?c^1Uu;vi@F-`oJ`0dpx}Pzn6D!d#(U(@N zT&stth~nmu236bU%aTd<@W=NFd@*Qo(OuunAr!g~_~JUZOy zc;=Cnl~-H`IJkk19DTLnx#thn;~3uHw}1c6QM zRflVF0Ae^$R<6B1Zo(9c9x1OEZ3%?# z(f|O62mPFRi%bE11pwT-2?L~m*?~tNuY2Xl@dhzn+;0Zp!wgK# zWshe-X&wSMACDY8w(_kD7n?4ZX|BI|;#A{w=92Tg=G#C0`7c+ePM=k^aM3dTnX|7q zPM$iW>b>_rx`LIhpMEa8K5$SG8>ae~{pZL3UKe4`_p!P=XWqhUek^V;zVn`Rj~g~^ zHNd<4;Xgn90`D&^0}XnsT_}!h;%*JBUbEiNw|{O0oC_ZC+4#ulILQMP>oaETgcc9b z{&q@E&D2hrHnVCe^Z3xGaILlLHyO}pc-XvUdkq{A3}-iP-o{`ESTDQTJ76|2_j{aIa+R$MZSd4OZth^uuzM~@SjQ^Y(#*8&g*`RTuxufrg`f-k&y zxc<=LS0w1+#xO6))3AjHI54kJf)PBcXP$kYd5g_AyL9;~JqKVwP*^z(fwE)clQgsE zE~x(R&*j&f=K*gu&V9QdsQvx(FV-JBexhLoo3{%H3@wKzh%zut=hyh~qd!~$r1`P9 zg$s^3J>D2%8ukG|%ty{)b;0%i`01sq><_R__imn_j&E%zvWaVK0suD80k$r`8Gx9V zzZq{Y05QU29~Wr#ke|0;aW$Zonx3V_(3ZoNZ+rC#E(ZYN9N~2oe%%?f=2qvn^m`tM z?Se&1_2{o0qF}})h49%$WcWaQe)-)t1VD8w~Gk+m3r{ zFl-z~zW|b$kVQHcGd{ia z*;UNx@%*SOpq!bVQ-QdB4?a@+hd+LL71zU$Fry4ClJp4(Eyr9X<_qV}Uo74KhK*Yd z@Gfy4@?(y2|3e3AdD*mePHSX8<@N(KFh6c?L;O_)=IO+E%**8sD%K$m(?*!@7Ss7Y z=Jw_>?IRE3`UHlRuiLQ2fT1<|`+C+N@MmX8V}E&}nLKr-G>i>q`L}M{Ra3&|$B~A9 zw0`3j19-v9=3As;sLTU<<)#Ydghj;Ml9!)j&lc>%i_lILf(uy#Aks0h`pvihxP~F) zWi~Gcz=#!`$bj|F@BaM@(g8F~cJg%0AHZY7YV40cUA}(bp1rjkfXD-2!pp+B$b;cD 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B1-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/B1-initial.snapshot.txt new file mode 100644 index 00000000..bfb5c6ef --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B1-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=55158000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10004 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=143 canvas_frame_encoder_cache_actions=94 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=44 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=44 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=94 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=505 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,16 288x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,16 288x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,16 74.9911x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,16 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,45.5 288x44) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,45.5 36x44) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.07129,53.5 9.857422x10) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(29.17101,66.5 9.65798x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(58,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(58,45.5 36x44) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(72.27246,53.5 7.455078x10) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(71.17101,66.5 9.65798x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,45.5 36x44) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.60254,53.5 10.794922x10) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(113.17101,66.5 9.65798x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,45.5 36x44) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.27246,53.5 7.455078x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.171,66.5 9.65798x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184,45.5 36x44) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.58008,53.5 6.8398438x10) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(197.171,66.5 9.65798x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226,45.5 36x44) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.25537,53.5 7.489258x10) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(239.171,66.5 9.65798x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268,45.5 36x44) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268,45.5 36x44) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(282.25537,53.5 7.489258x10) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(281.17102,66.5 9.65798x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,101.5 288x31.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,101.5 288x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="THIS WEEK" bounds=(16,101.5 68.75879x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(269.9273,101.5 34.072697x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,125 288x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,145 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,145 168x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,145 168x36) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,154.25 168x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(192,145 112x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(192,145 112x36) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(192,154.25 112x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/B2-after.png b/experiments/render-loop-cadence/final-captures/B2-after.png new file mode 100644 index 0000000000000000000000000000000000000000..a060c8538035259c6da25a8916e249b876aa8755 GIT binary patch literal 256283 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 D1coM% literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B2-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/B2-after.snapshot.txt new file mode 100644 index 00000000..6fe4f243 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B2-after.snapshot.txt @@ -0,0 +1,50 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=116170000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10580 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571597089929000 gpu_input_latency_ns=16284000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=159 canvas_frame_encoder_cache_actions=110 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=51 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=54 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=110 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=47/1024 widget_semantics=47/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=552 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=47 widget_semantics=47 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(15,14 290x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(15,14 290x18.75) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(15,14 82.75566x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(250.73633,15.25 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(15,45.333332 290x48) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(15,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(15,45.333332 36.285713x48) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(27.803501,51.583332 10.678711x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(28.433384,72.08333 9.418945x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.285713,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.285713,45.333332 36.285713x48) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(71.41051,51.583332 8.036133x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.7191,72.08333 9.418945x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.57143,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.57143,45.333332 36.285713x48) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(111.8593,51.583332 11.709961x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(113.00481,72.08333 9.418945x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.85715,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.85715,45.333332 36.285713x48) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(155.98193,51.583332 8.036133x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.29053,72.08333 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184.14285,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184.14285,45.333332 36.285713x48) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.60602,51.583332 7.359375x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(197.57623,72.08333 9.418945x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226.42856,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226.42856,45.333332 36.285713x48) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.53455,51.583332 8.07373x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(239.86194,72.08333 9.418945x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268.71426,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268.71426,45.333332 36.285713x48) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(282.82025,51.583332 8.07373x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(282.14764,72.08333 9.418945x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(15,105.916664 290x31.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(15,105.916664 290x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY GOAL" bounds=(15,105.916664 88.21484x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(271.42578,105.916664 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#4489113988768380928 role=group name="" bounds=(15,129.41666 290x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#13195408868291225394 role=group name="" bounds=(15,129.41666 290x8) focused=false enabled=true parent=#4489113988768380928 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(15,150 290x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(15,150 178x36) focused=true enabled=true parent=#5802963363624800140 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(15,150 178x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(15,159.25 178x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(201,150 104x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(201,150 104x36) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(201,159.25 104x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/final-captures/B2-initial.png b/experiments/render-loop-cadence/final-captures/B2-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..14a470e864a4ce14014b58db0b753d17ccb7321e GIT binary patch literal 256283 zcmeI52Xqui_OG?)z4Oj{yWU-F3??H$B1)hfkdTA|0wF{eK_GI@IU18O!GOUy5*)$C z2AgOTZDWJ8ch~Fn{&&~*+FmcxjHDUmfDQfbucaDV!}MsTXGWUQT%A+u?yBml+f}!| zzPGBUd;5@#)ZhQM)o*=#e11QmfATONpWh_V{>T6K|Iq(u{&&>tKL0ECrvb@*N38sf zk0eo?GyX!uqkO|6dS{14#O#fTj5!+-75nGN=-3}9=qTtpa2v1=unuU{0WjnTFa>M@ zW560P#~JL>Tt-M(R5KD}NqA)J)$qvP`d&d{`ffdX>HNF&&~@n4CAWPC|J-)IejK1WW;2z!U#DJ)%kbsp=;NkK*xdG zfOUX%pdNJq>;Z$oA_C!Fu*qJY*_A&mBKl!6MRnZ+f_3dXbk1!{7t4X$fOUX%pdobt zECQ3jCNRn_sM(U4Ow91`$e61=$@J{du?s_w!OuFtI^cFX05*Y9U=^5U3)||<6B-_! z4YGFW)>GGzl;^tH%3vK}9k4|Qz$!2c?5Y!R)-q55OK7!4-^srl!LJh$p98l6>j3M3 z`|ALh1$Kd9))=Rnh7&`=BFW{&T%Y@2Fw4k%w_pwt1d3kH~irm0$c%7l1(XX4X4P7t?ZUfc<)&Wn}0kDh~Ms#4C zl64mM=}GIWox27y{22ax^J5)oG&%sLfo&F{Cn7_`qSprY3e|fu?OArVR#*pE2Q29T z*apT4-qqR$herC+&r5W^vZl@?o-x*Y8?RMz&bF`1i_H7=*0nn z!MZkWDH8{71J(i7fkvzYU>%re0$^x(@2glUZcP`>f!ly}fOViT>i}2>=E(pgQ_z=a zsBg>{%-6;PnstD6K&b;@9@ytYD<`CYd%gVYzy1A}$M)KOJbmVT zg)NFeKUA(0vbN-@t1f4hVXcn3%D0rx0QAg(VoeV`F>T1Ok@=aUvkH`fUL8eKVE6V< zeBYG3h^QEgY3BJ868q&%oIK4iVbW9sJ!V24<-O%OGcI+&p#0dlM4M!@R4!Tt$VLrWqk`5Ei3%% z*WdhtJpcITcfUUM^mC={ef?#b;^LF?5FZgq9aU2g%0yhxUZFa~b);_wy!7(1vLAl@ z`8ML;xp291^qBDlBENF`==R5o|NX;HzbfO79y?wR**f`=)ml@>W4j+O`PaAK%lSHY z3CKNr?wyMK0^=Q&fBnWMRgg>M#rF9ZUM~CTKR4z2|MJz>zl_hGY!K;L<7zCxnz9l9 z%(I6|b^3xk$th{I$`R-AR+~<8yQ#O^#!cIbvnNb3WR4;T)&%9aQnuaDVVU_!$^Glp z&6Iv=d7CyrT0D5j$o!1K!}HfYvZ-jq$T1ejp0a$c`|$}WdArHu97kT2)-u36u#W)P z`v>^&t!O}M2>{?JvH;c24UdS?|M=6-w=Z70S~((fY{C46OAEgu(0%aXM^*GHYq`#` zSrZKgW6_-#31G?8m~-YWGTzM5-CnhNT@lLdQv*Qy2#Q|RlTrgf`gw~Eam!Y$Dg5a_ z|GhnWY<58$HP9+ddKO96BOz9xTZ1Ojtm@HjL>x@V<=x>{dgq;smn)w=c%&3@=){uJa%m*p zCF2s3Wng9u8DZ+=z+PcGoHKLQJR>?SFW+!y)tX0SVB>tq4M6UD;wia2B>)%DO#tVP zBMT9EIdB`)mky`_uvc)nZq38%i&n2)Uo?^o705GT;xt2g#xRr4tH}sGh6e{YS;~_= zajF63!Z=yCep8VcM+93LX0RBM=izl5ixw6rOQ_r;{0JFMi)2&K$H*m z`Gh$Efbt^9ZdwFUgcU2-$}l)_@>Ipe%U4ZcLdEo2>zrI&-faO4xUE~Z?T}$)>B4QX z0MSucWO)DD^(r)SVp6r`WvM*GJ@w4N(yQ-XlcBry(VfNbzW+hh`~^!2zxn$=e?j`3 zc?*p)iQ^jVN0QcT=j4f3~jhLt+~K&k`?#%g-f*nh>M4dyY}G?G9)o?hK^BQta4uf5RYtR9b|4qE{z@?#ql+gCqp&H^K>Nk9;FZP~h`SilzBoxApw z1cgMx-Ok;|4^yghBkY`WX{=Jcf%F4Q%gps6fl8<0p_?TI~YY&a2FW{iy`4sNQ|ZIJui|>9SRYF$68F)ILn(LcmsRu?kBs zCdl1I3ysP#052>peTd8jWqIHMJiEm-HHPpA?QfuKq3N_*V^VoeUHf6QT1^(9YXOLc z0cg&id%L1PS#6W2&M=TUhmcr0hc)&jt^CrPTlLdvp#c`+qQ%Q(SRfCq zy3=RQRnTYebm)}NKL7HT5`Y^vZYloxzqz-wCr&W{w&*;RIeP4P)dm8*vC512K+#y+ zcRVJq{Nh~t61^-R{g6BdbCe%{^4YCPlcyW#Bh31J`=2cR`M){0p*T4AxkE?F{`Kv@ zf5lt~?xstYuE0EB%{-?sErLvxp92*2_;v1{i#ft-SNN{th;-g^o47&;v;q*Y!p+{2 zOk=XL3zjZlMRR~yF!9a7xWTkiFuB%%+oRie72|Olq+#sLnmyl$M^jKHTwoXyNTcWS zblWH|#<+PsNE7hHcG8sThMBYH8L?1fp4Zl68G!UGjIL#C-yE&sC{}?_pR2HTJ}kXI z{pGLnBQAgzR#f4-D$iN5YHiWC-~I3_(!cxuhhGmo`AjKXWswIa@5i5fE<+F28Ri0z z7j7%^z%+jT#aGI{`}dD>8JJhZ3a&Wc(suIHnX*;(+`%JdBE4T~x@_%XK}5u1i`6hZ zz5_QF^#X=i)e?DN?qlIcpI0D1CiC^*{^yrPi%P{w0n0>5BF+=!853t-79)5Sh?f5N0`22A;&d{}iuhGv?^ z2HfKH8@3eVQ5n<`MRR^QSFGsHBdZU;DBHYsdvRL&P`N%)w%T^s@X-aBcT`KaB_8a< zgV6UhhAk&+$pctnx!u~iy@DgG%F~l3Rjr+mG|Vs5l}Bqj<|AO?Sv%jA^;@f#)2t7E zZXfOKgGXB6{nXWl=7x0*M zJvu<&3&tEE1CW*8dz7C0n)_Plz+C{gqDJAsZNNIfI^ab*AOjH3*R-IE=D=;hI>0*M zO*#Pf;f1ISK)wO+4Ul!f>vVtt$V%^ZO7Be;4qvNvi=F|<0Av8N4tT8&)BrG&T;O)p z2pqT#SO-`KyhjH@!Xjx7Fq8n;k}jG9w*l(_>wp*O0N97mV(K2Ei{`*>z&gM>;7vLJ z_Avk%{(SRe9q>vWU;wh>d!^!gla<5Qs&3UY02zP`K-K}T)qxrSM$jB!TWSR71-$OM zM_{lnI5a|!x5zpppe&S$vYjQXE9AtrdWx*xEN71qLkv-CmlXGXVtZN2^ZUzFUOeDf zpfXSv%0$_$qwYKIMc2$I(EqjHgfQMdygr2%6z4Ss$5=D9MU4%CG@Sx24214ne!QXhbQKF$Cjpn~szx)OSp%0`{`K(L|Y zgzTOoYh#rYAc`T&%s(;FrQlOS6?LIbdmzXuBBZvv=I9wKd|M0zfK6 z57Sf#R^MCH4H>LmXwAhosGMjQPm#5;$(ca&arNQ$3h0?{Q8#2@9km^Bb#cU29ktfx z4g(N(ESRHp3G3=~$Uw6ANRp3_swwC$!lE&11a^B_8;hJUzu=3Slc~OsA%itjkag64 zLe{0D)(BW*8DSzYoK_Rs&`OB?0iT)g(k+lE*qO}0h6|7ZvZ!5yyU2+)@)TJci=0tw zmJ|m~n_%?on?MtQ4HqB-WMLh39w+M3QMI-f@nD}%5Pj&j`9lOh4S~+pccSNCeCdO~ z4H+NI`W+?qcPBKtx@VoKiRDKm`t(WCO*h^Sco)M>Mf-2-~*l<~IgSI-4l zz6PywqTX@YlMIka8L}r%G1wxLS{`T1I%>=~1AZti>dPFRRnRvnHBTHTrS#8FN*RzZ zj&0pKTTW50v)j~~oYeq~r};l^q0f%>B}1;Ax}^+Z3uhH-DX-cEcD|0HT|3ba=0}ei zZ&8BW8`8Xh3{muTaxqwzY9x)nTIk0RuDg(=&z@h+{{#&X#pV=GcPN0qL^BVb`4tPRMy=;jQ}`k zSb;K5>%OyPjqQ_|H$Ho^+?KGSr%at`L|bA)8xLPES+=UEqhB|>`^njInzxs;+SHny z$zq@BA4%CJjJ?w>z;Y_mhM+dUxIGgioF5iHFo1E)0MrJ+$f!Pg+(fb`Op)gTJJ8!I0KwZ@!@9!xQN82x;1y^o3+K41@9R@eHSmde z1pr&oB8dF~u2wr=KWcFMLR$LZd<2{aS9sNGto(-1-OG;vIG5%CtM~0G7qX~bgH}0} z^;Zwpp#*9BuGLb0SICO@@h@MwrYN<4y4Y`b*=NlK%%`Y?@P<5}quTMGE+FHcR z0K_Y0nl@{dqa_4|MC#kN_seyM09n+o!JXtpTX~ACjX_RF0jLC+qx+D>)jA66t!wvQ zI!DK(tNXq_O55(Lv^{^R2Zf15n!y-ddY_O5dx2PsB3-8Gu%&FB-!jU;r`z1@O$b3_u1T15o4Q zh?e=l`j`W(539P7S%9Im2-1=kLF^CsB2nA+ooEm>e1I%!*WgZaqOCkd*2W;G`&odN z#~JIWHilT!Q8gZjc)WAKCy;)3+w?)|6b&JWes9>e9SQCR0kWuFgFDHIw(=BN8-tuO z0ORNp7B>j81*kI4SVy&S#F~z(@j%3beLncz?E};)S^|D>-G&CVI|Rt0b`9<%C)&zW zWNi#`0y-TCe(n$;3+t$Jd0|aQ)!JIbgMAFZ1^~FVPD7eI+)x?|s2PCTfYTUsRDe!x z%K&Tu_%#-=cnYW)fDAyl1R!36h2H>geROBZj$M07@Eg`{^il+^){iUiSe_y)%X#lq zj-vn!8aOcj;oW;mE?>VV@`LF!<`|!T_E6d0eFsYM!+k9fbQJ(SMOK#6@&IrIfOzZ6dmn#t>)RiG z`gPCYBV~^rJXH40zrOqRv%mcHm(EE^cF!xi3V_`Amiu0SPHkHQzz|vlX+eu1_6Pc? z2+db@Bw*PWrc9e@eCg$5<=uMpB8#v3T>maTbcdgRv26arC50l+o-Jfiy9TXtqJB@2 zmF2XoztsTjL$IuCLrd$qO}@nB!Q0}$r=Yp%YedCiYq0YFcYmE}|)1X=-@FlLOQth`bhK5KTNIn+|d zkC)R1PoHiyPqTLH3IKB7tM|Pc_(Xhz01(z4th^z^G7HQhmO5ZiJ^)CQlXkn-t^lB? z$jWl64+5H+g9eEhPk>}f}nlj)TPUnfBF0W{9=CI^)J4>b@j%_x6I?M9YY4l!a7=i<6f<; zMSMVDu+FCkeMzdx0}thB3HTl@eSAmPs!fMndjfsEO8>%(N6YcS?jU-xCM>jh3ziff zJ$Aet&-2++7V<&{$f9-)TIEF9o+2yDX<3KES1v3Lm^9AVJ~lSb-Vix-Xu;1py4x?F zc(WpY^cX{*%uE9wf6?a~?!=86Ww56_$N*VbN9%9gtF^U=2m1s7Z&IY)fu57g>Ds*~ z;Fn`>h>c6qKfdqDk`pxNhp_*Nr%RLjrRCXM4)Q|=$f9-)j>w7fJw;ZQ^Ije9oRMA- zwQ*I6J+M;d9X4~8@$;{~{snV>2!Hz9H@}Qqw75{2$CiD_09jZ^>u=nvwY7+M7=S1U z-y)??@!1VP0Xq7C3#=?yk($at-8f%dl-kx&IjceI8M1mxo7R_{1qi)Ecrkf(3b<}nS*gEb-+gjQ>1%R-wx(5Vl2AEdxiStmmHS14Y zctgtxc|Aqe#wI5$uh?B1OMU5=8@2$;nR!qr>b7S6v5wjfK6}T#Xj@BLrvMNIcchPS zYjuUi1!>u$PSkDb;w;5Al$^LWPm#5;${93gS|Qxf`h+0rLY=7Fl0I6BV;!vF)bexecTQ%+our^xCJasouK#vFBrZLtth2kNp1 zeypR`;pd2sindj5YXBIeYjS_{o6ZPr+LD_`ue9pgEiktOz14+Y|DMyTwXahG%0iha z8+D*Atunh(PF%02$m)%9cFq`B5Vvn@Y1GD*B>|JNjDBgU`Mz;jA&zkZo~N^dN)H2Ugo334qQF^!!|opMQ55RCwhKK0e||KpB7@%0$`DlGWLA z;u<|gR&STnpWsA~r4#{FiH9FAOFXi#+@U~ape&S$vROwR8}qIlOQLVUK9>McRKQ#3 z-dMOjxjk72oTmc}Kqp(itennMPHszXOIPav1CRme)Ts|wD=e4KP;{maFaQ~V3_#Wa zuhoGX0QRCqkY>~f9Jmcw2UrKZM+dqG^wRm@yBvRL((EP&ZUfc<)&XzQ0kDq&$nfWz zAM1cu>Hq_f72hir-$}ha z1|VC$Z27Yec&!dF09pCHR{4b$z+3ON2pND3Kn5V|fY<5(1CW*9Yn7iZKkv2tMBi5f zuv?(+_kU=5lLNN_>j3M3H|YRphX9wddKP4JiMW3-6NZd z;}Vkd>MEmk+m1Qs&R?j+gWbx!^s#8&tl9I8yB>SIWb%|5Mr9iIQwI#n-?({O@$!{x zih@ES^ycaI9)o=j18~5=!TD|5cghu&_fN~n4+)Dh2^SjPTOUS2q~jt+jTvuHhGq}7 z$w7Kc`l^sJ9{b7t((=W*K_QWP<%I_XhUie9Nbk_8OKyDMeil0b`TV;CnB+v`4;?8(~Xm-&M=}qnl@{7Pnj^g zhm9Cr&?i3W9{FPW^vzSsCd%e51IgWWASro3-i?nwy|tDAxN_CQMb~e9QZ;DsaMPHy zB!AZUNrp9R*B2?%qGRIqSKqx>1-OmPnqYYC_=)nh>o%D3Oqe*;@ZPl#tL86QQn+pV zu9E8?eNq)38EfK-vMgKoodUpq{nPVt2SBCx?%cfjiwlR398(~K7&$7d0ADo{$64bh z8rrnG3rrD@ZQJ&Kxwv>`oN_-lE-?=Qaeke9DE&>WLT!DZsoaM zx(4d9sSyDp#P^O($QzU~OtqsPc(7&8_z6=C=-}op+T_sJ)pJJ?1bYMqo2~^A9ho_{ z03D8N0x;9khvbhLn{B}BYnAnPrus)v-l@}P8O_shPGGMvQ@P6Xc%LEYt~!9Rbm{WD zl_~uOn#NH~pTxZPuU)Ug_)(Ml;GyTsqI<{Jg4cm3pDmp*X_{&5_l`-(yKw1BCCZ?0 zV&(#@7~i5yjIq~Gyj3BNwQQXNKzw3MKnH^ykeD%Ro)L`$K+Kvm-v}#72In^{_anO`mOS-lDB)Cq+c{(ZfO%a$}2*h*ET1C;C*~46+Ud zR7Kv&Q)e3SGaGS?Eg;t`I9!)b&<&(d$eE`x02y>jo$!QxjJJXmVXU(AUyC`FG15O{7)|1OSGFM(I0u3D6-ZT|a;gcL9-xZJV|oO>Qf! zKe)1hSI?k(EvC8v2y1aFfphTCkpaU;%>W@yg@K=stS5$jUhE_e)LB zkBz(Q>f)oM(`U>v!a~NoxQ7m_4OX@Q8GhzE*eOM9y;=38K!&8<8chH zZP|)7CfC+H4*)uk++4WBNht$lZx7>r*JFE2%=5l;;c{hoWQ^4@YJQIL*eL)+f$-_u z`TEH&BEDcQK!~}mID(?GQUDNcGx8uPCrtsssdTX-4O^wl2>@aa01zBY<-o#JmR%PB zkr!o5B*>bdt1Jimuof}ri2aTP^975R79zmn6M1ocDXDkOe-WQR^NRL&DJ02zQncRXo}dAkc2tKC$k+;5#aTOr`3jK}^9FTPS18Xj#C zS|MT4dd&SDI{ZQz;3Uq){QKeOUn&#F*uuqzTdXvol8Ek&uws zFAuIENR5hNp2B?`PIm#giORA8E?Nbu6(`c+(gGCX*nA7%^i4|5Lp&B65|jJO`ywA) za9DTZ*wPly{$vo`ETt*qV9CO|Q^vt%hP5l=P#^AS;#h3QWlu5$^b9ezE7}6!r;d~Z zR=C0qg`OXAji&pJ(u(FG}IZ^&Va*Hv)CypV*M9LEt z9jC`Wt{W@GQz#GaP{;>M4_4zJn%r#%x@+k$H6Y4i0M^fd746Mi=e76t9lJ~R?mJM5 zDK9{8$F4mk`=5BK)KVK`8fd|yWrdc~o_zYbQmi6dO2gQK<%pH$R&9K9FpY$Tloc!2 zTFh^$3`=oN10V+eoOz21BMAheBCP&m9zYz6EdV%w;nG57@Flky>97Em@z~F%l~{2u z;3oixI6QuX#gOK7C&DoRXnsE2ZE-%fwpxIqJggi8dYC)Jvik^H;Z~N{l0XTV&73{Y zIAhjaBc=nC7A_WD2BZzHB?InSaPnUxtgbg)nr(X%J9+0pWPDW0I)B<46PYx!iuN1Geb^zy;UUo!W~5$N=OU0PBF)>Hq_fmEUWX-<>QGmc=$J z(%J3A0Av6%09gmTRtFe>to&Z9{LZ!}xV(n3;v8vr1|S2F0mwSwwK~86Waal-<#)t# z;B!6C+OyPW3_u1T1CVvVYjwaW0L0H!TG2~I@iQ3TjvTlRSO-`KT%!YE3|Ir^ShDEs zjdK`)5QM?!n$G4y#O=yDU|9#i9A`k#VE}^0+)0)@iQ9$Sg>}GnIso?AYw?-qcNl-c&wyXn|b--;FLEv)(f}k~eSx(B4T$ z&fhqmpyz(%eryanzyRc50XXG>(#9|t_!_(q>I^^zAOnzfz-x7Y0m#blwaU*HpZ8gO z=6%ipWB@V%SqHpU2N-~?{9dd4=GFiod!I$f0Av6%09gmTRtFe>to&Z9{A}@gpT%e1 z=L|pwAOnzfz-x7Y0m#blwaRa94e+t|S%eHg1|S2Fb--(NfC0$L@3qR$7N7T7eCB=5 z0Av6%09gmTRtH=Pz^*eV=#x(zDjxRbrOL5Ces()s_g5)f|1}401J~;S=^Atnx(6ME zE}Gx{opt<&Ce3a(d#FuLt2P~S+WGo<gkQzXlrMK(CGk-KeD%wEjM8vaze@dRNag+W0r0<%T`vc8vjrwKOVh ziGyEeJ~H{(Id46+wH?t1w)9n9d7MT;y0sQD0onZXBprax)-^!P)7kv1U(i_tqBG1v zrvR|)%z{Sxa*efK778{y;zT@L>0cWoLLphktutlU!>9g@5MZUeHtC zgwQwE`p#OKV*vbJ6CJPqGC(~3CPJ&hza?F^Hc*rUj`!UUhSvJdTAD)u{C~guqt4@% zpRHG3z#$!gE?XNY3_bUQp0ZD@^_{geM*x`97y&r?pEsmIm)~gAP#E~mtJ0Y7K55j~ zXzz`=27sz_Ny@?I$bM3C|Ga^NhUAOTp;H&Hd4odtfFNB;>cD(Q+E49VYml>+#sD<4 z0Q((3D76d?ZPajhz_*h$@aBSz%zWP?y)ECU5G1^!zv9I#Z#R?nt~f$XQEc0D2(+?S+FkhB{R=O>QZ{w^ETf2X)%N10tChWD6Y^YDeqH4<0L@_IjsvSM3oz@a zFQjhcM@#p&>mWVo*IDX0dy1r72paLH%Tk8{sS@3Fq*f6TQtut>rFIGN7OkzU|9mO+ zn363u?dT^p?-3w{u2@hj-=M1}=-fEDtTw%)rT%ZdU`ikN^Pi-EX%nTUojOa+yZ4Yn zmd>jsN7R-zQj4G<>HfC9Qjf{wq*32|U^@4~&RwNJSMIv`sV9#}ZDL~NdfLYIkacgH@|B2z;F5YU)4XTI^^q36p4K(Z%HF}!;G zjq+-Te#up&R?h;JY<9^|A8l;DShI=)1@L`#^B)v=ik0q+0n0S zE};G7Q_q&Z`~C-2ub+6cLJ4n_wQ2LV;tr z;^BQV_?6Jt0vvZcr=b7{*Y_Z~!>d-WE5hI(kd~2u;o_Cb(FBE_L1DUek8CVH{`$#s zKm_jV#miSKF@G4)Geoyx(w?a`ej0Nl}I$ICZt+FBeO8mS*XVsruI zP0tu6&+V;Rv##i+SB{mV-k3gp^Im%SSo!L;kI2`i1Yl%zA3dNudFl+OSiaUEXDy8Z zXa@kt{rAt(@0+%$HGc+RHS5}~8a&s}O84F0Od9j;$0pbW&7YwPz{pLjB;S-IQ+_~a z$cJa-b5Sm=F(oJfytpTK$Z^q+u9MpLO^`m&Ji#GkH603PzEUwBQnP=|kUQ9d5? z?MKqU^LOX`lmLv{yhdu*x3+}}D=&7>X8BwhfGt`}SwDUu9|Q7D+O(H4-g{F%R?6qe z`}GMxF$aiwz-u2|uiE#-Q>6kl>(*~7eq{Y-8AO0lmu`VNfT&M=VqRE8Z~c{b->*ta z=`TYKgBLIa9ES`YS@8NBZ&oN5RSuAqHh2D_LSa=|1K=-Anw9qkpX3KwzzFf~A^v?v+|`;#^PN)+Yd$EL~A3R)OI@zIEzs#klNAvK#pHvxiEBtE${) zjh`r|PnkB;c>Il%@uaaXRsUkO-@8Z*uy%2sX<9)7+I>B=~<4_6+*1OU&Td#Cahng^xwssLRf zo1L8Gdf*pvN&rSYvRvxWKc!YZuskt$iM$NJ>d&V+IzYww=8GVRpErMT;l3xHlwH}4 zo3<6hq7wO)+tBc6eL`YC8F-lQ!+BT9BJ9?qmkyRzT`R2C0El`X-*=!CfF(<^JTW;n z50)mZ!YR{c8Tak4mJh(aM6NZ!p_EPRpE>(>g>o)Y#A6Ep0*Y{n2b0B$ImMum2-Ezg zGOxY+)*xpsjR8o5TnU-F<^VgT6KF;bmFMl?Vzy80E6@3fGO!qdxx1i+vn1c-M6#ZG zssb>4-75&^($#n}C7$AdOkR$Ev z%hChwJ4(YpuXcg4c+#v(Heu2FY&Z*sKYLGw0r}z?@%H?>IdcGlUC_1&|Auu2f=f5CN{~j9GJy zaEX!k{M#4g`9c8`xX5sC#j*J|n-*AJe&yA2veIN%8tya}GY~g%(lpru?d0Dr7oc6f za!nEDFM9=t>)tr=Rt3&Qd7HOvFNPHhcO7~0h|gnt_Q_T#0C@V$dDCMsm`6ljb2+pe zTZ5dnGzOpr08)e1ayxO1IX3_SuODZsSHt<7hP(X(A-Q{FJ<+i+Qy8r*=~Q z{-!jMM=tC8Ph{Zzv1J>%zBVzvrJ*06H|0%zmkKHzSWclm%HoOOnCtV z>97{X{2|H?SvF6$^pFOZRR9iYN&wn@L)^TccG~QkX|EBcTPQhTCkEK;@uGO)c%L=LWk>mB|gRge-_jIAn3?v zF~K~r&xfAf+4)e*b{YV9Kjs1TvK7dy!MxJzX$vT%v(VjY09yYj5&+0np!)$(tM!Ne z1oOZ?AOFrh#TzVmtY>)=Yv1;g)eHE2dsu*^<1FI5@dIn-C=iiheOjpSFOKNB-OtRb!IR_f1(d7X1dNkc ze{0c?4lp4IGHQ7!S}8Opm6a~BI}QSt$@}08owRqsL#fxiU;nUjcAM8c{Cs!u!yJM{ z#+6zhi7^*e1|eC5H88~EG90)K>Qx7-p+`DMH)V7EF?-#U}L?T@O80e!8+g>Isk@&W%92+?jfC(2s|f)S6ed# zJ)@&}Kyp8^4%F5GunP>U^~|3Y=G~Ko6G2aQhif-1D;l>4>wtUf0GK6Pe#!@)?;)HG z5ilL$Kf7pQq+aI&SZUo`X}N#6f1IHM@`493%Wk(~dNh zk+mIFvJ;izN5xv-BEt&mJqpTw&3)|(9RPd4pc?S)1e=@&y1EL&kBPBJQe$rB!t}&j zRv{EjQ7s=@az!I?nLPMd2RvH`z!ES8Yyo4y8iJkd>ViS{yx5>FcsV;=whC#nM79j+ zJ^MuDFDQHuGE>lT;5J|#U>(q?17HYP@&y@NZ-Fsb+;En)_uZY{|0r$$s2`X(ASEOD JWa7k){~xW;r=b7< literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B2-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/B2-initial.snapshot.txt new file mode 100644 index 00000000..df4265c9 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B2-initial.snapshot.txt @@ -0,0 +1,50 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=55693000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10464 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=148 canvas_frame_encoder_cache_actions=99 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=49 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=49 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=99 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=47/1024 widget_semantics=47/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=525 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=47 widget_semantics=47 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(15,14 290x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(15,14 290x18.75) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(15,14 82.75566x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(250.73633,15.25 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(15,45.333332 290x48) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(15,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(15,45.333332 36.285713x48) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(27.803501,51.583332 10.678711x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(28.433384,72.08333 9.418945x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.285713,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.285713,45.333332 36.285713x48) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(71.41051,51.583332 8.036133x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.7191,72.08333 9.418945x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.57143,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.57143,45.333332 36.285713x48) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(111.8593,51.583332 11.709961x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(113.00481,72.08333 9.418945x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.85715,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.85715,45.333332 36.285713x48) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(155.98193,51.583332 8.036133x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.29053,72.08333 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184.14285,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184.14285,45.333332 36.285713x48) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.60602,51.583332 7.359375x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(197.57623,72.08333 9.418945x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226.42856,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226.42856,45.333332 36.285713x48) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.53455,51.583332 8.07373x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(239.86194,72.08333 9.418945x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268.71426,45.333332 36.285713x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268.71426,45.333332 36.285713x48) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(282.82025,51.583332 8.07373x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(282.14764,72.08333 9.418945x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(15,105.916664 290x31.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(15,105.916664 290x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY GOAL" bounds=(15,105.916664 88.21484x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(271.42578,105.916664 33.57422x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#4489113988768380928 role=group name="" bounds=(15,129.41666 290x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#13195408868291225394 role=group name="" bounds=(15,129.41666 290x8) focused=false enabled=true parent=#4489113988768380928 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(15,150 290x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(15,150 178x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(15,150 178x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(15,159.25 178x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(201,150 104x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(201,150 104x36) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(201,159.25 104x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/final-captures/B3-after.png b/experiments/render-loop-cadence/final-captures/B3-after.png new file mode 100644 index 0000000000000000000000000000000000000000..2cc3f16c07dfda7a8277ac563d8114f30b56a65a GIT binary patch literal 256283 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 n2v~BRIa?>d7%XmRiqUH`0sy^r^twDJD~pD%@~ literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B3-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/B3-initial.snapshot.txt new file mode 100644 index 00000000..8483ada7 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B3-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=60209000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11349 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=148 canvas_frame_encoder_cache_actions=99 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=49 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=49 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=99 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=525 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(15,14 290x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(15,14 290x18) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(15,14 77.73071x18) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(254.61377,14.000002 50.38623x17.999998) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(15,44.666668 290x48) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(15,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(15,44.666668 36x48) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(28.011753,50.666668 9.976492x12.000001) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(27.880327,66.66667 10.239346x20) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.333332,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.333332,44.666668 36x48) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(71.55745,50.666668 7.5517664x12.000001) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.21366,66.66667 10.239346x20) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.666664,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.666664,44.666668 36x48) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.19311,50.666668 10.947117x12.000001) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.54699,66.66667 10.239346x20) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,44.666668 36x48) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.22412,50.666668 7.5517664x12.000001) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.88033,66.66667 10.239346x20) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184.33333,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184.33333,44.666668 36x48) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.78767,50.666668 7.0913086x12.000001) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(196.9388,66.66667 10.7890625x20) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226.66666,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226.66666,44.666668 36x48) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.85265,50.666668 7.628023x12.000001) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(239.54698,66.66667 10.239346x20) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(269,44.666668 36x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(269,44.666668 36x48) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(283.18597,50.666668 7.628023x12.000001) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(281.88034,66.66667 10.239346x20) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(15,105.333336 290x28) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(15,105.333336 290x14) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions" bounds=(15,105.333336 46.61035x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(272.36523,105.333336 32.634766x14) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(15,125.333336 290x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(15,146 290x40) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(15,146 164x40) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(15,146 164x40) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(15,157.25 164x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(187,146 118x40) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(187,146 118x40) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(187,157.25 118x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/B4-after.png b/experiments/render-loop-cadence/final-captures/B4-after.png new file mode 100644 index 0000000000000000000000000000000000000000..f948db64aad9b7e5e47fcb8fef7749b584c35514 GIT binary patch literal 256283 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 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B4-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/B4-after.snapshot.txt new file mode 100644 index 00000000..46eed7cf --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B4-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=113984000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=12700 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571609744826000 gpu_input_latency_ns=16655000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=50 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=157 canvas_frame_encoder_cache_actions=108 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=3 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=3 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=46 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=51 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=108 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=541 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,14 288x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,14 288x13) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,14 77.9911x13) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,15 54.26367x12) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,39 288x57) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,39 36x57) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.011753,51.5 9.976492x10) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(28.745605,66.5 10.508789x17) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(58,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(58,39 36x57) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(72.22412,51.5 7.5517664x10) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.745605,66.5 10.508789x17) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,39 36x57) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.52644,51.5 10.947117x10) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.745605,66.5 10.508789x17) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,39 36x57) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.22412,51.5 7.5517664x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.7456,66.5 10.508789x17) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184,39 36x57) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.53397,51.5 6.9320555x10) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(196.31812,66.5 11.36377x17) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226,39 36x57) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.18599,51.5 7.628023x10) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(238.7456,66.5 10.508789x17) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268,39 36x57) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(282.18597,51.5 7.628023x10) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(280.7456,66.5 10.508789x17) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,108 288x26) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,108 288x11) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY GOAL" bounds=(16,109 81.83984x10) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(272.8369,108 31.163086x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,127 288x7) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,146 288x40) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,146 140x40) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,146 140x40) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,157.25 140x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(164,146 140x40) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(164,146 140x40) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(164,157.25 140x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/B4-initial.png b/experiments/render-loop-cadence/final-captures/B4-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..ae9e6fe88f34cfe3672d9af78f76bf15060757db GIT binary patch literal 256283 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 SHoplL4$R5RKGA3D_Wuu&hv^&u literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/B4-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/B4-initial.snapshot.txt new file mode 100644 index 00000000..e9532516 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B4-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=63001000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=12585 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=145 canvas_frame_encoder_cache_actions=96 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=46 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=46 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=43 canvas_frame_gpu_packet_cache_actions=96 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=513 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(16,14 288x172) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(16,14 288x13) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,14 77.9911x13) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(249.73633,15 54.26367x12) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,39 288x57) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,39 36x57) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(29.011753,51.5 9.976492x10) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(28.745605,66.5 10.508789x17) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(58,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(58,39 36x57) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(72.22412,51.5 7.5517664x10) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.745605,66.5 10.508789x17) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,39 36x57) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(112.52644,51.5 10.947117x10) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.745605,66.5 10.508789x17) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142,39 36x57) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.22412,51.5 7.5517664x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.7456,66.5 10.508789x17) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(184,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(184,39 36x57) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(198.53397,51.5 6.9320555x10) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(196.31812,66.5 11.36377x17) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(226,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(226,39 36x57) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(240.18599,51.5 7.628023x10) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(238.7456,66.5 10.508789x17) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(268,39 36x57) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(268,39 36x57) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(282.18597,51.5 7.628023x10) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(280.7456,66.5 10.508789x17) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,108 288x26) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,108 288x11) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY GOAL" bounds=(16,109 81.83984x10) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(272.8369,108 31.163086x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,127 288x7) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,146 288x40) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,146 140x40) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,146 140x40) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,157.25 140x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(164,146 140x40) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(164,146 140x40) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(164,157.25 140x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/C1-after.png b/experiments/render-loop-cadence/final-captures/C1-after.png new file mode 100644 index 0000000000000000000000000000000000000000..c056892b0c30f3935127b489677971ea4b5fe31b GIT binary patch literal 256283 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 E4;X8OB>(^b literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C1-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/C1-after.snapshot.txt new file mode 100644 index 00000000..f376abee --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C1-after.snapshot.txt @@ -0,0 +1,96 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=103449000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10874 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571599206982000 gpu_input_latency_ns=15715000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=89 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=28 canvas_frame_encoder_commands=181 canvas_frame_encoder_cache_actions=122 canvas_frame_encoder_pipeline_binds=28 canvas_frame_encoder_draws=28 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=1 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=26 canvas_frame_uploads=0 canvas_frame_retains=26 canvas_frame_evicts=0 canvas_frame_effects=4 canvas_frame_shadows=4 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=4 canvas_frame_effect_evicts=0 canvas_frame_glyphs=56 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=60 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=85 canvas_frame_gpu_packet_cache_actions=122 canvas_frame_gpu_packet_cached_resources=26 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=93/1024 widget_semantics=93/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=707 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=93 widget_semantics=93 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,16 284x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,16 284x15) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,16 87.91674x15) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,19 54.26367x12) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,45 284x42) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#5743744725605747535 role=group name="" bounds=(18,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#4424186537103983558 role=group name="" bounds=(20,45 36.571426x42) focused=false enabled=true parent=#5743744725605747535 + widget @w1/widget-canvas#2428102130381644357 role=group name="" bounds=(20,52 36.571426x28) focused=false enabled=true parent=#4424186537103983558 + widget @w1/widget-canvas#5036925338709116941 role=text name="M" bounds=(33.607002,52 9.357422x10) focused=false enabled=true parent=#2428102130381644357 + widget @w1/widget-canvas#7445899412393006508 role=text name="0" bounds=(33.57624,65 9.418945x15) focused=false enabled=true parent=#2428102130381644357 + widget @w1/widget-canvas#12392041750931625881 role=group name="" bounds=(58.571426,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9042723113057631623 role=group name="" bounds=(60.571426,45 36.571426x42) focused=false enabled=true parent=#12392041750931625881 + widget @w1/widget-canvas#1911011459636458852 role=group name="" bounds=(60.571426,52 36.571426x28) focused=false enabled=true parent=#9042723113057631623 + widget @w1/widget-canvas#13495370015047273503 role=text name="T" bounds=(75.3796,52 6.955078x10) focused=false enabled=true parent=#1911011459636458852 + widget @w1/widget-canvas#11248424745687431576 role=text name="0" bounds=(74.14767,65 9.418945x15) focused=false enabled=true parent=#1911011459636458852 + widget @w1/widget-canvas#2798845554877152242 role=group name="" bounds=(99.14285,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(101.14285,45 36.571426x42) focused=false enabled=true parent=#2798845554877152242 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(101.14285,52 36.571426x28) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="W" bounds=(114.281105,52 10.294922x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(114.71909,65 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#10547606456136237439 role=group name="" bounds=(139.71428,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3755191306193106791 role=group name="" bounds=(141.71428,45 36.571426x42) focused=false enabled=true parent=#10547606456136237439 + widget @w1/widget-canvas#9426587283709577362 role=group name="" bounds=(141.71428,52 36.571426x28) focused=false enabled=true parent=#3755191306193106791 + widget @w1/widget-canvas#1591004126705514636 role=text name="T" bounds=(156.52246,52 6.955078x10) focused=false enabled=true parent=#9426587283709577362 + widget @w1/widget-canvas#423660634609421494 role=text name="0" bounds=(155.29053,65 9.418945x15) focused=false enabled=true parent=#9426587283709577362 + widget @w1/widget-canvas#15015154310066103275 role=group name="" bounds=(180.2857,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#16896545707069005182 role=group name="" bounds=(182.2857,45 36.571426x42) focused=false enabled=true parent=#15015154310066103275 + widget @w1/widget-canvas#3203703068654794736 role=group name="" bounds=(182.2857,52 36.571426x28) focused=false enabled=true parent=#16896545707069005182 + widget @w1/widget-canvas#13786191748898983725 role=text name="F" bounds=(197.40149,52 6.3398438x10) focused=false enabled=true parent=#3203703068654794736 + widget @w1/widget-canvas#13826355370529843847 role=text name="3" bounds=(195.48474,65 10.17334x15) focused=false enabled=true parent=#3203703068654794736 + widget @w1/widget-canvas#134348505103821528 role=group name="" bounds=(220.85713,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2340136145418704815 role=group name="" bounds=(222.85713,45 36.571426x42) focused=false enabled=true parent=#134348505103821528 + widget @w1/widget-canvas#9812687000789051539 role=group name="" bounds=(222.85713,52 36.571426x28) focused=false enabled=true parent=#2340136145418704815 + widget @w1/widget-canvas#6733426896005681708 role=text name="S" bounds=(237.64822,52 6.989258x10) focused=false enabled=true parent=#9812687000789051539 + widget @w1/widget-canvas#15729049687520163901 role=text name="0" bounds=(236.43338,65 9.418945x15) focused=false enabled=true parent=#9812687000789051539 + widget @w1/widget-canvas#17833843196129393581 role=group name="" bounds=(261.42856,45 40.571426x42) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(263.42856,45 36.571426x42) focused=false enabled=true parent=#17833843196129393581 + widget @w1/widget-canvas#417995898018150637 role=group name="" bounds=(263.42856,52 36.571426x28) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#9181518193224604988 role=text name="S" bounds=(278.21964,52 6.989258x10) focused=false enabled=true parent=#417995898018150637 + widget @w1/widget-canvas#2627286533109177756 role=text name="0" bounds=(277.0048,65 9.418945x15) focused=false enabled=true parent=#417995898018150637 + widget @w1/widget-canvas#11042477908510433656 role=group name="" bounds=(18,101 284x27) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,101 284x12) focused=false enabled=true parent=#11042477908510433656 + widget @w1/widget-canvas#10422795391015277995 role=text name="Sessions this week" bounds=(18,102 106.43098x11) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#3469744615432886383 role=text name="3 / 20" bounds=(267.9273,101 34.0727x12) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(18,120 284x8) focused=false enabled=true parent=#11042477908510433656 + widget @w1/widget-canvas#14075969226659233625 role=group name="" bounds=(18,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#1753948002084364320 role=group name="" bounds=(18,120 11.35x8) focused=false enabled=true parent=#14075969226659233625 + widget @w1/widget-canvas#6570805353255671499 role=group name="" bounds=(32.35,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#17656023610392828897 role=group name="" bounds=(32.35,120 11.35x8) focused=false enabled=true parent=#6570805353255671499 + widget @w1/widget-canvas#8701200248999500261 role=group name="" bounds=(46.699997,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#10966752483795794170 role=group name="" bounds=(46.699997,120 11.35x8) focused=false enabled=true parent=#8701200248999500261 + widget @w1/widget-canvas#13527403412610651720 role=group name="" bounds=(61.049995,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#5753417367632498755 role=group name="" bounds=(61.049995,120 11.35x8) focused=false enabled=true parent=#13527403412610651720 + widget @w1/widget-canvas#13635469530840347363 role=group name="" bounds=(75.399994,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#8637756170459363286 role=group name="" bounds=(75.399994,120 11.35x8) focused=false enabled=true parent=#13635469530840347363 + widget @w1/widget-canvas#11783282374073923389 role=group name="" bounds=(89.74999,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#2559976082750952458 role=group name="" bounds=(89.74999,120 11.35x8) focused=false enabled=true parent=#11783282374073923389 + widget @w1/widget-canvas#17029288176560108917 role=group name="" bounds=(104.09999,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#410150582816905342 role=group name="" bounds=(104.09999,120 11.35x8) focused=false enabled=true parent=#17029288176560108917 + widget @w1/widget-canvas#11205498459203833176 role=group name="" bounds=(118.44999,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#6316788077998381370 role=group name="" bounds=(118.44999,120 11.35x8) focused=false enabled=true parent=#11205498459203833176 + widget @w1/widget-canvas#2246091263593899101 role=group name="" bounds=(132.79999,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#10406161108069067221 role=group name="" bounds=(132.79999,120 11.35x8) focused=false enabled=true parent=#2246091263593899101 + widget @w1/widget-canvas#1426319289549790707 role=group name="" bounds=(147.15,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#884567278473380636 role=group name="" bounds=(147.15,120 11.35x8) focused=false enabled=true parent=#1426319289549790707 + widget @w1/widget-canvas#14540414246768961099 role=group name="" bounds=(161.5,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#288233966561996061 role=group name="" bounds=(161.5,120 11.35x8) focused=false enabled=true parent=#14540414246768961099 + widget @w1/widget-canvas#1625034029865857546 role=group name="" bounds=(175.85,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#2837332745728423667 role=group name="" bounds=(175.85,120 11.35x8) focused=false enabled=true parent=#1625034029865857546 + widget @w1/widget-canvas#17008002128939413576 role=group name="" bounds=(190.20001,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#1332974331711251147 role=group name="" bounds=(190.20001,120 11.35x8) focused=false enabled=true parent=#17008002128939413576 + widget @w1/widget-canvas#1999499713382163045 role=group name="" bounds=(204.55002,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#6559351030723410460 role=group name="" bounds=(204.55002,120 11.35x8) focused=false enabled=true parent=#1999499713382163045 + widget @w1/widget-canvas#17641968588901846976 role=group name="" bounds=(218.90002,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#8818928649754076621 role=group name="" bounds=(218.90002,120 11.35x8) focused=false enabled=true parent=#17641968588901846976 + widget @w1/widget-canvas#1272434707947114252 role=group name="" bounds=(233.25003,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#16298232974652290698 role=group name="" bounds=(233.25003,120 11.35x8) focused=false enabled=true parent=#1272434707947114252 + widget @w1/widget-canvas#4920910613241451683 role=group name="" bounds=(247.60004,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#11370141573566754118 role=group name="" bounds=(247.60004,120 11.35x8) focused=false enabled=true parent=#4920910613241451683 + widget @w1/widget-canvas#17897000519267774779 role=group name="" bounds=(261.95004,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#12956105731744913870 role=group name="" bounds=(261.95004,120 11.35x8) focused=false enabled=true parent=#17897000519267774779 + widget @w1/widget-canvas#10135565979688493150 role=group name="" bounds=(276.30005,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#213595096875862979 role=group name="" bounds=(276.30005,120 11.35x8) focused=false enabled=true parent=#10135565979688493150 + widget @w1/widget-canvas#13701739376575018508 role=group name="" bounds=(290.65005,120 11.35x8) focused=false enabled=true parent=#11464198168306097265 + widget @w1/widget-canvas#10889699711043493040 role=group name="" bounds=(290.65005,120 11.35x8) focused=false enabled=true parent=#13701739376575018508 + widget @w1/widget-canvas#9833334659390856017 role=group name="" bounds=(18,142 284x42) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#7085761552478848393 role=button name="Log session" bounds=(18,142 172x42) focused=true enabled=true parent=#9833334659390856017 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#9045096818664730114 role=group name="" bounds=(18,142 172x42) focused=false enabled=true parent=#7085761552478848393 + widget @w1/widget-canvas#17636400897664816725 role=text name="Log session" bounds=(18,154.25 172x17.5) focused=false enabled=true parent=#9045096818664730114 + widget @w1/widget-canvas#16583274180877314111 role=button name="Reset week" bounds=(198,142 104x42) focused=false enabled=true parent=#9833334659390856017 actions=[focus,press] + widget @w1/widget-canvas#5650537466637369561 role=group name="" bounds=(198,142 104x42) focused=false enabled=true parent=#16583274180877314111 + widget @w1/widget-canvas#14761013090513811271 role=text name="Reset week" bounds=(198,154.25 104x17.5) focused=false enabled=true parent=#5650537466637369561 diff --git a/experiments/render-loop-cadence/final-captures/C1-initial.png b/experiments/render-loop-cadence/final-captures/C1-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..7a6380400b452273248193fbedab877e06700f30 GIT binary patch literal 256283 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 B{#yV5 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C2-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/C2-after.snapshot.txt new file mode 100644 index 00000000..48ae72fe --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C2-after.snapshot.txt @@ -0,0 +1,52 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=103982000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11906 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571605425278000 gpu_input_latency_ns=15884000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=53 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=25 canvas_frame_encoder_commands=168 canvas_frame_encoder_cache_actions=115 canvas_frame_encoder_pipeline_binds=25 canvas_frame_encoder_draws=25 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=3 canvas_frame_opacity_layers=1 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=3 canvas_frame_layer_evicts=0 canvas_frame_resources=24 canvas_frame_uploads=0 canvas_frame_retains=24 canvas_frame_evicts=0 canvas_frame_effects=2 canvas_frame_shadows=2 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=2 canvas_frame_effect_evicts=0 canvas_frame_glyphs=52 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=56 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=47 canvas_frame_gpu_packet_cache_actions=115 canvas_frame_gpu_packet_cached_resources=24 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=49/1024 widget_semantics=49/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=598 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=49 widget_semantics=49 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,12 284x176) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,12 284x18.75) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,12 83.916756x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,13.25 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,42.75 284x51.25) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(18,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(18,48.75 38x39.25) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(32.32129,48.75 9.357422x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(32.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(59,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(59,48.75 38x39.25) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.52246,48.75 6.955078x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(73.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,48.75 38x39.25) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.85254,48.75 10.294922x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(114.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141,48.75 38x39.25) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.52246,48.75 6.955078x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.171,69.25 9.65798x18.75) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182,48.75 38x39.25) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.83008,48.75 6.3398438x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(195.91333,69.25 10.17334x18.75) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(223,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(223,48.75 38x39.25) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.50537,48.75 6.989258x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.171,69.25 9.65798x18.75) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(264,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(264,48.75 38x39.25) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(279.50537,48.75 6.989258x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(278.17102,69.25 9.65798x18.75) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(18,106 284x31.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(18,106 284x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Weekly goal" bounds=(18,106 67.66075x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(267.9273,106 34.0727x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(18,129.5 284x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#18430945474527397889 role=group name="" bounds=(18,129.5 284x8) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#6248736432991328966 role=group name="" bounds=(18,129.5 42.600002x8) focused=false enabled=true parent=#18430945474527397889 + widget @w1/widget-canvas#2139703770174480235 role=group name="" bounds=(18,129.5 42.600002x8) focused=false enabled=true parent=#6248736432991328966 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(18,149.5 284x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(18,149.5 172x36) focused=true enabled=true parent=#5802963363624800140 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,149.5 172x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(18,158.75 172x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(198,149.5 104x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(198,149.5 104x36) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(198,158.75 104x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/final-captures/C2-initial.png b/experiments/render-loop-cadence/final-captures/C2-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..9cacaede9c36438640740b3756fb87300afa015f GIT binary patch literal 256283 zcmeI52Xqui_U^Ukz4Oj{8=Wv&2<4nJLV=6`0V3y|OwJNHgTcmO*ItLUal`=!jIoU| z*k0Rfd)Mm?|6O~7*LjUJBaNhyPyl1*-LIt@ie_dsJ<}SsG?#OV4i&ok)>ps2Rn_Xb zbxhIFpZ&PUj{^b%el~pApyGglALY~jhyVBg(Es=U@62NX|Ev6);e!gsm;5NeW}|a@ z{7Xs83`$MUo|&57@6Pm$ekap2bN-T%mGcz^69qE|wgGE^HQ=EJz>u%N6tD%10c*e< zJ=o=O8Of=cU8o{!(=u}2Ov}hNCnTntqhbmRoSOZ>Z z04xDhz!oqDtO0Yt9xw4W~hPh&# z(>P>IPR*bpFXsA;f5TiyZX?zJYe3cj*ae1Zh9Hr1CatKL`(mLZkc`TKZNM5}4Rk;a zfMH-6nC8^mlOvK-lm!n{aA=gN7u_%iwgGE^HPDeY0G83hhzV?yS?6${-n4!*JTi{q z$MENeA8Vk~XaGzD+Z;kqoJ>j0+7g$LV(!Sa=eo1E!Wv)=IMM*v2F3~AUA0Y0$q1r9 zFEIttnAuTgKF6YB4X_3}vIf95Fb=G{3Vt}Cm6AK~cXqu3g9(5f*aoZt) zT?N3zeZVPabO#;23P}~ zSOZ`km}duIN?P`tSSs#GH|xBpPxJMX=J!BL2$KTq+d?9P^V*@`tak3N31p|jl= z-;Z~Fi0#+*_5kg#Y5p!9&*ci>Rn zM}PeDMLq1!Wwd>#VHvNpu_4d0L>KmGD*4p#7H_p7-M0FtJUCA?f$_&d#AOHCx z(tQ2Re}8!F@uT(h4v#&}zdrl?(#Fy)RyogCly2qfbv5GL+>F)%uxyLzk7gp7sZ?MVb@7TG=ifhB*qP&HRmR8r+)!U+D6P0?5DV|XIhmZcG zly5RuUVfV3PhYOJmydL(UVo#hs@i%PWxf5*dl#~@bE)x~?{oiwLoEPoJ`SS4TRi*b zZ<{{-$G^Uhm+n=h=j|1Jur0LNqGZ!n>!c~uEzqn8v=VCXPqIBnj2c^+S1`z~dpSoZ`UHTW?!W&1`K5Q>egDGDS@WtEE?!#w(I5YG@y~zxpNpa4(MlZ(1`e$-S5{qq z@uim=(HQd=E~);e+_DLklaGQ(l1Uu_vCYM?64?dC=dz|N9Gb<}IumGj>Ad>!;5&ee&r)zo*Z7EBC1e z;0rIFX#D((uP@POeC&`E*XFIZ4$tyGV;7kkJ;<5Zzcp9w6!TGp)HP&01)WDEL6A;Avk zksdHxx4yInBRx1Jixw}dmdlp+=|e1K%a*UMM*dMn<0>akA`ei9J_6=}eFVVluP~oIIpU*|J|$-&$1sKfbp-}~Ug6GxwEP^XcP0l*C{ zWs36xfZ`Y)*ymq~BWildrzs_%)@MAuoo*c&g!kkynn#K8C}$9y+YtCoO^~L*Tvp z4%VV4|98tt~GA_6wBQCi>nX^08StPI!dSY9O?@80e~j0nVqEv0AHd-5NGj6 z9(khvgAYHt27v$i_kS+kcK9v@3>Y@j>ml{d%D{QW1Ee`XISl}YhLF#VEuLfnOfh5z zknkjuK_5Z4C#0#bblz%}bODnsBH`T-Mh^ZjVm2_Dca^1N{Fei{z` z=ku>FiFj<`mA!uYY?Ckqyu=57bHonG%o==MA704%vIG%lV_s3YbsaZi{d5qXp+CdFg5 z4CinyOI6L~Vj3dgN%{Lfe0=fM*G@Ny^t@#N>ZJhy5c7QM^1J~cpaq!9WiDO5sv6LO zH@B9CxB|9fi%}Q=xO4ZuT6!1HUY`ZDz&Lp5$O^eE>@Q!rwgyg%04ZRI#ZUAvby`o3 z!9Je?Fd-?;^aTw|-#Ghr6D`YIrqB}ld+&dE0gD5n;W3IqF!Tf%Fee8%VlLqy|NQLx zyY9Zn4j{PGpZ({{OBkA_kt_Y&^T!+DaR~sTu>re#?|blkc20pA<(xSATH|S2adu`X z38qCTi2?wg0g3_hU=y|$hL5dAfb+7jd@f#bftLhG(C>PZp|0ea zHD`Vmpon;^=E4hWeu6cpq0d~K0KN0|jmoPu1jO3EfAY`oSFT!1?tF8ax$_rQVIB}= zApG{7-(7%fF5=bO?3`vV^0)N5iipF?G!{g#IxEhJEmouchlar@8$;O_j-P166IH}x zf*HUS*T;PpjTujk-dw+C0AfD$%6;SM29RUrT0YPFS8T+#&~A$o(v{qQgbm{ol4%IM z!QN+Ze)7~AEpvcDWur;2Sga7~BHd`?rgrRY> zw-`hKj4Q`EyjBKaZl;xEjM(I|o$Ze*DyBKWsWbn~S+(=-=Idz=hWgOTBtO3@5tN{#N z=~WT4e9qf_`jgmlEChO6jvo2JKD-Fc0OSV%KLA++ey0HjAdBAbM6ZYEz-4p}PniM8 z0Av8N2K-h7Edb1hSb01!*v-RPz{unkxPtO0-00N95QqA~#a0l*JH)_~t>fC0#&_dC)1lZV6i z>e{1c05Sj>fUE(()j$gXGiV4LNJikmHed~~2K+|@_^3)iGJT)FTX(u?4r~L~0BgXH zGywMDXE9A(>83fb4Oj!L0e{i}*v9~5`18Y$HQ<*T@Cg9%*?4>=9$$&Y_y6$aSbajY zQYOmAHN1IpaUG+|{l$)vLBXc<@NjcpbY#V#*eD9oI)$hTl!>x&4c4Ql{an9(-C7&8 zDF6YLX6Sip2yOXrEv+ErI$mqz&T29kK z@}Tq!^rhDpZx0@yZv(FF&b@FQUAIeTvSU(csHxf8gU9FFfNQfJU2Dx9M!2g-cWf=v zB&DQd4p3hJwkKGGAzL#R*U>#eb_P4PC;S9#TZ16$Q6D`Du(`Wc0Epk+xVc;JGCcx* z^$DN6HbOvM9NiPwQCs_TWIIOm>1!GkLmr<20_wtg)TTX09C4;cN49P49M~72Cjf)# zcRw9fx;@UJE{+Vqb<`%pj%>%=s0c&A4**78SdZGY=ZG85^ytX8t)0^qfJXAHgyGar z3$CMQ0_=!(G?MoxJW#b4$a>UAkF9~uS-h?Qq#pw}jQ1x1h&stP&vo=na2?T(X<=bz z0Uo1lQ76`;XBrfJ8e6paj5E(K8~d+gc0xxVjV9re+TY{!8y^tQ9X z0_r5!k@e_#yUTX;bU!gUjaEXE2!LG)eqM$UdK=k@LB1~|)(>^!I_jex*^Yzo=N<+O zavfQZp0~SfM^E>`zJLV!uM5G?+kihKFk+DJ%ZT+uow$zrXh*i=K!TqUgIq_}qv!1| z+tJf~u#W*~0C39<$elu;PGLm&p-yel*3q#^rnHP4vtHWiXmyn9t7YFX09?IxW6iwz zi>u`Z%*!8KvG2g4+N6|BlYCz5zHAV!dDZD*uobJ;)*$TObD&o2$HXPKdmSUA6HJ@7 zY`2O!PnbB(vU=@?8gV>(&Vs5zLq=4HW3AhcW=A~$cy86WOMhE5>Y@k_j>$XkZMk~d z5p6hn>_p3kk}cLnOO{u!+pwu7JEy>F5O%aW%JtQZn45s5NWk; z^{S)#x@~1gZ$X9p0H7Y_$Ytnl$IV-JTJi9MUEu{TU%A%)&{Nym-Q$i{N4dUQ_FDj$ zN^^icX%5i45F8pw@bWCcQ<*z|QT4FGqDqtz5fx`D-L%!ZY{lvte73>Ua*N>QQ z9S257&>Wz5;oPcX0-$$gsPpS>$JO-E8$EV{B_<9JH_zKw&fC%IDA!lZenL_z<^YWW z!2WpyE8w-DA%>4As+>A)R@KsFtEw4*?u$Anx1a(KlI)y3^IV!z7&2@`<)kUoErW*^ zD)y8`u617)me#zk(i#3YS~u+7@wGGy6NVgW!{Fq^ar?}20X>0ViHYj*O%7BC8U~`uUJ!) zl9p}0g#d^lou}m@pL}25l%vjDLLQ*{oTtZn)e&Et-LP@9wRrqw3%qH}O|D$Mu4cxp zdE^NWuJE*e$fs8w)pckqI}RYv&D#JE(AzT9`Sr9T+B+jF*DP#`A@JID@bsfR?u&Z2 zwJ+)@+f>Uw*cV_V0K%1@IeUK98fru|1Org}Lj_(lAQ+#RraU;-(L)8tVG*&0=@g>F zV#@&3-p0ay0Nv&-JFK)&s6Y^ZE4FF#cA86%GmO*Vi#lq7o}AWj0EEY~XWy;0MPtTW z7=WI2j4{O%Ev1{c*}YSEe=BHWTyz>wx3X|NEyGbh2B2r{ENq$8FWT>fP3DT}QdTTJ{YCKu;RU-8`~E+|A?bbX-U8ARyXHwxfFJX_RBRj-uXr zY_Y!~?qt#KauaceeqZ`?d1ERxe5yW^wt|RNw^LCf*=;^)!K&-mn z*ri9Aw*kMcXv84jml5lSI&mHK(T;4#f~fEcBL=yStVhq=UACjA`(R%H1JLtE&`ZE_ z1L{?#-sN<(IvNpvs8dI?qux5wt326`p6)XM4dS)R4XBqu^e(5P)sX?{`GdWqwY6Md zE&B{W2B6#17P7GPhO1uX$#rA^G5}>gINE0bG5{HXKAtO-JEC6T*SnmKR!6zMTJ~E2 zm_myn-DwfTyATu{PMyhkLB1~|)(>^!I_jev*^b8b0I&2j)}!a`F1NL(`*8^=vxVjV9re+UY{!B~S_L*>kn6~L^t|0=J9@eg_65Y!e>V{P zybbuhI&T90437Txx8~tT9(9 z7gc#@VZXW$=M`S~WO32O`-^hVk57uRcvB|wvL5yC*RoBu?1O!V03hZt9)0|1{i)Mu zno8-9xl2m7T2H=ms_EJ1UThFQ2I^_2lMUi&8OX2R_^yeWt4s1E>rWk+uy^{bINbqyOPU7na6YxnpHW1}j+T~U1LwP`~d zy(ydZsDHnfZK`G8FaUhv#S@LczVE^FYCzp~_^!IwPoHg4pVx9M8$?S!by}{YJ^=KU z9le1Regov=1tTx0%XneZz=qm&6ECaJYdK~;hL`KzuVtHR**63L@dwc#{^5@oSJ3Bt z)X>52f_(g^zg)z}Qq^(p9?J%CH;+0U*HNFjRA1Ur3zXDp0lCL$*sDIjb5MpAUx%KM zbj34Nr)lk&^%!2RcfXcxs%5_gfXTE7(v22DybFE$hS4I3_K?*tuj1oB|Men1gRjny z&*UR+@X!(0#HrIdJC^UuS(?_)a~;EIG3kmvTCe9R$s5bv0It9AuuSc+>?M` zwE81?dH52vI{&x{Q!F3<>8}^@d3<%8yT|fNt0gS&w1mdiQJDrdsw51HgOkec=4@mrgdSJJQjoo^5#K(I@KF=d~Qm2GNpF zotEpU4*-2-M|XkbDBUSq={3=B0;}WxFmJ?#e=aHdUVUE6G3zm`TWGVE~99 zb$RRUcQ4#}@Nivbc3wq#W`8qYe|hhBA6~$(Ua4WErwxHE!$MfzF`0e*bE(B zRC(Vou2F13_-PBv>yAyj%uiBJzkudSp6ye1qkN+ z5HKv>J|NwywH$SN)}#LYTDGZ{{T2Ww(IQA!S_JVf1O|oDB8c~aeyrF`KZZ_TpZ8^< z4EetFDwFG|PusMm9rGeWX`aseFgiZc0uNA+vQQ`1qdwY^?da)#Y+RBlAcp?p;<_8U zmU$a`1qPS*?h|ULfI7+d#dY+oeLA8YvqFO_^1?$66;LPEqh}hF*`n5?Y*Q`!V4ncs zIm+l&=-xA^j4ElUfI7+d#dY+oeLA8Y6N7?GMgt(~#Cr5hgECvxdX#OdWnWhScIn#d zoLosG?4wSyLAZ{diLWEtF}O#sa-#tdbz(hwra_q}YCXy})v~WE0CC}7fgy(R08tl5 z#^5??6JSTSBMmvtMu8ye!g|!EJsEmp-kM{`3GCDEbAhM>>(M>U2~W?_ zwlzJvvazGM762xiuDkx`b9#nu-2=;dV>sLn0oQitUbv2~+ov)AWF3}bd*1Y8T()N&tO$7|cB zv)Zw5_nzfhA;IQcf}k$~u7zu|9DW2{$oc#DWOjv69CmeEJQaTqAZk&vbBOw=um7~kNW6Q*wfk8CjfMIaXzoV*UdI% zo3aMn*8l^s4TkBZw<5nFo709x==^pz&2nF zum=1`1JSVwrhurJ1k=y2>vE0*+kiE|8t^9#fPD-=hCe_2SOb2k0R|uo-!FylPhJk+ zt8=fO0muMk0I~-BRs#$`rl4^t$N=QFVGXpg1{45B zM#r0e_KTa&abO#;23Q0BqyexmfC0#&_b1Wwy|Uhg1{i?s`LgHF8t_{UFaTNnek*?A z1@P8?JwgT`1CRm88t_{UFaTNnek*?V{QTGR6K&rNz^FLW&whU6ISy)j(QCj(PotP1cPiTde*17gV&C@A@0NoqPVp6OHuA>oPel z{U}KJq{%ZZ`w!e!w{Y>&>YKauzA8RCHpz6$vQ^dFw(qVTK4NsGoY&iZuunGtcJ1D~ zZ0`I;)uK}Ln}20XmaeSs(>J_aoSQOjR#o4SNc*uk@6HwmoH=`bm7}!z1BO&2CTEx( z#rg8w@WRoR5mE8{K;Z{!r*48={GH2KKWYX<}Ev{<0ee8+g|}3{{K~0D zKvKkeyVVtds7&dmZC3hCI|Xp5Y1w8_9dJV24L5Z!+qr9BEqGVM|sB< zPqO6X4rui$v>OH7JG%V1~7ki{KUz|f`LQr{Vg*)&;06Zr<=%0 zxypN!^8tQevA@C1m8$4|B_T(q=W+(1H7x@pnkWp;YQQ(C%wbq(l0VbU~tr$ZMz@jnZExCDvltz#NIAGAQiga?%MS0md`4u9aI48D%^y)PmYSwSu zY#lgwct!EJN%nfcb6r67-@0v=b=I5(RX29&VQ<{5etG6qlyCLg4K=d+&j4gt2yJ!N zZCFHX`I)nCH_810pKFGvhCc4-zA@~@@E4;vNAcoZcx0UE%$sjFb*1081qT4b_{7w! z$~^Mu6ZNA;kGl$_BEQzH?f?WBrcR%&3{zLGUSAU#onQjsP_d%X<1IsnjZ!KO;{kA} z0KhhjhPH!;j!@!878O@co;tJY26~#r#w9EHVGJ37g(JsQ&YQou8s|~A48R!5gQ2%D z#`2YGYhYM$EVlSrxh-3FTG620dIXli#a>KLB*fz>hq(>F9E~=nc%lUmL|osHh;qz* z;Aw@QrCYncq^3*Dyaof10VwpAcx001S_eHT~pg zH=NTetf5I!Op*cyC==cjhNZ$2#JR-ebTcRpZ%qVI4@|0N^~?_3XIukAQE?0p5%UcQ!wQQk#d&#~M2jX1X-F>4VVI0L2^@!nMU`V{ zEaGtO?K_(R2=^StykG|&mV7uC#Q~sqx9s_XByxvVP74Od^9y>@4tZE ziIcB3=JX$6@9XM3T8_b-00AB?8C|8t+#ePz`sWQ)Dv3n_9AgM6^1-9RvNm9XbAT5X zORztY<^wSd#y*TPd+vfNcz=MGTxy!)Q>cn!{xO>V#A?z(NEfu0E;0jJUw`*Sk70cb5;*$=hgZ7m;u;XHGn=OMsber5%YJ?KKEjSw|xcq;b}U$ zhBxO70YGnVz*$}lMa7D&t91^y)s|63j>e=$N*#w_^k#QfGmE$6~8Y%4ZfB! zy-nQ#i0^{+ptryAHI<-X4r~L~0Bb-W4S*?N3mBu<14UN=qGAj_eHxoP4cn15;8+7- zj9w7b6@Z{KH=5%{W4o|jSOfZL0Ibo&3)B^W?EUH2z}#8bmaGBi8USk;fIP>@^Q^1^ zztn&s0mwsO=T9ttnzLSp$wWVAw?vjL88((3$509XB3} zn(e|G@Js_>3fQ983NU!3>mrCAlagG9F<%(vcHwsEj2d77@?V1J_EKqQ>>zwkog4fN zKn5TKkTu}98ejmj`2AM=?A>*4@6Mg}WdJe&8Gx(-ztsQ(kj3w};&;bG;541vOJo2t z02zR+0l(D%1CYhD*o-1CRm8 z0AvmLtp*r?EPlTgKYMqb+q-k8eSHSNHEEINvr`Iczg}9@RKI@050^`)*le3PunqLn z05k<{L1WMwH0Mqy@FdO8uj_KIOV?gyJ$m&m3k(YN%Wv|v#YY`rOV|{)g^fLF8!dU- z9Doqvrwa=kxTEXW(b<;n+Y;K-6NKoL-Fx=opMLPshiGBzwgh3D0`P_6oErA@-0!Rm zwzjbqGzcwf@eCZLy|GIV2A_|>r}i#kdq-{J?YTAs;F&1}b=;xbrbBl?yZ-2-^3<+| znDc-zJ?%9Zm#KRuAA9z3KTqw3Ht@9loaJj13eqFj+5vm2Av!7Bt!Xh;I{9;Y-8_j46U}- zS=jqC9{dCx_3{FB1t3i_pXbi$edlBww!ICZ)z$#W3m?V>pk50ix&iRVKfS)}tEEL3 zxbwDs=VcpvZ)0c`nso(1yp=0F4&E9IhG-jCZRc*BjsU!_9IxVY=k&gFvJKnbhS2Jd ze|lZHtB%5d=3y-8$qym4jjOhEH%>nQ{^U9nul}}u$7ML`V`FIb$D~6~mw-`EkFb=6TAdd7pE+$OHt&fPe@09e*p0BBh=-uB0N zg`N7P=nv)$w^`Rs=+yV<&O@XHfKKO<702Fby0$ zywV%{Im_!V38>u1khP$kZ_)%K+muQX=$%Qd%E z`K^`908{}+i$L2WZEGH2V|WdgQSu>R&&7w(0I)-g`bZJ=+egY13y{JxreC%dfoFxNrZ#+RW@LK+Dd_ zulUtH_nkle#@Qx#m&N0+fcE8+uQlR4!fUU;(Il>gEr#LGJ%7A$WYJjr@bvH<{?YRjBwg`faGXVakD91K5GQ{>BrTypPB3nZ5 z-nL`o3zV`bEzVQo{;_zJ0=~a58mZJ{dQ!A)Wp;uRhkD8Y{3qo_xwy`ERMuevXOEk1wtcm1 zjFKJzy!nPMw!MSWZ4DbH+K$mZ0sJ!b^#YQw%V{qFV(1I_tzBPYMW-J!Y-Hu}mrfEC zrdr|>QcNYAwpt&1{AfKOg5m2+FTc`=`NNpFB-7?CJFIuy^(zHZm|uJPndcf-tXf+W zN9m?an^|?@&uZ<;}tvhz@tp(s7 zKJr-omaRLiiOK2aF=HoKP~YJrMl0}Kx1rSfn};5$&!OvP=j2s9_|TF1^&2)R<;nm| z%jjnYBxlZ^r;F$73T*DiF#t6H@M6g%+YQ&%8`X@OB;O#>*ZNnl%ZPjbXEBOJPPZo_*_K%IvS3EBn3IoWKd~9s45`XvbEZd-n z5L*?&5ox|5&lAAI{_p1wS3J}&mo`HT<;!)J0SHeK<;d5`3hrZjU{sEB4gl;*00jJy z29WQ0Q&;5yAm{0b`@RIAm;=N-;HlToG#$GA&bpAWC$_Hpz z{@`zp)Q=cBMgbe@JhphECA(i<#f!&ZZp5`kxm(EN+q8MRQs<{=j&C^CNyLqzJWn2d zMw#~$0E|yeHR0Tnr7P@p6X`wOx(hj1=@@_-00?ghfV)^S*$#|v$Ri^I+s?0_Xgf1~ zuq}){J{bo0jqK+XfPmLB8UkZzIhY`H$FMA0eG6!I4@^_aMcH!LNI*sTSjAmIo+gIk z@GuV(Oi>4M?E{0;Z5SG3K?iwIPZ1{raAA6!ZA)IW2P@)Nk+-;phW0oH0OM$QF5<9- zr}~~WOqSz1(!MVNxMJnn8nFtD;p0=}xlNurL-B;}y89kw2rGuGVmoO{bNsA1^Q*`s zYydzo)a;)(P=VpX#Y?M2T6w#B&;D8g6;~c$SVW8o!{p@DOmhi&f-6?8sew1Sv1E%C z=T6d)8-N%$VTwgAU+lw+MZ7qcw;0MJ4gfs%{ELlP2qKU-0=lAZ-fmri&D}T#pauY9 z&JF;?+??p>FHat53+dKfImRnAKP6xZFAiyn<06~_5apE9Q1>#W!*F_3OqdNrY~*{A zhO?OW6W391|4c)046|__dB?^^*rp{#DaW5L9jy$D5r?7rro3cj*o*7noD9HQ2WQwu z(wwDSKIZ%|cZqWhK=0p$L+6(lLD2CR-?F?KULf}2O(8e}0zj0TKS%){=KGNE4CvEjCjrhS~bit1e#<2yy(@%%L<)?_u{`WdH)g znB&8ICDH=CUFaC|h&W~dwhaI$OqyoFTp2oj(dcoO7mlB396Yp88AeW=Jk4_KxfdHS z=a-R{W5(hKz=X6|(LH|RWFzJV5im5Jw_tHKhQt|J{modkfTt;7f*~@7x8hj6#R3cF z@927seM7D+j^Nz%nR65m6=egotJiF(!SEcz*(aWSx&e7n-nQ+#Ywx0k8w}TxcF*1e zwfheoQs52%K6C7OJES+$JmOuyyvM%yqppvZV^?5vH;w^Fog5uq1OSkXcTM;uEfOFN zU{w?oZjYav8e?nPILV$LX--TUsI2HdNb_iq)0`dBi}K|yhOx6!qHW!15dzo5O6Nrd4);{zqG>pbMH3N+;qGjLB^EG{w?BD{pSH{&BF#1eF&1DDmp~AHz6EfI zlL3h1r^e+eLwBSFD34DXV80Fnux$W1boi*sXP&(R1`KDhf(mcx$fHlxBVNE@;i9G0 z82%y-dFIm!vWNpT0VBjcd+ddVCAVBX$2Mc;+$t=Ts8@kS{@C~=(7t$#mn8I-i8BUXLvP24F#>o zf1{OH3~S*{!E0NalW4m@tH)Z);q;z8nB27+v}!~Eiq6g3);({-0gyk3)wZ41-OkPF zT5ktvwKV|p=dfCbPv7tAb$|mxB%4ggQ(>J zG!gj4Pk(-+R}+d56Mqul7@eCT+j=`dt1SR@s(bz}QQTy8nT5auvsQjZy#s#1rKZ*qAfqent5wXW_xT(9-@1nT{ zK>EBmJyFe{EGTT^4&MG9oZG;88$hGbYHOdwhwk}jF^va7y?z!G%me!Z=sli8UAqT* z3BcXNJY`?{PK%c(}#3yjPDGYh>GlLKp0xyU-?tl!Y_OnaN!iS4_8?d?2ZGX$IG0);2Y!{PSp@C@5#+e3rG^HaRPR(=js?j-U)dxGr;K|MV` zv}w!y-)RMY_>acID|!V6d+h~M;bmed46$Lpg%?H`g6#!kXiv=fDe!9^`fBq2WC&vZ zi5EtE2SV6duQ@-t9l<&<&kn$lu;`m;Nw{2}i(P*e1O*5&1i=facnhCBLx!T>P=uzS zEocl{lficde%gk7r=u(o+AqUv1`r+xwn2Mqpyibpy|nGsJF}{O!e!Br)R#5^2Qi6*>NBVrh#o&!OqbE4TY026u$n(Zfy-g7ORivKe)qooDR!vrC(ctWndcE z=7@RMoWmQ^_}M-^=L5Mx^=nYJCEJoU;GPD+FtAMdtB-3)=i&t3lfh@M8G`N^ngz*r zVhtEe17H^zcGWw7E|_;s6f%OIJRCMw!*WOC_FxUT)&Q8Lcz*H=&({#njT3MkF@E;J z!U)d^@|+-RfHmN?29yO4VwUD%uQMJh3nR3Gf@NeL61#r#@ROPC!y0HG4S-Ex6jpoP zUhr@RJxAy9o*=wIyiMI!f2zXbX&>>h-P!IPRRdrVm;^R~QI6Q9+c_d@AYJ4TE`~oU z*5fNO9o6t$Z-xeIp#3xe_JBbx;5!61=?1#i3c?=~W09oA-7JUeiLb1pQgB7R{h=im zR{IHyZO^thk_NyMFa>M@W561Moifw~gRc3oL2K~RJ6`b$X|Y7{4Cy=jMC6Ytd;v03 zFmYfTum)HI9%=v#0ZTq6XX`i^gT)QKyuFwUXG;It{kwT!;_$&mgI*Xgd)NO5bg0zJ literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C2-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/C2-initial.snapshot.txt new file mode 100644 index 00000000..d1055857 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C2-initial.snapshot.txt @@ -0,0 +1,52 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=58494000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11791 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=51 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=24 canvas_frame_encoder_commands=153 canvas_frame_encoder_cache_actions=103 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=24 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=24 canvas_frame_uploads=0 canvas_frame_retains=24 canvas_frame_evicts=0 canvas_frame_effects=2 canvas_frame_shadows=2 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=2 canvas_frame_effect_evicts=0 canvas_frame_glyphs=51 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=51 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=45 canvas_frame_gpu_packet_cache_actions=103 canvas_frame_gpu_packet_cached_resources=24 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=49/1024 widget_semantics=49/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=562 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=49 widget_semantics=49 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,12 284x176) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,12 284x18.75) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,12 83.916756x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,13.25 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,42.75 284x51.25) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(18,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(18,48.75 38x39.25) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(32.32129,48.75 9.357422x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(32.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(59,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(59,48.75 38x39.25) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.52246,48.75 6.955078x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(73.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100,48.75 38x39.25) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.85254,48.75 10.294922x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(114.17101,69.25 9.65798x18.75) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141,48.75 38x39.25) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.52246,48.75 6.955078x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.171,69.25 9.65798x18.75) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182,48.75 38x39.25) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.83008,48.75 6.3398438x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(195.91333,69.25 10.17334x18.75) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(223,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(223,48.75 38x39.25) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.50537,48.75 6.989258x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.171,69.25 9.65798x18.75) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(264,42.75 38x51.25) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(264,48.75 38x39.25) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(279.50537,48.75 6.989258x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(278.17102,69.25 9.65798x18.75) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(18,106 284x31.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(18,106 284x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Weekly goal" bounds=(18,106 67.66075x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(267.9273,106 34.072697x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(18,129.5 284x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#18430945474527397889 role=group name="" bounds=(18,129.5 284x8) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#6248736432991328966 role=group name="" bounds=(18,129.5 0x8) focused=false enabled=true parent=#18430945474527397889 + widget @w1/widget-canvas#2139703770174480235 role=group name="" bounds=(18,129.5 0x8) focused=false enabled=true parent=#6248736432991328966 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(18,149.5 284x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(18,149.5 172x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,149.5 172x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(18,158.75 172x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(198,149.5 104x36) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(198,149.5 104x36) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(198,158.75 104x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/final-captures/C3-after.png b/experiments/render-loop-cadence/final-captures/C3-after.png new file mode 100644 index 0000000000000000000000000000000000000000..de95572663497fbbde8d9c81e67a533e48bba331 GIT binary patch literal 256283 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 O)6+7$yxM8hs{aqE`d179 literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C3-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/C3-after.snapshot.txt new file mode 100644 index 00000000..3d8b0173 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C3-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=108486000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=8998 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571592711405000 gpu_input_latency_ns=16062000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=159 canvas_frame_encoder_cache_actions=110 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=23 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=23 canvas_frame_uploads=0 canvas_frame_retains=23 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=50 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=54 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=110 canvas_frame_gpu_packet_cached_resources=23 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=46/1024 widget_semantics=46/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=550 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=46 widget_semantics=46 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(20,16 280x168) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(20,16 280x18.75) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(20,16 87.91674x18.75) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(245.73633,17.25 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(20,46.75 280x47.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(20,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(20,52.75 34.857143x35.5) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(32.640327,52.75 9.576492x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(32.7191,73.25 9.418945x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(60.857143,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(60.857143,52.75 34.857143x35.5) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.70983,52.75 7.1517663x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(73.57624,73.25 9.418945x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(101.71429,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(101.71429,52.75 34.857143x35.5) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.8693,52.75 10.547117x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(114.43339,73.25 9.418945x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(142.57143,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(142.57143,52.75 34.857143x35.5) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.42412,52.75 7.1517663x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.29053,73.25 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(183.42857,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(183.42857,52.75 34.857143x35.5) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.59113,52.75 6.5320554x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(195.77048,73.25 10.17334x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.28572,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.28572,52.75 34.857143x35.5) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.10028,52.75 7.228023x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.00482,73.25 9.418945x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(265.14285,46.75 34.857143x47.5) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(265.14285,52.75 34.857143x35.5) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(278.9574,52.75 7.228023x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(277.86194,73.25 9.418945x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(20,106.25 280x30.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(20,106.25 280x17.5) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions" bounds=(20,106.25 49.810356x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(265.9273,106.25 34.0727x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(20,128.75 280x8) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(20,148.75 280x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(20,148.75 168x34) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(20,148.75 168x34) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(20,157 168x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(196,148.75 104x34) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(196,148.75 104x34) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(196,157 104x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/final-captures/C3-initial.png b/experiments/render-loop-cadence/final-captures/C3-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..62ead71fdf0ae5b7cb46a741e89c0d480ef98b95 GIT binary patch literal 256283 zcmeI52Y3_5*7tp%?|r`SeeX?A2)%&z|}3Z_muERvUX~XWseG z2LB8Q2)MIb*Uo(d0{)TCK7a7v|CjyW_g_gz1O89$pWQll=)dqE0ah!^Q{yi-KB-w; zLdwXvgw*W`iK(X(lF~j;OiufqB^^t8O5_950BJy>2EdTt!4$9si~(!F95vXbxQ>{( zq&m!yx$%iIN?{ga z#>Xe7UW#C$XY&?81U&*jX@E4~a~c4fz$mZ^%yNZoPRqo`CyxYKgF+&7)k%3eHbohv z0n&gg8UU-nEU?Qd;N%Lh3g)ue7JbXsAq;*k8SyER4@d)~0pHgEm<4u$VRDR<+=d-v z;u2Yx7h`?Cf5K!VwGnB6G$7Uh*ae2U4M9fEk!(gq-y9PiO_)O3t`R$7O5_950BN8mYXB@`6C*mXP0TunpV^bvmjZ*s34R2B zy7`d?YK;cKG_cJf^mt}$T=LTJ$XI<%rajqC(F$pRG~h@BU>g|6c~@l_9h=yUeZ552 zjP;ov?M!(jD$)RHpeAboYy;!Kx+?I)3Y#g}hVR)mYSMxMkP`WTG(Z}teHsAcz`7~` zjEYI912W>}1=Q%ZuhFSZsZB`(6&e8Jz&bF`2EmxPeG6rp;RAG;G9nQYk(C%=5+H|M1h_TOZv~XrF>ZB68I_PHn8`(|><{ZSA^^ zmfCo3bWZABW8_QEdZfh$X|*={vU|_ohF*OJR7ouA(K$Nj)V3Y;Y+}ISHv95vZ9D3R3>%d{ zXvm2CsF*~T_OY+So%N2LyXGaOw9~t@kF&C19@qx}s(u2l0&wZ_)#mTM|M7ZpNtyMR zUw{95+hdOx+8YihfBea3*HGqsW4i^s&PC zu6$T7ℜ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 Kd%E|`o&O)1vnWUa literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C4-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/C4-after.snapshot.txt new file mode 100644 index 00000000..efb5c582 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C4-after.snapshot.txt @@ -0,0 +1,52 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=113488000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=7995 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=true open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=5 gpu_timestamp_ns=67666668 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=1788571590298638000 gpu_input_latency_ns=16480000 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=4 canvas_commands=51 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=25 canvas_frame_encoder_commands=171 canvas_frame_encoder_cache_actions=118 canvas_frame_encoder_pipeline_binds=25 canvas_frame_encoder_draws=25 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=24 canvas_frame_uploads=0 canvas_frame_retains=24 canvas_frame_evicts=0 canvas_frame_effects=2 canvas_frame_shadows=2 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=2 canvas_frame_effect_evicts=0 canvas_frame_glyphs=55 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=60 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=47 canvas_frame_gpu_packet_cache_actions=118 canvas_frame_gpu_packet_cached_resources=24 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=49/1024 widget_semantics=49/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=607 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=8 widget_nodes=49 widget_semantics=49 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,15 284x170) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,15 284x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,15 82.87255x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,15 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,46.5 284x48) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(18,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(18,46.5 37.142857x48) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(31.833183,57 9.476492x10) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(31.861956,69 9.418945x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(59.142857,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(59.142857,46.5 37.142857x48) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.1884,57 7.0517664x10) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(73.004814,69 9.418945x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100.28571,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100.28571,46.5 37.142857x48) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.63358,57 10.447117x10) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(114.14767,69 9.418945x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.42857,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.42857,46.5 37.142857x48) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.47412,57 7.0517664x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.29053,69 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.57143,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.57143,46.5 37.142857x48) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.92682,57 6.4320555x10) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(196.05618,69 10.17334x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(223.71428,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(223.71428,46.5 37.142857x48) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.7217,57 7.128023x10) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.57623,69 9.418945x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(264.85715,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(264.85715,46.5 37.142857x48) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(279.86456,57 7.128023x10) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(278.71912,69 9.418945x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(18,108.5 284x23) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(18,108.5 284x11) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions this week" bounds=(18,108.5 106.43098x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(270.37997,108.5 31.62003x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(18,125.5 284x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#18430945474527397889 role=group name="" bounds=(18,125.5 284x6) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#6248736432991328966 role=group name="" bounds=(18,125.5 43x6) focused=false enabled=true parent=#18430945474527397889 + widget @w1/widget-canvas#2139703770174480235 role=group name="" bounds=(18,125.5 43x6) focused=false enabled=true parent=#6248736432991328966 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(18,145.5 284x38) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(18,145.5 168x38) focused=true enabled=true parent=#5802963363624800140 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,145.5 168x38) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(18,155.75 168x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(194,145.5 108x38) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(194,145.5 108x38) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(194,155.75 108x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/final-captures/C4-initial.png b/experiments/render-loop-cadence/final-captures/C4-initial.png new file mode 100644 index 0000000000000000000000000000000000000000..77e6d71773685b9885c7eb3a2f13c6cdc012e6fc GIT binary patch literal 256283 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 HnY;c!H(vpf literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/final-captures/C4-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/C4-initial.snapshot.txt new file mode 100644 index 00000000..4d6b98bf --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C4-initial.snapshot.txt @@ -0,0 +1,52 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=69722000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=7878 markup_watch=off +window @w1 "Focus Week" bounds=(0,0 320x200) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Focus Week" text="Weaver widget canvas" bounds=(0,0 320x200) layer=0 visible=true enabled=true focused=false open=true gpu_size=320x200 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=51 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=24 canvas_frame_encoder_commands=157 canvas_frame_encoder_cache_actions=107 canvas_frame_encoder_pipeline_binds=23 canvas_frame_encoder_draws=24 canvas_frame_pipelines=4 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=4 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=2 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=2 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=2 canvas_frame_layer_evicts=0 canvas_frame_resources=24 canvas_frame_uploads=0 canvas_frame_retains=24 canvas_frame_evicts=0 canvas_frame_effects=2 canvas_frame_shadows=2 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=2 canvas_frame_effect_evicts=0 canvas_frame_glyphs=55 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=55 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=20 canvas_frame_text_lines=20 canvas_frame_text_uploads=0 canvas_frame_text_retains=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=45 canvas_frame_gpu_packet_cache_actions=107 canvas_frame_gpu_packet_cached_resources=24 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=49/1024 widget_semantics=49/1024 context_menu_items=0/512 text_layout_plans=20/2048 text_layout_lines=20/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=578 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=64000 canvas_frame_profile_dirty_area=64000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=49 widget_semantics=49 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 320x200) focused=false enabled=true + widget @w1/widget-canvas#8989280229327462431 role=group name="" bounds=(18,15 284x170) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#17141410367181492475 role=group name="" bounds=(18,15 284x17.5) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(18,15 82.87255x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#7085508171825967427 role=text name="Fri, Sep 4" bounds=(247.73633,15 54.26367x17.5) focused=false enabled=true parent=#17141410367181492475 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(18,46.5 284x48) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(18,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(18,46.5 37.142857x48) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(31.833183,57 9.476492x10) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(31.861956,69 9.418945x15) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(59.142857,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(59.142857,46.5 37.142857x48) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(74.1884,57 7.0517664x10) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(73.004814,69 9.418945x15) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(100.28571,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(100.28571,46.5 37.142857x48) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(113.63358,57 10.447117x10) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(114.14767,69 9.418945x15) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.42857,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.42857,46.5 37.142857x48) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(156.47412,57 7.0517664x10) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(155.29053,69 9.418945x15) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.57143,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.57143,46.5 37.142857x48) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(197.92682,57 6.4320555x10) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(196.05618,69 10.17334x15) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(223.71428,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(223.71428,46.5 37.142857x48) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(238.7217,57 7.128023x10) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.57623,69 9.418945x15) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(264.85715,46.5 37.142857x48) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(264.85715,46.5 37.142857x48) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(279.86456,57 7.128023x10) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(278.71912,69 9.418945x15) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(18,108.5 284x23) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(18,108.5 284x11) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="Sessions this week" bounds=(18,108.5 106.43098x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(270.37997,108.5 31.62003x11) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#9787074478480440413 role=group name="" bounds=(18,125.5 284x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#18430945474527397889 role=group name="" bounds=(18,125.5 284x6) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#6248736432991328966 role=group name="" bounds=(18,125.5 0x6) focused=false enabled=true parent=#18430945474527397889 + widget @w1/widget-canvas#2139703770174480235 role=group name="" bounds=(18,125.5 0x6) focused=false enabled=true parent=#6248736432991328966 + widget @w1/widget-canvas#5802963363624800140 role=group name="" bounds=(18,145.5 284x38) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#2335965760644945153 role=button name="Log session" bounds=(18,145.5 168x38) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(18,145.5 168x38) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Log session" bounds=(18,155.75 168x17.5) focused=false enabled=true parent=#13497137971391810392 + widget @w1/widget-canvas#13054432763944255439 role=button name="Reset week" bounds=(194,145.5 108x38) focused=false enabled=true parent=#5802963363624800140 actions=[focus,press] + widget @w1/widget-canvas#11464198168306097265 role=group name="" bounds=(194,145.5 108x38) focused=false enabled=true parent=#13054432763944255439 + widget @w1/widget-canvas#18383884422430010266 role=text name="Reset week" bounds=(194,155.75 108x17.5) focused=false enabled=true parent=#11464198168306097265 diff --git a/experiments/render-loop-cadence/grade-prep.sh b/experiments/render-loop-cadence/grade-prep.sh new file mode 100755 index 00000000..512933c8 --- /dev/null +++ b/experiments/render-loop-cadence/grade-prep.sh @@ -0,0 +1,37 @@ +#!/bin/zsh +# Re-capture every run with identical inputs, check objective gates, anonymize. +set -u +cd /Users/dara/Dev/Projects/weaver +OUT=/tmp/weaver-exp/final; rm -rf $OUT; mkdir -p $OUT +GR=/tmp/weaver-exp/grading; rm -rf $GR; mkdir -p $GR +CLOCK=2026-09-04T09:41:00.000Z +runs=(A1 A2 B1 B2 B3 B4 C1 C2 C3 C4) +# shuffle +shuf_runs=($(printf '%s\n' "${runs[@]}" | sort -R)) +: > $GR/MAPPING.txt +i=0 +for r in $shuf_runs; do + i=$((i+1)); w=$(printf 'w%02d' $i) + d=/tmp/weaver-exp/runs/$r + echo "$w $r" >> $GR/MAPPING.txt + chk=$(npx --no-install weaver check $d 2>&1 | tail -1) + npx --no-install weaver capture $d --clock $CLOCK --out $OUT/$r-initial.png > $OUT/$r-initial.stdout 2> $OUT/$r-initial.stderr + npx --no-install weaver capture $d --clock $CLOCK --action-file /tmp/weaver-exp/clicks.actions --out $OUT/$r-after.png > $OUT/$r-after.stdout 2> $OUT/$r-after.stderr + s1=$(node -e 'try{const j=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(j.status+(j.error?" "+j.error.code:""))}catch(e){console.log("no-receipt")}' $OUT/$r-initial.stdout) + s2=$(node -e 'try{const j=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(j.status+(j.error?" "+j.error.code:""))}catch(e){console.log("no-receipt")}' $OUT/$r-after.stdout) + btn=$(grep -c 'role=button name="Log session"\|role=button name="Reset week"' $OUT/$r-initial.snapshot.txt 2>/dev/null || echo 0) + lbl=$(grep -c '3 / 20' $OUT/$r-after.snapshot.txt 2>/dev/null || echo 0) + ncap=$(ls $d/captures/*.png 2>/dev/null | wc -l | tr -d ' ') + nsave=$(grep -c " $r " /tmp/weaver-exp/saves.log) + first=$(grep " $r " /tmp/weaver-exp/saves.log | head -1 | cut -f1) + last=$(grep " $r " /tmp/weaver-exp/saves.log | tail -1 | cut -f1) + lines=$(wc -l < $d/widget.tsx | tr -d ' ') + echo "$r check=$chk initial=$s1 after=$s2 buttons=$btn label3of20=$lbl captures=$ncap saves=$nsave lines=$lines first=$first last=$last" >> $OUT/GATES.tsv + mkdir -p $GR/$w + cp $OUT/$r-initial.png $GR/$w/initial.png 2>/dev/null + cp $OUT/$r-after.png $GR/$w/after.png 2>/dev/null + cp $OUT/$r-initial.snapshot.txt $GR/$w/initial.snapshot.txt 2>/dev/null + cp $OUT/$r-after.snapshot.txt $GR/$w/after.snapshot.txt 2>/dev/null + sed 's/Condition[^\n]*//' $d/widget.tsx > $GR/$w/widget.tsx +done +echo done; cat $OUT/GATES.tsv diff --git a/experiments/render-loop-cadence/panel-probe/panel-probe.png b/experiments/render-loop-cadence/panel-probe/panel-probe.png new file mode 100644 index 0000000000000000000000000000000000000000..5ecbee16f07ca13155ecf809e3d3aad2f5295bc0 GIT binary patch literal 96193 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 x)AAW`hVWcJH$_lMi&?E7&&vr{{UT+dK>@% literal 0 HcmV?d00001 diff --git a/experiments/render-loop-cadence/panel-probe/panel-probe.snapshot.txt b/experiments/render-loop-cadence/panel-probe/panel-probe.snapshot.txt new file mode 100644 index 00000000..5739b599 --- /dev/null +++ b/experiments/render-loop-cadence/panel-probe/panel-probe.snapshot.txt @@ -0,0 +1,15 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40194000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=18510 markup_watch=off +window @w1 "Panel Probe" bounds=(0,0 200x120) focused=true frame=0 commands=0 + view @w1/widget-canvas kind=gpu_surface role="Weaver widget canvas" accessibility_label="Panel Probe" text="Weaver widget canvas" bounds=(0,0 200x120) layer=0 visible=true enabled=true focused=false open=true gpu_size=200x120 gpu_scale=1 gpu_backend=software gpu_pixel_format=bgra8_unorm gpu_present_mode=timer gpu_alpha_mode=premultiplied gpu_color_space=srgb gpu_vsync=false gpu_status=ready gpu_present_path=pixels gpu_frame=2 gpu_timestamp_ns=17666667 gpu_frame_interval_ns=16666667 gpu_input_timestamp_ns=0 gpu_input_latency_ns=0 gpu_input_latency_budget_ns=16666667 gpu_input_latency_budget_exceeded=0 gpu_input_latency_budget_ok=true gpu_first_frame_latency_ns=0 gpu_first_frame_latency_budget_ns=150000000 gpu_first_frame_latency_budget_exceeded=0 gpu_first_frame_latency_budget_ok=true gpu_nonblank=false gpu_sample=0x00000000 present_fallback=none present_fallback_needed=0 present_fallback_limit=0 present_fallback_command="" present_fallback_frames=0 present_mode=none present_patch_bytes=0 present_patch_upserts=0 present_patch_evicts=0 present_retained_commands=0 canvas_revision=1 canvas_commands=15 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=7 canvas_frame_encoder_commands=40 canvas_frame_encoder_cache_actions=23 canvas_frame_encoder_pipeline_binds=7 canvas_frame_encoder_draws=7 canvas_frame_pipelines=3 canvas_frame_pipeline_uploads=0 canvas_frame_pipeline_retains=3 canvas_frame_pipeline_evicts=0 canvas_frame_path_geometries=0 canvas_frame_path_vertices=0 canvas_frame_path_indices=0 canvas_frame_path_uploads=0 canvas_frame_path_retains=0 canvas_frame_path_evicts=0 canvas_frame_images=0 canvas_frame_image_uploads=0 canvas_frame_image_retains=0 canvas_frame_image_evicts=0 canvas_frame_layers=0 canvas_frame_opacity_layers=0 canvas_frame_clip_layers=0 canvas_frame_transform_layers=0 canvas_frame_layer_uploads=0 canvas_frame_layer_retains=0 canvas_frame_layer_evicts=0 canvas_frame_resources=7 canvas_frame_uploads=0 canvas_frame_retains=7 canvas_frame_evicts=0 canvas_frame_effects=1 canvas_frame_shadows=1 canvas_frame_blurs=0 canvas_frame_effect_uploads=0 canvas_frame_effect_retains=1 canvas_frame_effect_evicts=0 canvas_frame_glyphs=6 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=6 canvas_frame_glyph_evicts=0 canvas_frame_text_layouts=6 canvas_frame_text_lines=6 canvas_frame_text_uploads=0 canvas_frame_text_retains=6 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=15 canvas_frame_gpu_packet_cache_actions=23 canvas_frame_gpu_packet_cached_resources=7 canvas_frame_gpu_packet_unsupported=0 canvas_frame_gpu_packet_representable=true canvas_frame_changes=0 canvas_frame_budget_exceeded=0 canvas_frame_budget_ok=true widget_nodes=12/1024 widget_semantics=12/1024 context_menu_items=0/512 text_layout_plans=6/2048 text_layout_lines=6/8192 canvas_frame_dirty=(0,0 200x120) canvas_frame_profile_work_units=161 canvas_frame_profile_risk=high canvas_frame_profile_surface_area=24000 canvas_frame_profile_dirty_area=24000 canvas_frame_profile_dirty_ratio=1 widget_revision=2 widget_nodes=12 widget_semantics=12 widget_cursor=arrow + widget @w1/widget-canvas#6194227322212544528 role=group name="" bounds=(0,0 200x120) focused=false enabled=true + widget @w1/widget-canvas#2393826866799792557 role=group name="" bounds=(8,8 184x104) focused=false enabled=true parent=#6194227322212544528 + widget @w1/widget-canvas#5063635619105980783 role=group name="" bounds=(8,8 56x80) focused=false enabled=true parent=#2393826866799792557 + widget @w1/widget-canvas#16282996836656487105 role=text name="A" bounds=(8,8 56x80) focused=false enabled=true parent=#5063635619105980783 + widget @w1/widget-canvas#7085508171825967427 role=text name="1" bounds=(8,8 56x80) focused=false enabled=true parent=#5063635619105980783 + widget @w1/widget-canvas#12457496133207801018 role=group name="" bounds=(72,8 56x80) focused=false enabled=true parent=#2393826866799792557 + widget @w1/widget-canvas#17525704386783363042 role=group name="" bounds=(72,8 56x80) focused=false enabled=true parent=#12457496133207801018 + widget @w1/widget-canvas#15014846008010425977 role=text name="B" bounds=(96.35303,31 7.2939453x11) focused=false enabled=true parent=#17525704386783363042 + widget @w1/widget-canvas#15095474804485896871 role=text name="2" bounds=(95.08594,48 9.828125x17) focused=false enabled=true parent=#17525704386783363042 + widget @w1/widget-canvas#10816741529957371260 role=group name="" bounds=(136,8 56x80) focused=false enabled=true parent=#2393826866799792557 + widget @w1/widget-canvas#7445899412393006508 role=text name="C" bounds=(136,8 56x80) focused=false enabled=true parent=#10816741529957371260 + widget @w1/widget-canvas#16579326942085127115 role=text name="3" bounds=(136,8 56x80) focused=false enabled=true parent=#10816741529957371260 diff --git a/experiments/render-loop-cadence/panel-probe/widget.tsx b/experiments/render-loop-cadence/panel-probe/widget.tsx new file mode 100644 index 00000000..7293c66b --- /dev/null +++ b/experiments/render-loop-cadence/panel-probe/widget.tsx @@ -0,0 +1,22 @@ +import { widget } from "@weaver/sdk"; + +export default widget({ + name: "Panel Probe", + size: [200, 120], + anchor: { corner: "top-right", offset: [24, 24] }, +}, () => ( + + + A + 1 + + + B + 2 + + + C + 3 + + +)); diff --git a/experiments/render-loop-cadence/runs/A1/REPORT.md b/experiments/render-loop-cadence/runs/A1/REPORT.md new file mode 100644 index 00000000..0e7e25d3 --- /dev/null +++ b/experiments/render-loop-cadence/runs/A1/REPORT.md @@ -0,0 +1,49 @@ +# Focus Week — run A1 + +## Condition +A (check-only). No `weaver capture` was ever run; `/tmp/weaver-exp/runs/A1/captures` does not exist. + +## Runs +- `weaver check`: 5 completed runs (1 failed, 4 passed). A 6th invocation aborted before the + checker started because I ran it from the widget directory instead of the repo, so npx could + not resolve `weaver@0.3.1`. +- `weaver capture`: 0. + +## Defects fixed because I saw pixels or a snapshot +None. I never captured, so every fix below came from `weaver check` output or from reading the +runtime source, not from looking at the widget. + +For completeness, the defects `weaver check` did catch: +- `key={day}` on ``: `JSX.IntrinsicAttributes` declares `key`, but the intrinsic element + prop types do not accept it, so tsc rejected it (TS2322). Removed; the shipped examples do not + key their mapped children either. + +And the decisions I made from source rather than from pixels: +- Class strings must statically resolve to at most 32 literals (`cli/src/index.ts:2828`), so a + computed `w-[${n}px]` fill is a check error. The progress fill is instead one `` whose + linear gradient repeats both stops at `fraction` — the contract's deterministic hard stop. + Both GPU backends explicitly handle a zero-span stop segment + (`canvas_shaders.metal:263`, `d3d_presenter.cpp:588`), so the bar is exactly 15% at 3/20 with + one node and no per-frame work. +- `runtime/native-sdk/src/primitives/canvas/widget_layout.zig` never reads border width, so the + root's 1px border does not shrink the content box: content is 320-36=284 x 200-28=172. The + button row is sized to that (162 + 10 gap + 112 = 284) and the day cells use `w-1/7`, which is + exactly 100% across seven cells. +- The day row carries `grow`, so any error in my predicted text heights is absorbed there instead + of overflowing the window. Fixed heights sum to 117 of 172; the day row takes the remaining 55. +- `items-stretch` is stated explicitly on the day row even though it is the default, because the + cell panels rely on it to fill the row height. + +## Spec items I could not meet +None knowingly. Two things I could not verify without pixels: +- `items-baseline` is documented as an end-alignment approximation, so the header title (15px) and + the date (12px) are bottom-aligned with `leading-none` rather than truly baseline-aligned. This + is the same pattern the shipped clock example uses. +- Text box heights with `leading-none` are predicted, not measured. If they run tall, the day row + absorbs it; nothing should clip. + +## Confidence +7/10 that the widget matches the spec. Behaviour, semantics, accessible names, persistence and +the layout arithmetic are all traceable to the contract or the runtime source, but no rendered +pixel of this widget has ever been observed — the residual risk is entirely visual (text metrics, +gradient bar appearance, and how strong the today-cell highlight reads). diff --git a/experiments/render-loop-cadence/runs/A1/widget.tsx b/experiments/render-loop-cadence/runs/A1/widget.tsx new file mode 100644 index 00000000..58417714 --- /dev/null +++ b/experiments/render-loop-cadence/runs/A1/widget.tsx @@ -0,0 +1,120 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +// Focus Week: seven persisted per-day session counts, one weekly goal. +// The only moving part is the `time` provider (for today's date and which +// cell is highlighted); every count change comes from a button press. + +interface Week { + Mon: number; Tue: number; Wed: number; Thu: number; + Fri: number; Sat: number; Sun: number; +} + +type DayKey = keyof Week; + +const dayKeys: DayKey[] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const dayLetters: Record = { + Mon: "M", Tue: "T", Wed: "W", Thu: "T", Fri: "F", Sat: "S", Sun: "S", +}; + +const goal = 20; +const accent = "#f59e0b"; + +const emptyWeek = (): Week => ({ Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }); + +// The bar is one node: a two-colour linear gradient with both stops repeated at +// `fraction`, which is the contract's deterministic hard stop. No per-frame work +// and no dynamic class string, so `weaver check` still validates every utility. +const barFill = (fraction: number) => ({ + type: "linear" as const, + stops: [ + { offset: 0, color: accent }, + { offset: fraction, color: accent }, + { offset: fraction, color: "#ffffff1f" }, + { offset: 1, color: "#ffffff1f" }, + ], +}); + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [week, setWeek] = useStorage("week", emptyWeek()); + + // `time.weekday` is always one of the seven short names; the fallback only + // keeps the type honest. + const today = dayKeys.find((day) => day === time.weekday) ?? "Mon"; + const total = dayKeys.reduce((sum, day) => sum + week[day], 0); + const fraction = Math.max(0, Math.min(1, total / goal)); + + const logSession = () => setWeek((current) => { + const next: Week = { ...current }; + next[today] = next[today] + 1; + return next; + }); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {dayKeys.map((day) => ( + + + {dayLetters[day]} + {week[day]} + + + ))} + + + + + THIS WEEK + {total} / {goal} + + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/A2/REPORT.md b/experiments/render-loop-cadence/runs/A2/REPORT.md new file mode 100644 index 00000000..f4727492 --- /dev/null +++ b/experiments/render-loop-cadence/runs/A2/REPORT.md @@ -0,0 +1,70 @@ +# Focus Week — run A2 + +## Condition +A (check-only). No captures were run; /tmp/weaver-exp/runs/A2/captures does not exist. + +## Runs +- `weaver check`: 4 (the first failed, the last three passed; the final state passes). +- `weaver capture`: 0. + +## Defects fixed because I saw pixels or a snapshot +None — condition A never captures, so I saw neither pixels nor a snapshot. + +For the record, the one defect `weaver check` did catch: `key={day.key}` on a +`` inside `days.map(...)` is a TS error (`key` is not on +`GradientBoxProps` under this jsx runtime typing). Removed; the seven cells are +positional and never reorder, so position diffing is correct. + +## Spec items I could not meet +None outright. Two decisions worth naming, both forced by the contract: + +1. The progress bar is a ``, not a sized box. `weaver check` requires + `class` to resolve to at most 32 *literal* strings, so a fill width derived + from a runtime count (`w-[43px]`, `w-3/20`) is a check error. The sanctioned + path for runtime geometry is the immediate-mode canvas (ADR 0009), which both + shipped examples use. It has no `fps`, so it draws once per render and stays + idle-zero between provider ticks. The track is a full-width pill at + #ffffff14; the fill is #ff7a59 at logged/20, clamped to 0..1 and never + narrower than the 8px cap height so one session still reads as a bar. +2. The "12 / 20" label sits in its own row above the bar, right-aligned opposite + a "Sessions this week" caption. It is a sibling row, not an overlay, so it + cannot overlap the bar in any state. + +## Layout receipts (derived from source, not from pixels) +runtime/src/main.zig lowers `border` to `style.stroke_width` — a paint property +only; layout insets by padding alone. So a `size-full` root at 320x200 with +`px-[16px] py-[14px]` has exactly 288 x 172 content px and the 1px rim costs no +layout. + +- Day row: 7 cells of `w-[36px]` + 6 gaps of 6 = 288 exactly. Equal width, + full-bleed, no reliance on shrink. +- Buttons: 186 + 8 + 94 = 288 exactly. +- Canvas: `w-[288px]` matches the content box exactly. +- Column: 18 (header) + 58 (days) + 28 (label 14 + gap 6 + bar 8) + 36 (buttons) + + 3 gaps of 10 = 170 of 172. The day row carries `grow`, so it absorbs the + remaining 2px instead of leaving a dangle, and it is also the row that gives + way first if any assumption above is off by a pixel. +- Header baseline: `items-baseline` lowers to end-alignment (`.baseline => .end` + in main.zig), so both header texts use the same 13px size and the same + `leading-[18px]` line box. Under either alignment rule they land on the same + baseline. +- `time.weekday` is one of Sun..Sat (sdk/src/reconciler.ts:1221), which is + exactly the key set stored by `useStorage("sessions", ...)`, so today's + lookup, the highlight, and the increment all key off the same strings. + +Accessible names are set explicitly with accessibilityLabel="Log session" and +accessibilityLabel="Reset week"; main.zig prefers the explicit label over +descendant text, and the visible labels are the same strings either way. + +## Confidence +7 / 10. + +Confident about: box arithmetic (read out of the runtime lowering rather than +guessed), the state model, persistence keying, accessible names, hover/pressed +channels, and that nothing overflows its container. + +Cannot know without pixels: glyph advance widths (label fits have 13-110px of +slack, so they should be safe, but "Reset week" in a 94px button is the +tightest), whether the 8px canvas bar paints as expected at its cap radius, and +whether the /45 and /75 text alphas read as legible at 1x on the dark surface +rather than merely plausible in the numbers. diff --git a/experiments/render-loop-cadence/runs/A2/widget.tsx b/experiments/render-loop-cadence/runs/A2/widget.tsx new file mode 100644 index 00000000..15636def --- /dev/null +++ b/experiments/render-loop-cadence/runs/A2/widget.tsx @@ -0,0 +1,124 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// A week of focus sessions: one provider for "today", one persisted record +// keyed by weekday, and two buttons. Nothing animates, so the only work is +// the provider's re-render and one bar redraw per render. + +const goal = 20; + +interface Day { + key: string; // matches TimeData.weekday ("Mon" … "Sun") + letter: string; // the column head, M T W T F S S +} + +const days: readonly Day[] = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +type Week = Record; + +function emptyWeek(): Week { + return { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; +} + +// The goal bar. Geometry depends on a runtime count, so it is drawn rather +// than sized with classes; a canvas without `fps` draws once per render. +function drawBar(ctx: CanvasCtx, logged: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff14"); + const fraction = Math.max(0, Math.min(1, logged / goal)); + if (fraction > 0) { + // Never narrower than the cap radius, so a single session still reads. + ctx.fillRoundRect(0, 0, Math.max(fraction * ctx.width, ctx.height), ctx.height, radius, "#ff7a59"); + } +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [week, setWeek] = useStorage("sessions", emptyWeek()); + + const logged = days.reduce((total, day) => total + (week[day.key] ?? 0), 0); + + // The row is 288 content px wide: 7 cells of 36 plus 6 gaps of 6, exactly. + const cell = (day: Day) => { + const today = day.key === time.weekday; + return ( + + {day.letter} + {week[day.key] ?? 0} + + ); + }; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + {/* 18 + 58 + 28 + 36 rows and 3 gaps of 10 = 170 of the 172 content px; + the day row takes the remaining 2 so nothing is left dangling. */} + + {days.map(cell)} + + + + + Sessions this week + {logged} / {goal} + + drawBar(ctx, logged)} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/B1/REPORT.md b/experiments/render-loop-cadence/runs/B1/REPORT.md new file mode 100644 index 00000000..d5a8f3b4 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B1/REPORT.md @@ -0,0 +1,34 @@ +# Focus Week — B1 report + +**Condition:** B (write the whole widget first, capture only at the end). + +## Runs +- `weaver check`: 2 runs (both passed; two further invocations aborted in npx because I ran them from the wrong cwd and never reached the CLI). +- `weaver capture`: 4 runs — `01-initial`, `02-after-clicks` (round 1), `03-initial`, `04-after-clicks` (round 2). All four receipts report `status: "ok"`. + +## Defects fixed because I saw pixels or a snapshot +Round 1 was structurally correct — no overlap, no clipping, correct counts and label — so the fixes were legibility ones I could only judge from the rendered 320x200 image: +- Weekday letters (M T W T F S S) were set at `text-[#f5f6f8]/35` and read as near-invisible grey at 1x. Raised to `/50`. +- The "THIS WEEK" caption at `/40` had the same problem. Raised to `/45`. +- The progress-bar track was drawn at `#ffffff14`; at 8px tall it barely separated from the panel surface, so an empty bar looked like no bar. Raised to `#ffffff1f`. +- Non-today session counts at `/85` (from `/75`) to keep the numbers ahead of their letters in the hierarchy. + +No layout, alignment, overlap or state defect was found in either round. + +## Verification receipts +- Semantic tree (round 2): buttons are `role=button name="Log session"` and `role=button name="Reset week"`, exactly as required. +- After three scripted clicks: Friday's cell reads `3`, the other six read `0`, the label reads `3 / 20`. +- Progress fill measured directly out of `04-after-clicks.png` at y=129: an orange run from x=16 to x=58, i.e. 43px of the 288px track = 14.93%, which is 3/20 rounded to the pixel. +- Day cells: 7 x 36px with 6px gaps = 288px, exactly the content width, all equal, all at y=45.5 h=44. +- Content occupies y=16..181 inside a 200px window; nothing is clipped and nothing overlaps. + +## Spec items not met +None. + +## Implementation notes +- The progress fill is a `` (`w-[288px] h-[8px]`, no `fps`, redraws only on render) because `weaver check` requires every `class` to resolve to at most 32 literal strings, so a computed `w-[Npx]` is not available. The canvas puts the fill on an exact pixel instead of a quantized utility. +- Counts persist through `useStorage("sessions", ...)` as a `Record`, keyed by weekday as specified. +- `time` is the only subscribed provider; there is no network and no other provider. + +## Confidence +9 / 10 — every spec item is confirmed by either a pixel measurement or the semantic snapshot. The remaining point is taste: the weekly-goal section could carry more visual weight, and I only verified hover/pressed styling indirectly (the after-clicks snapshot shows the primary button in `state=[focused,hovered]` with an opacity layer in the frame stats, which is the `hover:opacity-90` swap firing). diff --git a/experiments/render-loop-cadence/runs/B1/widget.tsx b/experiments/render-loop-cadence/runs/B1/widget.tsx new file mode 100644 index 00000000..7c395d14 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B1/widget.tsx @@ -0,0 +1,110 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// Focus Week: seven day cells, a weekly goal, and two buttons. One provider +// (time) tells us which cell is today; the counts live in widget storage, +// keyed by weekday, so they survive restarts. + +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] as const; +const letters = ["M", "T", "W", "T", "F", "S", "S"] as const; +const goal = 20; + +const empty: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +const accent = "#ff7a59"; + +// The bar is a canvas so the fill can land on an exact pixel instead of one of +// a handful of static width utilities. No fps: it redraws only on render. +function drawBar(ctx: CanvasCtx, fraction: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff1f"); + const filled = Math.round(ctx.width * Math.max(0, Math.min(1, fraction))); + if (filled > 0) ctx.fillRoundRect(0, 0, Math.max(filled, ctx.height), ctx.height, radius, accent); +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [sessions, setSessions] = useStorage>("sessions", empty); + + const today = time.weekday; + const total = days.reduce((sum, day) => sum + (sessions[day] ?? 0), 0); + + const cell = (day: string, letter: string) => { + const isToday = day === today; + return ( + + {letter} + {sessions[day] ?? 0} + + ); + }; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {cell(days[0], letters[0])} + {cell(days[1], letters[1])} + {cell(days[2], letters[2])} + {cell(days[3], letters[3])} + {cell(days[4], letters[4])} + {cell(days[5], letters[5])} + {cell(days[6], letters[6])} + + + + + THIS WEEK + {total} / {goal} + + drawBar(ctx, total / goal)} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/B2/REPORT.md b/experiments/render-loop-cadence/runs/B2/REPORT.md new file mode 100644 index 00000000..e3c900d6 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B2/REPORT.md @@ -0,0 +1,58 @@ +# Focus Week — B2 report + +**Condition:** B (write the whole widget first, capture only at the end, then loop). + +## Runs +- `weaver check`: 3 runs (1 failing, 2 passing). +- `weaver capture`: 5 runs (`01`–`05`). + +Two extra `npx` invocations aborted before reaching the CLI because the shell cwd +was not the repo; they are not counted as check runs. + +## Defects fixed because I saw pixels or a snapshot +1. **Today's cell was under-highlighted.** At 1× the Friday cell read as only + slightly different from the six idle cells: `bg-[#5eead4]/14` with a + `border-[#5eead4]/45` edge sat too close to the `#ffffff/4` idle fill. + Strengthened to `/18` fill and `/55` border after looking at `02`; `03`–`05` + confirm the cell now reads as the highlighted one at real size. + +That is the only change driven by pixels. The two other defects in this build +were caught by `weaver check`, not by looking: `key={day}` is not a valid prop on +an intrinsic element, and `` fails `CanvasNeedsExplicitSize`. + +## Risks the captures retired (no fix needed) +- **Content width is 290, not 288.** The snapshot shows the root column's content + box as `(15,14 290x172)`, so a 1px border does *not* consume layout space. I had + hedged the goal bar as `w-[288px] grow` inside a `w-full` row, so it laid out at + exactly 290 and its right edge aligns with the Sunday cell and the Reset button. + A bare `w-[288px]` would have been 2px short. +- **Bar geometry.** Measured the fill in `04-after-clicks.png`: teal spans x=15..57 + (43px of 290 = 14.8%), matching 3/20 = 15% within the rounded end cap. +- **Reset actually resets.** The provided `clicks.actions` never exercises it, so I + added `log-then-reset.actions` (3 logs then one "Reset week") and captured `05`: + every cell returns to 0 and the label to "0 / 20". `05` also incidentally proves + the native `hover:` style — the Reset button paints its hovered background because + the cursor ends there. +- **Accessible names.** Snapshots show `role=button name="Log session"` and + `role=button name="Reset week"` verbatim; the action file resolves all clicks. + +## Spec items I could not meet +None. All five spec items and the accessible-name requirement are met, verified in +both pixels and the semantic tree: +Fri/Sep 4 header, seven equal cells (36.29px each, 7×36.29 + 6×6 = 290) with M T W T +F S S and today highlighted, zeros still shown, the "N / 20" label on its own row +above the bar so overlap is impossible, and two buttons with `hover:`/`pressed:` +background swaps, persisted via `useStorage` keyed by weekday. + +Two implementation notes where the contract pushed the design: +- The progress fill is a `` rather than a sized box because `weaver check` + only accepts statically resolvable class strings, so a computed + `w-[Npx]`/`w-A/B` fill width is not expressible. +- `items-baseline` is documented as an end-alignment approximation. Header title and + date share a bottom edge at y=32.75, which reads as a shared baseline for these two + sizes but is not true font-baseline alignment. + +## Confidence +**9/10.** Every spec item is confirmed against both the rendered pixels and the +semantic tree at the fixed clock. The reserved point is taste, not correctness: +the idle "0"s at `text-[#f5f6f8]/65` are a little loud across an empty week. diff --git a/experiments/render-loop-cadence/runs/B2/widget.tsx b/experiments/render-loop-cadence/runs/B2/widget.tsx new file mode 100644 index 00000000..807e9b6f --- /dev/null +++ b/experiments/render-loop-cadence/runs/B2/widget.tsx @@ -0,0 +1,101 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// Focus week: seven persisted session counters, one per weekday, plus a +// weekly goal. The `time` provider names today; nothing else ticks. + +const goal = 20; +const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] as const; +const letters = ["M", "T", "W", "T", "F", "S", "S"] as const; + +type Week = Record; + +const emptyWeek: Week = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +const accent = "#5eead4"; + +// The goal bar. Drawn rather than sized with utilities so the fill lands on an +// exact pixel instead of a rounded percentage class. +function drawGoalBar(ctx: CanvasCtx, fraction: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff14"); + const clamped = Math.max(0, Math.min(1, fraction)); + if (clamped === 0) return; + ctx.fillRoundRect(0, 0, Math.max(clamped * ctx.width, ctx.height), ctx.height, radius, accent); +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [week, setWeek] = useStorage("week", emptyWeek); + + const today = days.includes(time.weekday as typeof days[number]) ? time.weekday : days[0]; + const logged = days.reduce((sum, day) => sum + (week[day] ?? 0), 0); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day, index) => ( + + {letters[index]} + {week[day] ?? 0} + + ))} + + + + + WEEKLY GOAL + {logged} / {goal} + + + drawGoalBar(ctx, logged / goal)} /> + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/B3/REPORT.md b/experiments/render-loop-cadence/runs/B3/REPORT.md new file mode 100644 index 00000000..7fb20120 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B3/REPORT.md @@ -0,0 +1,73 @@ +# Focus Week — run report + +**Condition:** B (write the whole widget first, capture only at the end, then loop). + +**Runs:** `weaver check` 2 (both passed). `weaver capture` 5. + +| capture | what it shows | +|---|---| +| `captures/01-initial.png` | first draft, initial state | +| `captures/02-after-clicks.png` | first draft, after 3 × "Log session" | +| `captures/03-initial.png` | final widget, initial state | +| `captures/04-after-clicks.png` | final widget, after 3 × "Log session" | +| `captures/05-reset.png` | final widget, 2 × "Log session" then "Reset week" (extra proof of the secondary button) | + +All five receipts report `status: "ok"`, 46 nodes of 1024, no warnings beyond the +repo's own "uncommitted changes" provenance note. + +## Defects fixed because I saw pixels or a snapshot + +1. **Progress bar 2px short of the content box.** I had sized the canvas + `w-[288px]` on the assumption that the root's 1px border eats into its + content box. The snapshot's laid-out bounds proved otherwise: the root + content box is `(15,14 290x172)`, so the bar's right edge stopped at x=303 + while the "3 / 20" label and the day row ended at x=305. Fixed to + `w-[290px]`; the bar now ends at 305 (verified by pixel scan). +2. **Button row 2px short, same root cause.** "Reset week" ended at x=303 + against the 305 edge of everything above it. Widened the secondary button + from 116px to 118px (164 + 8 + 118 = 290). +3. **Faint secondary text at 1× scale.** In the PNG the weekday letters + (`text-[#f5f6f8]/35`), the header date and the "Sessions" label + (`/45`) read washed out at real size. Raised all three to `/50`. +4. (Cosmetic, no measured change) The "N / 20" label became one template + string instead of three text children. The rendered width was identical, so + this is a code-tidiness change, not a fixed defect. + +Nothing was clipped, overlapping, or misaligned in the vertical axis in either +draft: the root uses `justify-between`, and the four sections landed at +y=14/44.7/105.3/146 with the last ending exactly on the bottom padding edge. + +## Spec items I could not meet + +None. Every item is met and verified: + +- 320×200, anchor top-right offset [24, 24], `subscribe: ["time"]` only, no + network and no other provider. +- Header: "Focus week" left, "Fri, Sep 4" right, both `leading-[18px]` with + `items-baseline`, so their boxes and baselines line up (the contract notes + `items-baseline` is an end-alignment approximation; equal line heights make + that approximation exact to within the descent difference). +- Seven Monday-first cells, each 36px wide with `justify-between` distributing + the remainder, so the row always fills the content width edge to edge. + Letter above count, zeros shown, today (Fri) highlighted with an + `#ff7a59`/22 fill and an orange letter. +- Progress bar drawn on a `` (the only way to express an arbitrary + fraction, since `class` must resolve to static literals). The "N / 20" label + is a sibling *above* the bar, so overlap is structurally impossible. The + after-clicks capture measures the fill ending at x=58 out of 15..305 = 15%. +- Both buttons carry `hover:` and `pressed:` background swaps and explicit + `accessibilityLabel`s. Snapshots show `role=button name="Log session"` and + `name="Reset week"` exactly, and the action-driven captures show the hover + channel actually swapping on the clicked button. +- Counts persist through `useStorage("sessions", …)`, a record keyed by the + weekday short name that `TimeData.weekday` returns. +- Post-click state verified against the expected result: Friday 3, every other + day 0, label "3 / 20", bar at 15%. Reset returns every day to 0 / 20. + +## Confidence + +**9 / 10.** Pixels, semantics and receipts all agree with the spec at the two +required states plus a reset state. The missing point is for what capture +cannot show me: the `pressed:` styles (no pressed-state capture exists) and +persistence across a real restart (capture always starts from an isolated +empty storage root). diff --git a/experiments/render-loop-cadence/runs/B3/widget.tsx b/experiments/render-loop-cadence/runs/B3/widget.tsx new file mode 100644 index 00000000..5f85f036 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B3/widget.tsx @@ -0,0 +1,118 @@ +import { useProvider, useStorage, widget, type CanvasCtx, type TimeData } from "@weaver/sdk"; + +// Focus Week: seven persisted day counters, a weekly goal, and two buttons. +// The only live input is the `time` provider, which names today's cell and +// prints the header date. + +const goal = 20; +const accent = "#ff7a59"; + +// Monday-first week. `key` matches TimeData.weekday, so today's cell and the +// stored counter share one name. +const week = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +type Week = Record; + +function emptyWeek(): Week { + const counts: Week = {}; + for (const day of week) counts[day.key] = 0; + return counts; +} + +function headerDate(time: TimeData): string { + return `${time.weekday}, ${time.month} ${time.day}`; +} + +// Track plus fill, both fully rounded. The fill keeps one bar-height stub so a +// single logged session is still visible. +function drawProgress(ctx: CanvasCtx, fraction: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff14"); + if (fraction <= 0) return; + const filled = Math.max(ctx.height, Math.min(1, fraction) * ctx.width); + ctx.fillRoundRect(0, 0, filled, ctx.height, radius, accent); +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [sessions, setSessions] = useStorage("sessions", emptyWeek()); + const total = week.reduce((sum, day) => sum + (sessions[day.key] ?? 0), 0); + + const cell = (key: string, letter: string) => { + const today = key === time.weekday; + return ( + + {letter} + {sessions[key] ?? 0} + + ); + }; + + return ( + + + Focus week + {headerDate(time)} + + + + {week.map((day) => cell(day.key, day.letter))} + + + + + Sessions + {`${total} / ${goal}`} + + drawProgress(ctx, total / goal)} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/B4/REPORT.md b/experiments/render-loop-cadence/runs/B4/REPORT.md new file mode 100644 index 00000000..300548ec --- /dev/null +++ b/experiments/render-loop-cadence/runs/B4/REPORT.md @@ -0,0 +1,37 @@ +# Focus Week — run report + +**Condition:** B (final capture — whole widget written before any capture) + +## Runs +- `weaver check`: 3 runs (1 failing, 2 passing; final state passes) +- `weaver capture`: 5 runs + - `01-initial.png`, `02-after-clicks.png` — first Render loop + - `03-initial.png`, `04-after-clicks.png` — after the pixel-driven fixes + - `05-after-reset.png` — extra state, 3× "Log session" then 1× "Reset week", from `reset.actions` + +## Defects fixed because I saw pixels or a snapshot +1. **Inactive weekday letters were illegible.** `text-[#f5f6f8]/40` at 10px on the dark surface washed out in `01-initial.png`; the M/T/W/T/S/S row read as smudges at 1× scale. Raised to `/50`. +2. **The "WEEKLY GOAL" caption was illegible.** Same failure at `/35`, worse because the caption sits directly above the bar and had no neighbouring bright element. Raised to `/45`. +3. **The label sat too close to the bar.** A 3× zoom of the progress block in `02-after-clicks.png` showed the caption crowding the track even though the layout proved no overlap (caption 110–120, bar 127–134). Raised the block gap from 7px to 8px. + +Everything else the captures confirmed rather than corrected: 36px-wide cells at x = 16/58/100/142/184/226/268 (equal, last edge exactly on the 304px content bound), header baselines both ending at y = 27, buttons at 140×40 filling the row, `3 / 20` with the fill ending at x ≈ 59 (15% of the 288px track), and `state=[focused,hovered]` on the pressed button proving `hover:` resolves natively. + +One defect was caught by `weaver check` rather than pixels and is listed for completeness: the first draft sized the progress fill with a computed `` class={`w-[${filled}px] …`} ``, which fails `class must resolve to at most 32 literal strings so weaver check can validate every utility`. + +## Spec items I could not meet +None. One implementation note: + +- **The progress bar is drawn on a ``, not laid out.** A fill of "sessions / 20" needs 21 distinct widths, and `class` must resolve to at most 32 static literals, so a computed width utility is not expressible. `drawProgress` paints two `fillRoundRect`s (track and fill) once per render with no `fps`, so it costs nothing between provider ticks — the same shape as the shipped `clock` example's dial. This gives an exact continuous 15% fill rather than a quantised approximation. +- The trade this makes: the bar contributes no semantic node beyond its 288×7 group, so a snapshot reader sees the `3 / 20` text but not the fill. The pixels are the receipt for the fill. + +## Verified states +| Capture | Expectation | Result | +|---|---|---| +| `03-initial` | all days 0, `0 / 20`, empty bar | ✓ | +| `04-after-clicks` | Fri = 3, others 0, `3 / 20`, fill at 15% | ✓ | +| `05-after-reset` | 3 logged then reset ⇒ all 0, `0 / 20` | ✓ | + +Receipt `status` was `"ok"` on all five captures. + +## Confidence +**9 / 10.** Every spec item is confirmed by a snapshot and by pixels at 1× scale, and the two interactive paths are driven end to end. The remaining point is taste rather than correctness: the 36×58 day cells carry more internal dead space than the shipped examples would, because the day row takes `grow` and absorbs all the column's slack. diff --git a/experiments/render-loop-cadence/runs/B4/widget.tsx b/experiments/render-loop-cadence/runs/B4/widget.tsx new file mode 100644 index 00000000..49bb1449 --- /dev/null +++ b/experiments/render-loop-cadence/runs/B4/widget.tsx @@ -0,0 +1,106 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// Focus Week: seven day cells fed by one persisted counter map, keyed by the +// short weekday name the `time` provider already speaks. One provider, no +// timers of our own, no network. + +const order = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] as const; +const letters = ["M", "T", "W", "T", "F", "S", "S"] as const; + +type Counts = Record; + +const empty: Counts = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +const goal = 20; +const accent = "#ff7a59"; + +// The bar is drawn rather than laid out: `weaver check` resolves `class` to at +// most 32 literal strings, so a fill width of "sessions / 20" cannot be a +// utility. One rounded rect per render, no `fps`, so it costs nothing between +// provider ticks. +function drawProgress(ctx: CanvasCtx, fraction: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff1f"); + const filled = Math.max(0, Math.min(1, fraction)) * ctx.width; + if (filled > 0) ctx.fillRoundRect(0, 0, Math.max(filled, ctx.height), ctx.height, radius, accent); +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage("sessions", empty); + + const today = time.weekday; + const total = order.reduce((sum, day) => sum + (counts[day] ?? 0), 0); + + const cell = (day: string, letter: string) => { + const current = day === today; + return ( + + {letter} + {counts[day] ?? 0} + + ); + }; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {order.map((day, index) => cell(day, letters[index]))} + + + + + WEEKLY GOAL + {total} / {goal} + + drawProgress(ctx, total / goal)} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/C1/REPORT.md b/experiments/render-loop-cadence/runs/C1/REPORT.md new file mode 100644 index 00000000..a9248267 --- /dev/null +++ b/experiments/render-loop-cadence/runs/C1/REPORT.md @@ -0,0 +1,54 @@ +# Focus Week — run report + +**Condition:** C (progressive capture — four slices, Render loop after each) + +**Runs:** 11 `weaver check` runs, 13 `weaver capture` runs (captures 01–13; every +slice captured its initial state, slice 4 also captured the after-clicks state). + +## Defects fixed because I saw pixels or a snapshot + +1. **Progress fill broke into three pills instead of one bar.** Slice 3 shipped a + continuous fill: a rounded `overflow-hidden` track holding 20 equal `grow` + cells, lit ones painted accent, so the fill would land exactly on the session + count. Capture 07 (and a 6× pixel dump of the bar region) showed the three lit + cells rendered as three separate rounded pills with notched seams. Capture 08 + removed the rounded mask from the track and capture 09 added explicit + `rounded-[0px]` to each lit cell; both rendered identically, so the ~2px corner + rounding on each small box does not come from any utility I wrote and cannot be + turned off from widget code. Fix: stop fighting it — the meter is now 20 + explicitly gapped ticks (`gap-[3px]`, `rounded-[2px]`), so the seams read as + intentional ticks. 3 lit of 20 is still exactly 15%, and the count is now + countable at a glance. +2. **Idle day cells had an invisible border** (`border-[#ffffff]/0`) purely to + stop today's ring from shifting the text inside. Looking at capture 10 next to + 12, a faint real border (`/8`) does the same job and reads as deliberate + instead of as a "why is this here?" line. + +Everything else (header baseline alignment, seven cells filling the width exactly +via `w-1/7`, the 42px button row landing flush with the bottom padding) came out +right on its first capture and the snapshot bounds confirmed it: cells span +x=18..302 with equal 40.571px pitch, buttons end at y=184 against a 184px content +box, no overlapping or clipped bounds anywhere. + +## Spec items I could not meet + +None. One deviation worth naming: item 3 asks for "a progress bar", and this is a +20-tick meter rather than a smooth fill. That was forced by the renderer behavior +in defect 1 — a multi-box continuous fill always shows seam artifacts, and a +single-box fill cannot be built because `class` must resolve to at most 32 literal +strings at `weaver check`, so no computed width (`w-${n}/20`, `w-[${px}px]`) is +allowed. The tick meter is the exact same information, drawn cleanly. + +## After-clicks verification (capture 13) + +Receipt `status: "ok"`, three `click` actions applied. Snapshot names: Friday's +cell shows `3`, the other six show `0`, the label is `3 / 20`, and the buttons +expose `role=button name="Log session"` and `role=button name="Reset week"`. +3 of 20 ticks lit = 15%. + +## Confidence + +9 / 10. Every spec item is verified in pixels and in the semantic snapshot at the +widget's real 320×200. The missing point is the tick meter versus a smooth bar, +and hover/pressed styles, which `weaver check` accepts and the contract defines +but a static capture cannot exercise. diff --git a/experiments/render-loop-cadence/runs/C1/widget.tsx b/experiments/render-loop-cadence/runs/C1/widget.tsx new file mode 100644 index 00000000..95a213be --- /dev/null +++ b/experiments/render-loop-cadence/runs/C1/widget.tsx @@ -0,0 +1,123 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +// Focus Week: seven day cells fed by per-weekday session counts. +// Only the `time` provider is subscribed; it names today and dates the header. + +interface Day { + key: string; // matches TimeData.weekday + letter: string; // column heading +} + +const week: Day[] = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +type Counts = Record; + +function emptyWeek(): Counts { + return { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; +} + +const goal = 20; + +// One tick per goal session. Equal ticks make the meter land exactly on the +// session count, and the gaps keep every tick readable at 1x. +const ticks: number[] = Array.from({ length: goal }, (_, index) => index); + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage("counts", emptyWeek()); + const total = week.reduce((sum, day) => sum + (counts[day.key] ?? 0), 0); + const filled = Math.max(0, Math.min(goal, total)); + + // One seventh of the row each, so the cells always fill the width exactly. + // The outer cell carries the spacing; the inner box carries the highlight, and + // every cell keeps a border so today's ring never shifts the text inside. + const cell = (day: Day) => { + const today = day.key === time.weekday; + return ( + + + {day.letter} + {counts[day.key] ?? 0} + + + ); + }; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {week.map(cell)} + + + + + Sessions this week + {total} / {goal} + + + {ticks.map((index) => ( + + ))} + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/C2/REPORT.md b/experiments/render-loop-cadence/runs/C2/REPORT.md new file mode 100644 index 00000000..287830c9 --- /dev/null +++ b/experiments/render-loop-cadence/runs/C2/REPORT.md @@ -0,0 +1,54 @@ +# Focus Week — build report + +**Condition:** C (progressive capture — four visual slices, Render loop after each) + +**Runs:** 14 `weaver check` runs, 11 `weaver capture` runs (captures 01–11). + +## Defects fixed because I saw pixels or a snapshot + +1. **Progress bar rendered as a row of pills, not a bar.** My first bar was 20 + equal-width, gapless segments (one per goal session) inside a + `rounded-full overflow-hidden` track. Capture 03 showed a scalloped strip + rather than a continuous fill. A per-column height profile of the accent + pixels confirmed it: every 14.2px segment boundary loses 4px of height at + the top and bottom rows, so each segment is painted with its own rounded + ends. Captures 04 and 05 ruled out the track: the profile is byte-identical + with `rounded-full`, with `rounded-full` and no `overflow-hidden`, and with + `rounded-[3px]`. Replaced with a single fill child sized by a `w-N/20` + fraction (capture 06 verified one continuous 99.4px pill for 7/20, and the + final captures show 42.6px = exactly 15% for 3/20). +2. **Low-contrast secondary text.** At 1x in capture 08 the weekday letters + (`/35`) and the "Weekly goal" label (`/40`) were near-illegible against the + dark surface. Raised to `/45` and `/50`, and lifted today's cell tint from + `bg-[#ff7a59]/16` to `/18` so the highlight reads at a glance (capture 10). + +Also used, without a defect: the slice-3 snapshot bounds told me the content +column ended at y=141.5 with only 44.5px left, so I sized the frame padding, +gaps and button height (12/12/36) from measured numbers before adding the +button row. The final tree ends at y=185.5 inside a content box that runs to +y=188 — nothing clipped, nothing overlapping. + +## Spec items I could not meet + +None. One implementation note: `weaver check` requires a `class` to resolve to +at most 32 literal strings, so a computed pixel width for the bar fill is a +check error (`class must resolve to at most 32 literal strings...`). The fill +is therefore a table over the 21 reachable session counts using `w-N/20` +fractions. For a goal of 20 every reachable value is exact, so nothing is lost +to quantization; the bar is continuous, not segmented. + +## Verified in the final captures (10 and 11) + +- Header: "Focus week" and "Fri, Sep 4" share a baseline (both bottoms at + y=30.75). +- Seven cells, exactly 38px each on a 41px pitch spanning the full 284px + content width; letters M T W T F S S; every day shows a number; Friday is + tinted and accented. +- Label "3 / 20" sits on its own row 6px above the 8px track — no overlap. +- Bar fill 42.6px of 284px = 15%. +- Buttons expose `role=button name="Log session"` and + `role=button name="Reset week"`; after the three-click action file, Friday + shows 3 and every other day 0. +- Both capture receipts report `status: "ok"`. + +**Confidence the widget matches the spec: 9/10.** diff --git a/experiments/render-loop-cadence/runs/C2/widget.tsx b/experiments/render-loop-cadence/runs/C2/widget.tsx new file mode 100644 index 00000000..5b86422b --- /dev/null +++ b/experiments/render-loop-cadence/runs/C2/widget.tsx @@ -0,0 +1,106 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +// Focus Week — one cell per weekday, a weekly goal bar, and two buttons. +// Counts live in widget storage keyed by the `time` provider's weekday, so +// they survive restarts; nothing here polls or fetches. + +const goal = 20; + +const days = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +const emptyWeek: Record = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [sessions, setSessions] = useStorage>("sessions", emptyWeek); + const logged = days.reduce((total, day) => total + (sessions[day.key] ?? 0), 0); + + // `weaver check` validates every literal a class can resolve to, so the fill + // is a table over the 21 reachable counts rather than a computed width. + const fill = + logged >= 20 ? "w-full" : logged >= 19 ? "w-19/20" : logged >= 18 ? "w-18/20" : logged >= 17 ? "w-17/20" : + logged >= 16 ? "w-16/20" : logged >= 15 ? "w-15/20" : logged >= 14 ? "w-14/20" : logged >= 13 ? "w-13/20" : + logged >= 12 ? "w-12/20" : logged >= 11 ? "w-11/20" : logged >= 10 ? "w-10/20" : logged >= 9 ? "w-9/20" : + logged >= 8 ? "w-8/20" : logged >= 7 ? "w-7/20" : logged >= 6 ? "w-6/20" : logged >= 5 ? "w-5/20" : + logged >= 4 ? "w-4/20" : logged >= 3 ? "w-3/20" : logged >= 2 ? "w-2/20" : logged >= 1 ? "w-1/20" : + "w-0"; + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => { + const today = day.key === time.weekday; + return ( + + {day.letter} + {sessions[day.key] ?? 0} + + ); + })} + + + + + Weekly goal + {logged} / {goal} + + + + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/C3/REPORT.md b/experiments/render-loop-cadence/runs/C3/REPORT.md new file mode 100644 index 00000000..60868c90 --- /dev/null +++ b/experiments/render-loop-cadence/runs/C3/REPORT.md @@ -0,0 +1,48 @@ +# Focus Week — build report + +**Condition:** C (progressive capture) + +**Runs:** `weaver check` 7 · `weaver capture` 6 + +## Defects fixed because I saw pixels or a snapshot + +- **Day letters unreadable.** Slice 2's PNG showed `M T W T F S S` at `text-[#f5f6f8]/40` + sitting almost invisible on the `bg-[#ffffff]/6` chips at 1x. Raised to `/55`. +- **Button row would have been clipped.** Slice 3's snapshot put the progress block's + bottom edge at y=136.75 with the content box ending at y=184. That left 35.25 px after + the 12 px gap, so the buttons were sized `h-[34px]` instead of the 40–44 px I had + sketched. The slice 4 snapshot confirms the row ends at y=182.75 — inside the box, + nothing clipped. +- **Equal-width day cells confirmed, not guessed.** The slice 2 snapshot showed each cell + at exactly 34.857143 px spanning x=20 to x=300, which validated the `w-[0px] grow` + basis-zero idiom over the fixed-width fallback I had as plan B. +- **Progress fill geometry proved before wiring storage.** Slice 3 was captured with a + temporary seed of 6 sessions so the fill had a visible length to inspect; the reverted + zero state and the after-clicks 15% fill both match. + +One defect was caught by `weaver check`, not pixels, and is noted only for completeness: +`CanvasNeedsExplicitSize` rejected `w-full` on the progress canvas (a canvas has no +intrinsic size). Fixed with the measured content width, `w-[280px]`. + +## Spec items not met + +None. + +## Verification + +- `04-initial.png` — empty week, every cell `0`, label `0 / 20`, empty track. +- `05-after-clicks.png` (the required action file) — Friday `3`, all other days `0`, + label `3 / 20`, fill at 15% of the 280 px track (42 px). Receipt `status: "ok"`. +- `06-after-reset.png` (my own action file: two logs then Reset week) — every cell back + to `0`, label `0 / 20`. Both captures also show the button under the cursor painting + its `hover:` background, so the native state swaps are live. +- Snapshot accessible names are exactly `Log session` and `Reset week`. +- `widget_nodes=46/1024`, `canvas_frame_budget_exceeded=0`. + +## Confidence + +9 / 10. Everything in the spec is verified against pixels, the semantic snapshot, and an +"ok" receipt. The reserved point is for things the headless renderer cannot show me: the +`pressed:` styles are declared and pass check but I never captured a frame mid-press, and +`useStorage` persistence across a real restart is exercised only through the capture +harness's isolated storage, not an actual `weaver up` cycle. diff --git a/experiments/render-loop-cadence/runs/C3/widget.tsx b/experiments/render-loop-cadence/runs/C3/widget.tsx new file mode 100644 index 00000000..790db8d2 --- /dev/null +++ b/experiments/render-loop-cadence/runs/C3/widget.tsx @@ -0,0 +1,103 @@ +import { useProvider, useStorage, widget, type CanvasCtx } from "@weaver/sdk"; + +// Focus Week — a week of logged focus sessions against a weekly goal. +// One provider (`time`) tells us the date and which cell is today. + +const goal = 20; +const accent = "#ff7a59"; + +const surface = [ + { type: "linear" as const, stops: [{ offset: 0, color: "#0b0d12e6" }, { offset: 1, color: "#0b0d12e6" }] }, + { type: "linear" as const, start: [0, 0] as [number, number], end: [0, 1] as [number, number], stops: [{ offset: 0, color: "#ffffff12" }, { offset: 0.6, color: "#ffffff00" }] }, +]; + +// Monday-first week. `key` matches TimeData.weekday, `letter` is the cell head. +const week = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +type Counts = Record; + +const emptyWeek: Counts = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +// The fill needs a pixel-exact width, so it is drawn rather than classed. +// No `fps`: this runs once per render and costs nothing between renders. +function drawBar(ctx: CanvasCtx, done: number): void { + ctx.clear(); + const radius = ctx.height / 2; + ctx.fillRoundRect(0, 0, ctx.width, ctx.height, radius, "#ffffff14"); + if (done <= 0) return; + const fraction = Math.min(1, done / goal); + ctx.fillRoundRect(0, 0, Math.max(ctx.height, ctx.width * fraction), ctx.height, radius, accent); +} + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage("week", emptyWeek); + const done = week.reduce((total, day) => total + (counts[day.key] ?? 0), 0); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {week.map((day) => { + const today = day.key === time.weekday; + return ( + + {day.letter} + {counts[day.key] ?? 0} + + ); + })} + + + + + Sessions + {done} / {goal} + + drawBar(ctx, done)} /> + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/runs/C4/REPORT.md b/experiments/render-loop-cadence/runs/C4/REPORT.md new file mode 100644 index 00000000..835b0f8b --- /dev/null +++ b/experiments/render-loop-cadence/runs/C4/REPORT.md @@ -0,0 +1,24 @@ +# Focus Week — build report + +**Condition:** C (progressive capture — four visual slices, Render loop after each) + +## Runs +- `weaver check`: **11** runs (5 of them deliberate probes of what `class` expressions the checker can resolve). +- `weaver capture`: **8** runs (`01`–`08` in `captures/`). Every receipt reported `status: "ok"`. + +Slice boundaries: 01 = frame + header, 02 = day cells, 03/04 = progress bar (03 with counts temporarily seeded so the fill was visible, 04 the real empty state), 05/06 = buttons + storage, 07/08 = final pair after the last polish. + +## Defects fixed because I saw pixels or a snapshot +1. **Day strip ate the whole widget.** Slice 2's PNG showed the seven cells 142px tall — I had given the row `grow`, so it absorbed all the space the bar and buttons had not claimed yet. Replaced with a fixed `h-[48px]` row, which also made the remaining vertical budget arithmetic explicit (170px content = 17.5 header + 48 days + 23 bar block + 38 buttons + 3×14 gaps + 1.5 slack). +2. **Day letters were too dim at 1×.** In the slice 2 capture the `M T W T F S S` row at `text-[#f5f6f8]/35` was barely separable from the cell background. Raised to `/45`. +3. **Progress caption was too dim at 1×.** In the slice 3 capture "Sessions this week" at `/40` read as noise next to the `0 / 20` value. Raised to `/50`. + +The three `check` failures I hit (template-literal class, array-indexed class, both rejected with "class must resolve to at most 32 literal strings") were caught statically, not by pixels, so they are not in this list — but they set the bar's implementation: the fill width is a 21-branch literal ladder (`total === N ? "… w-[Npx]"`), one class per session count, with a comment saying why. 3 sessions renders a 43px fill in a 284px track = 15.1%. + +## Spec items I could not meet +None. All five items are in: header with baseline-aligned title and "Fri, Sep 4"; seven equal-width cells (37.14px each, gap 4, summing to exactly 284) with today highlighted in amber; progress bar with its `N / 20` label on a separate row above the track, so overlap is structurally impossible; two buttons with `hover:bg-*` and `pressed:bg-*` and `useStorage` keyed by short weekday name. + +Verified in the `08` snapshot: `role=button name="Log session"` and `role=button name="Reset week"` — exact accessible names. After the three scripted clicks, Friday shows 3, every other day 0, label "3 / 20", fill 43px. + +## Confidence +**9 / 10.** Pixels and semantics both confirm the initial and after-clicks states at the real 320×200 size. The point I did not directly observe is the hover/pressed *swap* isolated from a click — the after-clicks capture leaves the pointer resting on "Log session", so the PNG shows its hover fill (`#fbbf24`) rather than its base fill, which is evidence the native state resolves but not a controlled test of `pressed:`. diff --git a/experiments/render-loop-cadence/runs/C4/widget.tsx b/experiments/render-loop-cadence/runs/C4/widget.tsx new file mode 100644 index 00000000..4bb6b176 --- /dev/null +++ b/experiments/render-loop-cadence/runs/C4/widget.tsx @@ -0,0 +1,121 @@ +import { useProvider, useStorage, widget } from "@weaver/sdk"; + +// Focus Week — seven day cells, a weekly session goal, and two buttons. +// Counts live in widget storage keyed by the short weekday name, so a +// restart reopens the same week. + +const goal = 20; + +const days: { key: string; letter: string }[] = [ + { key: "Mon", letter: "M" }, + { key: "Tue", letter: "T" }, + { key: "Wed", letter: "W" }, + { key: "Thu", letter: "T" }, + { key: "Fri", letter: "F" }, + { key: "Sat", letter: "S" }, + { key: "Sun", letter: "S" }, +]; + +type Counts = Record; + +const empty: Counts = { Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0, Sat: 0, Sun: 0 }; + +export default widget({ + name: "Focus Week", + size: [320, 200], + anchor: { corner: "top-right", offset: [24, 24] }, + subscribe: ["time"], +}, () => { + const time = useProvider("time"); + const [counts, setCounts] = useStorage("counts", empty); + const sessions = days.reduce((sum, day) => sum + (counts[day.key] ?? 0), 0); + const total = Math.min(sessions, goal); + + return ( + + + Focus week + {time.weekday}, {time.month} {time.day} + + + + {days.map((day) => { + const today = day.key === time.weekday; + return ( + + {day.letter} + {counts[day.key] ?? 0} + + ); + })} + + + + + Sessions this week + {sessions} / {goal} + + {/* The fill width is one of 21 literal classes: weaver check validates + every class it can see, so the width cannot be computed inline. */} + + + + + + + + + + + ); +}); diff --git a/experiments/render-loop-cadence/usage.tsv b/experiments/render-loop-cadence/usage.tsv new file mode 100644 index 00000000..1412bef7 --- /dev/null +++ b/experiments/render-loop-cadence/usage.tsv @@ -0,0 +1,10 @@ +B1 tokens=68376 tool_uses=33 duration_ms=229348 +C3 tokens=67706 tool_uses=40 duration_ms=287989 +C4 tokens=62627 tool_uses=38 duration_ms=298064 +B2 tokens=80682 tool_uses=48 duration_ms=358344 +B3 tokens=90177 tool_uses=44 duration_ms=391110 +B4 tokens=84711 tool_uses=42 duration_ms=396198 +C2 tokens=84907 tool_uses=59 duration_ms=465746 +A2 tokens=97332 tool_uses=44 duration_ms=487366 +C1 tokens=80780 tool_uses=55 duration_ms=489943 +A1 tokens=109527 tool_uses=56 duration_ms=634511 diff --git a/experiments/render-loop-cadence/watch-saves.mjs b/experiments/render-loop-cadence/watch-saves.mjs new file mode 100644 index 00000000..1713e4ea --- /dev/null +++ b/experiments/render-loop-cadence/watch-saves.mjs @@ -0,0 +1,15 @@ +import { statSync, appendFileSync, readdirSync, existsSync } from "node:fs"; +const root = "/tmp/weaver-exp/runs"; +const seen = new Map(); +setInterval(() => { + if (!existsSync(root)) return; + for (const run of readdirSync(root)) { + const f = `${root}/${run}/widget.tsx`; + let st; try { st = statSync(f); } catch { continue; } + const key = `${st.mtimeMs}:${st.size}`; + if (seen.get(run) !== key) { + seen.set(run, key); + appendFileSync("/tmp/weaver-exp/saves.log", `${new Date().toISOString()}\t${run}\t${st.size}\n`); + } + } +}, 500);