Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.30.0 · метрики 2.5.0 · 2026-08-03 04:44 UTC

townsendmerino / ken

Fast hybrid code search for agents. Pure Go, drop-in MCP-compatible with semble.

GoMIT★ 27 зірок⑂ 1 форкз трав. 2026 р.Переглянути на GitHub ↗
ТипMCP-серверяк це визначено

townsendmerino/ken має індекс здоров’я 67 зі 100, що відповідає смузі «Добрий». Найвищий показник — AI Readiness (86/100), найнижчий — Security (44/100). Останнє оновлення було 3 дні тому. Більшість нещодавньої роботи виконує один учасник.

67
загалом / 100
Добрий

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє зважене середнє, відкаліброване за розподілом публічного реєстру, тож діапазони мають перцентильний зміст; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 34 («У зоні ризику»).

67
Винятковий93-100Верхній щабель реєстру (≈ топ-5%); відповідає практично всім перевіреним критеріям
Відмінний80-92Сильний за всіма напрямами; незначні прогалини
Добрий65-79Здоровий; прогалини обмежені та керовані
Помірний50-64Прийнятний, але з помітними прогалинами; рекомендовано перевірку
Слабкий35-49Суттєві недоліки в кількох сферах
У зоні ризику20-34Суттєві слабкі місця; впровадження потребує обережності
Критичний1-19Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Зважений загальний бал 61 калібровано до 67 за шкалою опублікованого індексу (калібрування реєстру 2026-08-02).

Власність

Francis Townsend-MerinoОсобистий обліковий запис
4 підписники8 публічних репозиторіївз лют. 2011 р.

Цей репозиторій належить особистому обліковому запису. Проєкт з єдиним власником несе більший ризик безперервності, ніж підтримуваний організацією.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікація
Gogithub.com/townsendmerino/kenv1.3.1-277 днів тому

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

72Добрий · 21% загального індексу
Як обчислюється оцінка
36/36Свіжість push — останній push 3 дн. тому
6.2/36Ритм комітів — 9/52 тижнів із комітами
18/18Обсяг комітів — 405 комітів за останній рік
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Використані вхідні дані
commits_last_year405
human_commit_share0,94
days_since_last_push3
active_weeks_last_year9
Як обчислюється оцінка
27/27Випускає релізи — опубліковано 29 релізів
36/36Свіжість релізів — останній реліз 7 дн. тому
27/27Ритм релізів — реліз кожні ~5,6 дн.
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Використані вхідні дані
releases_count29
latest_release_tagv1.3.1
releases_from_tagsні
days_since_latest_release7
mean_days_between_releases5,6

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

45Слабкий · 17% загального індексу
Як обчислюється оцінка
23/60Зірки — 27 зірок
0/25Форки — 1 форків
0/15Спостерігачі — 1 спостерігачів
Використані вхідні дані
forks1
stars27
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (MIT)
18/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
readme_badges4
has_contributingтак
has_issue_templateні
has_code_of_conductні
readme_badge_servicesgithub.com, pkg.go.dev, shields.io
has_pull_request_templateні

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

50Помірний · 23% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
0/22.5Розподіл комітів — головний контриб’ютор — автор 100% комітів
1.4/13.5Широта контриб’юторів — 1 контриб’юторів
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Використані вхідні дані
bus_factor1
contributors_sampled1
top_contributor_share1
Як обчислюється оцінка
30.8/42Вирішення issue — закрито 73% issue
27.4/30Прийняття PR — злито 43/47 вирішених PR
0/13Newcomer PR acceptance — за 30 дн. не вирішено жодного PR від новачка
0/15OpenSSF Scorecard: Code-Review — Found 0/26 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs43
open_issues4
closed_issues11
prs_merged_7d0
prs_decided_7d0
prs_merged_30d0
prs_decided_30d0
issue_closed_ratio0,733
closed_unmerged_prs4
first_time_authors_30d0
first_time_prs_merged_30d0
first_time_prs_decided_30d0
Виключено з оцінювання (немає даних або не застосовно): newcomer_pr_acceptance. Залишкові ваги перенормовано.
Як обчислюється оцінка
10/30Підтримка власника — особистий (користувацький) обліковий запис
0/20Верифікований домен — не застосовно до користувацьких облікових записів
5/25Охоплення власника — 4 підписників у townsendmerino
18.9/25Послужний список — 8 публічних репозиторіїв, вік облікового запису ~15 р.
Використані вхідні дані
followers4
owner_typeUser
is_verified
owner_logintownsendmerino
public_repos8
account_age_days5 647
Виключено з оцінювання (немає даних або не застосовно): Верифікований домен. Залишкові ваги перенормовано.

Супровід пакетів

100Винятковий
Як обчислюється оцінка
25/25Опубліковано й доступно — 1 пакет(ів) у go
35/35Свіжість публікацій — остання публікація 7 дн. тому
20/20Історія версій — 27 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packagesgithub.com/townsendmerino/ken
ecosystemsgo
any_deprecatedні
min_days_since_publish7

Інженерна якість

Чи наявні базові інженерні практики та документація?

84Відмінний · 19% загального індексу
Як обчислюється оцінка
24/24Процеси CI — 3 процес(ів) CI
24/24Наявні тести
16/16Конфігурація лінтера — .golangci.yml
0/9.6Pre-commit-хуки
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 2 out of 2 merged PRs checked by a CI test -- score normalized to 10
Використані вхідні дані
has_ciтак
has_testsтак
has_editorconfigні
has_linter_configтак
has_precommit_configні

Документація

85Відмінний
Як обчислюється оцінка
30/30README
25/25Каталог документації
0/15Сайт документації / домашня сторінка
10/10Опис репозиторію
10/10Теми — 11 тем
10/10Wiki
Використані вхідні дані
topicsagents, bm25, code-search, embeddings, go, golang, mcp, mcp-server, model2vec, retrieval, semble
has_wikiтак
homepage
has_readmeтак
has_docs_dirтак
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

44Слабкий · 16% загального індексу

Стан безпеки

44Слабкий
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 2 out of 2 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/26 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
5/5Fuzzing — project is fuzzed
2.5/2.5Ліцензія — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
5/5Security-Policy — security policy file detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
1.5/7.5Vulnerabilities — 8 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4,4

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Має свідомо малу вагу (4%): агентний інструментарій — реальний сигнал супроводу, але репозиторій без нього все одно може отримати 100/100.

86Відмінний · 4% загального індексу
Як обчислюється оцінка
45/45Інструкції для агентів — CLAUDE.md
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 94 з 94 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes19 199
Як обчислюється оцінка
18/18Розгортання однією командою — Makefile
22/22Автоматизовані тести
11/11Конфігурація лінтера / форматера — .golangci.yml
11/11Статична перевірка типів — Go (статично типізована)
10/10Відтворюване середовище — lockfile
10/10Підтверджена практика роботи з агентами — 88 з останніх 100 комітів створено агентом або з його зазначенням
8/8Автоматизоване супроводження — 6 з останніх 100 комітів — автоматичні оновлення залежностей
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Використані вхідні дані
has_nixні
has_testsтак
lockfilesgo.sum
has_dockerfileні
typed_languageтак
bootstrap_filesMakefile
has_devcontainerні
has_linter_configтак
typecheck_configs
agent_commit_share0,88
toolchain_manifestsgo.mod
dependency_bot_commit_share0,06
Як обчислюється оцінка
45/45Типізований код — Go (статично типізована)
54.8/55Керовані розміри файлів — 1/266 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languageGo
largest_source_bytes67 873
source_files_sampled266
oversized_source_files1
Як обчислюється оцінка
0/40Схема API (OpenAPI/GraphQL/proto)
20/20Сервер MCP
40/40Придатні до запуску приклади — demos
Використані вхідні дані
example_dirsdemos
has_mcp_signalтак
api_schema_files

Ключові факти

27зірок GitHub
1контриб'юторів
405комітів за останні 12 місяців
3днів від останнього пушу
29релізів
1бас-фактор
4відкритих issue
Goпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Докладніше

OpenSSF Scorecard 4.4 / 10
4.4сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-08-03 04:44 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests2 out of 2 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/26 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
10Fuzzingproject is fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
10Security-Policysecurity policy file detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
2Vulnerabilities8 existing vulnerabilities detected
Прямі залежності 12
РеєстрПакетОбмеження версіїМаніфест
Gogithub.com/fsnotify/fsnotifyv1.10.1go.mod
Gogithub.com/go-git/go-git/v5v5.19.1go.mod
Gogithub.com/go-sql-driver/mysqlv1.10.0go.mod
Gogithub.com/jackc/pgx/v5v5.10.0go.mod
Gogithub.com/modelcontextprotocol/go-sdkv1.7.0go.mod
Gogithub.com/odvcencio/gotreesitterv0.47.0go.mod
Gogithub.com/pkoukk/tiktoken-gov0.1.8go.mod
Gogithub.com/townsendmerino/aikitv1.13.0go.mod
Gogo.uber.org/goleakv1.3.0go.mod
Gogolang.org/x/syncv0.22.0go.mod
Gomodernc.org/sqlitev1.55.0go.mod
Gogithub.com/townsendmerino/aikit/chunk/treesitterv1.0.0go.mod
Усі залежності не зібрано

