公开记录
软件健康报告模式 0.26.0 · 指标 1.13.0 · 2026-07-22 03:21 UTC

vultisig / vultisig-android

Vultisig Android App

KotlinApache-2.0★ 21 星标⑂ 16 复刻始于 2024年4月在 GitHub 上查看 ↗

vultisig/vultisig-android 的健康指数为 100 分中的 71 分,处于「良好」区间。 其得分最高的类别是Vitality(96/100),最低的是Community & Adoption(43/100)。 最近一次更新在今天。 近期的大部分工作由 2 位贡献者完成。

71
总分 / 100
良好

软件健康指数

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

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

评分画像

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

所有权

132 关注者72 个公开仓库始于 2024年1月

该仓库由组织支持——共同承担、可问责的托管责任,可延续于任何单一维护者之后。

按类别列示的指标

活力

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

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

发布纪律

90优秀
评分方式
27/27有发布版本 — 已发布 100 个发布版本
36/36发布时效 — 最近一次发布版本于 7 天前
27/27发布节奏 — 约每 4.5 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — Project has not signed or included provenance with any releases.
所用输入
releases_count100
latest_release_tagv1.0.114
releases_from_tags
days_since_latest_release7
mean_days_between_releases4.5

社区与采用

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

43存在风险 · 占总体的 18%

流行度与采用

31存在风险
评分方式
21.1/60星标 — 21 个星标
9.8/25复刻 — 16 个复刻
0/15关注者 — 2 位关注者
所用输入
forks16
stars21
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonbelow_threshold

社区健康

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

可持续性与治理

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

72良好 · 占总体的 24%
评分方式
25.2/54巴士系数 — 2 位贡献者贡献了半数提交
14.2/22.5提交分布 — 头号贡献者编写了 37% 的提交
13.5/13.5贡献者广度 — 16 位贡献者
6/10OpenSSF Scorecard:Contributors — project has 2 contributing companies or organizations -- score normalized to 6
所用输入
bus_factor2
contributors_sampled16
top_contributor_share0.368
评分方式
46.3/46.8议题解决 — 99% 的议题已关闭
36.1/38.3PR 接受 — 已裁定的 PR 中 2,630/2,785 已合并
13.5/15OpenSSF Scorecard:Code-Review — Found 28/30 approved changesets -- score normalized to 9
所用输入
merged_prs2,630
open_issues24
closed_issues2,537
issue_closed_ratio0.991
closed_unmerged_prs155
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
15.3/25所有者影响力 — vultisig 有 132 位关注者
18/25既往记录 — 72 个公开仓库,账户约 2 年
所用输入
followers132
owner_typeOrganization
is_verified
owner_loginvultisig
public_repos72
account_age_days906

工程质量

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

74良好 · 占总体的 20%

工程实践

74良好
评分方式
24/24CI 工作流 — 1 个工作流
24/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
6.4/6.4.editorconfig
20/20OpenSSF Scorecard:CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config

文档

75良好
评分方式
30/30README
25/25文档目录
0/15文档 / 主页站点
10/10仓库描述
0/10主题标签
10/10Wiki
所用输入
topics
has_wiki
homepage
has_readme
has_docs_dir
has_description

安全

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

61中等 · 占总体的 16%

安全态势

51中等
评分方式
6.8/7.5Binary-Artifacts — binaries present in source code
0.8/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
6.8/7.5Code-Review — Found 28/30 approved changesets -- score normalized to 9
1.5/2.5Contributors — project has 2 contributing companies or organizations -- score normalized to 6
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
7.5/7.5Maintained — 30 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — 无数据
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
5.2/7.5Vulnerabilities — 3 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate5.1
已排除计分(无数据或不适用):packaging。 其余权重已重新归一化。
评分方式
35/35直接依赖不含已知公告 — 没有直接依赖携带已知公告
0/25间接依赖不含已知公告 — 在此范围内,传递依赖集合无法与开发和测试依赖区分
0/40没有长期未处理的公告 — 没有公告带有发布日期
所用输入
sourceosv
advisories3
affected_packages3
assessed_packages95
unassessed_packages0
affected_by_severityhigh 2, moderate 1
direct_affected_packages0
已排除计分(无数据或不适用):间接依赖不含已知公告, 没有长期未处理的公告。 其余权重已重新归一化。 已将 95 个已解析依赖与 OSV 比对。 该仓库未发布任何索引可解析的软件包,因此改为评估仓库依赖图。该图将开发与测试版本固定同交付的依赖混在一起,因此仅对声明的运行时依赖计分;传递性发现仅作为背景信息列出,不计入评分。 未对可达性进行分析。

AI 就绪度

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

79良好 · 占总体的 0%
评分方式
45/45代理指令 — AGENTS.md, CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 100 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share1
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes19,254
评分方式
12.6/18一条命令的引导启动 — app/build.gradle.kts, build.gradle.kts, data/build.gradle.kts(工具链约定,无任务运行器)
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — Kotlin(静态类型)
10/10可复现环境 — lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 71 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfilesGemfile.lock
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.71
toolchain_manifestsapp/build.gradle.kts, build.gradle.kts, data/build.gradle.kts
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — Kotlin(静态类型)
54.7/55可控的文件大小 — 采样的 1,718 个源文件中有 8 个超过 60KB
所用输入
primary_languageKotlin
largest_source_bytes154,512
source_files_sampled1,718
oversized_source_files8

关键数据

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

更多细节

Star 与 Fork 历史 21 ★ / 16 ⇿
21Star
16Fork
100发布

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

04812162024211622024-042025-062026-07
主版本 0次版本 0修订 100

每个点涵盖 3 天。

OpenSSF Scorecard 5.1 / 10
5.1综合

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

9Binary-Artifactsbinaries present in source code
1Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests30 out of 30 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
9Code-ReviewFound 28/30 approved changesets -- score normalized to 9
6Contributorsproject has 2 contributing companies or organizations -- score normalized to 6
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10
不适用Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
7Vulnerabilities3 existing vulnerabilities detected
直接依赖 2
注册表软件包版本约束清单文件
RubyGemsfastlane2.229.1Gemfile
RubyGemsostructGemfile
全部依赖 95

来自 GitHub 依赖图的完整解析依赖集合:2 个直接依赖与 93 个间接(传递)软件包。仓库提交锁文件时,传递闭包才是完整的。

注册表软件包版本关系
RubyGemsfastlane2.229.1直接
RubyGemsostruct0.6.3直接
RubyGemsabbrev0.1.2间接
RubyGemsaddressable2.9.0间接
RubyGemsartifactory3.0.17间接
RubyGemsatomos0.1.3间接
RubyGemsaws-eventstream1.4.0间接
RubyGemsaws-partitions1.1201.0间接
RubyGemsaws-sdk-core3.241.2间接
RubyGemsaws-sdk-kms1.119.0间接
RubyGemsaws-sdk-s31.210.1间接
RubyGemsaws-sigv41.12.1间接
RubyGemsbabosa1.0.4间接
RubyGemsbase640.2.0间接
RubyGemsbigdecimal4.0.1间接
RubyGemsCFPropertyList3.0.8间接
RubyGemsclaide1.1.0间接
RubyGemscolored1.2间接
RubyGemscolored23.1.2间接
RubyGemscommander4.6.0间接
RubyGemscsv3.3.5间接
RubyGemsdeclarative0.0.20间接
RubyGemsdigest-crc0.7.0间接
RubyGemsdomain_name0.6.20240107间接
RubyGemsdotenv2.8.1间接
RubyGemsemoji_regex3.2.3间接
RubyGemsexcon0.112.0间接
RubyGemsfaraday1.10.5间接
RubyGemsfaraday-cookie_jar0.0.8间接
RubyGemsfaraday-em_http1.0.0间接
RubyGemsfaraday-em_synchrony1.0.1间接
RubyGemsfaraday-excon1.1.0间接
RubyGemsfaraday-httpclient1.0.1间接
RubyGemsfaraday-multipart1.2.0间接
RubyGemsfaraday-net_http1.0.2间接
RubyGemsfaraday-net_http_persistent1.2.0间接
RubyGemsfaraday-patron1.0.0间接
RubyGemsfaraday-rack1.0.0间接
RubyGemsfaraday-retry1.0.4间接
RubyGemsfaraday_middleware1.2.1间接
RubyGemsfastimage2.4.0间接
RubyGemsfastlane-sirp1.0.0间接
RubyGemsgh_inspector1.1.3间接
RubyGemsgoogle-apis-androidpublisher_v30.54.0间接
RubyGemsgoogle-apis-core0.11.3间接
RubyGemsgoogle-apis-iamcredentials_v10.17.0间接
RubyGemsgoogle-apis-playcustomapp_v10.13.0间接
RubyGemsgoogle-apis-storage_v10.31.0间接
RubyGemsgoogle-cloud-core1.8.0间接
RubyGemsgoogle-cloud-env1.6.0间接
RubyGemsgoogle-cloud-errors1.5.0间接
RubyGemsgoogle-cloud-storage1.47.0间接
RubyGemsgoogleauth1.8.1间接
RubyGemshighline2.0.3间接
RubyGemshttp-cookie1.0.8间接
RubyGemshttpclient2.9.0间接
RubyGemsjmespath1.6.2间接
RubyGemsjson2.19.2间接
RubyGemsjwt2.10.2间接
RubyGemslogger1.7.0间接
RubyGemsmini_magick4.13.2间接
RubyGemsmini_mime1.1.5间接
RubyGemsmulti_json1.19.1间接
RubyGemsmultipart-post2.4.1间接
RubyGemsmutex_m0.3.0间接
RubyGemsnanaimo0.4.0间接
RubyGemsnaturally2.3.0间接
RubyGemsnkf0.2.0间接
RubyGemsoptparse0.8.1间接
RubyGemsos1.1.4间接
RubyGemsplist3.7.2间接
RubyGemspublic_suffix7.0.5间接
RubyGemsrake13.3.1间接
RubyGemsrepresentable3.2.0间接
RubyGemsretriable3.1.2间接
RubyGemsrexml3.4.4间接
RubyGemsrouge3.28.0间接
RubyGemsruby2_keywords0.0.5间接
RubyGemsrubyzip2.4.1间接
RubyGemssecurity0.1.5间接
RubyGemssignet0.21.0间接
RubyGemssimctl1.6.10间接
RubyGemssysrandom1.0.5间接
RubyGemsterminal-notifier2.0.0间接
RubyGemsterminal-table3.0.2间接
RubyGemstrailblazer-option0.1.2间接
RubyGemstty-cursor0.7.1间接
RubyGemstty-screen0.8.2间接
RubyGemstty-spinner0.9.3间接
RubyGemsuber0.1.0间接
RubyGemsunicode-display_width2.6.0间接
RubyGemsword_wrap1.0.0间接
RubyGemsxcodeproj1.27.0间接
RubyGemsxcpretty0.4.1间接
RubyGemsxcpretty-travis-formatter1.0.1间接
依赖安全公告 3

该仓库未发布可被索引解析的包,因此评估的是其自身的依赖图——共 95 个包,其中也包含从不交付的开发与测试版本固定:3 个存在已知公告,0 个为直接依赖。

软件包版本关系严重程度公告数修复版本
faraday1.10.5间接12.14.3
jwt2.10.2间接13.2.0
excon0.112.0间接11.5.0

