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

jbygdell / subsurface

This is the official upstream of the Subsurface divelog program

C++ · CGPL-2.0★ 0 星标⑂ 0 复刻始于 2017年1月复刻在 GitHub 上查看 ↗

jbygdell/subsurface 的健康指数为 100 分中的 28 分,处于「危急」区间。 其得分最高的类别是AI Readiness(60/100),最低的是Community & Adoption(12/100)。 最近一次更新在 1057 天前。 近期的大部分工作由 2 位贡献者完成。

28
总分 / 100
危急

软件健康指数

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

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

评分画像

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

Abandonment Policy applies a 85% multiplier to weighted overall health.

所有权

Joakim Bygdell个人账户
4 关注者34 个公开仓库始于 2017年1月@NBISweden

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

按类别列示的指标

活力

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

17危急 · 占总体的 22%
评分方式
0/36推送新近度 — 最近一次推送于 1,057 天前
0/36提交节奏 — 52 周中有 0 周有提交
0/18提交量 — 最近一年 0 次提交
0/10OpenSSF Scorecard:Maintained — 0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
所用输入
commits_last_year0
human_commit_share1
days_since_last_push1,057
active_weeks_last_year0

发布纪律

40存在风险
评分方式
16.2/27有发布版本 — 39 个版本标签(无 GitHub 发布版本)
0/36发布时效 — 最近一次发布版本于 3,492 天前
19.8/27发布节奏 — 约每 50.7 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count39
latest_release_tagv4.5.97
releases_from_tags
days_since_latest_release3,492
mean_days_between_releases50.7
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

12危急 · 占总体的 18%
评分方式
0/60星标 — 0 个星标
0/25复刻 — 0 个复刻
0/15关注者 — 0 位关注者
所用输入
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

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

可持续性与治理

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

39存在风险 · 占总体的 24%
评分方式
25.2/54巴士系数 — 2 位贡献者贡献了半数提交
13.7/22.5提交分布 — 头号贡献者编写了 39% 的提交
13.5/13.5贡献者广度 — 99 位贡献者
10/10OpenSSF Scorecard:Contributors — project has 20 contributing companies or organizations
所用输入
bus_factor2
contributors_sampled99
top_contributor_share0.392
评分方式
0/46.8议题解决 — 没有议题或无数据
0/38.3PR 接受 — 没有已裁定的拉取请求或无数据
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
已排除计分(无数据或不适用):议题解决, PR 接受。 其余权重已重新归一化。
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
5/25所有者影响力 — jbygdell 有 4 位关注者
23.2/25既往记录 — 34 个公开仓库,账户约 9 年
所用输入
followers4
owner_typeUser
is_verified
owner_loginjbygdell
public_repos34
account_age_days3,489
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。

工程质量

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

56中等 · 占总体的 20%

工程实践

60中等
评分方式
24/24CI 工作流 — 12 个工作流
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。 其余权重已重新归一化。

文档

50中等
评分方式
0/30README
25/25文档目录
15/15文档 / 主页站点 — https://subsurface-divelog.org
0/10仓库描述
0/10主题标签
10/10Wiki
所用输入
topics
has_wiki
homepagehttps://subsurface-divelog.org
has_readme
has_docs_dir
has_description

安全

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

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

安全态势

39存在风险
评分方式
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
2.5/2.5Contributors — project has 20 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
0/7.5Maintained — 0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
0/5Packaging — 无数据
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
5/5SAST — SAST tool detected: CodeQL
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated15
scorecard_versionv5.5.0
checks_inconclusive3
scorecard_aggregate3.9
已排除计分(无数据或不适用):ci_tests, packaging, signed_releases。 其余权重已重新归一化。

AI 就绪度

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

60中等 · 占总体的 0%
评分方式
0/45代理指令 — 没有 CLAUDE.md / AGENTS.md / 编辑器规则
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 97 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.97
agent_instruction_files
agent_instruction_max_bytes
评分方式
18/18一条命令的引导启动 — Documentation/Makefile, ReleaseNotes/Makefile, makefile
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — C++(静态类型)
10/10可复现环境 — Dockerfile
0/10已体现的代理实践 — 最近 100 次提交中没有代理编写的提交
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_filesDocumentation/Makefile, ReleaseNotes/Makefile, makefile
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0
toolchain_manifestsandroid-mobile/build.gradle
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — C++(静态类型)
51.3/55可控的文件大小 — 采样的 626 个源文件中有 42 个超过 60KB
所用输入
primary_languageC++
largest_source_bytes651,486
source_files_sampled626
oversized_source_files42

关键数据

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

数据采集警告

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

更多细节

