Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-28 05:23 UTC

bgrewell / loom

GoApache-2.0★ 0 estrellas⑂ 0 forksdesde jun 2026Ver en GitHub ↗

bgrewell/loom tiene un índice de salud de 54 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (70/100) y la más baja, Security (32/100). Se actualizó por última vez hace 7 días. Una sola persona concentra la mayor parte del trabajo reciente.

54
global / 100
Moderado

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

54
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas 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.

Titularidad

Ben GrewellCuenta personal
11 seguidores124 repositorios públicosdesde abr 2013Grewell Technologies L.L.C.

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/bgrewell/loomv0.11.0-17hace 7 días

Métricas por categoría

Vitalidad

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

70Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 7 días
2.1/36Cadencia de commits — 3/52 semanas con commits
18/18Volumen de commits — 156 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_year156
human_commit_share1
days_since_last_push7
active_weeks_last_year3
Cómo se puntúa
27/27Publica versiones — 17 versiones publicadas
36/36Recencia de las versiones — última versión hace 7 días
27/27Cadencia de publicación — una versión cada ~3,9 días
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Datos de entrada utilizados
releases_count17
latest_release_tagv0.11.0
releases_from_tagsno
days_since_latest_release7
mean_days_between_releases3,9

Comunidad y Adopción

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

33En riesgo · 18% del índice global
Cómo se puntúa
0/60Estrellas — 0 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (Apache-2.0)
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
has_contributing
has_issue_templateno
has_code_of_conductno
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?

57Moderado · 24% 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
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
41.2/46.8Resolución de issues — 88% de issues cerradas
37.7/38.3Aceptación de PR — 67/68 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/14 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs67
open_issues6
closed_issues45
issue_closed_ratio0,882
closed_unmerged_prs1
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
7.8/25Alcance del propietario — 11 seguidores de bgrewell
25/25Trayectoria — 124 repos públicos, cuenta de ~13 años
Datos de entrada utilizados
followers11
owner_typeUser
is_verified
owner_loginbgrewell
public_repos124
account_age_days4863
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 — 17 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesgithub.com/bgrewell/loom
ecosystemsgo
any_deprecatedno
min_days_since_publish7

Calidad de Ingeniería

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

67Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 4 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 14 out of 14 merged PRs checked by a CI test -- score normalized to 10
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno

Documentación

65Moderado
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
0/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dir
has_descriptionno

Seguridad

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

32En riesgo · 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 — 14 out of 14 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/14 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no 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
0/5Security-Policy — security policy file not 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
0/7.5Vulnerabilities — 11 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate3,2

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

61Moderado · 0% del índice global
Cómo se puntúa
0/45Instrucciones para agentes — sin CLAUDE.md / AGENTS.md / reglas de editor
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 100 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
12.6/18Arranque con un solo comando — go.mod (convención del toolchain, sin ejecutor de tareas)
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — Go (tipado estático)
10/10Entorno reproducible — lockfile
0/10Práctica demostrada con agentes — ningún commit con autoría de agente entre los últimos 100
0/8Mantenimiento automatizado — no se observan 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_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
54.8/55Tamaños de archivo manejables — 1/228 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes77.235
source_files_sampled228
oversized_source_files1
Cómo se puntúa
40/40Esquema de API (OpenAPI/GraphQL/proto) — proto/loom/v1/control.proto
0/20Servidor MCP
40/40Ejemplos ejecutables — examples
Datos de entrada utilizados
example_dirsexamples
has_mcp_signalno
api_schema_filesproto/loom/v1/control.proto

Datos clave

0estrellas de GitHub
1contribuidores
156commits en los últimos 12 meses
7días desde el último push
17versiones publicadas
1factor bus
6issues abiertas
Goecosistemas de paquetes

Advertencias de recopilación de datos

  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 3.2 / 10
