skills-catalog/ln-654-resource-lifecycle-auditor/SKILL.md
Checks session scope mismatch, missing cleanup, pool config, error path leaks, resource holding. Use when auditing resource lifecycle.
npx skillsauth add levnikolaevich/claude-code-skills ln-654-resource-lifecycle-auditorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Paths: File paths (
shared/,references/,../ln-*) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root. Ifshared/is missing, fetch files via WebFetch fromhttps://raw.githubusercontent.com/levnikolaevich/claude-code-skills/master/skills/{path}.
Type: L3 Worker
Specialized worker auditing resource acquisition/release patterns, scope mismatches, and connection pool hygiene.
MANDATORY READ: Load shared/references/audit_worker_core_contract.md.
MANDATORY READ: Load shared/references/mcp_tool_preferences.md and shared/references/mcp_integration_patterns.md
Receives contextStore with: tech_stack, best_practices, db_config (database type, ORM settings, pool config, session factory), codebase_root, output_dir.
Domain-aware: Supports domain_mode + current_domain.
Use hex-graph first when reference chains or call paths materially improve lifecycle findings. Use hex-line first for local code/config reads when available. If MCP is unavailable, unsupported, or not indexed, continue with built-in Read/Grep/Glob/Bash and state the fallback in the report.
MANDATORY READ: Load shared/references/two_layer_detection.md for detection methodology.
Parse context from contextStore
Detect DI framework
Depends(), Django middleware, Spring @Autowired/@PersistenceContext, Express middleware, Go wire/fxDiscover resource infrastructure
sessionmaker, create_engine, DataSource, pool creation)Depends(), @Inject, providers, middleware mounting)Scan codebase for violations (6 checks)
Collect findings with severity, location, effort, recommendation
Calculate score using penalty algorithm
Write Report: Build full markdown report in memory per shared/templates/audit_worker_report_template.md, write to {output_dir}/ln-654--global.md in single Write call
Return Summary: Return minimal summary to coordinator (see Output Format)
What: Resource injected via DI lives for entire request/connection scope but is used for only a fraction of it.
Detection (Python/FastAPI):
async def\s+\w+\(.*Depends\(get_db\)|Depends\(get_session\)|db:\s*AsyncSession|session:\s*AsyncSessionsession\.|db\.|await.*repo usageusage_lines / total_lines < 0.2 (session used in <20% of function body)
Detection (Node.js/Express):
req.db or req.knex at request startapp\.use.*pool|app\.use.*knex|app\.use.*prisma (middleware injection)req.db only in first 20% of function bodyDetection (Java/Spring):
@Transactional on method with long non-DB processingEntityManager injected but used only briefly@Autowired.*EntityManager|@PersistenceContext + method body analysisDetection (Go):
sql.DB or *gorm.DB passed to handler, used once, then long processingfunc.*Handler.*\*sql\.DB|func.*Handler.*\*gorm\.DBSeverity:
Recommendation: Extract DB operations into scoped function; acquire session only for the duration needed; use async with get_session() as session: block instead of endpoint-level DI injection.
Effort: M (refactor DI to scoped acquisition)
What: SSE, WebSocket, or long-poll endpoint holds DB session/connection for stream duration.
Detection (Python/FastAPI):
StreamingResponse|EventSourceResponse|SSE|async def.*websocket|@app\.websocketyield\s+.*event|yield\s+.*data:|async for.*yield (SSE generator pattern)Depends() in endpoint signature -> held for entire streamDetection (Node.js):
res\.write\(|res\.flush\(|Server-Sent Events|new WebSocket|ws\.on\(Detection (Java/Spring):
SseEmitter|WebSocketHandler|StreamingResponseBody@Transactional wraps streaming methodDetection (Go):
Flusher|http\.Flusher|websocket\.Conn*sql.DB or transaction held during flush loopSeverity:
Recommendation: Move auth/permission check BEFORE stream: acquire session, check auth, release session, THEN start streaming. Use separate scoped session for any mid-stream DB access.
Effort: M (restructure endpoint to release session before streaming)
What: Resource acquired without guaranteed cleanup (no try/finally, no context manager, no close()).
Detection (Python):
session\s*=\s*Session\(\)|session\s*=\s*sessionmaker|engine\.connect\(\) NOT inside with or async withconnection\s*=\s*pool\.acquire\(\)|conn\s*=\s*await.*connect\(\) NOT followed by try:.*finally:.*close\(\)session = get_session() without context managerasync with session_factory() as session:, with engine.connect() as conn:Detection (Node.js):
pool\.connect\(\)|knex\.client\.acquireConnection|\.getConnection\(\) without corresponding .release() or .end() in same functioncreateConnection\(\) without .destroy() in try/finallyDetection (Java):
getConnection\(\)|dataSource\.getConnection\(\) without try-with-resourcesConnection conn = ds.getConnection() without try (Connection conn = ...) syntaxDetection (Go):
sql\.Open\(|db\.Begin\(\) without defer.*Close\(\)|defer.*Rollback\(\)tx, err := db.Begin() without defer tx.Rollback()Severity:
Exception: Session acquired and released before streaming/long-poll begins -> skip. NullPool / pool_size config documented as serverless design -> skip.
Recommendation: Ensure resources are cleaned up on all exit paths (context managers, try-finally, or framework-managed lifecycle).
Effort: S (wrap in context manager or add defer)
What: Missing pool health monitoring, no pre-ping, no recycle, no overflow limits.
Detection (Python/SQLAlchemy):
create_engine\(|create_async_engine\(:
pool_pre_ping=True -> stale connections not detectedpool_recycle -> connections kept beyond DB server timeout (default: MySQL 8h, PG unlimited)pool_size -> uses default 5 (may be too small for production)max_overflow -> unbounded overflow under loadpool_size=0 or NullPool in web service -> no pooling (anti-pattern)@event.listens_for(engine, "invalidate") -> no visibility into connection invalidation@event.listens_for(engine, "checkout") -> no connection checkout monitoring@event.listens_for(engine, "checkin") -> no connection return monitoringDetection (Node.js):
createPool\(|new Pool\(:
min/max configurationidleTimeoutMillis or reapIntervalMillisvalidateConnection, testOnBorrow)Detection (Java/Spring):
DataSource|HikariConfig|HikariDataSource:
leakDetectionThresholdmaximumPoolSize (defaults to 10)connectionTestQuery or connectionInitSqlDetection (Go):
sql\.Open\(:
db.SetMaxOpenConns()db.SetMaxIdleConns()db.SetConnMaxLifetime()Severity:
Context-dependent exceptions:
Recommendation: Configure pool_pre_ping=True, pool_recycle < DB server timeout, appropriate pool_size for expected concurrency, add pool event listeners for monitoring.
Effort: S (add config parameters), M (add event listeners/monitoring)
What: Exception/error handling paths that skip resource cleanup.
Detection (Python):
except blocks containing raise or return without prior session.close(), conn.close(), or cursor.close()except Exception: logger.error(...); raise (re-raise without cleanup)async def.*yield.*session|def.*yield.*session without try:.*finally:.*close\(\)Detection (Node.js):
catch\s*\( blocks that throw or return without releasing connectionpool.connect().then(client => { ... }) without .finally(() => client.release()).finally() for cleanupDetection (Java):
catch\s*\( blocks without finally { conn.close() } when connection opened in tryDetection (Go):
if err != nil \{.*return before defer statement for resource cleanupOpen() and defer Close() that returns without closingSeverity:
Recommendation: Use context managers/try-with-resources/defer BEFORE any code that can fail; for generators, add try/finally around yield.
Effort: S (restructure acquisition to before-error-path)
What: Using framework DI to inject short-lived resources into long-lived contexts instead of using factory pattern.
Detection (Python/FastAPI):
Depends\(get_db\)|Depends\(get_session\)|Depends\(get_async_session\)StreamingResponse, EventSourceResponse), WebSocket (@app.websocket), background task (BackgroundTasks.add_task)async with session_factory() as session: at point of needsession: AsyncSession = Depends(get_session) at endpoint levelDetection (Node.js/Express):
req.db) used in WebSocket handler or SSE routeconst conn = await pool.connect(); try { ... } finally { conn.release() } at point of needDetection (Java/Spring):
@Autowired EntityManager in @Controller with SSE endpoint (SseEmitter)Detection (Go):
*sql.DB injected at handler construction time but *sql.Conn should be acquired per-operationSeverity:
Recommendation: Use factory pattern for long-lived contexts; inject the factory (sessionmaker, pool), not the session/connection itself.
Effort: M (change DI from session to session factory, add scoped acquisition)
MANDATORY READ: Load shared/references/audit_worker_core_contract.md and shared/references/audit_scoring.md.
MANDATORY READ: Load shared/references/audit_worker_core_contract.md and shared/templates/audit_worker_report_template.md.
Write JSON summary per shared/references/audit_summary_contract.md. In managed mode the caller passes both runId and summaryArtifactPath; in standalone mode the worker generates its own run-scoped artifact path per shared contract.
Write report to {output_dir}/ln-654--global.md with category: "Resource Lifecycle" and checks: resource_scope_mismatch, streaming_resource_holding, missing_cleanup, pool_configuration, error_path_leak, factory_vs_injection.
Return summary per shared/references/audit_summary_contract.md.
When summaryArtifactPath is absent, write the standalone runtime summary under .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json and optionally echo the same summary in structured output.
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-654--global.md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
MANDATORY READ: Load shared/references/audit_worker_core_contract.md.
async with, with, try-with-resources, defer (already managed)MANDATORY READ: Load shared/references/audit_worker_core_contract.md.
{output_dir}/ln-654--global.md (atomic single Write call)shared/references/audit_output_schema.mdVersion: 1.0.0 Last Updated: 2026-03-03
testing
Audits architecture config boundaries: typed settings, scattered env reads, config leakage, and layer ownership. Use for config architecture.
tools
Finds architecture-level modernization opportunities: obsolete custom mechanisms, overbuilt extension points, and simplifiable architecture. Use when auditing architecture evolution.
development
Builds dependency topology, detects cycles, validates import rules, and calculates coupling metrics. Use when auditing architecture topology.
testing
Checks layer, resource ownership, and orchestration boundaries. Use when auditing architecture boundary enforcement.