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"
}