Living catalogue of 7 known hazard entries (SE-01 through SE-07) specific to agent-studio: Windows backslash paths, prototype pollution, hook exit codes, async swallowing, ReDoS in glob-to-regex, DST arithmetic, array mutation during iteration. Each entry: symptom, root cause, fix, test assertion.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Living catalogue of 7 known hazard entries (SE-01 through SE-07) specific to agent-studio: Windows backslash paths, prototype pollution, hook exit codes, async swallowing, ReDoS in glob-to-regex, DST arithmetic, array mutation during iteration. Each entry: symptom, root cause, fix, test assertion.
["Invoke at the START of any debugging session","Match your symptom against SE-01 through SE-07 before exploring new theories","If your bug is new and reproducible, add it to this catalogue"]
error_handling
graceful
source
builtin
trust_score
100
provenance_sha
6f5d33597c87879f
Sharp Edges
Living catalogue of confirmed hazard patterns in agent-studio. Each entry documents a real bug we've shipped. Invoke this skill during debugging and code review to check against known failure modes.
SE-01: Windows Backslash Paths
Symptom: Glob patterns match correctly in CI (Linux) but silently fail on developer machines (Windows).
Root cause:path.relative() returns backslash-separated paths on Windows (node_modules\foo), but glob patterns use forward slashes. [^/]* in regex won't block \.
Files affected:.claude/lib/utils/path-constants.cjs, any glob-based exclusion logic.
SE-02: Prototype Pollution via JSON.parse
Symptom:Object.prototype gains unexpected properties after parsing malformed JSON from hook input or agent memory.
Root cause:JSON.parse('{"__proto__":{"isAdmin":true}}') silently mutates Object.prototype in older Node.js versions or when objects are created via Object.create(null) checks are missed.
const before = Object.getPrototypeOf({});
safeParseJSON('{"__proto__":{"evil":true}}', {});
assert(!{}.evil);
Files affected: Any hook that calls JSON.parse() on stdin input.
SE-03: Hook Exit Code Protocol
Symptom: Hook appears to "block" when it should allow, or silently "allows" when it should block.
Root cause: Hooks use exit codes 0 (allow) and 2 (block). Using process.exit(1) or process.exit(true) does not block — it produces unexpected behavior.
Fix:
// CORRECTif (shouldBlock) process.exit(2); // Block tool execution
process.exit(0); // Allow tool execution// WRONGif (shouldBlock) process.exit(1); // Not a valid block code
process.exit(false); // Not valid
Test assertion:
// Mock hook execution and verify exit codeconst result = execHook(input);
assert(result.exitCode === 0 || result.exitCode === 2);
Files affected: All hooks in .claude/hooks/.
SE-04: Async Exception Swallowing in Promise.all
Symptom: One failing async operation silently causes all results to be lost; agent believes all tasks succeeded.
Root cause:Promise.all([...]) rejects on the first failure and discards all other results. When wrapped in try/catch that returns [], the caller sees empty results with no error.
Symptom: Glob pattern matching hangs or takes exponential time on long path strings.
Root cause: Naive glob-to-regex conversion produces patterns with nested quantifiers like (.*)* or (.+)+ which backtrack exponentially on non-matching strings.
Fix:
// Use anchored, non-backtracking patterns// BAD: (.*)* -> exponential backtracking// GOOD: [^/]* -> linear, no backtrackingfunctionglobToRegex(glob) {
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, '\\$&');
return escaped
.replace(/\*\*/g, '___DOUBLE___')
.replace(/\*/g, '[^/]*') // Single * -> no path separators
.replace(/___DOUBLE___/g, '.*'); // ** -> any path
}
Symptom: Date calculations are off by 1 hour for events that cross daylight saving time boundaries.
Root cause: Adding 24 60 60 * 1000ms to a timestamp does not always equal "tomorrow" — DST transitions can make a day 23 or 25 hours long.
Fix:
// WRONG: assumes 24h = 1 dayconst tomorrow = newDate(date.getTime() + 86400000);
// CORRECT: use date arithmetic, not ms arithmeticconst tomorrow = newDate(date);
tomorrow.setDate(tomorrow.getDate() + 1);
Test assertion:
// Test across a known DST boundary (e.g., March DST change)const dst = newDate('2026-03-08T01:00:00'); // Day before US spring forwardconst nextDay = addDays(dst, 1);
assert(nextDay.getDate() === 9);
assert(nextDay.getHours() === 1); // Same time, next day
SE-07: Array Mutation During forEach Iteration
Symptom: Items are skipped or processed twice; behavior is non-deterministic.
Root cause: Mutating an array (push, splice, shift) while iterating with forEach or for...of causes the iterator to skip or re-visit elements.
Fix:
// WRONG: mutates during iteration
arr.forEach(item => {
if (condition) arr.push(newItem); // Skips items
});
// CORRECT: collect mutations, apply afterconst toAdd = [];
arr.forEach(item => {
if (condition) toAdd.push(newItem);
});
arr.push(...toAdd);
// OR: work on a copy
[...arr].forEach(item => { ... });
Test assertion:
const arr = [1, 2, 3];
const result = safeForEach(arr, item => item * 2);
assert(result.length === 3); // Original not mutated, all items processed
Usage
Invoke at the START of any debugging session:
Skill({ skill: 'sharp-edges' });
Then match your symptom against SE-01 through SE-07. If your bug is new and reproducible, add it to this catalogue.
Adding New Entries
Pattern for new entries:
## SE-0N: [Short Title]
**Symptom:** [What you observe]
**Root cause:** [Why it happens]
**Fix:** [Code fix with before/after]
**Test assertion:** [Minimal test that would catch it]
**Files affected:** [Where in agent-studio this applies]
Memory Protocol
After invoking: if you find a new sharp edge, append it here via technical-writer agent.
Memory Protocol (MANDATORY)
Before starting:
Read .claude/context/memory/learnings.md
After completing:
New pattern -> .claude/context/memory/learnings.md
Issue found -> .claude/context/memory/issues.md
Decision made -> .claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.