公告表示依赖图中记录的版本落入某条公告的受影响范围。可达性未经分析,且依赖图包含开发与测试的版本固定——某项发现可能只涉及工具链而非交付的软件。

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 250256,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Ruby": 1739,
        "Shell": 7601,
        "Kotlin": 11573842,
        "JavaScript": 2413
      },
      "pushed_at": "2026-07-21T23:56:28Z",
      "created_at": "2024-04-22T02:25:31Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T23:56:30Z",
      "description": "Vultisig Android App",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Kotlin",
      "significant_languages": [
        "Kotlin"
      ]
    },
    "owner": {
      "blog": "vultisig.com",
      "name": "Vultisig: Secure Crypto Vault",
      "type": "Organization",
      "login": "vultisig",
      "company": null,
      "location": null,
      "followers": 132,
      "avatar_url": "https://avatars.githubusercontent.com/u/157932671?v=4",
      "created_at": "2024-01-28T01:22:46Z",
      "is_verified": null,
      "public_repos": 72,
      "account_age_days": 906
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.0.114",
          "kind": "patch",
          "published_at": "2026-07-14T10:27:19Z"
        },
        {
          "tag": "v1.0.113",
          "kind": "patch",
          "published_at": "2026-07-06T00:28:02Z"
        },
        {
          "tag": "v1.0.112",
          "kind": "patch",
          "published_at": "2026-07-03T01:12:42Z"
        },
        {
          "tag": "v1.0.111",
          "kind": "patch",
          "published_at": "2026-06-29T00:00:15Z"
        },
        {
          "tag": "v1.0.110",
          "kind": "patch",
          "published_at": "2026-06-25T23:39:44Z"
        },
        {
          "tag": "v1.0.109",
          "kind": "patch",
          "published_at": "2026-06-21T23:33:46Z"
        },
        {
          "tag": "v1.0.108",
          "kind": "patch",
          "published_at": "2026-06-12T09:33:43Z"
        },
        {
          "tag": "v1.0.107",
          "kind": "patch",
          "published_at": "2026-06-05T22:10:32Z"
        },
        {
          "tag": "v1.0.106",
          "kind": "patch",
          "published_at": "2026-06-05T09:48:20Z"
        },
        {
          "tag": "v1.0.105",
          "kind": "patch",
          "published_at": "2026-06-04T02:37:50Z"
        },
        {
          "tag": "v1.0.104",
          "kind": "patch",
          "published_at": "2026-06-03T23:36:15Z"
        },
        {
          "tag": "v1.0.103",
          "kind": "patch",
          "published_at": "2026-05-19T06:42:54Z"
        },
        {
          "tag": "v1.0.102",
          "kind": "patch",
          "published_at": "2026-05-14T10:22:16Z"
        },
        {
          "tag": "v1.0.101",
          "kind": "patch",
          "published_at": "2026-04-28T04:08:48Z"
        },
        {
          "tag": "v1.0.100",
          "kind": "patch",
          "published_at": "2026-04-25T06:42:34Z"
        },
        {
          "tag": "v1.0.99",
          "kind": "patch",
          "published_at": "2026-04-23T01:41:00Z"
        },
        {
          "tag": "v1.0.98",
          "kind": "patch",
          "published_at": "2026-03-26T06:06:48Z"
        },
        {
          "tag": "v1.0.97",
          "kind": "patch",
          "published_at": "2026-03-17T21:57:22Z"
        },
        {
          "tag": "v1.0.96",
          "kind": "patch",
          "published_at": "2026-02-26T21:57:20Z"
        },
        {
          "tag": "v1.0.95",
          "kind": "patch",
          "published_at": "2026-02-03T09:48:16Z"
        },
        {
          "tag": "v1.0.94",
          "kind": "patch",
          "published_at": "2026-02-02T22:33:39Z"
        },
        {
          "tag": "v1.0.93",
          "kind": "patch",
          "published_at": "2026-01-15T21:49:05Z"
        },
        {
          "tag": "v1.0.92",
          "kind": "patch",
          "published_at": "2026-01-15T00:44:19Z"
        },
        {
          "tag": "v1.0.91",
          "kind": "patch",
          "published_at": "2026-01-13T23:00:24Z"
        },
        {
          "tag": "v1.0.90",
          "kind": "patch",
          "published_at": "2026-01-07T22:03:48Z"
        },
        {
          "tag": "v1.0.89",
          "kind": "patch",
          "published_at": "2025-12-11T23:33:15Z"
        },
        {
          "tag": "v1.0.88",
          "kind": "patch",
          "published_at": "2025-12-09T23:14:30Z"
        },
        {
          "tag": "v1.0.87",
          "kind": "patch",
          "published_at": "2025-11-29T01:50:15Z"
        },
        {
          "tag": "v1.0.86",
          "kind": "patch",
          "published_at": "2025-11-26T23:56:24Z"
        },
        {
          "tag": "v1.0.85",
          "kind": "patch",
          "published_at": "2025-11-26T05:26:24Z"
        },
        {
          "tag": "v1.0.84",
          "kind": "patch",
          "published_at": "2025-11-18T09:06:56Z"
        },
        {
          "tag": "v1.0.83",
          "kind": "patch",
          "published_at": "2025-11-15T05:32:41Z"
        },
        {
          "tag": "v1.0.82",
          "kind": "patch",
          "published_at": "2025-11-03T23:25:04Z"
        },
        {
          "tag": "v1.0.81",
          "kind": "patch",
          "published_at": "2025-10-28T08:25:37Z"
        },
        {
          "tag": "v1.0.80",
          "kind": "patch",
          "published_at": "2025-10-27T08:49:49Z"
        },
        {
          "tag": "v1.0.79",
          "kind": "patch",
          "published_at": "2025-10-21T01:14:52Z"
        },
        {
          "tag": "v1.0.78",
          "kind": "patch",
          "published_at": "2025-10-18T23:32:48Z"
        },
        {
          "tag": "v1.0.77",
          "kind": "patch",
          "published_at": "2025-10-09T09:34:50Z"
        },
        {
          "tag": "v1.0.76",
          "kind": "patch",
          "published_at": "2025-10-07T22:38:11Z"
        },
        {
          "tag": "v1.0.75",
          "kind": "patch",
          "published_at": "2025-10-07T00:46:28Z"
        },
        {
          "tag": "v1.0.74",
          "kind": "patch",
          "published_at": "2025-10-02T05:59:03Z"
        },
        {
          "tag": "v1.0.73",
          "kind": "patch",
          "published_at": "2025-09-15T22:51:48Z"
        },
        {
          "tag": "v1.0.72",
          "kind": "patch",
          "published_at": "2025-09-08T05:59:44Z"
        },
        {
          "tag": "v1.0.71",
          "kind": "patch",
          "published_at": "2025-08-22T09:42:30Z"
        },
        {
          "tag": "v1.0.70",
          "kind": "patch",
          "published_at": "2025-08-20T07:01:35Z"
        },
        {
          "tag": "v1.0.69",
          "kind": "patch",
          "published_at": "2025-08-05T01:17:42Z"
        },
        {
          "tag": "v1.0.68",
          "kind": "patch",
          "published_at": "2025-08-04T09:54:47Z"
        },
        {
          "tag": "v1.0.66",
          "kind": "patch",
          "published_at": "2025-08-01T10:48:34Z"
        },
        {
          "tag": "v1.0.65",
          "kind": "patch",
          "published_at": "2025-07-21T23:23:20Z"
        },
        {
          "tag": "v1.0.64",
          "kind": "patch",
          "published_at": "2025-07-18T10:10:05Z"
        },
        {
          "tag": "v1.0.63",
          "kind": "patch",
          "published_at": "2025-07-17T00:32:26Z"
        },
        {
          "tag": "v1.0.62",
          "kind": "patch",
          "published_at": "2025-07-06T22:54:54Z"
        },
        {
          "tag": "v1.0.61",
          "kind": "patch",
          "published_at": "2025-07-04T10:24:17Z"
        },
        {
          "tag": "v1.0.60",
          "kind": "patch",
          "published_at": "2025-07-03T11:59:26Z"
        },
        {
          "tag": "v1.0.59",
          "kind": "patch",
          "published_at": "2025-06-21T00:47:02Z"
        },
        {
          "tag": "v1.0.58",
          "kind": "patch",
          "published_at": "2025-06-11T23:05:23Z"
        },
        {
          "tag": "v1.0.57",
          "kind": "patch",
          "published_at": "2025-05-29T01:14:05Z"
        },
        {
          "tag": "v1.0.56",
          "kind": "patch",
          "published_at": "2025-05-16T06:52:59Z"
        },
        {
          "tag": "v1.0.55",
          "kind": "patch",
          "published_at": "2025-05-07T06:53:30Z"
        },
        {
          "tag": "v1.0.54",
          "kind": "patch",
          "published_at": "2025-05-01T15:02:48Z"
        },
        {
          "tag": "v1.0.53",
          "kind": "patch",
          "published_at": "2025-04-30T22:55:33Z"
        },
        {
          "tag": "v1.0.52",
          "kind": "patch",
          "published_at": "2025-04-29T21:59:27Z"
        },
        {
          "tag": "v1.0.51",
          "kind": "patch",
          "published_at": "2025-04-28T10:41:26Z"
        },
        {
          "tag": "v1.0.50",
          "kind": "patch",
          "published_at": "2025-04-25T10:08:09Z"
        },
        {
          "tag": "v1.0.49",
          "kind": "patch",
          "published_at": "2025-04-14T08:22:51Z"
        },
        {
          "tag": "v1.0.48",
          "kind": "patch",
          "published_at": "2025-04-07T06:52:19Z"
        },
        {
          "tag": "v1.0.47",
          "kind": "patch",
          "published_at": "2025-03-23T23:54:14Z"
        },
        {
          "tag": "v1.0.46",
          "kind": "patch",
          "published_at": "2025-03-20T22:03:00Z"
        },
        {
          "tag": "v1.0.45",
          "kind": "patch",
          "published_at": "2025-03-19T23:00:19Z"
        },
        {
          "tag": "v1.0.44",
          "kind": "patch",
          "published_at": "2025-03-13T21:26:05Z"
        },
        {
          "tag": "v1.0.43",
          "kind": "patch",
          "published_at": "2025-03-12T05:52:02Z"
        },
        {
          "tag": "v1.0.42",
          "kind": "patch",
          "published_at": "2025-02-27T00:15:07Z"
        },
        {
          "tag": "v1.0.41",
          "kind": "patch",
          "published_at": "2025-02-13T21:36:11Z"
        },
        {
          "tag": "v1.0.40",
          "kind": "patch",
          "published_at": "2025-02-13T07:36:52Z"
        },
        {
          "tag": "v1.0.39",
          "kind": "patch",
          "published_at": "2025-02-06T01:53:18Z"
        },
        {
          "tag": "v1.0.38",
          "kind": "patch",
          "published_at": "2025-01-22T23:14:51Z"
        },
        {
          "tag": "v1.0.37",
          "kind": "patch",
          "published_at": "2025-01-09T22:00:21Z"
        },
        {
          "tag": "v1.0.36",
          "kind": "patch",
          "published_at": "2024-12-09T23:07:13Z"
        },
        {
          "tag": "v1.0.35",
          "kind": "patch",
          "published_at": "2024-12-04T22:20:09Z"
        },
        {
          "tag": "v1.0.34",
          "kind": "patch",
          "published_at": "2024-11-20T23:29:57Z"
        },
        {
          "tag": "v1.0.33",
          "kind": "patch",
          "published_at": "2024-11-14T02:27:51Z"
        },
        {
          "tag": "v1.0.32",
          "kind": "patch",
          "published_at": "2024-11-02T00:26:04Z"
        },
        {
          "tag": "v1.0.31",
          "kind": "patch",
          "published_at": "2024-10-30T23:30:10Z"
        },
        {
          "tag": "v1.0.30",
          "kind": "patch",
          "published_at": "2024-10-18T22:16:09Z"
        },
        {
          "tag": "v1.0.29",
          "kind": "patch",
          "published_at": "2024-10-14T11:37:29Z"
        },
        {
          "tag": "v1.0.27",
          "kind": "patch",
          "published_at": "2024-10-08T21:14:06Z"
        },
        {
          "tag": "v1.0.26",
          "kind": "patch",
          "published_at": "2024-10-07T00:17:56Z"
        },
        {
          "tag": "v1.0.25",
          "kind": "patch",
          "published_at": "2024-09-26T08:43:58Z"
        },
        {
          "tag": "v1.0.24",
          "kind": "patch",
          "published_at": "2024-09-25T22:48:58Z"
        },
        {
          "tag": "v1.0.23",
          "kind": "patch",
          "published_at": "2024-09-16T22:32:55Z"
        },
        {
          "tag": "v1.0.22",
          "kind": "patch",
          "published_at": "2024-09-11T10:57:37Z"
        },
        {
          "tag": "v1.0.21",
          "kind": "patch",
          "published_at": "2024-09-11T01:46:46Z"
        },
        {
          "tag": "v1.0.20",
          "kind": "patch",
          "published_at": "2024-09-05T05:28:24Z"
        },
        {
          "tag": "v1.0.19",
          "kind": "patch",
          "published_at": "2024-09-02T05:54:20Z"
        },
        {
          "tag": "v1.0.18",
          "kind": "patch",
          "published_at": "2024-08-28T22:08:39Z"
        },
        {
          "tag": "v1.0.17",
          "kind": "patch",
          "published_at": "2024-08-24T00:55:56Z"
        },
        {
          "tag": "v1.0.16",
          "kind": "patch",
          "published_at": "2024-08-18T02:38:27Z"
        },
        {
          "tag": "v1.0.15",
          "kind": "patch",
          "published_at": "2024-08-11T02:39:54Z"
        },
        {
          "tag": "v1.0.14",
          "kind": "patch",
          "published_at": "2024-08-06T06:13:57Z"
        },
        {
          "tag": "v1.0.13",
          "kind": "patch",
          "published_at": "2024-08-03T06:19:06Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "2c230ced6fed249f439e9fbca9c707458f369ce1",
          "body": "…#5360)\n\n* fix(cardano): recover loser device on duplicate-broadcast rejection\n\nOn a multi-device Cardano keysign the losing device rebroadcasts the peer's\nbyte-identical signed tx and Ogmios rejects it with \"All inputs are spent.\nTransaction has probably already been included\". The old recovery req\n[…]\n\n  every recovery path rethrows instead of reporting an untrackable success.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cardano): recover loser device on duplicate-broadcast rejection (…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-21T23:56:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f939c3e06b9fd77c5e25b450b1072b39b1c5f5d0",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump targetSdk to 36 (#5370)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-21T23:34:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cf94f1910c4af079807c6e6f222f914207a646ce",
          "body": "* fix(solana): count Solana swap priority fee once, not twice\n\ncalculateDefaultFees added a computed priority fee on top of a base-fee\nconstant that already bundled the floor priority fee, roughly doubling\nthe displayed swap fee. Use a genuine base-only signature-fee constant so\nthe priority fee is \n[…]\ncom>\n\n* address review comments: clarify single-signer scope in fee comment\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(solana): count swap priority fee once, not twice (#5359)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-21T22:54:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "11182faa0c5cc8d764ae1a2b836070f8a81a978e",
          "body": "Co-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>",
          "is_bot": false,
          "headline": "style: apply ktfmt formatting (#5365) (#5367)",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-21T11:41:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b42df2d93610d1d7ec1bc8378cc857661f8e6845",
          "body": "…reen (#5354)\n\n* fix(deposit): correct From/To/pool on Mint LP transaction-complete screen\n\nA MayaChain Mint (add-liquidity) deposit reached the Transaction-complete\nscreen with three display defects versus the pre-sign Function overview:\n\n- From showed the raw chain address instead of \"VaultName (a\n[…]\nrim the test comment to what toUiTransactionInfo() actually asserts.\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(deposit): correct From/To/pool on Mint LP transaction-complete sc…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-21T10:05:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6091a9a4ea6c5e9b2ce7e0b3a36d967db025a942",
          "body": "Co-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>",
          "is_bot": false,
          "headline": "style: apply ktfmt formatting (#5328) (#5362)",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-21T09:47:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "219fce05ef874ade8a9b53ee785e40cb4b465848",
          "body": "* fix: check swap inbound status before signing\n\n* fix: address swap preflight review\n\n* address review comments\n\n- default gasRate/gasRateUnits to empty to keep the shared inbound model\n  from decode-failing (and false-blocking) when Maya omits gas fields\n- assert isSigning resets to false on the b\n[…]\nross tests as\nUncaughtExceptionsBeforeTest. The VM already injects ioDispatcher for\nexactly this reason (withVaultLabels uses it).\n\n---------\n\nCo-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: check swap inbound status before signing (#5342)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-21T09:26:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0a0a65182ae7978305462dd526354c8afebef855",
          "body": "The Schnorr initiator regenerated and re-uploaded a fresh setup message\non every retry because its upload branch lacked the `attempt == 0` guard\nthat DklsKeysign and MldsaKeysign already use. A peer still mid-protocol\non the previous setup message would then desync, signing against a\ndifferent sessi\n[…]\noad on the first attempt so retries fall through to\nthe existing download branch and reuse the setup message already on the\nrelay.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): reuse Schnorr setup message on retry (#5327) (#5353)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-20T22:50:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b59e8dac91b1bde3ac6b9f0e9865ed06059c771d",
          "body": "* fix(swap): dispatch SwapKit UTXO signer by chain, not txType\n\nJoining a SwapKit swap sourced from Dogecoin/BitcoinCash/Dash/Zcash and\ninitiated on another client (e.g. the browser extension) failed with\n\"Unsupported SwapKit txType for signing\" or silently signed with the\nwrong signer. SwapKit's wi\n[…]\nch test\n\nCodeRabbit flagged e.message!! as a potential NPE if the exception carries\nno message; use a null-safe assertion instead so a missing message fails\nthe assertion cleanly rather than throwing.",
          "is_bot": false,
          "headline": "fix(swap): resolve SwapKit UTXO signer by chain, not txType (#5346)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-20T22:44:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ec951cb358101e67afe8a12b48dd8ca4e83323f1",
          "body": "* feat(icons): adopt Icons V3 for 29 icons at parity with iOS #4834\n\nSwap 29 UI drawables to their Icons V3 geometry, taken byte-for-byte from\nthe V3 art iOS shipped in #4834 (its imageset SVGs). Because Android resolves\ndrawables by filename through R, each file is edited in place under its\nexistin\n[…]\nfixes the aspect distortion\nwithout changing any rendered icon size.\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(icons): adopt Icons V3 across UI drawables (42 icons) (#5352)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-20T22:41:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7500e69997e5a14ec446d32b8077f4e504e80f68",
          "body": "…#5350)\n\nTwo same-shaped bugs where a per-chain lookup silently returned a wrong\nvalue instead of failing:\n\n- String.getChain() resolved any unknown ticker to ThorChain, so a rename\n  upstream could misroute a secured-asset withdrawal. It now throws; the\n  DepositFormViewModel catch surfaces a user \n[…]\n  and the chain-variable symbol display sites through it, and marked the\n  WalletCore accessors as unsafe for display/amount math.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(chain): make Coins the single source for chain identity (#5323) (…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-20T10:28:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fd65ee0144e6b98903626483c86d5dc26f4e4006",
          "body": "* feat(solana): sign and broadcast dApp transaction batches\n\nsignAllTransactions/signAndSendAllTransactions batches were hashed and\nsigned in full by the keysign ceremony, but assembly only delivered the\nfirst transaction, so the whole batch died with an opaque Signing Error\nafter the user had alrea\n[…]\nPayload test helper\ninstead of a near-identical solPayload, and add direct coverage for\nSigningHelper.getSignedTransactions' batch-vs-single routing, which was\npreviously only exercised through mocks.",
          "is_bot": false,
          "headline": "feat(solana): sign and broadcast dApp transaction batches (#5265)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-20T10:22:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dca2b35ab385f416b9b0c3df290e6d5f6a9695bd",
          "body": "…(#5349)\n\nXRPL (GemWallet signMessage) custom messages sign SHA-512-half — the\nfirst 32 bytes of SHA-512 — of the message bytes. Android's custom-message\nkeysign had no Ripple branch, so a `chain: Ripple` message fell through to\nkeccak256 and diverged from the initiator's digest, so a Secure-Vault\nA\n[…]\nsetup message and co-signing 404'd.\n\nAdd `toSha512ByteArray()` and a `Chain.Ripple` branch to the digest `when`,\nmirroring the shared contract in vultisig-windows getCustomMessageHex.ts.\n\nCloses #5341",
          "is_bot": false,
          "headline": "feat(ripple): SHA-512-half digest for XRPL custom-message co-signing …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-20T10:01:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d67248a4a05e7ec4bb22bd1651b5e63a38a6e974",
          "body": "…21) (#5332)\n\n* fix(swap): stop zeroing the SwapKit swap fee on Cardano (#5321)\n\nCardano is classified as TokenStandard.UTXO, so `isSwapKitUtxoSwap` in\nSwapQuotePipeline.buildSuccess treated ADA like a PSBT-broadcast UTXO chain\nand zeroed the displayed swap fee — understating the fee on ADA SwapKit \n[…]\ntValueToString dependency from SwapQuotePipeline.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): keep SwapKit swap fee zeroed on Cardano, hide the row (#53…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-19T23:27:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1c1f9553e552583756065ae93e7da2fb9249d13f",
          "body": "…39) (#5340)\n\nThe swap overview suppressed the \"on <chain>\" indicator on native assets,\nso a native From asset (e.g. BTC) showed no chain while a token To asset\n(e.g. USDC on Ethereum) did — an inconsistent read of the two sides. Gate\nthe indicator on isSwap alone so both rows communicate their chain.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): show chain indicator on both swap-overview token rows (#53…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-19T12:27:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "90b361570bde76e749d92502c4792ca1952a3374",
          "body": "…(#5338)\n\n* fix(substrate): stop reporting success on a malformed broadcast body (#5320)\n\nA truncated or proxy-mangled author_submitExtrinsic response decodes to\n(null, null) under the production explicitNulls=false config. That null was\nindistinguishable from the intended \"duplicate -> resolve to k\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(substrate): stop reporting success on a malformed broadcast body …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-19T12:19:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0cc3bb3ba70c537da6ecbb8576299408f9c28670",
          "body": "…ddress) (#5333) (#5336)\n\n* fix: format swap complete screen From/To as VaultName (Address) (#5333)\n\nThe swap Transaction-complete screen rendered From/To as bare\ntruncated addresses, unlike Send/Deposit which already show\nVaultName (Address). Resolve src/dst vault names in KeysignViewModel\nvia the \n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Swap complete screen: From/To addresses not formatted as VaultName (A…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-19T10:24:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "486e9f95930fcf7921772e587341cefdf0abf19c",
          "body": "…ined devices (#5329) (#5330)\n\n* style: apply ktfmt formatting (#5329)\n\n* fix: resolve CI compile error in SwapTransactionBuilder (#5329)\n\nquote.fees is a TokenValue with no 'token' back-reference, so\nquote.fees.token.{chain.id,contractAddress,decimal} failed to compile.\nThe swap-fee coin context is\n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Swap overview: Network Fee & Swap Fee differ between initiator and jo…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-18T23:48:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "296a9ce42bf15f72660e564230c0946fa0da167a",
          "body": "* feat(swap): make THORChain secured assets discoverable in swap picker\n\nSecured assets (btc-btc, eth-usdc-..., etc.) were only shown in the\nswap destination picker if the vault already held a balance, since the\nTHORChain token catalog had no secured-asset entries. Populate the\ncatalog from THORChai\n[…]\ne file), which could let a double-tap on two same-ticker rows\nleak a stale selection into a later, unrelated picker visit. Fixed with\na per-visit UUID plus a re-entrancy guard in SelectAssetViewModel.",
          "is_bot": false,
          "headline": "Make THORChain secured assets discoverable in the swap picker (#5271)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-18T23:37:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "38c8f7b29798f0d6678126898598ddd4292f03a1",
          "body": "\"Max\" captured the balance and gas fee once at tap time and never\nre-clamped when either moved before submit — a cached balance correcting\ndownward after network hydration, or EVM gas rising. The stale-high\nsnapshot then exceeded what was actually spendable and submit validation\nrejected it as \"insu\n[…]\nive token-balance shortfall to its own error\nstring without the \"with fees\" framing that wrongly implied reserving\ntokens for gas.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(send): re-clamp Max to current balance/fee at submit (#5316) (#5325)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-18T10:16:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5ce9389124542b847cb481d32a86332792b602cc",
          "body": "…314) (#5324)\n\n* fix(keysign): recover DKLS-family signature from relay on failure (#5314)\n\nA DKLS-family keysign device whose local session never reaches\n`isFinished` — e.g. when a final-round relay message is lost to a\ntransport error — would fail with \"signatures empty\" even though the\npeer alrea\n[…]\nresume.\nApplied to all three DKLS-family classes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): recover DKLS-family signature from relay on failure (#5…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-18T09:57:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3060455294e4b5461aeb444fed491b546682e286",
          "body": "…#5312)\n\n* fix(evm): stop persisting a failed balance read as a real 0 (#5308)\n\nA funded EVM account showed 0/$0.00 after a single transient network\nfailure, and that zero was written to Room over the last-known balance,\nsurviving app restarts until a successful refresh — reading as \"my funds\ndisapp\n[…]\npick.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>\nCo-authored-by: Roman <32820910+rkokhatskyi@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(evm): stop persisting a failed balance read as a real 0 (#5308) (…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-18T06:28:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ebf95647819a2ff7aa6e9c34a4702256bcb9c1d0",
          "body": "…ir (#5311)\n\n* fix(swap): drop late quote resolved for a different amount on the same pair\n\napplyQuoteResult's late-result guard only checked isLiveInputQuotable\n(\"is something quotable now\"), never whether the resolved fetch matched\nthe amount now in the field. A fetch queued for an earlier amount \n[…]\n Claude Opus 4.8 <noreply@anthropic.com>\n\n* fix(swap): reject superseded quote results\n\n* fix(swap): bind quotes to routing settings\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): drop late quote resolved for a different amount on same pa…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-18T00:48:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0eeacd873c302de6386e05c108507568e0179283",
          "body": "* fix(thorchain): label Unbond confirmation \"Unbonding\" with formatted From/To (#5301)\n\nThe THORChain Unbond \"Function overview\" confirmation mislabeled the action\nas \"You're sending\" and showed the From/To vault address as a raw thor1…\nstring.\n\nThe node-management Unbond flow builds its DepositTran\n[…]\nsolation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(thorchain): Unbond confirmation label + formatted From/To (#5306)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-17T09:13:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d630679314bd2d75ebb8cbca8912258d301fa2d4",
          "body": "hypurrscan only serves HyperEVM txs under an /evm/tx/ prefix; its bare\n/tx/<hash> path — what the generic explorer path produced — errors with\n\"Unexpected error (code=358)\". Switch the Hyperliquid base to\nhyperevmscan.io, an Etherscan-style explorer whose /tx/ and /address/\npaths resolve through the existing generic cases, fixing both\ntransaction and address links without special-casing.",
          "is_bot": false,
          "headline": "fix(hyperliquid): point explorer links at hyperevmscan (#5305) (#5307)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-16T11:49:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0eabdd7c45ad556291955fd61910bbc99ce1fe47",
          "body": "* fix(swap): stop placeholder skeletons blinking on empty amount\n\nThe destination/fee skeletons flashed true→false on form open and on a\npair/destination change because isLoading was raised unconditionally: the\ninput onEach fired for the empty-field emission, and the slippageBps /\nexternalRecipient \n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): stop placeholder skeletons blinking on empty amount (#5297)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-16T11:39:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "781cad4ca4d2d648425bf7c443ed8eea05d0ec1d",
          "body": "* feat(keysign/ripple): co-sign dApp XRPL transactions (SignRipple)\n\nCarry a dApp-supplied XRPL transaction (via the extension's GemWallet\nprovider) to the Secure Vault co-signer verbatim and sign its raw JSON\nthrough WalletCore's rawJson path, so every device produces byte-identical\nsigning bytes m\n[…]\nd verify_transaction_consent_dapp_transaction across all 10 locales.\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(keysign): co-sign dApp XRPL transactions (SignRipple) #5298 (#5303)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-16T10:34:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "12064887514b316d640f27ca9a03aed639711ff2",
          "body": "SEI is EVM-compatible (chainId 1329, secp256k1, 0x addresses, derivation\npath m/44'/60'/0'/0/0). It was mapped to WalletCore's native CoinType.SEI,\nwhose raw derivationPath() is the Cosmos path m/44'/118'/0'/0/0 — papered\nover with compatibleType/compatibleDerivationPath/compatibleChainId\noverrides \n[…]\nvation path consistent across platforms.\n\nAdds SeiEvmCoinTypeTest pinning Chain.Sei -> ETHEREUM, path m/44'/60', and\nchainId 1329.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sei): map SEI to the Ethereum coin type (#5300)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-15T12:17:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aa09c08783ece755822803fe09f1a258d9d8b17c",
          "body": "…ntil amount entered (#5294) (#5295)\n\n* fix: TRON un/freeze fee loads on entry & Continue gated on amount (#5294)\n\nThe TRON Freeze/Unfreeze screens reuse the shared SendForm. Their gas-fee\npipeline returned early when the amount field was empty, so isGasFeeLoading\nnever cleared — leaving the fee row\n[…]\ny@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: aminsato <amin.saradar@yahoo.com>",
          "is_bot": false,
          "headline": "TRON Unfreeze/Freeze: Continue disabled & Network Fee stuck loading u…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-15T10:19:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8b67e7c266fa25c23b5d4625a59151e9828bd47c",
          "body": "* feat: add USDC, USDD & stUSDT Tron tokens for desktop parity (#5286)\n\nAdd USDC, USDD and stUSDT TRC-20 tokens to the built-in Tron token\nregistry so they appear in the \"Choose Tokens\" screen with balances,\nUSD prices and logos, matching the desktop token set.\n\n- Add USDC (usd-coin), USDD (usdd) an\n[…]\nn (ios parity)\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "Tron: add USDC, USDD & stUSDT tokens (desktop parity) (#5286) (#5287)",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-15T00:57:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d7b262714fe4adce893c1a2b50b77dbbbb55cc91",
          "body": "…ating (#5275) (#5284)\n\n* fix(thorchain): auto-discover bRUNE/ybRUNE and correct stale identities\n\nA fresh wallet only ever seeds native RUNE, so getRefreshTokens' enabledDenoms\ngate dropped a newly received bRUNE/ybRUNE bank denom before it could reach the\ncanonicalization block — the tokens only s\n[…]\no-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(thorchain): bRUNE/ybRUNE follow-ups — discovery, pricing & swap g…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-14T23:06:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3ed662c94bde4fe75ba7d60d7e6e39e5b9c6b872",
          "body": "* fix(keysign): friendly message for unfunded Cosmos accounts\n\nA Cosmos SDK code=9 (ErrUnknownAddress) broadcast rejection - the\nfee-payer account has no on-chain presence, e.g. a never-funded QBTC\nvault - fell through to the generic broadcast-rejected copy, which\ninterpolates the node's raw_log ver\n[…]\nrted locales.\n\n* fix(keysign): clarify Dutch \"fund the wallet\" wording\n\n\"Schakel ... in\" reads as \"switch on/enable\", not \"top up\" - switch to\n\"Vul de wallet eerst aan\" per CodeRabbit review on #5292.",
          "is_bot": false,
          "headline": "fix(keysign): friendly message for unfunded Cosmos accounts (#5292)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-14T22:21:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4ba569f8147b3f206898ac557dcb414e06233422",
          "body": "…0 (#5276) (#5288)\n\nRippleApi.getBalance() swallowed every non-cancellation exception into\nBigInteger.ZERO, so a network timeout was indistinguishable from a\ngenuinely empty account and the UI committed a false $0.00 — reading as\n\"the funds disappeared\".\n\nLet the failure propagate: AccountsRepositor\n[…]\nnstead of\nflattening it into an IllegalStateException with no cause, so the\ntransport kind (timeout / no connectivity) survives for classification.\n\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(ripple): propagate balance fetch failures instead of showing $0.0…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-14T12:28:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7d6eb0c815c91edeb09e1fb58d7c573439a68f7d",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump version to 1.0.114 (#5289)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-14T10:29:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90c4fda6fe026833522478c386fb261c7c49bea9",
          "body": "…d) (#5277) (#5281)\n\n* fix(ripple): treat expired/unconfirmed XRP tx as neutral, not Error (#5277)\n\nXRPL returns a txnNotFound error response for a tx that never reached a\nvalidating node before its LastLedgerSequence. getTsStatus deserialized\nstrictly into the success shape and threw MissingFieldEx\n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "XRP send shows 'Error' when tx expired/never confirmed (no funds move…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-14T10:06:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "335682e4633bb1b58181a3d45a552e427d921769",
          "body": "…(#5280)\n\nWhen the OS reclaims the process, tapping a keysign push notification\ncold-starts MainActivity and replays the full branded AnimatedSplash\nbefore the keysign flow appears, so the cold path looks like the app\nrestarting from scratch — unlike the warm onNewIntent path which shows\nno splash.\n\n[…]\n destination resolves\n(isLoading) rather than starting on the stale Route.Home default, then\nroute straight into the keysign flow.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): skip branded splash on notification cold start (#5269) …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-14T09:56:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0ec13342c1c4e34ebad3a9c7e871cc3d9fc307b7",
          "body": "…rongly shows \"Add to Address Book\" (#5272) (#5278)\n\n* fix(keysign): resolve To-address to vault name via pubkey-derived address on joined devices (#5272)\n\nThe To field resolved dstVaultName by matching the destination only against\neach vault's enabled coins. On a joined co-signer the destination co\n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Joined device doesn't resolve To-address to saved vault/contact and w…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-14T09:53:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "451bedbc54b367965fd86672f0ad775c60319965",
          "body": "…e fee is ready (#5270) (#5273)\n\n* style: apply ktfmt formatting (#5270)\n\n* fix: re-arm gas-fee loading state on recomputes (#5270)\n\nisGasFeeLoading was only ever set false, so the shimmer + disabled\nContinue happened only on the first estimate. Add collectGasFeeLoading()\nto set it back to true when\n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Send: Network Fee shows nothing while loading; Continue enabled befor…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-14T09:50:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3e4ad01e6d5df798f73eb51f048b016af913f25b",
          "body": "…(#5283)\n\n* fix(tron): operation-aware Verify header for freeze/unfreeze (#5274)\n\nTRON freeze/unfreeze routes through the Send form and carries its\noperation only as an internal memo prefix (FREEZE:/UNFREEZE:<resource>).\nBy the Verify layer no operation signal survived, so the last\npre-signing check\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tron): operation-aware Verify header for freeze/unfreeze (#5274) …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-14T09:42:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0c9e64e9bf7feb126274877ae89bc3410053dc70",
          "body": "…success (#5266)\n\n* fix(broadcast): on-chain verify Cosmos/QBTC code-32 before reporting success\n\nThe joined-device duplicate-broadcast recovery trusted a Cosmos code=32\n(account sequence mismatch) blindly and returned the local hash as success —\nso a sequence consumed by an unrelated tx surfaced a \n[…]\nunded / Failed; only Pending / NotFound / TimedOut propagate the rejection.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(broadcast): on-chain verify Cosmos/QBTC code-32 before reporting …",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-13T22:23:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "965aebc72b70d6948fd2d393fa9121c9f2f61f90",
          "body": "…g (#5267)\n\n* fix(cardano): emit Conway-era 4-element tx envelope with is_valid flag\n\nWalletCore's compileWithSignatures emits the legacy 3-element Cardano\nenvelope [body, witness_set, aux_data]. Conway-era nodes reject it and\nrequire the 4-element form [body, witness_set, is_valid, aux_data].\n\nSpli\n[…]\n SwapKitCardanoSigner's walker. Also\nhardens extractCardanoTransactionBody.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cardano): emit Conway-era 4-element tx envelope with is_valid fla…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-13T22:23:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c1bb9b50ce92502b5eb39741f295b8bec28d281f",
          "body": "…(#5264)\n\n* fix(thorchain): treat bRUNE as an LP token so it's excluded from asset pickers\n\nThe `isLpToken` equality check for `x/brune` sat under the `Chain.MayaChain`\nbranch, but `x/brune` is a THORChain bank denom — so the check was unreachable\nand bRUNE was never filtered out of the swap/asset-s\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(thorchain): add bRUNE & ybRUNE (display, pricing, LP exclusion) …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-13T11:07:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "72ae8b96314145462b1b1b5be373c03b593352a5",
          "body": "…246)\n\n* fix(solana): sign dApp raw transactions over their original bytes\n\nCo-signing a dApp-supplied raw Solana transaction decoded it into\nWalletCore's representation and re-serialized it before hashing and\nsigning. That re-encode is not guaranteed to reproduce the original\nbytes for a v0 message\n[…]\nature-count decode into a small\ndocumented helper so parseRawTransaction reads as pure structure, and\nreplace the magic 64 with a named SIGNATURE_LENGTH constant that also\nguards the signature splice.",
          "is_bot": false,
          "headline": "fix(solana): sign dApp raw transactions over their original bytes (#5…",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-12T22:49:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2f0e6368089a8786f18d20d972e338a9a5f3fb31",
          "body": "* feat(solana): staking foundation + validator-metadata seam (Phases 1-2 of #5078)\n\nPhase 1 — Foundation: Solana stake-account/validator/epoch models, staking\nconfig, and RPC + caching read layer (getVoteAccounts / getProgramAccounts /\ngetEpochInfo / getMinimumBalanceForRentExemption). No UI, no sig\n[…]\no-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(solana): native staking on the DeFi tab (epic #5078) (#5239)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-12T22:37:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0d7c97c7af4d9bcefcd4df598e36a2fb1723ede4",
          "body": "… RequireDest gate) (#5247)\n\n* feat(ripple): dedicated XRP Destination Tag field (+ X-addr autofill, RequireDest gate)\n\nAdds first-class XRPL destination-tag support to the XRP send flow, mirroring\nthe iOS combo design (vultisig-ios#4749).\n\n- Sync commondata submodule to include RippleSpecific.desti\n[…]\nwe\n  intentionally keep it as free text rather than claim exact iOS parity.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ripple): dedicated XRP Destination Tag field (+ X-addr autofill,…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-12T09:57:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c2f0b5073e45ec28dc5382a801ef4b9f77c3e22d",
          "body": "…wn Confirmed (#5263)\n\nEvery TON send is signed with IGNORE_ACTION_PHASE_ERRORS, so a transfer that\ncan't be paid for (e.g. value+fees exceed balance under PAY_FEES_SEPARATELY) is\nsilently skipped instead of aborting: the wallet tx lands un-aborted with the\nseqno consumed but no funds moved. TonStat\n[…]\ng-sdk#1119).\n\nCovered by 13 unit tests, including the exact aborted:false + no_funds:true case\nand a verbatim production toncenter payload decoded through the real\nserialization pipeline.\n\nFixes #5249",
          "is_bot": false,
          "headline": "fix(ton): detect action-phase failures so failed transfers aren't sho…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-12T09:26:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b8c8d71487537e4563d7015f13562c5b4cd6a98d",
          "body": "* fix(deposit): remove duplicate Amount row on Function overview (#5216)\n\nThe amount is already shown in the \"You're sending\" header\n(SwapToken) at the top of the summary card. The separate \"Amount\"\nrow below repeated the same value, adding redundant visual noise.\n\nRemove the row and the now-unused \n[…]\nmissal is\npreserved, and the opt-in stays scoped to this one screen.\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(reshare): adopt new Figma reshare-flow entry (#5175) (#5222)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-12T09:23:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "04170b107747ea384ef531b8719483a54110a47c",
          "body": "Base's provider-table arm has offered only LIFI/THORCHAIN/SWAPKIT since\nthe table was created (#4313), while iOS and the SDK both quote 1inch and\nKyberSwap on Base. Both are same-chain aggregators (sameChainOnly), so the\narm now matches the BSC/Avalanche EVM pattern via the shared\nthorchainPlusEvmAggregators / evmAggregators sets.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): enable 1inch and KyberSwap on Base (#5255, #5256) (#5259)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-12T08:47:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "507cba016837e5ce2f13f6c2c1a89c3944257d7d",
          "body": "…5261)\n\n* fix(thorchain): read on-chain sRUJI receipt for Staked RUJI amount (#5258)\n\nThe DeFi Staked RUJI amount was read from the Rujira GraphQL `bonded`\nfield, which returns 0 even when the vault holds x/staking-x/ruji receipt\ntokens on-chain — so real positions showed 0. Two root causes:\n\n- `sta\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(thorchain): read on-chain sRUJI receipt for Staked RUJI amount (#…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-12T08:16:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a00400372a68114a382563ed7a64325224338591",
          "body": "…ing (#5260) (#5262)\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: add horizontal padding to I understand button on Backups onboard…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-12T07:35:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3e878b29321701825efa4e9d64f0307e8014612e",
          "body": "…#5257)\n\n* fix(ton): apply wallet-level bounceable to every TonConnect message\n\nMulti-message TonConnect swaps (e.g. STON.fi) never finished co-signing:\nthe joiner polled GET /router/setup-message forever (404). In DKLS keysign\nthe setup message is keyed by md5(pre-image-hash), so a co-signer that\nc\n[…]\nce flag for pool comments to match the initiator.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ton): apply wallet-level bounceable to every TonConnect message (…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-12T06:42:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7020dcc4e6d5d460ada4f67f6148b2bb91b9c7ee",
          "body": "…s success (#5254)\n\n* fix(broadcast): verify tx on-chain before reporting dedup rejections as success\n\nThe per-chain broadcast dedup heuristics accepted string evidence without an\non-chain check, so genuine rejections surfaced as success (issue #5250):\n\n- EVM: drop the bare \"known\" match (also match\n[…]\nccess\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>\nCo-authored-by: Roman <32820910+rkokhatskyi@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(broadcast): verify tx on-chain before treating dedup rejections a…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-12T06:27:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "114c81e0f33019c2e2e1a629398d0d2cb144e9ed",
          "body": "…253)\n\nRippleStatusProvider marked a tx Confirmed on RPC-level status==\"success\",\nwhich for the XRPL `tx` method only means the tx was found. That reported\nvalidated tec* failures (fee burned, no funds delivered) as Confirmed, and\nmade not-yet-validated txs terminally Confirmed even if later dropped\n[…]\n AND meta.TransactionResult==\"tesSUCCESS\";\ntec* -> Failed(code); unvalidated or meta-absent -> keep polling. Mirrors the\nSolana finalized gate.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ripple): gate Confirmed on validated + meta.TransactionResult (#5…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-10T22:14:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ccfa1fd7f81c07a6bfc68d4c0668a0554f49b5fa",
          "body": "getTokenAssociatedAccountByOwner made a single getTokenAccountsByOwner call\nand treated an empty or failed response as \"no token account\". Right after an\nATA is created the indexer can lag, which gave the sender a false \"missing\ntoken account\" error and made the recipient path try to recreate an ATA\n[…]\ned-token addresses and confirm existence with a direct getAccountInfo\nlookup before concluding the account is missing. A normal successful lookup is\nunchanged. Mirrors iOS SolanaService.\n\nCloses #5224",
          "is_bot": false,
          "headline": "fix(solana): fall back to ATA derivation when the indexer lags (#5245)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-09T23:06:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5366edb53509182ca1b66524d87778e0f623f432",
          "body": "The inbound keysign payload mapper parsed the Solana `compute_limit`\nfield with a throwing `toBigInteger()`, so a peer sending a non-numeric\nstring crashed the receiving device with an uncaught NumberFormatException\nduring a keysign ceremony. The sibling `priority_fee` field already fails\nsoft; mirror it with `toBigIntegerOrNull()` so malformed input falls back\nto the default compute-unit limit. Valid values, including an explicit 0,\nare parsed unchanged.",
          "is_bot": false,
          "headline": "fix(solana): fail soft on malformed inbound compute_limit (#5244)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-09T23:03:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06f9c23244d61a17a263fa2d6145d2075683e911",
          "body": "* feat(keysign): animate signing → broadcast → result transitions\n\nThe broadcast flow advanced between states with hard screen cuts. Wrap the\ntwo render seams in Compose transitions so it reads as one screen updating\nin place:\n\n- KeysignView: AnimatedContent over a coarse phase key (progress/finishe\n[…]\no-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(keysign): animate signing → broadcast → result transitions (#5232)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-09T10:47:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd850632851dabf8a1cde9c49a819e0c84127518",
          "body": "The Verify/Send overview screen rendered the Memo row whenever tx.memo\nwas non-null, so an empty-string memo produced a blank Memo label with\nno value, wasting vertical space in the summary card.\n\nGuard the row with isNullOrBlank() so it only appears when a memo is\nactually present. Also adds a PreviewActivity entry (verify_send_empty_memo)\ncovering the empty-memo case.\n\nFixes #5234\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(send): hide Memo row on Send overview when memo is blank (#5243)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-09T09:43:30Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "301920c80ef1aaea210ef129ca019ddbadca0bd6",
          "body": "… (#5240)\n\nThe custom-message keysign path (SigningHelper.getKeysignMessages) keccak256'd\nthe message for every non-EdDSA chain. But cosmos-family chains (THORChain,\nMaya, Cosmos, ...) sign the sha256 of the message — Keplr ADR-36 signArbitrary\nover the StdSignDoc bytes — so Android's digest, and th\n[…]\n> raw, everything else (EVM, Tron) -> keccak256.\n\nAdds ByteArray.toSha256ByteArray() and unit tests covering the cosmos sha256 path.\n\nCo-authored-by: ahdzib-maya <ahdzib-maya@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(keysign): sha256-hash cosmos custom messages instead of keccak256…",
          "author_name": "Itzamna",
          "author_login": "ahdzib-maya",
          "committed_at": "2026-07-09T02:00:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8ef5ce9921beb418fd78deca35576513e4105f7a",
          "body": "…5233)\n\nSolanaStatusProvider treated a non-null err as an immediately terminal\nFailed result regardless of confirmation level. Roughly 5% of Solana\nblocks at processed/confirmed never finalize (they can be forked out\nand re-included with a different outcome), so a transient err observed\nat that earl\n[…]\ntrictly\ninside the finalized case.\n\nRestructure the dispatch so err is only consulted once confirmationStatus\nis finalized; confirmed/processed/null all report Pending regardless of\nerr, matching iOS.",
          "is_bot": false,
          "headline": "fix(solana): gate tx-status err check to finalized commitment only (#…",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-09T01:39:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b31f74066b05bc15e7b01657c91ec75e49bd8030",
          "body": "The Cosmos bank endpoint returns every denom for an address in one\nresponse, but the balance layer calls it once per token — each picking a\nsingle denom and discarding the rest — so opening the Select asset sheet\nfired ~N identical GET /cosmos/bank/v1beta1/balances/{address} requests.\n\nAdd a shared \n[…]\ntrip whether the\ncalls arrive concurrently or back-to-back. getBalance is only used for\nbalance display and token discovery — never the signing/fee path — so a\nshort cache carries no correctness risk.",
          "is_bot": false,
          "headline": "fix(cosmos): coalesce per-token bank-balance requests (#5161) (#5230)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-09T00:17:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "86fa0e9ebd9872d92c54a2cefb0dae778a6919aa",
          "body": "…string (#5229)\n\n* fix(solana): throw on blockhash RPC error instead of returning empty string\n\ngetRecentBlockHash logged a JSON-RPC error response and returned \"\" instead\nof throwing, unlike the adjacent malformed/missing-result branch a few lines\nbelow it, which already throws. The empty string th\n[…]\nerror: ...\" reads\nas an internal detail rather than something a user should see. Reword to\nmatch the plain \"<Chain> RPC error: <message>\" idiom used elsewhere in the\napi package (DashApi, CardanoApi).",
          "is_bot": false,
          "headline": "fix(solana): throw on blockhash RPC error instead of returning empty …",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-08T10:56:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "94412cd269ad9d853428629cd4413e4d488c74ae",
          "body": "…200)\n\n* fix(thorchain): unbond MAX/percentage use bonded amount, not wallet balance\n\nThe THORChain unbond form reused the generic Send form with the wallet's\nspendable RUNE account, so MAX/percentage and the submit-time balance check\noperated on the wallet balance (max bondable) instead of the amou\n[…]\nnthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Johnny Luo <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(thorchain): unbond MAX uses bonded amount, not wallet balance (#5…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-08T10:21:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bb90193467e3b8f681a5308444f1c703a8914033",
          "body": "* fix(deposit): remove duplicate Amount row on Function overview (#5216)\n\nThe amount is already shown in the \"You're sending\" header\n(SwapToken) at the top of the summary card. The separate \"Amount\"\nrow below repeated the same value, adding redundant visual noise.\n\nRemove the row and the now-unused \n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(deposit): remove duplicate Amount row on Function overview (#5221)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-08T09:39:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "60163b4297db26d6ab73393b61884c89604e5889",
          "body": "…y matches signed fee (#5218)\n\n* fix(terraClassic): price send fee at the effective gas limit so Verify matches the signed fee\n\nPorts vultisig-ios#4762. TerraClassicTax.baseGas already prices the base at\nthe (effective) gas limit up front, so chainSpecific.gas is the final fee.\nDrop the redundant sc\n[…]\n\n\n* docs(keysign): update stale fee-helper KDoc for Cardano/Cosmos branches\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(terraClassic): price send fee at the effective gas limit so Verif…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-08T09:39:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3e90f123652a3a499de6948921d9c905240ad831",
          "body": "…#5220)\n\nReplace the bespoke Scaffold + VsTopAppBar + ad-hoc 16dp padding with the\nstandard V3Scaffold so the screen matches the app-wide V3 content inset\n(24dp horizontal / 12dp vertical), topbar, and background. The bottom CTA\npadding now references the V3Scaffold companion constants.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(referral): migrate Create Referral screen to V3Scaffold (#5219) (…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-08T00:36:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "746b311913a47c8055c9d987c92f09bca5ca813c",
          "body": "…08) (#5215)\n\nRippleApi.getBalance already returns the owner-aware, reserve-net balance\n(base + OwnerCount * increment reserves subtracted live from server_state),\nso the account tokenValue reaching ChainValidationService.checkIsReapable is\nalready net of the true on-chain reserve.\n\ncheckIsReapable \n[…]\nales\nand cover the XRP MAX / reserve-band cases in ChainValidationServiceTest.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(ripple): stop double-counting XRP reserve in reaping warning (#52…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-08T00:15:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "862b755961be81e0b1a1f556adc79d6c88ab9e58",
          "body": "…86) (#5214)\n\n* fix(send): reject hex/scientific-notation amounts before signing (#5186)\n\nThe send amount field's InputTransformation blocks non-decimal characters\nfrom IME and paste, but a `vultisig://send?...&amount=1e5` deeplink writes\nthe amount into the field programmatically via setTextAndPlac\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(send): reject hex/scientific-notation amounts before signing (#51…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T10:07:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "10b963c770a34bfaf43407180b296f813d5d0c1f",
          "body": "…5213)\n\nThe coin badge used width()/height(), which the header card's fixed\n118dp height clamped down — so the badge rendered small and fully\ncontained instead of the large, edge-bleeding badge in the Figma spec.\n\nSwitch to requiredWidth/requiredHeight so the drawable keeps its\nintended 200.78×206 size and its concentric gold ring bleeds past the\ncard edge (clipped by the card's rounded shape), matching the design.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(qbtc): size Claimable QBTC header badge to match Figma (#5072) (#…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T10:04:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fc1af83ef408b7fe53036027162117ad2953080c",
          "body": "* feat(cosmos): honor relayed CosmosSpecific.gas_limit in the SignDoc (#5112)\n\nReads the relayed per-tx gas limit (commondata CosmosSpecific.gas_limit, field\n7) and uses it as the signed fee gas limit when an initiator sets one, falling\nback to the static per-chain limit otherwise. The value is part\n[…]\no-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "feat(cosmos): honor relayed CosmosSpecific.gas_limit (#5112) (#5191)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T09:21:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1d3ee3c18a72433591e6ed87b0929b9f699c6c56",
          "body": "…never detected (#5162) (#5192)\n\n* fix(swap): resolve Omniston (TON) swap settlement on-chain (#5162)\n\nA same-chain TON swap routed through Omniston deposits the source jettons\ninto an escrow; SwapKit's /track only sees the deposit leg and reports\n`completed` with `fromAsset == toAsset`, so the app \n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Omniston (TON) swap shown as successful when escrow refunds — refund …",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-07T05:18:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e37765f490582c96659c6f49ddd815c1de9a345e",
          "body": "* feat(ton): gate TON DeFi staking and remove generic-deposit stake path\n\nTON staking now lives exclusively on the DeFi tab. Add Chain.Ton to the\nDeFi-supported / crypto-connection sets, and drop it from isDepositSupported +\nthe generic deposit option list so Stake/Unstake no longer surface in the\nF\n[…]\n\n* style: rewrap comment in TonDeFiBalanceService\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ton): TON nominator-pool staking on the DeFi tab (#5041) (#5133)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T01:56:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a5ab0f4e870d6f5c915c508f2f5c00ac73a7e8e7",
          "body": "…ast failure (#5207)\n\nXRPL echoes the deterministic tx_json.hash back regardless of engine result.\nPreviously a rejected submit returned the engine message as a fake txid, so the\nkeysign persisted a garbage hash instead of surfacing the failure.\n\nPort the iOS RippleService classification into Ripple\n[…]\nef*) throws a typed\n  RippleBroadcastException carrying the engine code + message.\n- broadcastTransaction does HTTP in a try (rewrapping non-broadcast errors),\n  then classifies the result outside it.",
          "is_bot": false,
          "headline": "fix(ripple): stop returning the error string as the tx hash on broadc…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T01:56:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "45f9d14523fca22d9bf60f5c2589581bcee6fc79",
          "body": "The swap \"Transaction pending\" done screen renders the Track button only\nwhen getSwapProgressLink() returns a non-blank URL. For EVM/Solana swaps\nthat link was gated behind the affiliate swapFee parsing as a BigInteger,\nbut EVMSwapQuoteJson.swapFee defaults to \"\" and \"\".toBigIntegerOrNull()\nis null.\n[…]\n the link\nfrom the src chain + tx hash (both always present for a broadcast swap).\nSwapKit-routed swaps are unaffected: they return earlier from the\ntrack.swapkit.dev branch before reaching this code.",
          "is_bot": false,
          "headline": "fix(swap): decouple Track link from parseable swapFee (#5206)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T01:20:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d78bb3044505c73e8d4f7e747fa0284ffa8727e",
          "body": "…s (#5204)\n\nThe foreground \"Join transaction\" banner popped in with no entrance\nanimation whenever a new signing request arrived. `key(qrCodeData)`\ndisposes and recreates the overlay AnimatedVisibility on each new\nrequest, so the node is born with `visible == true` and the\n`visible: Boolean` overloa\n[…]\nthe reserved-space expand) run on the freshly keyed node.\nThe key(qrCodeData) is kept, preserving the swipe-offset reset behavior.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(banner): restore Join-transaction banner slide-in for new request…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-07T01:12:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "127213368b9d8c03dcf8e1b2cfa8fc0976ac0bc4",
          "body": "…5203)\n\nThe Export Vaults flow could leave the user with a broken 0 KB archive:\na 1-character backup password validated as Valid (only non-empty +\nmatching were checked), and any export failure left the empty file SAF\nhad already created on disk with only a transient, generic snackbar.\n\n- Enforce a \n[…]\nrings for the two new messages across all locales.\n- Add regression tests for length validation and failure cleanup.\n\nCloses #5197\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(backup): validate PIN length and clean up failed vault exports (#…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-06T12:15:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "29615c6689450ca20d0a24c4427c4c146b79e4c8",
          "body": "…199)\n\nKeysignTxStatusPoller (which binds the running foreground service) and\nKeysignFlowViewModel.complete() (which cancels its notification) each\ninjected their own TransactionStatusServiceManager. Without a shared\nscope, completion cancelled a never-bound instance and the notification\nwas left showing after the transaction settled.",
          "is_bot": false,
          "headline": "fix(keysign): scope tx-status notification manager as a singleton (#5…",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-06T11:06:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae1acc81cd5a37616c5024a60eda124a82a58b64",
          "body": "…(#5198)\n\n* fix(tokens): require connectivity and retry on token-refresh failure\n\nToken discovery work now sets a NetworkType.CONNECTED constraint and\nreturns Result.retry() when a chain refresh fails, instead of a\nconstraint-free request that runs offline and either fails permanently\nor silently dr\n[…]\n-tokens read failure path\n\nTokenRefreshWorkerTest only exercised getRefreshTokens() throwing;\nadd a case for vaultRepository.getEnabledTokens() throwing, the other\nretryOrFail() call site in doWork().",
          "is_bot": false,
          "headline": "fix(tokens): require connectivity and retry on token-refresh failure …",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-06T10:57:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4d772b9c4c12336cea76046b2b8c20be5887244b",
          "body": "…5195)\n\n#5121 reports the SwapKit EVM verify-screen Network Fee as understated —\ntaken from SwapKit's near-zero `fees[].inbound` placeholder instead of the\noracle-priced broadcast gas, with the same understatement feeding the\ngas-sufficiency check. Tracing the code, that does not hold on Android: a\n\n[…]\nted Fees\" row; Network Fee and Total are the oracle bond.\n\nThis is the Android mirror of the iOS parity test in vultisig-ios#4723.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(swap): pin SwapKit EVM network fee to the oracle bond (#5121) (#…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-06T10:29:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3338603636f4c159d13f3da5089323a58fc935cf",
          "body": "…#5174) (#5190)\n\nLocks the #5115 fix (PR #5156): getFeeForMessage already folds the\nComputeBudget priority fee into the message fee, so the send estimate is\nmessageFee + rentExemption — never messageFee + priority + rent.\n\nThe path was previously untestable because constructing SolanaFeeService\ntrig\n[…]\n native SOL, SPL (with/without recipient token account), and\nthe swap default path's micro-lamports-per-CU to lamports conversion.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(solana): guard send fee estimate against priority double-count (…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-06T09:46:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c625e621dee75ab4389155d9812601f20b0d97ff",
          "body": "Co-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>",
          "is_bot": false,
          "headline": "style: apply ktfmt formatting (#5187) (#5189)",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-06T09:38:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f5e76e9ca320c12d5af826e04fe8294a47d8fc21",
          "body": "…(#5172)\n\n* fix(swap): show refund/failure reason on the transaction done screen (#5152)\n\nWhen a swap is refunded or fails, the app already resolves a human-readable\nreason (e.g. \"deposits are paused for asset (ETH.USDT…)\") and carries it on\nTransactionStatus.Refunded/Failed. The done screen — the e\n[…]\n\nCo-Authored-By: aminsato <Amin.saradar@yahoo.com>\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): show refund/failure reason on the transaction done screen …",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-06T09:17:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8c867fa53405720f1e7a1d4f0285adf6c93930af",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump version to 1.0.113 (#5183)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-06T00:35:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8bfe1275f39198c6211d564b9c1b5016ed0f2be",
          "body": "* fix(qbtc): block claim co-sign when the vault password is empty\n\nNeither the password sheet's Confirm button nor the ViewModel guarded\nagainst a blank password, so the IME \"Go\" action (and, on an unmodified\nbutton, a tap) could reach the server co-sign call with nothing typed.\nDisable Confirm whil\n[…]\na password of only spaces through to the co-sign call.\nSwitch both the ViewModel guard and the sheet's canSubmit check to\nisBlank() so an all-whitespace entry is rejected the same way an empty\none is.",
          "is_bot": false,
          "headline": "fix(qbtc): block claim co-sign when the vault password is empty (#5182)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-05T23:50:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4d6d587ce3891bed0a056a3108c509730ca7d6b2",
          "body": "* fix(send): block XRP/DOT sends that would fall below the chain reserve\n\nMAX and manually-entered near-full sends on Polkadot and XRP could pass\nclient-side validation, run the full MPC signing ceremony, and still get\nrejected on-chain because the existential deposit / account reserve was\nonly ever\n[…]\nunderlying cause. Log it via Timber so a\ntransient RPC failure stays debuggable, matching the BTC-like plan\nerror path in the same file.\n\n---------\n\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(send): block XRP/DOT sends below the chain reserve (#5180)",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-05T23:35:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "45d1173e62e700fb0f333d16d67def0b7706e647",
          "body": "* fix(keysign): reach a terminal state on a hashless broadcast\n\nA successful broadcast that yields no tx hash (Broadcasted.txHash is\nnullable; orKnownHash returns null when both the RPC hash and the local\ntx hash are blank) left signingState stuck at the last signing state —\nan infinite spinner with\n[…]\now before the terminal state lands and invite a\n  force-retry double-send).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): reach a terminal state on a hashless broadcast (#5170)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-05T23:05:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3278ed057b55c0b53ca28bd0e367c24d805a03dd",
          "body": "…kup (#5177)\n\n* fix(backup): wait for the vault list before writing an all-vaults backup\n\nBackupPasswordViewModel and BackupPasswordRequestViewModel loaded the vault\nlist asynchronously in init but backupAllVaults/backupWithoutPassword read it\nfrom a plain var with no guard, so a backup requested be\n[…]\n performs; poll with coVerify's\n  timeout instead of asserting immediately after completing the gate.\n- Switch the new tests from kotlin.test to Kotest assertions per the\n  project's test conventions.",
          "is_bot": false,
          "headline": "fix(backup): wait for the vault list before writing an all-vaults bac…",
          "author_name": "Roman",
          "author_login": "rkokhatskyi",
          "committed_at": "2026-07-05T23:04:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "27286e02007c769da33303db85c0ffc96fdcfff5",
          "body": "…re 4.7.0) (#5169)\n\n* feat(cardano): attach send memo on-chain as CIP-20 metadata (label 674)\n\nCardano's send memo was previously typed by the user but silently dropped at\nsigning time (the TODO in CardanoHelper). WalletCore 4.7.0 exposes the native\nCardano.SigningInput.auxiliary_data field, so we c\n[…]\neply@anthropic.com>\n\n* clarify memo field is optional in GasFeeOrchestrator\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cardano): attach send memo on-chain as CIP-20 metadata (WalletCo…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-05T22:47:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5dec8d9b082c1c5bd004175ef7462fedb2ba0535",
          "body": "…s (#5171)\n\n* fix(ripple): populate the canonical transaction hash on signed XRP txs\n\nRippleHelper.getSignedTransaction returned an empty transactionHash,\nunlike every other chain helper. The empty hash left XRP sends\nuntrackable (status polling, explorer deep-links) and also disabled the\nduplicate-\n[…]\ndoc\n\nThe hash prefix is 0x54584E00 (TXN + zero byte), not a trailing space.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ripple): populate the canonical transaction hash on signed XRP tx…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-05T11:44:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e5f3c966a63ca24e834e56911496b3efff8f41ea",
          "body": "WalletCore's `zip_0317` planner sizes an OP_RETURN output at a flat ~34\nbytes and ignores `byteFee`, so ZEC memo transactions (MayaChain-routed\nswaps carry the swap instruction in an OP_RETURN; sends with memo too)\nplan one logical action short — e.g. 15,000 zats where the network\nrequires 20,000. E\n[…]\ne plan-level golden\nvectors mirror iOS against the same wallet-core 4.7.0 pin.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: hailhydra <johnnyluo1980@gmail.com>",
          "is_bot": false,
          "headline": "fix(zcash): re-plan memo txs to the ZIP-317 conventional fee (#5165)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-05T01:59:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2980c449b725b2428a2cadc458c1579062306535",
          "body": "…ic (#5164)\n\n* feat(terra): support adding custom CW20 tokens on Terra / Terra Classic\n\nLet users add a custom CW20 token by pasting the contract address on\nthe custom-token screen — parity with the extension and iOS (#4733).\nSearchTokenUseCase previously dispatched only EVM / SOL / Kujira, so a\nter\n[…]\nay consistent.\n\nAddresses CodeRabbit review feedback on the PR.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(terra): support adding custom CW20 tokens on Terra / Terra Class…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-04T23:21:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1d7406ab4d2120c29eea94fcd2e7d334f62ec099",
          "body": "… SUI sign (#5168)\n\nPulls in commondata updates:\n- feat(keysign): add CosmosSpecific.gas_limit for relayed dynamic gas\n- feat(tokens): rebrand TON native token to GRAM\n- feat: SUI signing support\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(commondata): bump submodule for cosmos gas_limit, GRAM rebrand,…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-04T22:45:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "685be91ce729b8db10b176ae3f977c445784f9ab",
          "body": "…5160)\n\nTHORChain's only Cosmos Hub pool is native ATOM, but the provider table\noffered THORCHAIN for every GaiaChain coin. Selecting an IBC token like\nrKUJI as the destination sent `GAIA.rKUJI-ibc/...` to Thornode, which\ndeterministically 400s with \"bad to asset: invalid symbol\" — surfaced as\nthe m\n[…]\napError, so any\n  remaining path that reaches the node reports the route as unsupported\n  rather than suggesting an amount change.\n\nCloses #5113\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(swap): stop offering unroutable Cosmos IBC tokens on THORChain (#…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-04T10:23:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "65b6c2bf05caca005edd8f86cb5cf93651bb46c9",
          "body": "…ly fails (#5158)\n\n* fix(keysign): stop joined device faking a txid when broadcast genuinely fails\n\nrecoverJoinedDeviceBroadcast swallowed every non-cancellation exception on a\njoined (co-signing) device and returned the locally computed hash, showing a\nsuccess screen + explorer link for a transacti\n[…]\ns; never recover for the initiator or a blank hash;\npropagate cancellation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): stop joined device faking a txid when broadcast genuine…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-04T10:14:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fddab24a709420048e621a147ab0d57c50618b21",
          "body": "The \"enable post-quantum key\" (Dilithium/MLDSA keygen) option in advanced\nvault settings was shown for GG20 vaults, but a GG20 vault can't run the\nDKLS-based keygen — it must migrate to DKLS first. The option was gated on\n`libType != KeyImport`, which let GG20 through.\n\nGate it on `libType == DKLS` \n[…]\nt import, and GG20 vaults are now excluded. Since the settings screen\nfilters out `isEnabled = false` items, the row is hidden for GG20 vaults.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(settings): hide post-quantum keygen for legacy GG20 vaults (#5157)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-04T01:00:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7723ed5208ebb06c1bb760912e4bb8ddf53c3030",
          "body": "* feat(qbtc): add \"New quantum security\" intro screen before claim (#5074)\n\nIntroduces the onboarding/explainer screen that precedes the QBTC claim\nflow. The hero area plays the quantum_key_pair Rive animation inside a\ndashed frame, followed by three explainer rows (generate key pair, link\nto vault,\n[…]\naim routing, dilithium\nkeygen enablement, and intro navigation.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(qbtc): \"New quantum security\" intro screen before claim (#5123)",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-03T09:47:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3bddbc03114f3c9d94fea04d42fab557cbc3bdfc",
          "body": "…#5156)\n\ngetFeeForMessage already includes the prioritization fee, because the\nserialized message carries the ComputeBudget (SetComputeUnitPrice /\nSetComputeUnitLimit) instructions. calculateFees then added a second\npriority term on top, so the displayed SOL network fee was\nbase + 2x priority + rent\n[…]\nbase + 100000 priority at the 1,000,000 uLam/CU floor).\n\nTake the RPC message fee as the full base+priority and only add\nrent-exemption on top.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(solana): stop double-counting priority fee in send fee estimate (…",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-03T09:22:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6ac25725603872d1bd62fd8502dd01fc52f48675",
          "body": "…ing parity (#5154)",
          "is_bot": false,
          "headline": "chore(deps): bump wallet-core 4.6.13 -> 4.7.0 for cross-platform sign…",
          "author_name": "paaao",
          "author_login": "realpaaao",
          "committed_at": "2026-07-03T07:53:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7fead7ab650673fc3949b9e5acfb52d469e0d673",
          "body": "Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.0.112 (#5153)",
          "author_name": "hailhydra",
          "author_login": "johnnyluo",
          "committed_at": "2026-07-03T01:19:12Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d3f2d2d1b352483408181ff56c3fe4347f9f557e",
          "body": "…top it covering home content (#5134) (#5144)\n\nThe \"Join transaction\" foreground banner had two blocking-popup UX flaws:\n\n- Dismissal was wired to horizontal drag only, so the natural swipe-up\n  did nothing and the banner read as non-dismissable. Switch to\n  detectDragGestures and accept an upward f\n[…]\npushed down while the banner is\n  shown; the overlay itself is unchanged, preserving its status-bar bleed\n  and rounded-corner gradient reveal.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(keysign): make Join-transaction banner swipe-up dismissable and s…",
          "author_name": "Amin",
          "author_login": "aminsato",
          "committed_at": "2026-07-02T23:02:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "90d5e5f96865e8ac3d61bd76b74b4e281e19017e",
          "body": "…ching master (#5138) (#5139)\n\n* style: apply ktfmt formatting (#5138)\n\n* fix: revert out-of-scope comment reformat in JupiterSwapQuoteJson (#5138)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n* style: apply ktfmt formatting (#5138)\n\n* fix: canonicalize TON addresses before\n[…]\n-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Vaulty-bot <vaulty-bot@vultisig.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "TON: wrong jetton balance shown first jetton wallet taken without mat…",
          "author_name": "Vaulty",
          "author_login": "Vaulty-bot",
          "committed_at": "2026-07-02T11:55:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 100,
      "commits_last_year": 1412,
      "latest_release_at": "2026-07-14T10:27:19Z",
      "latest_release_tag": "v1.0.114",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 52,
      "days_since_latest_release": 7,
      "mean_days_between_releases": 4.5
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 50,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 16,
      "stars": 21,
      "watchers": 2,
      "fork_history": {
        "days": [
          {
            "date": "2024-05-22",
            "count": 1
          },
          {
            "date": "2024-06-12",
            "count": 1
          },
          {
            "date": "2025-02-05",
            "count": 1
          },
          {
            "date": "2025-02-09",
            "count": 1
          },
          {
            "date": "2025-03-09",
            "count": 1
          },
          {
            "date": "2025-12-17",
            "count": 1
          },
          {
            "date": "2026-01-21",
            "count": 1
          },
          {
            "date": "2026-03-05",
            "count": 1
          },
          {
            "date": "2026-03-16",
            "count": 1
          },
          {
            "date": "2026-03-26",
            "count": 1
          },
          {
            "date": "2026-04-02",
            "count": 1
          },
          {
            "date": "2026-04-27",
            "count": 1
          },
          {
            "date": "2026-05-05",
            "count": 2
          },
          {
            "date": "2026-07-08",
            "count": 1
          },
          {
            "date": "2026-07-20",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 16,
        "total_forks": 16
      },
      "star_history": {
        "days": [
          {
            "date": "2024-04-22",
            "count": 1
          },
          {
            "date": "2024-05-25",
            "count": 1
          },
          {
            "date": "2024-05-28",
            "count": 1
          },
          {
            "date": "2024-06-15",
            "count": 1
          },
          {
            "date": "2024-08-12",
            "count": 1
          },
          {
            "date": "2024-09-02",
            "count": 1
          },
          {
            "date": "2024-11-24",
            "count": 1
          },
          {
            "date": "2025-04-21",
            "count": 1
          },
          {
            "date": "2025-06-21",
            "count": 1
          },
          {
            "date": "2025-07-11",
            "count": 1
          },
          {
            "date": "2025-10-14",
            "count": 1
          },
          {
            "date": "2025-12-08",
            "count": 1
          },
          {
            "date": "2026-01-19",
            "count": 1
          },
          {
            "date": "2026-01-30",
            "count": 1
          },
          {
            "date": "2026-04-21",
            "count": 1
          },
          {
            "date": "2026-05-01",
            "count": 1
          },
          {
            "date": "2026-05-07",
            "count": 1
          },
          {
            "date": "2026-05-11",
            "count": 1
          },
          {
            "date": "2026-05-14",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-07-20",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 21,
        "total_stars": 21
      },
      "open_issues_and_prs": 28
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "app/build.gradle.kts",
        "build.gradle.kts",
        "data/build.gradle.kts"
      ],
      "largest_source_bytes": 154512,
      "source_files_sampled": 1718,
      "oversized_source_files": 8,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 19254
    },
    "dependencies": {
      "manifests": [
        "Gemfile",
        "app/build.gradle.kts",
        "build.gradle.kts",
        "data/build.gradle.kts"
      ],
      "advisories": {
        "error": null,
        "scope": "repository_graph",
        "source": "osv",
        "findings": [
          {
            "name": "faraday",
            "direct": false,
            "version": "1.10.5",
            "severity": "high",
            "ecosystem": "rubygems",
            "cvss_score": 7.5,
            "advisory_ids": [
              "GHSA-98m9-hrrm-r99r"
            ],
            "fixed_version": "2.14.3",
            "advisory_count": 1,
            "oldest_advisory_days": 32
          },
          {
            "name": "jwt",
            "direct": false,
            "version": "2.10.2",
            "severity": "high",
            "ecosystem": "rubygems",
            "cvss_score": 7.4,
            "advisory_ids": [
              "GHSA-c32j-vqhx-rx3x"
            ],
            "fixed_version": "3.2.0",
            "advisory_count": 1,
            "oldest_advisory_days": 64
          },
          {
            "name": "excon",
            "direct": false,
            "version": "0.112.0",
            "severity": "moderate",
            "ecosystem": "rubygems",
            "cvss_score": 6.5,
            "advisory_ids": [
              "GHSA-48rx-c7pg-q66r"
            ],
            "fixed_version": "1.5.0",
            "advisory_count": 1,
            "oldest_advisory_days": 11
          }
        ],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {
          "high": 2,
          "moderate": 1
        },
        "advisory_count": 3,
        "affected_count": 3,
        "assessed_count": 95,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "maven",
        "rubygems"
      ],
      "dependencies": [
        {
          "name": "fastlane",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": "2.229.1"
        },
        {
          "name": "ostruct",
          "manifest": "Gemfile",
          "ecosystem": "rubygems",
          "version_constraint": null
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "fastlane",
            "direct": true,
            "version": "2.229.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "ostruct",
            "direct": true,
            "version": "0.6.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "abbrev",
            "direct": false,
            "version": "0.1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "addressable",
            "direct": false,
            "version": "2.9.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "artifactory",
            "direct": false,
            "version": "3.0.17",
            "ecosystem": "rubygems"
          },
          {
            "name": "atomos",
            "direct": false,
            "version": "0.1.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-eventstream",
            "direct": false,
            "version": "1.4.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-partitions",
            "direct": false,
            "version": "1.1201.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-core",
            "direct": false,
            "version": "3.241.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-kms",
            "direct": false,
            "version": "1.119.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sdk-s3",
            "direct": false,
            "version": "1.210.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "aws-sigv4",
            "direct": false,
            "version": "1.12.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "babosa",
            "direct": false,
            "version": "1.0.4",
            "ecosystem": "rubygems"
          },
          {
            "name": "base64",
            "direct": false,
            "version": "0.2.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "bigdecimal",
            "direct": false,
            "version": "4.0.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "CFPropertyList",
            "direct": false,
            "version": "3.0.8",
            "ecosystem": "rubygems"
          },
          {
            "name": "claide",
            "direct": false,
            "version": "1.1.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "colored",
            "direct": false,
            "version": "1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "colored2",
            "direct": false,
            "version": "3.1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "commander",
            "direct": false,
            "version": "4.6.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "csv",
            "direct": false,
            "version": "3.3.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "declarative",
            "direct": false,
            "version": "0.0.20",
            "ecosystem": "rubygems"
          },
          {
            "name": "digest-crc",
            "direct": false,
            "version": "0.7.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "domain_name",
            "direct": false,
            "version": "0.6.20240107",
            "ecosystem": "rubygems"
          },
          {
            "name": "dotenv",
            "direct": false,
            "version": "2.8.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "emoji_regex",
            "direct": false,
            "version": "3.2.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "excon",
            "direct": false,
            "version": "0.112.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday",
            "direct": false,
            "version": "1.10.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-cookie_jar",
            "direct": false,
            "version": "0.0.8",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-em_http",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-em_synchrony",
            "direct": false,
            "version": "1.0.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-excon",
            "direct": false,
            "version": "1.1.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-httpclient",
            "direct": false,
            "version": "1.0.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-multipart",
            "direct": false,
            "version": "1.2.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-net_http",
            "direct": false,
            "version": "1.0.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-net_http_persistent",
            "direct": false,
            "version": "1.2.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-patron",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-rack",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday-retry",
            "direct": false,
            "version": "1.0.4",
            "ecosystem": "rubygems"
          },
          {
            "name": "faraday_middleware",
            "direct": false,
            "version": "1.2.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "fastimage",
            "direct": false,
            "version": "2.4.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "fastlane-sirp",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "gh_inspector",
            "direct": false,
            "version": "1.1.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-apis-androidpublisher_v3",
            "direct": false,
            "version": "0.54.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-apis-core",
            "direct": false,
            "version": "0.11.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-apis-iamcredentials_v1",
            "direct": false,
            "version": "0.17.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-apis-playcustomapp_v1",
            "direct": false,
            "version": "0.13.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-apis-storage_v1",
            "direct": false,
            "version": "0.31.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-cloud-core",
            "direct": false,
            "version": "1.8.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-cloud-env",
            "direct": false,
            "version": "1.6.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-cloud-errors",
            "direct": false,
            "version": "1.5.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "google-cloud-storage",
            "direct": false,
            "version": "1.47.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "googleauth",
            "direct": false,
            "version": "1.8.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "highline",
            "direct": false,
            "version": "2.0.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "http-cookie",
            "direct": false,
            "version": "1.0.8",
            "ecosystem": "rubygems"
          },
          {
            "name": "httpclient",
            "direct": false,
            "version": "2.9.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "jmespath",
            "direct": false,
            "version": "1.6.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "json",
            "direct": false,
            "version": "2.19.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "jwt",
            "direct": false,
            "version": "2.10.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "logger",
            "direct": false,
            "version": "1.7.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "mini_magick",
            "direct": false,
            "version": "4.13.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "mini_mime",
            "direct": false,
            "version": "1.1.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "multi_json",
            "direct": false,
            "version": "1.19.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "multipart-post",
            "direct": false,
            "version": "2.4.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "mutex_m",
            "direct": false,
            "version": "0.3.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "nanaimo",
            "direct": false,
            "version": "0.4.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "naturally",
            "direct": false,
            "version": "2.3.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "nkf",
            "direct": false,
            "version": "0.2.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "optparse",
            "direct": false,
            "version": "0.8.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "os",
            "direct": false,
            "version": "1.1.4",
            "ecosystem": "rubygems"
          },
          {
            "name": "plist",
            "direct": false,
            "version": "3.7.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "public_suffix",
            "direct": false,
            "version": "7.0.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "rake",
            "direct": false,
            "version": "13.3.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "representable",
            "direct": false,
            "version": "3.2.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "retriable",
            "direct": false,
            "version": "3.1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "rexml",
            "direct": false,
            "version": "3.4.4",
            "ecosystem": "rubygems"
          },
          {
            "name": "rouge",
            "direct": false,
            "version": "3.28.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "ruby2_keywords",
            "direct": false,
            "version": "0.0.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "rubyzip",
            "direct": false,
            "version": "2.4.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "security",
            "direct": false,
            "version": "0.1.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "signet",
            "direct": false,
            "version": "0.21.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "simctl",
            "direct": false,
            "version": "1.6.10",
            "ecosystem": "rubygems"
          },
          {
            "name": "sysrandom",
            "direct": false,
            "version": "1.0.5",
            "ecosystem": "rubygems"
          },
          {
            "name": "terminal-notifier",
            "direct": false,
            "version": "2.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "terminal-table",
            "direct": false,
            "version": "3.0.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "trailblazer-option",
            "direct": false,
            "version": "0.1.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "tty-cursor",
            "direct": false,
            "version": "0.7.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "tty-screen",
            "direct": false,
            "version": "0.8.2",
            "ecosystem": "rubygems"
          },
          {
            "name": "tty-spinner",
            "direct": false,
            "version": "0.9.3",
            "ecosystem": "rubygems"
          },
          {
            "name": "uber",
            "direct": false,
            "version": "0.1.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "unicode-display_width",
            "direct": false,
            "version": "2.6.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "word_wrap",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "xcodeproj",
            "direct": false,
            "version": "1.27.0",
            "ecosystem": "rubygems"
          },
          {
            "name": "xcpretty",
            "direct": false,
            "version": "0.4.1",
            "ecosystem": "rubygems"
          },
          {
            "name": "xcpretty-travis-formatter",
            "direct": false,
            "version": "1.0.1",
            "ecosystem": "rubygems"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 95,
        "direct_count": 2,
        "indirect_count": 93
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 4,
        "merged_prs": 2630,
        "open_issues": 24,
        "closed_ratio": 0.991,
        "closed_issues": 2537,
        "closed_unmerged_prs": 155
      },
      "bus_factor": 2,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "aminsato",
          "commits": 1098,
          "avatar_url": "https://avatars.githubusercontent.com/u/32006742?v=4"
        },
        {
          "type": "User",
          "login": "johnnyluo",
          "commits": 571,
          "avatar_url": "https://avatars.githubusercontent.com/u/749608?v=4"
        },
        {
          "type": "User",
          "login": "yvebe",
          "commits": 403,
          "avatar_url": "https://avatars.githubusercontent.com/u/14962060?v=4"
        },
        {
          "type": "User",
          "login": "JaimeToca",
          "commits": 288,
          "avatar_url": "https://avatars.githubusercontent.com/u/11850271?v=4"
        },
        {
          "type": "User",
          "login": "Vaulty-bot",
          "commits": 198,
          "avatar_url": "https://avatars.githubusercontent.com/u/257854823?v=4"
        },
        {
          "type": "User",
          "login": "yevhen1sec",
          "commits": 179,
          "avatar_url": "https://avatars.githubusercontent.com/u/173691873?v=4"
        },
        {
          "type": "User",
          "login": "rkokhatskyi",
          "commits": 172,
          "avatar_url": "https://avatars.githubusercontent.com/u/32820910?v=4"
        },
        {
          "type": "User",
          "login": "realpaaao",
          "commits": 37,
          "avatar_url": "https://avatars.githubusercontent.com/u/167348323?v=4"
        },
        {
          "type": "User",
          "login": "LucasFernandes01",
          "commits": 18,
          "avatar_url": "https://avatars.githubusercontent.com/u/25087381?v=4"
        },
        {
          "type": "User",
          "login": "gomesalexandre",
          "commits": 14,
          "avatar_url": "https://avatars.githubusercontent.com/u/17035424?v=4"
        }
      ],
      "contributors_sampled": 16,
      "top_contributor_share": 0.368
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "android.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": true,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "Gemfile.lock"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 9,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 1,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
            "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": 9,
            "reason": "Found 28/30 approved changesets -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 6,
            "reason": "project has 2 contributing companies or organizations -- score normalized to 6",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 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": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 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": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "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": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "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": 7,
            "reason": "3 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "2c230ced6fed249f439e9fbca9c707458f369ce1",
        "ran_at": "2026-07-22T03:21:00Z",
        "aggregate_score": 5.1,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-22T00:06:27Z",
      "oldest_open_prs": [
        {
          "number": 5331,
          "created_at": "2026-07-19T02:00:22Z",
          "last_comment_at": "2026-07-21T23:58:05Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 5364,
          "created_at": "2026-07-21T10:27:52Z",
          "last_comment_at": "2026-07-21T10:28:10Z",
          "last_comment_author": "coderabbitai"
        },
        {
          "number": 5368,
          "created_at": "2026-07-21T11:30:44Z",
          "last_comment_at": "2026-07-21T11:31:05Z",
          "last_comment_author": "coderabbitai"
        },
        {
          "number": 5369,
          "created_at": "2026-07-21T11:42:59Z",
          "last_comment_at": "2026-07-21T21:46:25Z",
          "last_comment_author": "Vaulty-bot"
        }
      ],
      "last_merged_pr_at": "2026-07-21T23:56:25Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 4006,
          "created_at": "2026-04-06T02:01:59Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4154,
          "created_at": "2026-04-23T01:21:17Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 4331,
          "created_at": "2026-04-30T09:37:31Z",
          "last_comment_at": "2026-05-18T10:17:04Z",
          "last_comment_author": "realpaaao"
        },
        {
          "number": 5079,
          "created_at": "2026-06-28T20:20:55Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5080,
          "created_at": "2026-06-28T20:42:53Z",
          "last_comment_at": "2026-07-09T09:20:49Z",
          "last_comment_author": "Vaulty-bot"
        },
        {
          "number": 5210,
          "created_at": "2026-07-06T18:59:55Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5211,
          "created_at": "2026-07-06T18:59:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5212,
          "created_at": "2026-07-06T18:59:58Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5227,
          "created_at": "2026-07-08T08:08:00Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5235,
          "created_at": "2026-07-08T14:29:56Z",
          "last_comment_at": "2026-07-08T23:48:09Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 5252,
          "created_at": "2026-07-10T08:36:17Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5317,
          "created_at": "2026-07-18T05:18:21Z",
          "last_comment_at": "2026-07-19T10:11:05Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 5318,
          "created_at": "2026-07-18T05:18:24Z",
          "last_comment_at": "2026-07-20T07:33:01Z",
          "last_comment_author": "realpaaao"
        },
        {
          "number": 5334,
          "created_at": "2026-07-19T07:32:46Z",
          "last_comment_at": "2026-07-20T07:43:48Z",
          "last_comment_author": "realpaaao"
        },
        {
          "number": 5335,
          "created_at": "2026-07-19T07:43:13Z",
          "last_comment_at": "2026-07-20T07:43:47Z",
          "last_comment_author": "realpaaao"
        },
        {
          "number": 5343,
          "created_at": "2026-07-20T07:22:23Z",
          "last_comment_at": "2026-07-20T09:52:11Z",
          "last_comment_author": "johnnyluo"
        },
        {
          "number": 5344,
          "created_at": "2026-07-20T07:50:08Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5345,
          "created_at": "2026-07-20T07:50:20Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5348,
          "created_at": "2026-07-20T08:36:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 5356,
          "created_at": "2026-07-20T15:20:06Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/vultisig/vultisig-android",
    "host": "github.com",
    "name": "vultisig-android",
    "owner": "vultisig"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 71,
      "inputs": {
        "security": 61,
        "vitality": 96,
        "community": 43,
        "governance": 72,
        "engineering": 74
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 96,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "excellent",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "commits_last_year": 1412,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 52
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "52/52 weeks with commits",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 52
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "1412 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1412
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 100,
              "latest_release_tag": "v1.0.114",
              "releases_from_tags": false,
              "days_since_latest_release": 7,
              "mean_days_between_releases": 4.5
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "100 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 7 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~4.5 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 4.5
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 0,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 0 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 43,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 31,
            "inputs": {
              "forks": 16,
              "stars": 21,
              "watchers": 2,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "below_threshold"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "21 stars",
                "points": 21.1,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 21
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "16 forks",
                "points": 9.8,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "2 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 57,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 6.3,
                "status": "met",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "good",
        "name": "Sustainability & Governance",
        "value": 72,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "moderate",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 59,
            "inputs": {
              "bus_factor": 2,
              "contributors_sampled": 16,
              "top_contributor_share": 0.368
            },
            "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 37% of commits",
                "points": 14.2,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 37
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "16 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 96,
            "inputs": {
              "merged_prs": 2630,
              "open_issues": 24,
              "closed_issues": 2537,
              "issue_closed_ratio": 0.991,
              "closed_unmerged_prs": 155
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "99% of issues closed",
                "points": 46.3,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 99
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "2630/2785 decided PRs merged",
                "points": 36.1,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 2630,
                      "decided": 2785
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 28/30 approved changesets -- score normalized to 9",
                "points": 13.5,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 63,
            "inputs": {
              "followers": 132,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "vultisig",
              "public_repos": 72,
              "account_age_days": 906
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "132 followers of vultisig",
                "points": 15.3,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 132,
                      "login": "vultisig"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "72 public repos, account ~2 yr old",
                "points": 18,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 72
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 2
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "good",
        "name": "Engineering Quality",
        "value": 74,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 61,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 51,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 5.1
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "30 out of 30 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "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 28/30 approved changesets -- score normalized to 9",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 19 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "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 is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "3 existing vulnerabilities detected",
                "points": 5.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories, No advisories left outstanding. Remaining weights renormalized. Matched 95 resolved dependencies against OSV. This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "indirect_dependencies_free_of_known_advisories",
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_repository",
                "params": {
                  "assessed": 95
                }
              },
              {
                "code": "advisories_repo_graph_caveat",
                "params": {}
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 3,
              "affected_packages": 3,
              "assessed_packages": 95,
              "unassessed_packages": 0,
              "affected_by_severity": "high 2, moderate 1",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "transitive set not separable from development and test dependencies in this scope",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_scope_not_separable",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 95,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 3
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 79,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 19254
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 66,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "Gemfile.lock"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.71,
              "toolchain_manifests": [
                "app/build.gradle.kts",
                "build.gradle.kts",
                "data/build.gradle.kts"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "app/build.gradle.kts, build.gradle.kts, data/build.gradle.kts (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "app/build.gradle.kts, build.gradle.kts, data/build.gradle.kts"
                    }
                  }
                ],
                "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": "Kotlin (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Kotlin"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "71 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 71,
                      "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": 100,
            "inputs": {
              "primary_language": "Kotlin",
              "largest_source_bytes": 154512,
              "source_files_sampled": 1718,
              "oversized_source_files": 8
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Kotlin (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Kotlin"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "8/1718 source files over 60KB",
                "points": 54.7,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 1718,
                      "oversized": 8
                    }
                  }
                ],
                "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": [],
  "report_type": "repository",
  "generated_at": "2026-07-22T03:21:28.441383Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/v/vultisig/vultisig-android.svg",
  "full_name": "vultisig/vultisig-android",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

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

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

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