refactor(deploy): benchmark, canary, land-and-deploy Step 7, devex-review drive Aside

One aside repl script per page prints NAV/PAINT/LCP/RESOURCES/SCRIPTS/CSS/SUMMARY (benchmark), CONSOLE_ERRORS/NAV/TEXT + screenshot (canary, re-run every 60s), and the post-deploy check reads responseStatus from the navigation entry; each carries the $B fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Sina
2026-09-05 16:48:37 -04:00
co-authored by Claude Fable 5.1
parent 27e38cbeec
commit 0953aedbb1
5 changed files with 132 additions and 100 deletions
+23 -29
View File
@@ -3,7 +3,7 @@ name: benchmark
preamble-tier: 1
version: 1.0.0
description: |
Performance regression detection using the browse daemon. Establishes
Performance regression detection. Establishes
baselines for page load times, Core Web Vitals, and resource sizes.
Compares before/after on every PR. Tracks performance trends over time.
Use when: "performance", "benchmark", "page speed", "lighthouse", "web vitals",
@@ -25,13 +25,15 @@ allowed-tools:
{{PREAMBLE}}
{{BROWSE_SETUP}}
{{ASIDE_SETUP}}
{{BROWSE_FALLBACK}}
# /benchmark — Performance Regression Detection
You are a **Performance Engineer** who has optimized apps serving millions of requests. You know that performance doesn't degrade in one big regression — it dies by a thousand paper cuts. Each PR adds 50ms here, 20KB there, and one day the app takes 8 seconds to load and nobody knows when it got slow.
Your job is to measure, baseline, compare, and alert. You use the browse daemon's `perf` command and JavaScript evaluation to gather real performance data from running pages.
Your job is to measure, baseline, compare, and alert. You drive the Aside browser and read `performance.getEntries()` straight from the live page — real numbers from a real browser, not estimates.
## User-invocable
When the user types `/benchmark`, run this skill.
@@ -65,42 +67,34 @@ git diff $(gh pr view --json baseRefName -q .baseRefName 2>/dev/null || gh repo
### Phase 3: Performance Data Collection
For each page, collect comprehensive performance metrics:
For each page, ONE `aside repl` script opens the page and prints every metric as a labelled line. Tabs die when the script ends, so nothing carries over between pages — each page gets its own run:
```bash
$B goto <page-url>
$B perf
aside repl '
const pg = await openTab("<page-url>");
await pg.waitForLoadState("load");
console.log("NAV=" + await pg.evaluate(() => JSON.stringify(performance.getEntriesByType("navigation")[0]))); // stringify IN the page: PerformanceEntry fields are getters and serialize to {} across the bridge
console.log("PAINT=" + await pg.evaluate(() => JSON.stringify(performance.getEntriesByType("paint").map(p => ({ name: p.name, start: Math.round(p.startTime) })))));
console.log("LCP=" + await pg.evaluate(() => new Promise(res => { const po = new PerformanceObserver(l => { const e = l.getEntries().pop(); if (e) res(Math.round(e.startTime)); }); po.observe({ type: "largest-contentful-paint", buffered: true }); setTimeout(() => res(null), 3000); })));
console.log("RESOURCES=" + JSON.stringify(await pg.evaluate(() => performance.getEntriesByType("resource").map(r => ({ name: r.name.split("/").pop().split("?")[0], type: r.initiatorType, size: r.transferSize, duration: Math.round(r.duration) })).sort((a, b) => b.duration - a.duration).slice(0, 15))));
console.log("SCRIPTS=" + JSON.stringify(await pg.evaluate(() => performance.getEntriesByType("resource").filter(r => r.initiatorType === "script").map(r => ({ name: r.name.split("/").pop().split("?")[0], size: r.transferSize })))));
console.log("CSS=" + JSON.stringify(await pg.evaluate(() => performance.getEntriesByType("resource").filter(r => r.initiatorType === "css").map(r => ({ name: r.name.split("/").pop().split("?")[0], size: r.transferSize })))));
console.log("SUMMARY=" + JSON.stringify(await pg.evaluate(() => { const r = performance.getEntriesByType("resource"); return { total_requests: r.length, total_transfer: r.reduce((s, e) => s + (e.transferSize || 0), 0), by_type: Object.entries(r.reduce((a, e) => { a[e.initiatorType] = (a[e.initiatorType] || 0) + 1; return a; }, {})).sort((a, b) => b[1] - a[1]) }; })));
await closeTab(pg); console.log("GSTACK_STEP_OK");
'
```
Then gather detailed metrics via JavaScript:
`NAV=` is the navigation timing entry, `PAINT=` the paint entries (FCP lives here), `LCP=` the largest-contentful-paint start time (`null` if the page emitted no LCP entry within 3s), `RESOURCES=` the 15 slowest resources, `SCRIPTS=` / `CSS=` the bundle inventory, `SUMMARY=` request count, total transfer, and requests by type. A missing `GSTACK_STEP_OK` or a line starting with `[error` means the page did not load — record it as a failure, not a slow page.
```bash
$B eval "JSON.stringify(performance.getEntriesByType('navigation')[0])"
```
Extract key metrics:
Extract key metrics from `NAV=`:
- **TTFB** (Time to First Byte): `responseStart - requestStart`
- **FCP** (First Contentful Paint): from PerformanceObserver or `paint` entries
- **LCP** (Largest Contentful Paint): from PerformanceObserver
- **FCP** (First Contentful Paint): the `first-contentful-paint` entry in `PAINT=`
- **LCP** (Largest Contentful Paint): the `LCP=` line (`null` if the page emitted no LCP entry — record it as missing, not 0)
- **DOM Interactive**: `domInteractive - navigationStart`
- **DOM Complete**: `domComplete - navigationStart`
- **Full Load**: `loadEventEnd - navigationStart`
Resource analysis:
```bash
$B eval "JSON.stringify(performance.getEntriesByType('resource').map(r => ({name: r.name.split('/').pop().split('?')[0], type: r.initiatorType, size: r.transferSize, duration: Math.round(r.duration)})).sort((a,b) => b.duration - a.duration).slice(0,15))"
```
Bundle size check:
```bash
$B eval "JSON.stringify(performance.getEntriesByType('resource').filter(r => r.initiatorType === 'script').map(r => ({name: r.name.split('/').pop().split('?')[0], size: r.transferSize})))"
$B eval "JSON.stringify(performance.getEntriesByType('resource').filter(r => r.initiatorType === 'css').map(r => ({name: r.name.split('/').pop().split('?')[0], size: r.transferSize})))"
```
Network summary:
```bash
$B eval "(() => { const r = performance.getEntriesByType('resource'); return JSON.stringify({total_requests: r.length, total_transfer: r.reduce((s,e) => s + (e.transferSize||0), 0), by_type: Object.entries(r.reduce((a,e) => { a[e.initiatorType] = (a[e.initiatorType]||0) + 1; return a; }, {})).sort((a,b) => b[1]-a[1])})})()"
```
Load times jitter with the network. If the user wants stable numbers, run the script 3 times per page and take the median of each metric.
### Phase 4: Baseline Capture (--baseline mode)
+47 -26
View File
@@ -4,7 +4,7 @@ preamble-tier: 2
version: 1.0.0
description: |
Post-deploy canary monitoring. Watches the live app for console errors,
performance regressions, and page failures using the browse daemon. Takes
performance regressions, and page failures. Takes
periodic screenshots, compares against pre-deploy baselines, and alerts
on anomalies. Use when: "monitor deploy", "canary", "post-deploy check",
"watch production", "verify deploy". (gstack)
@@ -22,7 +22,9 @@ triggers:
{{PREAMBLE}}
{{BROWSE_SETUP}}
{{ASIDE_SETUP}}
{{BROWSE_FALLBACK}}
{{BASE_BRANCH_DETECT}}
@@ -30,7 +32,7 @@ triggers:
You are a **Release Reliability Engineer** watching production after a deploy. You've seen deploys that pass CI but break in production — a missing environment variable, a CDN cache serving stale assets, a database migration that's slower than expected on real data. Your job is to catch these in the first 10 minutes, not 10 hours.
You use the browse daemon to watch the live app, take screenshots, check console errors, and compare against baselines. You are the safety net between "shipped" and "verified."
You drive the Aside browser to watch the live app, take screenshots, check console errors, and compare against baselines. You are the safety net between "shipped" and "verified."
## User-invocable
When the user types `/canary`, run this skill.
@@ -62,14 +64,24 @@ If the user passed `--baseline`, capture the current state BEFORE deploying.
For each page (either from `--pages` or the homepage):
```bash
$B goto <page-url>
$B snapshot -i -a -o ".gstack/canary-reports/baselines/<page-name>.png"
$B console --errors
$B perf
$B text
aside repl '
const HOOK = `(() => { window.__gstackErrs = window.__gstackErrs || []; const oe = console.error; console.error = (...a) => { window.__gstackErrs.push(a.map(String).join(" ")); oe.apply(console, a); }; window.addEventListener("error", e => window.__gstackErrs.push("uncaught: " + e.message)); window.addEventListener("unhandledrejection", e => window.__gstackErrs.push("unhandledrejection: " + (e.reason && e.reason.message || e.reason))); })()`;
const pg = await openTab("about:blank");
await pg._sendToTarget("Page.addScriptToEvaluateOnNewDocument", { source: HOOK });
await pg.goto("<page-url>");
console.log("CONSOLE_ERRORS=" + JSON.stringify(await pg.evaluate(() => window.__gstackErrs)));
console.log("NAV=" + await pg.evaluate(() => JSON.stringify(performance.getEntriesByType("navigation")[0])));
console.log("TEXT_START"); console.log((await pg.evaluate(() => document.body.innerText)).slice(0, 20000)); console.log("TEXT_END");
await pg.screenshot({ path: "<page-name>.jpg", type: "jpeg", quality: 60, fullPage: true });
console.log("ASIDE_DIR=" + pwd);
await closeTab(pg);
console.log("GSTACK_STEP_OK");
'
```
Collect for each page: screenshot path, console error count, page load time from `perf`, and a text content snapshot.
Then copy the screenshot out of the printed session directory: `cp "<ASIDE_DIR>/<page-name>.jpg" .gstack/canary-reports/baselines/<page-name>.jpg`
Collect for each page: screenshot path, console error count (`CONSOLE_ERRORS=`), load time (`loadEventEnd` in `NAV=`), and the text snapshot between `TEXT_START` / `TEXT_END`.
Save the baseline manifest to `.gstack/canary-reports/baseline.json`:
@@ -80,7 +92,7 @@ Save the baseline manifest to `.gstack/canary-reports/baseline.json`:
"branch": "<current branch>",
"pages": {
"/": {
"screenshot": "baselines/home.png",
"screenshot": "baselines/home.jpg",
"console_errors": 0,
"load_time_ms": 450
}
@@ -95,12 +107,15 @@ Then STOP and tell the user: "Baseline captured. Deploy your changes, then run `
If no `--pages` were specified, auto-discover pages to monitor:
```bash
$B goto <url>
$B links
$B snapshot -i
aside repl '
const pg = await openTab("<url>");
const links = await pg.evaluate(() => [...new Set([...document.querySelectorAll("a[href]")].map(a => a.href))].filter(h => h.startsWith(location.origin) && !/logout|signout|delete|remove|cancel|unsubscribe/i.test(h)));
for (const l of links) { const r = await fetch(l, { method: "HEAD" }).catch(e => ({ status: "ERR " + e.message })); console.log("LINK", r.status, l); }
await closeTab(pg); console.log("GSTACK_STEP_OK");
'
```
Extract the top 5 internal navigation links from the `links` output. Always include the homepage. Present the page list via AskUserQuestion:
Extract the top 5 internal navigation links from the `LINK` lines (same-origin only — the script already filters). Always include the homepage. Present the page list via AskUserQuestion:
- **Context:** Monitoring the production site at the given URL after a deploy.
- **Question:** Which pages should the canary monitor?
@@ -115,29 +130,35 @@ If no `baseline.json` exists, take a quick snapshot now as a reference point.
For each page to monitor:
```bash
$B goto <page-url>
$B snapshot -i -a -o ".gstack/canary-reports/screenshots/pre-<page-name>.png"
$B console --errors
$B perf
```
Run the Phase 2 read script for each page with the screenshot saved as `pre-<page-name>.jpg`, then `cp "<ASIDE_DIR>/pre-<page-name>.jpg" .gstack/canary-reports/screenshots/`.
Record the console error count and load time for each page. These become the reference for detecting regressions during monitoring.
### Phase 5: Continuous Monitoring Loop
Monitor for the specified duration. Every 60 seconds, check each page:
Monitor for the specified duration. Every 60 seconds, check each page. Nothing persists between scripts — every check re-opens the page from its URL and captures fresh evidence:
```bash
$B goto <page-url>
$B snapshot -i -a -o ".gstack/canary-reports/screenshots/<page-name>-<check-number>.png"
$B console --errors
$B perf
aside repl '
const HOOK = `(() => { window.__gstackErrs = window.__gstackErrs || []; const oe = console.error; console.error = (...a) => { window.__gstackErrs.push(a.map(String).join(" ")); oe.apply(console, a); }; window.addEventListener("error", e => window.__gstackErrs.push("uncaught: " + e.message)); window.addEventListener("unhandledrejection", e => window.__gstackErrs.push("unhandledrejection: " + (e.reason && e.reason.message || e.reason))); })()`;
const pg = await openTab("about:blank");
await pg._sendToTarget("Page.addScriptToEvaluateOnNewDocument", { source: HOOK });
await pg.goto("<page-url>");
console.log("CONSOLE_ERRORS=" + JSON.stringify(await pg.evaluate(() => window.__gstackErrs)));
console.log("NAV=" + await pg.evaluate(() => JSON.stringify(performance.getEntriesByType("navigation")[0])));
console.log("TEXT_START"); console.log((await pg.evaluate(() => document.body.innerText)).slice(0, 20000)); console.log("TEXT_END");
await pg.screenshot({ path: "<page-name>-<check-number>.jpg", type: "jpeg", quality: 60, fullPage: true });
console.log("ASIDE_DIR=" + pwd);
await closeTab(pg);
console.log("GSTACK_STEP_OK");
'
```
Then `cp "<ASIDE_DIR>/<page-name>-<check-number>.jpg" .gstack/canary-reports/screenshots/`.
After each check, compare results against the baseline (or pre-deploy snapshot):
1. **Page load failure** — `goto` returns error or timeout → CRITICAL ALERT
1. **Page load failure** — the script prints a line starting with `[error` or never prints `GSTACK_STEP_OK` → CRITICAL ALERT
2. **New console errors** — errors not present in baseline → HIGH ALERT
3. **Performance regression** — load time exceeds 2x baseline → MEDIUM ALERT
4. **Broken links** — new 404s not in baseline → LOW ALERT
+28 -16
View File
@@ -3,8 +3,8 @@ name: devex-review
preamble-tier: 3
version: 1.0.0
description: |
Live developer experience audit. Uses the browse tool to actually TEST the
developer experience: navigates docs, tries the getting started flow, times
Live developer experience audit. Actually TESTS the developer experience
in the Aside browser: navigates docs, tries the getting started flow, times
TTHW, screenshots error messages, evaluates CLI help text. Produces a DX
scorecard with evidence. Compares against /plan-devex-review scores if they
exist (the boomerang: plan said 3 minutes, reality says 8). Use when asked to
@@ -33,26 +33,31 @@ allowed-tools:
{{BASE_BRANCH_DETECT}}
{{BROWSE_SETUP}}
{{ASIDE_SETUP}}
{{BROWSE_FALLBACK}}
{{ASIDE_COOKBOOK}}
# /devex-review: Live Developer Experience Audit
You are a DX engineer dogfooding a live developer product. Not reviewing a plan.
Not reading about the experience. TESTING it.
Use the browse tool to navigate docs, try the getting started flow, and screenshot
what developers actually see. Use bash to try CLI commands. Measure, don't guess.
Drive the Aside browser to navigate docs, try the getting started flow, and screenshot
what developers actually see. One `aside repl` script per flow, each re-opening from the URL. Use bash to try CLI commands. Measure, don't guess.
{{DX_FRAMEWORK}}
## Scope Declaration
Browse can test web-accessible surfaces: docs pages, API playgrounds, web dashboards,
signup flows, interactive tutorials, error pages.
Aside can test web-accessible surfaces: docs pages, API playgrounds, web dashboards,
signup flows, interactive tutorials, error pages — with the user's real logged-in
sessions.
Browse CANNOT test: CLI install friction, terminal output quality, local environment
setup, email verification flows, auth requiring real credentials, offline behavior,
build times, IDE integration.
Aside CANNOT test: CLI install friction, terminal output quality, local environment
setup, email verification flows, credential entry (the user signs in themselves; you
never type passwords), offline behavior, build times, IDE integration.
For untestable dimensions, use bash (for CLI --help, README, CHANGELOG) or mark as
INFERRED from artifacts. Never guess. State your evidence source for every score.
@@ -78,7 +83,8 @@ If prior scores exist, display them. These are your baseline for the boomerang c
## Step 1: Getting Started Audit
Navigate to the docs/landing page via browse. Screenshot it.
Open the docs/landing page with the Aside read script from the cookbook (console errors,
snapshot, screenshot, text). Copy the screenshot out of the printed ASIDE_DIR and Read it.
```
GETTING STARTED AUDIT
@@ -95,7 +101,7 @@ Score 0-10. Load "## Pass 1" from dx-hall-of-fame.md for calibration.
Test what you can:
- CLI: Run `--help` via bash. Evaluate output quality, flag design, discoverability.
- API playground: Navigate via browse if one exists. Screenshot.
- API playground: Open it in Aside if one exists. Screenshot.
- Naming: Check consistency across the API surface.
Score 0-10. Load "## Pass 2" from dx-hall-of-fame.md for calibration.
@@ -103,7 +109,8 @@ Score 0-10. Load "## Pass 2" from dx-hall-of-fame.md for calibration.
## Step 3: Error Message Audit
Trigger common error scenarios:
- Browse: Navigate to 404 pages, submit invalid forms, try unauthenticated access
- Aside: Open a 404 URL, submit an invalid form (on a non-LOCAL target that is a mutating
action — one AskUserQuestion per run first, per the browser rules), open a protected URL
- CLI: Run with missing args, invalid flags, bad input
Screenshot each error. Score against the Elm/Rust/Stripe three-tier model.
@@ -112,7 +119,9 @@ Score 0-10. Load "## Pass 3" from dx-hall-of-fame.md for calibration.
## Step 4: Documentation Audit
Navigate the docs structure via browse:
Navigate the docs structure in Aside (search is `pg.fill(<search selector>, <query>)`,
then `pg.locator(<search selector>).press("Enter")` — or `pg.getByRole("searchbox").press("Enter")`,
or a click — then `snapshot`):
- Check search functionality (try 3 common queries)
- Verify code examples are copy-paste-complete
- Check language switcher behavior
@@ -141,12 +150,15 @@ Score 0-10. Evidence: INFERRED from files. Load "## Pass 6" from dx-hall-of-fame
## Step 7: Community & Ecosystem Audit
Browse:
Check the community links the docs point to. Aside stays on the docs origin (browser
rule 2): confirm the links are PRESENT in the Step 1 snapshot or with the same-origin links
script from the cookbook, and audit GitHub via `gh` in bash. Do not open Discord, Stack
Overflow, or any other third-party site — mark those INFERRED (link present, not followed):
- Community links (GitHub Discussions, Discord, Stack Overflow)
- GitHub issues (response time, templates, labels)
- Contributing guide
Score 0-10. Evidence: TESTED where web-accessible, INFERRED otherwise.
Score 0-10. Evidence: TESTED for the docs page and GitHub, INFERRED otherwise.
## Step 8: DX Measurement Audit
+30 -25
View File
@@ -24,7 +24,9 @@ triggers:
{{THIRD_PARTY_ACTIONS}}
{{BROWSE_SETUP}}
{{ASIDE_SETUP}}
{{BROWSE_FALLBACK}}
{{BASE_BRANCH_DETECT}}
@@ -308,45 +310,48 @@ Use the diff-scope classification from Step 5 to determine canary depth:
| Diff Scope | Canary Depth |
|------------|-------------|
| SCOPE_DOCS only | Already skipped in Step 5 |
| SCOPE_CONFIG only | Smoke: `$B goto` + verify 200 status |
| SCOPE_CONFIG only | Smoke: the Aside script below; `responseStatus` in `NAV=` must be 200 |
| SCOPE_BACKEND only | Console errors + perf check |
| SCOPE_FRONTEND (any) | Full: console + perf + screenshot |
| Mixed scopes | Full canary |
**Full canary sequence:**
**Full canary sequence** — one `aside repl` script does the whole check (console hook first, then load, then evidence):
```bash
$B goto <url>
aside repl '
const HOOK = `(() => { window.__gstackErrs = window.__gstackErrs || []; const oe = console.error; console.error = (...a) => { window.__gstackErrs.push(a.map(String).join(" ")); oe.apply(console, a); }; window.addEventListener("error", e => window.__gstackErrs.push("uncaught: " + e.message)); window.addEventListener("unhandledrejection", e => window.__gstackErrs.push("unhandledrejection: " + (e.reason && e.reason.message || e.reason))); })()`;
const pg = await openTab("about:blank");
await pg._sendToTarget("Page.addScriptToEvaluateOnNewDocument", { source: HOOK });
await pg.goto("<url>");
console.log("URL=" + pg.url());
console.log("CONSOLE_ERRORS=" + JSON.stringify(await pg.evaluate(() => window.__gstackErrs)));
console.log("NAV=" + await pg.evaluate(() => JSON.stringify(performance.getEntriesByType("navigation")[0])));
console.log("TEXT_START"); console.log((await pg.evaluate(() => document.body.innerText)).slice(0, 20000)); console.log("TEXT_END");
await pg.screenshot({ path: "post-deploy.jpg", type: "jpeg", quality: 60, fullPage: true });
const a = await annotatedScreenshot(pg);
await fs.writeFile(path.join(pwd, "post-deploy-annotated.png"), Buffer.from(a.base64Image, "base64"));
console.log("ASIDE_DIR=" + pwd);
await closeTab(pg);
console.log("GSTACK_STEP_OK");
'
```
Check that the page loaded successfully (200, not an error page).
Then copy the evidence out of the printed session directory:
```bash
$B console --errors
mkdir -p .gstack/deploy-reports && cp "<ASIDE_DIR>/post-deploy.jpg" "<ASIDE_DIR>/post-deploy-annotated.png" .gstack/deploy-reports/
```
Check for critical console errors: lines containing `Error`, `Uncaught`, `Failed to load`, `TypeError`, `ReferenceError`. Ignore warnings.
Read the output line by line:
```bash
$B perf
```
Check that page load time is under 10 seconds.
```bash
$B text
```
Verify the page has content (not blank, not a generic error page).
```bash
$B snapshot -i -a -o ".gstack/deploy-reports/post-deploy.png"
```
Take an annotated screenshot as evidence.
- `URL=` — the page loaded and stayed on the site (not a redirect to an error page). A line starting with `[error` or a missing `GSTACK_STEP_OK` means the load failed.
- `CONSOLE_ERRORS=` — check for critical errors: entries containing `Error`, `Uncaught`, `Failed to load`, `TypeError`, `ReferenceError`. Ignore warnings.
- `NAV=` — `responseStatus` is the HTTP status of the document (Chromium PerformanceNavigationTiming) — must be 200. `loadEventEnd` is the page load time. Check that it is under 10 seconds.
- `TEXT_START` / `TEXT_END` — verify the page has real content (not blank, not a generic error page).
- `post-deploy.jpg` and the annotated `post-deploy-annotated.png` are the evidence. Read the copied screenshot so the user sees it.
**Health assessment:**
- Page loads successfully with 200 status → PASS
- Page loads successfully with 200 status (`responseStatus` in `NAV=`) → PASS
- No critical console errors → PASS
- Page has real content (not blank or error screen) → PASS
- Loads in under 10 seconds → PASS
+4 -4
View File
@@ -279,7 +279,7 @@ describeIfSelected('Canary skill E2E', ['canary-workflow'], () => {
const result = await runSkillTest({
prompt: `Read canary/SKILL.md for the /canary skill instructions.
You are simulating a canary check. There is NO browse daemon available and NO production URL.
You are simulating a canary check. No browser is available on this machine (no Aside, no browse daemon) and there is NO production URL.
Instead, demonstrate you understand the workflow:
1. Create the .gstack/canary-reports/ directory structure
@@ -290,7 +290,7 @@ Instead, demonstrate you understand the workflow:
the Phase 6 Health Report format (CANARY REPORT header, duration, pages, status,
per-page results table, verdict)
Do NOT use AskUserQuestion. Do NOT run browse ($B) commands.
Do NOT use AskUserQuestion. Do NOT run aside or browse ($B) commands.
Just create the directory structure and report files showing the correct schema.`,
workingDirectory: canaryDir,
maxTurns: 15,
@@ -340,7 +340,7 @@ describeIfSelected('Benchmark skill E2E', ['benchmark-workflow'], () => {
const result = await runSkillTest({
prompt: `Read benchmark/SKILL.md for the /benchmark skill instructions.
You are simulating a benchmark run. There is NO browse daemon available and NO production URL.
You are simulating a benchmark run. No browser is available on this machine (no Aside, no browse daemon) and there is NO production URL.
Instead, demonstrate you understand the workflow:
1. Create the .gstack/benchmark-reports/ directory structure including baselines/
@@ -353,7 +353,7 @@ Instead, demonstrate you understand the workflow:
table with Baseline/Current/Delta/Status columns, regression thresholds applied)
4. Include the Phase 7 Performance Budget section in the report
Do NOT use AskUserQuestion. Do NOT run browse ($B) commands.
Do NOT use AskUserQuestion. Do NOT run aside or browse ($B) commands.
Just create the files showing the correct schema and report format.`,
workingDirectory: benchDir,
maxTurns: 15,