Registro público
Informe de salud del softwareesquema 0.30.0 · métricas 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 estrellas⑂ 1 forkdesde may 2026Ver en GitHub ↗
TipoServidor MCPcómo se determina

townsendmerino/ken tiene un índice de salud de 67 sobre 100, lo que lo sitúa en la banda Bueno. Su puntuación más alta es AI Readiness (86/100) y la más baja, Security (44/100). Se actualizó por última vez hace 3 días. Una sola persona concentra la mayor parte del trabajo reciente.

67
global / 100
Bueno

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala estandarizada de 1 a 100. El resultado global parte de su media ponderada, calibrada contra la distribución del registro público para que las bandas tengan significado percentil; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe un límite «En riesgo» de 34.

67
Excepcional93-100El nivel más alto del registro (≈ el 5% superior); cumple prácticamente todos los criterios evaluados
Excelente80-92Sólido en todos los frentes; carencias menores
Bueno65-79Saludable; carencias limitadas y manejables
Moderado50-64Aceptable con carencias notables; se recomienda revisión
Débil35-49Debilidades sustanciales en varias áreas
En riesgo20-34Debilidades significativas; su adopción exige cautela
Crítico1-19Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

El resultado global ponderado 61 se calibra a 67 en la escala publicada del índice (calibración del registro 2026-08-02).

Titularidad

4 seguidores8 repositorios públicosdesde feb 2011

Este repositorio pertenece a una cuenta personal. Un proyecto con un único propietario conlleva más riesgo de continuidad que uno respaldado por una organización.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicación
Gogithub.com/townsendmerino/kenv1.3.1-27hace 7 días

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

72Bueno · 21% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 3 días
6.2/36Cadencia de commits — 9/52 semanas con commits
18/18Volumen de commits — 405 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year405
human_commit_share0,94
days_since_last_push3
active_weeks_last_year9
Cómo se puntúa
27/27Publica versiones — 29 versiones publicadas
36/36Recencia de las versiones — última versión hace 7 días
27/27Cadencia de publicación — una versión cada ~5,6 días
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Datos de entrada utilizados
releases_count29
latest_release_tagv1.3.1
releases_from_tagsno
days_since_latest_release7
mean_days_between_releases5,6

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

45Débil · 17% del índice global
Cómo se puntúa
23/60Estrellas — 27 estrellas
0/25Forks — 1 forks
0/15Observadores — 1 observadores
Datos de entrada utilizados
forks1
stars27
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
18/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
readme_badges4
has_contributing
has_issue_templateno
has_code_of_conductno
readme_badge_servicesgithub.com, pkg.go.dev, shields.io
has_pull_request_templateno

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

50Moderado · 23% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
30.8/42Resolución de issues — 73% de issues cerradas
27.4/30Aceptación de PR — 43/47 PR decididos fusionados
0/13Newcomer PR acceptance — ningún PR de un contribuyente primerizo decidido en 30 d
0/15OpenSSF Scorecard: Code-Review — Found 0/26 approved changesets -- score normalized to 0
Datos de entrada utilizados
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
Excluidos de la puntuación (sin datos o no aplicable): newcomer_pr_acceptance. Los pesos restantes se han renormalizado.
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
5/25Alcance del propietario — 4 seguidores de townsendmerino
18.9/25Trayectoria — 8 repos públicos, cuenta de ~15 años
Datos de entrada utilizados
followers4
owner_typeUser
is_verified
owner_logintownsendmerino
public_repos8
account_age_days5647
Excluidos de la puntuación (sin datos o no aplicable): Dominio verificado. Los pesos restantes se han renormalizado.
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en go
35/35Recencia de publicación — última publicación hace 7 días
20/20Historial de versiones — 27 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesgithub.com/townsendmerino/ken
ecosystemsgo
any_deprecatedno
min_days_since_publish7

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

84Excelente · 19% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 3 flujo(s) de trabajo
24/24Pruebas presentes
16/16Configuración de linter — .golangci.yml
0/9.6Hooks de pre-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
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_config
has_precommit_configno

Documentación

85Excelente
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
10/10Topics — 11 topics
10/10Wiki
Datos de entrada utilizados
topicsagents, bm25, code-search, embeddings, go, golang, mcp, mcp-server, model2vec, retrieval, semble
has_wiki
homepage
has_readme
has_docs_dir
has_description

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

44Débil · 16% del índice global
Cómo se puntúa
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.5Licencia — 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
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4,4

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Tiene un peso deliberadamente pequeño (4%): las herramientas para agentes son una señal real de mantenimiento, pero un repositorio sin ninguna puede alcanzar igualmente 100/100.

86Excelente · 4% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 94 de 94 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes19.199
Cómo se puntúa
18/18Arranque con un solo comando — Makefile
22/22Pruebas automatizadas
11/11Configuración de lint / formato — .golangci.yml
11/11Verificación estática de tipos — Go (tipado estático)
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 88 de los últimos 100 commits con autoría o crédito de agente
8/8Mantenimiento automatizado — 6 de los últimos 100 commits son actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfilesgo.sum
has_dockerfileno
typed_language
bootstrap_filesMakefile
has_devcontainerno
has_linter_config
typecheck_configs
agent_commit_share0,88
toolchain_manifestsgo.mod
dependency_bot_commit_share0,06
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
54.8/55Tamaños de archivo manejables — 1/266 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes67.873
source_files_sampled266
oversized_source_files1
Cómo se puntúa
0/40Esquema de API (OpenAPI/GraphQL/proto)
20/20Servidor MCP
40/40Ejemplos ejecutables — demos
Datos de entrada utilizados
example_dirsdemos
has_mcp_signal
api_schema_files

Datos clave

27estrellas de GitHub
1contribuidores
405commits en los últimos 12 meses
3días desde el último push
29versiones publicadas
1factor bus
4issues abiertas
Goecosistemas de paquetes

Advertencias de recopilación de datos

  • 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

Más detalle

OpenSSF Scorecard 4.4 / 10
4.4agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).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
Dependencias directas 12
RegistroPaqueteRestricción de versiónManifiesto
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
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "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"
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v2.5.0, esquema v0.30.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasGo.