公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-27 17:52 UTC

chrplr / goxpyriment

An (AI friendly) psychology experiment framework

Jupyter Notebook · GoApache-2.0★ 11 星标⑂ 2 复刻始于 2026年3月在 GitHub 上查看 ↗

chrplr/goxpyriment 的健康指数为 100 分中的 49 分,处于「存在风险」区间。 其得分最高的类别是Vitality(83/100),最低的是Security(1/100)。 最近一次更新在今天。 近期的大部分工作由 1 位贡献者完成。

49
总分 / 100
存在风险

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 49(有风险)的上限。AI 就绪度不计入总体分。

49
优秀85-100堪称典范;基本满足所有检验标准
良好70-84健康;仅有轻微不足
中等50-69可接受,但存在明显不足;建议进行审查
存在风险30-49存在重大薄弱环节;采用时应保持审慎
危急1-29问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

每条轴代表一个类别。形状比平均值更重要——健康的对象会填满整个图形,而“一峰一谷”式画像意味着某一维度的优势正掩盖另一维度的风险。

所有权

Christophe Pallier个人账户
88 关注者126 个公开仓库始于 2012年3月CNRS

该仓库由个人账户拥有。相较于组织支持的项目,单一所有者项目的延续性风险更高。

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Gogithub.com/chrplr/goxpyrimentv0.12.5-1072 天前

按类别列示的指标

活力

项目是否仍有生命——是否仍在编写代码,是否仍在发布版本?

83良好 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
10.4/36提交节奏 — 52 周中有 15 周有提交
18/18提交量 — 最近一年 184 次提交
0/10OpenSSF Scorecard:Maintained — 无数据
所用输入
commits_last_year184
human_commit_share1
days_since_last_push0
active_weeks_last_year15

发布纪律

100优秀
评分方式
27/27有发布版本 — 已发布 27 个发布版本
36/36发布时效 — 最近一次发布版本于 2 天前
27/27发布节奏 — 约每 4.2 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count27
latest_release_tagv0.12.5
releases_from_tags
days_since_latest_release2
mean_days_between_releases4.2

社区与采用

项目是否拥有用户、下载量与关注度,并具备欢迎贡献者参与的配置?

32存在风险 · 占总体的 18%
评分方式
16.2/60星标 — 11 个星标
0/25复刻 — 2 个复刻
0/15关注者 — 1 位关注者
所用输入
forks2
stars11
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

50中等
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(Apache-2.0)
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template

可持续性与治理

项目能否在其成员之外延续——巴士系数、响应能力、由谁支持,以及软件包的维护状况?

40存在风险 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0.6/22.5提交分布 — 头号贡献者编写了 97% 的提交
2.7/13.5贡献者广度 — 2 位贡献者
0/10OpenSSF Scorecard:Contributors — 无数据
所用输入
bus_factor1
contributors_sampled2
top_contributor_share0.973
评分方式
0/46.8议题解决 — 没有议题或无数据
0/38.3PR 接受 — 已裁定的 PR 中 0/2 已合并
0/15OpenSSF Scorecard:Code-Review — 无数据
所用输入
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs2
已排除计分(无数据或不适用):议题解决。 其余权重已重新归一化。
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
14/25所有者影响力 — chrplr 有 88 位关注者
25/25既往记录 — 126 个公开仓库,账户约 14 年
所用输入
followers88
owner_typeUser
is_verified
owner_loginchrplr
public_repos126
account_age_days5,249
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — go 上有 1 个软件包
35/35发布时效 — 最近一次发布于 2 天前
20/20版本历史 — 107 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesgithub.com/chrplr/goxpyriment
ecosystemsgo
any_deprecated
min_days_since_publish2

工程质量

基础的工程与文档实践是否到位?

76良好 · 占总体的 20%

工程实践

60中等
评分方式
24/24CI 工作流 — 4 个工作流
24/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
0/6.4.editorconfig
0/20OpenSSF Scorecard:CI-Tests — 无数据
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config

文档

100优秀
评分方式
30/30README
25/25文档目录
15/15文档 / 主页站点 — https://chrplr.github.io/goxpyriment/
10/10仓库描述
10/10主题标签 — 5 个主题标签
10/10Wiki
所用输入
topicsexperiments, go, neuroscience, psychology, stimulation
has_wiki
homepagehttps://chrplr.github.io/goxpyriment/
has_readme
has_docs_dir
has_description

安全

可见的安全与供应链实践是否稳固,且不存在未解决的高风险司法辖区暴露?

1危急 · 占总体的 16%
评分方式
0/30安全策略(SECURITY.md)
0/25Dependabot 配置
0/25依赖锁定文件 — 已发布的类库——锁定文件属于应用层关注点,不作要求
0/20CodeQL 工作流
所用输入
sourcefile_signals
lockfilesgo.sum
manifestsdocs/requirements.txt, examples/go.mod, go.mod, tests/go.mod
has_codeql_workflow
has_security_policy
has_dependabot_config
已排除计分(无数据或不适用):依赖锁定文件。 其余权重已重新归一化。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?这是一枚独立的实验性徽章——权重为 0.0,因此单独呈现,不影响总体健康评分。

64中等 · 占总体的 0%
评分方式
45/45代理指令 — CLAUDE.md, GEMINI.md, apparatus/CLAUDE.md, clock/CLAUDE.md, control/CLAUDE.md, design/CLAUDE.md, examples/CLAUDE.md, geometry/CLAUDE.md, media/CLAUDE.md, paper/GEMINI.md, results/CLAUDE.md, staircase/CLAUDE.md, stimuli/CLAUDE.md, tests/CLAUDE.md, triggers/CLAUDE.md, units/CLAUDE.md
0/15机器可读文档(llms.txt)
29.9/40可读的提交历史 — 100 次人类提交中有 56 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.56
agent_instruction_filesCLAUDE.md, GEMINI.md, apparatus/CLAUDE.md, clock/CLAUDE.md, control/CLAUDE.md, design/CLAUDE.md, examples/CLAUDE.md, geometry/CLAUDE.md, media/CLAUDE.md, paper/GEMINI.md, results/CLAUDE.md, staircase/CLAUDE.md, stimuli/CLAUDE.md, tests/CLAUDE.md, triggers/CLAUDE.md, units/CLAUDE.md
agent_instruction_max_bytes16,734
评分方式
18/18一条命令的引导启动 — Makefile, examples/Number-Comparison/Makefile, paper/Makefile
22/22自动化测试
0/11Lint / 格式化配置
0/11静态类型检查
10/10可复现环境 — Dockerfile, lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 56 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — 无数据
所用输入
has_nix
has_tests
lockfilesgo.sum
has_dockerfile
typed_language
bootstrap_filesMakefile, examples/Number-Comparison/Makefile, paper/Makefile
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.56
toolchain_manifestsexamples/go.mod, go.mod, tests/go.mod
dependency_bot_commit_share0
评分方式
0/45可类型检查的代码 — Jupyter Notebook,未配置类型检查
54.8/55可控的文件大小 — 采样的 267 个源文件中有 1 个超过 60KB
所用输入
primary_languageJupyter Notebook
largest_source_bytes64,154
source_files_sampled267
oversized_source_files1

机器可读接口

40存在风险
评分方式
0/40API 模式(OpenAPI/GraphQL/proto)
0/20MCP 服务器
40/40可运行示例 — examples, notebooks
所用输入
example_dirsexamples, notebooks
has_mcp_signal
api_schema_files

关键数据

11GitHub 星标
2贡献者
184最近 12 个月提交数
0距最近推送天数
27发布版本数
1巴士系数(bus factor)
0开放议题
Go, PyPI软件包生态系统数

