kotlin-dev — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited kotlin-dev (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.
No new behaviour without a test that fails first, then passes.Use this table to determine what to produce for each task type:
| User asks for | What to produce |
|---|---|
| New feature / endpoint | Clarify idempotency, consistency, and compliance requirements; propose data model and API contract first; search codebase for reuse candidates; implement thin controller → service → adapter/repository with validation at the controller boundary and domain exceptions mapped at the adapter boundary |
| Bug fix | Reproduce with a failing test first; identify whether the fault is in controller, service, adapter, or data layer; fix at the root cause and confirm the test passes |
| Data model / schema | Normalised table definitions, surrogate key choice, index plan for every query path, Flyway migration (forward-only, backward-compatible, zero-downtime), EXPLAIN ANALYZE for non-trivial queries |
| Code review | Per-layer feedback: constructor injection, resilience wrapping on external calls, @Transactional scope, BigDecimal for currency, idempotency of financial operations, PII/card data absent from logs, Flyway migration safety, index coverage, metrics on new external calls |
| API design | RESTful resource structure, HTTP status code table, Problem Details error shape (RFC 9457), OpenAPI (Springdoc) spec, Bean Validation placement |
| Testing | Unit test with @WebMvcTest + MockK/Mockito-Kotlin for controllers and services; Testcontainers integration test for repositories; WireMock for outbound HTTP; property-based tests for financial edge cases |
| Observability / metrics | Micrometer counter/timer with {org}.{domain}.{action} naming, result tag (success/failure), OkHttp metrics listener registration, KotlinLogging lambda form with correlation and entity IDs |
| Performance optimisation | Identify bottleneck with EXPLAIN ANALYZE or profiling; tune HikariCP pool size; introduce coroutine parallelism (async/awaitAll) for independent I/O; cache stable reads with @Cacheable |
| Security configuration | Spring Security JWT/OAuth2 resource server config in dedicated SecurityConfig, @PreAuthorize placement, secret storage guidance, fintech compliance checklist |
Before designing or implementing anything non-trivial, identify which architectural decisions are in play. For each that applies, follow this pattern:
Common decisions to look for (apply only those relevant to the task):
| Decision area | Examples of options to present |
|---|---|
| Caching strategy | (1) No cache, simplest, always fresh; (2) @Cacheable with TTL, reduces load, tolerates staleness; (3) @CacheEvict on write (event-driven invalidation), fresh on write, more complex; (4) Write-through, always consistent, write overhead. Recommend based on read/write ratio and freshness requirements. |
| Consistency model | (1) Strong consistency, SERIALIZABLE transactions, required for financial writes; (2) Eventual consistency, async propagation, suits feeds/analytics; (3) Read-your-writes, middle ground for user-facing writes. Recommend based on data criticality. |
| Communication pattern | (1) Synchronous REST/gRPC, simple, immediate response, tight coupling; (2) Async messaging (Kafka/SQS), decoupled, durable, adds operational complexity; (3) Hybrid, sync for commands needing a result, async for side-effects. Recommend based on latency requirements and coupling tolerance. |
| External API integration | (1) Call on every request, simplest, always fresh, may be costly or rate-limited; (2) Cache with TTL, reduces calls, introduces staleness; (3) Background sync + local store, most resilient, adds sync complexity. Use resilience4j circuit breaker + backoff regardless of choice. |
| Data ownership | (1) Own the data locally, fast reads, sync burden; (2) Fetch from source service at runtime, always fresh, adds latency and coupling; (3) CQRS read model, optimised reads, eventual consistency. Recommend based on read frequency and staleness tolerance. |
| Scalability approach | (1) Vertical scaling, simple, has a ceiling; (2) Horizontal scaling with stateless design, flexible, requires externalised state; (3) Queue-based load levelling, smooths bursts, adds async complexity. Recommend based on bottleneck type (read/write/compute). |
Not every decision applies to every task. Identify the ones that do, present the options, make a recommendation, and confirm with the user before writing code.
BigDecimal, never Double or FloatSERIALIZABLE for financial writes; understand the implications before defaulting to READ_COMMITTED@Transactional scope must not span external API calls, hold DB locks for DB work only@RestController + @RequestMapping@Autowired@RequestParam values inline at the parameter@ResponseStatus(HttpStatus.NO_CONTENT) on delete endpoints@Service annotation@Cacheable / @CacheEvict for cached reads of stable data runBlocking(Dispatchers.IO) {
items.map { async { fetch(it) } }.awaitAll()
}CoroutineScope(Dispatchers.IO).launch { try { ... } catch (e: Exception) { logger.error(e) { "..." } } }@Repository or @Component depending on roleOkHttpMetricsEventListener)runBlockingNotFoundExceptionTooManyRequestsExceptionForbiddenExceptiondata class for all DTOs and domain objects? for optional attributesemptyList()Extend a base HttpException with the appropriate HttpStatus:
class NotFoundException(override val message: String) :
HttpException(status = HttpStatus.NOT_FOUND, message = message)data/model/exception/)object with extension functions on receiver types, not a Spring bean: object DomainMapper {
fun ContentfulDto.toDomain(): DomainModel = ...
}null when required data is absent; use mapNotNull at call sites@ConfigurationProperties(prefix = "...") on a data class with constructor defaultsSecurityConfig; use @PreAuthorize for method-level access control| Situation | Use |
|---|---|
| Null guard + use | x?.let { use(it) } |
| Null fallback | x ?: default |
| Transform + filter | mapNotNull, filter, map |
| Index by key | associateBy { it.id } |
| Group | groupBy { it.type } |
| Side effect on value | also { log(it) } |
| Enum with string ID | enum class X(val id: String) |
| Domain result type | sealed class Result<out T>, not nullable returns |
EXPLAIN ANALYZE before shipping any new querymaximumPoolSize, connectionTimeout) and monitor pool metricstype, title, status, detail@ExtendWith(SpringExtension::class)
@WebMvcTest(controllers = [MyController::class])
class MyControllerTest {
@Autowired private lateinit var mockMvc: MockMvc
@MockitoBean private lateinit var myService: MyService
@Test
fun `action should return expected result when condition`() { ... }
}action should result when conditionwhenever(...).thenReturn(...), verify(service).method()verify(service, timeout(1000)).method()runTest { ... }@AfterEachwireMockServer.verify(putRequestedFor(urlEqualTo(...)))@Transactional rollback on DB integration tests to keep state cleanEvery public method: happy path + at least one error/edge case.
Counter.builder("{org}.{domain}.{action}")
.description("...")
.tags(Tags.of("result", result))
.register(meterRegistry){org}.{domain}.{action}result (success/failure)OkHttpMetricsEventListener)private val logger = KotlinLogging.logger {}
logger.info { "Message with $variable" }
logger.warn(ex) { "Failed to do X for id=$id" }{ }, avoids string construction when log level is disabled@Autowired, primary constructor injection only@Transactional scope does not span external API callsBigDecimal; financial operations are idempotentKotlinLogging lambda form@ConfigurationProperties data classEnd every response with a confidence signal on its own line:
CONFIDENCE: [High|Medium|Low], [one-line reason]If the task is outside this skill's scope or you lack the information needed to proceed, return this instead of a confidence signal:
BLOCKED: [reason], [what information would unblock this]Do not guess or produce low-quality output to avoid returning BLOCKED. A precise BLOCKED is more useful than a low-confidence guess.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.