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

nakagami / grdpsdl2

Microsoft RDP client

GoGPL-3.0★ 0 estrellas⑂ 0 forksdesde jun 2025Ver en GitHub ↗

nakagami/grdpsdl2 tiene un índice de salud de 43 sobre 100, lo que lo sitúa en la banda En riesgo. Su puntuación más alta es Vitality (82/100) y la más baja, Engineering Quality (21/100). Se actualizó por última vez hace 5 días. Una sola persona concentra la mayor parte del trabajo reciente.

43
global / 100
En riesgo

Í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.

43
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

Hajime NakagamiCuenta personal
74 seguidores84 repositorios públicosdesde sept 2010@beproud

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/nakagami/grdpsdl2v0.9.6-31hace 5 días

Métricas por categoría

Vitalidad

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

82Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 5 días
13.8/36Cadencia de commits — 20/52 semanas con commits
18/18Volumen de commits — 150 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year150
human_commit_share1
days_since_last_push5
active_weeks_last_year20
Cómo se puntúa
16.2/27Publica versiones — 31 etiquetas de versión (sin releases de GitHub)
36/36Recencia de las versiones — última versión hace 5 días
27/27Cadencia de publicación — una versión cada ~7,4 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count31
latest_release_tagv0.9.6
releases_from_tags
days_since_latest_release5
mean_days_between_releases7,4
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

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

24Crítico · 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 (GPL-3.0)
0/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_contributingno
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?

50Moderado · 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
6/10OpenSSF Scorecard: Contributors — project has 2 contributing companies or organizations -- score normalized to 6
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
23.4/46.8Resolución de issues — 50% de issues cerradas
0/38.3Aceptación de PR — sin PR decididos o sin datos
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs0
open_issues1
closed_issues1
issue_closed_ratio0,5
closed_unmerged_prs0
Excluidos de la puntuación (sin datos o no aplicable): Aceptación de PR. Los pesos restantes se han renormalizado.
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
13.5/25Alcance del propietario — 74 seguidores de nakagami
25/25Trayectoria — 84 repos públicos, cuenta de ~15 años
Datos de entrada utilizados
followers74
owner_typeUser
is_verified
owner_loginnakagami
public_repos84
account_age_days5779
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 5 días
20/20Historial de versiones — 31 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesgithub.com/nakagami/grdpsdl2
ecosystemsgo
any_deprecatedno
min_days_since_publish5

Calidad de Ingeniería

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

21Crítico · 20% del índice global
Cómo se puntúa
0/24Flujos de trabajo de CI
0/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_cino
has_testsno
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.

Documentación

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

Seguridad

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

28Crítico · 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
0/2.5CI-Tests — sin datos
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
1.5/2.5Contributors — project has 2 contributing companies or organizations -- score normalized to 6
0/10Dangerous-Workflow — sin datos
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — sin datos
0/5Pinned-Dependencies — sin datos
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — sin datos
0/7.5Vulnerabilities — 20 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2,8
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Los pesos restantes se han renormalizado.

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.

43En riesgo · 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)
35.7/40Historial de commits legible — 67 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,67
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)
0/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — Go (tipado estático)
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 73 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — sin datos
Datos de entrada utilizados
has_nixno
has_testsno
lockfilesgo.sum
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0,73
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Pinned-Dependencies. Los pesos restantes se han renormalizado.
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
0/55Tamaños de archivo manejables — 1/1 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes76.444
source_files_sampled1
oversized_source_files1

Datos clave

