ln-654-resource-lifecycle-auditor — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ln-654-resource-lifecycle-auditor (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Paths: File paths (references/,../ln-*) are relative to this skill directory.
Type: L3 Worker
Specialized worker auditing resource acquisition/release patterns, scope mismatches, and connection pool hygiene.
MANDATORY READ: Load references/audit_worker_core_contract.md. Tool policy: follow host AGENTS.md MCP preferences; load references/mcp_tool_preferences.md and references/mcp_integration_patterns.md only when host policy is absent or MCP behavior is unclear.
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.
Detection policy: use two-layer detection (candidate scan, then context verification); load references/two_layer_detection.md only when the verification method is ambiguous.
1) Parse context from contextStore
2) Detect DI framework
Depends(), Django middleware, Spring @Autowired/@PersistenceContext, Express middleware, Go wire/fx3) Discover resource infrastructure
sessionmaker, create_engine, DataSource, pool creation)Depends(), @Inject, providers, middleware mounting)4) Scan codebase for violations (6 checks)
5) Collect findings with severity, location, effort, recommendation
6) Calculate score using penalty algorithm
7) Write Report: Build full markdown report in memory per references/templates/audit_worker_report_template.md, write to {output_dir}/ln-654--global.md in single Write call
8) 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 references/audit_scoring.md.
MANDATORY READ: Load references/templates/audit_worker_report_template.md.
Write JSON summary per 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 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)Apply the already-loaded references/audit_worker_core_contract.md.
async with, with, try-with-resources, defer (already managed)Apply the already-loaded references/audit_worker_core_contract.md.
{output_dir}/ln-654--global.md (atomic single Write call)references/audit_output_schema.mdVersion: 1.0.0 Last Updated: 2026-03-03
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.