OpenSSF Scorecard 3.9 / 10
3.9综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。Scorecard v5.5.0 · 2026-07-27 02:29 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
10Contributorsproject has 20 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintained0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
不适用Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
10SASTSAST tool detected: CodeQL
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": true,
      "size_kb": 142264,
      "has_wiki": true,
      "homepage": "https://subsurface-divelog.org",
      "languages": {
        "C": 1176494,
        "R": 4070,
        "C++": 2765392,
        "CSS": 12885,
        "QML": 272296,
        "TeX": 19220,
        "HTML": 36569,
        "Java": 19782,
        "Perl": 19749,
        "XSLT": 292686,
        "CMake": 76770,
        "QMake": 12770,
        "Shell": 152413,
        "Makefile": 6648,
        "Dockerfile": 8499,
        "JavaScript": 41191,
        "Objective-C++": 5497
      },
      "pushed_at": "2023-09-03T17:35:37Z",
      "created_at": "2017-01-05T17:54:43Z",
      "owner_type": "User",
      "updated_at": "2023-09-03T17:35:46Z",
      "description": "This is the official upstream of the Subsurface divelog program",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "GPL-2.0",
      "default_branch": "master",
      "license_spdx_raw": "GPL-2.0",
      "primary_language": "C++",
      "significant_languages": [
        "C++",
        "C"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Joakim Bygdell",
      "type": "User",
      "login": "jbygdell",
      "company": "@NBISweden ",
      "location": null,
      "followers": 4,
      "avatar_url": "https://avatars.githubusercontent.com/u/24942439?v=4",
      "created_at": "2017-01-05T17:50:31Z",
      "is_verified": null,
      "public_repos": 34,
      "account_age_days": 3489
    },
    "license": {
      "state": "standard",
      "spdx_id": "GPL-2.0",
      "raw_spdx": "GPL-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v4.5.97",
          "kind": "patch",
          "published_at": "2017-01-02T23:55:00Z"
        },
        {
          "tag": "v4.5.96",
          "kind": "patch",
          "published_at": "2016-12-12T03:43:55Z"
        },
        {
          "tag": "v4.5.6",
          "kind": "patch",
          "published_at": "2016-04-26T16:38:53Z"
        },
        {
          "tag": "v4.5.5",
          "kind": "patch",
          "published_at": "2016-04-09T15:33:37Z"
        },
        {
          "tag": "v4.5.4",
          "kind": "patch",
          "published_at": "2016-03-16T14:34:57Z"
        },
        {
          "tag": "v4.5.3",
          "kind": "patch",
          "published_at": "2015-12-13T19:40:16Z"
        },
        {
          "tag": "v4.5.2",
          "kind": "patch",
          "published_at": "2015-10-27T06:27:16Z"
        },
        {
          "tag": "v4.5.1",
          "kind": "patch",
          "published_at": "2015-10-27T06:27:16Z"
        },
        {
          "tag": "v4.5.0",
          "kind": "minor",
          "published_at": "2015-10-14T12:59:09Z"
        },
        {
          "tag": "v4.4.98",
          "kind": "patch",
          "published_at": "2015-10-04T15:42:27Z"
        },
        {
          "tag": "v4.4.97",
          "kind": "patch",
          "published_at": "2015-09-19T22:33:40Z"
        },
        {
          "tag": "v4.4.96",
          "kind": "patch",
          "published_at": "2015-09-03T14:40:14Z"
        },
        {
          "tag": "v4.4.2",
          "kind": "patch",
          "published_at": "2015-05-04T17:59:10Z"
        },
        {
          "tag": "v4.4.1",
          "kind": "patch",
          "published_at": "2015-02-18T19:11:03Z"
        },
        {
          "tag": "v4.4.0",
          "kind": "minor",
          "published_at": "2015-02-04T16:00:33Z"
        },
        {
          "tag": "v4.3.970",
          "kind": "patch",
          "published_at": "2015-02-01T15:24:48Z"
        },
        {
          "tag": "v4.3.960",
          "kind": "patch",
          "published_at": "2015-01-25T21:40:18Z"
        },
        {
          "tag": "v4.3.950",
          "kind": "patch",
          "published_at": "2015-01-24T02:52:26Z"
        },
        {
          "tag": "v4.2.91",
          "kind": "patch",
          "published_at": "2014-12-09T02:49:01Z"
        },
        {
          "tag": "v4.2.90",
          "kind": "patch",
          "published_at": "2014-11-17T22:27:05Z"
        },
        {
          "tag": "v4.2.1",
          "kind": "patch",
          "published_at": "2014-11-13T18:25:56Z"
        },
        {
          "tag": "v4.1.94",
          "kind": "patch",
          "published_at": "2014-08-05T22:50:14Z"
        },
        {
          "tag": "v4.1.93",
          "kind": "patch",
          "published_at": "2014-07-25T19:51:23Z"
        },
        {
          "tag": "v4.1.92",
          "kind": "patch",
          "published_at": "2014-07-24T20:53:21Z"
        },
        {
          "tag": "v4.1.91",
          "kind": "patch",
          "published_at": "2014-07-19T01:46:51Z"
        },
        {
          "tag": "v4.1.90",
          "kind": "patch",
          "published_at": "2014-07-13T04:09:32Z"
        },
        {
          "tag": "v4.0.99",
          "kind": "patch",
          "published_at": "2014-05-06T18:32:48Z"
        },
        {
          "tag": "v4.0.98",
          "kind": "patch",
          "published_at": "2014-05-02T04:30:29Z"
        },
        {
          "tag": "v4.0.97",
          "kind": "patch",
          "published_at": "2014-05-01T22:23:33Z"
        },
        {
          "tag": "v4.0.96",
          "kind": "patch",
          "published_at": "2014-04-25T14:20:33Z"
        },
        {
          "tag": "v4.0.3",
          "kind": "patch",
          "published_at": "2014-02-16T03:38:11Z"
        },
        {
          "tag": "v4.0.2",
          "kind": "patch",
          "published_at": "2014-01-09T08:09:43Z"
        },
        {
          "tag": "v4.0.1",
          "kind": "patch",
          "published_at": "2014-01-03T11:18:59Z"
        },
        {
          "tag": "v3.9.2",
          "kind": "patch",
          "published_at": "2013-12-07T06:57:39Z"
        },
        {
          "tag": "v3.9.1",
          "kind": "patch",
          "published_at": "2013-11-28T05:27:01Z"
        },
        {
          "tag": "v3.1.1",
          "kind": "patch",
          "published_at": "2013-06-30T16:47:46Z"
        },
        {
          "tag": "v3.0.2",
          "kind": "patch",
          "published_at": "2013-03-04T08:26:32Z"
        },
        {
          "tag": "v3.0.1",
          "kind": "patch",
          "published_at": "2013-02-26T21:29:23Z"
        },
        {
          "tag": "v2.0.1",
          "kind": "patch",
          "published_at": "2012-10-07T12:02:48Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "83e7f537fbacfc2dfeea1373a7bda7da6df26185",
          "body": "To be used on Subsurface merch, this introduces versions\nof the Subsurface icon with the program's name and web\naddress.\n\nSigned-off-by: Robert C. Helling <helling@atdotde.de>",
          "is_bot": false,
          "headline": "Text versions of Subsurface icon",
          "author_name": "Robert C. Helling",
          "author_login": "atdotde",
          "committed_at": "2023-08-16T10:11:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fae68b7a684bdc320159360308e7d420d7f9dc92",
          "body": "The existing logic correctly calculates the minimum (ie, ending) pressure, but not the maximum\n(ie starting) pressure.\n\nFor example, 2 tanks A and B with manual pressures (same tank on subsequent dives, which were\nthen merged):\nA: 205 - 84\nB: 83 - 55\n\nWhen merging the starting pressures, the call is\n[…]\n0, false)\n\nThe final comparison is:\n  if(false && 205 < 83) return 205;\n  else return 83;\n\n-> So 83 is returned even though 205 should have been.\n\nSigned-off-by: Michael Werle <micha@michaelwerle.com>",
          "is_bot": false,
          "headline": "fix: merge_pressure does not calculate starting pressures correctly",
          "author_name": "Michael Werle",
          "author_login": "mwerle",
          "committed_at": "2023-08-09T12:35:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "26f20b805d3c95445f0cbc2c68a6d59dd6c7d915",
          "body": "When events are hidden in the profile, only hide events with the same\nname and the same severity (flags).\nFrom discussion in https://github.com/subsurface/libdc/pull/54.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Consider Severity when Hiding Events.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-08-03T13:11:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b324849d0c26b588d87da73fb86fbacec89d613a",
          "body": "Update `libdivecomputer` submodule to the latest version.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Housekeeping: Update libdivecomputer Submodule.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-08-02T12:08:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8f0380fd05d95923c53190665ab2e73f7d268387",
          "body": "Fix how gases are marked as 'used' and kept from being deleted in the\nequipment tab for CCR dives.\nIt does not make sense to treat the (arbitrary) first gas in the list\nwith a usage type of 'diluent' or 'oxygen' as 'used' and prevent the\nuser from deleting it. Dive computers report the initial dilue\n[…]\n pressure change is not\napplied to the profile - the pressure is currently shown as constant on\nthe start pressure. But this is for another pull request.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Equipment: Fix 'used' Gas Selection for CCR Dives.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-25T00:05:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5fae7ce7a0926d6c0d80c47287c229676dcd7952",
          "body": "Include unused tanks in merges of multiple logs into a single dive if\nthe 'Show unused cylinders' preference is enabled.\nAlso rename the preference (in code) to `include_unused_tanks` to\nreflect the fact that it is already used in more places than just the\ndisplay (exporting, cloning dives).\nSimplif\n[…]\ng the persisted name of the preference as `display_unused_tanks`\nto avoid resetting this for all users - is there a good way to migrate\npreference names?\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Equipment: Include Unused Tanks in Merge if Preference is Enabled.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-24T23:19:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cb6f768865f90c15efbec0dcb36011a76bf798cf",
          "body": "Mark gases that are reported as 'inactive' by the dive computer as 'not\nused' in the Equipment tab.\n\nRequires https://github.com/subsurface/libdc/pull/52.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Equipment: Mark Gas Mixes Reported as 'inactive' as 'not used.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-23T16:55:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5e293689fddb13cf3b780a7b6c047b6870dcf271",
          "body": "Disable the build, as this has not been working for some time, and is\ncreating a distraction.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "CI: Disable Broken Ubuntu bionic Build.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-23T03:48:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8f8f901aa8d4044b6fad9195ece5f96021fa57c8",
          "body": "Signed-off-by: Rafael M. Salvioni <rafael.salvioni@gmail.com>",
          "is_bot": false,
          "headline": "Check \"hasDCSalinity\" is null in updateWaterTypeWidget()",
          "author_name": "Rafael M. Salvioni",
          "author_login": "rafsalvioni",
          "committed_at": "2023-07-14T07:47:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5511cd13d75f660104de7cc5ac29f676f8ed789e",
          "body": "Signed-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Add forcedFirmwareUpgradeSupported to supportedDivecomputers.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-11T14:30:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4ac27e3c718baf2e4208afaefa2ead7864569183",
          "body": "…amically.\n\nLoad the dive computer list in the 'Change Settings on Dive Computer'\ndialog dynamically.\nAlso incorporate suggestions from\nhttps://github.com/subsurface/subsurface/pull/3925#issuecomment-1595784076.\n\nSuggested-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Load the Dive Computer List in 'Configure Dive Computer' Dyn…",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-07-11T14:30:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "695c37499aefa5b4d7d51629ccb9d6c03c6afa1e",
          "body": "The conversion between mbar and depth sometimes uses DC's salinity, sometimes user's salinity. By other hand, it uses surface pressure given by user in calculation.\nThis fix try to standartize this values, using them from same source.\n\nSigned-off-by: Rafael M. Salvioni <rafael.salvioni@gmail.com>",
          "is_bot": false,
          "headline": "Core: Fix bug salinity and pressure values in mbar <-> depth conversion",
          "author_name": "Rafael M. Salvioni",
          "author_login": "rafsalvioni",
          "committed_at": "2023-07-11T01:26:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e082affddadf62621d233224860c2d8b484c0ae",
          "body": "Today salinity combo is editable if one of these rules matches: The dive was manually entered or if salinity edition is allowed in preferences.\nHowever we can have cases that dives were downloaded but its doesn't have salinity info.\n\nThis fix considers if there's a DC salinity info to decides combo edition and if salinity change indicator will be showed or not.\nIf DC doesn't have salinity, the UI behavior is the same of a manual dive\n\nSigned-off-by: Rafael M. Salvioni <rafael.salvioni@gmail.com>",
          "is_bot": false,
          "headline": "Fix salinity combo/icon when DC doesnt have salinity info",
          "author_name": "Rafael M. Salvioni",
          "author_login": "rafsalvioni",
          "committed_at": "2023-07-09T08:36:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90e5de83573254cd251fef243aef991d51f60d4b",
          "body": "Add an explicit checkbox to the 'cloud auto synch' status toggle in the\nmobile 'Dive Management' menu in order to make it more intuitive to\nunderstand.\nThis isn't super pretty, but I think it will improve the usability. A\nprettier way to achieve this will be to redesign the `ic_cloud_off.svg`\n/ `ic_\n[…]\nple of a support request caused by confusion from the current\nimplementation: https://groups.google.com/g/subsurface-divelog/c/9X-hTt9NFlE/m/ZcqtdOOhBQAJ\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Mobile: Make Cloud Auto Synch Status Easier to Understand.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-26T14:54:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e260780c9ded3d5455e5465fde4129cf14346c88",
          "body": "Fix the cylinder pressures in the CSV summary export. Only show\npressures derived from `pressure` attributes in samples for the first\ncylinder. Add support for showing pressures derived from `pressure0` ...\n`pressureX` attributes.\nAlso cleaned up unit conversions, and changed tabs to spaces.\nFrom discussion in\nhttps://github.com/subsurface/subsurface/pull/3906#issuecomment-1575980882.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Export: Fix Cylinder Pressures in CSV Export.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-25T23:24:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d708c0d92ca0a1161f7f98edd369a60ca6a2b14",
          "body": "It looks like Qt company has LGPLed versions tagged wich simplifies\nthings a bit while building, e.g. 5.15.3 current workaround matches\n\"v5.15.3-lts-lgpl\" tag.\n\nBackground: Debian Sid is currently at Qt 5.15.8 which is impossible to\nbuild from scratch with current script as only a few git versions are\ntagged in the script format \"v5.15.8\".\n\nSigned-off-by: Salvador Cuñat <salvador.cunat@gmail.com>",
          "is_bot": false,
          "headline": "Build script: Qt has tagged versions currently",
          "author_name": "Salvador Cuñat",
          "author_login": "salvadorcunat",
          "committed_at": "2023-06-25T16:47:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ce67c8b90272cfd104bbc081b044121d6683a7fc",
          "body": "Add a button that allows the user to hide the infobox with statistics\nabout the point in the dive under the mouse cursor in order to be able\nto see the full dive profile unobstructed.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Add a Button to Hide the Infobox in the Dive Profile.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-25T12:40:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5007bde674bd9b1100b24278250aab1790114d9",
          "body": "Regroup the file menu entries to give the dynamically generated\n'recently opened files' their own section.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Regroup File Menu Entries.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-17T18:19:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bceb367dc3af428648cc0f7009c0de5f8ed0fe4b",
          "body": "Rename inconsistently named private members introduced in #3923.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Cleanup: Use Correct Naming for Private Members.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-17T15:18:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b0d5b23227bfb8437fbce4fce882d55f675fc3db",
          "body": "Add meaningful error messages when creating a libdivecomputer dump. In\nparticular show if creating a dump is not supported on the dive computer\nthat is used.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Add Meaningful Error Messages for libdivecomputer Dump.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-17T10:06:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a0cb6ad6d7c6df6907262a91238e047f65cb471a",
          "body": "Remove unused class member variables in\n`profile-widget/diveprofileitem`.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Remove Unused Class Members.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-16T13:49:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "700bba7e30313be85d64e1c52228ae65fba78383",
          "body": "…tion.\n\nUse the dive computer / device information that was persisted when\npreviously downloading dives or configuring the dive computer in the\ndive computer configuration dialog.\nAlso rename 'Connect with bluetooth' and 'Cancel' buttons in the dialog\nto make them more consistent with what they do.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Use Persisted Device Information for Dive Computer Configura…",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-12T19:40:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35d88fa6ceaccaf2662c6c7565185a25d6b58d90",
          "body": "Fix a build warning for an unused variable.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Build: Fix build warning on MacOS.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-12T15:04:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3939cc8da28e7ab39e0bed22c9ce2298f1a72cbd",
          "body": "Just because now we can...\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use range based for and std::string in enumerate_devices()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-06-03T10:54:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81cd91f78ba9f87f77adf4db283341ac3b27a548",
          "body": "No free()in necessary means less convoluted control flow.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: more std::[w]string conversions in windows.cpp",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-06-03T10:54:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a3f540fe3476ce5e36a854c73dd520b57d229ffd",
          "body": "The compiler was (correctly) complaining about a const char *\nto char * conversion.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: fix warnings in windows.cpp",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-06-03T10:54:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "540cba07f3d52be82c56271091cb6d6c4ce66f86",
          "body": "The memory management and string concatenation was hard to follow.\n\nSince the mobile files ios.cpp and android.cpp were already\nconverted to C++, let's do the same for Unix, Windows and MacOS.\n\nSimply store the default directory and filename in a function-level\nstatic string. Thus, it will be initia\n[…]\n and\nfreed on application exit. Since the std::string data is\nguaranteed to be contiguous and zero-terminated, it can be used\nfrom C code.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use C++ std::strings for default directory and filename",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-06-03T10:54:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7771b444a1014eb529c7bcdd975bd1d69c1409cf",
          "body": "Fix a bug preventing the `mxe` symlink from being created.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Build system: Fix Windows Build Script.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-06-01T14:04:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4c193d7bdfbcb1ca755250df1873131d9709a9df",
          "body": "Rework of the XSLT used to generate the Summary CSV export:\n- fixed a bug causing invalid CSV to be generated for double quotes\n  (`\"\"`);\n- changed quoting and escaping to be compliant with RFC 4180;\n- changed output to contain information for all cylinders for all dives\n  (instead of limiting the n\n[…]\nast dive);\n- added an index to the cylinder data headings;\n- changed unit designators to use `[]` instead of `()`;\n- some minor improvements to the XSLT.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Rework the Summary CSV Export XSLT.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-31T17:11:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a127c4ac63869b753f2912cc3903b0ef68f96ba8",
          "body": "Change the range to be 10 to 150.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Mobile: Make Gradient Factor Range Consistent with Desktop.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-30T14:21:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "50438b045611f06197f49234c89a026629ad603e",
          "body": "Fix the issue that Gradient Factors cannot be set to 100 in the mobile\nversion. This is done by changing the edits from a text box to a spin\nedit, which seems to be a better match for numerical values.\nAs a side effect this also solves the issue that the keyboard for the\ntext edit is not properly displayed when settings are opened when dive\ndetails are already on the page stack.\n\nFixes #3911.\n\nReported-by: @gbetous\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Mobile: Fix Editing of Gradient Factors",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-30T14:21:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d7f294407c29f39e017d0ac6a05d769caef56b2",
          "body": "Rework the setting of custom date / time format preferences:\n- fix bug causing case changes if custom format case insensitively\n  matches a drop down entry;\n- fix invalid format examples in tooltip;\n- update URL for the format documentation;\n- add support for quoted literals to the format validity warning.\nFrom discussion in\nhttps://github.com/subsurface/subsurface/issues/3849#issuecomment-1481239270.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Rework Setting of Custom Date / Time Formats.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-30T09:24:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6002387d7b4908a93123e21aa03c2cfe533157e8",
          "body": "Add support for tracking the gas usage across multiple tanks to the 'bar\nused' and SAC values shown for the profile ruler.\nThe following rules are implemented:\n- a tank is considered 'used' if at least one bar has been consumed;\n- only used tanks are taken into account for calculations;\n- 'bar used'\n[…]\nn if all tanks used have the same (or unknown)\n  volume;\n- SAC is only shown if all tanks used have a known volume.\n\nFixes #3902.\n\nReported-by: @pabdakine\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Add Multi-Tank Support for Profile Ruler.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-30T09:21:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "62c2e9f07c2d613412407b49a4cdc8e9f07a3489",
          "body": "Update libdivecomputer to include the changes from the libdivecomputer\nv0.8.0 release:\n- Divesoft Freedom and Liberty support\n- A couple of iostream abstraction layers: a new 'packet layer' and a\n  HDLC layer, moving code from low-level dive computer downloaders to\n  generic iostream layers.\n- misc minor updates\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Libraries: Update libdivecomputer.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-28T21:13:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ee5b108103cf586cbb191cb4936f1b05ea80ef8",
          "body": "Remove `renderSVGIcon()` and `renderSVGIconWidth()`, as QPixmaps can be\nloaded directly from SVG, and support scaling.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Remove 'renderSVGIcon' methods.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-28T21:11:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2ef6cd89ccd63d76467cdcdd55a15d6805ea2425",
          "body": "Use SVG files as source for icons where they exist, and remove the\nrespective PNG artefacts generated from the SVG files from the\nrepository.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Use SVG directly for icons.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-28T21:11:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e9574679787ce33046b694e75b4a77e0f5923e9",
          "body": "Signed-off-by: Michael Andreen <michael@andreen.dev>",
          "is_bot": false,
          "headline": "profile: Fix so min pressure is not always 0",
          "author_name": "Michael Andreen",
          "author_login": "michaelandreen",
          "committed_at": "2023-05-23T11:12:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72175060729b87eb53bdc3faccc71a7d7a15c6a4",
          "body": "It's possible for the first sensor to start with a pressure\nsignificantly lower than other sensors.\n\nSigned-off-by: Michael Andreen <michael@andreen.dev>",
          "is_bot": false,
          "headline": "profile: Use all sensors to scale the pressure graph",
          "author_name": "Michael Andreen",
          "author_login": "michaelandreen",
          "committed_at": "2023-05-23T11:12:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a7889d1f4e6d3ffa7ab8aa95c0af39e1024570ef",
          "body": "Not really relevant, because it only affects debugging output.\n\nBut shows why I dislike weakly typed, non-compiled languages.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: fix typo: verboseEnabebled -> verboseEnabled",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-05-20T18:07:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e059be4ca71e13944b429688a14b23df7684a25",
          "body": "Improve the build instructions for Android. Provide a complete script\nfor building in a re-usable container.\nAlso changed the Android packaging README to markdown.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Android: Improve build instructions",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-20T14:49:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2aa13ea9d7d1a8b960d9d5a7b094b4896201b601",
          "body": "When editing a dive site in the 'Dive sites' view, add a context menu\nentry to allow mergeing of the displayed dive site into the dive site\nseleted in the 'Near dive sites' list.\nThis merge has the opposite direction of the existing 'Merge into\ncurrent site' function, which can simplify the workflow\n[…]\ntaining\na large number of dive sites, as the facilities to sort dive sites in\nthe 'Dive sites' view does not have a way to sort by location or\nproximity.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Add mergeing into the selected dive site.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-20T05:24:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "84d9d0abe7bde979aed6222ba364deecba533d53",
          "body": "Use 'xmlFree()' to free memory returned by libxml.\nFollow-up to #3900.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix incorrect use of 'free()'.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-19T08:51:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d7bfb9d61e7b3ac3eaee9079776221fca570610c",
          "body": "Fix a memory leak occurring during XSLT transformations.\n\nFixes #3899.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix memory leak during XSLT transformation.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-18T14:44:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "361baeda019537db8959b945def173b28aadf4e9",
          "body": "We now parse CSV and not TSV files.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Fixed CSV parsing tests.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-18T07:31:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1bd7806dcff2f1f1669bb5bfabbf662b7cedb7af",
          "body": "Change the output formato for the Export / 'CSV summary dive details'\nfrom TSV to CSV, to make it consistent with the menu item name, and with\nthe other 'CSV' export function.\nThis was changed to TSV by @mturkia in\nhttps://github.com/subsurface/subsurface/commit/6c825785401ea3e450795db8887eba9444c9b\n[…]\ny large log file, and importing into Google Sheets is\nworking fine for the output produced.\nAlso made capitalisation of the Export menu items consistent.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Change 'CSV summary dive details' output from TSV to CSV.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-05-18T07:31:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cf95c3bd82c46339e9cf68058c62c934aabff2ec",
          "body": "I don't understand why the functions must be called on a copy\nof the string.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: remove unnecessary string duplication",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-05-02T07:35:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15bf145f14ac00c1e6bc989a15092408b3c17753",
          "body": "This seems to be needed to make the build work with Qt6, which is needed for M1 based Macs.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix build for Qt6",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-04-26T05:14:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e60baff94006c5e32b98ce34e4de6dce3cecf998",
          "body": "Fix a bug introduced in 8cd451fc338da275f66b15181894e37621698109 causing\nan error to be thrown every time trying to do 'Save to cloud storage'.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix bug when synching to the cloud",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-04-21T13:18:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a8d2b2ff70826d5f24e908378391491840b13adf",
          "body": "This has to be applied to the object, not the pointer to the object.\nFixes a double-free crash introduced in 8cd451f.\n\nAlternatively, we could use std::swap() for C++98 charm and perhaps\nbetter readability for people unfamiliar with C++11. Nowadays,\nstd::move() is more idiomatic though. Shrug.\n\nReported-by: Michael Keller <github@ike.ch>\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "divelog: fix erroneous use of std::move()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-18T11:15:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a38ea971a00dda082e9e499a8aa67312d17908b4",
          "body": "Add an option for users to sync the dive computer time with the PC time\nevery time dives are downloaded.\nObviously this will only work on dive computers that have time\nsynchronisation support in libdivecomputer, for other computers a notice\nis logged.\nThe selection for this option is persisted as a preference.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Import: Add option to sync time on dive computer download",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-04-17T14:56:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb410fe1ba101c58f1634fda28e410d8bbbfe201",
          "body": "Just use the constructor of the parent class.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: don't define empty inline constructor",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e70e3082c9ba15fd81d394c9813c4ce8e50dbf24",
          "body": "There was this completely weird loop that the planner-widget would\ncall the planner-model to get the current rebreather mode, which\nwould then access the dive in the planner widget. Just keep those\nthings in the planner widgets.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: remove getRebreatherMode() from planner-model",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1fb9d6236baad81b95526b5424ca205a36e31072",
          "body": "There is no point in repopulating this regularly, as the\ncontent does not change.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: initialize dive selection mode in constructor",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4c02d1c27921652a79079706d65dfe31dde701ad",
          "body": "Allocate the dive in the planner. This is all a bit convoluted\nand needs more cleanup.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: get rid of global displayed_dive variable",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5682369f89796a94e47e3a63e73195daf4e3679",
          "body": "The only user of the DivePlannerPointsModel and the\nGasSelectionModel is the planner. Let's keep these models\nthere.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: remove global model instances",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3dd09b31e318dc06de07d97919801e86e5f41ffe",
          "body": "The gas and dive-type models were repopulated in the\ndiveplanner model. The former are used in the planner.\nHowever, the latter is also used outside of the planner,\nwhen editing non-planned dives. Thus the former shouldn't\nbe repopulated by the latter, but by the code that needs\nit.\n\nSide note: repopulating the dive-type model seems to\nmake no sense whatsoever since the values never change,\nbut let's keep it for now.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: move repopulation of models to planner",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d51589b9a7b26b79932eab2d218bc5005c963d4d",
          "body": "To phase out this global variable, avoid access of displayed_dive\nin the printing code. This is used when printing a plan. Instead,\nwhen in plan-mode, pass the planned dive to the printing code\nas a single dive to be printed.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "printing: don't access displayed_dive in printing code",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "80df790efc5894df663ec313ad8b4d35e2e9cd79",
          "body": "The last user of that state was removed in 9bbd8b8169480f12.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "desktop: remove EditPlannedDive application state",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d65f2f422cfff2c1adcc43ded7efb7e78882a841",
          "body": "The mode was accessed via the global `displayed_dive`. In an effort\nto remove globals, access it via the DivePlannerPointsModel instead.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: access divemode (a.k.a. rebreathermode) from model",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c5d6e0f44f6429935eb06d0d76c048d0355f5602",
          "body": "The undo-code uses owning pointers based on std::unique_ptr to\nmanage lifetime of C-objects. Since these are generally useful,\nmove them from the undo-code to the core-code. In fact, this\neliminates one instance of code duplication.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: make owning pointers a top-level features",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b1557ccb17bfc6e61ac72e97b12690744a6624e",
          "body": "displayed_dive used to contain the currently displayed (as in\nshown on the profile) dive. However, now it is only a \"scratch\"\ndive used by the planner and initialized every time the planner\nis started. There is no point in clearing this dive when clearing\nthe dive data. In fact, the dive should probably be cleared when\nthe planner finishes.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: don't clear displayed_dive when clearing data",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cad80e5a53901986aea49fdacbac0081f3a93aae",
          "body": "The current dc global makes no sense on mobile. Therefore,\nmove the logic of the currently displayed dive computer\nto the profile widget and remove the dc_number global\nvariable.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: move current dc logic to profile widget",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "19baae449d7706a948c9944996f2a4be37e2d2c4",
          "body": "Don't access the global current_dc, but pass it to the sensor and\ntank-use delegates, when the current dive or dive computer changes.\nThe same pattern is already realized for the tank and weight models.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "tab-widgets: pass current dive computer to delegates",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32de8a13871729b86d888129bbdea50cd96cd52e",
          "body": "The dive-equipment tab has a number of \"delegates\" for editing\ntanks sizes, etc. Instead of allocating them, make them subobjects.\n\nThe main point here is that, in an upcoming commit, the sensor\ndelegate will have to be accessed to change the current dive computer.\nSo far it didn't have a name and therefore was hard to access.\nBy making it a subobject it also gets a name.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "tab-widgets: make delegates subobject",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f03fc96894bae67a2c13e6ab032957957973830",
          "body": "An attempt at limitting accesses to the globals current_dive and\ndc_number. These globals do not make sense on mobile.\n\nThe parent widget of the tab-widgets remembers the currently\ndisplayer dive and dive computer and the individual widgets\naccess these values from there.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: remove current_dive and dc_number access from tabwidgets",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8cd191c271e49b3228868c54ab74dbbf6e059bbc",
          "body": "Make it possible for the individual tab-widgets to access the\nparent widget. In principle this could have been done by\ndowncasting the pointer returned by parent(), but this makes\nit explicit.\n\nThe goal here is to store information on the selection,\ncurrent dive, etc. without repeating it in every subwidget.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "desktop: store pointer to parent in tab-widgets",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cded7ef5fe344ce163ed3fc2f8edd02e8ebf4efe",
          "body": "On selection change, pass down selection (including current\ndive and dc) to the tab widgets. Ultimately, this should\nremove access to global variables. A number of new accesses\nare marked as TODO. They shall be removed in due course.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: pass down selection to tab widgets",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "908da778632579433da33a6c0aa452550d38905e",
          "body": "The signals/slot names for dive selection changes were a mess.\nUnify on divesSelected(). Firstly, selectionChanged() is a Qt\nthing. Secondly, it is consistent with tripSelected().\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: rename selectionChanged() to divesSelected()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "de2c4d93e02f2568be30c3b02fa1e4933c3b143b",
          "body": "This was very weird: a setSelection() call was always followed\nby a selectionChanged() call, though sometimes in convoluted\nways. Notably, the formed was called by the DiveListView, the\nlattern then by the MainWindow.\n\nLet's just merge these two functions.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "map: fold selectionChanged() into setSelection()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72a15c46d9e567b44f073ba8748a99cd06abdf3e",
          "body": "To reduce access of global variables.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: move dive selection, current dive and dc through signals",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "616dbd9671229674e787d1469187b5655edfb926",
          "body": "In DiveListView user actions (select-all, key-press,\nmouse-release) were intercepted to send the selection-changed\nsignal if the selection changed.\n\nHowever, with the recent cleanups, this can be done\ndirectly from selectionChanged(), since in all cases (at\nleast the ones I tested), the part of the function that\nis responsible for manual selection changes is called\nonly once.\n\nThis avoids quite some complex code flow.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: send selection signal from selectionChanged()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "018be753c35d450eb1ac0169d10f3ac3a1895d20",
          "body": "When manually selecting a trip, the selectionChanged()\nvirtual function was manually selecting the dives of the\ntrip and thus ultimately recurse into itself.\n\nSo far this seems to work OK, but better to avoid this\nrecursion by setting the programmaticalSelectionChange\nflag.\n\nI'd like to send the selection-changed signal directly\nfrom selectionChanged() and this recursion would lead\nto double signals.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: avoid recursion in divelist selection code",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8581e213ed2d5604ade8130cacfd7168db172d26",
          "body": "The trip selection code was an awkward layering violation.\nWhereas dive selections due to dive undo-commands trickled\ndown via DiveTripModel-->MultiFilterSortModel-->DiveListView,\nfor trip editing, the DiveListView directly intercepted the\nTripEdited signal.\n\nInstead, mimic the dive-selection code. \n[…]\nhis is a bit longer\nbut more consistent and logical. The undo/redo of trip changes\nis now also a \"programmatical\" change of the selection.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: trickle down trip selection",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9ccb940a1be0eb6eb2f6ac455474946ba3f71c24",
          "body": "After sending a selection-change signal, there follows a current\ndive changed signal. Combine these two into a single signal, since\nusually the current dive is changed when the selection is changed.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "list models: include current dive in selection signal",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "832398180c26a47353bca2340bd697b34d1de0e9",
          "body": "Instead of accessing the global dc_number from the\nDivePlannerPointsModel and the CylinderModel, pass them\nin the respective initialization functions.\n\nThe dc_number global might not make sense on mobile.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "planner: remove dc_number access from models",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d057af43b4365bbe790923fc6aca43c2ceccb8e6",
          "body": "Don't access the global variable dc_number, which might\nnot make sense on mobile.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "undo: pass divecomputer number to EditProfile command",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "297befc6f825a13130e041cebd284a8815efd9e0",
          "body": "Don't access the global variable dc_number, which might\nnot make sense on mobile.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "undo: pass divecomputer number to EditSensors command",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "996f85771a4d5a933b6bcdc31f64413444a6f79f",
          "body": "These were not optimal, because they would recalculate the current\ndive and divecomputers for every invocation.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: remove select_dive() and deselect_dive() functions",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f453094a93d4e4c0bfc00bc0a61d448b7963ddd",
          "body": "delete_single_dive() is one of those remnants from before the\nundo-code. Now it is only called in two contexts:\n\n1) When clearing the whole dive log.\n2) When importing dives from the cloud on mobile.\n\nIn the first case, the selection is cleared before deleting\nthe dives.\n\nIn the second case, let's j\n[…]\ncan remove the last call to the deselect_dive()\nfunction that does some complex calculations concerning\nthe current dive and divecomputer.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: don't call deselect_dive() from delete_single_dive()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "487974ea91381c3dfeb31d6ccc0374e1ce85e85c",
          "body": "Each of these calls recalculates the current dive and divecomputer.\nInstead, collect the dives to be selected/deselected and (de)select\nthem at once.\n\nThis needs some code refactoring in the core, because we need a\nfunction that\n1) doesn't send a signal by itself.\n2) doesn't clear the trip-selection\n[…]\nrrent dive changed. So let only the function that keeps the\nselected dive return whether the current dive changed.\n\nIt's all very fragile.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: avoid select_dive() and deselect_dive calls in dive list",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6df1c62dfce9c51ea46eff3841ab227f552c3f03",
          "body": "For each selected dive that is hidden by the filter,\nunselect_dive() was called, which led to a recalculation\nof the current dive and divecomputer.\n\nInstead, collect all deselected dives and deselect them\nat the end. Thus, these calculations are performed\nonly once.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "filter: set dive selection at once",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9f455b145712636c3e2c1711fc04771aa1238d14",
          "body": "This tries to encapsulate the management of the current dive and\ndivecomputer in the selection code. The current dive is alreay\nset by setSelection(). Add a new parameter to also set the\ncurrent divecomputer. If -1 is passed, then the current\ncomputer number is remained. This will allow us to audit \n[…]\nnd thus the dive computer\nnumber will depend on the dive with the lowest amount of dive\ncomputers in the trip. This will need to be fixed.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "selection: move current dive and divecomputer to selection.cpp",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-16T18:23:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b56b7abcf5d6f47f86493f7f246697bd7a785b79",
          "body": "Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use divelog struct in downloader code",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a2845ece82c7a1ace40402218151ecde823a1def",
          "body": "This removes a constant describing the length of the array.\n\nThe enumerated_range code had to be adapted, because the\ninteraction of C-type arrays with the C++ typesystem is mad.\nWith C-type arrays, one has to pass a reference to std::declval.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: use range based for in download code",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b61732da42b8df3900a889a4e7177a633cd14c29",
          "body": "Use the flag in the divelog structure, since this will be saved\nin the dive log.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: remove autogroup global",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa34afc3f7050879906a183991b87667003da780",
          "body": "It is only used in a single source file, so no point having\nit in a (non-generic) header.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: remove ARRAY_SIZE macro from header",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "59d678b5b13baabdffad39ede689d6cb5a83d163",
          "body": "Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: use range based for instead of loop with index",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7d5c6be1888dde21f48afc28c3f9136584f9d9b3",
          "body": "Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use divelog struct in git parser state",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "40275ea56bdf2de1515969a407f8c85eb73a6772",
          "body": "Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use divelog struct in parser state",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8cd451fc338da275f66b15181894e37621698109",
          "body": "Instead of a long argument list.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: use divelog in importDives() and process_imported_dives()",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c253ee6c5619edf754d3ec36974fd527b4aae76",
          "body": "The parser API was very annoying, as a number of tables\nto-be-filled were passed in as pointers. The goal of this\ncommit is to collect all these tables in a single struct.\nThis should make it (more or less) clear what is actually\nwritten into the divelog files.\n\nMoreover, it should now be rather eas\n[…]\nwhen importing dives\nfrom a different log, the autogroup flag was overwritten.\nThis was probably not intended and does not happen anymore.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "core: introduce divelog structure",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-04-14T19:20:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eebb47ec22aafa34e29cd0385853fde10fe208ab",
          "body": "Signed-off-by: Dirk Hohndel <dirk@hohndel.org>",
          "is_bot": false,
          "headline": "Update libdc to address build issue",
          "author_name": "Dirk Hohndel",
          "author_login": "dirkhh",
          "committed_at": "2023-03-29T18:25:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ad8aa988f0d6fa3943ba243126e940ce389e08ad",
          "body": "…mikeller/subsurface\n\ntogether with the libdc change this should now work\n\nSigned-off-by: Dirk Hohndel <dirk@hohndel.org>",
          "is_bot": false,
          "headline": "Merge branch 'add_ostc4_force_firmware_update' of https://github.com/…",
          "author_name": "Dirk Hohndel",
          "author_login": "dirkhh",
          "committed_at": "2023-03-29T17:36:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e3427c7cdec51210de132b3e06bd55c7d250456",
          "body": "- Add option to force overwrite firmware for OSTC4\n\nSigned-off-by: Dirk Hohndel <dirk@hohndel.org>",
          "is_bot": false,
          "headline": "Update libdc",
          "author_name": "Dirk Hohndel",
          "author_login": "dirkhh",
          "committed_at": "2023-03-29T17:35:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e27653374d0ff6479db233365bcd7c9e10389102",
          "body": "Strangely enough, half of the infrastructure was\nalready there, it just wasn't hooked up to a UI\nelement\n\nSigned-off-by: Robert C. Helling <helling@atdotde.de>",
          "is_bot": false,
          "headline": "Add printing option for page orientation",
          "author_name": "Robert C. Helling",
          "author_login": "atdotde",
          "committed_at": "2023-03-29T04:08:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2f4b415e9148c584a743e488804289e9b644c3ae",
          "body": "Some DCs only report water type, without salinity level. Subsurface\nfixes most of these cases using default levels, but when the type of water\nis Sea/Salt, this fix was not saved.\n\nThis causes a bit confusion, mainly if the user defines own salinity level.\n\nSigned-off-by: Rafael M. Salvioni <rafael.salvioni@gmail.com>",
          "is_bot": false,
          "headline": "Saves default sea water salinity in log",
          "author_name": "rafsalvioni",
          "author_login": "rafsalvioni",
          "committed_at": "2023-03-29T03:51:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9da7ec482859b9027c69736986404dd83e2cd798",
          "body": "Fix a bug causing the bluetooth address not being used when downloading\nfrom a 'remembered' dive computer if the device selection is populated.\nThis specifically excludes MacOS, as 'remembering' bluetooth connections\ndoes not seem to be working there as per\nhttps://github.com/subsurface/subsurface/p\n[…]\nng to use the 'remembered'\ndevice if the device selection is populated (`ui.device->currentIndex()\n== -1`) - maybe this should be clarified in a comment?\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix use of bluetooth address for remembered dive computer.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-03-29T03:51:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "31cf991afe0ab4de30c87242097df1ceca5ead5d",
          "body": "Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: remove pointless idle comment in string-format.cpp",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-03-29T03:39:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "264adacba1df1db60be6754c2ec486aaaf4cf2b0",
          "body": "Since the only caller was C++ code, this can be done in\nC++ code, which removes memory-management headaches.\n\nSigned-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>",
          "is_bot": false,
          "headline": "cleanup: move formatting of gas type to string-format.cpp",
          "author_name": "Berthold Stoeger",
          "author_login": "bstoeger",
          "committed_at": "2023-03-29T03:39:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "468c1d8d610ec1aeb7fba49057c870548ad73078",
          "body": "Make the time edit respect the configured time format. Also make the\ndate and time format change when the preferences are changed.\n\nFixes #3849.\n\nSigned-off-by: Michael Keller <github@ike.ch>",
          "is_bot": false,
          "headline": "Desktop: Fix time format in dive planner.",
          "author_name": "Michael Keller",
          "author_login": "mikeller",
          "committed_at": "2023-03-29T03:37:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 39,
      "commits_last_year": 0,
      "latest_release_at": "2017-01-02T23:55:00Z",
      "latest_release_tag": "v4.5.97",
      "releases_from_tags": true,
      "days_since_last_push": 1057,
      "active_weeks_last_year": 0,
      "days_since_latest_release": 3492,
      "mean_days_between_releases": 50.7
    },
    "community": {
      "has_readme": false,
      "has_license": false,
      "has_description": false,
      "has_contributing": false,
      "health_percentage": null,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Documentation/Makefile",
        "ReleaseNotes/Makefile",
        "makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "android-mobile/build.gradle"
      ],
      "largest_source_bytes": 651486,
      "source_files_sampled": 626,
      "oversized_source_files": 42,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "android-mobile/build.gradle"
      ],
      "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": [
        "maven"
      ],
      "dependencies": [],
      "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": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 2,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "dirkhh",
          "commits": 6850,
          "avatar_url": "https://avatars.githubusercontent.com/u/237471?v=4"
        },
        {
          "type": "User",
          "login": "bstoeger",
          "commits": 2469,
          "avatar_url": "https://avatars.githubusercontent.com/u/32835590?v=4"
        },
        {
          "type": "User",
          "login": "mturkia",
          "commits": 1032,
          "avatar_url": "https://avatars.githubusercontent.com/u/2674500?v=4"
        },
        {
          "type": "User",
          "login": "torvalds",
          "commits": 1008,
          "avatar_url": "https://avatars.githubusercontent.com/u/1024025?v=4"
        },
        {
          "type": "User",
          "login": "neolit123",
          "commits": 810,
          "avatar_url": "https://avatars.githubusercontent.com/u/331852?v=4"
        },
        {
          "type": "User",
          "login": "janiversen",
          "commits": 673,
          "avatar_url": "https://avatars.githubusercontent.com/u/6185391?v=4"
        },
        {
          "type": "User",
          "login": "glance-",
          "commits": 633,
          "avatar_url": "https://avatars.githubusercontent.com/u/1290022?v=4"
        },
        {
          "type": "User",
          "login": "atdotde",
          "commits": 615,
          "avatar_url": "https://avatars.githubusercontent.com/u/863957?v=4"
        },
        {
          "type": "User",
          "login": "janmulder",
          "commits": 438,
          "avatar_url": "https://avatars.githubusercontent.com/u/12073956?v=4"
        },
        {
          "type": "User",
          "login": "willemferguson",
          "commits": 295,
          "avatar_url": "https://avatars.githubusercontent.com/u/5078706?v=4"
        }
      ],
      "contributors_sampled": 99,
      "top_contributor_share": 0.392
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "android.yml",
        "codeql-analysis.yml",
        "coverity-scan.yml",
        "ios.yml",
        "linux-fedora-qt6.yml",
        "linux-focal-5.12.yml",
        "linux-jammy-5.15.yml",
        "linux-snap.yml",
        "linux-trusty-5.12.yml",
        "mac.yml",
        "snap_usns.yml",
        "windows.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "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": 10,
            "reason": "project has 20 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0",
            "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": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 10,
            "reason": "SAST tool detected: CodeQL",
            "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": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "83e7f537fbacfc2dfeea1373a7bda7da6df26185",
        "ran_at": "2026-07-27T02:29:20Z",
        "aggregate_score": 3.9,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": true,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/jbygdell/subsurface",
    "host": "github.com",
    "name": "subsurface",
    "owner": "jbygdell"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "critical",
      "name": "Overall health",
      "note": "Abandonment Policy applies a 85% multiplier to weighted overall health.",
      "notes": [
        {
          "code": "abandonment_overall_adjustment",
          "params": {
            "cap": 0,
            "pct": 85
          }
        }
      ],
      "value": 28,
      "inputs": {
        "security": 39,
        "vitality": 17,
        "community": 12,
        "governance": 39,
        "engineering": 56,
        "abandonment_cap": null,
        "abandonment_state": "at_risk",
        "abandonment_multiplier": 85,
        "weighted_overall_before_abandonment": 33,
        "overall_after_abandonment_multiplier": 28
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "critical",
        "name": "Vitality",
        "value": 17,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "critical",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "commits_last_year": 0,
              "human_commit_share": 1,
              "days_since_last_push": 1057,
              "active_weeks_last_year": 0
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 1057 days ago",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 1057
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "0/52 weeks with commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "0 commits in the last year",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "at_risk",
            "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": 40,
            "inputs": {
              "releases_count": 39,
              "latest_release_tag": "v4.5.97",
              "releases_from_tags": true,
              "days_since_latest_release": 3492,
              "mean_days_between_releases": 50.7
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "39 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 39
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 3492 days ago",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 3492
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~50.7 days",
                "points": 19.8,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 50.7
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "cap": null,
              "state": "at_risk",
              "guards": [
                "no_open_demand"
              ],
              "signals": [
                "release_stall",
                "scorecard_unmaintained"
              ],
              "red_flag": true,
              "multiplier_pct": 85,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": 0,
              "unanswered_open_issues": 0,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 1075,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "no human commit for 1075 days; 2 unmet obligation(s): releases stalled, Scorecard reports it unmaintained",
                "points": 85,
                "status": "partial",
                "details": [
                  {
                    "code": "abandonment_flagged",
                    "params": {
                      "days": 1075,
                      "count": 2,
                      "signals": "releases stalled, Scorecard reports it unmaintained"
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 12,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "critical",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": false,
              "has_license": false,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (GPL-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "GPL-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 39,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "moderate",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 62,
            "inputs": {
              "bus_factor": 2,
              "contributors_sampled": 99,
              "top_contributor_share": 0.392
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "2 contributor(s) cover half of all commits",
                "points": 25.2,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 39% of commits",
                "points": 13.7,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 39
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "99 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 99
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 20 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "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": 48,
            "inputs": {
              "followers": 4,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "jbygdell",
              "public_repos": 34,
              "account_age_days": 3489
            },
            "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": "4 followers of jbygdell",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 4,
                      "login": "jbygdell"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "34 public repos, account ~9 yr old",
                "points": 23.2,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 34
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 9
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 56,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "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": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "12 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 12
                    }
                  }
                ],
                "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": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": "https://subsurface-divelog.org",
              "has_readme": false,
              "has_docs_dir": true,
              "has_description": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://subsurface-divelog.org",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 39,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 39,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 15,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 3,
              "scorecard_aggregate": 3.9
            },
            "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 20 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0",
                "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": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool detected: CodeQL",
                "points": 5,
                "status": "met",
                "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": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 8
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 60,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.97,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "97 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 97,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 61,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [
                "Documentation/Makefile",
                "ReleaseNotes/Makefile",
                "makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "android-mobile/build.gradle"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Documentation/Makefile, ReleaseNotes/Makefile, makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Documentation/Makefile, ReleaseNotes/Makefile, 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": "C++ (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "C++"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 96,
            "inputs": {
              "primary_language": "C++",
              "largest_source_bytes": 651486,
              "source_files_sampled": 626,
              "oversized_source_files": 42
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "C++ (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "C++"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "42/626 source files over 60KB",
                "points": 51.3,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 626,
                      "oversized": 42
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Community profile unavailable",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-27T02:29:39.806297Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/j/jbygdell/subsurface.svg",
  "full_name": "jbygdell/subsurface",
  "license_state": "standard",
  "license_spdx": "GPL-2.0"
}

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

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

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