fix(performance): document the missing guard step

This commit is contained in:
CaoBochun committed 2026-08-28 12:15:32 +08:00
1 parent f63ec56a3c
commit 6a268d7710
4 files changed
+67 -5

No files matched your search

+3 -2
View File
@@ -38,14 +38,15 @@
{
"id": 1,
"prompt": "The products page renders slowly with 1000 items. Improve its performance.",
"expected_output": "A measured baseline, an identified bottleneck, a targeted fix, and a verified improvement",
"expected_output": "A measured baseline, an identified bottleneck, a targeted fix, a verified improvement, and a regression guard",
"files": [
"performance-optimization"
],
"expectations": [
"Performance is measured before any optimization is applied",
"The fix targets the measured bottleneck rather than guessing",
"Improvement is verified against the baseline after the change"
"Improvement is verified against the baseline after the change",
"A concrete guard is added after verification using a synthetic performance budget or field monitoring tied to the measured user-facing metric"
]
}
]
+25
View File
@@ -109,6 +109,31 @@ test('reports frontmatter name that disagrees with the directory', () => {
assert.match(errors[0], /does not match directory name/);
});
test('reports a workflow step declared without a matching process section', () => {
const content = withAllSections(VALID_FRONTMATTER).replace(
'## Common Rationalizations',
[
'## The Optimization Workflow',
'',
'```',
'1. MEASURE → Establish a baseline',
'2. GUARD → Prevent regression',
'```',
'',
'### Step 1: Measure',
'',
'Measure first.',
'',
'## Common Rationalizations',
].join('\n'),
);
const { errors } = lintSkillContent('alpha', content, KNOWN);
assert.equal(errors.length, 1);
assert.match(errors[0], /Workflow declares Step 2 but has no matching process section/);
});
test('reports a missing frontmatter block', () => {
const { errors } = lintSkillContent('alpha', '## Overview\nx\n', KNOWN);
assert.equal(errors.length, 1);
+21
View File
@@ -209,6 +209,27 @@ function lintSkillContent(dirName, content, knownSkills) {
}
}
// A named workflow that advertises numbered steps must document each step
// before the next level-two section. Otherwise the summary promises a
// process stage that the skill never teaches agents how to perform.
const workflowSections = content.matchAll(
/^## The [^\n]+ Workflow\s*\r?\n([\s\S]*?)(?=^## |(?![\s\S]))/gm
);
for (const match of workflowSections) {
const section = match[1];
const declared = [...section.matchAll(/^\s*(\d+)\.\s+[A-Z][A-Z -]*\s+→/gm)];
if (declared.length < 2) continue;
const documented = new Set(
[...section.matchAll(/^### Step\s+(\d+):/gm)].map(step => step[1])
);
for (const step of declared) {
if (!documented.has(step[1])) {
errors.push(`Workflow declares Step ${step[1]} but has no matching process section`);
}
}
}
// ── Cross-skill references ───────────────────────────────────────────────
const refs = extractSkillReferences(content);
for (const ref of refs) {
+18 -3
View File
@@ -400,9 +400,24 @@ Reverted work leaves no trace in git history, which is exactly why the same dead
A section in the PR description or a `PERF.md` in the repo both work. What matters is that the next person (or the next agent) reads it before proposing an experiment, and doesn't re-run one that already failed.
## Performance Budget
### Step 5: Guard Against Regression
Set budgets and enforce them:
Guard the metric the user actually feels, not every available number. Use the
same LCP, INP, p95 latency, or other primary metric that justified the fix.
Use two complementary layers when the surface is user-facing:
- **Synthetic CI gate:** Catch reproducible regressions before merge with a
performance budget. Repeat noisy measurements or compare a median/trend so
normal run-to-run variance does not turn the gate into a flaky check.
- **Field monitoring:** Alert on a meaningful p75 movement in RUM data. Use
attributed `web-vitals` data to locate the cause; treat CrUX's rolling window
as confirmation rather than an immediate alert.
When either guard fires, return to Step 1 and establish a fresh baseline before
proposing another fix.
**Set budgets and enforce them:**
```
JavaScript bundle: < 200KB gzipped (initial load)
@@ -477,5 +492,5 @@ After any performance-related change:
- [ ] No N+1 queries in new data fetching code
- [ ] Any new index is justified by a query plan before and after, and its write cost was considered
- [ ] Any new cache states what it keys on and how it goes stale
- [ ] Performance budget passes in CI (if configured)
- [ ] The measured user-facing metric has a synthetic budget or field monitor that can detect regression
- [ ] Existing tests still pass (optimization didn't break behavior)