# fileoldnewmust_fail_test # Прогон: python3 e2e/mutation_check.py --gradle ./gradlew # Правило: мутация обязана уронить ровно тот тест, который её ловит. Выжившая мутация = дыра в покрытии. # no-op мутации (old == new) запрещены — харнесс их отклоняет. # --- memo-core: ksqlite / FTS5 / vec0 --- memo-core/src/test/kotlin/memo/core/CoreSmokeTest.kt CREATE VIRTUAL TABLE v USING vec0(embedding float[4]) CREATE VIRTUAL TABLE v USING vec0(embedding float[8]) vec0KnnRoundTrip memo-core/src/test/kotlin/memo/core/CoreSmokeTest.kt floatArrayOf(0.1f, 0.9f, 0.0f, 0.0f) floatArrayOf(0.0f, 0.0f, 0.0f, 1.0f) vec0KnnRoundTrip memo-core/src/test/kotlin/memo/core/CoreSmokeTest.kt tokenize='unicode61' tokenize='ascii' fts5FindsCyrillic memo-core/src/test/kotlin/memo/core/CoreSmokeTest.kt "SELECT a FROM t" "SELECT a+1 FROM t" ksqliteSmoke # --- Чанкер --- memo-core/src/main/kotlin/memo/core/Chunker.kt Regex("^(#{1,3}) (.*)$") Regex("^(#+) (.*)$") fourHashesIsNotAHeading memo-core/src/main/kotlin/memo/core/Chunker.kt val trimmed = body.trim() val trimmed = body.uppercase() fourHashesIsNotAHeading memo-core/src/main/kotlin/memo/core/Chunker.kt private const val CHUNK_OVERLAP = 600 private const val CHUNK_OVERLAP = 0 longSectionIsSplitWithOverlap # --- Коллекции (дефект тройного обхода, найден на приёмке) --- memo-core/src/main/kotlin/memo/core/Collections.kt it.isFile && it.extension == "md" it.name.endsWith("md") findCollectionsReturnsOnlyDirsWithDirectMarkdown # --- Индексатор: пропуск неизменённого файла --- memo-core/src/main/kotlin/memo/core/Indexer.kt if (existing.mtime == mtime && existing.size == size) {\n return false if (existing.mtime == mtime && existing.size == size) {\n return true indexerSkipsUnchangedFile # --- Поиск: слияние режимов и ограничение k --- memo-core/src/main/kotlin/memo/core/Searcher.kt if (mode == SearchMode.LEX || mode == SearchMode.HYBRID) lexSearch(query) else emptyList() if (mode == SearchMode.LEX) lexSearch(query) else emptyList() hybridCombinesBoth memo-core/src/main/kotlin/memo/core/Searcher.kt .sortedByDescending { it.value }.take(k) .sortedByDescending { it.value }.take(k + 1) resultsRespectKAndTextLength # --- MCP: ошибка инструмента обязана помечаться isError --- memo-mcp/src/main/kotlin/memo/mcp/McpServer.kt ],"isError":true} ],"isError":false} searchWithoutPathIsError # --- Watcher: debounce сводит правки к одному вызову --- memo-watch/src/main/kotlin/memo/watch/Watcher.kt _indexCalls.incrementAndGet() _indexCalls.get() modifyTriggersSingleIndexCall