公开记录
软件健康报告模式 0.31.0 · 指标 2.5.0 · 2026-08-05 09:20 UTC

bigwhite / cc-session-migrate

Cross-node session migration and S3 backup for Claude Code.

Go未检测到许可证★ 5 星标⑂ 1 复刻始于 2026年7月在 GitHub 上查看 ↗
类型命令行工具如何判定

bigwhite/cc-session-migrate 的健康指数为 100 分中的 39 分,处于「薄弱」区间。 其得分最高的类别是AI Readiness(85/100),最低的是Community & Adoption(17/100)。 最近一次更新在 15 天前。 近期的大部分工作由 1 位贡献者完成。

39
总分 / 100
薄弱

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均,再依据公开记录的分布进行校准,使各等级具有百分位含义;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 34(存在风险)的上限。

39
卓越93-100公开记录中的最高层级(约前 5%);基本满足所有检验标准
优秀80-92各方面均表现强劲;仅有少量不足
良好65-79健康;不足之处有限且可控
中等50-64可接受,但存在明显不足;建议进行审查
薄弱35-49多个领域存在实质性薄弱环节
存在风险20-34存在重大薄弱环节;采用时应保持审慎
危急1-19问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

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

加权总体分 43 经校准后在公布的指数量表上为 39(记录校准 2026-08-02)。

所有权

Tony Bai个人账户
1,898 关注者74 个公开仓库始于 2010年9月reachauto

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Gogithub.com/bigwhite/cc-session-migratev0.1.1-216 天前

按类别列示的指标

活力

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

62中等 · 占总体的 21%
评分方式
28.8/36推送新近度 — 最近一次推送于 15 天前
0.7/36提交节奏 — 52 周中有 1 周有提交
17.3/18提交量 — 最近一年 83 次提交
0/10OpenSSF Scorecard:Maintained — project was created within the last 90 days. Please review its contents carefully
所用输入
commits_last_year83
human_commit_share1
days_since_last_push15
active_weeks_last_year1

发布纪律

84优秀
评分方式
27/27有发布版本 — 已发布 1 个发布版本
36/36发布时效 — 最近一次发布版本于 15 天前
12.6/27发布节奏 — 节奏未知(仅一次发布)
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count1
latest_release_tagv0.1.1
releases_from_tags
days_since_latest_release15
mean_days_between_releases
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

17危急 · 占总体的 17%
评分方式
9.8/60星标 — 5 个星标
0/25复刻 — 1 个复刻
0/15关注者 — 0 位关注者
所用输入
forks1
stars5
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

25存在风险
评分方式
22.5/22.5README
0/22.5许可证 — 未检测到许可证文件
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
readme_badges1
has_contributing
has_issue_template
has_code_of_conduct
readme_badge_servicesshields.io
has_pull_request_template

可持续性与治理

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

41薄弱 · 占总体的 23%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
3/10OpenSSF Scorecard:Contributors — project has 1 contributing companies or organizations -- score normalized to 3
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
0/42议题解决 — 0% 的议题已关闭
0/30PR 接受 — 没有已裁定的拉取请求或无数据
0/13Newcomer PR acceptance — 30 天内没有首次贡献者的 PR 得到裁决
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs0
open_issues1
closed_issues0
prs_merged_7d0
prs_decided_7d0
prs_merged_30d0
prs_decided_30d0
issue_closed_ratio0
closed_unmerged_prs0
first_time_authors_30d0
first_time_prs_merged_30d0
first_time_prs_decided_30d0
已排除计分(无数据或不适用):PR 接受, newcomer_pr_acceptance。 其余权重已重新归一化。
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
23.6/25所有者影响力 — bigwhite 有 1,898 位关注者
25/25既往记录 — 74 个公开仓库,账户约 15 年
所用输入
followers1,898
owner_typeUser
is_verified
owner_loginbigwhite
public_repos74
account_age_days5,789
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — go 上有 1 个软件包
35/35发布时效 — 最近一次发布于 16 天前
12/20版本历史 — 2 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesgithub.com/bigwhite/cc-session-migrate
ecosystemsgo
any_deprecated
min_days_since_publish16

工程质量

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

54中等 · 占总体的 19%

工程实践

30存在风险
评分方式
0/24CI 工作流
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
已排除计分(无数据或不适用):OpenSSF Scorecard:CI-Tests。 其余权重已重新归一化。

文档

90优秀
评分方式
30/30README
25/25文档目录
15/15文档 / 主页站点 — http://tonybai.com
10/10仓库描述
10/10主题标签 — 9 个主题标签
0/10Wiki
所用输入
topicsclaude-code, cli-tool, dev-tools, distributed-systems, golang, hub-and-spoke, s3-backup, session-migration, websocket
has_wiki
homepagehttp://tonybai.com
has_readme
has_docs_dir
has_description

安全

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

22存在风险 · 占总体的 16%

安全态势

22存在风险
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — 无数据
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
0/10Dangerous-Workflow — 无数据
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5许可证 — license file not detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — 无数据
0/5Pinned-Dependencies — 无数据
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — 无数据
6.8/7.5Vulnerabilities — 1 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate2.2
已排除计分(无数据或不适用):ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions。 其余权重已重新归一化。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?权重刻意设小(4%):代理工具链是一项真实的维护信号,但完全不具备的仓库仍可达到 100/100。

85优秀 · 占总体的 4%
评分方式
45/45代理指令 — CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 83 次人类提交中有 82 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.988
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes303
评分方式
18/18一条命令的引导启动 — Makefile
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — Go(静态类型)
10/10可复现环境 — lockfile
10/10已体现的代理实践 — 最近 83 次提交中有 81 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — 无数据
所用输入
has_nix
has_tests
lockfilesgo.sum
has_dockerfile
typed_language
bootstrap_filesMakefile
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.976
toolchain_manifestsgo.mod
dependency_bot_commit_share0
已排除计分(无数据或不适用):OpenSSF Scorecard:Pinned-Dependencies。 其余权重已重新归一化。
评分方式
45/45可类型检查的代码 — Go(静态类型)
55/55可控的文件大小 — 采样的 47 个源文件中有 0 个超过 60KB
所用输入
primary_languageGo
largest_source_bytes16,162
source_files_sampled47
oversized_source_files0

关键数据

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

数据采集警告

  • 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 2.2 / 10