0estrellas de GitHub
1contribuidores
150commits en los últimos 12 meses
5días desde el último push
31versiones publicadas
1factor bus
1issues 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 2.8 / 10
2.8agregado

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-23 05:54 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
n/dCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
6Contributorsproject has 2 contributing companies or organizations -- score normalized to 6
n/dDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
n/dPackagingpackaging workflow not detected
n/dPinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
n/dToken-PermissionsNo tokens found
0Vulnerabilities20 existing vulnerabilities detected
Dependencias directas 2
RegistroPaqueteRestricción de versiónManifiesto
Gogithub.com/nakagami/grdpv0.9.4go.mod
Gogithub.com/veandco/go-sdl2v0.4.40go.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": 13986,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 76444
      },
      "pushed_at": "2026-07-17T07:25:47Z",
      "created_at": "2025-06-04T10:10:05Z",
      "owner_type": "User",
      "updated_at": "2026-07-11T00:21:33Z",
      "description": "Microsoft RDP client",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "GPL-3.0",
      "default_branch": "master",
      "license_spdx_raw": "GPL-3.0",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "https://about.me/nakagami",
      "name": "Hajime Nakagami",
      "type": "User",
      "login": "nakagami",
      "company": "@beproud",
      "location": "Funabashi, Japan",
      "followers": 74,
      "avatar_url": "https://avatars.githubusercontent.com/u/415278?v=4",
      "created_at": "2010-09-25T07:32:50Z",
      "is_verified": null,
      "public_repos": 84,
      "account_age_days": 5779
    },
    "license": {
      "state": "standard",
      "spdx_id": "GPL-3.0",
      "raw_spdx": "GPL-3.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.9.6",
          "kind": "patch",
          "published_at": "2026-07-17T07:25:05Z"
        },
        {
          "tag": "v0.9.5",
          "kind": "patch",
          "published_at": "2026-07-11T00:19:13Z"
        },
        {
          "tag": "v0.9.4",
          "kind": "patch",
          "published_at": "2026-07-10T23:31:12Z"
        },
        {
          "tag": "v0.9.3",
          "kind": "patch",
          "published_at": "2026-07-04T10:28:12Z"
        },
        {
          "tag": "v0.9.2",
          "kind": "patch",
          "published_at": "2026-07-04T02:39:20Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-07-04T01:40:56Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-07-02T06:11:56Z"
        },
        {
          "tag": "v0.8.2",
          "kind": "patch",
          "published_at": "2026-06-13T10:30:57Z"
        },
        {
          "tag": "v0.8.1",
          "kind": "patch",
          "published_at": "2026-05-16T07:38:06Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-05-12T02:46:27Z"
        },
        {
          "tag": "v0.7.3",
          "kind": "patch",
          "published_at": "2026-05-10T05:02:53Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2026-05-09T12:28:27Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2026-05-08T12:54:31Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-05-07T08:36:04Z"
        },
        {
          "tag": "v0.6.2",
          "kind": "patch",
          "published_at": "2026-04-23T10:44:03Z"
        },
        {
          "tag": "v0.6.1",
          "kind": "patch",
          "published_at": "2026-04-23T08:10:25Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-04-22T06:16:23Z"
        },
        {
          "tag": "v0.5.3",
          "kind": "patch",
          "published_at": "2026-04-22T03:55:26Z"
        },
        {
          "tag": "v0.5.2",
          "kind": "patch",
          "published_at": "2026-04-18T12:01:43Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2026-04-09T23:54:22Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-04-03T05:05:54Z"
        },
        {
          "tag": "v0.4.5",
          "kind": "patch",
          "published_at": "2026-03-27T05:39:52Z"
        },
        {
          "tag": "v0.4.4",
          "kind": "patch",
          "published_at": "2026-03-19T08:01:35Z"
        },
        {
          "tag": "v0.4.3",
          "kind": "patch",
          "published_at": "2026-03-19T08:01:35Z"
        },
        {
          "tag": "v0.4.2",
          "kind": "patch",
          "published_at": "2026-03-19T08:01:35Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-03-13T07:06:24Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-03-13T01:15:16Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2025-07-26T03:13:04Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2025-06-13T10:20:34Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2025-06-10T09:24:54Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2025-06-04T10:16:27Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "984af1b39cfc105eaac4673bb4f395aae61acb0c",
          "body": "On startup the server sometimes sends its first IDR before the desktop\nfinishes painting; that frame decodes as an all-black warm-up frame and\nis dropped, after which the server goes idle and the screen stays black\nuntil the ~30s reconnect watchdog fires (each reconnect restarting the\nsame black war\n[…]\nxisting stall watchdog no longer owns the never-shown\nreconnect trigger.\n\nRequires grdp v0.9.4 for the public RequestKeyframe API.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Add ForceRefresh-based black-screen startup recovery",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-11T00:19:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9be682defae79b6299cf94e25f4b1da337232a2b",
          "body": "…o v0.9.3\n\ngrdp v0.9.3 detects when the H.264 hardware decoder gets stuck emitting\nonly black/warm-up junk frames and falls back to software decoding, but\nif the SW fallback (or the server itself) also stays silent, the\nexisting video-stall watchdog treated it as a legitimately idle remote\ndesktop a\n[…]\nhe\nsession has been silent for videoStallTimeout without ever having shown\na frame, since that can no longer be legitimate idling.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Reconnect on video stall if no frame has ever been shown; bump grdp t…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-10T23:31:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4106cbb13900de8bea19c1156807f5ed873781a4",
          "body": "…noise\n\nWhen the H.264 hardware decoder stalls, grdp falls back to software decoding\nand the server sends full-screen BGRA bitmap patches. The SW decoder is often\nprimed with a stale cached IDR and produces persistent block-noise/mosaic\nframes that never resync on their own.\n\nDetect this state by tr\n[…]\nReconnect so the full-screen detection\nuses the current window size after a resize reconnect.\n\nBuild and vet pass with -tags h264.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: add SW fallback BGRA watchdog to recover from persistent block …",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T10:28:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5e4adea5fbe4f2f15d1466466a648314fdf439b1",
          "body": "…llback frames\n\nScrolling in the browser generated a burst of input that caused the RDP\nserver to send more video updates. The H.264 hardware decoder stalled\nunder the load, grdp fell back to software decoding, and the stale-IDR\nprimed SW decoder produced green-monochrome corrupt frames.\n\nCommit 86b\n[…]\nand V planes for I420. Corrupt frames are now held back and the\nprevious good frame stays visible instead of freezing the display.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: restore isNullYUVFrame guard to prevent freeze on corrupt SW fa…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T02:39:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c41cc47555179048b8c7ca8c2da4545232f167b2",
          "body": "Green-monochrome corruption is fixed upstream in grdp v0.9.2 by\nraising the low-chroma threshold to 72 and hardening AVC444 LC-2\nchroma-plane validation.  Switch from the local replace directive to\nthe published release.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Use grdp v0.9.2 and remove local replace",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T01:40:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ca5965b5d5a103053742fd50701810f9a4b7cb46",
          "body": "Temporarily replace the published grdp dependency with the local tree\nso the AVC444 LC=2 chroma-validation fixes can be exercised before a\nnew grdp release is tagged.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "go.mod: use local grdp for LC=2 chroma guard testing",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T01:22:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "86b6b25322e4413fb66dbe6f8e2f04b03ea1ccf4",
          "body": "The ffmpeg decoder in grdp v0.9.1 now drops green-monochrome frames\nbefore they reach the callback, so the last-line isNullYUVFrame check\nin main.go may be redundant.  Remove it temporarily to verify that\ncorruption is fully handled upstream.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: remove isNullYUVFrame guard for testing",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T01:03:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7ea604a0a005bfe59497b3e0dfac7ffd0166e987",
          "body": "- Update github.com/nakagami/grdp from v0.9.0 to v0.9.1\n- Import grdp/plugin/rdpgfx/ffmpeg instead of the local copy\n- Delete plugin/rdpgfx/ffmpeg/h264_ffmpeg.go (duplicate decoder)\n- Keep isNullYUVFrame in main.go as a last-line SDL2 upload guard\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Use grdp v0.9.1 ffmpeg plugin and remove local duplicate",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-04T00:57:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9132ef0573f28364d292ccec0d8f64855eaf241c",
          "body": "v0.9.0 carries the AVC444 green-frame fixes: dropping near-zero-chroma\nSW frames regardless of luma, and keeping the SW-fallback stale-prime\ntracking armed until a real IDR resync. Drop the local replace\ndirective now that the fixes are released.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "go.mod: bump grdp to v0.9.0",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T06:11:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b91894855ac597b821861d0abb3fc665824fc079",
          "body": "During a VideoToolbox HW stall the decoder falls back to software and\nprimes with a cached (stale) IDR. Live P-frames then reference a\nmismatched DPB state, producing frames with near-zero chroma\n(e.g. Y=75, U=0, V=2). BT.709 conversion of Cb≈0,Cr≈0 yields\nBGRA(0, Y+84, 0) — a full-screen green-mono\n[…]\nback. Drop when U<4 && V<4\nregardless of luma; both chroma planes collapsing to ~0 never occurs in\nreal content at any brightness.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "rdpgfx: drop near-zero-chroma SW frames regardless of luma",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T05:56:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e04173d97ff8c00f6885f532ec742f47c73aa36e",
          "body": "- Drop SW-decoded frames where U<8 && V<8 && Y<32 to avoid green\n  screen after VideoToolbox stall + stale IDR fallback.\n- Update grdp dependency to v0.8.10 and remove local replace.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "rdpgfx/ffmpeg: detect near-zero UV corruption and bump grdp to v0.8.10",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T04:14:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "04a681462203b8094df936afa67425ab3efc7870",
          "body": "The SW decoder fallback on macOS outputs YUV420P, which grdp converts to\nBGRA using hand-written BT.601 coefficients. Meanwhile the HW NV12 path\nis rendered by SDL2 with BT.709, causing a visible color shift on SW\nfallback. Update all NEON/SSE2/scalar paths and the helper pixel macro to\nuse BT.709 coefficients so the two paths match.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Switch hand-written YUV→BGRA conversion to BT.709 coefficients",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T03:45:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "08ecf1a953bf7458fc75e3d370b786077bae2fca",
          "body": "Pick up the tighter stale IDR fallback limit (3 drops) and earlier\nVideoToolbox stall detection (15 null frames).\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Bump grdp to v0.8.9",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T02:08:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "78425abcf6411b0258ecf338f8110310747807f5",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Update go.sum for grdp v0.8.8",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T01:50:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e1f38fca19afa5e6f323a10b6bcdeaab352741ab",
          "body": "Add a -disable-avc444 command-line option that calls\nrdpClient.DisableAVC444(), allowing users to fall back to AVC420 only when\nAVC444 causes display corruption.\n\nAlso tighten the VideoToolbox HW stall detection thresholds in the local\nFFmpeg backend:\n- avcHWReadyFreezeThreshold: 7s -> 5s\n- avcHWRec\n[…]\n 500ms -> 300ms\n- avcHWMidSessionNullFrameLimit: 30 -> 20\n\nBump grdp dependency to v0.8.8 to pick up the stale IDR validation fix.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: add -disable-avc444 flag and tighten HW stall thresholds",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-07-02T01:46:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fcbe44b239804fa71790b4eaf7808be2972bed19",
          "body": null,
          "is_bot": false,
          "headline": "bump up grdp v0.8.7",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-13T10:30:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dbbd750eb464b184a7cef885024715abb42dbe15",
          "body": "SDL2 AUTOMATIC mode selects BT.601 for SD (≤1000×600) and BT.709 for HD.\nCalling sdl.SetYUVConversionMode(YUV_CONVERSION_BT709) before creating the\nYUV texture ensures the Metal renderer always uses BT.709 limited-range\ncoefficients, matching the combineAVC444v2BGRA path (also now limited BT.709\naft\n[…]\nnion grdp fix).  Without this, a low-resolution RDP session\nwould see BT.601 from SDL2 but BT.709 from LC=2, causing colour shift.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: force SDL2 BT.709 YUV conversion mode for all resolutions",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-10T04:46:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4f0d842e8ba337ce891b7ff0b1f5ce2ad983773b",
          "body": "…is freed\n\ndrainPreLock had a race condition: calling yuvWriteWg.Wait() first\nallowed a callback to call Add(1), receive the stage from yuvStageCh,\nand spawn write goroutines after Wait() returned (counter was 0 at\nthe time of the call).  Those goroutines then raced with the imminent\nyuvTexture.Dest\n[…]\nred renderer.Destroy() could free the\nMetal buffer while NV12 write goroutines from the last pre-lock\ncallback were still running.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: prevent NV12 goroutine use-after-free when Metal staging buffer …",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-10T01:10:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8f1dcdf84b71f94ed7c87db726ffca47d3e2d8b6",
          "body": "Three related fixes for the software (YUV420P) H.264 decode path used when\nVideoToolbox falls back to software decoding:\n\n1. Y-cache refresh via LastI420() (SW + NV12 path)\n   extractI420fromSrc is now also called when outNV12Enabled and the source\n   format is YUV420P/YUVJ420P (not NV12), populatin\n[…]\natch can persist across many frames until the server delivers a fresh\n   IDR.  Cost: one C.grdp_sample_yuv call per YUV420P frame.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "h264_ffmpeg: fix SW decoder zero-frame drops and AVC444 Y-cache refresh",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-06T08:58:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3b47892139805e2ff990890b3f10d2280f076e73",
          "body": "Restores the original sync.WaitGroup + go func() approach for the\nparallel Y/UV plane copy in OnH264NV12.  The channel-based pool was\nlogically equivalent but caused image garbling in practice; revert\nto the proven approach.\n\nKeeps the paintImages single-pass loop optimization from the same\ncommit — that change is independent and unaffected.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Revert persistent Y/UV copy pool (caused image corruption)",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-05T07:19:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7a867ad858eaac6b8058fc4f9c127e4be652789b",
          "body": "- paintImages: merge two-pass loop into single pass, eliminating\n  redundant iteration over bs (O(2N) -> O(N))\n\n- OnH264NV12 fast path: replace per-frame sync.WaitGroup + go func()\n  pair with a persistent 2-goroutine pool dispatched via channels.\n  Eliminates ~2 closure heap allocations per frame (~120 allocs/s at\n  60 fps) and avoids goroutine creation overhead on every H.264 frame.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Optimize paintImages single-pass loop and persistent Y/UV copy pool",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-05T07:10:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6ec25e5168ab8fd336faa7139230b5c504c3dbaf",
          "body": "…re per rect\n\ngo-sdl2's Texture.Lock with a subrect computes the returned slice\ncapacity as:\n  bytesPerPixel * (textureWidth*(rect.H-1) + rect.W)\nusing the texture's query width, not the actual SDL pitch.  On macOS\nwith the Metal renderer, SDL pads texture rows to an alignment boundary\nso pitch > te\n[…]\nas the existing Tier-3 and\nLock-failed fallback paths).  The large-dirty-area Tier-1 full-screen\nwipe is retained as the hot path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: replace Lock-based Tier-2 clearOverlayDirty with SDL_UpdateTextu…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-02T04:24:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b357e796807b54245721f09129252a465be6a026",
          "body": "… and data race\n\nWhen VideoToolbox decodes H.264, the frame height is rounded up to a\n16-pixel multiple (e.g. 1072 for a 1060-row display).  The fast-path\nYUV copy used the decoded height h instead of stage.th (the texture\nheight), which caused two bugs:\n\n1. Buffer overflow: uvLen = pitch*(h+1)/2 = \n[…]\npyPh = (copyH+1)/2 for\nall plane copies.  Applied to both NV12 and I420 paths (fast-path\nparallel/serial and slow-path row loops).\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: clip NV12/I420 copy height to texture bounds to prevent overflow…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-02T03:53:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4d6829e1da4c90b92561954d442d4329fc521e01",
          "body": "… paths\n\nOpt 2 — Parallel uploadYUVFrame / primary staging copies:\n  In uploadYUVFrame NV12 fast-path, run the Y and UV copy() calls in\n  concurrent goroutines (guarded by sync.WaitGroup) so both planes are\n  written in parallel.  Same treatment for the I420 fast-path (3\n  goroutines for Y/U/V).  A \n[…]\nand reused across patches so at most one allocation occurs per\n  call regardless of how many legacy-bpp patches arrive in a frame.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: parallel YUV plane copies in uploadYUVFrame and primary staging…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-01T02:30:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "11af45722712acc1e3e720aa3d5e82f09b7d0835",
          "body": "Replace the scalar per-byte R/B swap loop in paintImages with a single\ncall to grdp.SwapRB, which reuses grdp's SIMD batch converter (NEON on\narm64, SSE2 on amd64) to convert the RGBA image buffer to the BGRA byte\norder expected by the SDL_PIXELFORMAT_BGRA32 texture in one vectorised\npass.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: use grdp.SwapRB SIMD for legacy bitmap R/B swap",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-01T02:07:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9dd0e6eb2bdad5801cc4c0a8a8ab92dbf8e55a55",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Move plugin/rdpgfx/ffmpeg from grdp into grdpsdl2",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-06-01T00:19:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dfe37e8aa41566d396bbf09d54f95dc20b7924d3",
          "body": "SDL_LockTexture on macOS/Metal returns a zero-initialised staging buffer\nrather than the existing texture content.  The previous multi-patch lock\npath wrote black over all pixels inside the bounding rect that were not\ncovered by a bitmap patch.\n\nRemove the Lock path entirely.  All bitmaps (fast-path\n[…]\nPixel==4)\nare now uploaded with individual SDL_UpdateTexture calls, which are\nread-modify-write and only touch the specified rect.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "paintImages: always use per-patch SDL_UpdateTexture, remove Lock path",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T23:40:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6641973d0c191d1ca8d1eb180528591da2278408",
          "body": "…ap batches\n\nOn macOS/Metal, SDL_LockTexture returns a new zero-initialised staging\nbuffer, not the existing texture content.  When the lock rect covers a\nlarge area but the actual bitmap patches are sparse (e.g. one patch in\nthe middle of the screen + one small patch in the taskbar), all pixels\nins\n[…]\n dense batches (e.g. row-tiling that fills the lock rect at ≥ 75%),\nthe Lock path is still used for its CGo-call-count efficiency.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "paintImages: fall back to per-patch SDL_UpdateTexture for sparse bitm…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T23:37:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "551dfd08c617be3321d0b62a2923fa61d209e632",
          "body": "paintImages: handle empty pixels slice after SDL_LockTexture\nOn macOS/Metal, SDL_LockTexture returns pitch=lockRect.W*bpp instead of\ntextureWidth*bpp, causing go-sdl2 to compute a slice length of 0 via\ninteger truncation.  Accessing pixels[0] on an empty slice panics.\nWhen len(pixels)==0 after a suc\n[…]\nand reset to false only on a Tier-1 full-texture clear or\nreconnect.  Use it in the render condition instead of overlayDirtyRects.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix paintImages panic and black overlay outside video area",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T23:11:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "80641e5552b087f6375f763d65c52a8732279f20",
          "body": "After a server-initiated disconnect (MCS DISCONNECT_PROVIDER_ULTIMATUM)\nthe read goroutine emits a follow-up \"use of closed network connection\"\nerror.  Both were logged at ERROR level even though they are expected\nduring the normal reconnect flow.\n\n- Use CompareAndSwap on connectionErrorPending so o\n[…]\nrade the first error from Error to Warn because connection drops\n  are handled by the watchdog reconnect path, not fatal failures.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Suppress cascading OnError noise and downgrade to Warn",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T15:39:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a7ebc936d9198d4548bafcc533bb56b06de7026a",
          "body": "On macOS, SDL_LockTexture returns pitch = lockRect.W * bpp (not\ntextureWidth * bpp).  go-sdl2 computes the slice length as\n  (pitch / textureWidth) * (textureWidth*(H-1) + W)\nwhere the integer division pitch/textureWidth truncates, producing\na slice that is too small by roughly (textureWidth - lockR\n[…]\nafe.Slice — the SDL allocation covers pitch*lockRect.H bytes,\nwe are just correcting the Go slice header to reflect the true size.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix paintImages: correct pixels slice length on macOS/Metal",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T15:19:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "25590e4292609d412139434d9cd7dbd125f68f65",
          "body": "- Replace N SDL_UpdateTexture calls with single Lock/Unlock when\n  multiple BGRA bitmaps arrive in one render tick (O(N)→O(1) cgo)\n- Clamp bounding rect to texture bounds to handle off-screen bitmaps\n  (negative DestTop/DestLeft from partially off-screen RDP windows)\n- Add per-bitmap visible-region \n[…]\nError bounds-check guard with diagnostic fields instead of\n  panicking; slog.Debug logs lockRect and per-bitmap coords for tracing\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "optimize paintImages: batch Lock + add bounds-check logging",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T15:16:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4fa1ed44fc35e008e0a6f2c80d1e9d14d59e2da1",
          "body": "Previously maxBitmapBatchesPerTick=1 meant a burst of 32 batches\ntook ~512ms to drain (32 × ~16ms ticks). Now all pending batches\nare drained and combined into a single paintImages() call per tick,\neliminating catch-up lag and reducing total cgo call count per frame.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Drain all pending bitmap batches in one tick for lower latency",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T14:40:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bf413dec472ab2675fd68086da476828c38165ba",
          "body": "Replace N SDL_UpdateTexture calls with a single Lock/zero/Unlock\nfor the common case of multiple dirty overlay rects, reducing cgo\ncrossing overhead.\n\nThree-tier strategy:\n1. Total dirty area > half screen -> one full-texture SDL_UpdateTexture\n2. Multiple dirty rects           -> lock bounding rect \n[…]\nice bounds panic whose root cause could not be determined.\npaintImages retains the original per-bitmap SDL_UpdateTexture approach.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Optimize clearOverlayDirty with bounding rect Lock",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T14:36:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "094f730e4d2cfd18a4fc309b8ce14e42786f9669",
          "body": "- Change preLockYUV to return (yuvStage, bool) instead of *yuvStage,\n  and yuvStageCh to chan yuvStage, eliminating ~60 heap allocations/sec\n  on the H.264 rendering hot path.\n\n- Remove 8ms busy-polling during active rendering (renderDirty > 0).\n  H.264 and bitmap callbacks already push SDL wake eve\n[…]\nsed int(t.Button-1)\n  (uint8 subtraction before cast) while MouseDown used int(t.Button)-1.\n  Unified to int(t.Button)-1 for both.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "optimize: reduce CPU usage and eliminate per-frame heap allocation",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T13:56:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e115d949c738973d1a9b44e5a4bad77d15b731fd",
          "body": "When the server drops the TCP connection (e.g. \"connection reset by peer\"),\nOnError now sets connectionErrorPending. The video stall watchdog (10 s)\ndetects the flag and triggers a Reconnect instead of just logging, so the\nsession recovers automatically instead of staying black forever.\n\n- Add conne\n[…]\n before (idle desktop should not cause spurious reconnects)\n  If Reconnect fails, re-arm the flag so the next stall cycle retries.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: auto-reconnect after connection reset (black screen fix)",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T12:56:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "20b491ddb317af337db0108a76fbc48c24701c98",
          "body": "…ntions\n\n- preLockYUV: eliminate duplicate var bufLen and duplicated return statement\n- paintImages slow path: cache img.Bounds() to avoid double call\n- OnPointerUpdate: replace conditional alpha with truly branchless arithmetic\n  ((uint(b|g|r)+255)>>8)*255 — no branch, no CMOV ambiguity\n- Rename ph_tex→phTex, swap_alt_meta→swapAltMeta, trans_alt_meta→transAltMeta\n  to follow Go naming conventions\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "optimize: simplify preLockYUV, fix branchless alpha, fix naming conve…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T12:54:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "954daac0f21ec43e4a6d3a73c958d7c7e973ca46",
          "body": "Add a -debug CLI flag that enables slog debug-level output, making it\neasy to capture verbose logs without recompiling.\n\nAlso add maxBitmapBatchesPerTick (= 1) to limit how many bitmap update\nbatches are flushed to the GPU texture per render loop iteration.\nPreviously all pending batches were draine\n[…]\n spike when VirtualBox sends a large burst of updates.\nLimiting to one batch per tick spreads the GPU writes evenly across\nframes.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "main: add -debug flag and limit bitmap batches per render tick",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T10:25:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f1a52212cbfe77e3b28ed24ef828757ac14f72c7",
          "body": "Instead of calling sdl.GetClipboardText() every second, handle\nthe SDL_CLIPBOARDUPDATE event (fired by SDL2 whenever the clipboard\nchanges) in the event switch.  This eliminates periodic wakeups and\nsyscalls entirely.\n\nsdl.SetClipboardText() (server→client path) also triggers\nSDL_CLIPBOARDUPDATE; gr\n[…]\nt self-notification so no echo loop occurs.\n\nRemove lastClipboardText and lastClipboardCheck variables which are\nno longer needed.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Replace clipboard polling with SDL_CLIPBOARDUPDATE event",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T08:53:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1de5251dc425772927951fe98ab29dd5eb85cb1a",
          "body": "- renderDirty counter (init 3): skip Clear/Copy/Present when idle;\n  only re-render while dirty, decrement after each Present.\n  Eliminates redundant GPU work on idle remote desktops.\n- Adaptive WaitEventTimeout: 8 ms when active, 50 ms when idle.\n  H.264/bitmap callbacks wake the loop via PushEvent\n[…]\nbitrary 8-rect limit.\n- Clipboard poll interval: 500 ms -> 1 s.\n- Pre-allocate decoderBrokenEvent to avoid heap alloc in callback.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Reduce CPU usage with rendering and memory optimizations",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T08:51:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "86514446391b222202d086b4faefc8e51486f9b4",
          "body": "The H.264 decoder implementation now lives entirely in the grdp library.\ngrdpsdl2 imports it with a blank import so the init() function registers\nthe backend via rdpgfx.SetH264Backend.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Remove duplicate h264_ffmpeg.go; use grdp/plugin/rdpgfx/ffmpeg instead",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T08:15:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3d9627e35a6b9f619b1387814039f665a62c5989",
          "body": "…out 3s→1s\n\nVideoToolbox stalls at a specific video position (observed: hwSentCount ~422–582)\nand the Windows Server in AVC444 mode does not send IDR in response to\nForceRefresh (SuppressOutput toggle).  The root cause (VT stall + no server IDR)\nis not fixable on the client side, but the visible fre\n[…]\noft-reset retry and goes straight to reconnect, so 1 s is sufficient.\n\nResult: total visible freeze reduced from ~6.1 s to ~2.5 s.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Reduce VT stall freeze time: null-frame limit 75→30, SW fallback time…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-24T08:10:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2ac10d82518b0b092bc15a64196ffad2365f4630",
          "body": "Normal GOP boundaries produce at most ~25 consecutive null frames at 30\nfps.  The previous 150-frame threshold (~5 s) was chosen to stay 2 s\nunder the 7-second safety valve, but it means a genuine VideoToolbox\nmid-session stall is not detected until ~5 s of blank output.\n\n75 frames (~2.5 s at 30 fps\n[…]\n skip in SW fallback\nmode (grdp), this reduces the total visible freeze by ~5.5 s in the\ntypical VT-stall-then-reconnect scenario.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "h264: reduce avcHWMidSessionNullFrameLimit from 150 to 75",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-21T01:11:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "457010843d1f065a7f807416737b49a138dc67b7",
          "body": "The early-window null-frame stall probe (earlyStall) triggered after\n25 consecutive null frames regardless of wall-clock time.  At high\npacket rates (e.g. bursts at session start), 25 frames could arrive in\nunder 200 ms — well before VideoToolbox finishes initialising its\npipeline (~1 s).  This caus\n[…]\nctly.\n\nThe hwReady=false path (initial VT init failure) is unaffected;\nit is covered by the existing avcFreezeThreshold=6 s check.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "h264: add time gate to early-window HW stall probe",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-19T13:44:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "60431225f1fa57b15da1732c099ce1fe468a1464",
          "body": "- Add SSE2 inline helpers (grdp_yuv_to_bgra_sse2_core,\n  grdp_nv12_to_bgra_sse2_8, grdp_yuv420p_to_bgra_sse2_8) and\n  #elif defined(__SSE2__) branches in all 6 YUV→BGRA conversion\n  functions.  On x86_64 this accelerates the region-hint code path\n  that bypasses swscale, using _mm_madd_epi16 for 8 p\n[…]\nrs.\n\n- Merge double time.Now() call when hwSentCount==1 into a single\n  hwNow variable shared by hwFirstSendTime and lastSendTime.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: SSE2 YUV→BGRA, goroutine pool, time.Now() dedup",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-19T10:27:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "327024f386e716fd8d3ca2ff9c9b1f35cd85760f",
          "body": "grdp_copy_yuv420p_to_i420, grdp_copy_nv12_to_i420, grdp_copy_nv12,\ngrdp_yuv420p_to_bgra_regions, grdp_nv12_to_bgra_regions,\ngrdp_frame_to_bgra, grdp_sample_nv12, grdp_sample_yuv, and\ngrdp_sample_nv12_at are all pure C functions that never call back into\nGo, but were missing the #cgo nocallback direc\n[…]\nows\nthe Go runtime to skip the goroutine-stack-switch bookkeeping on each\ncall, reducing CGo call overhead on the hot decode path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "cgo: add missing nocallback annotations to pure C functions",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-19T04:37:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6d78fd8941d22f3ffe4cf01b20e31d10a3b56136",
          "body": "Three changes to reduce per-frame CPU cost on ARM64 and x86_64:\n\n1. x86_64 region-aware conversion: when dirty-region hints are provided,\n   use the hand-written BT.601 region loop instead of running swscale over\n   the entire frame.  swscale has no partial-frame API, so a typical\n   cursor-update r\n[…]\nt and\n   reduces the per-row scalar pre-loop from up to 15 pixels to up to 7,\n   allowing the NEON 16-pixel loop to start earlier.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "cgo: optimize YUV→BGRA conversion in hot NEON paths",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-19T01:52:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "81e08c27c4e1c7a7fe446abb5d7c6ff0cec0ff2e",
          "body": "…place\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Update keyframeWaitTimeoutSWFallback to 3s and activate local grdp re…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-18T00:03:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "380c87b2e06f115ab8fe64735c53d44c59fa877a",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Update go.sum for missing grdp module entries",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T01:01:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c5a60d2fe74c62bca5e795c0ad2f032f6bc251df",
          "body": null,
          "is_bot": false,
          "headline": "comment out replace",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T00:58:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a790d5a58759a5665f037367043d8a41c582ba71",
          "body": null,
          "is_bot": false,
          "headline": "disable debug log output",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T00:43:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3bf80820ab08364d51e1ae303300a2becb50d6dc",
          "body": "After all internal recovery attempts are exhausted (HW stall → SW\nfallback → keyframe requests timeout), grdp fires OnDecoderBroken.\nAt that point the server will not send a new IDR without a full TCP\nreconnect, so the image freezes permanently.\n\nRestore the decoderBrokenPending atomic flag: the cal\n[…]\n\nAlso commit go.mod/go.sum changes: replace directive pointing to the\nlocal ~/grdp repo (for development) and bump to grdp v0.8.5.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Restore reconnect on OnDecoderBroken; use local grdp replace",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T00:40:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8b3372fad201ff4da6542b0099a12e839d0b1b0e",
          "body": "OnDecoderBroken triggered a full TCP reconnect when the HW H.264\ndecoder stalled and SW fallback could not obtain an IDR within 1 second.\nThis caused an unnecessary visible freeze: the server was still active\nand would have sent an IDR shortly after the ForceRefresh request.\n\nReconnection is now lim\n[…]\niodic keyframe requests\nuntil the server delivers an IDR, at which point decoding resumes\nwithout tearing down the TCP connection.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Remove decoder-broken reconnect; reconnect only on window resize",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T00:22:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "93602b738bd919df4fc26e76537b65bcff9c1ece",
          "body": "The I420 and NV12 fast paths in convertFrame() ran before the\nhwNeedsZeroCheck (lines ~2177), so zero-filled VideoToolbox IOSurfaces\ncould bypass the UV=0 drop guard.\n\nTwo problems resulted:\n\n1. Y≠0, UV=0 (partially-initialised IOSurface): isNullYUVFrame only\n   triggers when both Y AND UV are zero,\n[…]\nnalling grdp to skip the I420\ncallback and Y-cache update.  If UV≠0, clear hwNeedsZeroCheck and\nproceed with extraction as before.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix green frame: apply hwNeedsZeroCheck in NV12/I420 fast paths",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-17T00:13:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5bf354849d40b478c45c181f4d91c3804e70cfe8",
          "body": "- Add renderer.SetDrawColor+Clear before each Present so the initial\n  uninitialized renderer background (seen as static/snow before the\n  first RDP frame) is replaced with black.\n- Add yuvTextureIsNull flag: set true when a null frame (Y=0,UV=0=green)\n  is uploaded to yuvTexture, false when a valid\n[…]\ng is set so the green\n  artifact introduced by always-Present is never displayed.\n- Reset yuvTextureIsNull in resetAfterReconnect.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix initial snow and green film on null H.264 frames",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T14:47:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "647cc522cd2e4f7e2ca86ded40122e0bd2f22bc2",
          "body": "- On OnDecoderBroken, set decoderBrokenPending flag and wake the SDL\n  main loop; the main loop then calls Reconnect to recover the H.264 stream.\n- Always call renderer.Copy + renderer.Present every loop iteration so\n  the last frame stays visible during video stalls (matches gxui.go behaviour).\n- Remove dirty flag and commented-out video-stall reconnect code.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix screen freeze on decoder broken and video stall",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T14:39:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c961300f48cfab4f1f67b29fc773c424d403b00b",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Log a warning when the decoder is broken",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T14:16:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2d41fb85406872a20e5d323e8ca87f592ddb3a17",
          "body": null,
          "is_bot": false,
          "headline": "Remove the reconnect process",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T13:30:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bdbf0cbb348d4fb34e23c09b8508035c2f1e4f80",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.8.3",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T07:38:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "11fdbe7e0a2cf66144729ab030a4bf62447eb4b5",
          "body": "- Add grdp_yuv420p_to_bgra_neon_16 / grdp_nv12_to_bgra_neon_16:\n  process 16 luma pixels per NEON iteration (was 8) by loading a\n  full uint8x16_t and splitting into low/high halves.\n\n- Update all inner loops (grdp_yuv420p_to_bgra, grdp_nv12_to_bgra,\n  and their _regions variants) to try the 16-pixe\n[…]\nn small inputs.\n\n- Replace direct C.grdp_{nv12,yuv420p}_to_bgra calls in convertFrame\n  with parallelConvertRows + _rows variants.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: NEON 16px loop, SSE2 UV deinterleave, row-parallel YUV→BGRA",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-16T03:21:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "91472ac8b9e12d3158782bcb0314c76166e3274d",
          "body": null,
          "is_bot": false,
          "headline": "optimize",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-14T10:18:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ca98a6a5fdbc38504723b3bc4f70eb1454715635",
          "body": null,
          "is_bot": false,
          "headline": "add more #cgo nocallback",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-14T07:51:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4147bd35640891116d6c28916bfefd0940016d5f",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.8.1",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-13T06:57:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6efff44c8d60c92e7704bdbc3037d299fbf58247",
          "body": null,
          "is_bot": false,
          "headline": "Comment out the debug log output",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-12T02:46:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eae48072582e8c5bdcb093fbe6609095f51f76d8",
          "body": "Without -tags h264 the binary uses software-only rendering.\nH.264 HW decode requires FFmpeg and 'go install -tags h264'.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "README: document h264 build tag and FFmpeg requirement",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-12T02:45:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5c77815639199e6e796e72e5d7f1e1f4e966add4",
          "body": "grdp v0.8.0 moved all CGo FFmpeg/VideoToolbox H.264 decoder code out of\nthe plugin and into the application layer, requiring the app to register\na backend via rdpgfx.SetH264Backend() in an init() function.\n\nWithout this registration, no H.264 decoder (HW or SW) is created, so\nthe server falls back t\n[…]\ngrdp\nexample, which contains the CGo FFmpeg/VideoToolbox decoder and calls\nrdpgfx.SetH264Backend() in init() to restore HW decode.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Add h264_ffmpeg.go: register H264DecoderBackend for grdp v0.8.0 DI",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-12T02:33:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9b245d156e46bdb19e0ab1a5555ad46038379334",
          "body": null,
          "is_bot": false,
          "headline": "tuning",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-10T12:19:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a64097fd4bc7f3664583d83a26bac2c5546510aa",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.30",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-10T10:08:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e7446e732deb92aae76f8ebc91970c57688246a",
          "body": "- NV12/I420 primary path: detect null frame before copying data.\n  Instead of writing Y=0,UV=0 (green in BT.601) into the staging\n  buffer, fill UV with 128 (neutral chroma) so Unlock commits black.\n- Main loop: do not call clearOverlayDirty() for null frames.\n  Null frames must not erase existing bitmap patches from the overlay.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix green flash from VideoToolbox null frames",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-10T05:02:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5b187b854eccb08b6b7b3fd5b978bdfb311dc953",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.28",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-10T04:26:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6ba07462beefe024a54252c7d880bec3959c9384",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.28",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-10T01:31:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c9e3fbe29e4c57cf921a477b312d9876ceeb69be",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.27",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T12:28:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0ca53c8f1b18b2ef64db929dbcbfd8a5f641c8a6",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.26",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T10:28:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09826422da347b3af9e8558c8d087f546659f4a0",
          "body": "- NV12/I420 callbacks: move yuvWriteWg.Add(1) before the select, Done()\n  in the default branch, eliminating the narrow window where drainPreLock\n  could return between the stage-channel receive and the first write.\n\n- Track fullTexture (fastPath && h==stage.th) in yuvDone; when the frame\n  covers t\n[…]\nxt preLockYUV skips the ~1 MB UV memset (neutral chroma init).\n  Partial frames and null frames still initialise chroma as before.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: skip UV chroma init for full-texture frames; fix yuvWriteWg race",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T10:02:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "771a29ad00688c7776431aac588ea58c2afdd0d9",
          "body": "- Update grdp to v0.7.25 (lc2EverDecoded: no reconnect when LC=2 never worked)\n- audioPlayer: reopen device on 'Invalid audio device ID' via main-thread flag\n- resetAfterReconnect: clear reopenNeeded and reset audio queue after reconnect\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: LC=2 reconnect loop suppression and audio device recovery",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T09:50:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "df69c3c71554149770a466f0943a97df3c533048",
          "body": "sdl.AudioCVT embeds C filter-function pointers in its filters array.\nStoring it as a persistent struct field keeps those C pointers on the\nGo heap between calls, which can interact unexpectedly with the GC.\n\nRefactor: remove cvt sdl.AudioCVT from audioPlayer.  Instead allocate\na local sdl.AudioCVT i\n[…]\nth stays O(1).\nFormat changes are rare (usually once per session) so calling\nBuildAudioCVT twice on a format change is negligible.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "audio: keep AudioCVT as local var, not struct field",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T09:17:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "28a2bba8d4fafc14996eed7c81d5b72c3fa20626",
          "body": "When VideoToolbox flushes its pipeline at IDR/GOP boundaries, it emits\na handful of null frames (Y=0, UV=0).  In BT.601 that maps to\nRGB(0,136,0) — a bright green — so uploading those frames to the GPU\ntexture and then rendering them as the H.264 background causes visible\ngreen flicker in the video \n[…]\nof\n  uploading green data and setting yuvReady/dirty.  The previous real\n  frame stays in the texture, avoiding any visible flash.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: suppress green flicker from VideoToolbox null frames",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:48:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "98f7d0884a67f3d04bdd176f1e041b171d05429d",
          "body": null,
          "is_bot": false,
          "headline": "add .gitignore",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:36:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8551284bca3175aae7744aa101b2a930dfc07a7a",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "chore: untrack personal helper scripts w and u",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:34:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dde1bf34b29243050e3a89d83e9e5739fb2e3696",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "chore: remove binary and add to .gitignore",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:32:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "42d1e129cce6502166907aeb5f43477dc696d038",
          "body": "Metal's staging MTLBuffer pool may return a freshly zeroed buffer on\neach lock.  The 1e08760 optimisation skipped the ~1 MB UV memset when\nthe previous frame was full-screen (fullFrame=true), assuming the\ncallback had overwritten every UV byte.  However, the *next* lock\nacquires a new buffer whose U\n[…]\nevery re-lock.\nRemove the now-unused fullFrame field from yuvDone and the related\nlocal variables in both NV12 and I420 callbacks.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: always init chroma=128 on re-lock to prevent green flicker",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:23:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "39ffc03b2c21c1f94dc347fa21760229081a1dfb",
          "body": "…in clamps\n\n- Pre-allocate wakeEvent once instead of heap-allocating &sdl.UserEvent{}\n  on every H.264/bitmap callback (up to 60 allocs/sec at video framerate).\n- Precompute fastPath/fullFrame booleans in NV12 and I420 primary paths\n  so the condition is evaluated once instead of twice per frame.\n- Replace manual if/clamp with min() builtin in paintImages slow path,\n  matching the style already used in the fast path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "optimize: pre-alloc wake event, precompute fast/fullFrame, simplify m…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T08:14:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3e4f51c2166ce14f91759f03081b746fb23f3186",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.24",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T07:56:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5fc87b213fe301a2a24ec928281c26e24e237267",
          "body": "- go fix ./...: interface{}→any, rangeint, minmax modernizers\n- go mod tidy: update go.sum for Go 1.26.3\n- Upgrade go/toolchain directives to 1.26.3\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "style: apply Go 1.26 modernizers; upgrade Go to 1.26.3",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T07:54:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "74eabe10401a468e260f17960f2e347567b0ce75",
          "body": "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Update grdp to v0.7.23",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T07:48:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1e0876023b7823f8944e695652d14ef51976b2c7",
          "body": "… to 1.26.3\n\nFor full-screen NV12/I420 H.264 frames the callback overwrites every UV byte\nvia the fast-path bulk copy, so the ~1 MB memset to chroma=128 in preLockYUV\nis wasted work.  Track whether the previous frame was full-frame in yuvDone and\npass initChroma=false when it was, saving ~60 MB/s of memory bandwidth at 60 fps.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: skip initChroma memset for full-frame H.264 updates; upgrade Go…",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T07:37:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6b0b0dfa6955a9f709eceb170ae3b3bbaae98428",
          "body": "MouseWheel signature changed to float64; pass float64(dy) explicitly.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "chore: upgrade grdp v0.7.20 → v0.7.22",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T07:09:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7855ecbe50845d4f3f1d3618e6adf32ed093cee8",
          "body": "VideoToolbox's H264 decoder occasionally emits 'null' frames during\nstream initialization or decoder flush — frames where the entire Y and\nchroma planes are all-zero bytes.  When such a frame is committed to\nthe MTLTexture it renders as solid green (Y=0,UV=0 → RGB≈(0,136,0) in\nBT.601) for one displa\n[…]\nprevious good frame\n  (or the initYUVBlack black frame on first connection) continues to\n  be displayed instead of flashing green.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: detect and suppress null H264 frames (VideoToolbox flush artifacts)",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T06:47:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "006deec6ce4431481542782cc0f2c55c0b89c74f",
          "body": "The wasFullFrame optimization (skip UV init after a full-frame H264 update)\nwas incorrect: H264 partial-frame updates only write the changed region into\nthe pre-locked MTLBuffer, so unwritten UV bytes remain zero. Y=0,UV=0 in\nBT.601 is ~RGB(0,136,0) (green), causing a green overlay on unupdated area\n[…]\nthout this, the Go scheduler can migrate the goroutine to a different\nOS thread, causing subtle crashes or missed events on macOS.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: always init chroma=128 on re-lock; add runtime.LockOSThread",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T06:31:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0d810dfdda530c67b900ce68022ba3c6e3513841",
          "body": null,
          "is_bot": false,
          "headline": "initialize texture",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T06:00:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4f81be5ef21a417afed0e27a1565711040c29563",
          "body": null,
          "is_bot": false,
          "headline": "fix compile error",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-09T05:45:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "47acc50d57d4952292e0a8f63dd63627067b0135",
          "body": null,
          "is_bot": false,
          "headline": "recover stall",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T12:54:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e8717f0ce9cd544d91737c7bdf58619e38b3d0f",
          "body": null,
          "is_bot": false,
          "headline": "delete binary",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T09:43:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "51bfce9af5bc2b796a950da4ef4c9b6aa152ee6d",
          "body": null,
          "is_bot": false,
          "headline": "fix Metal pre-lock bug",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T09:42:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8af3553ebe1f5326d9ff526d5fc1a231333a3c07",
          "body": "- Audio queue cap (maxAudioQueueBytes=176400 ~1s): drop packets when\n  SDL2 audio queue is full to prevent ever-growing latency buildup\n- Add audioPlayer.reset() + OnAudioReset callback: clear stale audio\n  on server-side seek/reset (was missing, present in gxui frontend)\n- eventPending atomic.Bool:\n[…]\nrames\n- resetAfterReconnect closure: eliminate duplicated texture-recreation\n  code in both resize and video-stall reconnect paths\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "perf: SDL2 frontend optimizations",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T09:26:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "63f0bf2c1b4dd70be708b05d4bffb47487e01df7",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.18",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T07:04:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6c691586fb09adca8c92875bdc27a78a6c964ea0",
          "body": null,
          "is_bot": false,
          "headline": "grdp 0.7.16",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T06:04:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "900f9f21a16c3d2386ae1538014df3fe1316ae1c",
          "body": null,
          "is_bot": false,
          "headline": "optimization",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T04:24:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "805ef2d08e333476e1c3e959e8747d9879975411",
          "body": null,
          "is_bot": false,
          "headline": "a bit tuning",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T03:48:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e97e2bc2728b356754fbf7329266d4dc1b433001",
          "body": null,
          "is_bot": false,
          "headline": "tuning",
          "author_name": "Hajime Nakagami",
          "author_login": "nakagami",
          "committed_at": "2026-05-08T02:46:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 31,
      "commits_last_year": 150,
      "latest_release_at": "2026-07-17T07:25:05Z",
      "latest_release_tag": "v0.9.6",
      "releases_from_tags": true,
      "days_since_last_push": 5,
      "active_weeks_last_year": 20,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 7.4
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/nakagami/grdpsdl2",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/nakagami/grdpsdl2",
          "is_deprecated": false,
          "latest_version": "v0.9.6",
          "repository_url": "https://github.com/nakagami/grdpsdl2",
          "versions_count": 31,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-17T07:25:05Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "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": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 76444,
      "source_files_sampled": 1,
      "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/nakagami/grdp",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.9.4"
        },
        {
          "name": "github.com/veandco/go-sdl2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.4.40"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 1,
        "closed_ratio": 0.5,
        "closed_issues": 1,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "nakagami",
          "commits": 169,
          "avatar_url": "https://avatars.githubusercontent.com/u/415278?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": false,
      "ci_workflows": [],
      "has_docs_dir": false,
      "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": null,
            "reason": "no pull request found",
            "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/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 6,
            "reason": "project has 2 contributing companies or organizations -- score normalized to 6",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "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": 0,
            "reason": "project is not 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": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "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": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "20 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "984af1b39cfc105eaac4673bb4f395aae61acb0c",
        "ran_at": "2026-07-23T05:54:31Z",
        "aggregate_score": 2.8,
        "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": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 1,
          "created_at": "2025-06-11T00:19:48Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/nakagami/grdpsdl2",
    "host": "github.com",
    "name": "grdpsdl2",
    "owner": "nakagami"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 43,
      "inputs": {
        "security": 28,
        "vitality": 82,
        "community": 24,
        "governance": 50,
        "engineering": 21
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 82,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 78,
            "inputs": {
              "commits_last_year": 150,
              "human_commit_share": 1,
              "days_since_last_push": 5,
              "active_weeks_last_year": 20
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "20/52 weeks with commits",
                "points": 13.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 20
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "150 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 150
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 88,
            "inputs": {
              "releases_count": 31,
              "latest_release_tag": "v0.9.6",
              "releases_from_tags": true,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 7.4
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "31 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 31
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~7.4 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 7.4
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 12,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 12 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 12
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 24,
        "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": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "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 (GPL-3.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "GPL-3.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 50,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 16,
            "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 2 contributing companies or organizations -- score normalized to 6",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 38,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 1,
              "closed_issues": 1,
              "issue_closed_ratio": 0.5,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "50% of issues closed",
                "points": 23.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 50
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 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": 61,
            "inputs": {
              "followers": 74,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "nakagami",
              "public_repos": 84,
              "account_age_days": 5779
            },
            "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": "74 followers of nakagami",
                "points": 13.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 74,
                      "login": "nakagami"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "84 public repos, account ~15 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 84
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 15
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/nakagami/grdpsdl2"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 5
            },
            "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 5 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "31 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 31
                    }
                  }
                ],
                "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": "critical",
        "name": "Engineering Quality",
        "value": 21,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "critical",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "has_ci": false,
              "has_tests": false,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": 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": "critical",
        "name": "Security",
        "value": 28,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 28,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 2.8
            },
            "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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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 not fuzzed",
                "points": 0,
                "status": "missed",
                "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": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "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": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "20 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": 4
            },
            "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": "at_risk",
        "name": "AI Readiness",
        "value": 43,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 36,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.67,
              "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": "67 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 35.7,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 67,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 48,
            "inputs": {
              "has_nix": false,
              "has_tests": false,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.73,
              "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": 0,
                "status": "missed",
                "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": "73 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 73,
                      "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": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "at_risk",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 45,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 76444,
              "source_files_sampled": 1,
              "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/1 source files over 60KB",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 1,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "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-23T05:54:35.798087Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/n/nakagami/grdpsdl2.svg",
  "full_name": "nakagami/grdpsdl2",
  "license_state": "standard",
  "license_spdx": "GPL-3.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.