数据采集警告

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • OpenSSF Scorecard did not return a usable result (2026/07/27 17:51:32 Warning: PATs stored in env variables GITHUB_AUTH_TOKEN and GITHUB_TOKEN differ. Scorecard will use the former.); skipping Scorecard checks

更多细节

Star 与 Fork 历史 0 ★ / 2 ⇿
0Star
2Fork
11发布

每颗 star 和每个 fork 的添加时间,来自 GitHub 并按天汇总。累计增长位于其构成来源——每日新增——的正上方,二者可相互对照:稳定的自然增长与短暂的突增形态截然不同。当这一差别可被衡量时,它会作为增长真实性予以报告。

111222212026-042026-042026-05
主版本 0次版本 0修订 11
直接依赖 7
注册表软件包版本约束清单文件
Gogithub.com/Zyko0/go-sdl3v0.1.1go.mod
Gogithub.com/ebitengine/puregov0.10.0go.mod
Gogithub.com/funatsufumiya/go-gv-videov0.0.2go.mod
Gogithub.com/gen2brain/mpegv0.5.0go.mod
Gogithub.com/goburrow/modbusv0.1.0go.mod
Gogithub.com/pierrec/lz4/v4v4.1.26go.mod
Gogo.bug.st/serialv1.6.4go.mod
全部依赖 未采集

