بنقرة واحدة
signal-audit
Audit monitoring, test, type, and error handling coverage for a scope and identify gaps.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Audit monitoring, test, type, and error handling coverage for a scope and identify gaps.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Scan for PII exposure in API responses, committed files, grimoires, and data flow paths.
Scan for secret leakage in env files, client code, git history, and build artifacts.
API endpoint security surface scan — auth gates, data exposure, rate limiting, input validation.
Audit authentication flow completeness — login, refresh, logout, session, RBAC, middleware.
Map impact surface of a change or regression by tracing data flow through every consumer.
Generate defensive measure specifications from a PMR — test specs, types, error boundaries, checklists.
| name | signal-audit |
| description | Audit monitoring, test, type, and error handling coverage for a scope and identify gaps. |
| user-invocable | true |
| allowed-tools | Read, Glob, Grep, Bash |
Audit what monitoring, tests, types, and error handling exist for a given scope — and what's missing. Produces a signal coverage matrix showing defense depth across four dimensions (test, type, error handling, monitoring) for every file or module in scope. Cross-references coverage against historical PMR blast radii to prioritize gaps in historically fragile code.
/signal-audit [scope]
/signal-audit [scope] --dimension <test|type|error|monitor>
/signal-audit --all
Examples:
/signal-audit components/loan/
/signal-audit lib/envio/ --dimension type
/signal-audit app/api/loans/
/signal-audit --all
Arguments:
[scope] — Directory path, feature name, or "all" (optional, defaults to src/ or app/)--dimension — Audit only a specific signal dimension (optional)--all — Audit the entire codebaseResolve the scope to a set of files:
| Input | Resolution |
|---|---|
| Directory path | All .ts, .tsx, .js, .jsx files in directory (recursive) |
| Feature name | Grep for feature-related directories: components/{feature}/, app/{feature}/, lib/{feature}/ |
--all | All source files in src/, app/, lib/, components/ |
Exclude: node_modules/, .next/, *.test.*, *.spec.*, *.d.ts, build artifacts.
For each file in scope, check test coverage:
Test file existence: Does a corresponding test file exist?
Glob: **/{filename}.test.{ts,tsx} or **/{filename}.spec.{ts,tsx}
Glob: **/__tests__/{filename}.{ts,tsx}
Test type classification:
| Type | Detection Pattern |
|---|---|
| Unit | Single file import, mock dependencies |
| Integration | Multiple file imports, real dependencies, database/API calls |
| E2E | Playwright/Cypress patterns, browser interactions |
| Smoke | Minimal assertions, health check patterns |
Fixture realism audit: For files with tests, check if fixtures match production data shapes:
Grep: mock|fixture|stub|fake in test files → read fixture definitions
Flag unrealistic fixtures: simple string IDs where compound IDs are expected, hardcoded timestamps, placeholder addresses.
Coverage gap: Files with no corresponding test file are untested. Files with tests using unrealistic fixtures are weakly tested.
For each file in scope, audit type safety:
Loose types: Count occurrences of type system escape hatches:
Grep: : any[^_] or as any or : unknown[^)] in file
Grep: @ts-ignore or @ts-expect-error
Grep: !\. (non-null assertions)
Branded/opaque types at data boundaries: Check if data entering from external sources is typed with branded types:
Grep: Brand<|Opaque<|NewType< in type definitions
Grep: type.*Id.*= string (loose ID types)
Implicit type coercions: Find type-sensitive operations without explicit conversion:
Grep: BigInt\( in non-utility files → check if argument is typed
Grep: new Date\( → check if argument has unit documentation
Grep: Number\( or parseInt\( → check for overflow guards
Type gap: Files with any count > 3, or files at data boundaries without branded types, are weakly typed.
For each file in scope, audit error handling coverage:
Try/catch blocks: Find error handling patterns:
Grep: try\s*\{ in file → count and check scope
Grep: \.catch\( in file → count promise error handlers
Grep: ErrorBoundary in JSX files → check component-level error handling
Unhandled dangerous operations: Find operations that can throw without surrounding error handling:
Grep: BigInt\( not inside try/catch → unhandled parse errors
Grep: new Date\( not inside try/catch → potential Invalid Date
Grep: JSON\.parse\( not inside try/catch → unhandled parse errors
Grep: \.json\(\) not inside try/catch → unhandled response parse errors
Error surfacing: For caught errors, check if they're surfaced to users or monitoring:
Grep: console\.error|Sentry|toast|alert in catch blocks
Errors caught but not surfaced (swallowed) are worse than unhandled — they hide failure.
Error gap: Files with dangerous operations outside error handlers, or with swallowed errors, are unguarded.
For each file or module in scope, check runtime monitoring:
Error reporting integration:
Grep: Sentry\.|captureException|captureMessage in file
Grep: ErrorBoundary.*fallback in JSX files
Health check endpoints:
Glob: app/api/health*
Grep: /health|/status|/readiness in route files
CI workflows:
Glob: .github/workflows/*.yml → check if scope files are covered
Monitoring gap: Areas with zero runtime error capture or no CI coverage are unmonitored.
Check if any historical PMR's blast radius overlaps the audited scope:
grimoires/hardening/pmr/verified statusThis cross-reference ensures that historically fragile code gets the highest scrutiny.
SIGNAL COVERAGE AUDIT
======================
Scope: {scope}
Files Audited: {N}
Date: {timestamp}
Coverage Matrix:
| File | Tests | Types | Error Handling | Monitoring | PMR Overlap |
|------|-------|-------|----------------|------------|-------------|
| {path} | {status} | {status} | {status} | {status} | {pmr_ids} |
Status Legend:
■ Strong — Full coverage with realistic data
◧ Weak — Coverage exists but has gaps (unrealistic fixtures, loose types, swallowed errors)
□ None — No coverage in this dimension
⚠ Historic — File appears in past PMR blast radius
Summary:
Tests: {N} strong / {N} weak / {N} none
Types: {N} strong / {N} weak / {N} none
Error Handling: {N} strong / {N} weak / {N} none
Monitoring: {N} strong / {N} weak / {N} none
Critical Gaps (historically fragile + uncovered):
1. {file} — in PMR-{id} blast radius, {dimension} uncovered
2. {file} — in PMR-{id} blast radius, {dimension} uncovered
Recommended Actions:
- Highest priority: {files with PMR overlap + gaps}
- Generate hardening specs: /harden {pmr-id}
- Detailed blast radius: /blast-radius {file}
Write detailed report to grimoires/hardening/signals/SIGNAL-AUDIT-{scope_slug}-{date}.md if the audit covers more than 10 files.
Signal auditing measures the depth of defense across multiple dimensions. The failure modes involve either measuring the wrong property of each dimension or weighting all gaps equally regardless of historical evidence.
When auditing components/loan/ after the Envio incident, the skill inventories all 4 dimensions for each file. For repay-loan.tsx, it finds:
repay-loan.test.ts exists but tests loan-utils.ts helpers, not the contract call path → weakloanId typed as string with no branded type → weakBigInt() call outside try/catch → nonenonehistoricThis produces a 4-dimensional profile: [weak, weak, none, none] with PMR overlap. The audit correctly identifies that repay-loan.tsx has the worst signal coverage profile in the scope AND appears in a past incident's blast radius — making it the highest priority for hardening.
Contrast with loan-parameter-form.tsx, which has: [none, weak, none, none] with PMR overlap (missing chainId bug). This file is also high priority but for a different reason — its gap is in the type dimension (no chain ID enforcement) rather than the error handling dimension.
The audit doesn't just count gaps — it characterizes them by dimension, enabling targeted hardening. "File X needs tests" is less actionable than "File X needs an integration test that exercises the contract call path with realistic Envio compound IDs and a try/catch around the BigInt conversion."
The seductively wrong approach: equating test count with test coverage.
The Envio migration test suite had 82 tests across 13 files, all passing. A signal audit that reports "82 tests, 100% pass rate, test coverage: strong" has measured quantity, not quality. Those 82 tests covered the API route layer — every route handler was tested with Envio response validation. Zero tests covered the frontend component layer where the actual bugs manifested.
The audit that counts tests would report components/loan/ as having strong test coverage because repay-loan.test.ts exists with multiple test cases. But those test cases test isLoanExpired(), sortLoans(), and filterActiveLoans() — utility functions that didn't break. The contract call path (BigInt(loanId)) has zero test coverage despite sharing a file name with the utility tests.
The correct audit measures coverage per code path, not per file. A file with 50 tests for utility functions and zero tests for its primary responsibility (contract interaction) is weakly tested, not strongly tested. The signal audit must distinguish between "tests exist for this file" (existence) and "tests exist for the dangerous operations in this file" (substance).
The detection signal: if a file has tests but also appears in a PMR blast radius, the tests demonstrably failed to prevent the incident. This means either (a) the tests didn't cover the path that broke, or (b) the tests used unrealistic data. Both indicate weak coverage despite test existence.
Physics of Error: Semantic Collapse — reducing the multi-dimensional concept of "test coverage" (which code paths? with what data? testing what properties?) to a single dimension (test count). The 82-test suite had excellent quantity coverage and zero quality coverage for the paths that mattered. Collapsing these dimensions produces false confidence.
The fundamentally wrong approach: inventorying the signals that exist rather than the signals that would detect the actual failure modes.
A signal audit that finds "Sentry is configured, 3 error boundaries exist, CI runs on every PR" reports on the monitoring infrastructure's existence. But the question is not "what monitoring exists?" — it's "what monitoring would catch the failures that actually happen?"
In the Envio incident, the failure mode was BigInt("80094_backing_157") throwing a SyntaxError. What signal would catch this?
BigInt() path with compound IDs. They didn't — fixtures used simple strings.loanId has a branded type that prevents passing compound IDs to BigInt(). It didn't.An audit that reports "Sentry is configured" is technically accurate but useless — Sentry was configured globally but had no instrumentation in the component that broke. The audit must ask: "for each dangerous operation in scope, is there a signal that would fire if the operation fails?" Not: "does the project have monitoring infrastructure?"
The distinction is between infrastructure presence and signal path completeness. A project can have every monitoring tool installed and still have zero coverage for a specific failure mode because the tools aren't wired to the vulnerable code paths. The signal audit traces from failure mode to detection mechanism, not from monitoring tool to configuration file.
For the Envio incident, the correct audit would report:
BigInt() in repay-loan.tsx:32 — no error boundary, no Sentry, no type guard → 0/3 signals for SyntaxErrornew Date() in Activity.tsx:34 — no unit assertion, misleading comment, no monitoring → 0/3 signals for timestamp unit errorThis per-operation audit finds the exact gaps. The infrastructure-level audit ("Sentry: configured") provides false assurance.
Physics of Error: Semantic Drift — applying the concept of "signal coverage" to the monitoring infrastructure (does the tool exist?) rather than the monitoring paths (does the tool connect to the vulnerable operation?). Coverage applies to code paths, not to tool installations. A configured-but-unwired tool provides zero coverage for the paths it doesn't monitor.
After signal audit:
any, as any, @ts-ignore) per filegrimoires/hardening/signals/ for large audits (>10 files)| Error | Resolution |
|---|---|
| Scope resolves to zero files | Suggest valid directories, check for typos in path |
| Feature name doesn't match any directory | Search for feature-related files with broader Grep |
| No PMRs exist for cross-reference | Skip PMR cross-reference, note "no historical incident data" |
grimoires/hardening/signals/ doesn't exist | Create directory |
| Audit scope too large (>500 files) | Suggest narrowing scope or using --dimension filter |
/harden: Signal audit identifies gaps that become hardening action specifications/postmortem: Signal gaps section of PMR draws from signal audit findings/regression-check: Signal audit reveals whether past hardening actions still hold in context/blast-radius: Audit scope can be defined by a blast radius report/harden — Generate defensive specs for identified gaps/postmortem — Full incident analysis (signal audit feeds the signal gaps section)/regression-check — Verify specific PMR hardening actions (narrower than signal audit)/blast-radius — Map impact surface to define audit scope