2.2综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。Scorecard v5.5.0 · 2026-08-05 09:20 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
不适用CI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
不适用Dangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
不适用Packagingpackaging workflow not detected
不适用Pinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
不适用Token-PermissionsNo tokens found
9Vulnerabilities1 existing vulnerabilities detected
直接依赖 7
注册表软件包版本约束清单文件
Gogithub.com/aws/aws-sdk-go-v2v1.42.1go.mod
Gogithub.com/aws/aws-sdk-go-v2/credentialsv1.19.29go.mod
Gogithub.com/aws/aws-sdk-go-v2/service/s3v1.105.2go.mod
Gogithub.com/robfig/cron/v3v3.0.1go.mod
Gogithub.com/schollz/progressbar/v3v3.19.1go.mod
Gogithub.com/spf13/cobrav1.10.2go.mod
Gogithub.com/spf13/viperv1.21.0go.mod
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "icon": {
      "bytes": 5394,
      "width": 180,
      "height": 180,
      "rejected": [],
      "collected": true,
      "media_type": "image/png",
      "source_url": "https://tonybai.com/apple-touch-icon.png",
      "source_type": "homepage",
      "content_hash": "faa930f38af93aff4e96f7735923c62a440effa8e0463c0434c839ea308d2acb",
      "candidates_considered": 1
    },
    "repo": {
      "topics": [
        "claude-code",
        "cli-tool",
        "dev-tools",
        "distributed-systems",
        "golang",
        "hub-and-spoke",
        "s3-backup",
        "session-migration",
        "websocket"
      ],
      "is_fork": false,
      "size_kb": 10248,
      "has_wiki": false,
      "homepage": "http://tonybai.com",
      "languages": {
        "Go": 201965,
        "Shell": 6036,
        "Makefile": 819
      },
      "pushed_at": "2026-07-20T09:23:12Z",
      "created_at": "2026-07-13T03:08:31Z",
      "owner_type": "User",
      "updated_at": "2026-07-25T18:06:28Z",
      "description": "Cross-node session migration and S3 backup for Claude Code. ",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "https://tonybai.com",
      "name": "Tony Bai",
      "type": "User",
      "login": "bigwhite",
      "company": "reachauto",
      "location": "P.R. China",
      "followers": 1898,
      "avatar_url": "https://avatars.githubusercontent.com/u/419088?v=4",
      "created_at": "2010-09-28T12:20:24Z",
      "is_verified": null,
      "public_repos": 74,
      "account_age_days": 5789
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2026-07-20T09:26:31Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "4a11405e3aa29153165472432cbeb7006ef23511",
          "body": "…dination\n\nReadLoop dispatched JSON headers and released readMu, then immediately\nlooped back to read the next frame — racing with Request() or\nStreamRequestWithHeader() which needed readMu to consume the binary\nframe. If ReadLoop won, it read binary data as JSON, producing\n\"invalid json frame\" erro\n[…]\nfinishes\nreading the binary frame. All error paths (timeout, write failure,\nconnection close) properly signal to prevent ReadLoop from hanging.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ws): resolve ReadLoop/binary-consumer race via streamPending coor…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-20T09:13:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "01a230ab511c684f4773105d2b8a528fe1aa64eb",
          "body": "The previous fix introduced a deadlock: ReadLoop held readMu while\nreading the binary frame (for DataSize > 0 responses), which blocked\nStreamRequestWithHeader from ever acquiring readMu to stream the data.\n\nRoot cause: ReadLoop and StreamRequestWithHeader both need to read\nthe binary frame, but the\n[…]\n io.Copy (streaming path)\n- For unmatched responses with binary data, ReadLoop discards the\n  binary frame via NextReader + io.Copy(io.Discard)\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ws): eliminate readMu deadlock in ReadLoop binary frame handling",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-20T08:51:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1366537b88f0d64e210c1ecc715104d07ad218b5",
          "body": "ReadLoop and StreamRequestWithHeader were both reading from the same\nWebSocket connection simultaneously, violating gorilla/websocket's\n\"one concurrent reader\" constraint. This caused protocol errors\n(RSV1/RSV3 set, bad opcode, bad MASK) during pull relay operations.\n\nFix: add readMu mutex to Conn, \n[…]\nore dispatching to pending channels. StreamRequestWithHeader\nacquires readMu during NextReader+io.Copy to consume the binary frame\nexclusively.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ws): resolve concurrent reader race in StreamRequestWithHeader",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-20T08:25:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "576cacf0f6f4f519c6525e371cd1c52216544460",
          "body": "- client.go: log HTTP request/response with timing for pull and push\n- hub.go: log Request/StreamRequestWithHeader lifecycle and Close pending count\n- server.go: log local pack/unpack paths and session ID resolution\n- cmd/session.go: log operation-level events for pull/push CLI commands\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(logging): add structured logging for pull/push relay flow",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-20T08:04:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "59cedc50610b90101352a65e435cfe70634254f8",
          "body": "- Add real-time progress bars for session pull/push operations (single and batch)\n- Fix push progress bug: use progressReader for streaming upload progress\n- Make relay request timeout configurable via cluster.request_timeout (default 15m)\n- Increase default timeouts from 5min to 15min for large session transfers\n- Set Content-Length in pull relay response using StreamRequestWithHeader\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(session): add progress bar for pull/push and configurable timeout",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-20T07:32:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8b32b09131b445feb56475a473258da5c7412e27",
          "body": "go install produces a binary named cc-session-migrate, but all\nexamples use csm. Add alias setup steps for zsh/bash and PowerShell.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): add csm alias instructions for macOS/Windows install",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:35:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8ff7bccdb961566793b4dfa96381b263eb39c0a2",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): add donation section with PayPal, WeChat Pay and Alipay",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:23:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2997c0e1f974a810c5b750bd0e25d2b57267dd0d",
          "body": "Agent Ctrl+C took up to 90s to exit because ReadMessage() blocked\nuntil PongTimeout. Add AgentClient.Stop() to close the connection\nimmediately, unblocking the read loop. Node.Stop() now closes the\nWebSocket before cancelling context.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(agent): close WebSocket on shutdown to fix slow Ctrl+C exit",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0074eb51a16590bf2290a5198ffea2372e4068c0",
          "body": "`csm` supports ID prefix matching (minimum 8 chars), but Claude Code's\n`--resume` flag requires the complete UUID. Added a note and a full ID\nexample to prevent confusion.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): note that claude --resume requires full session ID",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9a80c5a82689d0af20c340bd2ea727b354355dc1",
          "body": "Three fixes for post-pull issues:\n\n1. Unpack --force now removes stale copies of the same session ID from\n   other project directories before unpacking, preventing duplicate\n   entries in session list.\n\n2. history.jsonl entries now use Claude Code's expected format:\n   \"project\" instead of \"cwd\", pl\n[…]\nupdate.\n\n3. Scan deduplicates sessions by ID, keeping only the most recently\n   modified copy when the same ID appears in multiple directories.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(session): clean stale copies, align history.jsonl format, dedup scan",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e823a8a81f6db18d6d0fa6f5feb0cd310c215380",
          "body": "Two bugs caused \"claude -r\" to fail after pulling a session:\n\n1. Unpack did not rename the source project's encoded directory to\n   match the target path. Files landed in projects/<source-encoded>/\n   but Claude Code looks in projects/<target-encoded>/.\n\n2. Remote pull relay did not set the X-Source\n[…]\ngithub/com\").\n\nresolveRemoteSession now returns *SessionMeta instead of just the ID,\nenabling handlePull to set HdrSourcePath for remote relay.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(session): rename project directory on unpack to match target path",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f5a6be88fc38b261f57a64967da4b59bd31fcb59",
          "body": "…ture\n\nReplace peer-to-peer HTTP with hub-and-spoke WebSocket relay through the\nLeader server. Agents now maintain outbound WebSocket connections only,\neliminating NAT traversal issues.\n\nPhase 2: Rewrite agent node to use ws.AgentClient with message handler\nPhase 3: Add Leader relay handlers for /v1\n[…]\nlay\nPhase 5: Remove heartbeat, migration package, and stale API types\nPhase 6: Update README architecture diagram, mark old specs as superseded\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(arch): migrate from mesh to hub-and-spoke WebSocket architec…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3439bb644bb442ef5b9aa5ccc88e8a6c9f9ebbdd",
          "body": "New internal/ws/ package implementing the hub-and-spoke communication\nlayer between the cluster leader and agent nodes:\n\n- protocol.go: message type constants, DataHeader struct, SessionInfo\n- hub.go: Hub (connection registry) + Conn (request-response correlation\n  with UUID ids, StreamRequest for z\n[…]\n loop + exponential\n  backoff reconnect), MessageHandler interface for local operations\n\nAdds github.com/gorilla/websocket v1.5.3 dependency.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ws): add WebSocket hub-and-spoke infrastructure (Phase 1)",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "38bc7eb6ca59e3aba55ccb8e3d9a2b6850c1c4bc",
          "body": "… plan\n\nThe current mesh topology (peer-to-peer HTTP) fails when agents are\nbehind NAT (e.g. MacBook on home network). The new design replaces\nit with a hub-and-spoke model where:\n\n- Agents establish persistent WebSocket connections to the leader\n  (outbound, NAT-friendly)\n- All cross-node session o\n[…]\nto run HTTP servers or expose ports\n\nFiles added:\n- doc/spec/008-hub-spoke-architecture/spec.md\n- doc/plan/008-hub-spoke-architecture/plan.md\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(architecture): add hub-and-spoke WebSocket architecture spec and…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e60707ea2b6b61a67ff0b7283fb30454bf95e182",
          "body": "When nodes bind to 0.0.0.0 (the default), the wildcard address was\nregistered as the advertise address in the cluster topology. Other\nnodes trying to reach it via \"http://0.0.0.0:9827\" end up connecting\nto themselves, breaking cross-node session list/pull/push.\n\nTwo fixes:\n- api/server.go handleJoin\n[…]\nerver node's own\n  self-registration\n\nIf users bind to a specific address (e.g. --bind 10.0.0.5:9827), it\nis used as-is without substitution.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cluster): replace wildcard 0.0.0.0 with real IP in node topology",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "45576da258ca4a7bce0c66b307c545efc5615863",
          "body": "cluster join was redundant with csm agent --server-addr --auth-token,\nwhich now handles both registration and daemon startup. Each operation\nshould have exactly one entry point.\n\nFinal cluster subcommand set:\n- leave: deregister node and clear local credentials (use after daemon stops)\n- list:  view cluster topology\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(cmd): remove cluster join subcommand",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "77e530c23ebd487d5fc0fac71f8709878c43a57a",
          "body": "Before: macOS users needed two commands (cluster join + agent), and\nrunning agent after join would fail with HTTP 409 since the node was\nalready registered as \"online\" by the join command.\n\nAfter: a single command does it all:\n  csm agent --server-addr <addr> --auth-token <token> --name my-macbook\n\n\n[…]\n join now prints \"Run 'csm agent' to start\n  the daemon\" after success\n- README.md / README_zh.md: macOS/Windows section shows single command\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(agent): auto-join on startup, single-command macOS setup",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "328cafff1259a6de67b2079c3680a6493449a462",
          "body": "When running under systemd without User= directive, os.UserHomeDir()\nreturns \"\" because $HOME is not set. This caused DefaultConfigPath()\nto return a relative path \".csm/config.yaml\" instead of the absolute\n\"~/.csm/config.yaml\", making the server read/write a wrong config file\n(e.g. /.csm/config.yam\n[…]\nwas the root cause of the auth token mismatch: the server was\nusing /.csm/config.yaml while the operator was checking /root/.csm/config.yaml.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(config): handle missing HOME env var in systemd context",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e3c3f183f68c054da412146a7129bae690510441",
          "body": "Add auth token prefix (first 8 chars) and length to server startup\nlogs to help diagnose token mismatch during cluster join. Log in both\ninitCluster() (when generated or loaded) and Start() summary.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(agent): log auth token prefix at server startup",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "79ac3aa3dcafc77531d0826db14b88c7900e6cc8",
          "body": "Show expected and received token lengths in the 401 error message\nand log prefix comparison at debug level to diagnose auth failures.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "debug(api): add auth token length logging to join handler",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0a032dffb2c92fa55c7bce5a74d85bdaa4c23b1c",
          "body": null,
          "is_bot": false,
          "headline": "chore: go1.27rc1 -> go1.25.0 in go.mod",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8f6a01da963e947fab7dce96ca34d6dccc55ff62",
          "body": "The server node is not just a cluster manager — it's a full agent\nthat also participates in session migration. Redraw the diagram\nto show all nodes as peers with bidirectional migration arrows,\nand annotate the server's additional cluster management role.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): update architecture diagram to show server as full agent",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7c04c66e2b5b841c2111fd4e86b172a64b73d108",
          "body": "- Add tip recommending running the server (leader) on a Linux server\n- Merge macOS/Windows instructions (both use go install + manual run)\n- Add Windows to platform support table\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): recommend Linux for server node, add Windows support",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a8ddd3d9ff8525dd260152555a70ac744f642c41",
          "body": "Move macOS install and cluster setup instructions from the\nPlatform Support section into the Install and Set Up a Cluster\nsections, so users see both Linux and macOS options side by side\nat each step. Simplify Platform Support to a table only.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): add macOS instructions to each Quick Start step",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2fd1498c3ad3bfa4c63be1ac335c9c6d5d90b84f",
          "body": "Replace the multi-option installation section with a single\nrecommended method (install script). Replace the standalone\n`csm agent --server` command with the systemctl-based workflow\nthat matches actual Linux deployment. Move macOS/manual usage\nto the Platform Support section as a secondary option.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): simplify Quick Start to one recommended path",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "246804478dfd71c16d34e3119d5ada9d8062163e",
          "body": "config.Load() previously returned an error when ~/.csm/config.yaml\ndid not exist, causing root.go to fall back to DefaultConfig()\nwhich bypassed all CSM_ environment variables. This meant systemd\nservices using /etc/cc-session-migrate/env with CSM_AGENT_ROLE=server\nwould still start in agent mode.\n\n\n[…]\nr\nstill applies defaults + env vars even without a config file.\nSimplify root.go accordingly (remove the fallback branch and\nhelper functions).\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(config): apply env vars when config file is missing",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "95792a08f1a6a92d3d1db21ff84712628d08b88e",
          "body": "Update T502-T508 interface signatures and prd.md directory tree\nto reflect the HTTP API migration.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: fix remaining gRPC references in tasks.md and prd.md",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "19831c5380c6f9308eba700a6b7e7d8cd6637718",
          "body": "Remove all gRPC/protobuf dependencies and replace with a lightweight\nJSON over HTTP API using Go standard library net/http. This enables\n`go install` without requiring buf/protoc toolchain.\n\nChanges:\n- Delete proto/, gen/, buf.yaml, buf.gen.yaml\n- Add internal/api/ package (types, server, client)\n- \n[…]\n dependencies\n- Update Makefile (remove proto/lint/breaking/buf-setup targets)\n- Update all docs (specs, plan, tasks, prd, READMEs, install.sh)\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(api): replace gRPC with JSON over HTTP",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "756b8ccdf920993222abc6923b9067963d7e9e2c",
          "body": "Replace raw protoc with buf.build's buf CLI for protobuf code\ngeneration. Add buf.yaml and buf.gen.yaml with BASIC lint and\nFILE-level breaking change detection. Add make lint/breaking/buf-setup\ntargets. Generated files are functionally identical.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(proto): migrate from protoc to buf CLI",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "63b49f3b8af03c17167d0961416936684cfb331d",
          "body": "…_zh.md\n\nEnglish README is now the main documentation with a link to the\nChinese version. Both versions cover the same content: architecture,\nquick start, CLI reference, configuration, and development guide.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add English README as primary, rename Chinese version to README…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "467b9f386b76d05a2655966dc8ec0163e33d3a7c",
          "body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add Chinese README with full project documentation",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f0453b2202b72d1e9dfcf0d12b6038fbeeb9d8a0",
          "body": "Update tasks.md to reflect completion of all 7 phases (49 tasks),\nadding real commit hashes for Phase 5-7 and updating the statistics\ntable to show 100% completion.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(tasks): mark all 49 tasks complete with commit references",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "72a2ff6bb306105a41e2d66772c0aee9b0d6c816",
          "body": "Both Server and Node now start the backup Scheduler on boot when\nconfig.backup.auto_enabled is true and S3 is configured. The scheduler\nruns incremental backups (mtime-based) on the configured cron interval\nand cleans expired entries on each run. Scheduler is stopped gracefully\non shutdown.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T706): integrate automatic backup scheduler into server and agent",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3243f7be3675f0fa4b2d392a3b4f1f2feb4499ff",
          "body": "backup create [--session <id>] backs up one or all sessions to S3,\nprinting a batch report for multi-session runs.\n\nbackup list [--node <name>] [--session <id>] [--format json] queries S3\nand displays backup entries sorted by timestamp descending.\n\nbackup restore --node <name> --session <id> [--time\n[…]\n(or specified) backup.\n\nAll commands validate S3 config upfront with a clear error message\npointing to `csm backup config` when not configured.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T705): implement backup create/list/restore CLI commands",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "be8ba88d25e11a221d0e801edae8e7c35a3d3341",
          "body": "Scheduler uses robfig/cron for periodic backups. Only sessions whose\nmtime changed since the last run are backed up (incremental). Expired\nbackups (older than retention_days, default 30) are cleaned up, with\na minimum of 3 backups retained per session.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T704): implement automatic backup scheduler with expiration cleanup",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ff345c1f30b5581504eab259deb2d4f83a575ce3",
          "body": "RestoreBackup downloads a backup archive from S3, auto-selects the\nlatest if no timestamp is specified, extracts the source project path\nfrom the embedded manifest, and unpacks locally with optional path\nremapping. Also exports ReadManifestFromTar for external use.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T703): implement backup restore with S3 download and unpack",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2bce640704ea44e03fe4dc89e90c5ff1d050895c",
          "body": "ListBackups queries S3 with an optional node/session prefix filter,\nparses tar.gz keys into BackupInfo structs (node, session, timestamp,\nsize), and sorts by timestamp descending. Malformed keys are silently\nskipped.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T702): implement backup listing with S3 key parsing",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4384a493c17c4b794ec7e70375aba3acd45813a2",
          "body": "CreateBackup packs a single session and uploads the tar.gz archive\nand manifest.json to S3 under key structure:\n  backups/{node}/{session-id}/{timestamp}.tar.gz\n  backups/{node}/{session-id}/{timestamp}.manifest.json\n\nCreateAllBackups scans all local sessions and backs them up sequentially.\nA single failure does not abort the batch; results are collected in\nBackupReport.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T701): implement backup creation with S3 upload",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "aff96d02732def085212b4a5566b3a45897750bd",
          "body": "`csm backup config --endpoint <url> --bucket <name> [--access-key ...]\n[--secret-key ...] [--region auto]` saves S3 credentials to the config\nfile after verifying connectivity via HeadBucket. Fails early if the\nbucket is unreachable or credentials are invalid.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T602): implement backup config command with connection verification",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fd814b38007cf6effd46c2ffc5213e5328da8f55",
          "body": "S3Client wraps aws-sdk-go-v2 with bucket-aware operations:\nVerifyConnection (HeadBucket), Upload (PutObject), Download (GetObject),\nList (ListObjectsV2 with pagination), Delete, and DeletePrefix.\n\nUses BaseEndpoint for R2/MinIO/custom S3-compatible endpoints with\npath-style addressing. Region defaults to us-east-1 if not specified.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T601): implement S3 client with custom endpoint support (R2/MinIO)",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "df50e4164c2bd96c0c593cec8e46e350a51b5cc9",
          "body": "The --node flag on `csm session list` now queries a remote node's\nMigrationService via gRPC ListSessions, converts the response to\nSessionMeta, and formats it with the same table/JSON output used\nfor local listing. Node resolution supports both name (topology\nlookup) and host:port address.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T509): implement session list --node for remote session queries",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5e77641cc6a4c22f7508df99eccec1a37e12c1ff",
          "body": "session pull --from <node> <session-id> streams a session from a remote\nnode, verifies checksum, and unpacks locally. session push --to <node>\n<session-id> packs locally and streams to the remote node.\n\nBoth commands support:\n- Node reference by name (topology lookup) or host:port address\n- Session \n[…]\nllAll/PushAll\n- --force to overwrite existing sessions\n- --project to remap project paths\n- Progress bar (TTY) or text percentage (pipe) output\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T508): implement session pull/push CLI commands with progress bar",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "95e22ec007c109c098d9fc3c5067559686c73daf",
          "body": "…orting\n\nPullAll lists sessions from a remote node and pulls each one sequentially.\nPushAll lists local sessions and pushes each to the remote node. A single\nsession failure is recorded in BatchReport.Details and does not abort\nthe remaining sessions. Context cancellation stops the batch early.\n\nTests cover multi-session pull/push and empty node edge case.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T507): implement batch PullAll/PushAll with failure-tolerant rep…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "709c41ace7752418f03f71d57b0201be8648aa86",
          "body": "NewProgressWriter returns a schollz/progressbar when stderr is a TTY,\nor a plain text percentage reporter when piped. Pull and Push now\naccept an optional io.Writer for progress tracking (nil to disable).\n\nTests updated to pass nil progress writer.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T506): add progress bar for session transfers (TTY-aware)",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "956b73e1de3764c9f83453cdc050f457fdf7648f",
          "body": "…ion tests\n\nPush packs a local session, opens an UnpackSession client stream to the\nremote node, sends metadata in the first chunk, streams 64KB data chunks\nwith SHA-256 checksum in the last chunk, and waits for the remote\nunpack confirmation.\n\nTests cover: successful push, push with project path remapping, and\npush of a non-existent local session.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T505): implement session Push with streaming upload and integrat…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2f4b8ab04e233fcabb252a8c19bab76c841ea4fb",
          "body": "…egration tests\n\nPull connects to a remote node's MigrationService, streams the packed\nsession archive back in 64KB chunks, verifies the SHA-256 checksum,\nand unpacks into the local data directory with optional path remapping.\n\nTests use bufconn for in-memory gRPC, covering:\n- Successful pull with source path preserved\n- Pull with explicit target project path remapping\n- Pull of non-existent session returns error\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T504): implement session Pull with checksum verification and int…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fea250c8b79707643cb6b295204166c890bc96b4",
          "body": "…ndpoints\n\nThe MigrationService is now registered in server.Start() and node.Start()\nso that every cluster node (leader and agents alike) can accept inbound\nListSessions / PackSession / UnpackSession RPCs from peer nodes.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T503): register MigrationService on both server and agent gRPC e…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7a1d343948b26253619f0cf2fe85443f4f55534d",
          "body": "…treaming\n\nMigrationServer.ListSessions scans local sessions via the session package.\nPackSession packs a session and streams it as 64KB DataChunk messages with\nmetadata in the first chunk and checksum in the last. UnpackSession\nreceives the stream, reassembles the tar.gz, and delegates to session.Unpack.\nTests cover listing, packing, unpack round-trip, and error cases.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T502): implement MigrationService gRPC server with pack/unpack s…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "965a8a39c683d0ec74f35e7d6a34a43d01441346",
          "body": "…ession\n\nPackSession streams packed session data as 64KB DataChunk messages.\nFirst chunk carries metadata (total_size, session_id, source_path).\nLast chunk carries SHA256 checksum. UnpackSession receives a stream\nof DataChunks and returns success/failure response.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T501): extend MigrationService protobuf with PackSession/UnpackS…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9850096a7ce37fa3b8e4ff3784bd4ba7d743b1e2",
          "body": "…tations)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: remove cluster doc.go placeholder (superseded by real implemen…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "398693898feeba79953a4f839bf368a8ca61f167",
          "body": "csm session list scans ~/.claude/projects/ for session JSONL files,\nsorts by last modified (descending), and outputs as table (default)\nor JSON (--format json). Includes human-readable relative times and\nfile sizes. Remote mode (--node) returns a helpful not-yet-implemented\nmessage.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T407): implement session list command with local scanning",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2cd76408fb1e30bdfe57759b22b03deeb2d5af32",
          "body": "MigrationService.ListSessions returns all sessions on a node with\nsession_id, project_path, data_size, last_modified, and file_count.\nPackSession/UnpackSession streaming RPCs will be added in Phase 5.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T406): define MigrationService protobuf with ListSessions RPC",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4c346d582f43b8a5c0478e554e95b9c8154de139",
          "body": "…pping\n\nUnpack() extracts tar.gz to a staging directory, verifies SHA256 checksum,\napplies path remapping if source/target paths differ, atomically moves\nfiles to final locations, and updates history.jsonl. Supports --force\nto overwrite existing files. Includes path traversal protection.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T404): implement session unpack with staging, checksum, and rema…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b43ea0430b3bcf4da9219febff1ec907a86c5ee0",
          "body": "RemapPaths replaces source project path with target path in session\nJSONL files and subagent data. UpdateHistoryJSON appends or force-updates\na session entry in history.jsonl with the new project path.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T405): implement path remapping for JSONL files and history.jsonl",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6b01f1cbce59b609d114e64ceb66351a310050ce",
          "body": "Pack() collects all session files, creates a tar.gz archive with a\nmanifest.json at the root containing session metadata, file list,\nand SHA256 checksum. readManifestFromTar() extracts the manifest\nfor verification during unpack.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T403): implement session packer with tar.gz and manifest",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "73140b89864955912df9d1213c8add308f0a83fb",
          "body": "MatchSessionID supports minimum 8-character prefix matching with\ncase-insensitive comparison. Returns ErrPrefixTooShort, ErrNotFound,\nor ErrAmbiguous (wrapping count) for respective error conditions.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T402): implement session ID prefix matching (git-style)",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cd82a805bb278679ccb64dfd78e5e2d984c29070",
          "body": "Scan() discovers all sessions under ~/.claude/ by traversing projects/\ndirectories, matching .jsonl files, and collecting associated files from\nsession-env/, tasks/, and subagent directories. decodeProjectPath() maps\ndirectory names back to filesystem paths (lossy: - → /).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T401): implement session scanner with project path decoding",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "21617210c7a9b9c438111204df305cd28795f957",
          "body": "cluster join: connects to server via gRPC, sends Join RPC, saves cluster\nconfig (ID, token, server addr), outputs node list.\ncluster leave: sends Leave RPC to server, clears cluster config. Supports\n--force for unreachable servers.\ncluster list: subscribes to TopologyStream for initial snapshot, outputs\nas table (default) or JSON (--format json).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T304-T306): implement cluster join/leave/list commands",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "14e1ce57353b38bc5ec7d4900fd42cbff9fd8ba0",
          "body": "StartTopologySync subscribes to the server's TopologyStream RPC and\napplies incremental updates (join/leave/status_change) to the local\ntopology. Full snapshots replace all nodes. Handles non-existent node\nedge cases safely.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T303): implement topology sync client for agent-side streaming",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6288eed48ddb6e8e3f15f887fea926ab6dae3dbf",
          "body": "… streaming\n\nServer.Join now rejects duplicate online node names. Server.Leave broadcasts\ndeparture events. Added TopologyStream server-side streaming RPC: sends\ninitial snapshot then pushes join/leave/status_change events to all active\nsubscribers via buffered channels. Extracted topologyToProtoNodes helper.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T301+T302): enhance Join/Leave with duplicate check and topology…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ab0d440ad04a6868492ab52238fe7a2eb7544fcb",
          "body": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: add .gitignore and remove binary from tracking",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0bdad40da6161237157bf8c4366f1261a0beac44",
          "body": "…tions)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: remove agent doc.go placeholder (superseded by real implementa…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "64fbad7dcdaaa38bc45ba8a5820438968379e241",
          "body": "cmd/agent.go now dispatches to Server.Start() (server mode) or\nNode.Start() (agent mode) based on --server flag or config role.\nFlag values override config. Signal handler triggers graceful stop.\nServer implements Join/Leave RPC handlers; Node sends Leave RPC\non shutdown before closing the gRPC connection.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T207): wire agent sub-command to server/node lifecycle",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0f89b0097fe45c2a8ac911e81826e94cc67a164c",
          "body": "SetupSignalHandler registers OS signal listeners that invoke the provided\nstopFn (Server.Stop or Node.Stop), allowing the gRPC server to drain\ngracefully before process exit.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T206): implement graceful shutdown via SIGINT/SIGTERM handler",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b4c53d9ea5f4555408625dcf3c516a07bee40f49",
          "body": "Node sends Heartbeat RPC every 30s with node name, timestamp, and uptime.\nServer handles Heartbeat RPC by updating topology. Server-side checker\nruns every 60s and marks nodes offline after 5min without heartbeat.\nServer node itself is excluded from offline marking.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T205): implement heartbeat mechanism for agent-server liveness",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ca737143bf33999239666998976f7bec9eedc61c",
          "body": "Node struct connects to server via Join RPC, populates local topology\nwith returned node list, and starts a local gRPC listener for inbound\nmigration requests. Includes integration test with in-process mock\nserver validating the full join flow and auth token rejection.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T204): implement agent node mode with cluster join via gRPC",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "37198cfe3e0b197fb8d7383a16d2f7c4b8c8ae06",
          "body": "Server struct embeds UnimplementedClusterServiceServer and holds config,\ntopology, and gRPC server. initCluster() generates a UUID v4 cluster-id\nand 32-byte random auth token on first boot, persisting to config.yaml\nwith 0600 permissions. Existing values are preserved on subsequent boots.\nStart() binds gRPC listener and blocks until context cancellation.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T203): implement server mode with cluster identity generation",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ef3e5649645b5717c138819e1a38edd5e43e391f",
          "body": "…-safe access\n\nTopology manages cluster membership as a thread-safe map with RWMutex.\nSupports AddNode, GetNode, RemoveNode, UpdateHeartbeat, MarkOffline,\nand sorted ListNodes (server-first, then alphabetical by name).\nTests cover CRUD, sorting, 50-goroutine concurrency, and edge cases.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T202): implement cluster topology data structure with concurrent…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9e95f24a6a9fd4da6ac1284b449054423deeea52",
          "body": "- proto/cluster.proto: ClusterService with Join, Leave, Heartbeat,\n  TopologyStream RPCs; NodeInfo, JoinRequest/Response, LeaveRequest/Response,\n  HeartbeatRequest/Response, TopologyRequest, TopologyUpdate messages\n- gen/cluster.pb.go: generated protobuf Go code\n- gen/cluster_grpc.pb.go: generated gRPC service stubs\n- Installed protoc + protoc-gen-go + protoc-gen-go-grpc\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T201): add ClusterService protobuf definition and generated code",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bd50f11a466de883619e2194de21bdea6b91f15b",
          "body": "T111 - scripts/cc-session-migrate.service:\n  - systemd unit file with EnvironmentFile, Restart=on-failure, RestartSec=5\n  - StandardOutput/Error to journal for journald integration\n\nT112 - scripts/install.sh:\n  - Detect OS/Arch (linux/darwin, amd64/arm64)\n  - Install binary to /usr/local/bin/\n  - Ad\n[…]\nm/config.yaml with 0600 permissions\n  - Print platform-specific next steps\n\nPhase 1 complete. All CLI commands and infrastructure are in place.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(T111+T112): add systemd service file and install script",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "527a982533b7333874e8ddb62ea94a708c36a32e",
          "body": "- cmd/root.go: root command with --config and --verbose global flags,\n  PersistentPreRunE for log init and config loading\n- cmd/version.go: version output with ldflags-injected build info\n- cmd/agent.go: agent command skeleton (--server, --server-addr, --auth-token,\n  --bind, --name, --data-dir flag\n[…]\nestore sub-commands with S3 flags\n- main.go: entry point using cmd.NewRootCmd()\n\nAll commands output correct --help matching PRD §6 CLI design.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T105-T110): implement CLI framework with all sub-command skeletons",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4ab0f992a77f1dc7f82f8b83f6fc54ec927f4c41",
          "body": "- Config struct with Node, Agent, Cluster, S3, Backup sections\n- Load(): YAML file + CSM_ env var overrides (env takes precedence)\n- Save(): persist to YAML with 0600 permissions (secrets protection)\n- DefaultConfig(): sensible defaults (hostname, ~/.claude, port 9827)\n- EnsureConfigDir(): create ~/.csm/ directory\n- 6 tests: defaults, save/load round-trip, env override,\n  non-existent file, config dir creation, default path\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T104): implement configuration management with viper",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d286ee20cdb44230f44297547620aa08b900d437",
          "body": "- Init(verbose, daemon): CLI mode (text→stderr) or daemon mode (JSON→stdout)\n- Info/Debug/Error/Warn: convenience wrappers around slog\n- Verbose flag controls debug vs info level\n- 6 tests covering: verbose/non-verbose filtering, all log levels,\n  key-value args, CLI and daemon mode initialization\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(T103): implement structured logging module with slog wrapper",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5a5c4748ccc44d6de0fd6f3b1f1cb16f7a6bba19",
          "body": "- build: compile with ldflags injection (version, buildTime, goVersion)\n- proto: protoc command for .proto → Go code generation\n- test: go test -v ./...\n- clean: remove bin/ directory\n- install: install binary to /usr/local/bin\n- help: display available targets\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(T102): add Makefile with build, proto, test, clean targets",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e4a999ce2d14f774253537aea1b8ce9e8112e8b5",
          "body": "- go mod init github.com/bigwhite/cc-session-migrate\n- Create directory tree: cmd/, internal/{agent,cluster,session,\n  migration,store,backup,config,log}/, proto/, gen/, scripts/\n- Add placeholder doc.go in each package for build verification\n- Add minimal main.go entry point\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(T101): initialize Go module and project directory structure",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2650d40229b3e70d2a18dac31f32924ce0d7e112",
          "body": "Break down implementation plan into 49 atomic tasks:\n- Phase 1 (T101-T112): CLI framework, config, Makefile, install script\n- Phase 2 (T201-T207): Agent daemon, protobuf, heartbeat, graceful shutdown\n- Phase 3 (T301-T306): Cluster join/leave/list, topology sync\n- Phase 4 (T401-T407): Session scanner\n[…]\n06): Backup create/list/restore, scheduler, agent integration\n\nEach task includes: goal, files, interfaces, key points, and verification steps.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(plan): add atomic task list with 49 tasks across 7 phases",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b1876f63f1c14b19c50c5c7aadf1a9a0242fadb4",
          "body": "7-phase implementation plan based on feature specs:\n- Phase 1: CLI framework + config (007)\n- Phase 2: Agent daemon core (001)\n- Phase 3: Cluster management (002)\n- Phase 4: Session scan & pack (003)\n- Phase 5: Session migration (004)\n- Phase 6: S3 config (005)\n- Phase 7: Backup & restore (006)\n\nEach phase includes: step-by-step tasks, key files, Go interfaces,\nprotobuf definitions, verification steps, and testing strategy.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(plan): add technical implementation plan",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1b1fa353dd8ff2836dad4a091c31ed50e9a3effd",
          "body": "Break down PRD into 7 feature specs:\n- 001-agent-daemon: server/agent modes, heartbeat, systemd, macOS foreground\n- 002-cluster-management: join/leave/list commands, topology sync\n- 003-session-scan-pack: session scanning, tar.gz packing/unpacking, path mapping\n- 004-session-migration: pull/push com\n[…]\nlias setup\n\nEach spec includes: scope, requirements, gRPC definitions (where applicable),\ndata structures, error handling, and output examples.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(spec): add feature specs for all 7 modules",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2f5f31e09eea50a9c6296478bc3f31fc44ad214f",
          "body": "macOS has no systemd. Update PRD to reflect:\n- Linux nodes: managed by systemd (both server and agent)\n- macOS nodes: foreground `csm agent` (optionally with tmux)\n- Remove launchd from Phase 4 milestone\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(prd): clarify macOS uses foreground mode instead of systemd",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "305ef82ac86d368b4c61cd8068126cf1107b8832",
          "body": "…3 config\n\n- Add explicit migration scope constraint: only local<->remote, no\n  third-party relay between two remote nodes\n- Unify systemd lifecycle management for all nodes (both server and agent)\n- Make S3 configuration independent per node (no server distribution)\n- Add both server and agent env file examples\n- Update cluster setup flow to show unified systemd-based workflow\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(prd): clarify migration scope, systemd for all nodes, per-node S…",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ac1be05362ec184ee2bc54308266e0d2f2aa3ea6",
          "body": "Key changes from v0.1:\n- Rename tool to cc-session-migrate (alias csm)\n- Switch from S3-based registry to Consul-style cluster (server/agent)\n- Remove session viewing/search (avoid coupling with Claude Code data format)\n- Simplify security (no mTLS, no AES encryption)\n- Replace observability stack with structured logging via slog/journald\n- Use systemd for agent lifecycle management\n- Add complete CLI -h output design for all commands\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(prd): rewrite PRD with focused scope and Consul-style cluster model",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "40621ab482c69dda19c8c3f8408f166a63e2463d",
          "body": "Define product requirements for a CLI tool that enables cross-node\nsession visibility, bidirectional session migration, and S3 backup/restore\nfor Claude Code sessions across multiple development machines.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(prd): add PRD for ccsm (Claude Code Session Manager)",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "022c3be0a64c196a5f583885476ecc758b02d6df",
          "body": null,
          "is_bot": false,
          "headline": "add doc",
          "author_name": "Tony Bai",
          "author_login": "bigwhite",
          "committed_at": "2026-07-19T13:05:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 1,
      "commits_last_year": 83,
      "latest_release_at": "2026-07-20T09:26:31Z",
      "latest_release_tag": "v0.1.1",
      "releases_from_tags": false,
      "days_since_last_push": 15,
      "active_weeks_last_year": 1,
      "days_since_latest_release": 15,
      "mean_days_between_releases": null
    },
    "artifacts": {
      "collected": true,
      "structure": [
        "tree.go_main"
      ],
      "declarations": []
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "readme_badges": {
        "hosts": [
          "shields.io"
        ],
        "total": 1,
        "header": 0,
        "collected": true,
        "has_inspect_badge": false
      },
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 28,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/bigwhite/cc-session-migrate",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "categories": [],
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/bigwhite/cc-session-migrate",
          "declared_type": null,
          "is_deprecated": false,
          "latest_version": "v0.1.1",
          "repository_url": "https://github.com/bigwhite/cc-session-migrate",
          "versions_count": 2,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-20T09:13:03Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 16
        }
      ]
    },
    "popularity": {
      "forks": 1,
      "stars": 5,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-07-24",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 1,
        "total_forks": 1
      },
      "star_history": null,
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 16162,
      "source_files_sampled": 47,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 303
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go"
      ],
      "dependencies": [
        {
          "name": "github.com/aws/aws-sdk-go-v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.42.1"
        },
        {
          "name": "github.com/aws/aws-sdk-go-v2/credentials",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.19.29"
        },
        {
          "name": "github.com/aws/aws-sdk-go-v2/service/s3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.105.2"
        },
        {
          "name": "github.com/robfig/cron/v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        },
        {
          "name": "github.com/schollz/progressbar/v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.19.1"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.2"
        },
        {
          "name": "github.com/spf13/viper",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.21.0"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 1,
        "closed_ratio": 0,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "bigwhite",
          "commits": 83,
          "avatar_url": "https://avatars.githubusercontent.com/u/419088?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 9,
            "reason": "1 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "4a11405e3aa29153165472432cbeb7006ef23511",
        "ran_at": "2026-08-05T09:20:15Z",
        "aggregate_score": 2.2,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "recent_prs": {
        "merged_7d": 0,
        "decided_7d": 0,
        "merged_30d": 0,
        "authors_30d": 0,
        "decided_30d": 0,
        "sample_size": 0,
        "window_days": 30,
        "sample_exhausted": false,
        "authors_probed_30d": 0,
        "newcomer_merged_30d": 0,
        "bot_prs_excluded_30d": 0,
        "newcomer_authors_30d": 0,
        "newcomer_decided_30d": 0
      },
      "ci_last_run_at": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 1,
          "created_at": "2026-07-22T08:12:03Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/bigwhite/cc-session-migrate",
    "host": "github.com",
    "name": "cc-session-migrate",
    "owner": "bigwhite"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "weak",
      "name": "Overall health",
      "note": "The weighted overall 43 is calibrated to 39 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 43,
            "calibrated": 39,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 39,
      "inputs": {
        "security": 22,
        "vitality": 62,
        "community": 17,
        "governance": 41,
        "calibration": "2026-08-02",
        "engineering": 54,
        "ai_readiness": 85,
        "weighted_overall_raw": 43
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "moderate",
        "name": "Vitality",
        "value": 62,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "weak",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 47,
            "inputs": {
              "commits_last_year": 83,
              "human_commit_share": 1,
              "days_since_last_push": 15,
              "active_weeks_last_year": 1
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 15 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 15
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "1/52 weeks with commits",
                "points": 0.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "83 commits in the last year",
                "points": 17.3,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 83
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 84,
            "inputs": {
              "releases_count": 1,
              "latest_release_tag": "v0.1.1",
              "releases_from_tags": false,
              "days_since_latest_release": 15,
              "mean_days_between_releases": null
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "1 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 15 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 15
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "cadence unknown (single release)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence_unknown",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "exceptional",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 17,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "forks": 1,
              "stars": 5,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "5 stars",
                "points": 9.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "1 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "at_risk",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "readme_badges": 1,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [
                "shields.io"
              ],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "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": "weak",
        "name": "Sustainability & Governance",
        "value": 41,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): PR acceptance, Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "pr_acceptance",
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 1,
              "closed_issues": 0,
              "prs_merged_7d": 0,
              "prs_decided_7d": 0,
              "prs_merged_30d": 0,
              "prs_decided_30d": 0,
              "issue_closed_ratio": 0,
              "closed_unmerged_prs": 0,
              "first_time_authors_30d": 0,
              "first_time_prs_merged_30d": 0,
              "first_time_prs_decided_30d": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "0% of issues closed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 0
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "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": 73,
            "inputs": {
              "followers": 1898,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "bigwhite",
              "public_repos": 74,
              "account_age_days": 5789
            },
            "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": "1,898 followers of bigwhite",
                "points": 23.6,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 1898,
                      "login": "bigwhite"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "74 public repos, account ~15 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 74
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 15
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 92,
            "inputs": {
              "packages": [
                "github.com/bigwhite/cc-session-migrate"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 16
            },
            "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 16 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 16
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "2 published versions",
                "points": 12,
                "status": "partial",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 54,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "has_ci": false,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "topics": [
                "claude-code",
                "cli-tool",
                "dev-tools",
                "distributed-systems",
                "golang",
                "hub-and-spoke",
                "s3-backup",
                "session-migration",
                "websocket"
              ],
              "has_wiki": false,
              "homepage": "http://tonybai.com",
              "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": "http://tonybai.com",
                "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": "9 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 9
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 22,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 22,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 2.2
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "1 existing vulnerabilities detected",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "exceptional",
            "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"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "excellent",
        "name": "AI Readiness",
        "value": 85,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.988,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 303
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "82 of 83 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 82,
                      "sampled": 83
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 79,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.976,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "81 of the last 83 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 81,
                      "sampled": 83
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "exceptional",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 16162,
              "source_files_sampled": 47,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/47 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 47,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "top": [
        "application"
      ],
      "labels": [
        "cli"
      ],
      "scores": {
        "cli": 6,
        "library": 3,
        "application": 5
      },
      "primary": "cli",
      "evidence": [
        {
          "tier": "structure",
          "label": "application",
          "source": "tree.go_main",
          "weight": 5
        },
        {
          "tier": "dependencies",
          "label": "cli",
          "source": "dep:github.com/spf13/cobra",
          "weight": 4
        },
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:go",
          "weight": 3
        },
        {
          "tier": "tags",
          "label": "cli",
          "source": "tag:cli-tool",
          "weight": 2
        }
      ],
      "artifacts": [],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": true,
      "consumed_by_code": false
    },
    "metrics_version": "2.5.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-08-05T09:20:19.576205Z",
  "schema_version": "0.31.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/bigwhite/cc-session-migrate.svg",
  "full_name": "bigwhite/cc-session-migrate",
  "license_state": "absent",
  "license_spdx": null
}

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

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

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