本报告未能采集到解析后的依赖集合:GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [
        "experiments",
        "go",
        "neuroscience",
        "psychology",
        "stimulation"
      ],
      "is_fork": false,
      "size_kb": 347150,
      "has_wiki": true,
      "homepage": "https://chrplr.github.io/goxpyriment/",
      "languages": {
        "C": 2165,
        "Go": 901883,
        "TeX": 45577,
        "HTML": 4420,
        "Shell": 7815,
        "Python": 64588,
        "Makefile": 6390,
        "Emacs Lisp": 8705,
        "Jupyter Notebook": 1837480
      },
      "pushed_at": "2026-07-26T18:01:29Z",
      "created_at": "2026-03-04T00:21:41Z",
      "owner_type": "User",
      "updated_at": "2026-07-26T18:01:56Z",
      "description": "An (AI friendly) psychology experiment framework",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Jupyter Notebook",
      "significant_languages": [
        "Jupyter Notebook",
        "Go"
      ]
    },
    "owner": {
      "blog": "http://www.pallier.org",
      "name": "Christophe Pallier",
      "type": "User",
      "login": "chrplr",
      "company": "CNRS",
      "location": "France",
      "followers": 88,
      "avatar_url": "https://avatars.githubusercontent.com/u/1530674?v=4",
      "created_at": "2012-03-12T21:49:04Z",
      "is_verified": null,
      "public_repos": 126,
      "account_age_days": 5249
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": null,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.12.5",
          "kind": "patch",
          "published_at": "2026-07-25T05:54:59Z"
        },
        {
          "tag": "v0.12.4",
          "kind": "patch",
          "published_at": "2026-07-21T09:25:43Z"
        },
        {
          "tag": "v0.12.3",
          "kind": "patch",
          "published_at": "2026-07-18T16:09:26Z"
        },
        {
          "tag": "v0.12.2",
          "kind": "patch",
          "published_at": "2026-07-17T06:27:59Z"
        },
        {
          "tag": "v0.12.1",
          "kind": "patch",
          "published_at": "2026-07-08T09:46:25Z"
        },
        {
          "tag": "v0.11.4",
          "kind": "patch",
          "published_at": "2026-06-26T16:02:47Z"
        },
        {
          "tag": "v0.11.3",
          "kind": "patch",
          "published_at": "2026-06-22T08:33:22Z"
        },
        {
          "tag": "v0.11.2",
          "kind": "patch",
          "published_at": "2026-06-21T16:27:16Z"
        },
        {
          "tag": "v0.11.1",
          "kind": "patch",
          "published_at": "2026-06-21T13:58:05Z"
        },
        {
          "tag": "v0.10.9",
          "kind": "patch",
          "published_at": "2026-06-17T19:53:20Z"
        },
        {
          "tag": "v0.10.8",
          "kind": "patch",
          "published_at": "2026-06-17T19:43:09Z"
        },
        {
          "tag": "v0.10.7",
          "kind": "patch",
          "published_at": "2026-06-17T19:11:46Z"
        },
        {
          "tag": "v0.10.6",
          "kind": "patch",
          "published_at": "2026-06-17T06:27:28Z"
        },
        {
          "tag": "v0.10.5",
          "kind": "patch",
          "published_at": "2026-06-15T13:48:41Z"
        },
        {
          "tag": "v0.10.4",
          "kind": "patch",
          "published_at": "2026-06-13T09:55:27Z"
        },
        {
          "tag": "v0.10.3",
          "kind": "patch",
          "published_at": "2026-06-02T20:09:13Z"
        },
        {
          "tag": "v0.9.24",
          "kind": "patch",
          "published_at": "2026-04-21T13:13:36Z"
        },
        {
          "tag": "v0.9.23",
          "kind": "patch",
          "published_at": "2026-04-21T11:46:22Z"
        },
        {
          "tag": "v0.9.22",
          "kind": "patch",
          "published_at": "2026-04-20T05:43:26Z"
        },
        {
          "tag": "v0.9.21",
          "kind": "patch",
          "published_at": "2026-04-19T11:11:37Z"
        },
        {
          "tag": "v0.9.20",
          "kind": "patch",
          "published_at": "2026-04-17T12:39:14Z"
        },
        {
          "tag": "v0.9.19",
          "kind": "patch",
          "published_at": "2026-04-17T07:36:51Z"
        },
        {
          "tag": "v0.9.18",
          "kind": "patch",
          "published_at": "2026-04-17T06:49:23Z"
        },
        {
          "tag": "v0.9.17",
          "kind": "patch",
          "published_at": "2026-04-11T09:08:13Z"
        },
        {
          "tag": "v0.9.16",
          "kind": "patch",
          "published_at": "2026-04-09T22:14:38Z"
        },
        {
          "tag": "v0.9.15",
          "kind": "patch",
          "published_at": "2026-04-09T21:06:48Z"
        },
        {
          "tag": "v0.9.14",
          "kind": "patch",
          "published_at": "2026-04-09T05:11:50Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "b36c4c63d5d6d8cff1006f2bd353b2e8d7ccfec1",
          "body": "Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "paper: revise for the Apache-2.0 relicense and fix the LaTeX build",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T18:00:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4796ba92e971e3b0eadaed2cf98781347199f341",
          "body": "The script was last synced with main.go on 2026-04-03; the Go suite has\nchanged six times since, so the two were no longer measuring the same\nthing and a same-hardware comparison was not possible.\n\nStimulus shape:\n  - frames took --frames-per-phase (a symmetric square wave) and could\n    not express\n[…]\nriod. Not yet exercised against a real display\nor a working audio device.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "tests: realign the PsychoPy comparison script with Timing-Tests",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T17:48:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ffffebaa547f3b5ed6ba5c8343b02c4279795aea",
          "body": "`$BIN ... | tee report.txt` reports tee's exit status, so a test that\ncrashed looked like it succeeded and left a truncated report behind —\nwhich in a multi-machine session is indistinguishable from a good run.\n\nAdd `set -o pipefail` and have run() act on the status: mark the failure\nin the console \n[…]\ning steps are still worth collecting on a machine that is already\nset up.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "tests: fail loudly when a timing test crashes",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T17:48:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1f4a28aef5ddfdbab445b3d7576c597ed0fd154e",
          "body": "Opening a stimulus CSV/ODS in LibreOffice creates a `.~lock.<name>#`\nfile next to it. One had already been committed by accident. The\nexisting `._*` rule does not match these (it covers `._`, not `.~`).\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "chore: ignore LibreOffice lock files",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T16:31:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3b085be81bc8a1edc284886430e324734544cb95",
          "body": "- docs/*.pdf: regenerated with `make pdfs`.\n- CLAUDE.md: correct a stale claim that the PDFs are excluded from git.\n  Only `site/` is ignored; the PDFs are tracked and must be regenerated\n  and committed when the underlying Markdown changes.\n- wasm/exported_functions.json: regenerated by cmd/gen-was\n[…]\nmove a stray LibreOffice lock file that had been committed by\n  accident.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "chore: regenerate docs PDFs and wasm exports, tidy repo housekeeping",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T16:31:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e9a68217a56fbd18fc0024227d7786190a04b992",
          "body": "Some collaborators work for companies whose policies forbid reusing GPL\ncode, which blocked adoption. Every dependency is already permissive\n(MIT, Apache-2.0, BSD, ISC, zlib), and all library code is by a single\nauthor, so nothing constrained the choice.\n\nApache-2.0 rather than a dual GPL/MIT offer:\n[…]\nariable\nis unaffected, since the linker already dropped the unused embed.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "Relicense from GPLv3 to Apache License 2.0",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T16:18:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2539683f253bac6d04ed1edeb214af60ba2c140c",
          "body": "The six timing-critical loops in Timing-Tests hardcoded\ndebug.SetGCPercent(-1), so the garbage collector was suspended\nunconditionally and its effect on timing could not be measured. Add a\n-gc flag (default off, preserving current behaviour) routed through a\nsuspendGC() helper, and record the collec\n[…]\ne rt step is commented out until the BBTK\nresponse actuator is available.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015uL1UDaU7r927nMsZSi3qq",
          "is_bot": false,
          "headline": "tests: add -gc flag to Timing-Tests and fix the session driver",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-26T16:17:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cba5dad92f795fc443df61a9307fd3c2d6531480",
          "body": "Give the zip-and-email path its actual command (make share-<Name>, with the\nVERSION= override) in the intro callout, and note in Step 1 that the make\nwrapper writes to _build/share/ whereas share.sh's third argument places the\nmodule straight where the repo will live.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "docs: show the make share-NAME command in the standalone-repo guide",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-25T06:12:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b88ac095ff9a62978c23e068ec1411337be5dd66",
          "body": "New docs/StandaloneExampleRepo.md documents the full process of splitting one\nexamples/ directory into its own git/GitHub repository — share.sh, pruning\ninternal files, the release and Pages (WebAssembly) CI workflows, the\ngo-sdl3-wasm fork wiring, gh repo/Pages setup, and the gotchas that broke the\n[…]\ns/README.md, and\npointed to from examples/CLAUDE.md for the agent path.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "docs: add guide for publishing an example as a standalone repo",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-25T06:09:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "603252a3b9d3fedd8e7082bde0612c9bd04e9102",
          "body": "…ser crash\n\nOn js there is no filesystem, so an unrecovered panic used to unwind silently\nthrough the deferred End() and download the partial, half-written data files —\nwith nothing on screen to say the experiment had crashed. The first\nmouse-driven experiment to run in the browser (Rush-Hour) hit e\n[…]\nic: overlay shown, console has the\nstack, and no download is triggered.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "control: show an error overlay (and skip the data download) on a brow…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-25T05:47:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "89e979092acf4050c3642f07fbbf32c4d376fc69",
          "body": "…on guides\n\nMigrationGuide: extend the Psychtoolbox EEG-triggers note with the two\nnetworked clients (NetStation ECI event markers, BEL_video recorder),\nincluding the network-latency caveat vs. a TTL Pulse.\n\nComparisonWithPsychoPy: add a \"Networked recording control\" feature row,\nand clarify the eye\n[…]\npant-video\nmonitoring, no gaze/pupil) is not mistaken for eye tracking.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "docs: cover NetStation and BEL video recorder in migration & comparis…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-24T10:57:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c4e703c00d7bf9476a4cfc75773c8a8240bf217",
          "body": "VideoRecorder is the client for the NeuroSpin EEG-room behavioral video\nrecorder (\"BEL_video\"): a camera PC films the participant, burns event\nlabels into the footage, and saves an AVI. This type starts/stops that\nrecording and pushes the labels over TCP; capture/encoding stay on the\ncamera PC. Same\n[…]\novering both NetStation and VideoRecorder, and the regenerated gallery.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "triggers: add VideoRecorder (BEL_video camera) client over TCP/IP",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-24T10:55:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6e82164896b472458e54b212bc91a17bced4955e",
          "body": "NetStation marks named events in an EGI/NetStation EEG recording and\ncontrols recording remotely over TCP using the ECI protocol. It is a\nstandalone device (like SerialPort) — not an OutputTTLDevice, since it\ncarries 4-char event codes with durations and key/value payloads rather\nthan 8 electrical l\n[…]\nal host, docs in\ntriggers/CLAUDE.md, and the regenerated gallery entry.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01WvUoRa7NCVP2LEQWZ48HpK",
          "is_bot": false,
          "headline": "triggers: add NetStation (EGI ECI over TCP/IP) driver",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-24T09:58:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "04680ea726d89e3369e53508f327ee9dc2a05c9a",
          "body": "…cell\n\nstepFor decided the direction of a one-cell move by comparing cell indices,\nwhich left the middle cell of every 3-cell vehicle — a third of its surface\n— with no direction to give, and therefore inert. Clicking there did\nnothing, the one place where a click on a vehicle silently had no effect\n[…]\n\ncell, so the new case is covered by the unit test rather than in vivo.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Sv4wWMdkytsAfK23F6rsr1",
          "is_bot": false,
          "headline": "Rush-Hour: split the click direction on the vehicle midline, not the …",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-23T07:14:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f63dd2c409e357a2e885cbe4488df4dc34d6b655",
          "body": "Pressing a vehicle used to move it or merely select it depending on which\nof its cells was hit. The press branch and the drag branch ran in the same\npoll iteration, and destinationFor handed the pressed cell to TryMove as\nthe vehicle's *anchor* (its top-left cell) with no grab offset. Pressing\nthe a\n[…]\nthe\ndata file shows 4 click_move rows collapsing to n_moves = 3 on p01.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Sv4wWMdkytsAfK23F6rsr1",
          "is_bot": false,
          "headline": "Rush-Hour: one click, one cell — replace the drag/select input modes",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-23T07:05:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b6e55fff9e4344a42947f6218b702cd5bb5b2da4",
          "body": null,
          "is_bot": false,
          "headline": "wasm version of Rush-Hour",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-22T19:10:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "53cea7ee706b6bbd29046ec4d3cc4154a486175a",
          "body": null,
          "is_bot": false,
          "headline": "added Rush-Hour",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-22T18:29:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "67333996124904986a1d532c6cdce3428fe6f589",
          "body": "Answers the question software timing cannot: when PlayGv says a frame was\nflipped, did the screen actually change, and does the TTL edge line up with\nit? The test plays a flash train and pulses a trigger at each bright onset,\nso a photodiode on the square and the TTL line on a second scope channel\ns\n[…]\n readers PlayGv had no per-frame\nhook and to drive the loop themselves.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "tests: add gvsync, a photodiode test of .gv onset vs. trigger alignment",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T09:16:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e3a1c10aa8b2fccee670156b71069682eb0a5a38",
          "body": "Matches the naming of its siblings demo_play_videos and\ndemo_play_two_videos, and says what it plays.\n\ndemo_sync_two_gv_movies and demo_bouncing_gv_movies locate their fixtures\nthrough \"../demo_playgv/\", so both are updated; without that they would\nfall through to the next candidate path and fail to\n[…]\nhan at build time.\n\nGallery regenerated (make update-examples-gallery).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "examples: rename demo_playgv to demo_play_gv_videos",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T08:53:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ea19e1540befccdc339cb54506a58ff78ff76501",
          "body": "PlayGv presented exactly one video frame per flip, so a clip played at\nwhatever the display refreshed at rather than at its authored rate. On a\n60 Hz monitor a 30 fps clip ran at double speed. Measured on real assets:\n\n  wedges.gv    33 frames @ 30 fps  ->  0.536 s  (should be 1.10 s)\n  bonatti1.gv \n[…]\nferent), a 60 fps\nfile plays at hold=1, and the 24 fps case is refused.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "stimuli: play .gv at the rate in its header, not the monitor's",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T08:49:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5fc99938156c5108ab959584fa7b7401877b4203",
          "body": "Prompted by an images2gv release-build failure: `go build ./cmd/x/main.go`\ncompiles only that one file, as the pseudo-package \"command-line-arguments\",\nso the rest of the package is silently left out. It works right up until a\nsecond file appears.\n\ngoxpyriment's CI is not exposed to this — the workf\n[…]\nfile.\n\nVerified all 97 examples and tests build when named as packages.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "docs: name packages, not main.go, in build and run commands",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T08:30:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5d5f51b8b9c74a23c8c1227ad5a391ac13978a92",
          "body": "Section 15 documented both formats accurately but was hard to act on: the\nmp4-to-MPEG-1 recipe, which is what most people arrive needing, sat in the\nmiddle of section 15.2 behind prose about pack headers and hex signatures,\nand triggers were not mentioned at all.\n\n  - A \"Start here\" block after the \n[…]\ntriggers.NewParallelPort as if it returned an error, which it does\nnot.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "docs: make the video section task-oriented; add GvVideo.CurrentFrame",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T08:09:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9b8e7d252cee77fc544d958e79212a41f606df02",
          "body": "Feature-by-feature comparison based on the PsychoPy documentation sources,\ncovering where the two reach parity (staircases, unit conversion,\ncounterbalancing, gamma, triggers) and where PsychoPy is ahead (eye\ntracking via ioHub, ElementArrayStim and the wider visual module, Pavlovia\nand recruitment \n[…]\ns and the advantages.\n\nAlso records the new video tooling in CLAUDE.md.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "docs: compare goxpyriment with PsychoPy",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T07:46:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "44fb6bdb8cdae3aea3b08d15a964c871eafbfea1",
          "body": "gv-convert converts a video, or a directory of numbered images, into the\n.gv format used for timing-critical playback. It needs no new dependencies:\nMPEG-1 program streams are decoded in pure Go with the already-vendored\ngen2brain/mpeg, any other video format is piped through ffmpeg if it is on\nPATH\n[…]\n pre-existing wrong section\nreference in the timing table is corrected.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "cmd: add gv-convert and gv-getinfo, document video in the User Manual",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T07:45:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ea8b79bd7f4007af0d85a16ed18a6abb23a02d93",
          "body": "stimuli.Video decoded only the video stream, so .mpg files always played\nsilently even though gen2brain/mpeg decodes MP2 audio too.\n\nVideo.PreloadDevice(deviceID) now enables the audio track and binds it to\nan SDL audio stream, following the same convention as Sound.PreloadDevice.\nUpdate() keeps 100\n[…]\neturn true with a nil decoder and SetAudioFormat then\ndereferences nil.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01H1hJCmumAXx2hmBQWdreNp",
          "is_bot": false,
          "headline": "stimuli: play the MP2 soundtrack of MPEG-1 videos",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-21T07:45:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3a9dc7cd75aa72470f58cede8cafc07fc9297616",
          "body": null,
          "is_bot": false,
          "headline": "fixed examples/demo_stream*",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-20T13:23:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "74bda50f932471f9fa8b9a27746092fcf1a5d5de",
          "body": "Split the example/test catalogue on the demonstrate-vs-measure rule:\n\n- Move 20 single-feature demonstrations from tests/ to examples/ (category\n  test -> demo): canvas, follow_mouse, getinfo, images, images_embedded,\n  keyboard, menu, text_input, MovingGrating, playgv, the five stream_* demos,\n  bo\n[…]\nt`.\nFlags examples that read sibling files (../) as not self-contained.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Mu3x6xkNitwJkjs7qPAFqw",
          "is_bot": false,
          "headline": "Reclassify demos vs tests; prefix demos with demo_; add `make share`",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-20T13:09:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "352cf47a938982500b8a0220b2e5112d10a3e332",
          "body": "…axis\n\nNew examples/Typing-Speed experiment: per-trial sentence-copy task that\nrecords every keystroke with a hardware-precision timestamp (onset, inter-key\ninterval, and a correct/incorrect/movement category), advances only on an exact\ncopy + ENTER, and reports percent-correct and cps percentiles a\n[…]\nCenterToSDL's godoc\nand in the root/apparatus/examples CLAUDE.md files.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Mu3x6xkNitwJkjs7qPAFqw",
          "is_bot": false,
          "headline": "Add Typing-Speed example; re-export event primitives; document +Y-up …",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-20T09:40:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "92674e17a76d0bca5d0d237ba3671f0784385b89",
          "body": null,
          "is_bot": false,
          "headline": "cleaner split betwwen sdl clock and go time clock",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-18T16:00:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9bbe174e1a7f4305cf218c5fc8599219e34b5d17",
          "body": null,
          "is_bot": false,
          "headline": "small fix to README",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-17T07:27:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef6600ba5033d74b88473877bd0301840e5f4bcb",
          "body": null,
          "is_bot": false,
          "headline": "added RSVP-MathLang",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-17T06:19:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "39509d9d113b7dc6bf925f98aa46edfda42d72c6",
          "body": null,
          "is_bot": false,
          "headline": "added Language-Localizer-French-audio to examples",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-16T07:22:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f9ee4d6720624c2332d66e3c39fb9ac50b6bd730",
          "body": null,
          "is_bot": false,
          "headline": "added Language-Localizer",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-15T15:51:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "218ac159da6f1faa370439deff410ffed706e871",
          "body": "Unblocks CollectEventLog in the browser; with it the Stroop task runs\nend-to-end in headless Chrome (16 trials, RTs, CSV download).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "go.mod: bump go-sdl3-wasm pin to 87a9041 (TTF_GetFontSize on js)",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T10:29:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "31493656d420841caf485c6cf7596034e6da43e1",
          "body": "…se TODO.md\n\nFix statements that later phases made stale: control/CLAUDE.md and\ndocs/WASM.md still described browser audio as a deferred no-op (it opens the\ndefault device since Phase 4); docs/WASM.md quoted a hardcoded fork\npseudo-version (now points readers at go.mod as the source of truth) and it\n[…]\nlidation, more examples, canvas-viewport option, HTML\nparticipant form).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "docs: sync CLAUDE.md files and WASM.md with the finished port; conden…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T10:20:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a672c6786e72c4b035b9f617e4c1e2e313ffbada",
          "body": "Makefile: the wasm-% targets now run the wasmsdl bundler from the pinned\ngo-sdl3 fork (go run github.com/Zyko0/go-sdl3/cmd/wasmsdl) — no local fork\nclone or Emscripten install needed. 'make wasm-NAME' builds a self-contained\nbundle into _build/wasm/NAME/; 'make wasm-NAME-serve' serves it on :8080\nwi\n[…]\n the upstream-PR decision for\nthe fork is recorded as the one open item.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "WASM Phase 5: wasmsdl make targets, CI, stale-artifact cleanup",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T10:07:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dc6989443c90a1855e0ce64e162c134a6dbf03ed",
          "body": "platformInitAudio on js now opens the default playback device exactly like\ndesktop, instead of installing a silent zero-Device AudioManager. Browsers\ncreate the AudioContext suspended until a user gesture; SDL's Emscripten\nbackend resumes it on the first click/keypress, so any experiment that opens\n\n[…]\nt,\nPlaySyncedWithFlip guarantees do not transfer); TODO.md Phase 4 done.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "control: enable audio in the browser",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T09:54:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2f60a4f997de3d8cd406207834ae99c8719b1b33",
          "body": "Platform-split the present path of Screen. On desktop nothing changes:\npresent() is SDL_RenderPresent and paceToFrame() carries PacedFlip's\nbusy-wait for triple/mailbox-buffered drivers. On js, present() parks until\nthe next requestAnimationFrame tick (sdl.WaitAnimationFrame in the fork) —\nrequired \n[…]\n\nmeasured numbers; photodiode validation on real hardware noted as open.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "apparatus: align browser flips to requestAnimationFrame",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T09:34:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b67b17e6f9f6ed38019941bdc1319a2d627fc8f0",
          "body": "…port tool\n\nRuntime changes (build tag js):\n- control/platform_js.go: synthesize os.Args from the page URL's query string\n  (?s=3&w behaves like -s 3 -w, experiment-specific flags included; unknown\n  keys are skipped with a console note). The participant-info setup dialog\n  never opens in the browse\n[…]\necision runs end-to-end (10 RT\ntrials, CSV download) in headless Chrome.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01RoHd7hxKVyobSGiikNQ5m6",
          "is_bot": false,
          "headline": "Browser/WASM support: URL-parameter session setup, fork pin, docs, ex…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-13T08:58:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3d5508761c6e8524f388649fe151b06304c74887",
          "body": null,
          "is_bot": false,
          "headline": "small fix to index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-09T08:00:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "26b27dc657f24fe6eef792a395c4e2e5fb6fda73",
          "body": "The landing page duplicated the sidebar nav and buried a fragmented\nonboarding path, making it hard for a first-time visitor to know where\nto start. Restructure around four clear pointers.\n\n- index.md: replace the flat Documentation table + Quick Start with four\n  labeled groups (Start here, User Ma\n[…]\nn Experiment\") everywhere.\n- README.md: regenerated from docs/index.md.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AYCyBSmcTDFwpuGzDoqEf5",
          "is_bot": false,
          "headline": "docs: reorganize landing page and nav for clearer entry points",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T12:38:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d873a9103ff923ba8c9c10f4f873a23327c34aa",
          "body": "Add .gitignore entries for the Attentional-Blink,\nStatistical-Learning-Auditory, and Temporal-Integration-Word-Recognition\nexample binaries. They were untracked (nothing to remove from git), just\nnever ignored, so `go build` left them showing up in git status.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "examples: gitignore three more stray compiled binaries",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:29:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bbb69132f2a04fefe5a9dd74d4a25755ec961f12",
          "body": "Add house-style README.md files (paradigm summary, task/timing, design,\nflags, output columns, expected results, references) for:\nContrast-Detection-QUEST, Visual-Search, Number-Double-Digits-Comparison,\nClassification-Posner-Mitchell, Finger-Tapping, Mouse-tracking,\nRSVP-Images-OneBack, and play_tw\n[…]\non)\nand regenerate docs/GalleryOfExamples.md from the updated metadata.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "examples: add READMEs for eight examples; fix Mouse-tracking metadata",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:14:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "78162254dd6ed8f631be0ef6f79ecf94c6188482",
          "body": "The framework's -d flag is the display index (via NewExperimentFromFlags),\nbut several files still described it as a \"developer/windowed\" mode:\n\n- Letter-size-illusion, Magnitude-Estimation-Luminosity,\n  Sensory-Threshold-Estimation-Auditory, Visual-Angle-Calibration: fix the\n  header usage comments\n[…]\n(which wrongly documented -w and -d N display) and note the difference.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "examples: correct stale/incorrect -d flag documentation",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:13:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c687751510887b405be085367170c99457d2ea64",
          "body": "- Contrast-Detection-QUEST: log the real random signal interval and the\n  participant's actual response instead of the previous placeholders\n  ((trialNum%2)+1 and \"?\"); runTrial now returns them. Also corrects the\n  stale \"-d = developer mode\" usage comment in the file header.\n- RSVP-Images-OneBack:\n[…]\nms) and the previously always-zero false-alarm\n  summary counter works.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "examples: fix data-logging bugs in QUEST and RSVP one-back",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:13:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b410cce63864faa5e11fb350b719b778c922e0e7",
          "body": "Six compiled example binaries were committed to the repo. Remove them\nfrom tracking (the local files are kept) and add matching entries under\nthe .gitignore \"Compiled binaries\" section so `go build` no longer\nre-adds them.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "examples: untrack compiled binaries and gitignore them",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:13:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f631b52e9aefbbb055c3f02c94db2aefa6ae9863",
          "body": "Findings from a review of the VSYNC-locked core:\n\n- moving_grating: allocate one persistent STREAMING texture and Update()\n  it each frame, instead of creating+destroying a GPU texture every frame\n  (driver-side churn that GC-disabling cannot help). Mirrors GvVideo.\n- screen.PacedFlip: cache the nom\n[…]\nered on the\n  slot's first off-frame instead of being silently dropped.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "stimuli,apparatus: fix rendering/timing hot-path issues",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:11:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "01895468708fe80ae9f049016f8cef0de5b6689e",
          "body": "UserManual §1 now describes the automatic setup dialog that opens when a\nbinary is launched without -s, the -headless skip, and the cross-session\nmemory of display/fullscreen/folder choices.\n\nAlso carries the earlier one-paragraph clarification that held (audio)\nframes in the RSVP stream loop are re-rendered rather than relying on GPU\nbackbuffer persistence.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "docs: document the auto session-setup dialog (and held-frame note)",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:08:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d87480abbab3125135c3c0c5fe1ccdc8a932d461",
          "body": "Launching an experiment binary by double-clicking its icon passes no -s\nflag, so NewExperimentFromFlags silently used SubjectID 0 with no way to\nenter a subject code, choose the monitor/window mode, or set the results\nfolder.\n\nNewExperimentFromFlags now detects (via flag.Visit) whether -s was given\n\n[…]\n\ndialog can prefill the real default results folder ($HOME/goxpy_data).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019p5YowJfHDKqWrZTnwFEfY",
          "is_bot": false,
          "headline": "control: auto-prompt session setup when -s is absent",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-08T09:05:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "527d7f735f69dc752a0608d35636a6bc0d0d14e6",
          "body": null,
          "is_bot": false,
          "headline": "modified docs/index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-01T10:47:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4b9caf0459c4c7185dd30096611acf8ff9efa0b4",
          "body": null,
          "is_bot": false,
          "headline": "modified docs/index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-01T10:47:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cd3e5c8fde3afbac73b68c0cfbf7cc5e00da6f56",
          "body": null,
          "is_bot": false,
          "headline": "modified the order of docs pages  in nav bar",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-07-01T10:44:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "670622a67fd4fdccbfc2205c86aacccd179dfd97",
          "body": null,
          "is_bot": false,
          "headline": "corrected errors in docs links",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T17:36:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "965097e12f13f128d8967b961dc016c9bc355839",
          "body": null,
          "is_bot": false,
          "headline": "corrected error in homepage link in index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T17:09:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "671c0b293f341ddcd0568337c5f3d62e1d41e31c",
          "body": null,
          "is_bot": false,
          "headline": "modified examples/RSVP-Images to parallelize image resizing",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T13:16:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d26863e883ef38493e3c515aa2aa281cec44e96",
          "body": null,
          "is_bot": false,
          "headline": "added doc to view doc locally",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T12:56:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f2c40d6821525ee54abd6b13c84e0a8815861055",
          "body": "Replicates the RSVP oddball-detection paradigm from Hebart et al. (2023,\nTHINGS-data). Object images flash by on a mid-gray background with a central\nblack fixation dot; the participant presses SPACE on pixelated oddballs.\n\n- cmd/gen-design: generates MEG (SOA 1500±200 ms, jittered) and fMRI\n  (SOA \n[…]\nndred MB for these 1600px images).\n- Committed sample design_meg.csv / design_fmri.csv, README, meta.yaml, and the\n  regenerated gallery entry.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add RSVP-Images example: Hebart et al. (2023) oddball task",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T12:54:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0d2e6fe42e8dabd8730221698e2b381e71fc4d08",
          "body": null,
          "is_bot": false,
          "headline": "replace spaces by \"-\" in output filenames",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-27T07:32:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d8f7265397d522ca1e9a33086bd4843e2a21f598",
          "body": null,
          "is_bot": false,
          "headline": "streamlined examples/lexical_decision",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-26T15:56:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d595f631eec3b3a168d9904a0ee1d839248969c",
          "body": null,
          "is_bot": false,
          "headline": "added a test for PlayStremOfSounds()",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-24T16:11:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2efe5bf11ce069deb4646aa20c1fa1392fcdc9b1",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T10:55:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0ff2458fce47f217cd4dfce9f4b9c75b315a48ec",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T10:54:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc6cbb4830569ef8f2d0a36bc02e2b7e3af3dd81",
          "body": "Reword the triple-buffering/mailbox notes in UserManual.md to describe a\nnon-blocking *presentation mode* (mailbox / compositor-mediated) rather than\nVSYNC being disabled or impossible: the display stays tear-free but the present\ncall no longer paces one frame per call. Add the Wayland frame-callbac\n[…]\n(hand-run technical tests: categories, test_ naming, meta.yaml,\nseparate module). Both route to canonical sources rather than duplicating APIs.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: clarify VSYNC/triple-buffering wording; add authoring guides",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T10:54:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "87a5ac51bc62260c817ac7eb5116ae29473df895",
          "body": null,
          "is_bot": false,
          "headline": "modify doc's nav bar",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T10:06:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7534dfd9eb0b263827de41779d29b5b6803fc22c",
          "body": null,
          "is_bot": false,
          "headline": "switch doc conf from mkdocs.yml to zensical.toml",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T09:27:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ca5a596672914397afe3893d508fd1f681cf4ae9",
          "body": null,
          "is_bot": false,
          "headline": "switch doc conf from mkdocs.yml to zensical.toml",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-23T09:26:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c67d6002249486878aee5ab940a9a3cec0465912",
          "body": "These edits were the source for the just-committed generated README.md;\ncommit them so docs/index.md and README.md are back in sync.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(index): expand landing page intro, features, and background",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-22T14:57:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4c4c0c643fcb0af01d48499859e9d91c413672da",
          "body": "Make docs/index.md the single source of truth for the landing page so\nthe root README can no longer drift / be forgotten. Add cmd/gen-readme\n(copies content, prefixes relative links with docs/), a `make readme`\ntarget, and a CI guard that fails when README.md is out of date.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: generate README.md from docs/index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-22T14:51:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8d7fecfcce8b71d845882d7663d8723c83ce4a09",
          "body": "The actions/deploy-pages step requests an OIDC token and validates the\npermissions of the job it runs in. Relying on top-level permissions\ninheritance triggered: 'Ensure GITHUB_TOKEN has permission id-token:\nwrite'. Declare the permissions explicitly on the deploy job.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(docs): grant id-token/pages write on deploy job",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-22T08:39:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "af5ba4573f287edefaee929c5c76f288af297dff",
          "body": null,
          "is_bot": false,
          "headline": "fix the missing .exe in Windows in build-all.sh",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-22T08:27:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eaefaebf49281c4392bc357e85141ec77fdc10af",
          "body": "- Installation.md: fix typos (goxpyriment, misleading, containing,\n  pkgsite), correct the tests/* link target, repair the pkgsite URL,\n  and reword the awkward \"from two things one\" sentence.\n- CLAUDE.md: document the docs site as Zensical-built; fix make targets\n  (clean, deploy via GitHub Actions).\n- make_pdfs.sh: replace stale MkDocs references with Zensical.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: fix Installation.md typos/links, switch docs tooling to Zensical",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-22T06:40:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2a149c998dd2e10a0661f4153cb5dd83aeff423c",
          "body": "… VSYNC or not",
          "is_bot": false,
          "headline": "added test_vsync_blocking to tests, to check if FlipTS is blocking on…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-21T16:16:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ea23b6113ad8a1b01790f6c5ff826d4f003245a",
          "body": "…frame callback\n\nAdd PresentStreamOfStimuli, a heterogeneous sequential stream that mixes\nvisual and audio stimulus types over the shared VSYNC-locked loop:\n\n- PresentStreamOfImages/Text now delegate to it (one loop implementation)\n- StreamElement + MakeStream/MakeRegularStream builders\n- PacedFlip \n[…]\non-Word-Recognition: raw flips -> PacedFlip\n\nAdd tests/test_stream_mixed and tests/test_stream_callback; refresh docs and\nthe examples gallery.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(stimuli): generic stream presentation with VSYNC pacing and per-…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-21T15:57:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d1987c66833ab7e9833035db47e0c98cb2f198cf",
          "body": "…oc drift\n\nBehavior-preserving cleanups across the library:\n\n- triggers: add shared readLineFromMask/pollWaitForInput/pollDrainInputs in\n  device.go; the five devices delegate their input loops to them. Add\n  device_test.go (package previously had no tests).\n- stimuli: add destroyTexture helper (rep\n[…]\nreen.CenteredRect.\n\ngo build/vet/gofmt clean; new and existing unit tests pass (the control\npackage test requires a display and is unaffected).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract duplicated code, complete control re-exports, fix d…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-21T14:33:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9e1bb9a20d44a8ee5f141d6e13bed74cf8235a0b",
          "body": null,
          "is_bot": false,
          "headline": "wrap returned errors",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-21T13:51:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c3f2ab7f8125c47ca26c79c78345f9ce7586b86a",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-20T10:53:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "17c9789a8519bc46c45bed7a82aaac2032df0695",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-20T10:32:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "00e1a1db522433dbfae98170d6fafb09d186c1ff",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-19T08:19:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15f5a31ffbfabbc4083eb05f27396f317e607818",
          "body": null,
          "is_bot": false,
          "headline": "streamlining docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-19T07:33:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "41cb2c2d7ddb319ebaf2303109cd7c594454959b",
          "body": null,
          "is_bot": false,
          "headline": "small fixes in docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-18T12:31:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "353a6251e8ac406b64b7bce89146246534654f27",
          "body": null,
          "is_bot": false,
          "headline": "simplify doc",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-18T10:46:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a2265c934a26b2e8d9d045dedec80f246c797fe0",
          "body": "…fixes\n\n- Rename two reference PDFs in examples/Trubutschek_Unconscious_Working_Memory\n  to drop the non-ASCII \"ü\" (U+00FC) and embedded spaces. Non-ASCII paths are a\n  Go module-zip / module-proxy hazard and break on case-/encoding-sensitive\n  filesystems. No code or links referenced the files (cit\n[…]\ning_gv_movies, tests/sync_two_gv_movies: add missing `reference:`\n  key to meta.yaml so they validate against the gallery generator convention.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release prep: ASCII-safe filenames, Windows-safe Makefile, meta.yaml …",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T19:47:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d57a2fc73dac16679f239f75ec8d4de50cd0af8d",
          "body": "Addresses findings from a codebase review.\n\nresults: include seconds (HHMMSS) in data filenames so re-running the\nsame experiment + subject within the same minute no longer silently\ntruncates the previous run's .csv/-info.txt (results/data.go); docs\nupdated accordingly.\n\ncontrol: ShowInstructions no\n[…]\nsection to the User Manual explaining the Go\nmonotonic clock vs the SDL event clock, with use cases and the rule\nnever to subtract across them.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Harden data files, staircase errors, and timing-thread docs",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T19:34:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fff9a85340326ff7519aade1f76e9c33ab89e939",
          "body": "…ode skill+hook\n\nDocs:\n- mkdocs.yml: grouped nav into sections so all 20 pages are reachable\n  (11 were orphaned, 6 entirely unlinked).\n- Fix broken cross-references: MigrationGuide UserManual §16 anchor;\n  MediaMovies links repointed to tests/sync_two_gv_movies and dead\n  media/Plan.md + media/CLAU\n[…]\nCLAUDE.md: add Go Development, Build & Environment, Workflow Conventions\n  guidance.\n- .gitignore: ignore personal .claude/settings.local.json.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: reorg nav, fix cross-references, harden PDF build; add Claude C…",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T19:02:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "28fa7ac8e11296fee3b6f7dbc5cfa491ee18c47c",
          "body": null,
          "is_bot": false,
          "headline": "minimal changes to index.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T18:10:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f4fe419d75736a197eb32b96b492ab708c2c750",
          "body": null,
          "is_bot": false,
          "headline": "fix windows issue with find.exe shadowing /usr/bin/find",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T06:56:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3539d087bad3d19d33cf572c6b3f3f2d21697c06",
          "body": null,
          "is_bot": false,
          "headline": "added parity decision to CreatingYourOwnExperiment.md",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-17T06:21:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8004a1ce19eaa75d83709e2e9617435e8b1e2378",
          "body": null,
          "is_bot": false,
          "headline": "tidy",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-15T16:40:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eee04016c6ee5e68c848dfa383d6cf465d717ba7",
          "body": "The arrow character (U+2192) in\n  paper/timing-test/av-001_diff_TTLin1→{Mic1,Opto1}.png\nis not a Unicode letter, so Go's module zip creation\n(module.CheckFilePath / fileNameOK) rejects it with\n\"malformed file path ... invalid char '→'\". This made\n`go get`/`go mod tidy` of github.com/chrplr/goxpyrime\n[…]\n any consumer (reported on Windows, v0.10.4).\n\nRename to ASCII '_to_' and update the image references in\nav-001.md and av-001.html accordingly.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(paper): rename timing-test PNGs containing '→' that broke module zip",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-15T13:33:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5088c4d8bf77aec04a3ece768b6e934ab96e711d",
          "body": "Make the program explain which input path it took and why, and help locate\nthe analog stick on raw-joystick devices:\n\n- Print the selected API at startup (Gamepad vs Joystick fallback), and for\n  the joystick path report name, USB VID:PID, axis/button counts, and\n  IsGamepad() so it's clear when SDL\n[…]\nenters and clips a0 off-screen.\n- Add an on-screen mode + direction readout and prefer the gamepad analog\n  stick with a raw-joystick fallback.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(test_joystick): startup device diagnostics + live axis dump",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-14T20:34:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d5a08c5ae2aff64046106a5608cf61e2db9068a",
          "body": "The raw Joystick API exposes device-specific axis numbers; on many gamepads\naxes 0/1 are a digital D-pad, so test_joystick only moved in 8 directions\n(0/45/90/... degrees) instead of smoothly.\n\n- apparatus: add GamePad.Axis(sdl.GamepadAxis) — standardized analog axes\n  (LEFTX/LEFTY always the left s\n[…]\nas a device-inspection tool.\n- Document the prefer-gamepad-over-joystick guidance in apparatus/CLAUDE.md\n  and refresh the gallery description.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(apparatus): GamePad.Axis() + drive test_joystick via gamepad API",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-14T20:08:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "42361837c03933ddd51ebc1a77eaf58f3749ea01",
          "body": "Note the three workspace modules and add an \"examples/ vs tests/\" subsection\ncovering the test_* naming convention, the per-directory meta.yaml, and the\nmake update-examples-gallery generation for both folders.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(CLAUDE.md): document examples/ vs tests/ convention",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-14T19:59:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a8627ee423c6c933a394fdcdb0f0ea424b862049",
          "body": "…gallery\n\nMove six feature demos from examples/ into the tests/ module, renamed to the\ntest_* convention already used there:\n\n  text_input           -> test_text_input\n  joystick_cursor      -> test_joystick\n  canvas_demo          -> test_canvas\n  getinfo_demo         -> test_getinfo\n  follow-mouse \n[…]\n Add README.md to examples/ and tests/ explaining each folder's purpose.\n- tests/go.mod: go-gv-video promoted indirect -> direct (go mod tidy).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Reorganize: move feature/hardware demos to tests/, document tests in …",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-14T19:54:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4663857b150d579e4189e036c53c936d28983123",
          "body": null,
          "is_bot": false,
          "headline": "a bit of cleaning",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T10:12:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b567637f796ca8b0b0c431c07a2f2688128a2ee1",
          "body": null,
          "is_bot": false,
          "headline": "a bit of cleaning",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T09:59:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72f8c4e02c824926c367bd878998973f8b3d16ea",
          "body": null,
          "is_bot": false,
          "headline": "a bit of cleaning",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T09:48:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e958b3b71db821269f4034ae6dd48da5e0de6345",
          "body": null,
          "is_bot": false,
          "headline": "work on installation instructions",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T08:32:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2bcd91fedc7557f568fc359f026acc512cdbf5c6",
          "body": null,
          "is_bot": false,
          "headline": "work on installation instructions",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T08:17:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ee5cc159eeadac9eac88370a696ac23f9078f68",
          "body": null,
          "is_bot": false,
          "headline": "work on doc",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T08:02:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "526b341237a105592026acfa585c09a1cae688dd",
          "body": null,
          "is_bot": false,
          "headline": "work on installation instructions",
          "author_name": "Christophe Pallier",
          "author_login": "chrplr",
          "committed_at": "2026-06-13T06:36:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 27,
      "commits_last_year": 184,
      "latest_release_at": "2026-07-25T05:54:59Z",
      "latest_release_tag": "v0.12.5",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 15,
      "days_since_latest_release": 2,
      "mean_days_between_releases": 4.2
    },
    "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/chrplr/goxpyriment",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/chrplr/goxpyriment",
          "is_deprecated": false,
          "latest_version": "v0.12.5",
          "repository_url": "https://github.com/chrplr/goxpyriment",
          "versions_count": 107,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-25T05:47:51Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 2
        }
      ]
    },
    "popularity": {
      "forks": 2,
      "stars": 11,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2026-04-01",
            "count": 1
          },
          {
            "date": "2026-05-19",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 2,
        "total_forks": 2
      },
      "star_history": null,
      "open_issues_and_prs": 2
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples",
        "notebooks"
      ],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile",
        "examples/Number-Comparison/Makefile",
        "paper/Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "examples/go.mod",
        "go.mod",
        "tests/go.mod"
      ],
      "largest_source_bytes": 64154,
      "source_files_sampled": 267,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "CLAUDE.md",
        "GEMINI.md",
        "apparatus/CLAUDE.md",
        "clock/CLAUDE.md",
        "control/CLAUDE.md",
        "design/CLAUDE.md",
        "examples/CLAUDE.md",
        "geometry/CLAUDE.md",
        "media/CLAUDE.md",
        "paper/GEMINI.md",
        "results/CLAUDE.md",
        "staircase/CLAUDE.md",
        "stimuli/CLAUDE.md",
        "tests/CLAUDE.md",
        "triggers/CLAUDE.md",
        "units/CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 16734
    },
    "dependencies": {
      "manifests": [
        "docs/requirements.txt",
        "examples/go.mod",
        "go.mod",
        "tests/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",
        "pypi"
      ],
      "dependencies": [
        {
          "name": "github.com/Zyko0/go-sdl3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.1"
        },
        {
          "name": "github.com/ebitengine/purego",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.10.0"
        },
        {
          "name": "github.com/funatsufumiya/go-gv-video",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.2"
        },
        {
          "name": "github.com/gen2brain/mpeg",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.5.0"
        },
        {
          "name": "github.com/goburrow/modbus",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.0"
        },
        {
          "name": "github.com/pierrec/lz4/v4",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v4.1.26"
        },
        {
          "name": "go.bug.st/serial",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.6.4"
        }
      ],
      "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": 2,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 2
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "chrplr",
          "commits": 179,
          "avatar_url": "https://avatars.githubusercontent.com/u/1530674?v=4"
        },
        {
          "type": "User",
          "login": "jubnr",
          "commits": 5,
          "avatar_url": "https://avatars.githubusercontent.com/u/91159278?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.973
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "build-examples.yml",
        "docs.yml",
        "go-build.yml",
        "readme-sync.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": null,
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-26T18:02:00Z",
      "oldest_open_prs": [
        {
          "number": 3,
          "created_at": "2026-04-09T19:59:16Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4,
          "created_at": "2026-05-19T19:13:45Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": null,
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/chrplr/goxpyriment",
    "host": "github.com",
    "name": "goxpyriment",
    "owner": "chrplr"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 49,
      "inputs": {
        "security": 1,
        "vitality": 83,
        "community": 32,
        "governance": 40,
        "engineering": 76
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 83,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "commits_last_year": 184,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 15
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "15/52 weeks with commits",
                "points": 10.4,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 15
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "184 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 184
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "OpenSSF Scorecard unavailable",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "releases_count": 27,
              "latest_release_tag": "v0.12.5",
              "releases_from_tags": false,
              "days_since_latest_release": 2,
              "mean_days_between_releases": 4.2
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "27 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 27
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 2 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~4.2 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 4.2
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "OpenSSF Scorecard unavailable",
                "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": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 32,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 16,
            "inputs": {
              "forks": 2,
              "stars": 11,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "11 stars",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "2 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "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 (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 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": "at_risk",
        "name": "Sustainability & Governance",
        "value": 40,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 14,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.973
            },
            "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 97% of commits",
                "points": 0.6,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 97
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "OpenSSF Scorecard unavailable",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 2
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "0/2 decided PRs merged",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 0,
                      "decided": 2
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "OpenSSF Scorecard unavailable",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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": 88,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "chrplr",
              "public_repos": 126,
              "account_age_days": 5249
            },
            "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": "88 followers of chrplr",
                "points": 14,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 88,
                      "login": "chrplr"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "126 public repos, account ~14 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 126
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 14
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/chrplr/goxpyriment"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 2
            },
            "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 2 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "107 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 107
                    }
                  }
                ],
                "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": "good",
        "name": "Engineering Quality",
        "value": 76,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "OpenSSF Scorecard unavailable",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "topics": [
                "experiments",
                "go",
                "neuroscience",
                "psychology",
                "stimulation"
              ],
              "has_wiki": true,
              "homepage": "https://chrplr.github.io/goxpyriment/",
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://chrplr.github.io/goxpyriment/",
                "points": 15,
                "status": "met",
                "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": "5 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "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": 1,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Dependency lockfiles. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "dependency_lockfiles"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "source": "file_signals",
              "lockfiles": [
                "go.sum"
              ],
              "manifests": [
                "docs/requirements.txt",
                "examples/go.mod",
                "go.mod",
                "tests/go.mod"
              ],
              "has_codeql_workflow": false,
              "has_security_policy": false,
              "has_dependabot_config": false
            },
            "components": [
              {
                "key": "security_policy_security_md",
                "name": "Security policy (SECURITY.md)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 30
              },
              {
                "key": "dependabot_config",
                "name": "Dependabot config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "dependency_lockfiles",
                "name": "Dependency lockfiles",
                "detail": "published library — lockfiles are an application concern, not expected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "lockfiles_not_expected",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "codeql_workflow",
                "name": "CodeQL workflow",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "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": 3
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 64,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "good",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.56,
              "agent_instruction_files": [
                "CLAUDE.md",
                "GEMINI.md",
                "apparatus/CLAUDE.md",
                "clock/CLAUDE.md",
                "control/CLAUDE.md",
                "design/CLAUDE.md",
                "examples/CLAUDE.md",
                "geometry/CLAUDE.md",
                "media/CLAUDE.md",
                "paper/GEMINI.md",
                "results/CLAUDE.md",
                "staircase/CLAUDE.md",
                "stimuli/CLAUDE.md",
                "tests/CLAUDE.md",
                "triggers/CLAUDE.md",
                "units/CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 16734
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md, GEMINI.md, apparatus/CLAUDE.md, clock/CLAUDE.md, control/CLAUDE.md, design/CLAUDE.md, examples/CLAUDE.md, geometry/CLAUDE.md, media/CLAUDE.md, paper/GEMINI.md, results/CLAUDE.md, staircase/CLAUDE.md, stimuli/CLAUDE.md, tests/CLAUDE.md, triggers/CLAUDE.md, units/CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md, GEMINI.md, apparatus/CLAUDE.md, clock/CLAUDE.md, control/CLAUDE.md, design/CLAUDE.md, examples/CLAUDE.md, geometry/CLAUDE.md, media/CLAUDE.md, paper/GEMINI.md, results/CLAUDE.md, staircase/CLAUDE.md, stimuli/CLAUDE.md, tests/CLAUDE.md, triggers/CLAUDE.md, units/CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "56 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 29.9,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 56,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 67,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": true,
              "typed_language": false,
              "bootstrap_files": [
                "Makefile",
                "examples/Number-Comparison/Makefile",
                "paper/Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.56,
              "toolchain_manifests": [
                "examples/go.mod",
                "go.mod",
                "tests/go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile, examples/Number-Comparison/Makefile, paper/Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile, examples/Number-Comparison/Makefile, paper/Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "56 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 56,
                      "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": "OpenSSF Scorecard unavailable",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "primary_language": "Jupyter Notebook",
              "largest_source_bytes": 64154,
              "source_files_sampled": 267,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Jupyter Notebook without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Jupyter Notebook"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/267 source files over 60KB",
                "points": 54.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 267,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples",
                "notebooks"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples, notebooks",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples, notebooks"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "OpenSSF Scorecard did not return a usable result (2026/07/27 17:51:32 Warning: PATs stored in env variables GITHUB_AUTH_TOKEN and GITHUB_TOKEN differ. Scorecard will use the former.); skipping Scorecard checks"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-27T17:52:33.259082Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/c/chrplr/goxpyriment.svg",
  "full_name": "chrplr/goxpyriment",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

评分是信号,而非担保。 评分反映的是 GitHub 上公开可见的实践——不是代码审计,也不是安全保证。

缺失数据将被剔除并重新归一化权重,绝不按零分计。方法论已版本化并公开:指标 v1.13.0、模式 v0.27.0—— 完整方法论 · 指标知识库.

单项结果在整体记录中的位置: 汇总统计Go.