3.2agregado

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-07-28 05:22 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests14 out of 14 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/14 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update 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
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities11 existing vulnerabilities detected
Dependencias directas 10
RegistroPaqueteRestricción de versiónManifiesto
Gogithub.com/BGrewell/go-conversionsv0.0.0-20260615151034-4f93f00cd275go.mod
Gogithub.com/asavie/xdpv0.3.3go.mod
Gogithub.com/bgrewell/stencilv0.0.0-20260610184505-9b3d050c070ego.mod
Gogithub.com/vishvananda/netlinkv1.3.1-0.20250303224720-0e7078ed04c8go.mod
Gogolang.org/x/netv0.52.0go.mod
Gogolang.org/x/sysv0.43.0go.mod
Gogoogle.golang.org/grpcv1.81.1go.mod
Gogoogle.golang.org/protobufv1.36.11go.mod
Gogopkg.in/yaml.v3v3.0.1go.mod
Gogvisor.dev/gvisorv0.0.0-20260717235516-4f55f3833ba5go.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": [],
      "is_fork": false,
      "size_kb": 950,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 1174241,
        "Shell": 14353
      },
      "pushed_at": "2026-07-20T16:57:48Z",
      "created_at": "2026-06-11T01:50:34Z",
      "owner_type": "User",
      "updated_at": "2026-07-20T16:56:52Z",
      "description": null,
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "www.bengrewell.com",
      "name": "Ben Grewell",
      "type": "User",
      "login": "bgrewell",
      "company": "Grewell Technologies L.L.C.",
      "location": "USA",
      "followers": 11,
      "avatar_url": "https://avatars.githubusercontent.com/u/4050562?v=4",
      "created_at": "2013-04-03T16:59:42Z",
      "is_verified": null,
      "public_repos": 124,
      "account_age_days": 4863
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2026-07-20T16:59:22Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-07-20T04:00:43Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-06-17T00:08:28Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-06-16T22:46:17Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-06-16T21:57:31Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2026-06-16T21:05:11Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2026-06-16T20:47:15Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-06-16T20:10:15Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-06-16T02:26:36Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-06-16T01:14:50Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-06-15T23:47:26Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-06-15T23:29:08Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-06-15T20:59:08Z"
        },
        {
          "tag": "v0.2.2",
          "kind": "patch",
          "published_at": "2026-06-15T19:38:01Z"
        },
        {
          "tag": "v0.2.1",
          "kind": "patch",
          "published_at": "2026-06-15T18:54:25Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-06-15T18:29:33Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2026-06-15T14:12:55Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "a394619801c796c7df70a979454bce3851887aa5",
          "body": "feat: vidstream ABR player with QoE metrics, user docs, and the SIP design note",
          "is_bot": false,
          "headline": "Merge pull request #119 from bgrewell/feat/vidstream-docs",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T16:56:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5cf7bbec607d21641cb063abebae42a78dca60d1",
          "body": "…esign note\n\nPhase 7 (loom side) — the last loom piece of the real-application-traffic\ninitiative:\n\n- core/app/vidstream: the \"video\" app — an ABR player model driving the\n  httpx HTTPOrigin's generated HLS ladder over any injected network.\n  Virtual playhead with startup threshold, stall/rebuffer a\n[…]\n.MediaConfig unchanged.\n\nFull suite + race + loom_nonetstack builds green; docs nav/links validated.\n\nCloses #108. Closes #109.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: vidstream ABR player with QoE metrics, user docs, and the SIP d…",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T16:33:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eab8803309d7f5dfcec0cb15644e87f5065320c1",
          "body": "feat: gVisor netstack netpath backend and real HTTP/TLS httpx apps",
          "is_bot": false,
          "headline": "Merge pull request #118 from bgrewell/feat/netstack-httpx",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T16:27:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "861da3dfc5e293814de531a11341f5aee2306d56",
          "body": "Phase 6 of the real-application-traffic design: TCP-based application\ntraffic can now ride any raw-L3 loom datapath without NET_ADMIN, and loom\ngains a wire-true HTTP tier.\n\n- core/netstack: gvisor.dev tcpip (pinned) as a netpath backend. One Stack\n  hosts many addresses; Network(local) returns sour\n[…]\nns and the loom_nonetstack build; go.mod\ngains the pinned gVisor release, confined to core/netstack.\n\nCloses #106. Closes #107.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: gVisor netstack netpath backend and real HTTP/TLS httpx apps",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T15:38:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4f8d83d7e6573e8e0973a7de68770c55a90ea6ad",
          "body": "fix: voip rxLoop anchors arrival times at the datapath receive timestamp",
          "is_bot": false,
          "headline": "Merge pull request #116 from bgrewell/fix/voip-arrival-meta",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T14:04:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "49f2295515eac265dd80a2f3f5479fa5f97abb50",
          "body": "MediaSession.rxLoop stamped every datagram with time.Now() at dequeue, so\nwhen the media socket rides a tunneled datapath (orbit's GTP-U bridge via\nnetpath/dgram), RFC 3550 A.8 jitter included demux-ring wait, conn-channel\nqueueing, and goroutine handoffs — measuring the embedder's scheduler under\nl\n[…]\njitter at\nthe pacer noise floor while plain dequeue stamping reports tens of\nmilliseconds — and fails against the pre-fix code.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "fix: voip rxLoop anchors arrival times at the datapath receive timestamp",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T14:02:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ac890b99f281cb7994801f797bdea17ccbab5b54",
          "body": "feat: app flow roles on the wire, agent/controller wiring, and loom rtp quick mode",
          "is_bot": false,
          "headline": "Merge pull request #115 from bgrewell/feat/app-wire",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T03:59:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e67add099c0ac1698ce4a5e9b934afaca4162c63",
          "body": "feat: app framework, metrics plane, and the voip RTP/RTCP media session",
          "is_bot": false,
          "headline": "Merge pull request #113 from bgrewell/feat/app-voip",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T03:57:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a0dfee2cc9133dca39b8104eb197f3e0bfaaa969",
          "body": "…tp quick mode\n\nPhase 3 of the real-application-traffic design — apps become first-class\ndistributed flows and the two-host VoIP demo needs nothing but loom:\n\n- proto: additive FLOW_ROLE_APP_CLIENT/APP_SERVER, FlowSpec app/network/local,\n  TelemetrySample.app carrying VoIP/HTTP/Video metrics (E-mode\n[…]\n suite green including race runs across control/controller/cmd;\nproto regeneration is deterministic.\n\nCloses #105. Closes #102.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: app flow roles on the wire, agent/controller wiring, and loom r…",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:33:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1853b70f5a9612fad856bb55314a28aad2495ed8",
          "body": "Phase 2b of the real-application-traffic design (docs/design/real-app-traffic.md):\n\n- core/app: Client/Server runner interfaces (flow-lifecycle compatible),\n  app.Options with injected Network and OWD provider, typed param helpers,\n  and AppClients/AppServers component registries. Proto/agent wiring\n[…]\nh ends scoring ≈4.4 MOS at zero impairment.\n\nCloses #103. Closes #104. Partial #102 (Go framework; wire roles land in Phase 3).\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: app framework, metrics plane, and the voip RTP/RTCP media session",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:32:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c3010f7dcbc5dd4f14a21f9314ea2c980582ec18",
          "body": "feat: netpath connection-factory seam (host/memory/dgram) + Capabilities.RawL3",
          "is_bot": false,
          "headline": "Merge pull request #112 from bgrewell/feat/netpath",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:30:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f60ab2df3d95c68d95ccf174238fbd78d9aec7ac",
          "body": "feat: G.107 E-model, Gilbert burst-loss estimator, one-way-delay tracker",
          "is_bot": false,
          "headline": "Merge pull request #111 from bgrewell/feat/quality-owd",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:30:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7f2dba0d7ee97f8a12c146f76509d2d9a61c21c1",
          "body": "feat: RFC-exact RTP layer (header/packetizer/receiver stats), RTCP + XR, codec table",
          "is_bot": false,
          "headline": "Merge pull request #110 from bgrewell/feat/rtp-core",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:29:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "57f83134b1fced6eea1ac89990f7d21772b6512e",
          "body": "docs: real application traffic design (netpath seam, RTP/G.107 quality, app framework)",
          "is_bot": false,
          "headline": "Merge pull request #92 from bgrewell/docs/real-app-traffic-design",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-20T02:29:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e3a6a4196c122af472e5d6bcbba12176bf87d32",
          "body": "…awL3 capability\n\nAdds the single injectable socket-semantics seam every wire-true protocol\nengine will dial through (design: docs/design/real-app-traffic.md, PR #92):\n\n- core/netpath: the Network interface (DialContext/ListenPacket/Listen) with\n  Host (kernel stack, source-bindable) and Memory (pai\n[…]\ns fall back to Host when an embedder-supplied Components predates the\n  Networks registry.\n\nCloses #93. Closes #94. Closes #95.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: netpath connection-factory seam — host/memory/dgram networks, R…",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-19T17:31:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a0894d69b62b2bda015762a50c954c954e01db3f",
          "body": "…tracker\n\nAdds the quality-scoring and delay-measurement tier on top of the RTP layer\n(design: docs/design/real-app-traffic.md, PR #92):\n\n- core/quality/emodel: ITU-T G.107 E-model with full default formulas\n  (zero-impairment R = 93.2 pinned, components computed not hardcoded), the\n  100 ms Idd kne\n[…]\nburst\nrecovery, drift tracking, and error-bound honesty are covered by simulation\ntests.\n\nCloses #99. Closes #100. Closes #101.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: G.107 E-model, Gilbert burst-loss estimator, and one-way-delay …",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-18T02:13:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "43365b41408a8fa9e396f153079122bd4ad77a26",
          "body": "… RTCP, codec table\n\nAdds the wire-true RTP measurement tier (design: docs/design/real-app-traffic.md, PR #92):\n\n- core/rtp: header marshal/parse, media-clock Packetizer (crypto/rand SSRC/seq/ts\n  per RFC 3550 §5.1), G.711 mu/A-law synthetic-speech and Opus valid-TOC payload\n  sources, and ReceiverS\n[…]\nr\nre-anchors transit across an A.1 re-init so a sender restart cannot poison the\nestimate.\n\nCloses #96. Closes #97. Closes #98.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "feat: RFC-exact RTP layer — header codec, packetizer, receiver stats,…",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-18T02:13:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "72bad682b2cf9e17a55ca2230fa5fd8c5743e040",
          "body": "…y, app framework)\n\nAdds the loom-side design for wire-true application traffic and records the\nkey decisions as ADR-0023..0027:\n\n- docs/design/real-app-traffic.md: the netpath.Network seam (host/dgram/\n  memory/netstack backends, Capabilities.RawL3), core/rtp + codec + rtcp\n  with the RFC 3550/3611\n[…]\nirst embedder driving the requirements is orbit (5G RAN/UE emulator);\nevery capability here is a loom feature in its own right.\n\nClaude-Session: https://claude.ai/code/session_01PSe5wBw4nzoUw9wDFidvrQ",
          "is_bot": false,
          "headline": "docs: real application traffic design (netpath seam, RTP/G.107 qualit…",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-07-18T00:42:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cc11e2b7951ce7b0632493937a154be3cc5d8e4d",
          "body": "feat: label summary TCP diagnostics with their stream",
          "is_bot": false,
          "headline": "Merge pull request #90 from bgrewell/fix/summary-tcp-stream-label",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-17T00:02:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "100d0c62d9f29e80a4fb4789c7083d85bcea484a",
          "body": "fix: warn when a non-root install won't update the loomd service",
          "is_bot": false,
          "headline": "Merge pull request #89 from bgrewell/fix/install-service-skew-warning",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-17T00:02:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "597ec28ad30dc033ff4f78a7eceacac6c7ebec66",
          "body": "With parallel streams the summary's per-stream tcp lines were all tagged only\nwith the (shared) direction, so you couldn't tell which stream each retrans/cwnd\nbelonged to. Lead each tcp line with its event name (and direction), matching\nthe per-flow rows.",
          "is_bot": false,
          "headline": "feat: label summary TCP diagnostics with their stream",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-17T00:00:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ba59bbdf2da124e0077b07fb2e5e2d08f46d385f",
          "body": "A non-root upgrade installs to ~/.local/bin (and wins on PATH, so loomd\n--version looks updated), but a system loomd.service keeps running its\nroot-owned binary elsewhere — leaving the agent stale. Detect the service's\nExecStart path and, when it differs from the target dir, warn with the exact\nsudo re-run command.",
          "is_bot": false,
          "headline": "fix: warn when a non-root install won't update the loomd service binary",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T23:51:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7a1c8cffc325026cda6f86617e6618994b925470",
          "body": "feat: live per-interval TCP health on telemetry lines",
          "is_bot": false,
          "headline": "Merge pull request #88 from bgrewell/feature/live-tcp-diagnostics",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T22:40:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "acd6106256decae9686d7ea957f601b498d74013",
          "body": "Carry the sender's TCP_INFO into each live consolidated line: retransmits *this\ninterval* (delta, the real-time trouble signal), current congestion window, and\nsmoothed RTT — so a degrading link shows up as it happens (retrans climbing,\ncwnd collapsing). The controller tracks last cumulative retrans per flow to\nderive the delta; the summary keeps reporting cumulative totals. Live JSON gains\ntcp_retrans/tcp_lost/tcp_rtt_us/tcp_cwnd.",
          "is_bot": false,
          "headline": "feat: live per-interval TCP health on the telemetry lines",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T22:18:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "abc8030dae019fbb7c99404e8e5240f7a5aaabb2",
          "body": "feat: clearer live lines and a richer authoritative summary",
          "is_bot": false,
          "headline": "Merge pull request #87 from bgrewell/feature/summary-and-line-clarity",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T21:51:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "845731fd185cb85f1bb6aeac3e3c18d8102638d5",
          "body": "Read TCP_INFO (getsockopt) from the sender's socket and surface it in the run\nsummary for link profiling: total retransmits, lost segments, smoothed RTT ±\nvariance, congestion window, and slow-start threshold (∞ during slow start).\n\nTcpInfo rides the TelemetrySample proto; the TCP datapath exposes a\n[…]\nd elsewhere) via an optional datapath.Diagnoser; the\nagent attaches it at each boundary so the summary carries the end state. Only\nsender TCP flows produce a line (udp/afxdp/receiver flows have none).",
          "is_bot": false,
          "headline": "feat: sender-side TCP diagnostics in the summary",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T21:27:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "12b88cdbc92b8bfb558cd53236a0660a48f06806",
          "body": "Sum sender/receiver packet totals and add a loss line: count + percentage of\ntraffic. For packet datapaths (udp/afxdp) report packet loss (counts correspond\n1:1); for stream transports (tcp) report byte loss, which is ~0 since TCP\nrecovers loss via retransmits below the app layer. Thread the datapath onto\nPlaced/FlowSample to pick the right metric.",
          "is_bot": false,
          "headline": "feat: report end-to-end loss in the summary",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T21:17:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35a5dc7949ddc18d2ef56da3762759067bfe7280",
          "body": "Drop the per-line '(N flows)' count — it was always sender+receiver for a\nsingle stream, so it conveyed nothing and read as '2 flows' for one transfer.\n\nLead the summary with scenario, duration, and stream count + directions\n(deriving streams from distinct events), and label the totals as\nsender-measured (tx) vs receiver-measured (rx) so the two numbers' meaning is\nexplicit. Carry from/to onto FlowSample so per-flow rows (live and summary)\nshow direction. JSON summary gains scenario + streams.",
          "is_bot": false,
          "headline": "feat: clearer live lines and a richer authoritative summary",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T21:11:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1293c251e516e7d2176e9b02a968f60dfb30112e",
          "body": "fix: correct release archive examples mapping (v0.7.1 was corrupt)",
          "is_bot": false,
          "headline": "Merge pull request #86 from bgrewell/fix/release-archive-examples",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:59:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "31aaa5c1ba483526fb9092562c958d084792bc93",
          "body": "…rupt)\n\nv0.7.1's release tarball was unextractable: a single-file 'dst: examples'\nmapping wrote 'examples' as a FILE while the scenarios glob wrote 'examples/'\nentries, so tar hit 'examples: Not a directory' and exited non-zero —\ninstall_from_release then aborted to source even though the binaries h\n[…]\nacts clean,\nexit 0).\n\nAlso harden install_from_release: don't hard-fail on tar's exit; gate on the\nper-binary existence check instead, so a cosmetic archive quirk can't block a\nworking binary install.",
          "is_bot": false,
          "headline": "fix: correct release archive examples mapping (v0.7.1 archive was cor…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:57:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1d795aedc5ceaadc96f74a53a5da8b1be2207563",
          "body": "docs: comprehensive example scenarios + install wiring",
          "is_bot": false,
          "headline": "Merge pull request #85 from bgrewell/feature/example-scenarios",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:41:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4e77be8c0d94b9adc2f7527ec2107195ecc5b775",
          "body": "…elease",
          "is_bot": false,
          "headline": "fix: fall back to main when fetching example scenarios for an older r…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:37:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b04bb74c848d8ef201347dc547ed394da5460e68",
          "body": "Add a curated set of ready-to-run scenarios under docs/examples covering TCP\n(throughput, bulk, bidirectional, parallel, rate-limited), UDP (throughput,\nrate-limited, jumbo, bidirectional), AF_XDP (veth, nic-to-nic), application\nemulations (https-browse, voip-call, ssh-session, prometheus), and time\n[…]\nDIR; uninstall.sh removes them; the release archive bundles them\nunder examples/. All scenarios validated through scenario.Parse + timeline.Plan,\nand the socket/emulation ones smoke-tested end to end.",
          "is_bot": false,
          "headline": "docs: add comprehensive example scenarios and install them",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:35:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d0af3d8f0d804a22119b63ca19442e94b1953059",
          "body": "perf: batch UDP receives with recvmmsg (#74)",
          "is_bot": false,
          "headline": "Merge pull request #83 from bgrewell/perf/udp-recvmmsg",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d73095529731f05d9e62affa1d9d1e00244ceac",
          "body": "fix: accurate live rx, directional flow labels, TCP throughput, datapath resolution",
          "is_bot": false,
          "headline": "Merge pull request #84 from bgrewell/fix/tcp-rx-consolidation",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T20:05:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "44c2bc4647dde406bae19ffedd5adb77e0c20ea9",
          "body": "TCP throughput was capped at the per-write syscall rate because the sender\nwrote in packet_size units (e.g. 1400 B). TCP is a byte stream, so packet_size\nis meaningless on the wire; write a large 128 KiB block (iperf3's default)\ninstead, decoupled from packet_size. Loopback single-stream TCP goes fr\n[…]\nd, so 'datapath: tcp'\nplaced under 'flow:' (next to packet_size, where authors naturally put it)\nwas silently ignored and ran UDP. Resolve datapath from flow params as a\nfallback, event-level winning.",
          "is_bot": false,
          "headline": "fix: TCP writes in large blocks and datapath resolves from flow params",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T19:11:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "62687562f63d7fb3980af7da3e39a0a0e7338860",
          "body": "The watermark flushed an interval as soon as it was one interval old, so a\nslow-but-alive receiver got stamped rx 0 and its late sample was orphaned.\nEmit instead once every flow has settled an interval (reported it, or ended\nits stream), with a generous backstop for a node that goes silent without\n\n[…]\ncket leak.\n\nCarry event + from/to onto Placed/Aggregate so concurrent flows (bidir,\nN-way) render as labeled, distinguishable lines (e.g. 'up client->server')\ninstead of indistinguishable tx/rx pairs.",
          "is_bot": false,
          "headline": "fix: consolidate live rx accurately and label directional flows",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T19:03:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "281c0904820bcd43d7d94553028e2bb1ac77b7ec",
          "body": "The UDP receive datapath did one recvfrom per datagram, so the receiver was\nsyscall-bound and dropped at high pps (field test: 1400B soak tx 4.78 / rx\n1.93 Gbps — ~60% rx loss). Read the whole batch with one recvmmsg via\nipv4.PacketConn.ReadBatch (MSG_WAITFORONE returns as soon as one datagram is\nqu\n[…]\nild tags; DART LXD\nsuite (UDP/reqresp/TCP) all pass.\n\nNote: GRO (kernel datagram coalescing) is a further lever — it needs large\nreceive buffers + UDP_GRO setsockopt — left as a follow-on. Closes #74.",
          "is_bot": false,
          "headline": "perf: batch UDP receives with recvmmsg (#74)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T17:21:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "509dfbb19b37f87e4a4245c7d70cadf0f86ddb5c",
          "body": "perf: batch UDP sends with sendmmsg (#56)",
          "is_bot": false,
          "headline": "Merge pull request #82 from bgrewell/perf/udp-sendmmsg",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T03:18:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72f4ffa0f2c5130d2c6a94fab1665bfbdd498a13",
          "body": "The UDP transmit datapath did one conn.Write (sendto) per datagram, so the\nsend side was syscall-bound (field test: ~4.8 Gbps tx soak at 1400B, the\nceiling rising sharply with jumbo frames). Send the whole committed batch in\none sendmmsg via ipv4.PacketConn.WriteBatch on the connected socket (Addr n\n[…]\nonly. The receiver still does one recvfrom per\npacket (#74, recvmmsg/GRO), so a 1400B soak still shows tx > rx until that\nlands. Real send-throughput gains are best measured on hardware.\n\nPart of #56.",
          "is_bot": false,
          "headline": "perf: batch UDP sends with sendmmsg (#56)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T03:02:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f97ff58653580cc0253d942723e3e8901c8c17dd",
          "body": "feat: TCP receive datapath + vectored (TSO) sender (#76)",
          "is_bot": false,
          "headline": "Merge pull request #81 from bgrewell/feat/tcp-datapath",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T02:19:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c3fbbd930a5a03be7283e74abdce1eeb1d791a04",
          "body": "`datapath: tcp` couldn't run before — there was no TCP receiver (RxRegistry\nhad only udp/afxdp), so the controller failed to place the receiver and the\nsender had nothing to dial. And the TCP sender wrote one packet_size frame\nper Write(), defeating TSO.\n\n- core/datapath/tcp_listener.go: a TCP recei\n[…]\neued to the socket) can\nexceed rx (bytes delivered) at the cutoff due to in-flight/buffered data;\ncount-bounded runs reconcile exactly. Real throughput (TSO) is best measured\non hardware.\n\nCloses #76.",
          "is_bot": false,
          "headline": "feat: TCP receive datapath + vectored (TSO) sender (#76)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T01:33:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1ee5dc63815fab7479b6208c771f49178a6afcdc",
          "body": "ci: ship AF_XDP-enabled loomd; install script notes readiness",
          "is_bot": false,
          "headline": "Merge pull request #80 from bgrewell/ci/afxdp-build",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T01:04:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "229575399bc0b5c5d6e8a48be5159eb5788b9b15",
          "body": "Release loomd now compiles the AF_XDP datapath in (-tags afxdp in the\nGoReleaser loomd build), so installed agents support `datapath: afxdp`\nout of the box instead of erroring \"unknown name afxdp\". One binary: the\nbackend is dormant unless a flow selects it, it's pure Go so it still\ncross-compiles t\n[…]\npaths.md updated: released loomd\nhas afxdp built in.\n\nPairs with #75 (the frame-crafting generator) — together a released loomd\ncan drive cross-host AF_XDP. Part of the release-lifecycle roadmap item.",
          "is_bot": false,
          "headline": "ci: build loomd with AF_XDP; install script notes afxdp readiness",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T00:14:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "99b36e1a329898cbcb175ff763c7410f58125946",
          "body": "feat: frame-crafting ethernet generator for cross-host AF_XDP (#75)",
          "is_bot": false,
          "headline": "Merge pull request #79 from bgrewell/feat/afxdp-frame-generator",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T00:07:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "211e8f7ace2a534988c3befe4a6cc425199e5e90",
          "body": "AF_XDP bypasses the kernel stack, so it transmits complete Ethernet frames\n— but the only generator emitted payload bytes, so cross-host AF_XDP went\nout with a garbage destination MAC and the peer NIC dropped it (it only\nworked over veth, where the redirect grabs every frame).\n\nAdd an `ethernet` gen\n[…]\n veth e2e still uses the stream generator).\n\nCloses #75.\n\nNOTE: cross-host AF_XDP delivery can't be validated in CI (no NIC pair);\nneeds verification on real NICs (SR-IOV/bridge) before relying on it.",
          "is_bot": false,
          "headline": "feat: frame-crafting ethernet generator for cross-host AF_XDP (#75)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-16T00:01:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c612e13053fbe898ebb73e9ab4d8af29f79d01fe",
          "body": "fix: rate pacing hits the target (burst + spin, not per-packet timer) (#73)",
          "is_bot": false,
          "headline": "Merge pull request #78 from bgrewell/fix/rate-pacing",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T23:38:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2dd8527597ce37e192554f4d8b7d0a221dd09cb5",
          "body": "… (#73)\n\nThe Interval scheduler released one packet per time.NewTimer; at the\nmicrosecond gaps high rates need (11µs at 1Gbps/1400B) the timer wakeup\ngranularity — not the link — set the rate, capping a rate-limited flow far\nbelow target (1Gbps configured → ~257Mbps observed).\n\nRework it to release \n[…]\nis now honored up to\nthe socket ceiling (which #56/#74 raise). Tests: burst release + cap\n(deterministic clock), and a real-time regression guard that the old\nper-packet timer would fail.\n\nCloses #73.",
          "is_bot": false,
          "headline": "fix: rate pacing hits the target (burst + spin, not per-packet timer)…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T23:35:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "21763512c5005c21f12c67a00cc8da8612c355f5",
          "body": "feat: agent-owned interval reporting, controller consolidates by index",
          "is_bot": false,
          "headline": "Merge pull request #77 from bgrewell/feat/interval-consolidation",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T23:24:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b86cd22ab086e61eef3c2addd3ac8eed77000689",
          "body": "Replace the central rate clock with a first-class, iperf3-style design:\nthe interval clock lives at the data source, anchored to the shared\nscheduled-start gate, and the controller is a pure watermark aggregator.\n\nRoot cause of the prior tail-chasing: two unsynchronized clocks (each\nagent's sample t\n[…]\nth a first interval that is full and a summary average that\nmatches the per-interval rates. Verified locally (10s@1s=10, 10s@500ms=20,\n5s@1s=5), under -race, and on the DART LXD cross-container suite.",
          "is_bot": false,
          "headline": "feat: agent-owned interval reporting, controller consolidates by index",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T22:24:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c2bdda678241ed1158703ecd9d96f5e0515ad585",
          "body": "feat: scheduled-start gate so flows begin in lockstep",
          "is_bot": false,
          "headline": "Merge pull request #72 from bgrewell/feat/scheduled-start-gate",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T20:54:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f75138124e250cec23ca3d9b92ff4cd56a2f17ef",
          "body": "Traffic sources now open at a shared \"starting gate\" instead of whenever\ntheir Start RPC happens to arrive. The controller already runs a TimeSync\nexchange with every agent; it now keeps those offsets and, when starting a\nflow, picks a target time T = now + slack (slack scales with the slowest\nmeasu\n[…]\nFollow-up: anchor the telemetry display clock to the gate T so the first\ninterval is full (today it's a partial first line) and the summary average\nis exact — the gate gives us the precise T to do it.",
          "is_bot": false,
          "headline": "feat: scheduled-start gate so flows begin in lockstep",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T20:51:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "88084d3a19236c7efb0470ee2549d5793b16ed6f",
          "body": "fix: synchronize telemetry reporting to the run",
          "is_bot": false,
          "headline": "Merge pull request #71 from bgrewell/fix/telemetry-sync",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T19:33:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1ec70bc569a49d7997f9f6a2469b10288c50f591",
          "body": "A 10s run at 1s interval showed only ~8 sample lines, not 10. Two causes:\nthe collector subscribed to a flow's telemetry ~1 interval after it\nstarted (missing the first second or two), and the agent send ticker and\nthe controller display ticker were independent clocks that drifted.\n\nRework the realt\n[…]\nr wall-clock elapsed (which includes ~1s\nstartup), so it slightly understates active throughput — that becomes\nexact with the scheduled-start \"starting gate\" (known start/stop), the\nplanned follow-up.",
          "is_bot": false,
          "headline": "fix: synchronize telemetry reporting to the run",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T19:30:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5e8fef361b185537f3c2e6f53206e49180a39e28",
          "body": "fix: don't inflate the first telemetry sample's rate",
          "is_bot": false,
          "headline": "Merge pull request #70 from bgrewell/fix/telemetry-first-sample-rate",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T18:49:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "40c6070b8d06995bdde2a3d7b2c30c3edbb805cd",
          "body": "A flow is usually already running by the time its telemetry stream is\nopened (the collector subscribes ~1 interval after the flow starts). The\nrate calc seeded the byte baseline at 0 but the time baseline at stream\nopen, so the first sample charged *every byte sent since the flow started*\nto a singl\n[…]\n counter's current value at stream open so\nthe byte and time windows align. Extracted the calc into a small\nrateTracker (counter-monotonic + zero-interval guards) with a\ndeterministic regression test.",
          "is_bot": false,
          "headline": "fix: don't inflate the first telemetry sample's rate",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T18:44:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6a61576f2eed5265ebbdd64e52ac27a7c66fcd5a",
          "body": "docs: document the release process and semver policy",
          "is_bot": false,
          "headline": "Merge pull request #69 from bgrewell/docs/releasing",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T18:33:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "23c190601db32398ed26038662c1b503a0106d62",
          "body": null,
          "is_bot": false,
          "headline": "docs: document the tag-driven release process and semver policy",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T18:30:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30787a4bc489c3a724fba77eaf9d0a760e61f5d7",
          "body": "feat(scripts): optionally install loomd as a systemd service",
          "is_bot": false,
          "headline": "Merge pull request #68 from bgrewell/feature/install-loomd-service",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T18:03:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58e1ceae7ebb4639a63bc63fb9f56672ab4de941",
          "body": "Skip the `loomd &` dance. When install.sh runs as root on a systemd host\nit offers to install /etc/systemd/system/loomd.service and `enable --now`\nit, so the agent starts on boot. On a terminal it prompts; piped through\n`curl | bash` it skips unless LOOM_SERVICE=1. New env knobs:\nLOOM_SERVICE (1/yes\n[…]\n, and removes the unit (as root).\n- scripts/loomd.service: a reference unit for manual installs.\n- docs: scripts/README documents the service flow.\n\nThe generated unit passes `systemd-analyze verify`.",
          "is_bot": false,
          "headline": "feat(scripts): optionally install loomd as a systemd service",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T17:59:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "433eda023455cae52345b7896fedbeb252c9dbdd",
          "body": "fix: end loomctl run at flow completion with a real summary",
          "is_bot": false,
          "headline": "Merge pull request #67 from bgrewell/fix/loomctl-run-lifecycle",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T17:52:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "974ffb3da5e62b6e500df4f9b8a50a32bd74d7e1",
          "body": "A real two-VM test surfaced three issues in `loomctl run`:\n\n1. A 10s flow ran for the full 30s horizon. `c.Run` returns once the\n   timeline's fires are dispatched, then loomctl idled on the horizon. Add\n   Telemetry.WaitSources so the run stops as soon as every source flow\n   (sender/requester) fin\n[…]\nnt paths).\n\nAlso suppress empty leading telemetry ticks (the \"0 flows\" dead lines\nbefore placement) so the first printed line is real traffic, and print the\nsummary last. Docs/README updated to match.",
          "is_bot": false,
          "headline": "fix: end loomctl run at flow completion with a real summary",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T17:46:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3e0fe4a50814731b29161e17d10410246be0c30f",
          "body": "feat: responder role for request/response emulations",
          "is_bot": false,
          "headline": "Merge pull request #65 from bgrewell/feat/responder-role",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T16:01:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7ead2e6a5a26d1e9dd87eda734efa013addfd1d",
          "body": "Push emulations (voip-call, prometheus-sender, ssh-session) are\none-directional: the client sends, a plain receiver absorbs. Real\nrequest/response apps (https-browse, later ftp-transfer) need the server\nto respond with each requested object, so the dominant download traffic\nflows server->client over\n[…]\nnder as Tx.\n- tests: emul unit tests (tcp+udp, count/volume bounds), agent e2e\n  through gRPC, controller spec + scenario tests.\n- docs: document push vs request/response modes and the transport knob.",
          "is_bot": false,
          "headline": "feat: responder role for request/response emulations",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T15:39:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "65dad7581d1661186bc682d272b458c4cc478b4b",
          "body": "fix: distinguish SI from IEC units for sizes",
          "is_bot": false,
          "headline": "Merge pull request #64 from bgrewell/fix/si-iec-units",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T15:34:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a9c5ed3c5ac089c81ba5b5d66bf1be6e13a82f2c",
          "body": "Previously ParseSize used binary multipliers for SI prefixes, so \"100MB\"\nand \"100MiB\" both parsed to 104857600 bytes. Delegate size parsing to the\nfixed go-conversions library, which treats SI K/M/G/T as powers of 1000\nand IEC Ki/Mi/Gi/Ti as powers of 1024. ParseRate already used the\nlibrary; bump i\n[…]\n differ too.\n\n- core/units: delegate ParseSize to conv.StringByteSizeToInt\n- tests: assert SI decimal values, add IEC cases and a must-differ check\n- docs/scenario-schema.md: document the SI/IEC split",
          "is_bot": false,
          "headline": "fix: distinguish SI from IEC units for sizes",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T15:20:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a2e8b3d303d5fdb322b4695e3de6b79c09404477",
          "body": "docs: publish a mkdocs-material site to GitHub Pages; iperf-style REA…",
          "is_bot": false,
          "headline": "Merge pull request #63 from bgrewell/docs/site-and-readme",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T14:36:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "77db6c9846244f406be13144440b097df4d8e4e1",
          "body": "…DME example\n\n- README: lead with a measured client->server throughput test (run loomd on\n  each host, drive a flow with loomctl) instead of the local discard demo,\n  which better reflects real use; keep a brief one-host check.\n- mkdocs.yml: Material theme, full nav over the docs/ manual, light/dark\n[…]\nithub URLs so they resolve both on GitHub and in the\n  built site.\n\nValidated: mkdocs-material build succeeds and emits all pages (home,\ngetting-started, concepts, architecture, guides, reference, …).",
          "is_bot": false,
          "headline": "docs: publish a mkdocs-material site to GitHub Pages; iperf-style REA…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T14:34:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c31be3a6327a5d96e10a8ff72ec828ad6339399f",
          "body": "ci: cut releases with GoReleaser + full version metadata",
          "is_bot": false,
          "headline": "Merge pull request #62 from bgrewell/ci/goreleaser",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T14:08:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c9b9577b053021fdbba107fb63db35ee04893087",
          "body": "- .goreleaser.yaml: builds loom/loomd/loomctl for linux amd64+arm64\n  (CGO-free, -trimpath), packaged as one loom_<version>_linux_<arch>.tar.gz\n  per arch containing all three binaries — the exact layout\n  scripts/install.sh downloads. Injects version/commit/buildDate/branch via\n  ldflags; checksums\n[…]\ned archive with all three binaries + LICENSE/README at root,\nand the injected metadata shows in 'loom --version' (commit/date/branch).\nBoth default and -tags afxdp builds stay green; go.sum untouched.",
          "is_bot": false,
          "headline": "ci: cut releases with GoReleaser; plumb full build metadata via stencil",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T14:04:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "80af9d0f994910077837bf16881e301ecf45dc29",
          "body": "chore: curl|bash install / upgrade / uninstall scripts",
          "is_bot": false,
          "headline": "Merge pull request #61 from bgrewell/chore/install-scripts",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T13:33:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ceea3d13ce50b7f67ebbaa7780d36c9e24ba6856",
          "body": "Adds scripts/{install,upgrade,uninstall}.sh, runnable via curl piping to\nbash, for distributing the loom/loomd/loomctl binaries.\n\n- install.sh: Linux amd64/arm64; installs prebuilt release binaries when a\n  release exists, else builds from source via 'go install'. Idempotent.\n  Env knobs: LOOM_VERSI\n[…]\nase URL, and falls through\nversion -> latest -> main from source as designed. (Full curl|bash needs the\nrepo public / releases published — go-publishing via goreleaser is the\ncomplementary follow-up.)",
          "is_bot": false,
          "headline": "chore: curl|bash install / upgrade / uninstall scripts",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T13:29:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f9a6df7eb2e479b78d81fec832923b6e8253a721",
          "body": "feat: application emulation engine + four launch emulations",
          "is_bot": false,
          "headline": "Merge pull request #60 from bgrewell/feat/emulation-engine",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T12:51:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc4240bf63e5b03defbd3c1560f0f941f0933664",
          "body": "…ience)\n\nRefines the emulation knob surface so each exposes what a user expects:\n\n- voip-call: proper codec model — codec (g711 64kbps / g729 8kbps / opus\n  ~32kbps) sets the bitrate, ptime (default 20ms; 'interval' alias) sets the\n  interval, and frame size = bitrate x ptime (g711@20ms = 160B); fra\n[…]\nip codec/ptime/frame_size math; duration-knob -> run duration\nmapping (and stop.after precedence). Validated e2e (g729 call honoring the\nduration knob across two agents). Full suite green under -race.",
          "is_bot": false,
          "headline": "feat: natural per-emulation knobs (codec/ptime model, duration conven…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T12:45:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4b1a66780d3099915f2e8070febebc42e4716a5d",
          "body": "Adds core/emul, loom's behavior-script engine for realistic app traffic\nshapes — the stateful, low-rate counterpart to the pump (DESIGN §10).\n\n- Dist: constant/uniform/normal/exponential distributions (seeded), parsed\n  from size/duration params via the units value grammar.\n- BehaviorScript ([]Step{\n[…]\n -race; raw udp\npath re-checked via the LXD suite (1/0); both build configs compile.\n\nFollow-ups: a responder role (dynamic-webserver / FTP data channel) for true\nrequest/response sizes; ftp-transfer.",
          "is_bot": false,
          "headline": "feat: application emulation engine + four launch emulations",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T04:36:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6a22c38717a4940af42130245f51400c4b572ffa",
          "body": "docs: comprehensive user manual",
          "is_bot": false,
          "headline": "Merge pull request #59 from bgrewell/docs/comprehensive",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T02:29:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "926747fc14d622adf1acc96a2717d9cf20e4e6c4",
          "body": "refactor: component DI + functional-option constructors (ADR-0022)",
          "is_bot": false,
          "headline": "Merge pull request #58 from bgrewell/refactor/component-di",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T02:29:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c8f976800df1db775c8ad3205dd6ccbaa7585534",
          "body": "…cture, guides, deployment, reference)\n\nA layered docs set written for both first-time users and experts —\nprogressive disclosure, with explicit reader paths.\n\n- README.md: rewritten as the hero (what/why, 60s quickstart, signposts);\n  the old 'phase 1' status was stale.\n- docs/README.md: manual hom\n[…]\ns/testing/ci-cd/\nblueprints) are cross-linked, not duplicated. Every command/flag/example was\nchecked against the real binaries and code. Markdown-only; site-ready\nstructure (drops into mkdocs later).",
          "is_bot": false,
          "headline": "docs: comprehensive user manual (intro, quickstart, concepts, archite…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T02:17:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d5706a9fe683e8acaaf7760611030ed85a353cd7",
          "body": "…s (ADR-0022)\n\nReplaces global-registry reach-through and Set* setters with injectable\ncomponents and option constructors (the project's house style; kills the\nhidden global mutable state in the use path).\n\n- core/components: Components bundles the Tx/Rx datapath, generator,\n  scheduler, payload reg\n[…]\nurpose: factories still self-register into the package registries\n(Default() wraps them) rather than per-instance, preserving init()/build-tag\nregistration with minimal churn. See ADR-0022 resolution.",
          "is_bot": false,
          "headline": "refactor: inject component registries + functional-option constructor…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T01:57:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "71425a77d87f5ab2a54c2290e5c2e79b03184a82",
          "body": "feat: select AF_XDP end to end via scenario/controller/agent",
          "is_bot": false,
          "headline": "Merge pull request #57 from bgrewell/feat/afxdp-e2e",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T01:02:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d887def7d408c7840c8e1bf490f21f26a5f8c949",
          "body": "Wires the AF_XDP backend through the whole stack so a flow can run over it\nfrom a scenario, not just the datapath in isolation.\n\n- proto: FlowSpec gains iface (7) + queue (8); regenerated api/loomv1.\n- datapath: add RxRegistry (receive-side factory map) mirroring the TX\n  Registry; udp listener regi\n[…]\n on one veth\nend, an afxdp receiver on the other, receiver accounts bytes. Full suite\ngreen under -race; both build configs compile; LXD udp suite still 1/0\n(udp receiver now goes through RxRegistry).",
          "is_bot": false,
          "headline": "feat: select AF_XDP end to end via scenario/controller/agent",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-15T00:35:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f8a60c1d92b30e398bc49be873bf3b6b2e76542a",
          "body": "test: tracked datapath throughput benchmarks + baseline doc",
          "is_bot": false,
          "headline": "Merge pull request #54 from bgrewell/perf/datapath-benchmarks",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T20:43:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5809b33fa47733c37aa30a25bc30882a4aaa554d",
          "body": "feat: AF_XDP datapath backend (build-tagged, zero-copy)",
          "is_bot": false,
          "headline": "Merge pull request #53 from bgrewell/feat/afxdp-datapath",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T20:42:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "339748855fac79cfe44ba5f5138998529e067ada",
          "body": "feat: batched pacing in the pump",
          "is_bot": false,
          "headline": "Merge pull request #55 from bgrewell/feat/batched-pacing",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T20:41:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "963bf184518023c96c241c1e13a48590279ae3f4",
          "body": "feat: wire/proto evolution discipline (ADR-0021)",
          "is_bot": false,
          "headline": "Merge pull request #52 from bgrewell/feat/proto-wire-discipline",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T20:40:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e740829c3d54b9752598c0e329d9e987e873a263",
          "body": "The scheduler now tells the pump how many packets may go now, and the pump\nreserves/fills/commits that many in one batch — so an unpaced (soak) flow\namortizes the per-commit datapath cost instead of paying it per packet.\n\n- Scheduler.Pace(ctx) bool -> Pace(ctx, max int) (n, ok): soak returns max\n  (\n[…]\nsts: TestPumpBatchesUnderSoak (batches >1, counts exactly),\nTestPumpPacedSendsOneAtATime (paced stays at 1). Full suite green under\n-race; alloc gate green; LXD two-node suite re-run end to end (1/0).",
          "is_bot": false,
          "headline": "feat: batched pacing in the pump",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T18:41:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "73dd2b097f6145b8ca34987294b74f3845e27838",
          "body": "Adds committed throughput benchmarks so per-datapath performance is tracked\n(and benchstat-diffable) over time:\n\n- core/datapath/bench_test.go: BenchmarkTxDiscard / TxMemory / TxUDPSocket,\n  each with b.SetBytes so 'go test -bench' reports MB/s. Captures the\n  socket-based number (kernel-stack UDP o\n[…]\ns; memory ~155 Gbps; AF_XDP/veth\n  ~19 Gbps; UDP socket ~2.16 Gbps) with the caveats (veth != NIC, per-packet\n  syscall, single-core).\n\nDefault build/test unaffected; benchmarks run only under -bench.",
          "is_bot": false,
          "headline": "test: tracked datapath throughput benchmarks + baseline doc",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T18:20:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d8ee71f5c2d723726832f278b5d42f458a1852e7",
          "body": "First kernel-bypass backend on the new datapath seam (ADR-0008/0019). Built\nonly with the 'afxdp' tag: it pulls in eBPF/netlink and needs a NIC (or veth)\nplus root, so it lives in the physical/veth testbed tier, never default CI.\n\n- AFXDPTx: TxReserve hands out UMEM frame aliases (GetDescs/GetFrame,\n[…]\nuite green; both default and '-tags afxdp' builds compile.\n\nNote: the afxdp deps must survive 'go mod tidy' (run it with -tags afxdp, or\nthey'll be pruned since the default build doesn't import them).",
          "is_bot": false,
          "headline": "feat: AF_XDP datapath backend (build-tagged, zero-copy)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T16:09:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "766eea274387bd28ce38020301e9acb08094a2b4",
          "body": "Locks the control-plane wire down before any external consumer pins it:\n\n- listen bool -> FlowRole enum. Field 20 + name 'listen' are now reserved;\n  'role' is added at field 21. UNSPECIFIED is treated as SENDER (default);\n  REFLECTOR returns codes.Unimplemented until built. Controller sends\n  RECEI\n[…]\nevery RPC, so a message field\nwould duplicate it.\n\nRegenerated api/loomv1. Tests added for the role semantics and api_version.\nFull suite green under -race; LXD two-node suite re-run end to end (1/0).",
          "is_bot": false,
          "headline": "feat: wire/proto evolution discipline (ADR-0021)",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T13:56:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "49d16301e07384cbbb2ced1e6429ac385a9b6a93",
          "body": "feat: native frame backends; drop legacy datapath interface (ADR-0019/0020, 2/2)",
          "is_bot": false,
          "headline": "Merge pull request #51 from bgrewell/feat/native-frame-backends",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T13:27:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "08d8a45c207646aafe23ebabff6e05f0ff2688b9",
          "body": "feat: batch zero-copy-capable datapath interface (ADR-0019/0020, 1/2)",
          "is_bot": false,
          "headline": "Merge pull request #50 from bgrewell/feat/batch-datapath-interface",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T13:26:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1a53cc068fbd83174e62cdcf3c879549483d9c4",
          "body": "…/0020, PR 2/2)\n\nCompletes the batch, zero-copy-capable datapath migration.\n\n- framePool: shared reusable-frame helper for kernel-socket backends.\n- udp/tcp: native TxDatapath (pooled frames, one write per committed frame).\n- udp_listener: native RxDatapath — RxPoll reads a batch of datagrams into\n \n[…]\nap updated.\n\nThe datapath seam is now ready for a native AF_XDP backend with no\ninterface change. Full suite green under -race; alloc gates pass; LXD\ntwo-node suite re-run end to end (1 pass, 0 fail).",
          "is_bot": false,
          "headline": "feat: native frame backends; drop legacy datapath interface (ADR-0019…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T04:49:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2f9c0fea812a8a33dc7353ddd9f75747177c3b00",
          "body": "…1/2)\n\nIntroduces the TX/RX split, frame-based datapath interface that AF_XDP and\nDPDK need, without copying packet bytes — the responsiveness gate for the\nfast backends.\n\n- datapath.Frame{Data,Len,Meta} + Meta{Nanos,Src}: a packet's storage,\n  owned by the datapath; Data may alias device memory (UM\n[…]\ne real reserve/fill/commit ops\n(closing critical-review finding #6, which had tested a stand-in). Full\nsuite green under -race; alloc gates pass; LXD two-node suite re-run end to\nend (1 pass, 0 fail).",
          "is_bot": false,
          "headline": "feat: batch, zero-copy-capable datapath interface (ADR-0019/0020, PR …",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T03:41:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "086c138848e06461ac9d9b38ee884161fe58db5e",
          "body": "docs: design ADRs from the critical review (batch 5)",
          "is_bot": false,
          "headline": "Merge pull request #49 from bgrewell/docs/design-adrs",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:41:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8125347709aa3b8e70de769485bfc4a39f5fa715",
          "body": "fix: correctness cleanup (critical-review batch 4)",
          "is_bot": false,
          "headline": "Merge pull request #48 from bgrewell/fix/correctness-cleanup",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:40:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4960768896b93b1193a6eb058d05212cc01fb256",
          "body": "feat: optional shared-token control-plane auth (critical-review batch 3)",
          "is_bot": false,
          "headline": "Merge pull request #47 from bgrewell/security/control-plane-auth",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:40:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "49b0c263b0818cfeaa3da8c1b90271a7ba19f098",
          "body": "feat: bound agent resources + guard numeric parsers (critical-review batch 2)",
          "is_bot": false,
          "headline": "Merge pull request #46 from bgrewell/security/agent-input-bounds",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:39:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db62bdd45f9368622a216d810d81d60658f631d2",
          "body": "fix: agent flow lifecycle data race + panic containment",
          "is_bot": false,
          "headline": "Merge pull request #45 from bgrewell/fix/agent-flow-concurrency",
          "author_name": "Ben Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:38:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1f7c2a545fd6516c528f9dfb50d16e6d067fa4c",
          "body": "…atch 5)\n\nRecords the four architectural directions surfaced by the critical\nreview as Proposed ADRs to settle before implementing (no code change):\n\n- ADR-0019 batch-first datapath interface (align with DESIGN §5.1 before\n  the first NIC backend; define buffer ownership).\n- ADR-0020 per-packet RX m\n[…]\nbal mutable state; match the house DI/options standards).\n\nReconciles the DESIGN §5.1 batch-interface spec with the single-packet\nMVP via an implementation note, and schedules the ADRs in the roadmap.",
          "is_bot": false,
          "headline": "docs: ADRs for the design/future-proofing findings (critical-review b…",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T01:12:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b51840a214996ee967747505d31f8aefb06e20b1",
          "body": "- scheduler/interval: re-baseline to now when behind instead of releasing\n  a back-to-back catch-up burst that spikes the rate past target; add an\n  injectable clock for a deterministic no-burst test.\n- datapath/memory: Close no longer closes the channel (close-then-send\n  raced a concurrent Send an\n[…]\n subscribe goroutine.\n- controller: wrap each timeline fire in fireSafe so a placement panic\n  becomes an error instead of crashing the controller.\n\nTests added for each; full suite green under -race.",
          "is_bot": false,
          "headline": "fix: correctness cleanup from the critical review",
          "author_name": "Benjamin Grewell",
          "author_login": "bgrewell",
          "committed_at": "2026-06-14T00:26:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 17,
      "commits_last_year": 156,
      "latest_release_at": "2026-07-20T16:59:22Z",
      "latest_release_tag": "v0.11.0",
      "releases_from_tags": false,
      "days_since_last_push": 7,
      "active_weeks_last_year": 3,
      "days_since_latest_release": 7,
      "mean_days_between_releases": 3.9
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": false,
      "has_contributing": true,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/bgrewell/loom",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/bgrewell/loom",
          "is_deprecated": false,
          "latest_version": "v0.11.0",
          "repository_url": "https://github.com/bgrewell/loom",
          "versions_count": 17,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-20T16:56:40Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 7
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 7
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [
        "proto/loom/v1/control.proto"
      ],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 77235,
      "source_files_sampled": 228,
      "oversized_source_files": 1,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "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/BGrewell/go-conversions",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20260615151034-4f93f00cd275"
        },
        {
          "name": "github.com/asavie/xdp",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.3.3"
        },
        {
          "name": "github.com/bgrewell/stencil",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20260610184505-9b3d050c070e"
        },
        {
          "name": "github.com/vishvananda/netlink",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.3.1-0.20250303224720-0e7078ed04c8"
        },
        {
          "name": "golang.org/x/net",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.52.0"
        },
        {
          "name": "golang.org/x/sys",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.43.0"
        },
        {
          "name": "google.golang.org/grpc",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.81.1"
        },
        {
          "name": "google.golang.org/protobuf",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.36.11"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        },
        {
          "name": "gvisor.dev/gvisor",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20260717235516-4f55f3833ba5"
        }
      ],
      "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": 1,
        "merged_prs": 67,
        "open_issues": 6,
        "closed_ratio": 0.882,
        "closed_issues": 45,
        "closed_unmerged_prs": 1
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "bgrewell",
          "commits": 156,
          "avatar_url": "https://avatars.githubusercontent.com/u/4050562?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "docs.yml",
        "lxd.yml",
        "release.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "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": "14 out of 14 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/14 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "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": 0,
            "reason": "no 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": 0,
            "reason": "security policy file not 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": 0,
            "reason": "11 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "a394619801c796c7df70a979454bce3851887aa5",
        "ran_at": "2026-07-28T05:22:54Z",
        "aggregate_score": 3.2,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-20T16:59:26Z",
      "oldest_open_prs": [
        {
          "number": 91,
          "created_at": "2026-06-17T00:39:04Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-07-20T16:56:40Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 2,
          "created_at": "2026-06-11T14:59:33Z",
          "last_comment_at": "2026-06-11T16:40:37Z",
          "last_comment_author": "bgrewell"
        },
        {
          "number": 7,
          "created_at": "2026-06-11T19:53:20Z",
          "last_comment_at": "2026-06-12T20:36:15Z",
          "last_comment_author": "bgrewell"
        },
        {
          "number": 56,
          "created_at": "2026-06-14T20:27:45Z",
          "last_comment_at": "2026-06-15T23:14:46Z",
          "last_comment_author": "bgrewell"
        },
        {
          "number": 66,
          "created_at": "2026-06-15T17:13:59Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 117,
          "created_at": "2026-07-20T14:02:18Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 120,
          "created_at": "2026-07-20T19:20:56Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/bgrewell/loom",
    "host": "github.com",
    "name": "loom",
    "owner": "bgrewell"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 54,
      "inputs": {
        "security": 32,
        "vitality": 70,
        "community": 33,
        "governance": 57,
        "engineering": 67
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 70,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 56,
            "inputs": {
              "commits_last_year": 156,
              "human_commit_share": 1,
              "days_since_last_push": 7,
              "active_weeks_last_year": 3
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 7 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "3/52 weeks with commits",
                "points": 2.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 3
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "156 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 156
                    }
                  }
                ],
                "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": 17,
              "latest_release_tag": "v0.11.0",
              "releases_from_tags": false,
              "days_since_latest_release": 7,
              "mean_days_between_releases": 3.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "17 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 17
                    }
                  }
                ],
                "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 ~3.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 3.9
                    }
                  }
                ],
                "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": "excellent",
            "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": "at_risk",
        "name": "Community & Adoption",
        "value": 33,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 70,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "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 (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "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": 57,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "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 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 79,
            "inputs": {
              "merged_prs": 67,
              "open_issues": 6,
              "closed_issues": 45,
              "issue_closed_ratio": 0.882,
              "closed_unmerged_prs": 1
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "88% of issues closed",
                "points": 41.2,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 88
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "67/68 decided PRs merged",
                "points": 37.7,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 67,
                      "decided": 68
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/14 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "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": 54,
            "inputs": {
              "followers": 11,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "bgrewell",
              "public_repos": 124,
              "account_age_days": 4863
            },
            "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": "11 followers of bgrewell",
                "points": 7.8,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 11,
                      "login": "bgrewell"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "124 public repos, account ~13 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 124
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 13
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/bgrewell/loom"
              ],
              "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": "17 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 17
                    }
                  }
                ],
                "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": "moderate",
        "name": "Engineering Quality",
        "value": 67,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "14 out of 14 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": false
            },
            "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": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "at_risk",
        "name": "Security",
        "value": 32,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 32,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 3.2
            },
            "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": "14 out of 14 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/14 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "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": "no update tool detected",
                "points": 0,
                "status": "missed",
                "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 not detected",
                "points": 0,
                "status": "missed",
                "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": "11 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 61,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "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": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 56,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "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": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 77235,
              "source_files_sampled": 228,
              "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/228 source files over 60KB",
                "points": 54.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 228,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "good",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "api_schema_files": [
                "proto/loom/v1/control.proto"
              ]
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": "proto/loom/v1/control.proto",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "proto/loom/v1/control.proto"
                    }
                  }
                ],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T05:23:09.476874Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/bgrewell/loom.svg",
  "full_name": "bgrewell/loom",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

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 v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

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