Не вдалося зібрати розв'язаний набір залежностей для цього звіту: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [
        "agents",
        "bm25",
        "code-search",
        "embeddings",
        "go",
        "golang",
        "mcp",
        "mcp-server",
        "model2vec",
        "retrieval",
        "semble"
      ],
      "is_fork": false,
      "size_kb": 4198,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 2035444,
        "Shell": 33157,
        "Python": 89789,
        "PLpgSQL": 1539,
        "Makefile": 1606
      },
      "pushed_at": "2026-07-30T21:25:16Z",
      "created_at": "2026-05-19T23:11:42Z",
      "owner_type": "User",
      "updated_at": "2026-07-31T12:02:37Z",
      "description": "Fast hybrid code search for agents. Pure Go, drop-in MCP-compatible with semble.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Francis Townsend-Merino",
      "type": "User",
      "login": "townsendmerino",
      "company": null,
      "location": null,
      "followers": 4,
      "avatar_url": "https://avatars.githubusercontent.com/u/620372?v=4",
      "created_at": "2011-02-16T02:25:11Z",
      "is_verified": null,
      "public_repos": 8,
      "account_age_days": 5647
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.3.1",
          "kind": "patch",
          "published_at": "2026-07-27T03:06:43Z"
        },
        {
          "tag": "v1.3.0",
          "kind": "minor",
          "published_at": "2026-07-26T03:02:07Z"
        },
        {
          "tag": "v1.2.1",
          "kind": "patch",
          "published_at": "2026-07-24T14:01:21Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-07-24T13:55:46Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-07-16T14:57:53Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2026-06-12T01:34:04Z"
        },
        {
          "tag": "v1.0.1",
          "kind": "patch",
          "published_at": "2026-06-11T17:27:44Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-06-06T23:58:40Z"
        },
        {
          "tag": "v0.10.1",
          "kind": "patch",
          "published_at": "2026-06-06T22:58:16Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-06-06T15:49:51Z"
        },
        {
          "tag": "demos/v0.2.0",
          "kind": "other",
          "published_at": "2026-06-03T23:02:54Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-06-03T16:19:44Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-06-03T16:19:43Z"
        },
        {
          "tag": "demos/v0.1.0",
          "kind": "other",
          "published_at": "2026-05-28T05:32:36Z"
        },
        {
          "tag": "v0.8.8",
          "kind": "patch",
          "published_at": "2026-05-28T05:04:50Z"
        },
        {
          "tag": "v0.8.7",
          "kind": "patch",
          "published_at": "2026-05-27T20:00:37Z"
        },
        {
          "tag": "v0.8.3",
          "kind": "patch",
          "published_at": "2026-05-26T15:24:15Z"
        },
        {
          "tag": "v0.8.2",
          "kind": "patch",
          "published_at": "2026-05-26T05:58:27Z"
        },
        {
          "tag": "v0.8.1",
          "kind": "patch",
          "published_at": "2026-05-26T04:57:08Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-05-26T02:40:58Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2026-05-25T17:40:55Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2026-05-25T16:28:48Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-05-25T14:56:22Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-05-25T05:30:27Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-05-23T15:44:41Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-05-21T23:33:45Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-05-21T18:12:16Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-05-21T01:39:45Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2026-05-20T17:16:14Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "cd782750485cf0bb872bc6c56f946a1e289f1076",
          "body": "…rnc.org/sqlite-1.55.0\n\nchore(deps): Bump modernc.org/sqlite from 1.54.0 to 1.55.0",
          "is_bot": false,
          "headline": "Merge pull request #65 from townsendmerino/dependabot/go_modules/mode…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-30T21:25:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0e260fed6fe6018f3a7ccc56d9cd7b8a5cf319c7",
          "body": "…ub.com/modelcontextprotocol/go-sdk-1.7.0\n\nchore(deps): Bump github.com/modelcontextprotocol/go-sdk from 1.6.1 to 1.7.0",
          "is_bot": false,
          "headline": "Merge pull request #64 from townsendmerino/dependabot/go_modules/gith…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-30T21:24:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "796cda7b971d39af07e7c041be4f96a2e9e5b0d3",
          "body": "Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.54.0 to 1.55.0.\n- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)\n- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.54.0...v1.55.0)\n\n---\nupdated-dependencies:\n- dependency-name: modernc.org/sqlite\n  dependency-version: 1.55.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump modernc.org/sqlite from 1.54.0 to 1.55.0",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-30T20:53:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5e937aaf693d80d3205180ba55d346cfd68e2a5f",
          "body": "Bumps [github.com/modelcontextprotocol/go-sdk](https://github.com/modelcontextprotocol/go-sdk) from 1.6.1 to 1.7.0.\n- [Release notes](https://github.com/modelcontextprotocol/go-sdk/releases)\n- [Commits](https://github.com/modelcontextprotocol/go-sdk/compare/v1.6.1...v1.7.0)\n\n---\nupdated-dependencies\n[…]\nhub.com/modelcontextprotocol/go-sdk\n  dependency-version: 1.7.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump github.com/modelcontextprotocol/go-sdk",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-30T20:53:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4358b94d824251a1a3645c680065600f40e90408",
          "body": "Picks up aikit's own 2026-07-25 audit remediation + perf pass in the packages\nken imports. Relevant to ken's CPU retrieval path (the v1.12/v1.13 GPU + vision +\nembedder-coverage headline does not apply — ken is pure-Go/no-cgo/CPU): topk now\nbreaks ties by index (determinism), chunk.Register is race-\n[…]\n\ntied result: no determinism/NDCG-exact-match/snapshot test needed re-baselining.\nvet + golangci-lint + -race (search, mcp) clean.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(deps): bump aikit v1.11.0 → v1.13.0",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-28T22:52:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4aed5e907cad93f90a80c38b30c1e70df0a705c8",
          "body": "R5-4 (Low, R4-6b regression): R4-6b swapped WriteFile+Rename for CreateTemp →\nfsync → rename, but os.CreateTemp makes the temp 0600 and nothing restored the\nmode — so the shipped .ken/index.bin (an operator artifact baked into images /\n//go:embed'd) became group/other-unreadable. A container built a\n[…]\n, 0644) before rename, matching the same-round modelfetch conversion,\nand assert group/other-readable in TestBuildIndex_HappyPath.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R5-4 restore 0644 on ken build-index output",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-27T00:13:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3e06867ce81831cd508e7afcf1908adba6982742",
          "body": "…ming()\n\nR5-3 (Med, R4-1 orphan): cmd/ken-mcp/snapshot.go's re-persist gate keyed off the\nraw StagedEmbedding option (its pre-R4-1 shape) with a comment asserting a warm\npass that no longer runs on this path. R4-1 made staging corpus-derived\n(len(vecs)==0), and the reconcile path arrives with vecs a\n[…]\ned, true only on a genuine staged cold build (where the warm\npass persists). The sibling live-build gate in main.go stays correct.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R5-3 gate reconcile-boot snapshot persist on wi.War…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-27T00:13:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9ea01e7ac89a76461710fb3fa73b1513595f2c7",
          "body": "…ex_db error\n\nR5-2 (Med, R13/R4-5 follow-on): wireDBTier2 returns a CONCRETE-nil\n*mcpdb.Refresher at five sites (no DSN, validation/setup failure), and that was\nassigned straight into the Config.DB INTERFACE field — a concrete-nil in an\ninterface is a non-nil interface, so `cfg.DB != nil` was true w\n[…]\nLL error\nin handleReindexDB before sanitizing. Now every error the sanitized reply tells\nthe agent to grep for is actually logged.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R5-2 guard typed-nil DBIntegration + log full reind…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-27T00:13:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a93168b315fb7dee0b36604c43143205bf8c0afd",
          "body": "…test guards (search)\n\nR5-1 (Med, R4-1 follow-on): buildUnionedIndexLocked's parallel-slice invariant\ncompared w.vecs to w.chunks only, which passes vacuously during the staged\nwindow (len(w.vecs)==0). But SetExtraChunks embeds Tier-2 DB chunks\nunconditionally on w.model!=nil, so the extras branch c\n[…]\nk is now batch-aware\n(receives the batch, returns true to consume itself) and fires only on the flush\nthat actually appended pkg/.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R5-1 merged-extras vecs/chunks invariant + round-5 …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-27T00:13:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6fd812cc2d47c349380c7136762439f433f3961e",
          "body": "…verify)\n\nRunning docs/verify-audit-round4.sh's Mutation B (restore the real\n`knownIndexedFile(rel) || isTrackedRel(rel)` gate) revealed the first cut of the\nrewritten N2 test bit only against a simplified gate: the real knownIndexedFile\nis `chunk.Language(rel) != \"\"`, which accepts any recognized-e\n[…]\nally exercised. Now goes RED under Mutation B (faithful\ngate), GREEN with N2 in place — confirmed by re-running the verify script.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(search): make the N2 bite test faithful cross-platform (round-4 …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T23:22:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "72384b5deef5bf7585895e919679fdea08c0241d",
          "body": "…nc paths (round-4 re-audit)\n\nR4-5 (Med, db#4 follow-on): the reindex_db allowlist correctly stopped leaking\ndriver text, but both sanitized messages promise \"check the server logs\" and on\nthe agent-callable path (TryRefresh → handleReindexDB) the detail was logged\nNOWHERE — doRefresh returned the w\n[…]\n write path, gains the parent-dir fsync); build-index and modelfetch get\ninline fsync-data-before-rename + fsync-parent-dir-after.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R4-5 reindex diagnostic logging, R4-6 remaining fsy…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T23:15:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08f3549540ca7eebc765d6ab97ecc4ed3b1c366a",
          "body": "…re-audit)\n\nR4-4 (Med, N7 half-done → FIXED): round 3 added stopStructuralBuild and wired it\ninto reapEntry (Purge/Close), but getBundleOnce kept its own older reap closure\nthat only closed the Index — and four sites used it, including the steady-state\nLRU-eviction path. So an eviction firing while \n[…]\nht, Get(B) evicts A) and\nasserts A's build context is cancelled. Verified RED with the eviction site\nreverted to Index-close-only.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R4-4 route LRU eviction through reapEntry (round-4 …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T23:15:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "730d1d9eecf2e9844685bc503d6904ff24c1f431",
          "body": "… re-audit)\n\nR4-2 (High, N4 half-done → FIXED): round 3's label sentinel (\"# ken:\", was\n\"# func:\") invalidated the .ken/snapshot artifact via the SnapshotConfigKey\nv1→v2 bump, but NOT the OTHER artifact that persists enriched Chunk.Text — the\nKEN1 .ken/index.bin operator prebuilt / //go:embed path, \n[…]\n now asserts the key carries the \"v2|\"\nprefix — without it, reverting the version bump (N4's whole migration story)\nbroke no test.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R4-2 bump KEN1 serializeFormatVersion to 2 (round-4…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T23:15:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ca580ee1b57ad4c411bf1be2a406c7110ef97ee5",
          "body": "…nc — round-4 re-audit\n\nR4-1 (High, N1 REGRESSED → FIXED): staged-embedding (KEN_MCP_STAGED) set\nstagedPending from the *option*, before the pre-publish snapshot reconcile. On\na snapshot-seeded boot vecs arrives full-length, so a drift reconcile appended\nchunks under the stagedPending gate that skip\n[…]\nerdict is\npinned before publish. Verified RED with the stale-snapshot gate restored\n(pkg/mod.py orphaned), GREEN with N2 in place.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R4-1 staged-boot panic, R4-3 no-op flush, R4-6 resy…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T23:14:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e8638e4468b35449962c51d9653bf7c05e10bdc9",
          "body": "…ent (round-3 leftovers)\n\ndb#4 (leftover, PARTIAL→FIXED): safeDBErrorMessage was a growing denylist\nthat kept missing phrasings — the re-audit found MySQL's \"denied to user\n'x'@'ip'\" (vs \"for user\") in a \"db: mysql introspect:\" wrapper still reached\nthe model, and a bare Contains(s,\"connect\") miscla\n[…]\nound warned about; it's a perf optimization (correct today), so it stays a\ndedicated follow-up rather than a tail-of-round change.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(pull-forward): db#4 allowlist, §21 vecs peak, §27 fsync, R14 comm…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T22:09:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "59c714b0fd1982f920121d7783d91d164b4cb5e7",
          "body": "…udit)\n\nR15's overshoot message (\"offset N is past the end\") was encoded only in the\nmarkdown argument, which dispatchOutput discards in json mode — so a json-mode\nagent (the mode agents most use) paging past the end still got a silent\n{\"symbols\":[],\"total_symbols\":100,\"offset\":100}. Add Overshot bo\n[…]\n\nOutlineResponse + SymbolsResponse and set it before dispatch.\n\nTest: symbols{offset past end, output:json} carries overshot=true.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): N9 overshoot signal in JSON responses (round-3 re-a…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T21:52:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3bcffb9cd8f75ba0c0bdb49c86af49982b2d497b",
          "body": "…ural-build lifecycle (round-3 re-audit)\n\nN5: R11's fnv.New64a().Write([]byte(text)) allocated a full copy of every\nchunk's text per flush (plus a hasher) through a hash.Hash64 interface that\ndefeats inlining — a net loss vs the runtime memhash it replaced. Swap to\nmaphash.String (AES-backed, zero-a\n[…]\n + stale bundle reaped\n(builds==2); a new stopStructuralBuild test cancels an in-flight build\npromptly; goleak covers the package.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): N5 zero-alloc token hash, N6 purge retry, N7 struct…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T21:50:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f9afc35b532d7db1b67d3a55502eb65a95396dee",
          "body": "…-audit)\n\nN3: the snapshot config key omitted lazy/staged, so a lazy/staged run's\nsnapshot (BM25, vector-less, deferred-label) could be accepted by an inline\nrun; and the drift path wrote a pre-warm snapshot with no lazy/staged gate,\npersisting a vector-less BM25 .bin stamped with the served mode th\n[…]\nabel now keeps\nold-grammar source lines and strips only the sentinel; format-stability +\nlazy/strip tests updated to the sentinel.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): N3 snapshot key/lock, N4 label sentinel (round-3 re…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T21:41:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f4e210c8dd26a653bf2064b7a293b34e7aa0eb1e",
          "body": "…debounce bypass; make the slow-flush test bite (round-3 re-audit)\n\nN1 (High): R6 gated the migration-fold on !StagedEmbedding on the BUILD path\nbut the two WATCH-path append sites (appendFile, refoldMigrationDir) still\ngated only on w.model != nil. Under KEN_MCP_STAGED=1 a flush during the\npre-warm\n[…]\nin would push it\ninto the thousands; it passed even with R1 reverted before. Plus a new\ndir-rename-during-flush test that pins N2.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): N1 staged panic, N2 orphaned dir-rename chunks, N8 …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T21:17:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7d35d3ec011994cb20a3185a1161b725aec38bce",
          "body": "…7-26 re-audit)\n\nR12: addRecursive emitted one stderr line per failed w.Add — ~42k lines at\nstartup on a 50k-dir tree past an 8192 inotify limit. Count failures during\nthe walk and emit ONE summary line (count + first error).\n\nR13: a nil *usage.Recorder assigned into Config.UsageRecorder (an interfa\n[…]\nts: pageWindow overshot cases; R14 last-component behavior pin\n(A::B::C defines C not B); safeDBErrorMessage MySQL+SQLite no-leak.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R12-R15 + leftover watcher/credential holes (2026-0…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T20:14:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "388d935ce760a152068e35cea8db2a8e9a4d5c7f",
          "body": "…ey (2026-07-26 re-audit)\n\nR10: #19's cached usage-stats handle promised \"handles log rotation\" but the\nonly reopen trigger was a write error — and on POSIX rename(2)/unlink(2)\ndon't invalidate an open fd, so after `logrotate` moves the file the writes\nkeep succeeding against the rotated-away (or un\n[…]\n: rotation reopens the live path and leaves the rotated file intact;\ntoken-cache eviction/size assertions updated to the hash key.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R10 usage rotation recovery, R11 token-cache hash k…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T19:42:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4e49b7fc39f9d3c1124eb58e854042b3df931808",
          "body": "…gnore-gate new dirs (2026-07-26 re-audit)\n\nR8: the async flush (§12) was supposed to keep the event loop draining, but\ntwo paths pulled corpusMu back onto the loop. (a) isTrackedRel and\nenqueueFullResync scanned w.chunks under corpusMu — held by the flush\ngoroutine for its whole (multi-second) dura\n[…]\nuth within a bounded wall-clock (exercises R1 no-spin, R8 loop\ndrains, and the handoff); plus ShouldDescend's gitignore/.git gate.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R8 event loop no longer blocks on corpusMu, R9 giti…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T19:24:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d10a28dc335c4ced4f137a24f98f0ccedfd6749b",
          "body": "… stale bundle (2026-07-26 re-audit)\n\nR6: the StagedEmbedding deferral guarded the per-file worker\n(`if model != nil && !opts.StagedEmbedding`) but NOT the migration-fold\nloop in the same function — so KEN_MCP_STAGED=1 on a repo with a migrations/\ndir produced len(vecs)==numFolded while len(chunks)=\n[…]\ningBuild_NoStaleRepopulate (race-clean) — purge\nmid-build, assert the stale bundle is reaped not cached and the next Get\nrebuilds.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R6 staged-embed vecs misalign, R7 purge repopulates…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T19:12:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "36f694595bc1e3674a93b836158c81d25d3d0232",
          "body": "…r-converges, R4 bogus row count, R5 label strip (2026-07-26 re-audit)\n\nR1 (High): the §13 debounce ceiling + §12 async flush composed into a\nfull-core busy spin — once past the ceiling, the `flushing` arm re-armed\nthe timer at delay=0, which fired immediately, re-armed, and looped (~1.7M\niters/s). \n[…]\n two sides can't drift a third time.\n\nTests: StripLabel per-arm + idempotence; structural failure cooldown +\nretry-after-cooldown.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(regressions): R1 busy-spin, R2 label doubling, R3 structural neve…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T18:59:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "508361eacc1013e65dd260c4f9212060bd8ee08a",
          "body": "…rch §21)\n\nserializeIndex built separate chunksBody + vecsBody bytes.Buffers and then\nCOPIED both into buf — so all three lived at once (~192 MB peak for a ~96 MB\nartifact on a 64k×256 index), and the vecs loop made one Buffer.Write per\nfloat (~16.4 M calls). On a KEN_MEMLIMIT=512MiB server that pus\n[…]\n. Byte format\nis unchanged — the length-prefix values are identical — so the serialize\nroundtrip + KEN1 load tests pass untouched.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(search): serialize into one buffer, pack vecs in bulk (audit sea…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T17:11:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9aca43413098f0435efef3f5e93eb478b5c68bc6",
          "body": "…arch §27)\n\nThe atomic save used a fixed \"<path>.tmp\", so two ken-mcp processes sharing\na cache path interleaved writes to the same temp file before rename. Switch\nto os.CreateTemp with a per-write \"-*.tmp\" suffix (matching\ninternal/modelfetch), keeping the same-filesystem rename atomic.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(search): unique temp name for rerank-cache atomic write (audit se…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T17:05:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f295e4dbf234aeb3add03c6546c6f27f6a91c003",
          "body": "…rch §10)\n\nEnrichment (default-on) prepends a synthetic `# func: NAME | calls: … |\nraises: …` line to each chunk's Text so BM25/embeddings see the structural\nsignal. Nothing stripped it before results reached the agent, so every\nsearch/find_related result began with a line that ISN'T in the source\nf\n[…]\n when a chunk isn't enriched.\n\nTest: label stripped + body preserved; non-enriched and plain-markdown text\npass through untouched.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): strip Arm B enrichment label from search results (audit sea…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T17:00:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ae2e3eea89255d3f1f8561ae3daa1088898f23aa",
          "body": "…rch §16)\n\nEvery `**` compiled to a bare `.*`, dropping git's whole-component rule.\nSo `**/migrations/*.php` (the README's own .kenignore example) also excluded\n`src/dbmigrations/*.php` and `app/usermigrations/*.php`; `**/foo` matched\n`barfoo`; and `a/**/b` matched `a/xb`. Legit source files silentl\n[…]\nr `[^/]*`.\n\nTest: the four false-positive cases above now correctly DON'T match, while\nthe intended at-any-depth matches still do.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(repo): gitignore ** respects path-component boundaries (audit sea…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:57:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "71bd780af8c8dd47245d0daf36f05382c28d2817",
          "body": "…g (audit search §13, §15, §17)\n\n§17: reconcileCorpusLocked appended chunks in Go's randomized map-iteration\norder (over the batch and touchedMigDirs), so two ken-mcp processes on the\nsame repo built different chunk orders → different BM25 doc IDs → different\nrerankTopK tie-breaks → different result\n[…]\n× debounce); reset on flush.\n\nTests: continuous-churn still flushes within the ceiling; a file oversized\nby flush time is skipped.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(watch): deterministic flush order, size re-check, debounce ceilin…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:50:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9bdecabb10d7f8974c08acc94db0756d9da3ed3c",
          "body": "…, misc Lows (audit §11,§23,§24,§25,§26,§29,§30)\n\n§11: SearchWithQVecPredicted's hybrid branch passed bare `k` to hybridSearch\nwhile computing (and ignoring) `overFetch` — so on a tombstone-carrying\nindex the post-retrieval tombstone filter returned fewer than k results,\nthe exact bug SearchMode doc\n[…]\nhen k > rerankN (head normalized [0,1], tail raw\nRRF).\n\nTest: WithExtraChunks invariant now returns an error instead of panicking.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(search): tombstone over-fetch, no-panic extras, synced lazy reads…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:43:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3aa62a291efd1aabec269899c1c7fccda9ad23a0",
          "body": "…ism comment (audit search §18, §28)\n\n§18: kenLangToTSLang has only lowercase keys, but ExtractFile and Build\nlooked it up with the raw filepath.Ext — so Foo.PY / MAIN.C / Widget.TS\n(Windows-authored + legacy C/C++ trees) got chunked with the right\nlanguage rules but extracted NO structure: no Arm B\n[…]\n\nso a future edit that drops those sorts doesn't trust a false invariant.\n\nTest: uppercase .PY extracts the same structure as .py.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(structural): case-insensitive extension lookup + correct determin…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:37:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "14796618fb7771d1b3b35d952f905772cf1580c4",
          "body": "…r-clone byte cap (audit db/mcp §21, §22, §24)\n\n§21 (behavioral divergence): the embedded-corpus server's find_related\nreturned a bare textResult on bad input, while the Cache-backed server\nreturns output-mode-aware errorResult — so a json-mode agent hitting the\nembedded server on a bad `line` got u\n[…]\nclone decrements the same counter — genuinely per-clone.\n\nTests: shared-budget cutoff across two conns; existing cap tests ported.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): embedded find_related error mode, MCP rerank validation, pe…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:34:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c9f46a7524ec5b90851fdcc6d2c77acb61af94eb",
          "body": "…mcp §11)\n\nThe flagship engine's sample loop was serial N+1 — one round-trip per table\nstrictly in sequence — while MySQL and SQLite fan out (ADR-031). On 400\ntables 25ms away that's ~10s of pure RTT in the sample loop alone, inside\nboth the (now-bounded, §3) startup path and the reindex_db tool cal\n[…]\neric (M5, no password echo). go.mod gains puddle\n(pgxpool's dep). Postgres now matches the other two engines at ~8× on\nremote DBs.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(db): parallelize the Postgres row sampler over a pool (audit db/…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:30:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9fc85c46dfb8fd16c17a810a8308f4e1c19ffe29",
          "body": "…caught (audit db/mcp §20)\n\nThe audit noted .golangci.yml omitted the two linters aimed squarely at\nthis package's bug history — a missing rows.Err() had shipped and been\nhand-fixed twice. Enabling rowserrcheck + sqlclosecheck immediately found\n6 real issues, all fixed:\n\n- rowserrcheck: internal/db/\n[…]\ns) and defer rows.Close() in the sample closures, plus rows.Err() where\nit was missing. Whole tree is clean under the new linters.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(lint): enable rowserrcheck + sqlclosecheck; fix the 6 leaks they …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:23:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "656de7c56b3e3e03550670134324e6010b0fdb4c",
          "body": "… db/mcp §16, §23)\n\n§16: the outline directory handler called sidx.Outline(f) once to build the\nJSON structs, then AGAIN via formatOutlineEntries(sidx.Outline(fe.File)) to\nrender markdown — every file in the subtree walked twice, and in markdown\nmode (the default) the JSON structs were built and dis\n[…]\nmode (render markdown, append the mode note).\n\nTests: error text survives a bad output mode; json errorResult stays\n{\"error\":...}.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): single-pass outline + error survives bad output mode (audit…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:20:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "38366adbaf0acc854a2d911de9e2f56e9c02ff6e",
          "body": "…p §9, §19)\n\n§9: BuildSummary's `today := now.Truncate(24*time.Hour)` bucketed by UTC\nday, not local — time.Truncate rounds relative to the zero time in UTC by\ndefinition, contradicting the doc comment's \"local timezone\" promise. A\nuser in UTC+10 saw every search before 10am local reported under yes\n[…]\n\nshutdown cleanup.\n\nTest: persistent-handle reuse + Close/reopen-across-boundary (all writes\nsurvive) + idempotent/nil-safe Close.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(usage): local-tz day boundary + cached append handle (audit db/mc…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:16:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1957fd0fdaf960d3da8aa25020861ebbb2ca56d8",
          "body": "…outs (audit db/mcp §10,§13,§14,§26,§27,§28)\n\n§10: MySQL set MaxIdleConns(sampleWorkers) + ConnMaxLifetime(5m). With\nMaxOpenConns=8 but the database/sql default MaxIdleConns=2, 6 of every 8\nsample-connection releases closed the connection — ~375 extra TLS\nhandshakes on a 500-table sample, in the loo\n[…]\ntayed dead. Bounded to 5s.\n\nTests: withSampleRecover (panic caught+logged), SQLite implicit-FK real-PK\nresolution (dbintegration).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(db): sampler robustness — pool churn, BLOBs, FK PKs, panics, time…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T16:14:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7045bcdd1d84ab83362347a7d91343ff053ec957",
          "body": "…§17, §25, §29)\n\n§12: overloaded Postgres functions (same schema+name, different args) sorted\nnondeterministically and collapsed to one Chunk.File — breaking the \"chunks\ndeterministic across runs\" guarantee and letting file-saturation decay\nsuppress all but one overload. Add pg_get_function_identity\n[…]\n args.\n\nTests: dbChunkPath dot-omission table, overloaded-function distinct-path\nassertion, function-path arg-signature assertion.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(db): introspection determinism + cleanup (audit db/mcp §12, §15, …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:59:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "43ace00361a95087e9033892169de118cf1d6ccb",
          "body": "…ps draining (audit search §12)\n\nflush() does file I/O + embedding + a full BM25/ANN rebuild, and it ran\ninline on the watcher goroutine — so for the whole flush (seconds on a\nlarge `git checkout`) w.fs.Events was not drained, letting the kernel event\nqueue fill toward the overflow that §3 then has \n[…]\ns (exercising flushing→flushDone→re-arm) and\nasserts nothing is dropped; goleak + -race confirm no leaked/ racing flush\ngoroutine.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(watch): run flush async with single-flight so the event loop kee…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:52:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "10ac79e73b1ce7033054d0a4f2577ea3820eb40f",
          "body": "… (audit search §6, §7)\n\n§7: rerankTopK recomputed minSelected as a full O(M) scan over the\nappend-only `selected` slice on EVERY append past topK. On a symbol query\nwhere scanNonCandidates injects high-scoring non-candidates, `selected`\ngrows to thousands while file-saturation decay drives minSelec\n[…]\nrrency-safe). The former data-race test on the deleted cache becomes a\nconcurrency + correctness smoke test on the lock-free path.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(search): O(1) rerank min + single precompiled definition pattern…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:41:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "42afd84ca010d802b4b2a9fbfe1fd5825a47e586",
          "body": "…on failures (audit search §3, §4)\n\n§3: the fs.Errors branch discarded every error, including ErrEventOverflow\n— which is NOT transient. When a large `git checkout` / `npm install` fires\nmore events than the kernel queue holds (esp. while the loop is blocked in\nflush), the kernel permanently drops t\n[…]\noversFromDroppedEvents drives\ndelete+add+modify on disk, then enqueueFullResync + flush, asserting the\nindex matches ground truth.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(watch): recover from fsnotify overflow; tolerate watch-registrati…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:36:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4b58a10bbd7b589c919310e696fd20b36e7f7f0b",
          "body": "…it db/mcp §1)\n\nwireDBTier2 captured the default repo's *WatchedIndex at startup and wrote\nevery DB refresh into that captured pointer. The cache is a bounded LRU\nthat closes+discards an entry on eviction; nothing pinned the default repo.\nAfter one search for a different repo (cache size 1, or 16 di\n[…]\nict\nvia a second repo (size-1 cache) → rebuild, asserting the DB chunk is\nstill searchable. Plus the dbExtras store/load contract.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ken-mcp): Tier-2 DB chunks survive default-repo LRU eviction (aud…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:30:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "034fadd98e69002a47646c565359c33f802698d6",
          "body": "…lure (audit db/mcp §8)\n\nThe first structural-tool call builds the whole-corpus tree-sitter symbol\nindex — tens of seconds on a large polyglot repo (M0: a 44s build once\nexceeded an MCP client's tool-call timeout). Three problems, all fixed:\n\n(a) Cancellation. structural.Build took no context and ra\n[…]\nnceled; the\nlazy-structural cache test inverts to assert retry-then-cache (2 failed\nretries + 1 cached success = 3 builder calls).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): structural build honors ctx, heartbeats, and retries on fai…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:25:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1a3cd3922108a5ac272155cf6fa0a6baed04d6f1",
          "body": "…it db/mcp §3)\n\nSetupTier2 ran the initial IndexSchema synchronously before the server\nserves JSON-RPC, on a context with no deadline. A DSN pointing at an\nunreachable host (firewall dropping SYN, VPN down) blocked on TCP connect\nfor the OS default (~130s on Linux); the MCP client saw no `initialize\n[…]\nt SetupTier2\nreturns an error and the caller degrades to FS-only, matching the existing\n\"Tier 2 going dark is not fatal\" contract.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(db): bound startup introspection with KEN_DB_STARTUP_TIMEOUT (aud…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:12:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6be2ab92b5c6e0f1ef0e5ff9ca9ad3c5e1961113",
          "body": "… (audit §5)\n\nBuildIndex re-tokenized every chunk on every watch flush, single-threaded.\nADR-012's \"rebuild is dwarfed by embedding\" holds for a cold build but\ninverts on the incremental path: a one-file save embeds ~5 chunks while\ntokenization runs over all N — a multi-hundred-ms to multi-second st\n[…]\nnt loop/shutdown interaction, and\n§5 already removes the whole-corpus re-tokenize that was the dominant\nunder-lock cost §12 cited.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(search): incremental + parallel BM25 tokenization on watch flush…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T15:06:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f47a8505c1615c987907180f8439d9dce9a184db",
          "body": "… dumps (audit §5, §6)\n\n§5: commitChangedFiles used Commit.Stats() (and a parent.Patch fallback),\nboth of which materialize and textually diff every blob just to read the\nchanged NAMES — tens of seconds and hundreds of MB on a commit that bumps\na lockfile or vendored tree. Swap to object.DiffTreeWit\n[…]\nhonored + total reported + notice in\nboth output modes). recently_changed handler tests exercise the new\ntree-diff path unchanged.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): tree-diff recently_changed + honor ctx; cap outline/symbols…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T14:49:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9cbacf36834b5c06fd30c78927ff492ada11c6ad",
          "body": "…§14)\n\nfsnotify delivers ONE Create for a directory and no per-file events for\ncontents that already existed (a `mv pkg ./` or `mkdir && write` race),\nand Matcher.ShouldIndex is false for directories — so the file-oriented\nevent path skipped the whole subtree and a new package stayed invisible\nuntil\n[…]\n: moved-in dir (the pure\nenqueueDirFiles case, zero per-file events) and dir rename (old subtree\ntombstoned, new subtree indexed).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(watch): index new/moved-in dirs, re-path renamed dirs (audit §2, …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T14:44:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "17d09d2d362c1b3a592055ca7789b494109e8c3a",
          "body": "…, #4, #7)\n\nThe M5 \"no raw DSN in errors\" policy (internal/db/db.go: NEVER return\nusername/password/host) was applied to db.go + mysql.go but three siblings\nleaked it anyway.\n\n- #2 redactDSN (cmd/ken-mcp): the schemeless-MySQL branch cut on the FIRST\n  '@', but the driver splits on the LAST '@' befo\n[…]\nrest. Test asserts no\n  leak; ReindexResult.Err doc corrected.\n\ngolangci-lint clean; internal/db + mcp + cmd/ken-mcp suites green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(security): close three credential/topology leaks (audit db/mcp #2…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T14:38:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "60e1370469bd6c4778e6e56f21057b7fbd8f27e5",
          "body": "…data race (audit §1)\n\nBuildIndex stores the chunks slice header verbatim (index.go:667), so the\npublished *Index aliases w.chunks' backing array. tombstoneFile writes\nchunk[i].Tombstoned in place, and readers touch that field lock-free\n(tombstoneCount / ResolveChunk) — an unsynchronized read/write \n[…]\nn another while 4 reader goroutines loop Search/\nResolveChunk; clean under -race. Existing watch/compaction/reconcile tests green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(search): copy-on-write in reconcileCorpusLocked — kill the flush …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T07:58:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1bdf2788b92c2d8e61bb03a1717d8e3cd2ab0a72",
          "body": "CI golangci-lint (v2.11.4) flagged 14 issues in the M1–M4 additions:\n- errcheck: unchecked wix/c/wi.Close() in cmd/ken (--write-snapshot) and the\n  new embedcache / lazy-enrich / staged-embed tests → wrap in defer func(){ _ =\n  ... }() or `_ =`.\n- staticcheck SA4031: the embed-cache cleanup was wrap\n[…]\nache != nil so cleanup stays nil for a plain local repo.\n\nVerified locally with golangci-lint v2.11.4: 0 issues. Full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(lint): golangci-lint clean for the cold-start changes",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T02:53:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6456a7143603d018286d2092e0a5c18780d841ae",
          "body": "Release notes for the cold-start campaign (M1 default-on snapshots + reconcile;\nM2/M3/M4 opt-in serve-before-warm / embed cache; parse budget; --write-snapshot;\nlazy structural). Add a single consolidated results table (final binary, one\npass) to the campaign doc, and the honest M1-Pro / 4-core caveat.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: CHANGELOG [1.3.0] + consolidated cold-start results table",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T02:50:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2a1b82d23d30460aa738b06ee7b00cde2d47c4a7",
          "body": "…d (M4, opt-in)\n\nCold-start M4: on a true-cold hybrid build, publish a BM25 (lexical-only) index\nfor an INSTANT first query, then enrich + embed in the background and upgrade to\nhybrid. Staged defers BOTH the enrichment parse and the embed, so first-servable\nis the pure BM25 floor.\n\n- FSOptions.Stag\n[…]\nno-watch); the\nsemantic:warming wire field; M2 lazy tests still pass on the unified pass; full\nsuite + mcp DB-free contract green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ken-mcp): staged readiness — serve BM25 instantly, warm to hybri…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T02:38:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "86f5827393a7e7260d0b81a37689a63d9e65f10f",
          "body": "Persistent sha256(chunk text) → vector cache so a full rebuild re-embeds only\nnever-seen text. Model2Vec is deterministic, so this is the second line of\ndefense behind an M1 snapshot load (which skips embedding entirely) — it helps\nthe rebuilds M1 can't: heavy drift, a mode change (bm25→hybrid), or \n[…]\nut/get, model/dim scope invalidation,\nsize-bound eviction, encodeCached hit-skips-encode; full suite + mcp DB-free\ncontract green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(search): content-hash embedding cache (cold-start M3, opt-in)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T02:00:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e0f5288ab4f849bab0023184fd6f68942e47ec80",
          "body": "…t-in)\n\nCold-start M2: take the Arm B enrichment tree-sitter parse (M0: ~50% of cold\nindex time, and M0(a): ~2.7x slower post-gotreesitter-bump) off the\nfirst-servable path. The cold build serves a RAW BM25/dense index for a fast\nfirst query; a background pass then enriches and republishes the full-\n[…]\n byte for byte; watch=true serves raw then swaps in\nenriched; fresh-slice publish is race-clean (fixed an in-place-mutation race).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(search): lazy/async enrichment — parse off the cold path (M2, op…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T01:30:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4526017a89511b80a0e39b852ad2f9cbfcf10b86",
          "body": "Build a repo's index once and persist the M1 snapshot to\n<path>/.ken/snapshot.{bin,manifest}, so a later ken-mcp boot on the same repo\nloads it instead of rebuilding. Build-once takes precedence over --watch.\n\nShared-writer refactor (single source of truth): move the snapshot write path\ninto interna\n[…]\nests updated for the shared path helpers; full suite\ngreen.\n\nCompletes the M1 tidy-up (with the fuzz gate + PERF row). M1 is done.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ken): `ken index --write-snapshot` for CI prewarming (M1)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-26T01:12:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b710a315606c849e2b7a0dc955ebcae36f9008a5",
          "body": "The \"What you should feel\" cold-start column is the FIRST index of a repo. Add\na note that M1 snapshots (ADR-039) make an unchanged-repo restart a fraction of\nthat: measured yii2 (~12k chunks, M1 Pro, median-of-3) clean-load bm25 532ms vs\n1.72s (3.2x) / hybrid 575ms vs 2.40s (4.2x); edit-1-file reconcile 3.1x/3.3x.\nOnly the first index (or a config change) pays full cold build.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(perf): everyday-cold (ken-mcp restart) row for M1 snapshots",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T16:29:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "393b2568a5b44a54b87a940ef418d9b94e607a93",
          "body": "…, M1)\n\nThe M1 snapshot artifacts (<repo>/.ken/snapshot.{manifest,bin}) are parsed as\nuntrusted input on every boot — an operator or attacker can hand the loaders\nanything. Add Go native fuzz targets asserting crash-safety:\n\n- FuzzDecodeManifest: KMAN manifest reader must never panic; any manifest i\n[…]\n46k (KEN1) executions locally, zero crashers; the seed\ncorpora also run as a normal `go test`. No crashers saved to testdata/fuzz.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(search): fuzz the snapshot loaders (untrusted-input crash-safety…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T16:27:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dfe0722c27f859b333a8ae4f2f1a5ce90d0806e6",
          "body": "…(M1)\n\nThe drift-reconcile path seeded a watching index (publish #1: BM25 re-tokenize +\nann.Flat build) and then ReconcileFiles → flush (publish #2), throwing the first\nbuild away. Reconcile before the initial publish so drift costs exactly one\nbuild.\n\n- Extract reconcileCorpusLocked from flush (per\n[…]\nd included). ReconcileFiles + the fsnotify flush path are unchanged (still\nused for live edits) and re-verified. Full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(search): single-publish snapshot reconcile — one build, not two …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T16:21:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9c3ebeac52027943dbaba4968b38ec3a07e9122b",
          "body": "… (M1)\n\nThe snapshot load path built a full runtime *Index (BM25 re-tokenize +\nann.Flat) via LoadSerializedIndex just to hand its chunks/vecs to\nNewWatchedIndexFromSnapshot, which builds the index AGAIN. Extract a\ncorpus-only loader so the load pays exactly one build.\n\n- Refactor deserializeIndex → \n[…]\nentical\nchunks/vecs; identical ErrChunkerMismatch on config mismatch). Full suite +\nserialize/determinism tests green under -race.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(search): corpus-only snapshot loader — skip throwaway BuildIndex…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T16:14:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "322510d993bc5fbf0cc0be78d759e6712323de6e",
          "body": "…t 2)\n\nOn snapshot drift, ken-mcp now re-indexes ONLY the changed files instead of a\nfull rebuild, keeping every unchanged file's chunks + vectors from the\nsnapshot.\n\n- search.SnapshotManifest.Diff(current) → (changed, deleted): added/modified\n  files to re-index, removed files to drop.\n- search.Wat\n[…]\nus, also speeds the common clean-load) and a single-publish\nreconcile — deferred to keep the delicate serialize function unrushed.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ken-mcp): incremental reconcile-on-drift (cold-start M1 Incremen…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T16:03:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "992edc730359bd0e43582c1216cbd895cb250695",
          "body": "…1 Inc 1)\n\nThe M1 payoff (ADR-039): ken-mcp no longer rebuilds from scratch on every\nrestart. It persists the built index to <repo>/.ken/snapshot.{bin,manifest}\nand, on boot, loads it + drift-scans instead of rebuilding when the repo is\nunchanged — the everyday-cold fast path.\n\nWiring (cmd/ken-mcp/s\n[…]\n in README (env table) + CLAUDE.md.\nFull suite green; stdout-cleanliness contract re-verified (writeSnapshot logs\nto stderr only).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ken-mcp): wire index snapshot persistence + reconcile-on-boot (M…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T15:04:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a6098f3f367557c49a41e031fe89a02a7d6e8699",
          "body": "…file)\n\nTask 4: a DRAFT upstream note for odvcencio/gotreesitter, for manual review +\nfiling. Framed as a real-world ratchet data point from a downstream consumer,\nNOT a regression complaint.\n\nIncludes: ken's use case (index-time enrichment parse of PHP corpora, on the\ncold-start critical path); the\n[…]\nntribute recurring real-corpus\ntimings. Marked draft/not-filed at the top with a note to strip ken-internal\nframing before filing.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): draft gotreesitter PHP throughput data point (do not …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T14:23:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dce673de6707515673efaeebd635433d8f408792",
          "body": "Task 3 verification + hardening. Confirmed the new tests pin SHAPE, not timing:\nthe full suite passed 3x (0 failures) and the determinism test passed under\n-race 3x; the new tests show zero timing variance across 3 runs\n(PhpTruncatedController 0.01s, ParseBudget_Exhaustion 0.02s,\nParseBudget_Disable\n[…]\nst's 1µs override could in principle leak a cached pool and turn the\nerror-recovery-shape assertions into a timing-dependent skip.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(structural): pin malformed-PHP fixture to shape, budget-independent",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T14:22:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "00f8997ff6eba421bcc957094990eb92cf7012c4",
          "body": "…UDGET_MS)\n\nTask 2 of the cold-start campaign. A per-file wall-clock cap on the Arm B\nenrichment / structural tree-sitter parse: on exhaustion the file is skipped\n(indexed without its structural label — results unaffected, just unenriched),\ncounted, and logged; the build never fails. Rationale: gotr\n[…]\nps; env parse (ms→µs,\nempty/invalid→0). Documented alongside KEN_MAX_FILE_BYTES (README env table +\nCLAUDE.md enrichment section).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(structural): per-file enrichment parse budget (KEN_ENRICH_FILE_B…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T14:17:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8f2bd12014cda3120b7abcfdef59df323d731151",
          "body": "…ld path)\n\nM0(a) reframed the campaign: the enrichment tree-sitter parse is ~50% of cold\nindex time AND ~2.7x slower post-bump, so the lever is taking it OFF the cold\npath, not speeding it up. Add M2 (lazy/async enrichment), renumber the rest\n(embed cache M2→M3, staged readiness M3→M4, mmap M4→M5).\n\n[…]\nslow now — 0.47.0 C-faithful —\nso the open question is the share, not the cause); require M1 + M2 both before\nan external rebench.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): promote lazy/async enrichment to M2 (parse off the co…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T09:28:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d37eb96ae806c7846beacb5003dde67e7de4d10b",
          "body": "…rse ~2.7x\n\nTask 3: timed `ken perf index --mode bm25` on a yii2 corpus (1,184 .php /\n12,349 chunks), median of 5, temp binaries at each ref (GOWORK=off, own pins),\nM1 Pro / 16 GB, 2026-07-25. KEN_ENRICH=off is the control (removes the\ntree-sitter parse).\n\n  enrich on : v1.1.1 (0.20.5) 1598ms  vs  H\n[…]\n\" to a real target: get 0.47.0 correctness without\nits ~2.7x well-formed-PHP parse cost. M1 must land before the external rebench.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): M0(a) measured — gotreesitter 0.47.0 REGRESSED PHP pa…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T08:25:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "90bb2ebfcb68c4612598ad3efa122f01d3443bc2",
          "body": "…e shape\n\nTask 2 of the cold-start campaign: audit PHP/tree-sitter goldens after the\ngotreesitter 0.20.5 → 0.47.0 bump (PR #62, 2026-07-24).\n\nAudit result: the full test suite is GREEN at 0.47.0 — no golden diffs to\nverify or regenerate. But every structural extractor test used deliberately\nwell-for\n[…]\nrects the reader to verify against the changelog (C-oracle\nshapes) BEFORE re-baselining, per the campaign doc's golden-drift risk.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(structural): malformed-PHP fixture guards gotreesitter error-tre…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T08:21:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fb4ef30cdab867a97ef22b10f83aa9de1bf2e16b",
          "body": "ADR-039 was appended with its section but not its index-table row; the\nbuildchecks TestADRIndexMatchesSections guard flags the drift. Add the row.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): add ADR-039 index-table row (fixes docdrift check)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T08:21:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c930b7333e700e01d21169eac407ae4e18b4e816",
          "body": "…uspect\n\nRework the campaign doc's problem statement to the three structural facts,\nadding the one that reframes the whole investigation:\n\n3. The 256.6s bench ran ken v1.1.x (gotreesitter 0.20.5). The 0.20.x line\n   silently disabled the hand-written repeat-boundary conflict resolvers for\n   PHP (pe\n[…]\n-drift risk (error-tree shapes changed in\n0.21.0) that Task 2 audits, and reflects the M1 snapshot infra already landed\n(ADR-039).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): cold-start campaign — 3-fact framing + gotreesitter s…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T08:16:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ab7f3f5cf8a8ae10229be1f467d3bed355951711",
          "body": "Follow-up to 8f6e7da, tightening the M1 infra before the ken-mcp wiring:\n\n- SnapshotConfigKey drops the size-cap params (KEN_MAX_FILE_BYTES /\n  KEN_MAX_AVG_LINE_BYTES). Those — like ignore rules — change the file\n  SET, so any change is already caught by the manifest drift check\n  (FilesEqual); keyi\n[…]\ng, shared by both write and load paths. EmbedModel() lets that\n  wiring compute the model fingerprint without reloading the model.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(search): simplify snapshot config-key; add EmbedModel accessor",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T08:14:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8f6e7daa54d01ab42d429c3191d8cb2c60e3bae0",
          "body": "…infra)\n\nCold-start M1 (ADR-039) foundation, in internal/search only — additive,\nno runtime behavior change yet (ken-mcp wiring is the next commit).\n\n- snapshot.go: the drift/invalidation sidecar the KEN1 format omits.\n  SnapshotConfigKey (mode/chunker/model-fingerprint/enrich/size-caps —\n  ignore-r\n[…]\namps stat+sort,\nand a snapshot-seeded index that is searchable + closable.\n\nRefs docs/internal/cold-start-campaign.md M1, ADR-039.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(search): snapshot manifest + snapshot-seeded watching index (M1 …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T04:44:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ce1581ffd077d4cb1ddde9904367176fb413f3ca",
          "body": "…k win)\n\nken-mcp built structural.Build eagerly at startup (main.go:411) — a full\nper-file tree-sitter parse of the corpus for the definition/references/\ncallers/outline/symbols tools. Cold-start M0 profiling showed that parse\nis ~50% of index time on PHP (on top of the enrichment pass that already\n\n[…]\n, nil-builder and\nfailed-build both degrade to nil without retry. Full suite green.\n\nRefs docs/internal/cold-start-M0-findings.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(ken-mcp): lazy structural symbol-index build (cold-start M0 quic…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T04:29:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bddb8d3d4d6e6856bf479a4552ca7a25580572ca",
          "body": "Land the cold-start campaign task doc (M0-M4: profile first, snapshot\npersistence, embed cache, staged readiness, mmap stretch) and complete\nM0 — profiling the ken-mcp cold-start build path on a yii2 PHP proxy\n(2,783 files / 12,349 chunks, M1 Pro).\n\nM0 findings (docs/internal/cold-start-M0-findings.\n[…]\nash, not just embeddings. M3 -> GO (476 ms BM25 floor). New candidate:\nupstream the PHP GLR-retry cost to gotreesitter (cf. #110).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(internal): cold-start campaign task doc + M0 build-path profiling",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T04:19:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "33e6ce296bf6ca9315395c6cef458075be70927f",
          "body": "…arness\n\nReplace the extrapolated Linux-kernel row in PERF-expectations.md with a\nreal full-tree measurement (linux v6.10, M1 Pro / 16 GB, go1.26.5, aikit\nv1.11.0, regex chunker):\n\n  bm25   826k chunks  index 471.9s  search p50 5.84ms  peak RSS 6.14 GB\n  hybrid 826k chunks  index 501.9s  search p50 \n[…]\ns/internal/kernel-run-plan.md (run plan) + kernel-demo-feasibility.md.\n- .gitignore: kernel_bench_out/ (regenerated bench output).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(perf): measured whole-kernel numbers (was extrapolated) + demo h…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-25T03:21:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b416e5b0a163be12a8d56bd88954dd3e790bd100",
          "body": "…ub.com/odvcencio/gotreesitter-0.47.0\n\nchore(deps): Bump github.com/odvcencio/gotreesitter from 0.20.5 to 0.47.0",
          "is_bot": false,
          "headline": "Merge pull request #62 from townsendmerino/dependabot/go_modules/gith…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T23:15:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a4180681d95b06c82ca52293b9d20776e9836557",
          "body": "Bumps [github.com/odvcencio/gotreesitter](https://github.com/odvcencio/gotreesitter) from 0.20.5 to 0.47.0.\n- [Release notes](https://github.com/odvcencio/gotreesitter/releases)\n- [Changelog](https://github.com/odvcencio/gotreesitter/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/odvcencio/g\n[…]\n github.com/odvcencio/gotreesitter\n  dependency-version: 0.47.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump github.com/odvcencio/gotreesitter",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-24T23:11:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ea75606fa4a461d4e17993d92eb779825a1dff25",
          "body": "…rnc.org/sqlite-1.54.0\n\nchore(deps): Bump modernc.org/sqlite from 1.53.0 to 1.54.0",
          "is_bot": false,
          "headline": "Merge pull request #59 from townsendmerino/dependabot/go_modules/mode…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T14:12:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "66bf3d54b7bf4ef55f022a8bb0a3f012e694ac7d",
          "body": "…actions/setup-go-7\n\nchore(deps): Bump actions/setup-go from 6 to 7",
          "is_bot": false,
          "headline": "Merge pull request #58 from townsendmerino/dependabot/github_actions/…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T14:11:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e57fb221f29b5a3f9833948eda918ef714b8ad73",
          "body": "Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.53.0 to 1.54.0.\n- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)\n- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.53.0...v1.54.0)\n\n---\nupdated-dependencies:\n- dependency-name: modernc.org/sqlite\n  dependency-version: 1.54.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump modernc.org/sqlite from 1.53.0 to 1.54.0",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-24T14:08:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "56b77a859e04e4ba211fc86b68227b9215c022ff",
          "body": "…ub.com/townsendmerino/aikit-1.11.0\n\nchore(deps): Bump github.com/townsendmerino/aikit from 1.9.0 to 1.11.0",
          "is_bot": false,
          "headline": "Merge pull request #63 from townsendmerino/dependabot/go_modules/gith…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T14:06:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "020ce4c76b51daedb8fccfdd51ff2000314c8a34",
          "body": "Bumps [github.com/townsendmerino/aikit](https://github.com/townsendmerino/aikit) from 1.9.0 to 1.11.0.\n- [Release notes](https://github.com/townsendmerino/aikit/releases)\n- [Changelog](https://github.com/townsendmerino/aikit/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/townsendmerino/aikit\n[…]\ne: github.com/townsendmerino/aikit\n  dependency-version: 1.11.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump github.com/townsendmerino/aikit from 1.9.0 to 1.11.0",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-24T13:59:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "81be60cba54ecc76d06f4d97d39d3fee58503d01",
          "body": "govulncheck flagged GO-2026-5970 (infinite loop on invalid input in x/text)\nas REACHABLE — via the Postgres connect path (pgx → norm) and the embedder's\nUnicode normalization. The advisory landed in the vuln DB after v1.2.0 was\ntagged, so v1.2.0's govulncheck CI went red post-release and its binarie\n[…]\nd in x/text v0.39.0; cut as v1.2.1.\n\nGOWORK=off build + full suite + govulncheck all green (0 affecting vulns).\nNo source changes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "security: bump golang.org/x/text v0.37.0 → v0.39.0 (GO-2026-5970)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T13:56:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "967e5c1e06238cc0741decac569c4e5d6c031fd6",
          "body": "… hardening\n\nFolds the full code review (C1/C2 process-kills, M1–M7 majors, minors/nits,\nfollow-ups #1–#4) and the Task B shutdown work into the release alongside the\nmemory campaign (.kenignore ADR-038, GC hygiene, size cap). Minor bump: new\nfeatures + env vars (KEN_MAX_FILES, KEN_MCP_SHUTDOWN_GRACE) + a new public API\n(NewWatchedIndexWithContext), no breaking changes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(changelog): cut [1.2.0] — memory campaign + security/correctness…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T13:44:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "381777985a2655f8de989a6423f47fdba4eff944",
          "body": "…eview Task B)\n\nTask B correction: in-flight tool calls DO already drain on shutdown — the\nSDK's jsonrpc2 layer blocks srv.Run until the connection is idle, and\ncleanup() already runs synchronously after Run (the M1 fix). The earlier\n'no in-flight-request draining' note was wrong. The real residual \n[…]\n vet ./..., go test ./mcp/... ./internal/search/...\n./cmd/ken-mcp/... all green (incl goleak + the -race-safe cancellation tests).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ken-mcp): bounded shutdown grace + ctx-cancellable index build (r…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T05:04:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "34a36dcff9ae4fd879c28986395979f7e0bf283d",
          "body": "resolve/main is a mutable, unpinned ref with no checksum, and the package\nhad no download-time verification — a truncated or swapped file surfaced\nonly as a cryptic safetensors error later, and the rerank checkpoint\n(CodeRankEmbed) has no downstream parity test to catch a silently-corrupt\nmodel at a\n[…]\n existing suite green (they set Content-Length,\nexercising the byte-count gate).\n\ngofmt/vet/golangci-lint clean; full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(modelfetch): download-time integrity verification (code review #1)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T04:23:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "87f246c803f47c89b76d44f3eda0a83d089240fb",
          "body": "Handlers advertise output:'json' but many early returns emitted plain\ntextResult() regardless of mode (Structural==nil, 'symbol is required',\n'No repo specified', the index-failure paths, recently_changed's git\nerrors), while sibling paths like 'No definition found' went through\ndispatchOutput — so \n[…]\nas-is (status/action tool, no Output arg).\nTest: TestServer_ErrorPathHonorsJSON.\n\ngofmt/vet/golangci-lint clean; full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): honor output:json on error/edge responses (code review §4)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T04:18:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9a6d07fd3470bf5da23d6ad5568d720acad757c0",
          "body": "…n/field (code review §4/§5)\n\n- repo: looksMinified sniff window 8 KiB → 32 KiB so a bundle that leads\n  with a short-lined license banner then a single multi-MB line is still\n  caught (a giant line starting past 32 KiB still evades, bounded by the\n  size cap).\n- db/listen: on a missing NOTIFY trigg\n[…]\n  read (+ the now-dead colNames construction in the pg sample path).\n\ngofmt/vet/golangci-lint clean; db + repo + mcp suites green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "cleanup: minified sniff window, listener trigger re-check, dead retur…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T04:09:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e2616ca57be3c05b41029f663eb4bb54bdbbfd0a",
          "body": "… repos before OOM (code review §5)\n\nWalkFS collected an unbounded file slice and Build holds every FileStruct\nlive, so a repo of millions of tiny files was an OOM vector bounded only by\nGC thrash (the per-file size cap + minified skip bound individual files, not\nthe aggregate). WalkFS now errors wi\n[…]\n(a truncated index reads as complete). Hardened ken-mcp deployments\nlower it for untrusted remote clones. Test + README/CLAUDE.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(repo): file-count admission cap (KEN_MAX_FILES) — reject hostile…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T04:02:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "06ca02ce8bbd8d7e5f65570b36b1cc34b569df9a",
          "body": "- internal/search/rerank.go: maxScore's local 'max' → 'hi' (shadowed the\n  max builtin in a file that otherwise uses it).\n- internal/db/emit.go + internal/sql/migrations.go: local 'close' →\n  'closeIdx' (shadowed the close builtin; holds a closing-paren index).\n- mcp/structural_tools.go: didOrDoes →\n[…]\net — built but\n  never read (dedup is done via fn.IsMethod).\n\nBehavior unchanged; gofmt/vet/golangci-lint clean; full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "cleanup: builtin-shadow renames + dead code (code review §5)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:55:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8f9dccfe2eb7212033ee5f8ed1175e8a0a8da683",
          "body": "- search: ModeHybrid now over-fetches by k+tombstoneCount like the\n  semantic/bm25 branches. hybridSearch doesn't filter Tombstoned and the\n  out-loop trims to k after dropping them, so a tombstoned top-k hit could\n  leave the result short. Latent while compaction precedes publish, but the\n  branch \n[…]\nleStruct.Calls field and no longer compiled → CalleeNames().\n\ngofmt(cmd/internal/mcp/bench)/vet/golangci-lint clean; suites green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: minor correctness/determinism/robustness batch (code review §4)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:52:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f39cd9c816ccfbce34053186b42b3800df875ba1",
          "body": "….Config (M5)\n\nCode review §7 #4 — the credential-redaction contract had a hole on the\nerror path.\n\nMySQL: mysqlURLToNative returned url.Parse's error unmodified, and\n*url.Error.Error() embeds the whole input — so a bad port or stray % in\nthe password (mysql://alice:hunter2@db.local:notaport/mydb) s\n[…]\nidated DSN + pgconn redacts passwords in\nconnect-time errors, so it's left as-is.)\n\ngofmt/vet/golangci-lint clean; db suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(db): never leak DB password on DSN parse error + structured mysql…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:47:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d46d6a007011ebf06976ba1597528728667d6027",
          "body": "…ce (M4), symlink escape (M6)\n\nCode review §7 order-of-attack #3: three cases where a parallel path\nviolated an invariant its primary path holds. Each fixed by aligning the\npaths, not patching one side.\n\nM3 — appendFile (incremental watch re-index) chunked+embedded RAW text,\ndropping the Arm B func:\n[…]\n Switch to os.Lstat. Test:\nTestMatcher_SymlinkNotIndexed.\n\ngofmt/vet/golangci-lint clean; search + repo suites (incl -race) green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: close sibling-path drift — watch enrichment (M3), SetReranker ra…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:41:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cf987c26ed5f9a1d7e156aeadfca45dc7e9d6952",
          "body": "… lock (M2)\n\nCode review §7 order-of-attack #2 — server-lifetime correctness.\n\nM1: shutdown cleanup (drop temp clone dirs, persist the M9 warm-start\nrerank cache, dbCleanup) was gated on <-ctx.Done(), which fires only on\nSIGINT/SIGTERM. The common stdio shutdown — client closes stdin, srv.Run\nreturn\n[…]\nurge() and Close() via a shared detachAll + reapEntry.\n\ngofmt/vet/golangci-lint clean; mcp suite (incl -race + godoc audit) green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ken-mcp): synchronous shutdown cleanup (M1) + evict outside cache…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:27:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "05430c301c39215455363975cbc79b389901c19e",
          "body": "…o process-kills\n\nFrom the 2026-07-24 code review, §7 order-of-attack #1: both are\nuntrusted/client-triggerable kills of the long-lived server.\n\nC1 — unbounded top_k: the search + find_related MCP handlers only floored\ntop_k, never capped it, so a client (or prompt-injected agent) passing\ntop_k: 500\n[…]\nthrough — they can't drift again. Test:\nTestBuild_OversizedSkipped.\n\ngofmt/vet/golangci-lint clean; mcp + structural suites green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: clamp top_k (C1) + guard structural.Build parse (C2/M7) — the tw…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-24T03:20:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eaacaedc097de7a3b64c1a71625d37fd8238ff81",
          "body": "…campaign M5)\n\nThe memory section gave small-repo structural.Index figures but hand-waved\nfull-process RSS ('gotreesitter arenas dominate') and said nothing about\nlarge/artifact-heavy repos. Adds a non-defensive note: RSS scales with\nindexed corpus size and can reach multiple GB on artifact-heavy mo\n[…]\n=50,\nKEN_MEMLIMIT, FreeOSMemory) and a pointer to scripts/rss_bench.sh. Fixes the\n'the claim didn't hold on his host' honesty gap.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(perf): honest full-process RSS guidance + memory levers (memory …",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-20T04:49:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9c3a512908b71ed0742ddaa2a991dd768000ed8a",
          "body": "…n M3)\n\nReduces build-path memory + index bloat on artifact-heavy repos (the Denis\nbench corpus was ~2x the ignore-parity tools' file count):\n\n- KEN_MAX_FILE_BYTES makes the per-file size cap (was a hard-coded 2 MiB)\n  tunable (byte count or 512KiB/1MiB suffix).\n- Minified/generated-file skip: files\n[…]\nrnal/bytesize table test. Docs: README env table + the\n.kenignore section + CLAUDE.md. gofmt/vet/golangci-lint clean; suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(repo): env-tunable size cap + minified-file skip (memory campaig…",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-20T04:48:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eeb9df59b022eca62d5363b5c0619e417e88f52a",
          "body": "ken-mcp holds a full in-RAM index but idles between queries, so under the\ndefault GOGC=100 its steady-state RSS sits at ~2x live heap and rarely\nreturns pages to the OS — a root cause in Denis Trofimov's memory bench.\n\nAdds three server-only GC controls (cmd/ken-mcp/gc.go):\n- GOGC=50 default (unless\n[…]\nr numbers are comparable (A/B via GOGC).\nDocs: README core env table + CLAUDE.md. gofmt/vet/golangci-lint clean;\nfull suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ken-mcp): GC hygiene for the long-lived server (memory campaign M2)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-20T04:36:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "75df9457b6dab52f3cdfe03c456d7e9a8aa77956",
          "body": "Denis Trofimov's memory bench found ken idling at ~2.1 GB on a PHP/Yii\nmonorepo vs sub-GB for ignore-parity tools — root cause: ken was\ngitignore-only, so it indexed ~3.6k committed-but-unwanted files (built\nassets, generated migrations) the other tools excluded via their own\nignore files, nearly do\n[…]\nthe memory campaign; M2 (GC hygiene) is the other half of the\nsub-GB-idle target. gofmt/vet/golangci-lint clean; full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(repo): .kenignore / .sembleignore ignore-file parity (ADR-038)",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-20T04:24:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6dc1322f2d5c6b4345b89b835a0ddf02f8a54dd1",
          "body": "Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7.\n- [Release notes](https://github.com/actions/setup-go/releases)\n- [Commits](https://github.com/actions/setup-go/compare/v6...v7)\n\n---\nupdated-dependencies:\n- dependency-name: actions/setup-go\n  dependency-version: '7'\n  dependency-type: direct:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>",
          "is_bot": true,
          "headline": "chore(deps): Bump actions/setup-go from 6 to 7",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-16T20:53:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc1dfa18c8fbe47781c9fe41b7534328548564d7",
          "body": "Applied the go1.26 fixers (semantics-preserving):\n- strings.Split → strings.SplitSeq (buildchecks/docdrift_test.go)\n- wg.Add(1)+go+defer wg.Done() → wg.Go() (search/rerank_race_test.go)\n- for i:=0;i<n;i++ → for i := range n (structural/extract_csharp.go, 5 sites)\n\nNo behavior change. gofmt/vet/golangci-lint clean; full suite + the changed\n-race test green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: go fix ./... — Go 1.26 modernizers",
          "author_name": "Francis Townsend-Merino",
          "author_login": "townsendmerino",
          "committed_at": "2026-07-16T15:07:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        }
      ],
      "releases_count": 29,
      "commits_last_year": 405,
      "latest_release_at": "2026-07-27T03:06:43Z",
      "latest_release_tag": "v1.3.1",
      "releases_from_tags": false,
      "days_since_last_push": 3,
      "active_weeks_last_year": 9,
      "days_since_latest_release": 7,
      "mean_days_between_releases": 5.6
    },
    "artifacts": {
      "collected": true,
      "structure": [
        "tree.go_main",
        "tree.goreleaser"
      ],
      "declarations": []
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "readme_badges": {
        "hosts": [
          "github.com",
          "pkg.go.dev",
          "shields.io"
        ],
        "total": 4,
        "header": 4,
        "collected": true,
        "has_inspect_badge": false
      },
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 71,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/townsendmerino/ken",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "categories": [],
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/townsendmerino/ken",
          "declared_type": null,
          "is_deprecated": false,
          "latest_version": "v1.3.1",
          "repository_url": "https://github.com/townsendmerino/ken",
          "versions_count": 27,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-27T00:13:24Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 7
        }
      ]
    },
    "popularity": {
      "forks": 1,
      "stars": 27,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2026-06-09",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 1,
        "total_forks": 1
      },
      "star_history": null,
      "open_issues_and_prs": 4
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "demos"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 67873,
      "source_files_sampled": 266,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 19199
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go"
      ],
      "dependencies": [
        {
          "name": "github.com/fsnotify/fsnotify",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.1"
        },
        {
          "name": "github.com/go-git/go-git/v5",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v5.19.1"
        },
        {
          "name": "github.com/go-sql-driver/mysql",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.0"
        },
        {
          "name": "github.com/jackc/pgx/v5",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v5.10.0"
        },
        {
          "name": "github.com/modelcontextprotocol/go-sdk",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.7.0"
        },
        {
          "name": "github.com/odvcencio/gotreesitter",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.47.0"
        },
        {
          "name": "github.com/pkoukk/tiktoken-go",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.8"
        },
        {
          "name": "github.com/townsendmerino/aikit",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.13.0"
        },
        {
          "name": "go.uber.org/goleak",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.3.0"
        },
        {
          "name": "golang.org/x/sync",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.22.0"
        },
        {
          "name": "modernc.org/sqlite",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.55.0"
        },
        {
          "name": "github.com/townsendmerino/aikit/chunk/treesitter",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.0"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 43,
        "open_issues": 4,
        "closed_ratio": 0.733,
        "closed_issues": 11,
        "closed_unmerged_prs": 4
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "townsendmerino",
          "commits": 384,
          "avatar_url": "https://avatars.githubusercontent.com/u/620372?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "govulncheck.yml",
        "release.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        ".golangci.yml"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "2 out of 2 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/26 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 10,
            "reason": "project is fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 10,
            "reason": "security policy file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 2,
            "reason": "8 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "cd782750485cf0bb872bc6c56f946a1e289f1076",
        "ran_at": "2026-08-03T04:44:41Z",
        "aggregate_score": 4.4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": true,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "recent_prs": {
        "merged_7d": 0,
        "decided_7d": 0,
        "merged_30d": 0,
        "authors_30d": 0,
        "decided_30d": 0,
        "sample_size": 47,
        "window_days": 30,
        "sample_exhausted": false,
        "authors_probed_30d": 0,
        "newcomer_merged_30d": 0,
        "bot_prs_excluded_30d": 10,
        "newcomer_authors_30d": 0,
        "newcomer_decided_30d": 0
      },
      "ci_last_run_at": "2026-07-30T21:28:15Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-30T21:25:15Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 15,
          "created_at": "2026-05-25T23:09:09Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 35,
          "created_at": "2026-05-28T13:25:22Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 37,
          "created_at": "2026-05-28T15:12:30Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 61,
          "created_at": "2026-07-18T18:10:51Z",
          "last_comment_at": "2026-07-27T03:09:38Z",
          "last_comment_author": "townsendmerino"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/townsendmerino/ken",
    "host": "github.com",
    "name": "ken",
    "owner": "townsendmerino"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": "The weighted overall 61 is calibrated to 67 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 61,
            "calibrated": 67,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 67,
      "inputs": {
        "security": 44,
        "vitality": 72,
        "community": 45,
        "governance": 50,
        "calibration": "2026-08-02",
        "engineering": 84,
        "ai_readiness": 86,
        "weighted_overall_raw": 61
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 72,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 405,
              "human_commit_share": 0.94,
              "days_since_last_push": 3,
              "active_weeks_last_year": 9
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 3 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 3
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "9/52 weeks with commits",
                "points": 6.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "405 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 405
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 29,
              "latest_release_tag": "v1.3.1",
              "releases_from_tags": false,
              "days_since_latest_release": 7,
              "mean_days_between_releases": 5.6
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "29 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 29
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 7 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~5.6 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 5.6
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "exceptional",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "weak",
        "name": "Community & Adoption",
        "value": 45,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 23,
            "inputs": {
              "forks": 1,
              "stars": 27,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "27 stars",
                "points": 23,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 27
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "1 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 70,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "readme_badges": 4,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [
                "github.com",
                "pkg.go.dev",
                "shields.io"
              ],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 50,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 67,
            "inputs": {
              "merged_prs": 43,
              "open_issues": 4,
              "closed_issues": 11,
              "prs_merged_7d": 0,
              "prs_decided_7d": 0,
              "prs_merged_30d": 0,
              "prs_decided_30d": 0,
              "issue_closed_ratio": 0.733,
              "closed_unmerged_prs": 4,
              "first_time_authors_30d": 0,
              "first_time_prs_merged_30d": 0,
              "first_time_prs_decided_30d": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "73% of issues closed",
                "points": 30.8,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 73
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "43/47 decided PRs merged",
                "points": 27.4,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 43,
                      "decided": 47
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/26 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "weak",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 42,
            "inputs": {
              "followers": 4,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "townsendmerino",
              "public_repos": 8,
              "account_age_days": 5647
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "4 followers of townsendmerino",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 4,
                      "login": "townsendmerino"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "8 public repos, account ~15 yr old",
                "points": 18.9,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 8
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 15
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/townsendmerino/ken"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 7
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 7 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "27 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 27
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "excellent",
        "name": "Engineering Quality",
        "value": 84,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 84,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": ".golangci.yml",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "2 out of 2 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "topics": [
                "agents",
                "bm25",
                "code-search",
                "embeddings",
                "go",
                "golang",
                "mcp",
                "mcp-server",
                "model2vec",
                "retrieval",
                "semble"
              ],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "11 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "weak",
        "name": "Security",
        "value": 44,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "weak",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 44,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 4.4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "2 out of 2 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/26 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is fuzzed",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "8 existing vulnerabilities detected",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "excellent",
        "name": "AI Readiness",
        "value": 86,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 19199
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "94 of 94 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 94,
                      "sampled": 94
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "excellent",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0.88,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0.06
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": ".golangci.yml",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "88 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 88,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "6 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 6,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "exceptional",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 67873,
              "source_files_sampled": 266,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/266 source files over 60KB",
                "points": 54.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 266,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "moderate",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "example_dirs": [
                "demos"
              ],
              "has_mcp_signal": true,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "demos",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "demos"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "top": [
        "application"
      ],
      "labels": [
        "mcp-server"
      ],
      "scores": {
        "library": 3,
        "mcp-server": 5,
        "application": 9
      },
      "primary": "mcp-server",
      "evidence": [
        {
          "tier": "structure",
          "label": "application",
          "source": "tree.go_main",
          "weight": 5
        },
        {
          "tier": "structure",
          "label": "application",
          "source": "tree.goreleaser",
          "weight": 4
        },
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:go",
          "weight": 3
        },
        {
          "tier": "structure",
          "label": "mcp-server",
          "source": "mcp_signal",
          "weight": 3
        },
        {
          "tier": "tags",
          "label": "mcp-server",
          "source": "tag:mcp-server",
          "weight": 2
        }
      ],
      "artifacts": [],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": true,
      "consumed_by_code": false
    },
    "metrics_version": "2.5.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-08-03T04:44:48.569338Z",
  "schema_version": "0.30.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/t/townsendmerino/ken.svg",
  "full_name": "townsendmerino/ken",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v2.5.0, схема v0.30.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаGo.