diff --git a/skills/conjure-widget/SKILL.md b/.agents/skills/conjure-widget/SKILL.md similarity index 84% rename from skills/conjure-widget/SKILL.md rename to .agents/skills/conjure-widget/SKILL.md index 925faeeb..951f8b44 100644 --- a/skills/conjure-widget/SKILL.md +++ b/.agents/skills/conjure-widget/SKILL.md @@ -27,7 +27,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 @@ -93,7 +93,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: @@ -112,6 +112,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..951f8b44 --- /dev/null +++ b/.claude/skills/conjure-widget/SKILL.md @@ -0,0 +1,147 @@ +--- +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. Run the CLI as `weaver …`; it is on `PATH` after +`npm run link` in the Weaver repository. Without that link, `npx --no-install +weaver …` works only from inside the repository tree, and from anywhere else +fails with an unrelated npm message about a missing `weaver` package. 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 + `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 + `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, then after each + added visual region (header, then each content block, then the controls and + every requested state), and after any edit that changes semantics or + interaction behavior. Each pass is a step the user can watch land. When the + user is not watching the desktop, one pass after the last edit is enough. + The final pass is never optional: no widget is complete until its last PNG + has been opened and inspected and its snapshot read. Fix what contradicts + the request or the contract. When a capture shows renderer behavior that + contradicts the contract, keep the requested design and report a framework + reproduction (see **Framework failures**); do not redesign the request + around the surprise. +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 `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 `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. Secondary text on the dark house surface needs at least + `/45` opacity to read at 1×; dimmer text is the most common thing a first + capture reveals. +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/.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/README.md b/README.md index 0abd33c7..50ea7b40 100644 --- a/README.md +++ b/README.md @@ -217,9 +217,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 +weaver capture examples/system \ + --provider-fixture test/capture/system.provider.json --out /tmp/system.png +``` + ## How it's put together | Path | What | @@ -227,7 +250,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 9e6189df..94957d6a 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 caa0a610..00000000 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 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 b264f7d3..00000000 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 1f9e46f3..00000000 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 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 caa0a610..00000000 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 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/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/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/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 00000000..e21fd446 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/A1-after.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/A1-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/A1-after.receipt.json new file mode 100644 index 00000000..4456c01f --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A1-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "7bbe91519ca167387f0e41be1f60bd554a01149ca3ba2129a4434725f31591fc", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A1/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A1/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": 47, + "nodes": 46, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 319358, + "spawn": 53561, + "startup": 29955, + "render": 1859, + "encode": 485, + "write": 253, + "total": 405700 + }, + "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/A1-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/A1-after.snapshot.txt new file mode 100644 index 00000000..9fe41db3 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A1-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40983000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=31759 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=1788623601244239000 gpu_input_latency_ns=2647000 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=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=159 canvas_frame_encoder_cache_actions=112 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=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=43 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=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=559 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 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,47.333332 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,47.333332 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54.083332 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,74.58333 37.714287x18) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,47.333332 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,54.083332 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,74.58333 37.714287x18) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,47.333332 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,54.083332 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,74.58333 37.714287x18) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,47.333332 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,54.083332 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,74.58333 37.714287x18) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,47.333332 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,54.083332 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,74.58333 37.714287x18) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,47.333332 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,54.083332 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,74.58333 37.714287x18) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,47.333332 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,54.083332 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,74.58333 37.714287x18) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,110.666664 288x26) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,110.666664 288x14) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY SESSIONS" bounds=(16,110.666664 101.674805x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="3 / 20" bounds=(270.42578,112.666664 33.57422x12) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,130.66666 286x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,148 170x36) focused=true enabled=true parent=#2479990500450380282 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,148 170x36) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,157.25 170x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(194,148 110x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(194,148 110x36) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(194,157.25 110x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/astra/final-captures/A1-initial.png b/experiments/render-loop-cadence/astra/final-captures/A1-initial.png new file mode 100644 index 00000000..1dd5b6dd Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/A1-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/A1-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/A1-initial.receipt.json new file mode 100644 index 00000000..4d036bce --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A1-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "7bbe91519ca167387f0e41be1f60bd554a01149ca3ba2129a4434725f31591fc", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A1/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A1/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": 341750, + "spawn": 57400, + "startup": 41567, + "render": 1846, + "encode": 480, + "write": 266, + "total": 453943 + }, + "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/A1-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/A1-initial.snapshot.txt new file mode 100644 index 00000000..0ce88e97 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A1-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=43883000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=31636 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=147 canvas_frame_encoder_cache_actions=100 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=54 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=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=42 canvas_frame_gpu_packet_cache_actions=100 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=529 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 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,47.333332 288x52) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,47.333332 37.714287x52) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54.083332 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,74.58333 37.714287x18) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,47.333332 37.714287x52) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,54.083332 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,74.58333 37.714287x18) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,47.333332 37.714287x52) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,54.083332 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,74.58333 37.714287x18) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,47.333332 37.714287x52) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,54.083332 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,74.58333 37.714287x18) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,47.333332 37.714287x52) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,54.083332 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(182.85715,74.58333 37.714287x18) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,47.333332 37.714287x52) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,54.083332 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,74.58333 37.714287x18) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,47.333332 37.714287x52) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,47.333332 37.714287x52) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,54.083332 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,74.58333 37.714287x18) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#14521845296726044339 role=group name="" bounds=(16,110.666664 288x26) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15091253999156092641 role=group name="" bounds=(16,110.666664 288x14) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#15729049687520163901 role=text name="WEEKLY SESSIONS" bounds=(16,110.666664 101.674805x17.5) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12445700919989132789 role=text name="0 / 20" bounds=(270.42578,112.666664 33.57422x12) focused=false enabled=true parent=#15091253999156092641 + widget @w1/widget-canvas#12567209568093186446 role=group name="" bounds=(16,130.66666 286x6) focused=false enabled=true parent=#14521845296726044339 + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#4860165038249741585 role=button name="Log session" bounds=(16,148 170x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#7217482369044429682 role=group name="" bounds=(16,148 170x36) focused=false enabled=true parent=#4860165038249741585 + widget @w1/widget-canvas#2165676007840600680 role=text name="Log session" bounds=(16,157.25 170x17.5) focused=false enabled=true parent=#7217482369044429682 + widget @w1/widget-canvas#2238034082661263458 role=button name="Reset week" bounds=(194,148 110x36) focused=false enabled=true parent=#2479990500450380282 actions=[focus,press] + widget @w1/widget-canvas#11813601622197617951 role=group name="" bounds=(194,148 110x36) focused=false enabled=true parent=#2238034082661263458 + widget @w1/widget-canvas#7032127835310027939 role=text name="Reset week" bounds=(194,157.25 110x17.5) focused=false enabled=true parent=#11813601622197617951 diff --git a/experiments/render-loop-cadence/astra/final-captures/A2-after.png b/experiments/render-loop-cadence/astra/final-captures/A2-after.png new file mode 100644 index 00000000..e0770a47 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/A2-after.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/A2-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/A2-after.receipt.json new file mode 100644 index 00000000..0f6db89f --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A2-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "bfaf52dd493a8422c56299a741e1a7eff6ee1242686269a16647439cc0d17804", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A2/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A2/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": 328106, + "spawn": 53350, + "startup": 30944, + "render": 1593, + "encode": 478, + "write": 231, + "total": 415811 + }, + "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/A2-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/A2-after.snapshot.txt new file mode 100644 index 00000000..7a6e2bdc --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A2-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=40840000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32035 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=1788623603195392000 gpu_input_latency_ns=2469000 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=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=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=44 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=47 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=510 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 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,18 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + 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 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,48 288x56) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,48 37.714287x56) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,75.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,48 37.714287x56) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,54 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,75.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,48 37.714287x56) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,54 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,75.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,48 37.714287x56) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,54 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,75.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,48 37.714287x56) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,54 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(182.85715,75.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,48 37.714287x56) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,54 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,75.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,48 37.714287x56) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,54 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,75.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,114 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,123 216x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 20" bounds=(244,117.25 60x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,148 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,148 168x36) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 168x36) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,157.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,148 112x36) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,148 112x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,157.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/A2-initial.png b/experiments/render-loop-cadence/astra/final-captures/A2-initial.png new file mode 100644 index 00000000..265de7a3 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/A2-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/A2-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/A2-initial.receipt.json new file mode 100644 index 00000000..2e123438 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A2-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "bfaf52dd493a8422c56299a741e1a7eff6ee1242686269a16647439cc0d17804", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A2/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/A2/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": 342084, + "spawn": 48150, + "startup": 32813, + "render": 1577, + "encode": 480, + "write": 694, + "total": 423227 + }, + "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/A2-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/A2-initial.snapshot.txt new file mode 100644 index 00000000..0909c1ac --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/A2-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=34858000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=31912 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=135 canvas_frame_encoder_cache_actions=86 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=42 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=42 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=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=478 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 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,18 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + 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 + widget @w1/widget-canvas#10162277730996300551 role=group name="" bounds=(16,48 288x56) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#15080105495274655534 role=group name="" bounds=(16,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#14348414673741379304 role=group name="" bounds=(16,48 37.714287x56) focused=false enabled=true parent=#15080105495274655534 + widget @w1/widget-canvas#15095474804485896871 role=text name="M" bounds=(16,54 37.714287x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(16,75.5 37.714287x22.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#12556696334436056940 role=group name="" bounds=(57.714287,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#3815727781268906353 role=group name="" bounds=(57.714287,48 37.714287x56) focused=false enabled=true parent=#12556696334436056940 + widget @w1/widget-canvas#16579326942085127115 role=text name="T" bounds=(57.714287,54 37.714287x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(57.714287,75.5 37.714287x22.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7597821939212968695 role=group name="" bounds=(99.42857,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9425647543182277583 role=group name="" bounds=(99.42857,48 37.714287x56) focused=false enabled=true parent=#7597821939212968695 + widget @w1/widget-canvas#11248424745687431576 role=text name="W" bounds=(99.42857,54 37.714287x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(99.42857,75.5 37.714287x22.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#7296780229786415153 role=group name="" bounds=(141.14285,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#9271565681298391461 role=group name="" bounds=(141.14285,48 37.714287x56) focused=false enabled=true parent=#7296780229786415153 + widget @w1/widget-canvas#7285692155281014087 role=text name="T" bounds=(141.14285,54 37.714287x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(141.14285,75.5 37.714287x22.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#1102249205766815737 role=group name="" bounds=(182.85715,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#6754876511232257284 role=group name="" bounds=(182.85715,48 37.714287x56) focused=false enabled=true parent=#1102249205766815737 + widget @w1/widget-canvas#1147135667572071714 role=text name="F" bounds=(182.85715,54 37.714287x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(182.85715,75.5 37.714287x22.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#9608914897307801018 role=group name="" bounds=(224.57144,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#2454825294539352308 role=group name="" bounds=(224.57144,48 37.714287x56) focused=false enabled=true parent=#9608914897307801018 + widget @w1/widget-canvas#16294110544623668557 role=text name="S" bounds=(224.57144,54 37.714287x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(224.57144,75.5 37.714287x22.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#10997492118612647209 role=group name="" bounds=(266.28574,48 37.714287x56) focused=false enabled=true parent=#10162277730996300551 + widget @w1/widget-canvas#5379490745807977887 role=group name="" bounds=(266.28574,48 37.714287x56) focused=false enabled=true parent=#10997492118612647209 + widget @w1/widget-canvas#13826355370529843847 role=text name="S" bounds=(266.28574,54 37.714287x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(266.28574,75.5 37.714287x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,114 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,123 216x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="0 / 20" bounds=(244,117.25 60x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,148 288x36) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,148 168x36) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,148 168x36) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,157.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,148 112x36) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,148 112x36) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,157.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/B1-after.png b/experiments/render-loop-cadence/astra/final-captures/B1-after.png new file mode 100644 index 00000000..36320291 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B1-after.png differ 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 00000000..c34ac479 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B1-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/B1-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B1-initial.receipt.json new file mode 100644 index 00000000..e396ec4f --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B1-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "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/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B1/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": 346780, + "spawn": 47409, + "startup": 32692, + "render": 1802, + "encode": 502, + "write": 366, + "total": 428613 + }, + "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/B1-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B1-initial.snapshot.txt new file mode 100644 index 00000000..cc414878 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B1-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=34977000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32200 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=136 canvas_frame_encoder_cache_actions=87 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=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=41 canvas_frame_gpu_packet_cache_actions=87 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=482 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,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="0" 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="0 / 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=false enabled=true parent=#4456204386640616177 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/B2-after.png b/experiments/render-loop-cadence/astra/final-captures/B2-after.png new file mode 100644 index 00000000..e159cf2a Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B2-after.png differ 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 00000000..75c6301a Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B2-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/B2-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B2-initial.receipt.json new file mode 100644 index 00000000..398c70ba --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B2-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "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/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B2/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": 48, + "nodes": 48, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 330843, + "spawn": 48726, + "startup": 34022, + "render": 1753, + "encode": 497, + "write": 254, + "total": 412635 + }, + "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/B2-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B2-initial.snapshot.txt new file mode 100644 index 00000000..7f84d90a --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B2-initial.snapshot.txt @@ -0,0 +1,51 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=36259000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32476 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=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=22 canvas_frame_encoder_commands=146 canvas_frame_encoder_cache_actions=99 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=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=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=54 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=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=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=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=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="0" 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="0 / 20" bounds=(269.9273,110 34.072697x17.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=false enabled=true parent=#5802963363624800140 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/B3-after.png b/experiments/render-loop-cadence/astra/final-captures/B3-after.png new file mode 100644 index 00000000..6d9e6e9c Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B3-after.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/B3-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B3-after.receipt.json new file mode 100644 index 00000000..45e4724a --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B3-after.receipt.json @@ -0,0 +1,70 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "8c24c3be76034c61092ab24bbec5963b465bfa832497b3c3170659c38acdfef2", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B3/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B3/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": 318019, + "spawn": 55835, + "startup": 32044, + "render": 1753, + "encode": 481, + "write": 211, + "total": 408994 + }, + "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/B3-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B3-after.snapshot.txt new file mode 100644 index 00000000..fce731ae --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B3-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=43098000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32884 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=1788623609181275000 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=4 canvas_commands=46 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=144 canvas_frame_encoder_cache_actions=95 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=40 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=44 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=95 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=496 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 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,18 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + 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 + 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.9523,54.5 9.809688x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(29.157516,75 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=(73.00018,54.5 7.14249x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.8718,75 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.84703,54.5 10.877375x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.58609,75 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.42876,54.5 7.14249x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.30037,75 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.48389,54.5 6.4608083x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="3" bounds=(195.70778,75 12.013037x22.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.8154,54.5 7.2263727x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.72896,75 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.5297,54.5 7.2263727x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(279.44324,75 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,114 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,123 232x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 20" bounds=(260,117.25 44x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,150 288x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,150 168x34) focused=true enabled=true parent=#4456204386640616177 state=[focused,hovered] actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,150 168x34) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,158.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,150 112x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,150 112x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,158.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/B3-initial.png b/experiments/render-loop-cadence/astra/final-captures/B3-initial.png new file mode 100644 index 00000000..c44491b2 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B3-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/B3-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B3-initial.receipt.json new file mode 100644 index 00000000..904a537c --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B3-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "schema": "weaver.capture.v1", + "status": "ok", + "provenance": { + "weaverCommit": "ab20771762be56faff04173ab11a5525a8d89be5", + "nativeSdkCommit": "464ff65faa02d36179b34e2252fa2a1cf46f7541", + "bundleSha256": "8c24c3be76034c61092ab24bbec5963b465bfa832497b3c3170659c38acdfef2", + "platform": "darwin-headless-coretext" + }, + "output": { + "image": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B3/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B3/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": 361279, + "spawn": 43333, + "startup": 29154, + "render": 1760, + "encode": 519, + "write": 265, + "total": 436235 + }, + "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/B3-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B3-initial.snapshot.txt new file mode 100644 index 00000000..f8b596ff --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B3-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=31415000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=32761 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=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 288x22) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#16282996836656487105 role=text name="Focus week" bounds=(16,18 91.01953x20) focused=false enabled=true parent=#17141410367181492475 + 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 + 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.9523,54.5 9.809688x17.5) focused=false enabled=true parent=#14348414673741379304 + widget @w1/widget-canvas#5036925338709116941 role=text name="0" bounds=(29.157516,75 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=(73.00018,54.5 7.14249x17.5) focused=false enabled=true parent=#3815727781268906353 + widget @w1/widget-canvas#7946296496768470956 role=text name="0" bounds=(70.8718,75 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.84703,54.5 10.877375x17.5) focused=false enabled=true parent=#9425647543182277583 + widget @w1/widget-canvas#15686864919909977529 role=text name="0" bounds=(112.58609,75 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.42876,54.5 7.14249x17.5) focused=false enabled=true parent=#9271565681298391461 + widget @w1/widget-canvas#802649812111143556 role=text name="0" bounds=(154.30037,75 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.48389,54.5 6.4608083x17.5) focused=false enabled=true parent=#6754876511232257284 + widget @w1/widget-canvas#1591004126705514636 role=text name="0" bounds=(195.70778,75 12.013037x22.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.8154,54.5 7.2263727x17.5) focused=false enabled=true parent=#2454825294539352308 + widget @w1/widget-canvas#8022720664598915415 role=text name="0" bounds=(237.72896,75 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.5297,54.5 7.2263727x17.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#17764601967149365852 role=text name="0" bounds=(279.44324,75 11.399255x22.5) focused=false enabled=true parent=#5379490745807977887 + widget @w1/widget-canvas#5404126479162880160 role=group name="" bounds=(16,114 288x24) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9682609897917696589 role=group name="" bounds=(16,123 232x6) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#15729049687520163901 role=text name="0 / 20" bounds=(260,117.25 44x17.5) focused=false enabled=true parent=#5404126479162880160 + widget @w1/widget-canvas#4456204386640616177 role=group name="" bounds=(16,150 288x34) focused=false enabled=true parent=#8989280229327462431 + widget @w1/widget-canvas#9787074478480440413 role=button name="Log session" bounds=(16,150 168x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#2479990500450380282 role=group name="" bounds=(16,150 168x34) focused=false enabled=true parent=#9787074478480440413 + widget @w1/widget-canvas#2627286533109177756 role=text name="Log session" bounds=(16,158.25 168x17.5) focused=false enabled=true parent=#2479990500450380282 + widget @w1/widget-canvas#2335965760644945153 role=button name="Reset week" bounds=(192,150 112x34) focused=false enabled=true parent=#4456204386640616177 actions=[focus,press] + widget @w1/widget-canvas#13497137971391810392 role=group name="" bounds=(192,150 112x34) focused=false enabled=true parent=#2335965760644945153 + widget @w1/widget-canvas#10422795391015277995 role=text name="Reset week" bounds=(192,158.25 112x17.5) focused=false enabled=true parent=#13497137971391810392 diff --git a/experiments/render-loop-cadence/astra/final-captures/B4-after.png b/experiments/render-loop-cadence/astra/final-captures/B4-after.png new file mode 100644 index 00000000..0a7616ab Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B4-after.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/B4-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/B4-after.receipt.json new file mode 100644 index 00000000..616a912a --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B4-after.receipt.json @@ -0,0 +1,70 @@ +{ + "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/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/B4/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": 47, + "nodes": 46, + "images": 0, + "fonts": 0, + "pixelsDifferentFromClear": 63572 + }, + "pending": { + "timers": 1, + "fetches": 0, + "images": 0, + "providers": [], + "frameRequests": 0 + }, + "timingUs": { + "bundle": 325697, + "spawn": 51199, + "startup": 28720, + "render": 1573, + "encode": 491, + "write": 253, + "total": 410785 + }, + "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/B4-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/B4-after.snapshot.txt new file mode 100644 index 00000000..63b05124 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/B4-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=38928000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33171 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=1788623611095551000 gpu_input_latency_ns=2677000 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=47 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=25 canvas_frame_encoder_commands=149 canvas_frame_encoder_cache_actions=96 canvas_frame_encoder_pipeline_binds=25 canvas_frame_encoder_draws=25 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=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=40 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=44 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=45 canvas_frame_gpu_packet_cache_actions=96 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=19/2048 text_layout_lines=19/8192 canvas_frame_dirty=(0,0 320x200) canvas_frame_profile_work_units=526 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,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="3" 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#13054432763944255439 role=group name="" bounds=(18,123 31.800001x6) focused=false enabled=true parent=#15731116241903212993 + widget @w1/widget-canvas#15729049687520163901 role=text name="3 / 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=true enabled=true parent=#4456204386640616177 state=[focused,hovered] 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/B4-initial.png b/experiments/render-loop-cadence/astra/final-captures/B4-initial.png new file mode 100644 index 00000000..6187e33a Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/B4-initial.png differ 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 00000000..65009d6a Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C1-after.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/C1-after.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C1-after.receipt.json new file mode 100644 index 00000000..e34fee0e --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C1-after.receipt.json @@ -0,0 +1,70 @@ +{ + "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/after-clicks.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C1/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": 329467, + "spawn": 58390, + "startup": 34173, + "render": 1846, + "encode": 533, + "write": 267, + "total": 425863 + }, + "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/C1-after.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C1-after.snapshot.txt new file mode 100644 index 00000000..92fecae1 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C1-after.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=45258000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33453 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=1788623613136835000 gpu_input_latency_ns=2958000 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=144 canvas_frame_encoder_cache_actions=95 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=41 canvas_frame_glyph_uploads=0 canvas_frame_glyph_retains=44 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=95 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=498 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 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="3" 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="3 / 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=true enabled=true parent=#4456204386640616177 state=[focused,hovered] 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/C1-initial.png b/experiments/render-loop-cadence/astra/final-captures/C1-initial.png new file mode 100644 index 00000000..a3f294ce Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C1-initial.png differ 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 00000000..85a212ad Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C2-after.png differ 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 00000000..e12739bd Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C2-initial.png differ diff --git a/experiments/render-loop-cadence/astra/final-captures/C2-initial.receipt.json b/experiments/render-loop-cadence/astra/final-captures/C2-initial.receipt.json new file mode 100644 index 00000000..491ff3b9 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C2-initial.receipt.json @@ -0,0 +1,61 @@ +{ + "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/initial.png", + "snapshot": "/Users/dara/Dev/Projects/weaver/experiments/render-loop-cadence/astra/final/C2/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": 327617, + "spawn": 45406, + "startup": 31040, + "render": 1788, + "encode": 538, + "write": 294, + "total": 405112 + }, + "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/C2-initial.snapshot.txt b/experiments/render-loop-cadence/astra/final-captures/C2-initial.snapshot.txt new file mode 100644 index 00000000..0faa7b25 --- /dev/null +++ b/experiments/render-loop-cadence/astra/final-captures/C2-initial.snapshot.txt @@ -0,0 +1,47 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=33347000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=33607 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=136 canvas_frame_encoder_cache_actions=87 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=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=41 canvas_frame_gpu_packet_cache_actions=87 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=482 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,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="0" 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="0 / 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=false enabled=true parent=#4456204386640616177 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/C3-after.png b/experiments/render-loop-cadence/astra/final-captures/C3-after.png new file mode 100644 index 00000000..25ab1e57 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C3-after.png differ 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 00000000..0eac1dea Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C3-initial.png differ 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 00000000..95e07379 Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C4-after.png differ 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 00000000..22fed57c Binary files /dev/null and b/experiments/render-loop-cadence/astra/final-captures/C4-initial.png differ 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/examples/styling-spacing/tsconfig.json b/experiments/render-loop-cadence/astra/runs/A1/tsconfig.json similarity index 56% rename from examples/styling-spacing/tsconfig.json rename to experiments/render-loop-cadence/astra/runs/A1/tsconfig.json index 4248ebc1..ca0e342e 100644 --- a/examples/styling-spacing/tsconfig.json +++ b/experiments/render-loop-cadence/astra/runs/A1/tsconfig.json @@ -11,9 +11,15 @@ "types": [], "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@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"] + "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/examples/styling-text/tsconfig.json b/experiments/render-loop-cadence/astra/runs/A2/tsconfig.json similarity index 56% rename from examples/styling-text/tsconfig.json rename to experiments/render-loop-cadence/astra/runs/A2/tsconfig.json index 4248ebc1..ca0e342e 100644 --- a/examples/styling-text/tsconfig.json +++ b/experiments/render-loop-cadence/astra/runs/A2/tsconfig.json @@ -11,9 +11,15 @@ "types": [], "baseUrl": ".", "paths": { - "@weaver/sdk": ["../../sdk/index.d.ts"], - "@weaver/sdk/jsx-runtime": ["../../sdk/jsx-runtime.d.ts"] + "@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"] + "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 00000000..6090da99 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-display-plain/capture.png differ 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 00000000..39465cd9 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-one/none.png differ 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 00000000..7cb486f6 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-one/tick.png differ 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 00000000..60abb92c Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-one/ticks2.png differ 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 00000000..8cb9c9fa Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-pair/none.png differ 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 00000000..b2a287dd Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-pair/tick.png differ 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 00000000..dd7bfd68 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-pair/ticks2.png differ 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 00000000..e2fb1462 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/cp-shrink/tick.png differ 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 00000000..cae4af85 Binary files /dev/null and b/experiments/render-loop-cadence/canvas-probe/probe1/capture.png differ 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 00000000..ecee70a6 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/A1-after.png differ 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 00000000..5d51ae23 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/A1-initial.png differ diff --git a/experiments/render-loop-cadence/final-captures/A1-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/A1-initial.snapshot.txt new file mode 100644 index 00000000..e42b8912 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/A1-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=57397000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11053 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=48 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=24 canvas_frame_encoder_commands=152 canvas_frame_encoder_cache_actions=101 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=50 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=20 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=101 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=536 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=(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="0" 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="0 / 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=false enabled=true parent=#3105235776718550580 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/A2-after.png b/experiments/render-loop-cadence/final-captures/A2-after.png new file mode 100644 index 00000000..099e0175 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/A2-after.png differ 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 00000000..0829cbab Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/A2-initial.png differ 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 00000000..f0f8eb76 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B1-after.png differ diff --git a/experiments/render-loop-cadence/final-captures/B1-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/B1-after.snapshot.txt new file mode 100644 index 00000000..4082ff9e --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B1-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=101603000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10120 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=1788571594887197000 gpu_input_latency_ns=14854000 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=155 canvas_frame_encoder_cache_actions=106 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=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=26 canvas_frame_text_evicts=0 canvas_frame_gpu_packet_commands=44 canvas_frame_gpu_packet_cache_actions=106 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=537 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 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="3" 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="3 / 20" bounds=(269.9273,101.5 34.0727x17.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=true enabled=true parent=#2479990500450380282 state=[focused,hovered] 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/B1-initial.png b/experiments/render-loop-cadence/final-captures/B1-initial.png new file mode 100644 index 00000000..eee585ee Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B1-initial.png differ 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 00000000..a060c853 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B2-after.png differ 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 00000000..14a470e8 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B2-initial.png differ 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 00000000..2cc3f16c Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B3-after.png differ diff --git a/experiments/render-loop-cadence/final-captures/B3-after.snapshot.txt b/experiments/render-loop-cadence/final-captures/B3-after.snapshot.txt new file mode 100644 index 00000000..3b579b06 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/B3-after.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=102670000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=11545 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=1788571603358678000 gpu_input_latency_ns=15223000 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=49 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=548 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=(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="3" 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="3 / 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=true enabled=true parent=#2479990500450380282 state=[focused,hovered] 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/B3-initial.png b/experiments/render-loop-cadence/final-captures/B3-initial.png new file mode 100644 index 00000000..12bed419 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B3-initial.png differ 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 00000000..f948db64 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B4-after.png differ 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 00000000..ae9e6fe8 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/B4-initial.png differ 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 00000000..c056892b Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C1-after.png differ 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 00000000..7a638040 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C1-initial.png differ diff --git a/experiments/render-loop-cadence/final-captures/C1-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/C1-initial.snapshot.txt new file mode 100644 index 00000000..c7445bb1 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C1-initial.snapshot.txt @@ -0,0 +1,96 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=58231000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=10758 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=84 canvas_frame_requires_render=true canvas_frame_full_repaint=true canvas_frame_batches=23 canvas_frame_encoder_commands=153 canvas_frame_encoder_cache_actions=104 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=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=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=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=82 canvas_frame_gpu_packet_cache_actions=104 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=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=583 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=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="0" 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="0 / 20" bounds=(267.9273,101 34.072697x12) 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=false enabled=true parent=#9833334659390856017 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/C2-after.png b/experiments/render-loop-cadence/final-captures/C2-after.png new file mode 100644 index 00000000..6feae67f Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C2-after.png differ 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 00000000..9cacaede Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C2-initial.png differ 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 00000000..de955726 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C3-after.png differ 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 00000000..62ead71f Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C3-initial.png differ diff --git a/experiments/render-loop-cadence/final-captures/C3-initial.snapshot.txt b/experiments/render-loop-cadence/final-captures/C3-initial.snapshot.txt new file mode 100644 index 00000000..a8acde40 --- /dev/null +++ b/experiments/render-loop-cadence/final-captures/C3-initial.snapshot.txt @@ -0,0 +1,49 @@ +ready=true protocol=6 frame=0 commands=0 runtime_uptime_ns=66509000 dispatch_errors=0 dropped_trace_records=0 publisher_pid=8329 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=(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="0" 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="0 / 20" bounds=(265.9273,106.25 34.072697x17.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=false enabled=true parent=#2479990500450380282 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/C4-after.png b/experiments/render-loop-cadence/final-captures/C4-after.png new file mode 100644 index 00000000..e18bd6c0 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C4-after.png differ 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 00000000..77e6d717 Binary files /dev/null and b/experiments/render-loop-cadence/final-captures/C4-initial.png differ 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 00000000..5ecbee16 Binary files /dev/null and b/experiments/render-loop-cadence/panel-probe/panel-probe.png differ 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); 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 c377d3b6..71ef3ad2 100644 --- a/sdk/CONTRACT.md +++ b/sdk/CONTRACT.md @@ -305,7 +305,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 e78fc167..c72db66f 100644 --- a/test/capture-smoke.mjs +++ b/test/capture-smoke.mjs @@ -13,14 +13,14 @@ 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); // A layout-sized canvas paints at its laid-out width on the first frame and @@ -44,7 +44,7 @@ try { assert.match(snapshotText(classHoleClicked), /role=group name="" bounds=\(\d+(?:\.\d+)?,\d+(?:\.\d+)? 42x8\)/, "hole fill is 42px after three clicks"); assert.ok(countPixels(classHoleClicked, [0x5e, 0xea, 0xd4]) > countPixels(classHole, [0x5e, 0xea, 0xd4]), "hole fill painted more accent after clicks"); - 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); @@ -56,16 +56,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)); @@ -74,6 +74,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"), ]); @@ -180,6 +198,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